| @@ 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 { |
|