diff --git a/LICENSE b/LICENSE index 638cdf29f4..18db5a5313 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2012-2014 the AngularUI Team, https://github.com/organizations/angular-ui/teams/291112 +Copyright (c) 2012-2015 the AngularUI Team, https://github.com/organizations/angular-ui/teams/291112 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/alert/docs/readme.md b/src/alert/docs/readme.md index 0982c205ea..4bc6f5242c 100644 --- a/src/alert/docs/readme.md +++ b/src/alert/docs/readme.md @@ -2,4 +2,6 @@ Alert is an AngularJS-version of bootstrap's alert. This directive can be used to generate alerts from the dynamic model data (using the `ng-repeat` directive); -The presence of the `close` attribute determines if a close button is displayed +The presence of the `close` attribute determines if a close button is displayed. + +The optional `dismiss-on-timeout` attribute takes the number of milliseconds that specify timeout duration, after which the alert will be closed. diff --git a/src/alert/test/alert.spec.js b/src/alert/test/alert.spec.js index fa0b4fb619..271833309a 100644 --- a/src/alert/test/alert.spec.js +++ b/src/alert/test/alert.spec.js @@ -68,12 +68,12 @@ describe('alert', function () { } }); - it('should show close buttons and have the dismissable class', function () { + it('should show close buttons and have the dismissible class', function () { var alerts = createAlerts(); for (var i = 0, n = alerts.length; i < n; i++) { expect(findCloseButton(i).css('display')).not.toBe('none'); - expect(alerts.eq(i)).toHaveClass('alert-dismissable'); + expect(alerts.eq(i)).toHaveClass('alert-dismissible'); } }); @@ -91,11 +91,11 @@ describe('alert', function () { expect(scope.removeAlert).toHaveBeenCalledWith(1); }); - it('should not show close button and have the dismissable class if no close callback specified', function () { + it('should not show close button and have the dismissible class if no close callback specified', function () { element = $compile('No close')(scope); scope.$digest(); expect(findCloseButton(0)).toBeHidden(); - expect(element).not.toHaveClass('alert-dismissable'); + expect(element).not.toHaveClass('alert-dismissible'); }); it('should be possible to add additional classes for alert', function () { diff --git a/src/dropdown/docs/demo.html b/src/dropdown/docs/demo.html index b051e6edc5..88f1d71c56 100644 --- a/src/dropdown/docs/demo.html +++ b/src/dropdown/docs/demo.html @@ -56,6 +56,15 @@ + +
+ + +
+

@@ -77,4 +86,13 @@ + diff --git a/src/dropdown/docs/readme.md b/src/dropdown/docs/readme.md index 6f1cb41810..ff94a1cca1 100644 --- a/src/dropdown/docs/readme.md +++ b/src/dropdown/docs/readme.md @@ -12,5 +12,8 @@ By default the dropdown will automatically close if any of its elements is click * `always` - (Default) automatically closes the dropdown when any of its elements is clicked. * `outsideClick` - closes the dropdown automatically only when the user clicks any element outside the dropdown. - * `disabled` - disables the auto close. You can then control the open/close status of the dropdown manually, by using `is-open`. Please notice that the dropdown will still close if the toggle is clicked, the `esc` key is pressed or another dropdown is open. + * `disabled` - disables the auto close. You can then control the open/close status of the dropdown manually, by using `is-open`. Please notice that the dropdown will still close if the toggle is clicked, the `esc` key is pressed or another dropdown is open. The dropdown will no longer close on `$locationChangeSuccess` events. +Optionally, you may specify a template for the dropdown menu using the `template-url` attribute. This is especially useful when you have multiple similar dropdowns in a repeater and you want to keep your HTML output lean and your number of scopes to a minimum. The template has full access to the scope in which the dropdown lies. + +Example: `

`. diff --git a/src/dropdown/dropdown.js b/src/dropdown/dropdown.js index 7e7befa985..3ad31095f8 100644 --- a/src/dropdown/dropdown.js +++ b/src/dropdown/dropdown.js @@ -65,9 +65,10 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) }; }]) -.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document) { +.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', '$compile', '$templateRequest', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document, $compile, $templateRequest) { var self = this, scope = $scope.$new(), // create a child scope so we are not polluting original one + templateScope, openClass = dropdownConfig.openClass, getIsOpen, setIsOpen = angular.noop, @@ -173,9 +174,29 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) $animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass); if ( isOpen ) { + if (self.dropdownMenuTemplateUrl) { + $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) { + templateScope = scope.$new(); + $compile(tplContent.trim())(templateScope, function(dropdownElement) { + var newEl = dropdownElement; + self.dropdownMenu.replaceWith(newEl); + self.dropdownMenu = newEl; + }); + }); + } + scope.focusToggleElement(); dropdownService.open( scope ); } else { + if (self.dropdownMenuTemplateUrl) { + if (templateScope) { + templateScope.$destroy(); + } + var newEl = angular.element(''); + self.dropdownMenu.replaceWith(newEl); + self.dropdownMenu = newEl; + } + dropdownService.close( scope ); self.selectedOption = null; } @@ -187,7 +208,9 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) }); $scope.$on('$locationChangeSuccess', function() { - scope.isOpen = false; + if (scope.getAutoClose() !== 'disabled') { + scope.isOpen = false; + } }); $scope.$on('$destroy', function() { @@ -209,10 +232,16 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) restrict: 'AC', require: '?^dropdown', link: function(scope, element, attrs, dropdownCtrl) { - if ( !dropdownCtrl ) { + if (!dropdownCtrl) { return; } - dropdownCtrl.dropdownMenu = element; + var tplUrl = attrs.templateUrl; + if (tplUrl) { + dropdownCtrl.dropdownMenuTemplateUrl = tplUrl; + } + if (!dropdownCtrl.dropdownMenu) { + dropdownCtrl.dropdownMenu = element; + } } }; }) diff --git a/src/dropdown/test/dropdown.spec.js b/src/dropdown/test/dropdown.spec.js index 356a0a0930..686f27d52c 100644 --- a/src/dropdown/test/dropdown.spec.js +++ b/src/dropdown/test/dropdown.spec.js @@ -1,12 +1,13 @@ describe('dropdownToggle', function() { - var $compile, $rootScope, $document, dropdownConfig, element; + var $compile, $rootScope, $document, $templateCache, dropdownConfig, element; beforeEach(module('ui.bootstrap.dropdown')); - beforeEach(inject(function(_$compile_, _$rootScope_, _$document_, _dropdownConfig_) { + beforeEach(inject(function(_$compile_, _$rootScope_, _$document_, _$templateCache_, _dropdownConfig_) { $compile = _$compile_; $rootScope = _$rootScope_; $document = _$document_; + $templateCache = _$templateCache_; dropdownConfig = _dropdownConfig_; })); @@ -182,6 +183,30 @@ describe('dropdownToggle', function() { expect(element.hasClass(dropdownConfig.openClass)).toBe(false); }); }); + + describe('using dropdownMenuTemplate', function() { + function dropdown() { + $templateCache.put('custom.html', ''); + + return $compile('
  • ')($rootScope); + } + + beforeEach(function() { + element = dropdown(); + }); + + it('should apply custom template for dropdown menu', function() { + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); + }); + + it('should clear ul when dropdown menu is closed', function() { + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').length).toEqual(0); + }); + }); describe('using dropdown-append-to-body', function() { function dropdown() { @@ -432,6 +457,16 @@ describe('dropdownToggle', function() { expect(elm1.hasClass(dropdownConfig.openClass)).toBe(false); expect(elm2.hasClass(dropdownConfig.openClass)).toBe(true); }); + + it('should not close on $locationChangeSuccess if auto-close="disabled"', function () { + var elm1 = dropdown('disabled'); + expect(elm1.hasClass(dropdownConfig.openClass)).toBe(false); + clickDropdownToggle(elm1); + expect(elm1.hasClass(dropdownConfig.openClass)).toBe(true); + $rootScope.$broadcast('$locationChangeSuccess'); + $rootScope.$digest(); + expect(elm1.hasClass(dropdownConfig.openClass)).toBe(true); + }); }); describe('`keyboard-nav` option', function() { diff --git a/src/modal/docs/readme.md b/src/modal/docs/readme.md index 1f60a009da..573b2510f6 100644 --- a/src/modal/docs/readme.md +++ b/src/modal/docs/readme.md @@ -23,7 +23,7 @@ The `open` method returns a modal instance, an object with the following propert * `dismiss(reason)` - a method that can be used to dismiss a modal, passing a reason * `result` - a promise that is resolved when a modal is closed and rejected when a modal is dismissed * `opened` - a promise that is resolved when a modal gets opened after downloading content's template and resolving all variables -* 'rendered' - a promise that is resolved when a modal is rendered. +* `rendered` - a promise that is resolved when a modal is rendered. In addition the scope associated with modal's content is augmented with 2 methods: diff --git a/src/timepicker/docs/readme.md b/src/timepicker/docs/readme.md index a658668d52..cc2f7a1d53 100644 --- a/src/timepicker/docs/readme.md +++ b/src/timepicker/docs/readme.md @@ -35,3 +35,7 @@ All settings can be provided as attributes in the `` or globally con * `arrowkeys` _(Defaults: true)_ : Whether user can use up/down arrowkeys inside the hours & minutes input to increase or decrease it's values. + + * `show-spinners` + _(Defaults: true)_ : + Shows spinner arrows above and below the inputs diff --git a/src/timepicker/timepicker.js b/src/timepicker/timepicker.js index 367d69659d..fed6d39b8e 100644 --- a/src/timepicker/timepicker.js +++ b/src/timepicker/timepicker.js @@ -7,7 +7,8 @@ angular.module('ui.bootstrap.timepicker', []) meridians: null, readonlyInput: false, mousewheel: true, - arrowkeys: true + arrowkeys: true, + showSpinners: true }) .controller('TimepickerController', ['$scope', '$attrs', '$parse', '$log', '$locale', 'timepickerConfig', function($scope, $attrs, $parse, $log, $locale, timepickerConfig) { @@ -258,7 +259,10 @@ angular.module('ui.bootstrap.timepicker', []) selected.setHours( dt.getHours(), dt.getMinutes() ); refresh(); } - + + $scope.showSpinners = angular.isDefined($attrs.showSpinners) ? + $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners; + $scope.incrementHours = function() { addMinutes( hourStep * 60 ); }; diff --git a/src/tooltip/docs/readme.md b/src/tooltip/docs/readme.md index fcea6c11b0..78902756e3 100644 --- a/src/tooltip/docs/readme.md +++ b/src/tooltip/docs/readme.md @@ -7,10 +7,10 @@ There are three versions of the tooltip: `tooltip`, `tooltip-template`, and - `tooltip` takes text only and will escape any HTML provided. - `tooltip-template` takes text that specifies the location of a template to use for the tooltip. -- `tooltip-html-unsafe` takes - whatever HTML is provided and displays it in a tooltip; it's called "unsafe" - because the HTML is not sanitized. *The user is responsible for ensuring the +- `tooltip-html` takes + whatever HTML is provided and displays it in a tooltip; *The user is responsible for ensuring the content is safe to put into the DOM!* +- `tooltip-html-unsafe` -- deprecated in favour of `tooltip-html` The tooltip directives provide several optional attributes to control how they will display: diff --git a/template/alert/alert.html b/template/alert/alert.html index 6415960996..c813624858 100644 --- a/template/alert/alert.html +++ b/template/alert/alert.html @@ -1,4 +1,4 @@ -