1 | /*!
|
---|
2 | * AngularJS Material Design
|
---|
3 | * https://github.com/angular/material
|
---|
4 | * @license MIT
|
---|
5 | * v1.2.3
|
---|
6 | */
|
---|
7 | goog.provide('ngmaterial.components.switch');
|
---|
8 | goog.require('ngmaterial.components.checkbox');
|
---|
9 | goog.require('ngmaterial.core');
|
---|
10 | /**
|
---|
11 | * @ngdoc module
|
---|
12 | * @name material.components.switch
|
---|
13 | */
|
---|
14 |
|
---|
15 | MdSwitch['$inject'] = ["mdCheckboxDirective", "$mdUtil", "$mdConstant", "$parse", "$$rAF", "$mdGesture", "$timeout"];
|
---|
16 | angular.module('material.components.switch', [
|
---|
17 | 'material.core',
|
---|
18 | 'material.components.checkbox'
|
---|
19 | ])
|
---|
20 | .directive('mdSwitch', MdSwitch);
|
---|
21 |
|
---|
22 | /**
|
---|
23 | * @ngdoc directive
|
---|
24 | * @module material.components.switch
|
---|
25 | * @name mdSwitch
|
---|
26 | * @restrict E
|
---|
27 | *
|
---|
28 | * The switch directive is used very much like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
|
---|
29 | *
|
---|
30 | * As per the [Material Design spec](https://material.io/archive/guidelines/style/color.html#color-color-system)
|
---|
31 | * the switch is in the accent color by default. The primary color palette may be used with
|
---|
32 | * the `md-primary` class.
|
---|
33 | *
|
---|
34 | * @param {expression} ng-model Assignable angular expression to data-bind to.
|
---|
35 | * @param {string=} name Property name of the form under which the control is published.
|
---|
36 | * @param {expression=} ng-true-value The value to which the expression should be set when selected.
|
---|
37 | * @param {expression=} ng-false-value The value to which the expression should be set when not selected.
|
---|
38 | * @param {expression=} ng-change Expression to be executed when the model value changes.
|
---|
39 | * @param {expression=} ng-disabled En/Disable based on the expression.
|
---|
40 | * @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects.
|
---|
41 | * @param {string=} aria-label Publish the button label used by screen-readers for accessibility. Defaults to the switch's text.
|
---|
42 | * @param {boolean=} md-invert When set to true, the switch will be inverted.
|
---|
43 | *
|
---|
44 | * @usage
|
---|
45 | * <hljs lang="html">
|
---|
46 | * <md-switch ng-model="isActive" aria-label="Finished?">
|
---|
47 | * Finished ?
|
---|
48 | * </md-switch>
|
---|
49 | *
|
---|
50 | * <md-switch md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
|
---|
51 | * No Ink Effects
|
---|
52 | * </md-switch>
|
---|
53 | *
|
---|
54 | * <md-switch ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
|
---|
55 | * Disabled
|
---|
56 | * </md-switch>
|
---|
57 | *
|
---|
58 | * </hljs>
|
---|
59 | */
|
---|
60 | function MdSwitch(mdCheckboxDirective, $mdUtil, $mdConstant, $parse, $$rAF, $mdGesture, $timeout) {
|
---|
61 | var checkboxDirective = mdCheckboxDirective[0];
|
---|
62 |
|
---|
63 | return {
|
---|
64 | restrict: 'E',
|
---|
65 | priority: $mdConstant.BEFORE_NG_ARIA,
|
---|
66 | transclude: true,
|
---|
67 | template:
|
---|
68 | '<div class="md-container">' +
|
---|
69 | '<div class="md-bar"></div>' +
|
---|
70 | '<div class="md-thumb-container">' +
|
---|
71 | '<div class="md-thumb" md-ink-ripple md-ink-ripple-checkbox></div>' +
|
---|
72 | '</div>'+
|
---|
73 | '</div>' +
|
---|
74 | '<div ng-transclude class="md-label"></div>',
|
---|
75 | require: ['^?mdInputContainer', '?ngModel', '?^form'],
|
---|
76 | compile: mdSwitchCompile
|
---|
77 | };
|
---|
78 |
|
---|
79 | function mdSwitchCompile(element, attr) {
|
---|
80 | var checkboxLink = checkboxDirective.compile(element, attr).post;
|
---|
81 | // No transition on initial load.
|
---|
82 | element.addClass('md-dragging');
|
---|
83 |
|
---|
84 | return function (scope, element, attr, ctrls) {
|
---|
85 | var containerCtrl = ctrls[0];
|
---|
86 | var ngModel = ctrls[1] || $mdUtil.fakeNgModel();
|
---|
87 | var formCtrl = ctrls[2];
|
---|
88 |
|
---|
89 | var disabledGetter = null;
|
---|
90 | if (attr.disabled != null) {
|
---|
91 | disabledGetter = function() { return true; };
|
---|
92 | } else if (attr.ngDisabled) {
|
---|
93 | disabledGetter = $parse(attr.ngDisabled);
|
---|
94 | }
|
---|
95 |
|
---|
96 | var thumbContainer = angular.element(element[0].querySelector('.md-thumb-container'));
|
---|
97 | var switchContainer = angular.element(element[0].querySelector('.md-container'));
|
---|
98 | var labelContainer = angular.element(element[0].querySelector('.md-label'));
|
---|
99 |
|
---|
100 | // no transition on initial load
|
---|
101 | $$rAF(function() {
|
---|
102 | element.removeClass('md-dragging');
|
---|
103 | });
|
---|
104 |
|
---|
105 | checkboxLink(scope, element, attr, ctrls);
|
---|
106 |
|
---|
107 | if (disabledGetter) {
|
---|
108 | scope.$watch(disabledGetter, function(isDisabled) {
|
---|
109 | element.attr('tabindex', isDisabled ? -1 : 0);
|
---|
110 | });
|
---|
111 | }
|
---|
112 |
|
---|
113 | attr.$observe('mdInvert', function(newValue) {
|
---|
114 | var isInverted = $mdUtil.parseAttributeBoolean(newValue);
|
---|
115 |
|
---|
116 | isInverted ? element.prepend(labelContainer) : element.prepend(switchContainer);
|
---|
117 |
|
---|
118 | // Toggle a CSS class to update the margin.
|
---|
119 | element.toggleClass('md-inverted', isInverted);
|
---|
120 | });
|
---|
121 |
|
---|
122 | // These events are triggered by setup drag
|
---|
123 | $mdGesture.register(switchContainer, 'drag');
|
---|
124 | switchContainer
|
---|
125 | .on('$md.dragstart', onDragStart)
|
---|
126 | .on('$md.drag', onDrag)
|
---|
127 | .on('$md.dragend', onDragEnd);
|
---|
128 |
|
---|
129 | var drag;
|
---|
130 | function onDragStart(ev) {
|
---|
131 | // Don't go if the switch is disabled.
|
---|
132 | if (disabledGetter && disabledGetter(scope)) return;
|
---|
133 | ev.stopPropagation();
|
---|
134 |
|
---|
135 | element.addClass('md-dragging');
|
---|
136 | drag = {width: thumbContainer.prop('offsetWidth')};
|
---|
137 | }
|
---|
138 |
|
---|
139 | function onDrag(ev) {
|
---|
140 | if (!drag) return;
|
---|
141 | ev.stopPropagation();
|
---|
142 | ev.srcEvent && ev.srcEvent.preventDefault();
|
---|
143 |
|
---|
144 | var percent = ev.pointer.distanceX / drag.width;
|
---|
145 |
|
---|
146 | // if checked, start from right. else, start from left
|
---|
147 | var translate = ngModel.$viewValue ? 1 + percent : percent;
|
---|
148 | // Make sure the switch stays inside its bounds, 0-1%
|
---|
149 | translate = Math.max(0, Math.min(1, translate));
|
---|
150 |
|
---|
151 | thumbContainer.css($mdConstant.CSS.TRANSFORM, 'translate3d(' + (100*translate) + '%,0,0)');
|
---|
152 | drag.translate = translate;
|
---|
153 | }
|
---|
154 |
|
---|
155 | function onDragEnd(ev) {
|
---|
156 | if (!drag) return;
|
---|
157 | ev.stopPropagation();
|
---|
158 |
|
---|
159 | element.removeClass('md-dragging');
|
---|
160 | thumbContainer.css($mdConstant.CSS.TRANSFORM, '');
|
---|
161 |
|
---|
162 | // We changed if there is no distance (this is a click a click),
|
---|
163 | // or if the drag distance is >50% of the total.
|
---|
164 | var isChanged = ngModel.$viewValue ? drag.translate < 0.5 : drag.translate > 0.5;
|
---|
165 | if (isChanged) {
|
---|
166 | applyModelValue(!ngModel.$viewValue);
|
---|
167 | }
|
---|
168 | drag = null;
|
---|
169 |
|
---|
170 | // Wait for incoming mouse click
|
---|
171 | scope.skipToggle = true;
|
---|
172 | $timeout(function() {
|
---|
173 | scope.skipToggle = false;
|
---|
174 | }, 1);
|
---|
175 | }
|
---|
176 |
|
---|
177 | function applyModelValue(newValue) {
|
---|
178 | scope.$apply(function() {
|
---|
179 | ngModel.$setViewValue(newValue);
|
---|
180 | ngModel.$render();
|
---|
181 | });
|
---|
182 | }
|
---|
183 |
|
---|
184 | };
|
---|
185 | }
|
---|
186 |
|
---|
187 |
|
---|
188 | }
|
---|
189 |
|
---|
190 | ngmaterial.components.switch = angular.module("material.components.switch"); |
---|