material_design_lite-sass 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +108 -0
- data/Rakefile +4 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/material_design_lite-sass.rb +46 -0
- data/lib/material_design_lite/sass/engine.rb +13 -0
- data/lib/material_design_lite/sass/version.rb +5 -0
- data/material_design_lite-sass.gemspec +28 -0
- data/vendor/assets/javascripts/material.js +3919 -0
- data/vendor/assets/javascripts/material/button.js +132 -0
- data/vendor/assets/javascripts/material/checkbox.js +265 -0
- data/vendor/assets/javascripts/material/data-table.js +149 -0
- data/vendor/assets/javascripts/material/icon-toggle.js +248 -0
- data/vendor/assets/javascripts/material/layout.js +434 -0
- data/vendor/assets/javascripts/material/mdlComponentHandler.js +346 -0
- data/vendor/assets/javascripts/material/menu.js +468 -0
- data/vendor/assets/javascripts/material/progress.js +116 -0
- data/vendor/assets/javascripts/material/rAF.js +38 -0
- data/vendor/assets/javascripts/material/radio.js +257 -0
- data/vendor/assets/javascripts/material/ripple.js +244 -0
- data/vendor/assets/javascripts/material/slider.js +252 -0
- data/vendor/assets/javascripts/material/spinner.js +140 -0
- data/vendor/assets/javascripts/material/switch.js +269 -0
- data/vendor/assets/javascripts/material/tabs.js +152 -0
- data/vendor/assets/javascripts/material/textfield.js +247 -0
- data/vendor/assets/javascripts/material/tooltip.js +146 -0
- data/vendor/assets/stylesheets/_material.scss +50 -0
- data/vendor/assets/stylesheets/material/_animation.scss +34 -0
- data/vendor/assets/stylesheets/material/_badge.scss +66 -0
- data/vendor/assets/stylesheets/material/_button.scss +298 -0
- data/vendor/assets/stylesheets/material/_card.scss +111 -0
- data/vendor/assets/stylesheets/material/_checkbox.scss +175 -0
- data/vendor/assets/stylesheets/material/_color-definitions.scss +599 -0
- data/vendor/assets/stylesheets/material/_data-table.scss +105 -0
- data/vendor/assets/stylesheets/material/_functions.scss +3 -0
- data/vendor/assets/stylesheets/material/_grid.scss +180 -0
- data/vendor/assets/stylesheets/material/_icon-toggle.scss +121 -0
- data/vendor/assets/stylesheets/material/_layout.scss +580 -0
- data/vendor/assets/stylesheets/material/_mega_footer.scss +309 -0
- data/vendor/assets/stylesheets/material/_menu.scss +193 -0
- data/vendor/assets/stylesheets/material/_mini_footer.scss +88 -0
- data/vendor/assets/stylesheets/material/_mixins.scss +268 -0
- data/vendor/assets/stylesheets/material/_palette.scss +2303 -0
- data/vendor/assets/stylesheets/material/_progress.scss +115 -0
- data/vendor/assets/stylesheets/material/_radio.scss +155 -0
- data/vendor/assets/stylesheets/material/_resets.scss +55 -0
- data/vendor/assets/stylesheets/material/_ripple.scss +42 -0
- data/vendor/assets/stylesheets/material/_shadow.scss +42 -0
- data/vendor/assets/stylesheets/material/_slider.scss +396 -0
- data/vendor/assets/stylesheets/material/_spinner.scss +248 -0
- data/vendor/assets/stylesheets/material/_switch.scss +199 -0
- data/vendor/assets/stylesheets/material/_tabs.scss +115 -0
- data/vendor/assets/stylesheets/material/_textfield.scss +190 -0
- data/vendor/assets/stylesheets/material/_tooltip.scss +66 -0
- data/vendor/assets/stylesheets/material/_typography.scss +297 -0
- data/vendor/assets/stylesheets/material/_variables.scss +572 -0
- data/vendor/assets/stylesheets/material/resets/_h5bp.scss +284 -0
- data/vendor/assets/stylesheets/material/resets/_mobile.scss +25 -0
- metadata +151 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* Copyright 2015 Google Inc. All Rights Reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Class constructor for Progress MDL component.
|
20
|
+
* Implements MDL component design pattern defined at:
|
21
|
+
* https://github.com/jasonmayes/mdl-component-design-pattern
|
22
|
+
* @param {HTMLElement} element The element that will be upgraded.
|
23
|
+
*/
|
24
|
+
function MaterialProgress(element) {
|
25
|
+
'use strict';
|
26
|
+
|
27
|
+
this.element_ = element;
|
28
|
+
|
29
|
+
// Initialize instance.
|
30
|
+
this.init();
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Store constants in one place so they can be updated easily.
|
35
|
+
* @enum {string | number}
|
36
|
+
* @private
|
37
|
+
*/
|
38
|
+
MaterialProgress.prototype.Constant_ = {
|
39
|
+
};
|
40
|
+
|
41
|
+
/**
|
42
|
+
* Store strings for class names defined by this component that are used in
|
43
|
+
* JavaScript. This allows us to simply change it in one place should we
|
44
|
+
* decide to modify at a later date.
|
45
|
+
* @enum {string}
|
46
|
+
* @private
|
47
|
+
*/
|
48
|
+
MaterialProgress.prototype.CssClasses_ = {
|
49
|
+
INDETERMINATE_CLASS: 'mdl-progress__indeterminate'
|
50
|
+
};
|
51
|
+
|
52
|
+
MaterialProgress.prototype.setProgress = function(p) {
|
53
|
+
'use strict';
|
54
|
+
|
55
|
+
if (this.element_.classList.contains(this.CssClasses_.INDETERMINATE_CLASS)) {
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
this.progressbar_.style.width = p + '%';
|
60
|
+
};
|
61
|
+
|
62
|
+
MaterialProgress.prototype.setBuffer = function(p) {
|
63
|
+
'use strict';
|
64
|
+
|
65
|
+
this.bufferbar_.style.width = p + '%';
|
66
|
+
this.auxbar_.style.width = (100 - p) + '%';
|
67
|
+
};
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Initialize element.
|
71
|
+
*/
|
72
|
+
MaterialProgress.prototype.init = function() {
|
73
|
+
'use strict';
|
74
|
+
|
75
|
+
if (this.element_) {
|
76
|
+
var el = document.createElement('div');
|
77
|
+
el.className = 'progressbar bar bar1';
|
78
|
+
this.element_.appendChild(el);
|
79
|
+
this.progressbar_ = el;
|
80
|
+
|
81
|
+
el = document.createElement('div');
|
82
|
+
el.className = 'bufferbar bar bar2';
|
83
|
+
this.element_.appendChild(el);
|
84
|
+
this.bufferbar_ = el;
|
85
|
+
|
86
|
+
el = document.createElement('div');
|
87
|
+
el.className = 'auxbar bar bar3';
|
88
|
+
this.element_.appendChild(el);
|
89
|
+
this.auxbar_ = el;
|
90
|
+
|
91
|
+
this.progressbar_.style.width = '0%';
|
92
|
+
this.bufferbar_.style.width = '100%';
|
93
|
+
this.auxbar_.style.width = '0%';
|
94
|
+
|
95
|
+
this.element_.classList.add('is-upgraded');
|
96
|
+
}
|
97
|
+
};
|
98
|
+
|
99
|
+
/*
|
100
|
+
* Downgrade the component
|
101
|
+
*/
|
102
|
+
MaterialProgress.prototype.mdlDowngrade_ = function() {
|
103
|
+
'use strict';
|
104
|
+
while (this.element_.firstChild) {
|
105
|
+
this.element_.removeChild(this.element_.firstChild);
|
106
|
+
}
|
107
|
+
};
|
108
|
+
|
109
|
+
// The component registers itself. It can assume componentHandler is available
|
110
|
+
// in the global scope.
|
111
|
+
componentHandler.register({
|
112
|
+
constructor: MaterialProgress,
|
113
|
+
classAsString: 'MaterialProgress',
|
114
|
+
cssClass: 'mdl-js-progress',
|
115
|
+
widget: true
|
116
|
+
});
|
@@ -0,0 +1,38 @@
|
|
1
|
+
// Source: https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js
|
2
|
+
// Adapted from https://gist.github.com/paulirish/1579671 which derived from
|
3
|
+
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
|
4
|
+
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
|
5
|
+
|
6
|
+
// requestAnimationFrame polyfill by Erik Möller.
|
7
|
+
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
|
8
|
+
|
9
|
+
// MIT license
|
10
|
+
|
11
|
+
(function() {
|
12
|
+
'use strict';
|
13
|
+
|
14
|
+
if (!Date.now) {
|
15
|
+
Date.now = function() { return new Date().getTime(); };
|
16
|
+
}
|
17
|
+
|
18
|
+
var vendors = ['webkit', 'moz'];
|
19
|
+
for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
|
20
|
+
var vp = vendors[i];
|
21
|
+
window.requestAnimationFrame = window[vp + 'RequestAnimationFrame'];
|
22
|
+
window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] ||
|
23
|
+
window[vp + 'CancelRequestAnimationFrame']);
|
24
|
+
}
|
25
|
+
|
26
|
+
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
|
27
|
+
var lastTime = 0;
|
28
|
+
window.requestAnimationFrame = function(callback) {
|
29
|
+
var now = Date.now();
|
30
|
+
var nextTime = Math.max(lastTime + 16, now);
|
31
|
+
return setTimeout(function() { callback(lastTime = nextTime); },
|
32
|
+
nextTime - now);
|
33
|
+
};
|
34
|
+
window.cancelAnimationFrame = clearTimeout;
|
35
|
+
}
|
36
|
+
|
37
|
+
})();
|
38
|
+
|
@@ -0,0 +1,257 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* Copyright 2015 Google Inc. All Rights Reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Class constructor for Radio MDL component.
|
20
|
+
* Implements MDL component design pattern defined at:
|
21
|
+
* https://github.com/jasonmayes/mdl-component-design-pattern
|
22
|
+
* @param {HTMLElement} element The element that will be upgraded.
|
23
|
+
*/
|
24
|
+
function MaterialRadio(element) {
|
25
|
+
'use strict';
|
26
|
+
|
27
|
+
this.element_ = element;
|
28
|
+
|
29
|
+
// Initialize instance.
|
30
|
+
this.init();
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Store constants in one place so they can be updated easily.
|
35
|
+
* @enum {string | number}
|
36
|
+
* @private
|
37
|
+
*/
|
38
|
+
MaterialRadio.prototype.Constant_ = {
|
39
|
+
TINY_TIMEOUT: 0.001
|
40
|
+
};
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Store strings for class names defined by this component that are used in
|
44
|
+
* JavaScript. This allows us to simply change it in one place should we
|
45
|
+
* decide to modify at a later date.
|
46
|
+
* @enum {string}
|
47
|
+
* @private
|
48
|
+
*/
|
49
|
+
MaterialRadio.prototype.CssClasses_ = {
|
50
|
+
IS_FOCUSED: 'is-focused',
|
51
|
+
IS_DISABLED: 'is-disabled',
|
52
|
+
IS_CHECKED: 'is-checked',
|
53
|
+
IS_UPGRADED: 'is-upgraded',
|
54
|
+
JS_RADIO: 'mdl-js-radio',
|
55
|
+
RADIO_BTN: 'mdl-radio__button',
|
56
|
+
RADIO_OUTER_CIRCLE: 'mdl-radio__outer-circle',
|
57
|
+
RADIO_INNER_CIRCLE: 'mdl-radio__inner-circle',
|
58
|
+
RIPPLE_EFFECT: 'mdl-js-ripple-effect',
|
59
|
+
RIPPLE_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
|
60
|
+
RIPPLE_CONTAINER: 'mdl-radio__ripple-container',
|
61
|
+
RIPPLE_CENTER: 'mdl-ripple--center',
|
62
|
+
RIPPLE: 'mdl-ripple'
|
63
|
+
};
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Handle change of state.
|
67
|
+
* @param {Event} event The event that fired.
|
68
|
+
* @private
|
69
|
+
*/
|
70
|
+
MaterialRadio.prototype.onChange_ = function(event) {
|
71
|
+
'use strict';
|
72
|
+
|
73
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
74
|
+
|
75
|
+
// Since other radio buttons don't get change events, we need to look for
|
76
|
+
// them to update their classes.
|
77
|
+
var radios = document.getElementsByClassName(this.CssClasses_.JS_RADIO);
|
78
|
+
for (var i = 0; i < radios.length; i++) {
|
79
|
+
var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN);
|
80
|
+
// Different name == different group, so no point updating those.
|
81
|
+
if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) {
|
82
|
+
this.updateClasses_(button, radios[i]);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Handle focus.
|
89
|
+
* @param {Event} event The event that fired.
|
90
|
+
* @private
|
91
|
+
*/
|
92
|
+
MaterialRadio.prototype.onFocus_ = function(event) {
|
93
|
+
'use strict';
|
94
|
+
|
95
|
+
this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
|
96
|
+
};
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Handle lost focus.
|
100
|
+
* @param {Event} event The event that fired.
|
101
|
+
* @private
|
102
|
+
*/
|
103
|
+
MaterialRadio.prototype.onBlur_ = function(event) {
|
104
|
+
'use strict';
|
105
|
+
|
106
|
+
this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
|
107
|
+
};
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Handle mouseup.
|
111
|
+
* @param {Event} event The event that fired.
|
112
|
+
* @private
|
113
|
+
*/
|
114
|
+
MaterialRadio.prototype.onMouseup_ = function(event) {
|
115
|
+
'use strict';
|
116
|
+
|
117
|
+
this.blur_();
|
118
|
+
};
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Update classes.
|
122
|
+
* @param {HTMLElement} button The button whose classes we should update.
|
123
|
+
* @param {HTMLElement} label The label whose classes we should update.
|
124
|
+
* @private
|
125
|
+
*/
|
126
|
+
MaterialRadio.prototype.updateClasses_ = function(button, label) {
|
127
|
+
'use strict';
|
128
|
+
|
129
|
+
if (button.disabled) {
|
130
|
+
label.classList.add(this.CssClasses_.IS_DISABLED);
|
131
|
+
} else {
|
132
|
+
label.classList.remove(this.CssClasses_.IS_DISABLED);
|
133
|
+
}
|
134
|
+
|
135
|
+
if (button.checked) {
|
136
|
+
label.classList.add(this.CssClasses_.IS_CHECKED);
|
137
|
+
} else {
|
138
|
+
label.classList.remove(this.CssClasses_.IS_CHECKED);
|
139
|
+
}
|
140
|
+
};
|
141
|
+
|
142
|
+
/**
|
143
|
+
* Add blur.
|
144
|
+
* @private
|
145
|
+
*/
|
146
|
+
MaterialRadio.prototype.blur_ = function(event) {
|
147
|
+
'use strict';
|
148
|
+
|
149
|
+
// TODO: figure out why there's a focus event being fired after our blur,
|
150
|
+
// so that we can avoid this hack.
|
151
|
+
window.setTimeout(function() {
|
152
|
+
this.btnElement_.blur();
|
153
|
+
}.bind(this), this.Constant_.TINY_TIMEOUT);
|
154
|
+
};
|
155
|
+
|
156
|
+
// Public methods.
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Disable radio.
|
160
|
+
* @public
|
161
|
+
*/
|
162
|
+
MaterialRadio.prototype.disable = function() {
|
163
|
+
'use strict';
|
164
|
+
|
165
|
+
this.btnElement_.disabled = true;
|
166
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
167
|
+
};
|
168
|
+
|
169
|
+
/**
|
170
|
+
* Enable radio.
|
171
|
+
* @public
|
172
|
+
*/
|
173
|
+
MaterialRadio.prototype.enable = function() {
|
174
|
+
'use strict';
|
175
|
+
|
176
|
+
this.btnElement_.disabled = false;
|
177
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
178
|
+
};
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Check radio.
|
182
|
+
* @public
|
183
|
+
*/
|
184
|
+
MaterialRadio.prototype.check = function() {
|
185
|
+
'use strict';
|
186
|
+
|
187
|
+
this.btnElement_.checked = true;
|
188
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
189
|
+
};
|
190
|
+
|
191
|
+
/**
|
192
|
+
* Uncheck radio.
|
193
|
+
* @public
|
194
|
+
*/
|
195
|
+
MaterialRadio.prototype.uncheck = function() {
|
196
|
+
'use strict';
|
197
|
+
|
198
|
+
this.btnElement_.checked = false;
|
199
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
200
|
+
};
|
201
|
+
|
202
|
+
/**
|
203
|
+
* Initialize element.
|
204
|
+
*/
|
205
|
+
MaterialRadio.prototype.init = function() {
|
206
|
+
'use strict';
|
207
|
+
|
208
|
+
if (this.element_) {
|
209
|
+
this.btnElement_ = this.element_.querySelector('.' +
|
210
|
+
this.CssClasses_.RADIO_BTN);
|
211
|
+
|
212
|
+
var outerCircle = document.createElement('span');
|
213
|
+
outerCircle.classList.add(this.CssClasses_.RADIO_OUTER_CIRCLE);
|
214
|
+
|
215
|
+
var innerCircle = document.createElement('span');
|
216
|
+
innerCircle.classList.add(this.CssClasses_.RADIO_INNER_CIRCLE);
|
217
|
+
|
218
|
+
this.element_.appendChild(outerCircle);
|
219
|
+
this.element_.appendChild(innerCircle);
|
220
|
+
|
221
|
+
var rippleContainer;
|
222
|
+
if (this.element_.classList.contains(
|
223
|
+
this.CssClasses_.RIPPLE_EFFECT)) {
|
224
|
+
this.element_.classList.add(
|
225
|
+
this.CssClasses_.RIPPLE_IGNORE_EVENTS);
|
226
|
+
rippleContainer = document.createElement('span');
|
227
|
+
rippleContainer.classList.add(
|
228
|
+
this.CssClasses_.RIPPLE_CONTAINER);
|
229
|
+
rippleContainer.classList.add(this.CssClasses_.RIPPLE_EFFECT);
|
230
|
+
rippleContainer.classList.add(this.CssClasses_.RIPPLE_CENTER);
|
231
|
+
rippleContainer.addEventListener('mouseup', this.onMouseup_.bind(this));
|
232
|
+
|
233
|
+
var ripple = document.createElement('span');
|
234
|
+
ripple.classList.add(this.CssClasses_.RIPPLE);
|
235
|
+
|
236
|
+
rippleContainer.appendChild(ripple);
|
237
|
+
this.element_.appendChild(rippleContainer);
|
238
|
+
}
|
239
|
+
|
240
|
+
this.btnElement_.addEventListener('change', this.onChange_.bind(this));
|
241
|
+
this.btnElement_.addEventListener('focus', this.onFocus_.bind(this));
|
242
|
+
this.btnElement_.addEventListener('blur', this.onBlur_.bind(this));
|
243
|
+
this.element_.addEventListener('mouseup', this.onMouseup_.bind(this));
|
244
|
+
|
245
|
+
this.updateClasses_(this.btnElement_, this.element_);
|
246
|
+
this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
|
247
|
+
}
|
248
|
+
};
|
249
|
+
|
250
|
+
// The component registers itself. It can assume componentHandler is available
|
251
|
+
// in the global scope.
|
252
|
+
componentHandler.register({
|
253
|
+
constructor: MaterialRadio,
|
254
|
+
classAsString: 'MaterialRadio',
|
255
|
+
cssClass: 'mdl-js-radio',
|
256
|
+
widget: true
|
257
|
+
});
|
@@ -0,0 +1,244 @@
|
|
1
|
+
/**
|
2
|
+
* @license
|
3
|
+
* Copyright 2015 Google Inc. All Rights Reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* You may obtain a copy of the License at
|
8
|
+
*
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
*
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
* See the License for the specific language governing permissions and
|
15
|
+
* limitations under the License.
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Class constructor for Ripple MDL component.
|
20
|
+
* Implements MDL component design pattern defined at:
|
21
|
+
* https://github.com/jasonmayes/mdl-component-design-pattern
|
22
|
+
* @param {HTMLElement} element The element that will be upgraded.
|
23
|
+
*/
|
24
|
+
function MaterialRipple(element) {
|
25
|
+
'use strict';
|
26
|
+
|
27
|
+
this.element_ = element;
|
28
|
+
|
29
|
+
// Initialize instance.
|
30
|
+
this.init();
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Store constants in one place so they can be updated easily.
|
35
|
+
* @enum {string | number}
|
36
|
+
* @private
|
37
|
+
*/
|
38
|
+
MaterialRipple.prototype.Constant_ = {
|
39
|
+
INITIAL_SCALE: 'scale(0.0001, 0.0001)',
|
40
|
+
INITIAL_SIZE: '1px',
|
41
|
+
INITIAL_OPACITY: '0.4',
|
42
|
+
FINAL_OPACITY: '0',
|
43
|
+
FINAL_SCALE: ''
|
44
|
+
};
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Store strings for class names defined by this component that are used in
|
48
|
+
* JavaScript. This allows us to simply change it in one place should we
|
49
|
+
* decide to modify at a later date.
|
50
|
+
* @enum {string}
|
51
|
+
* @private
|
52
|
+
*/
|
53
|
+
MaterialRipple.prototype.CssClasses_ = {
|
54
|
+
RIPPLE_CENTER: 'mdl-ripple--center',
|
55
|
+
RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events',
|
56
|
+
RIPPLE: 'mdl-ripple',
|
57
|
+
IS_ANIMATING: 'is-animating',
|
58
|
+
IS_VISIBLE: 'is-visible'
|
59
|
+
};
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Handle mouse / finger down on element.
|
63
|
+
* @param {Event} event The event that fired.
|
64
|
+
* @private
|
65
|
+
*/
|
66
|
+
MaterialRipple.prototype.downHandler_ = function(event) {
|
67
|
+
'use strict';
|
68
|
+
|
69
|
+
if (!this.rippleElement_.style.width && !this.rippleElement_.style.height) {
|
70
|
+
var rect = this.element_.getBoundingClientRect();
|
71
|
+
this.boundHeight = rect.height;
|
72
|
+
this.boundWidth = rect.width;
|
73
|
+
this.rippleSize_ = Math.sqrt(rect.width * rect.width +
|
74
|
+
rect.height * rect.height) * 2 + 2;
|
75
|
+
this.rippleElement_.style.width = this.rippleSize_ + 'px';
|
76
|
+
this.rippleElement_.style.height = this.rippleSize_ + 'px';
|
77
|
+
}
|
78
|
+
|
79
|
+
this.rippleElement_.classList.add(this.CssClasses_.IS_VISIBLE);
|
80
|
+
|
81
|
+
if (event.type === 'mousedown' && this.ignoringMouseDown_) {
|
82
|
+
this.ignoringMouseDown_ = false;
|
83
|
+
} else {
|
84
|
+
if (event.type === 'touchstart') {
|
85
|
+
this.ignoringMouseDown_ = true;
|
86
|
+
}
|
87
|
+
var frameCount = this.getFrameCount();
|
88
|
+
if (frameCount > 0) {
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
this.setFrameCount(1);
|
92
|
+
var bound = event.currentTarget.getBoundingClientRect();
|
93
|
+
var x;
|
94
|
+
var y;
|
95
|
+
// Check if we are handling a keyboard click.
|
96
|
+
if (event.clientX === 0 && event.clientY === 0) {
|
97
|
+
x = Math.round(bound.width / 2);
|
98
|
+
y = Math.round(bound.height / 2);
|
99
|
+
} else {
|
100
|
+
var clientX = event.clientX ? event.clientX : event.touches[0].clientX;
|
101
|
+
var clientY = event.clientY ? event.clientY : event.touches[0].clientY;
|
102
|
+
x = Math.round(clientX - bound.left);
|
103
|
+
y = Math.round(clientY - bound.top);
|
104
|
+
}
|
105
|
+
this.setRippleXY(x, y);
|
106
|
+
this.setRippleStyles(true);
|
107
|
+
window.requestAnimationFrame(this.animFrameHandler.bind(this));
|
108
|
+
}
|
109
|
+
};
|
110
|
+
|
111
|
+
/**
|
112
|
+
* Handle mouse / finger up on element.
|
113
|
+
* @param {Event} event The event that fired.
|
114
|
+
* @private
|
115
|
+
*/
|
116
|
+
MaterialRipple.prototype.upHandler_ = function(event) {
|
117
|
+
'use strict';
|
118
|
+
|
119
|
+
// Don't fire for the artificial "mouseup" generated by a double-click.
|
120
|
+
if (event && event.detail !== 2) {
|
121
|
+
this.rippleElement_.classList.remove(this.CssClasses_.IS_VISIBLE);
|
122
|
+
}
|
123
|
+
};
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Initialize element.
|
127
|
+
*/
|
128
|
+
MaterialRipple.prototype.init = function() {
|
129
|
+
'use strict';
|
130
|
+
|
131
|
+
if (this.element_) {
|
132
|
+
var recentering =
|
133
|
+
this.element_.classList.contains(this.CssClasses_.RIPPLE_CENTER);
|
134
|
+
if (!this.element_.classList.contains(
|
135
|
+
this.CssClasses_.RIPPLE_EFFECT_IGNORE_EVENTS)) {
|
136
|
+
this.rippleElement_ = this.element_.querySelector('.' +
|
137
|
+
this.CssClasses_.RIPPLE);
|
138
|
+
this.frameCount_ = 0;
|
139
|
+
this.rippleSize_ = 0;
|
140
|
+
this.x_ = 0;
|
141
|
+
this.y_ = 0;
|
142
|
+
|
143
|
+
// Touch start produces a compat mouse down event, which would cause a
|
144
|
+
// second ripples. To avoid that, we use this property to ignore the first
|
145
|
+
// mouse down after a touch start.
|
146
|
+
this.ignoringMouseDown_ = false;
|
147
|
+
|
148
|
+
this.boundDownHandler = this.downHandler_.bind(this);
|
149
|
+
this.element_.addEventListener('mousedown',
|
150
|
+
this.boundDownHandler);
|
151
|
+
this.element_.addEventListener('touchstart',
|
152
|
+
this.boundDownHandler);
|
153
|
+
|
154
|
+
this.boundUpHandler = this.upHandler_.bind(this);
|
155
|
+
this.element_.addEventListener('mouseup', this.boundUpHandler);
|
156
|
+
this.element_.addEventListener('mouseleave', this.boundUpHandler);
|
157
|
+
this.element_.addEventListener('touchend', this.boundUpHandler);
|
158
|
+
this.element_.addEventListener('blur', this.boundUpHandler);
|
159
|
+
|
160
|
+
this.getFrameCount = function() {
|
161
|
+
return this.frameCount_;
|
162
|
+
};
|
163
|
+
|
164
|
+
this.setFrameCount = function(fC) {
|
165
|
+
this.frameCount_ = fC;
|
166
|
+
};
|
167
|
+
|
168
|
+
this.getRippleElement = function() {
|
169
|
+
return this.rippleElement_;
|
170
|
+
};
|
171
|
+
|
172
|
+
this.setRippleXY = function(newX, newY) {
|
173
|
+
this.x_ = newX;
|
174
|
+
this.y_ = newY;
|
175
|
+
};
|
176
|
+
|
177
|
+
this.setRippleStyles = function(start) {
|
178
|
+
if (this.rippleElement_ !== null) {
|
179
|
+
var transformString;
|
180
|
+
var scale;
|
181
|
+
var size;
|
182
|
+
var offset = 'translate(' + this.x_ + 'px, ' + this.y_ + 'px)';
|
183
|
+
|
184
|
+
if (start) {
|
185
|
+
scale = this.Constant_.INITIAL_SCALE;
|
186
|
+
size = this.Constant_.INITIAL_SIZE;
|
187
|
+
} else {
|
188
|
+
scale = this.Constant_.FINAL_SCALE;
|
189
|
+
size = this.rippleSize_ + 'px';
|
190
|
+
if (recentering) {
|
191
|
+
offset = 'translate(' + this.boundWidth / 2 + 'px, ' +
|
192
|
+
this.boundHeight / 2 + 'px)';
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
transformString = 'translate(-50%, -50%) ' + offset + scale;
|
197
|
+
|
198
|
+
this.rippleElement_.style.webkitTransform = transformString;
|
199
|
+
this.rippleElement_.style.msTransform = transformString;
|
200
|
+
this.rippleElement_.style.transform = transformString;
|
201
|
+
|
202
|
+
if (start) {
|
203
|
+
this.rippleElement_.classList.remove(this.CssClasses_.IS_ANIMATING);
|
204
|
+
} else {
|
205
|
+
this.rippleElement_.classList.add(this.CssClasses_.IS_ANIMATING);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
};
|
209
|
+
|
210
|
+
this.animFrameHandler = function() {
|
211
|
+
if (this.frameCount_-- > 0) {
|
212
|
+
window.requestAnimationFrame(this.animFrameHandler.bind(this));
|
213
|
+
} else {
|
214
|
+
this.setRippleStyles(false);
|
215
|
+
}
|
216
|
+
};
|
217
|
+
}
|
218
|
+
}
|
219
|
+
};
|
220
|
+
|
221
|
+
/*
|
222
|
+
* Downgrade the component
|
223
|
+
*/
|
224
|
+
MaterialRipple.prototype.mdlDowngrade_ = function() {
|
225
|
+
'use strict';
|
226
|
+
this.element_.removeEventListener('mousedown',
|
227
|
+
this.boundDownHandler);
|
228
|
+
this.element_.removeEventListener('touchstart',
|
229
|
+
this.boundDownHandler);
|
230
|
+
|
231
|
+
this.element_.removeEventListener('mouseup', this.boundUpHandler);
|
232
|
+
this.element_.removeEventListener('mouseleave', this.boundUpHandler);
|
233
|
+
this.element_.removeEventListener('touchend', this.boundUpHandler);
|
234
|
+
this.element_.removeEventListener('blur', this.boundUpHandler);
|
235
|
+
};
|
236
|
+
|
237
|
+
// The component registers itself. It can assume componentHandler is available
|
238
|
+
// in the global scope.
|
239
|
+
componentHandler.register({
|
240
|
+
constructor: MaterialRipple,
|
241
|
+
classAsString: 'MaterialRipple',
|
242
|
+
cssClass: 'mdl-js-ripple-effect',
|
243
|
+
widget: false
|
244
|
+
});
|