From 5a1c2c9a270940a791d1ebda4fb221ba8ad8f9d9 Mon Sep 17 00:00:00 2001 From: Foxandxss Date: Mon, 21 Sep 2015 19:56:58 +0200 Subject: [PATCH] feat(buttons): use uib- prefix Closes #4445 --- src/buttons/buttons.js | 124 ++++++++++++++++++++++++++++--- src/buttons/docs/demo.html | 22 +++--- src/buttons/test/buttons.spec.js | 109 ++++++++++++++++++--------- 3 files changed, 200 insertions(+), 55 deletions(-) diff --git a/src/buttons/buttons.js b/src/buttons/buttons.js index 6229105ea9..35bfdd6e7b 100644 --- a/src/buttons/buttons.js +++ b/src/buttons/buttons.js @@ -1,19 +1,19 @@ angular.module('ui.bootstrap.buttons', []) -.constant('buttonConfig', { +.constant('uibButtonConfig', { activeClass: 'active', toggleEvent: 'click' }) -.controller('ButtonsController', ['buttonConfig', function(buttonConfig) { +.controller('UibButtonsController', ['uibButtonConfig', function(buttonConfig) { this.activeClass = buttonConfig.activeClass || 'active'; this.toggleEvent = buttonConfig.toggleEvent || 'click'; }]) -.directive('btnRadio', function() { +.directive('uibBtnRadio', function() { return { - require: ['btnRadio', 'ngModel'], - controller: 'ButtonsController', + require: ['uibBtnRadio', 'ngModel'], + controller: 'UibButtonsController', controllerAs: 'buttons', link: function(scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; @@ -22,7 +22,7 @@ angular.module('ui.bootstrap.buttons', []) //model -> UI ngModelCtrl.$render = function() { - element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio))); + element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.uibBtnRadio))); }; //ui->model @@ -35,7 +35,7 @@ angular.module('ui.bootstrap.buttons', []) if (!isActive || angular.isDefined(attrs.uncheckable)) { scope.$apply(function() { - ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio)); + ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.uibBtnRadio)); ngModelCtrl.$render(); }); } @@ -44,10 +44,10 @@ angular.module('ui.bootstrap.buttons', []) }; }) -.directive('btnCheckbox', ['$document', function($document) { +.directive('uibBtnCheckbox', ['$document', function($document) { return { - require: ['btnCheckbox', 'ngModel'], - controller: 'ButtonsController', + require: ['uibBtnCheckbox', 'ngModel'], + controller: 'UibButtonsController', controllerAs: 'button', link: function(scope, element, attrs, ctrls) { var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; @@ -98,3 +98,107 @@ angular.module('ui.bootstrap.buttons', []) } }; }]); + +/* Deprecated buttons below */ + +angular.module('ui.bootstrap.buttons') + + .value('$buttonsSuppressWarning', false) + + .directive('btnRadio', ['$log', '$buttonsSuppressWarning', function($log, $buttonsSuppressWarning) { + return { + require: ['btnRadio', 'ngModel'], + controller: 'UibButtonsController', + controllerAs: 'buttons', + link: function(scope, element, attrs, ctrls) { + if (!$buttonsSuppressWarning) { + $log.warn('btn-radio is now deprecated. Use uib-btn-radio instead.'); + } + + var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + element.find('input').css({display: 'none'}); + + //model -> UI + ngModelCtrl.$render = function() { + element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio))); + }; + + //ui->model + element.bind(buttonsCtrl.toggleEvent, function() { + if (attrs.disabled) { + return; + } + + var isActive = element.hasClass(buttonsCtrl.activeClass); + + if (!isActive || angular.isDefined(attrs.uncheckable)) { + scope.$apply(function() { + ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio)); + ngModelCtrl.$render(); + }); + } + }); + } + }; + }]) + + .directive('btnCheckbox', ['$document', '$log', '$buttonsSuppressWarning', function($document, $log, $buttonsSuppressWarning) { + return { + require: ['btnCheckbox', 'ngModel'], + controller: 'UibButtonsController', + controllerAs: 'button', + link: function(scope, element, attrs, ctrls) { + if (!$buttonsSuppressWarning) { + $log.warn('btn-checkbox is now deprecated. Use uib-btn-checkbox instead.'); + } + + var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + element.find('input').css({display: 'none'}); + + function getTrueValue() { + return getCheckboxValue(attrs.btnCheckboxTrue, true); + } + + function getFalseValue() { + return getCheckboxValue(attrs.btnCheckboxFalse, false); + } + + function getCheckboxValue(attributeValue, defaultValue) { + var val = scope.$eval(attributeValue); + return angular.isDefined(val) ? val : defaultValue; + } + + //model -> UI + ngModelCtrl.$render = function() { + element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue())); + }; + + //ui->model + element.bind(buttonsCtrl.toggleEvent, function() { + if (attrs.disabled) { + return; + } + + scope.$apply(function() { + ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); + ngModelCtrl.$render(); + }); + }); + + //accessibility + element.on('keypress', function(e) { + if (attrs.disabled || e.which !== 32 || $document[0].activeElement !== element[0]) { + return; + } + + scope.$apply(function() { + ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue()); + ngModelCtrl.$render(); + }); + }); + } + }; + }]); + diff --git a/src/buttons/docs/demo.html b/src/buttons/docs/demo.html index 8d00e5134a..72b0b39311 100644 --- a/src/buttons/docs/demo.html +++ b/src/buttons/docs/demo.html @@ -1,27 +1,27 @@

Single toggle

{{singleModel}}
-

Checkbox

Model: {{checkModel}}
Results: {{checkResults}}
- - - + + +

Radio & Uncheckable Radio

{{radioModel || 'null'}}
- - - + + +
- - - + + +
-
\ No newline at end of file + diff --git a/src/buttons/test/buttons.spec.js b/src/buttons/test/buttons.spec.js index 9ac5d29c0b..ff041957be 100644 --- a/src/buttons/test/buttons.spec.js +++ b/src/buttons/test/buttons.spec.js @@ -16,8 +16,8 @@ describe('buttons', function() { }; it('should expose the controller to the view', inject(function($templateCache) { - var btn = compileButton('', $scope); - var ctrl = btn.controller('btnCheckbox'); + var btn = compileButton('', $scope); + var ctrl = btn.controller('uibBtnCheckbox'); expect(ctrl).toBeDefined(); ctrl.text = 'foo'; @@ -29,7 +29,7 @@ describe('buttons', function() { //model -> UI it('should work correctly with default model values', function() { $scope.model = false; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); expect(btn).not.toHaveClass('active'); $scope.model = true; @@ -39,7 +39,7 @@ describe('buttons', function() { it('should bind custom model values', function() { $scope.model = 1; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); expect(btn).toHaveClass('active'); $scope.model = 0; @@ -50,7 +50,7 @@ describe('buttons', function() { //UI-> model it('should toggle default model values on click', function() { $scope.model = false; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); btn.click(); expect($scope.model).toEqual(true); @@ -63,7 +63,7 @@ describe('buttons', function() { it('should toggle custom model values on click', function() { $scope.model = 0; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); btn.click(); expect($scope.model).toEqual(1); @@ -76,7 +76,7 @@ describe('buttons', function() { it('should toggle custom model values on spacebar if focused', function() { $scope.model = 0; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); $('body').append(btn); var e = $.Event('keypress'); e.which = 32; @@ -99,7 +99,7 @@ describe('buttons', function() { $scope.model = 1; $scope.trueVal = 1; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); expect(btn).toHaveClass('active'); expect($scope.model).toEqual(1); @@ -115,7 +115,7 @@ describe('buttons', function() { it('should not toggle when disabled - issue 4013', function() { $scope.model = 1; $scope.falseVal = 0; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); $('body').append(btn); expect(btn).not.toHaveClass('active'); @@ -126,7 +126,7 @@ describe('buttons', function() { expect(btn).not.toHaveClass('active'); $scope.$digest(); - + expect(btn).not.toHaveClass('active'); btn[0].focus(); @@ -137,7 +137,7 @@ describe('buttons', function() { expect(btn).not.toHaveClass('active'); $scope.$digest(); - + expect(btn).not.toHaveClass('active'); btn.remove(); @@ -146,22 +146,22 @@ describe('buttons', function() { describe('setting buttonConfig', function() { var originalActiveClass, originalToggleEvent; - beforeEach(inject(function(buttonConfig) { - originalActiveClass = buttonConfig.activeClass; - originalToggleEvent = buttonConfig.toggleEvent; - buttonConfig.activeClass = false; - buttonConfig.toggleEvent = false; + beforeEach(inject(function(uibButtonConfig) { + originalActiveClass = uibButtonConfig.activeClass; + originalToggleEvent = uibButtonConfig.toggleEvent; + uibButtonConfig.activeClass = false; + uibButtonConfig.toggleEvent = false; })); - afterEach(inject(function(buttonConfig) { + afterEach(inject(function(uibButtonConfig) { // return it to the original value - buttonConfig.activeClass = originalActiveClass; - buttonConfig.toggleEvent = originalToggleEvent; + uibButtonConfig.activeClass = originalActiveClass; + uibButtonConfig.toggleEvent = originalToggleEvent; })); it('should use default config when buttonConfig.activeClass and buttonConfig.toggleEvent is false', function() { $scope.model = false; - var btn = compileButton('', $scope); + var btn = compileButton('', $scope); expect(btn).not.toHaveClass('active'); $scope.model = true; @@ -181,8 +181,8 @@ describe('buttons', function() { }; it('should expose the controller to the view', inject(function($templateCache) { - var btn = compileButtons('', $scope); - var ctrl = btn.controller('btnRadio'); + var btn = compileButtons('', $scope); + var ctrl = btn.controller('uibBtnRadio'); expect(ctrl).toBeDefined(); ctrl.text = 'foo'; @@ -193,7 +193,7 @@ describe('buttons', function() { //model -> UI it('should work correctly set active class based on model', function() { - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -205,7 +205,7 @@ describe('buttons', function() { //UI->model it('should work correctly set active class based on model', function() { - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect($scope.model).toBeUndefined(); btns.eq(0).click(); @@ -219,10 +219,10 @@ describe('buttons', function() { expect(btns.eq(0)).not.toHaveClass('active'); }); - it('should watch btn-radio values and update state accordingly', function() { + it('should watch uib-btn-radio values and update state accordingly', function() { $scope.values = ['value1', 'value2']; - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -240,7 +240,7 @@ describe('buttons', function() { it('should do nothing when click active radio', function() { $scope.model = 1; - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -252,7 +252,7 @@ describe('buttons', function() { it('should not toggle when disabled - issue 4013', function() { $scope.model = 1; - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -268,9 +268,9 @@ describe('buttons', function() { expect(btns.eq(1)).not.toHaveClass('active'); }); - it('should handle string values in btn-radio value', function() { + it('should handle string values in uib-btn-radio value', function() { $scope.model = 'Two'; - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).toHaveClass('active'); @@ -290,7 +290,7 @@ describe('buttons', function() { describe('uncheckable', function() { //model -> UI it('should set active class based on model', function() { - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -302,7 +302,7 @@ describe('buttons', function() { //UI->model it('should unset active class based on model', function() { - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect($scope.model).toBeUndefined(); btns.eq(0).click(); @@ -316,10 +316,10 @@ describe('buttons', function() { expect(btns.eq(0)).not.toHaveClass('active'); }); - it('should watch btn-radio values and update state', function() { + it('should watch uib-btn-radio values and update state', function() { $scope.values = ['value1', 'value2']; - var btns = compileButtons('', $scope); + var btns = compileButtons('', $scope); expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).not.toHaveClass('active'); @@ -336,3 +336,44 @@ describe('buttons', function() { }); }); }); + +/* Deprecation tests below */ + +describe('buttons deprecation', function() { + beforeEach(module('ui.bootstrap.buttons')); + + it('should suppress warning', function() { + module(function($provide) { + $provide.value('$buttonsSuppressWarning', true); + }); + + inject(function($compile, $log, $rootScope) { + spyOn($log, 'warn'); + + var element = $compile('')($rootScope); + $rootScope.$digest(); + + expect($log.warn.calls.count()).toBe(0); + + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect($log.warn.calls.count()).toBe(0); + }); + }); + + it('should give warning by default', inject(function($compile, $log, $rootScope) { + spyOn($log, 'warn'); + + var element = $compile('')($rootScope); + $rootScope.$digest(); + + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect($log.warn.calls.count()).toBe(3); + expect($log.warn.calls.argsFor(0)).toEqual(['btn-checkbox is now deprecated. Use uib-btn-checkbox instead.']); + expect($log.warn.calls.argsFor(1)).toEqual(['btn-radio is now deprecated. Use uib-btn-radio instead.']); + expect($log.warn.calls.argsFor(2)).toEqual(['btn-radio is now deprecated. Use uib-btn-radio instead.']); + })); +});