Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
"**/.*"
],
"dependencies": {
"angular": ">=1.3.0",
"angular": ">=1.7.0",
"bootstrap": ">=3.2.0"
},
"devDependencies": {
"angular-mocks": ">=1.3.0",
"angular-scenario": ">=1.3.0",
"angular": ">=1.3.0"
"angular-mocks": ">=1.7.0",
"angular-scenario": ">=1.7.0",
"angular": ">=1.7.0"
},
"license": "MIT"
}
154 changes: 75 additions & 79 deletions dist/angular-bootstrap-toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@
* Description: Class for "on" state from one of standard bootstrap button types.
* Possible values: btn-default, btn-primary, btn-success, btn-info, btn-warning, btn-danger
*/
onstyle: 'btn-primary',
onClass: 'btn-primary',
onstyle: '', /* for backward compatibility only */
/**
* Type: string
* Default: "btn-default"
* Description: Class for "off" state from one of standard bootstrap button types.
* Possible values: btn-default, btn-primary,btn- success, btn-info, btn-warning, btn-danger
*/
offstyle: 'btn-default',
offClass: 'btn-default',
offstyle: '', /* for some backward compatibility only */
/**
* Type: JSON string
* Default: ''
Expand Down Expand Up @@ -77,11 +79,11 @@
* manipulates this attribute, plus there is additional code that propagates its value to child elements.
* Applying "disabled" to <toggle> itself apparently does nothing, but when its value is propagated to
* two child <label> elements, it allows us to disable the widget.
* Note that attribute "diasbled" is not the same as ng-disabled Angular directive. In most cases, you should
* use <toggle ... ng-disabled="expression"> (not <toggle ... disabled="{{expression}}">) for this to work
* properly.
* [Per HTML specs, the "disabled" property does not need a value. Just mentioning it is enough. Angular will,
* however, also add the value "disabled" (< ... disabled="disabled">)]
* Note that attribute "diasbled" is not the same as ng-disabled Angular directive. In most cases, you
* should use <toggle ... ng-disabled="expression"> (not <toggle ... disabled="{{expression}}">) for this
* to work properly.
* [Per HTML specs, the "disabled" property does not need a value. Just mentioning it is enough. Angular
* will, however, also add the value "disabled" (< ... disabled="disabled">)]
*/
disabled: false,
})
Expand All @@ -91,19 +93,12 @@
function ($scope, $attrs, $interpolate, $log, toggleConfig, $toggleSuppressError) {
var self = this;
var labels, spans, divs;
var ngModelCtrl = {$setViewValue: angular.noop};
var ngModelCtrl;
var toggleConfigKeys = Object.keys(toggleConfig);

// Configuration attributes
angular.forEach( toggleConfigKeys, function (k, i) {
if (angular.isDefined($attrs[k])) {
/*
if (i < toggleConfigKeys.length) {
self[k] = $interpolate($attrs[k])($scope.$parent);
} else {
self[k] = $scope.$parent.$eval($attrs[k]);
}
*/
switch ( typeof toggleConfig[k] ) {
case 'string':
self[k] = $interpolate($attrs[k])($scope.$parent);
Expand All @@ -119,24 +114,36 @@
}
});

// Special treatment for onstyle and offstyle, now deprecated attributes:
// If set, we will use their values for onClass and offClass respectively
if (self.onstyle) {
self.onClass = self.onstyle;
}
if (self.offstyle) {
self.offClass = self.offstyle;
}

this.init = function (ngModelCtrl_) {
ngModelCtrl = ngModelCtrl_;

labels = self.element.find('label');
spans = self.element.find('span');
divs = self.element.find('div');
// ^-- divs[0] is the DIV that has class="toggle btn"
// divs[1] is a child of [0] and has class="toggle-group"
var labels = self.element.find('label');
var spans = self.element.find('span');
var divs = self.element.find('div');

self.wrapperElement = divs[0];
self.onElement = labels[0];
self.offElement = labels[1];
self.handleElement = spans[0];

// Set wigget's visible text such as On/Off or Enable/Disable
angular.element(labels[0]).html(self.on);
angular.element(labels[1]).html(self.off);
angular.element(self.onElement).html(self.on);
angular.element(self.offElement).html(self.off);

self.computeStyle();

ngModelCtrl.$render = function () {
self.toggle();
}
};

// ng-change (for optional onChange event handler)
if (angular.isDefined($attrs.ngChange)) {
Expand All @@ -152,79 +159,68 @@
// The property must be propagated to lables and span inside the toggle-group container. This
// triggers .btn[disabled] style (cursor: not-allowed; opacity: 0.65;) but it does not prohibit
// the click event. Click event is handled in .onSwitch().
angular.element(labels[0]).attr('disabled', self.disabled);
angular.element(labels[1]).attr('disabled', self.disabled);
angular.element( spans[0]).attr('disabled', self.disabled);
angular.element(self.onElement).attr('disabled', self.disabled);
angular.element(self.offElement).attr('disabled', self.disabled);
angular.element(self.handleElement).attr('disabled', self.disabled);

// Build an object for widget's ng-style
$scope.wrapperStyle = (self.toggleStyle) ? $scope.$parent.$eval(self.toggleStyle) : {};

// Calculate the proper width
if (self.width) {
$scope.wrapperStyle.width = self.width;
} else {
// INCORRECT MATH - spans[0] overlaps two side-by-side LABEL's. Half of its width should not be included in the total.
//var wrapperComputedWidth = Math.max(labels[0].offsetWidth, labels[1].offsetWidth) + (spans[0].offsetWidth / 2);
var wrapperComputedWidth = Math.max(labels[0].offsetWidth, labels[1].offsetWidth);
var wrapperWidth = divs[0].offsetWidth;

if (wrapperWidth < wrapperComputedWidth) {
$scope.wrapperStyle.width = wrapperComputedWidth + 'px';
} else {
$scope.wrapperStyle.width = wrapperWidth + 'px';
}
var wrapperComputedWidth = Math.max(
self.onElement.scrollWidth,
self.offElement.scrollWidth) + 12;
$scope.wrapperStyle.width = wrapperComputedWidth + 'px';
}

// Calculate the proper height
if (self.height) {
$scope.wrapperStyle.height = self.height;
} else {
var wrapperComputedHeight = Math.max(labels[0].offsetHeight, labels[1].offsetHeight);
var wrapperHeight = divs[1].offsetHeight;
var wrapperComputedHeight = Math.max(
self.onElement.offsetHeight,
self.offElement.offsetHeight);
var wrapperHeight = self.wrapperElement.offsetHeight;

if (wrapperHeight < wrapperComputedHeight && self.size !== 'btn-xs' && self.size !== 'btn-sm') {
$scope.wrapperStyle.height = wrapperComputedHeight + 'px';
if (wrapperHeight < wrapperComputedHeight &&
self.size !== 'btn-xs' && self.size !== 'btn-sm') {
$scope.wrapperStyle.height = wrapperComputedHeight + 'px';
} else {
$scope.wrapperStyle.height = wrapperHeight + 'px';
}
}

// Build arrays that will be passed to widget's ng-class.
$scope.onClass = [self.onstyle , self.size, 'toggle-on'];
$scope.offClass = [self.offstyle, self.size, 'toggle-off'];
$scope.handleClass = [self.size , 'toggle-handle'];
$scope.onComputedClass = [self.onClass , self.size, 'toggle-on'];
$scope.offComputedClass = [self.offClass, self.size, 'toggle-off'];
$scope.handleComputedClass = [self.size , 'toggle-handle'];
};

this.toggle = function () {
if (angular.isDefined(ngModelCtrl.$viewValue)) {
if (ngModelCtrl.$viewValue) {
$scope.wrapperClass = [self.onstyle, self.size, self.style];
} else {
$scope.wrapperClass = [self.offstyle, 'off ', self.size, self.style];
}
} else {
$scope.wrapperClass = [self.offstyle, 'off ', self.size, self.style];
}
if (ngModelCtrl.$viewValue) {
angular.element(self.wrapperElement).
removeClass('off ' + self.offClass).
addClass(self.onClass);
} else {
angular.element(self.wrapperElement).
addClass('off ' + self.offClass).
removeClass(self.onClass);
}
};

$scope.onSwitch = function (evt) {
if (self.disabled) { // prevent changing .$viewValue if .disabled == true
if (self.disabled) { // prevent changing .$viewValue if .disabled == true
return false;
} else {
ngModelCtrl.$setViewValue(!ngModelCtrl.$viewValue);
ngModelCtrl.$render();
}
return true;
} else {
ngModelCtrl.$setViewValue(!ngModelCtrl.$viewValue);
ngModelCtrl.$render();
}
return true;
};

// Watchable data attributes
angular.forEach(['ngModel'], function (key) {
var watch = $scope.$parent.$watch($attrs[key], function (value) {
ngModelCtrl.$render();
});
$scope.$parent.$on('$destroy', function () {
watch();
});
});

angular.forEach( toggleConfigKeys, function (k, i) {
$attrs.$observe(k, function (v) {
if (self[k] !== v) {
Expand All @@ -238,14 +234,14 @@
.directive('toggle', function () {
return {
restrict: 'E',
transclude: true,
template: '<div class="toggle btn" ng-class="wrapperClass" ng-style="wrapperStyle" ng-click="onSwitch($event)">' +
'<div class="toggle-group">' +
'<label class="btn" ng-class="onClass"></label>' +
'<label class="btn active" ng-class="offClass"></label>' +
'<span class="btn btn-default" ng-class="handleClass"></span>' +
'</div>' +
'</div>',
template: '<div ng-cloak class="toggle btn off" ng-style="wrapperStyle"' +
'ng-click="onSwitch($event)">' +
'<div class="toggle-group">' +
'<label class="btn" ng-class="onComputedClass"></label>' +
'<label class="btn active" ng-class="offComputedClass"></label>' +
'<span class="btn btn-default" ng-class="handleComputedClass"></span>' +
'</div>' +
'</div>',
scope: {
ngModel: '='
},
Expand All @@ -254,13 +250,13 @@
controllerAs: 'toggle',
compile: function (element, attrs, transclude) {
return {
pre: function (scope, element, attrs, ctrls) {
post: function (scope, element, attrs, ctrls) {
var toggleCtrl = ctrls[0], ngModelCtrl = ctrls[1];
toggleCtrl.element = element;
toggleCtrl.init(ngModelCtrl);
},
post: function () {}
}
pre: function () {}
};
}
};
}
Expand Down
Loading