@@ 3098-3298 (lines=201) @@ | ||
3095 | }; |
|
3096 | }]) |
|
3097 | ||
3098 | .controller('UibDropdownController', ['$scope', '$element', '$attrs', '$parse', 'uibDropdownConfig', 'uibDropdownService', '$animate', '$uibPosition', '$document', '$compile', '$templateRequest', function($scope, $element, $attrs, $parse, dropdownConfig, uibDropdownService, $animate, $position, $document, $compile, $templateRequest) { |
|
3099 | var self = this, |
|
3100 | scope = $scope.$new(), // create a child scope so we are not polluting original one |
|
3101 | templateScope, |
|
3102 | appendToOpenClass = dropdownConfig.appendToOpenClass, |
|
3103 | openClass = dropdownConfig.openClass, |
|
3104 | getIsOpen, |
|
3105 | setIsOpen = angular.noop, |
|
3106 | toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop, |
|
3107 | appendToBody = false, |
|
3108 | appendTo = null, |
|
3109 | keynavEnabled = false, |
|
3110 | selectedOption = null, |
|
3111 | body = $document.find('body'); |
|
3112 | ||
3113 | $element.addClass('dropdown'); |
|
3114 | ||
3115 | this.init = function() { |
|
3116 | if ($attrs.isOpen) { |
|
3117 | getIsOpen = $parse($attrs.isOpen); |
|
3118 | setIsOpen = getIsOpen.assign; |
|
3119 | ||
3120 | $scope.$watch(getIsOpen, function(value) { |
|
3121 | scope.isOpen = !!value; |
|
3122 | }); |
|
3123 | } |
|
3124 | ||
3125 | if (angular.isDefined($attrs.dropdownAppendTo)) { |
|
3126 | var appendToEl = $parse($attrs.dropdownAppendTo)(scope); |
|
3127 | if (appendToEl) { |
|
3128 | appendTo = angular.element(appendToEl); |
|
3129 | } |
|
3130 | } |
|
3131 | ||
3132 | appendToBody = angular.isDefined($attrs.dropdownAppendToBody); |
|
3133 | keynavEnabled = angular.isDefined($attrs.keyboardNav); |
|
3134 | ||
3135 | if (appendToBody && !appendTo) { |
|
3136 | appendTo = body; |
|
3137 | } |
|
3138 | ||
3139 | if (appendTo && self.dropdownMenu) { |
|
3140 | appendTo.append(self.dropdownMenu); |
|
3141 | $element.on('$destroy', function handleDestroyEvent() { |
|
3142 | self.dropdownMenu.remove(); |
|
3143 | }); |
|
3144 | } |
|
3145 | }; |
|
3146 | ||
3147 | this.toggle = function(open) { |
|
3148 | scope.isOpen = arguments.length ? !!open : !scope.isOpen; |
|
3149 | if (angular.isFunction(setIsOpen)) { |
|
3150 | setIsOpen(scope, scope.isOpen); |
|
3151 | } |
|
3152 | ||
3153 | return scope.isOpen; |
|
3154 | }; |
|
3155 | ||
3156 | // Allow other directives to watch status |
|
3157 | this.isOpen = function() { |
|
3158 | return scope.isOpen; |
|
3159 | }; |
|
3160 | ||
3161 | scope.getToggleElement = function() { |
|
3162 | return self.toggleElement; |
|
3163 | }; |
|
3164 | ||
3165 | scope.getAutoClose = function() { |
|
3166 | return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled' |
|
3167 | }; |
|
3168 | ||
3169 | scope.getElement = function() { |
|
3170 | return $element; |
|
3171 | }; |
|
3172 | ||
3173 | scope.isKeynavEnabled = function() { |
|
3174 | return keynavEnabled; |
|
3175 | }; |
|
3176 | ||
3177 | scope.focusDropdownEntry = function(keyCode) { |
|
3178 | var elems = self.dropdownMenu ? //If append to body is used. |
|
3179 | angular.element(self.dropdownMenu).find('a') : |
|
3180 | $element.find('ul').eq(0).find('a'); |
|
3181 | ||
3182 | switch (keyCode) { |
|
3183 | case 40: { |
|
3184 | if (!angular.isNumber(self.selectedOption)) { |
|
3185 | self.selectedOption = 0; |
|
3186 | } else { |
|
3187 | self.selectedOption = self.selectedOption === elems.length - 1 ? |
|
3188 | self.selectedOption : |
|
3189 | self.selectedOption + 1; |
|
3190 | } |
|
3191 | break; |
|
3192 | } |
|
3193 | case 38: { |
|
3194 | if (!angular.isNumber(self.selectedOption)) { |
|
3195 | self.selectedOption = elems.length - 1; |
|
3196 | } else { |
|
3197 | self.selectedOption = self.selectedOption === 0 ? |
|
3198 | 0 : self.selectedOption - 1; |
|
3199 | } |
|
3200 | break; |
|
3201 | } |
|
3202 | } |
|
3203 | elems[self.selectedOption].focus(); |
|
3204 | }; |
|
3205 | ||
3206 | scope.getDropdownElement = function() { |
|
3207 | return self.dropdownMenu; |
|
3208 | }; |
|
3209 | ||
3210 | scope.focusToggleElement = function() { |
|
3211 | if (self.toggleElement) { |
|
3212 | self.toggleElement[0].focus(); |
|
3213 | } |
|
3214 | }; |
|
3215 | ||
3216 | scope.$watch('isOpen', function(isOpen, wasOpen) { |
|
3217 | if (appendTo && self.dropdownMenu) { |
|
3218 | var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true), |
|
3219 | css, |
|
3220 | rightalign; |
|
3221 | ||
3222 | css = { |
|
3223 | top: pos.top + 'px', |
|
3224 | display: isOpen ? 'block' : 'none' |
|
3225 | }; |
|
3226 | ||
3227 | rightalign = self.dropdownMenu.hasClass('dropdown-menu-right'); |
|
3228 | if (!rightalign) { |
|
3229 | css.left = pos.left + 'px'; |
|
3230 | css.right = 'auto'; |
|
3231 | } else { |
|
3232 | css.left = 'auto'; |
|
3233 | css.right = window.innerWidth - |
|
3234 | (pos.left + $element.prop('offsetWidth')) + 'px'; |
|
3235 | } |
|
3236 | ||
3237 | // Need to adjust our positioning to be relative to the appendTo container |
|
3238 | // if it's not the body element |
|
3239 | if (!appendToBody) { |
|
3240 | var appendOffset = $position.offset(appendTo); |
|
3241 | ||
3242 | css.top = pos.top - appendOffset.top + 'px'; |
|
3243 | ||
3244 | if (!rightalign) { |
|
3245 | css.left = pos.left - appendOffset.left + 'px'; |
|
3246 | } else { |
|
3247 | css.right = window.innerWidth - |
|
3248 | (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px'; |
|
3249 | } |
|
3250 | } |
|
3251 | ||
3252 | self.dropdownMenu.css(css); |
|
3253 | } |
|
3254 | ||
3255 | var openContainer = appendTo ? appendTo : $element; |
|
3256 | var hasOpenClass = openContainer.hasClass(appendTo ? appendToOpenClass : openClass); |
|
3257 | ||
3258 | if (hasOpenClass === !isOpen) { |
|
3259 | $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() { |
|
3260 | if (angular.isDefined(isOpen) && isOpen !== wasOpen) { |
|
3261 | toggleInvoker($scope, { open: !!isOpen }); |
|
3262 | } |
|
3263 | }); |
|
3264 | } |
|
3265 | ||
3266 | if (isOpen) { |
|
3267 | if (self.dropdownMenuTemplateUrl) { |
|
3268 | $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) { |
|
3269 | templateScope = scope.$new(); |
|
3270 | $compile(tplContent.trim())(templateScope, function(dropdownElement) { |
|
3271 | var newEl = dropdownElement; |
|
3272 | self.dropdownMenu.replaceWith(newEl); |
|
3273 | self.dropdownMenu = newEl; |
|
3274 | }); |
|
3275 | }); |
|
3276 | } |
|
3277 | ||
3278 | scope.focusToggleElement(); |
|
3279 | uibDropdownService.open(scope, $element); |
|
3280 | } else { |
|
3281 | if (self.dropdownMenuTemplateUrl) { |
|
3282 | if (templateScope) { |
|
3283 | templateScope.$destroy(); |
|
3284 | } |
|
3285 | var newEl = angular.element('<ul class="dropdown-menu"></ul>'); |
|
3286 | self.dropdownMenu.replaceWith(newEl); |
|
3287 | self.dropdownMenu = newEl; |
|
3288 | } |
|
3289 | ||
3290 | uibDropdownService.close(scope, $element); |
|
3291 | self.selectedOption = null; |
|
3292 | } |
|
3293 | ||
3294 | if (angular.isFunction(setIsOpen)) { |
|
3295 | setIsOpen($scope, isOpen); |
|
3296 | } |
|
3297 | }); |
|
3298 | }]) |
|
3299 | ||
3300 | .directive('uibDropdown', function() { |
|
3301 | return { |
@@ 3097-3297 (lines=201) @@ | ||
3094 | }; |
|
3095 | }]) |
|
3096 | ||
3097 | .controller('UibDropdownController', ['$scope', '$element', '$attrs', '$parse', 'uibDropdownConfig', 'uibDropdownService', '$animate', '$uibPosition', '$document', '$compile', '$templateRequest', function($scope, $element, $attrs, $parse, dropdownConfig, uibDropdownService, $animate, $position, $document, $compile, $templateRequest) { |
|
3098 | var self = this, |
|
3099 | scope = $scope.$new(), // create a child scope so we are not polluting original one |
|
3100 | templateScope, |
|
3101 | appendToOpenClass = dropdownConfig.appendToOpenClass, |
|
3102 | openClass = dropdownConfig.openClass, |
|
3103 | getIsOpen, |
|
3104 | setIsOpen = angular.noop, |
|
3105 | toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop, |
|
3106 | appendToBody = false, |
|
3107 | appendTo = null, |
|
3108 | keynavEnabled = false, |
|
3109 | selectedOption = null, |
|
3110 | body = $document.find('body'); |
|
3111 | ||
3112 | $element.addClass('dropdown'); |
|
3113 | ||
3114 | this.init = function() { |
|
3115 | if ($attrs.isOpen) { |
|
3116 | getIsOpen = $parse($attrs.isOpen); |
|
3117 | setIsOpen = getIsOpen.assign; |
|
3118 | ||
3119 | $scope.$watch(getIsOpen, function(value) { |
|
3120 | scope.isOpen = !!value; |
|
3121 | }); |
|
3122 | } |
|
3123 | ||
3124 | if (angular.isDefined($attrs.dropdownAppendTo)) { |
|
3125 | var appendToEl = $parse($attrs.dropdownAppendTo)(scope); |
|
3126 | if (appendToEl) { |
|
3127 | appendTo = angular.element(appendToEl); |
|
3128 | } |
|
3129 | } |
|
3130 | ||
3131 | appendToBody = angular.isDefined($attrs.dropdownAppendToBody); |
|
3132 | keynavEnabled = angular.isDefined($attrs.keyboardNav); |
|
3133 | ||
3134 | if (appendToBody && !appendTo) { |
|
3135 | appendTo = body; |
|
3136 | } |
|
3137 | ||
3138 | if (appendTo && self.dropdownMenu) { |
|
3139 | appendTo.append(self.dropdownMenu); |
|
3140 | $element.on('$destroy', function handleDestroyEvent() { |
|
3141 | self.dropdownMenu.remove(); |
|
3142 | }); |
|
3143 | } |
|
3144 | }; |
|
3145 | ||
3146 | this.toggle = function(open) { |
|
3147 | scope.isOpen = arguments.length ? !!open : !scope.isOpen; |
|
3148 | if (angular.isFunction(setIsOpen)) { |
|
3149 | setIsOpen(scope, scope.isOpen); |
|
3150 | } |
|
3151 | ||
3152 | return scope.isOpen; |
|
3153 | }; |
|
3154 | ||
3155 | // Allow other directives to watch status |
|
3156 | this.isOpen = function() { |
|
3157 | return scope.isOpen; |
|
3158 | }; |
|
3159 | ||
3160 | scope.getToggleElement = function() { |
|
3161 | return self.toggleElement; |
|
3162 | }; |
|
3163 | ||
3164 | scope.getAutoClose = function() { |
|
3165 | return $attrs.autoClose || 'always'; //or 'outsideClick' or 'disabled' |
|
3166 | }; |
|
3167 | ||
3168 | scope.getElement = function() { |
|
3169 | return $element; |
|
3170 | }; |
|
3171 | ||
3172 | scope.isKeynavEnabled = function() { |
|
3173 | return keynavEnabled; |
|
3174 | }; |
|
3175 | ||
3176 | scope.focusDropdownEntry = function(keyCode) { |
|
3177 | var elems = self.dropdownMenu ? //If append to body is used. |
|
3178 | angular.element(self.dropdownMenu).find('a') : |
|
3179 | $element.find('ul').eq(0).find('a'); |
|
3180 | ||
3181 | switch (keyCode) { |
|
3182 | case 40: { |
|
3183 | if (!angular.isNumber(self.selectedOption)) { |
|
3184 | self.selectedOption = 0; |
|
3185 | } else { |
|
3186 | self.selectedOption = self.selectedOption === elems.length - 1 ? |
|
3187 | self.selectedOption : |
|
3188 | self.selectedOption + 1; |
|
3189 | } |
|
3190 | break; |
|
3191 | } |
|
3192 | case 38: { |
|
3193 | if (!angular.isNumber(self.selectedOption)) { |
|
3194 | self.selectedOption = elems.length - 1; |
|
3195 | } else { |
|
3196 | self.selectedOption = self.selectedOption === 0 ? |
|
3197 | 0 : self.selectedOption - 1; |
|
3198 | } |
|
3199 | break; |
|
3200 | } |
|
3201 | } |
|
3202 | elems[self.selectedOption].focus(); |
|
3203 | }; |
|
3204 | ||
3205 | scope.getDropdownElement = function() { |
|
3206 | return self.dropdownMenu; |
|
3207 | }; |
|
3208 | ||
3209 | scope.focusToggleElement = function() { |
|
3210 | if (self.toggleElement) { |
|
3211 | self.toggleElement[0].focus(); |
|
3212 | } |
|
3213 | }; |
|
3214 | ||
3215 | scope.$watch('isOpen', function(isOpen, wasOpen) { |
|
3216 | if (appendTo && self.dropdownMenu) { |
|
3217 | var pos = $position.positionElements($element, self.dropdownMenu, 'bottom-left', true), |
|
3218 | css, |
|
3219 | rightalign; |
|
3220 | ||
3221 | css = { |
|
3222 | top: pos.top + 'px', |
|
3223 | display: isOpen ? 'block' : 'none' |
|
3224 | }; |
|
3225 | ||
3226 | rightalign = self.dropdownMenu.hasClass('dropdown-menu-right'); |
|
3227 | if (!rightalign) { |
|
3228 | css.left = pos.left + 'px'; |
|
3229 | css.right = 'auto'; |
|
3230 | } else { |
|
3231 | css.left = 'auto'; |
|
3232 | css.right = window.innerWidth - |
|
3233 | (pos.left + $element.prop('offsetWidth')) + 'px'; |
|
3234 | } |
|
3235 | ||
3236 | // Need to adjust our positioning to be relative to the appendTo container |
|
3237 | // if it's not the body element |
|
3238 | if (!appendToBody) { |
|
3239 | var appendOffset = $position.offset(appendTo); |
|
3240 | ||
3241 | css.top = pos.top - appendOffset.top + 'px'; |
|
3242 | ||
3243 | if (!rightalign) { |
|
3244 | css.left = pos.left - appendOffset.left + 'px'; |
|
3245 | } else { |
|
3246 | css.right = window.innerWidth - |
|
3247 | (pos.left - appendOffset.left + $element.prop('offsetWidth')) + 'px'; |
|
3248 | } |
|
3249 | } |
|
3250 | ||
3251 | self.dropdownMenu.css(css); |
|
3252 | } |
|
3253 | ||
3254 | var openContainer = appendTo ? appendTo : $element; |
|
3255 | var hasOpenClass = openContainer.hasClass(appendTo ? appendToOpenClass : openClass); |
|
3256 | ||
3257 | if (hasOpenClass === !isOpen) { |
|
3258 | $animate[isOpen ? 'addClass' : 'removeClass'](openContainer, appendTo ? appendToOpenClass : openClass).then(function() { |
|
3259 | if (angular.isDefined(isOpen) && isOpen !== wasOpen) { |
|
3260 | toggleInvoker($scope, { open: !!isOpen }); |
|
3261 | } |
|
3262 | }); |
|
3263 | } |
|
3264 | ||
3265 | if (isOpen) { |
|
3266 | if (self.dropdownMenuTemplateUrl) { |
|
3267 | $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) { |
|
3268 | templateScope = scope.$new(); |
|
3269 | $compile(tplContent.trim())(templateScope, function(dropdownElement) { |
|
3270 | var newEl = dropdownElement; |
|
3271 | self.dropdownMenu.replaceWith(newEl); |
|
3272 | self.dropdownMenu = newEl; |
|
3273 | }); |
|
3274 | }); |
|
3275 | } |
|
3276 | ||
3277 | scope.focusToggleElement(); |
|
3278 | uibDropdownService.open(scope, $element); |
|
3279 | } else { |
|
3280 | if (self.dropdownMenuTemplateUrl) { |
|
3281 | if (templateScope) { |
|
3282 | templateScope.$destroy(); |
|
3283 | } |
|
3284 | var newEl = angular.element('<ul class="dropdown-menu"></ul>'); |
|
3285 | self.dropdownMenu.replaceWith(newEl); |
|
3286 | self.dropdownMenu = newEl; |
|
3287 | } |
|
3288 | ||
3289 | uibDropdownService.close(scope, $element); |
|
3290 | self.selectedOption = null; |
|
3291 | } |
|
3292 | ||
3293 | if (angular.isFunction(setIsOpen)) { |
|
3294 | setIsOpen($scope, isOpen); |
|
3295 | } |
|
3296 | }); |
|
3297 | }]) |
|
3298 | ||
3299 | .directive('uibDropdown', function() { |
|
3300 | return { |