diff --git a/bower.json b/bower.json index 38a636a..71e507f 100644 --- a/bower.json +++ b/bower.json @@ -2,10 +2,10 @@ "name": "frontkit", "version": "0.0.1", "dependencies": { - "angular": "1.2.17" + "angular": "~1.2.10" }, "devDependencies": { - "angular-mocks": "1.2.17", + "angular-mocks": "~1.2.10", "holderjs": "~2.3.1", "highlightjs": "~8.0.0", "normalize.css": "~3.0.0" diff --git a/src/scripts/dropdown.js b/src/scripts/dropdown.js index 42a4dcf..f0f4c90 100644 --- a/src/scripts/dropdown.js +++ b/src/scripts/dropdown.js @@ -135,21 +135,7 @@ ctrl.parseOptions = function( model ) { var currPromise; - $scope.$watch( model, watchFn, true ); - $scope.$watch( model, function( newValue, oldValue ) { - var isFn = ng.isFunction; - var isPromise = !!newValue && isFn( newValue.then ); - isPromise &= !!oldValue && isFn( oldValue.then ); - - // We won't handle anything here unless both values are promises. - if ( !ng.equals( newValue, oldValue ) || !isPromise ) { - return; - } - - watchFn( newValue ); - }); - - function watchFn( value ) { + $scope.$watch( model, function watchFn( value ) { var promise; currPromise = null; @@ -174,7 +160,7 @@ currPromise = promise; } - } + }, true ); }; function clearSearch() { @@ -204,9 +190,10 @@ ]); module.directive( "dropdownOptions", [ + "$compile", "repeatParser", "dropdownConfig", - function( repeatParser, dropdownConfig ) { + function( $compile, repeatParser, dropdownConfig ) { var definition = {}; definition.restrict = "EA"; @@ -215,112 +202,131 @@ definition.templateUrl = "templates/dropdown/options.html"; definition.require = "^dropdown"; - definition.compile = function( tElement, tAttr ) { - var model; - var option = tElement.querySelector( ".dropdown-option" ); - var repeat = repeatParser.parse( tAttr.items ); - - if ( !repeat ) { + definition.compile = function( tElement ) { + // When in a detached case, we won't let compile go ahead + if ( !tElement.parent().length ) { return; } - model = repeat.expr; - repeat.expr = "$dropdown.options"; - - option.attr( "ng-repeat", repeatParser.toNgRepeat( repeat ) ); - option.attr( "ng-click", "$dropdown.addItem( " + repeat.item + " )" ); - option.attr( "ng-class", "{" + - "active: $dropdown.activeOption === " + repeat.item + - "}" ); - - return function( scope, element, attr, $dropdown ) { - var list = element[ 0 ]; - configureOverflow(); - - $dropdown.parseOptions( model ); - $dropdown.valueKey = tAttr.value || null; - - scope.$watch( "$dropdown.open", adjustScroll ); - scope.$watch( "$dropdown.activeOption", adjustScroll ); - - function adjustScroll() { - var fromScrollTop, index, activeElem; - var options = $dropdown.options; - var scrollTop = list.scrollTop; - - if ( ng.isArray( options ) ) { - index = options.indexOf( $dropdown.activeOption ); - } else { - // To keep compatibility with arrays, we'll init the index as -1 - index = -1; - Object.keys( options ).some(function( key, i ) { - if ( options[ key ] === $dropdown.activeOption ) { - index = i; - return true; - } - }); - } + return definition.link; + }; - activeElem = list.querySelectorAll( ".dropdown-option" )[ index ]; + definition.link = function( scope, element, attr, $dropdown, transclude ) { + var list = element[ 0 ]; + var option = element.querySelector( ".dropdown-option" ); + var repeat = repeatParser.parse( attr.items ); + + // If we have a repeat expr, let's use it to build the option list + if ( repeat ) { + $dropdown.parseOptions( repeat.expr ); + repeat.expr = "$dropdown.options"; + + // Option list building + transclude(function( childs ) { + option.append( childs ); + }); + + // Add a few directives to the option... + option.attr( "ng-repeat", repeatParser.toNgRepeat( repeat ) ); + option.attr( "ng-click", "$dropdown.addItem( " + repeat.item + " )" ); + option.attr( "ng-class", "{" + + "active: $dropdown.activeOption === " + repeat.item + + "}" ); + + // ...and compile it + $compile( option )( scope ); + } - if ( !$dropdown.open || !activeElem ) { - // To be handled! - return; - } + // Configure the overflow for this list + configureOverflow(); - fromScrollTop = activeElem.offsetTop - list.scrollTop; - - // If the option is above the current scroll, we'll make it appear on the - // top of the scroll. - // Otherwise, it'll appear in the end of the scroll view. - if ( fromScrollTop < 0 ) { - scrollTop = activeElem.offsetTop; - } else if ( list.clientHeight <= fromScrollTop + activeElem.clientHeight ) { - scrollTop = activeElem.offsetTop + - activeElem.clientHeight - - list.clientHeight; - } + // Set the value key + $dropdown.valueKey = attr.value || null; - list.scrollTop = scrollTop; - } + // Scope Watches + // --------------------------------------------------------------------------------- + scope.$watch( "$dropdown.open", adjustScroll ); + scope.$watch( "$dropdown.activeOption", adjustScroll ); + + // Functions + // --------------------------------------------------------------------------------- + function adjustScroll() { + var fromScrollTop, index, activeElem; + var options = $dropdown.options; + var scrollTop = list.scrollTop; - function configureOverflow() { - var height; - var view = list.ownerDocument.defaultView; - var styles = view.getComputedStyle( list, null ); - var display = element.css( "display" ); - var size = dropdownConfig.optionsPageSize; - var li = $( "