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,152 @@
|
|
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 Tabs 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 MaterialTabs(element) {
|
25
|
+
'use strict';
|
26
|
+
|
27
|
+
// Stores the HTML element.
|
28
|
+
this.element_ = element;
|
29
|
+
|
30
|
+
// Initialize instance.
|
31
|
+
this.init();
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Store constants in one place so they can be updated easily.
|
36
|
+
* @enum {string}
|
37
|
+
* @private
|
38
|
+
*/
|
39
|
+
MaterialTabs.prototype.Constant_ = {
|
40
|
+
// None at the moment.
|
41
|
+
};
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Store strings for class names defined by this component that are used in
|
45
|
+
* JavaScript. This allows us to simply change it in one place should we
|
46
|
+
* decide to modify at a later date.
|
47
|
+
* @enum {string}
|
48
|
+
* @private
|
49
|
+
*/
|
50
|
+
MaterialTabs.prototype.CssClasses_ = {
|
51
|
+
TAB_CLASS: 'mdl-tabs__tab',
|
52
|
+
PANEL_CLASS: 'mdl-tabs__panel',
|
53
|
+
ACTIVE_CLASS: 'is-active',
|
54
|
+
UPGRADED_CLASS: 'is-upgraded',
|
55
|
+
|
56
|
+
MDL_JS_RIPPLE_EFFECT: 'mdl-js-ripple-effect',
|
57
|
+
MDL_RIPPLE_CONTAINER: 'mdl-tabs__ripple-container',
|
58
|
+
MDL_RIPPLE: 'mdl-ripple',
|
59
|
+
MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS: 'mdl-js-ripple-effect--ignore-events'
|
60
|
+
};
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Handle clicks to a tabs component
|
64
|
+
* @private
|
65
|
+
*/
|
66
|
+
MaterialTabs.prototype.initTabs_ = function(e) {
|
67
|
+
'use strict';
|
68
|
+
|
69
|
+
if (this.element_.classList.contains(this.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
|
70
|
+
this.element_.classList.add(
|
71
|
+
this.CssClasses_.MDL_JS_RIPPLE_EFFECT_IGNORE_EVENTS);
|
72
|
+
}
|
73
|
+
|
74
|
+
// Select element tabs, document panels
|
75
|
+
this.tabs_ = this.element_.querySelectorAll('.' + this.CssClasses_.TAB_CLASS);
|
76
|
+
this.panels_ =
|
77
|
+
this.element_.querySelectorAll('.' + this.CssClasses_.PANEL_CLASS);
|
78
|
+
|
79
|
+
// Create new tabs for each tab element
|
80
|
+
for (var i = 0; i < this.tabs_.length; i++) {
|
81
|
+
new MaterialTab(this.tabs_[i], this);
|
82
|
+
}
|
83
|
+
|
84
|
+
this.element_.classList.add(this.CssClasses_.UPGRADED_CLASS);
|
85
|
+
};
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Reset tab state, dropping active classes
|
89
|
+
* @private
|
90
|
+
*/
|
91
|
+
MaterialTabs.prototype.resetTabState_ = function() {
|
92
|
+
'use strict';
|
93
|
+
|
94
|
+
for (var k = 0; k < this.tabs_.length; k++) {
|
95
|
+
this.tabs_[k].classList.remove(this.CssClasses_.ACTIVE_CLASS);
|
96
|
+
}
|
97
|
+
};
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Reset panel state, droping active classes
|
101
|
+
* @private
|
102
|
+
*/
|
103
|
+
MaterialTabs.prototype.resetPanelState_ = function() {
|
104
|
+
'use strict';
|
105
|
+
|
106
|
+
for (var j = 0; j < this.panels_.length; j++) {
|
107
|
+
this.panels_[j].classList.remove(this.CssClasses_.ACTIVE_CLASS);
|
108
|
+
}
|
109
|
+
};
|
110
|
+
|
111
|
+
MaterialTabs.prototype.init = function() {
|
112
|
+
'use strict';
|
113
|
+
|
114
|
+
if (this.element_) {
|
115
|
+
this.initTabs_();
|
116
|
+
}
|
117
|
+
};
|
118
|
+
|
119
|
+
function MaterialTab(tab, ctx) {
|
120
|
+
'use strict';
|
121
|
+
|
122
|
+
if (tab) {
|
123
|
+
if (ctx.element_.classList.contains(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT)) {
|
124
|
+
var rippleContainer = document.createElement('span');
|
125
|
+
rippleContainer.classList.add(ctx.CssClasses_.MDL_RIPPLE_CONTAINER);
|
126
|
+
rippleContainer.classList.add(ctx.CssClasses_.MDL_JS_RIPPLE_EFFECT);
|
127
|
+
var ripple = document.createElement('span');
|
128
|
+
ripple.classList.add(ctx.CssClasses_.MDL_RIPPLE);
|
129
|
+
rippleContainer.appendChild(ripple);
|
130
|
+
tab.appendChild(rippleContainer);
|
131
|
+
}
|
132
|
+
|
133
|
+
tab.addEventListener('click', function(e) {
|
134
|
+
e.preventDefault();
|
135
|
+
var href = tab.href.split('#')[1];
|
136
|
+
var panel = ctx.element_.querySelector('#' + href);
|
137
|
+
ctx.resetTabState_();
|
138
|
+
ctx.resetPanelState_();
|
139
|
+
tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
|
140
|
+
panel.classList.add(ctx.CssClasses_.ACTIVE_CLASS);
|
141
|
+
});
|
142
|
+
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
// The component registers itself. It can assume componentHandler is available
|
147
|
+
// in the global scope.
|
148
|
+
componentHandler.register({
|
149
|
+
constructor: MaterialTabs,
|
150
|
+
classAsString: 'MaterialTabs',
|
151
|
+
cssClass: 'mdl-js-tabs'
|
152
|
+
});
|
@@ -0,0 +1,247 @@
|
|
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 Textfield 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 MaterialTextfield(element) {
|
25
|
+
'use strict';
|
26
|
+
|
27
|
+
this.element_ = element;
|
28
|
+
this.maxRows = this.Constant_.NO_MAX_ROWS;
|
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
|
+
MaterialTextfield.prototype.Constant_ = {
|
39
|
+
NO_MAX_ROWS: -1,
|
40
|
+
MAX_ROWS_ATTRIBUTE: 'maxrows'
|
41
|
+
};
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Store strings for class names defined by this component that are used in
|
45
|
+
* JavaScript. This allows us to simply change it in one place should we
|
46
|
+
* decide to modify at a later date.
|
47
|
+
* @enum {string}
|
48
|
+
* @private
|
49
|
+
*/
|
50
|
+
MaterialTextfield.prototype.CssClasses_ = {
|
51
|
+
LABEL: 'mdl-textfield__label',
|
52
|
+
INPUT: 'mdl-textfield__input',
|
53
|
+
IS_DIRTY: 'is-dirty',
|
54
|
+
IS_FOCUSED: 'is-focused',
|
55
|
+
IS_DISABLED: 'is-disabled',
|
56
|
+
IS_INVALID: 'is-invalid',
|
57
|
+
IS_UPGRADED: 'is-upgraded'
|
58
|
+
};
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Handle input being entered.
|
62
|
+
* @param {Event} event The event that fired.
|
63
|
+
* @private
|
64
|
+
*/
|
65
|
+
MaterialTextfield.prototype.onKeyDown_ = function(event) {
|
66
|
+
'use strict';
|
67
|
+
|
68
|
+
var currentRowCount = event.target.value.split('\n').length;
|
69
|
+
if (event.keyCode === 13) {
|
70
|
+
if (currentRowCount >= this.maxRows) {
|
71
|
+
event.preventDefault();
|
72
|
+
}
|
73
|
+
}
|
74
|
+
};
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Handle focus.
|
78
|
+
* @param {Event} event The event that fired.
|
79
|
+
* @private
|
80
|
+
*/
|
81
|
+
MaterialTextfield.prototype.onFocus_ = function(event) {
|
82
|
+
'use strict';
|
83
|
+
|
84
|
+
this.element_.classList.add(this.CssClasses_.IS_FOCUSED);
|
85
|
+
};
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Handle lost focus.
|
89
|
+
* @param {Event} event The event that fired.
|
90
|
+
* @private
|
91
|
+
*/
|
92
|
+
MaterialTextfield.prototype.onBlur_ = function(event) {
|
93
|
+
'use strict';
|
94
|
+
|
95
|
+
this.element_.classList.remove(this.CssClasses_.IS_FOCUSED);
|
96
|
+
};
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Handle class updates.
|
100
|
+
* @param {HTMLElement} button The button whose classes we should update.
|
101
|
+
* @param {HTMLElement} label The label whose classes we should update.
|
102
|
+
* @private
|
103
|
+
*/
|
104
|
+
MaterialTextfield.prototype.updateClasses_ = function() {
|
105
|
+
'use strict';
|
106
|
+
this.checkDisabled();
|
107
|
+
this.checkValidity();
|
108
|
+
this.checkDirty();
|
109
|
+
};
|
110
|
+
|
111
|
+
// Public methods.
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Check the disabled state and update field accordingly.
|
115
|
+
* @public
|
116
|
+
*/
|
117
|
+
MaterialTextfield.prototype.checkDisabled = function() {
|
118
|
+
'use strict';
|
119
|
+
if (this.input_.disabled) {
|
120
|
+
this.element_.classList.add(this.CssClasses_.IS_DISABLED);
|
121
|
+
} else {
|
122
|
+
this.element_.classList.remove(this.CssClasses_.IS_DISABLED);
|
123
|
+
}
|
124
|
+
};
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Check the validity state and update field accordingly.
|
128
|
+
* @public
|
129
|
+
*/
|
130
|
+
MaterialTextfield.prototype.checkValidity = function() {
|
131
|
+
'use strict';
|
132
|
+
if (this.input_.validity.valid) {
|
133
|
+
this.element_.classList.remove(this.CssClasses_.IS_INVALID);
|
134
|
+
} else {
|
135
|
+
this.element_.classList.add(this.CssClasses_.IS_INVALID);
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
/**
|
140
|
+
* Check the dirty state and update field accordingly.
|
141
|
+
* @public
|
142
|
+
*/
|
143
|
+
MaterialTextfield.prototype.checkDirty = function() {
|
144
|
+
'use strict';
|
145
|
+
if (this.input_.value && this.input_.value.length > 0) {
|
146
|
+
this.element_.classList.add(this.CssClasses_.IS_DIRTY);
|
147
|
+
} else {
|
148
|
+
this.element_.classList.remove(this.CssClasses_.IS_DIRTY);
|
149
|
+
}
|
150
|
+
};
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Disable text field.
|
154
|
+
* @public
|
155
|
+
*/
|
156
|
+
MaterialTextfield.prototype.disable = function() {
|
157
|
+
'use strict';
|
158
|
+
|
159
|
+
this.input_.disabled = true;
|
160
|
+
this.updateClasses_();
|
161
|
+
};
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Enable text field.
|
165
|
+
* @public
|
166
|
+
*/
|
167
|
+
MaterialTextfield.prototype.enable = function() {
|
168
|
+
'use strict';
|
169
|
+
|
170
|
+
this.input_.disabled = false;
|
171
|
+
this.updateClasses_();
|
172
|
+
};
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Update text field value.
|
176
|
+
* @param {String} value The value to which to set the control (optional).
|
177
|
+
* @public
|
178
|
+
*/
|
179
|
+
MaterialTextfield.prototype.change = function(value) {
|
180
|
+
'use strict';
|
181
|
+
|
182
|
+
if (value) {
|
183
|
+
this.input_.value = value;
|
184
|
+
}
|
185
|
+
this.updateClasses_();
|
186
|
+
};
|
187
|
+
|
188
|
+
/**
|
189
|
+
* Initialize element.
|
190
|
+
*/
|
191
|
+
MaterialTextfield.prototype.init = function() {
|
192
|
+
'use strict';
|
193
|
+
|
194
|
+
if (this.element_) {
|
195
|
+
this.label_ = this.element_.querySelector('.' + this.CssClasses_.LABEL);
|
196
|
+
this.input_ = this.element_.querySelector('.' + this.CssClasses_.INPUT);
|
197
|
+
|
198
|
+
if (this.input_) {
|
199
|
+
if (this.input_.hasAttribute(this.Constant_.MAX_ROWS_ATTRIBUTE)) {
|
200
|
+
this.maxRows = parseInt(this.input_.getAttribute(
|
201
|
+
this.Constant_.MAX_ROWS_ATTRIBUTE), 10);
|
202
|
+
if (isNaN(this.maxRows)) {
|
203
|
+
this.maxRows = this.Constant_.NO_MAX_ROWS;
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
this.boundUpdateClassesHandler = this.updateClasses_.bind(this);
|
208
|
+
this.boundFocusHandler = this.onFocus_.bind(this);
|
209
|
+
this.boundBlurHandler = this.onBlur_.bind(this);
|
210
|
+
this.input_.addEventListener('input', this.boundUpdateClassesHandler);
|
211
|
+
this.input_.addEventListener('focus', this.boundFocusHandler);
|
212
|
+
this.input_.addEventListener('blur', this.boundBlurHandler);
|
213
|
+
|
214
|
+
if (this.maxRows !== this.Constant_.NO_MAX_ROWS) {
|
215
|
+
// TODO: This should handle pasting multi line text.
|
216
|
+
// Currently doesn't.
|
217
|
+
this.boundKeyDownHandler = this.onKeyDown_.bind(this);
|
218
|
+
this.input_.addEventListener('keydown', this.boundKeyDownHandler);
|
219
|
+
}
|
220
|
+
|
221
|
+
this.updateClasses_();
|
222
|
+
this.element_.classList.add(this.CssClasses_.IS_UPGRADED);
|
223
|
+
}
|
224
|
+
}
|
225
|
+
};
|
226
|
+
|
227
|
+
/*
|
228
|
+
* Downgrade the component
|
229
|
+
*/
|
230
|
+
MaterialTextfield.prototype.mdlDowngrade_ = function() {
|
231
|
+
'use strict';
|
232
|
+
this.input_.removeEventListener('input', this.boundUpdateClassesHandler);
|
233
|
+
this.input_.removeEventListener('focus', this.boundFocusHandler);
|
234
|
+
this.input_.removeEventListener('blur', this.boundBlurHandler);
|
235
|
+
if (this.boundKeyDownHandler) {
|
236
|
+
this.input_.removeEventListener('keydown', this.boundKeyDownHandler);
|
237
|
+
}
|
238
|
+
};
|
239
|
+
|
240
|
+
// The component registers itself. It can assume componentHandler is available
|
241
|
+
// in the global scope.
|
242
|
+
componentHandler.register({
|
243
|
+
constructor: MaterialTextfield,
|
244
|
+
classAsString: 'MaterialTextfield',
|
245
|
+
cssClass: 'mdl-js-textfield',
|
246
|
+
widget: true
|
247
|
+
});
|
@@ -0,0 +1,146 @@
|
|
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 Tooltip 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 MaterialTooltip(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
|
+
MaterialTooltip.prototype.Constant_ = {
|
39
|
+
// None for now.
|
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
|
+
MaterialTooltip.prototype.CssClasses_ = {
|
50
|
+
IS_ACTIVE: 'is-active'
|
51
|
+
};
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Handle mouseenter for tooltip.
|
55
|
+
* @param {Event} event The event that fired.
|
56
|
+
* @private
|
57
|
+
*/
|
58
|
+
MaterialTooltip.prototype.handleMouseEnter_ = function(event) {
|
59
|
+
'use strict';
|
60
|
+
|
61
|
+
event.stopPropagation();
|
62
|
+
var props = event.target.getBoundingClientRect();
|
63
|
+
var left = props.left + (props.width / 2);
|
64
|
+
var marginLeft = -1 * (this.element_.offsetWidth / 2);
|
65
|
+
|
66
|
+
if (left + marginLeft < 0) {
|
67
|
+
this.element_.style.left = 0;
|
68
|
+
this.element_.style.marginLeft = 0;
|
69
|
+
} else {
|
70
|
+
this.element_.style.left = left + 'px';
|
71
|
+
this.element_.style.marginLeft = marginLeft + 'px';
|
72
|
+
}
|
73
|
+
|
74
|
+
this.element_.style.top = props.top + props.height + 10 + 'px';
|
75
|
+
this.element_.classList.add(this.CssClasses_.IS_ACTIVE);
|
76
|
+
window.addEventListener('scroll', this.boundMouseLeaveHandler, false);
|
77
|
+
window.addEventListener('touchmove', this.boundMouseLeaveHandler, false);
|
78
|
+
};
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Handle mouseleave for tooltip.
|
82
|
+
* @param {Event} event The event that fired.
|
83
|
+
* @private
|
84
|
+
*/
|
85
|
+
MaterialTooltip.prototype.handleMouseLeave_ = function(event) {
|
86
|
+
'use strict';
|
87
|
+
|
88
|
+
event.stopPropagation();
|
89
|
+
this.element_.classList.remove(this.CssClasses_.IS_ACTIVE);
|
90
|
+
window.removeEventListener('scroll', this.boundMouseLeaveHandler);
|
91
|
+
window.removeEventListener('touchmove', this.boundMouseLeaveHandler, false);
|
92
|
+
};
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Initialize element.
|
96
|
+
*/
|
97
|
+
MaterialTooltip.prototype.init = function() {
|
98
|
+
'use strict';
|
99
|
+
|
100
|
+
if (this.element_) {
|
101
|
+
var forElId = this.element_.getAttribute('for');
|
102
|
+
|
103
|
+
if (forElId) {
|
104
|
+
this.forElement_ = document.getElementById(forElId);
|
105
|
+
}
|
106
|
+
|
107
|
+
if (this.forElement_) {
|
108
|
+
// Tabindex needs to be set for `blur` events to be emitted
|
109
|
+
if (!this.forElement_.getAttribute('tabindex')) {
|
110
|
+
this.forElement_.setAttribute('tabindex', '0');
|
111
|
+
}
|
112
|
+
|
113
|
+
this.boundMouseEnterHandler = this.handleMouseEnter_.bind(this);
|
114
|
+
this.boundMouseLeaveHandler = this.handleMouseLeave_.bind(this);
|
115
|
+
this.forElement_.addEventListener('mouseenter', this.boundMouseEnterHandler,
|
116
|
+
false);
|
117
|
+
this.forElement_.addEventListener('click', this.boundMouseEnterHandler,
|
118
|
+
false);
|
119
|
+
this.forElement_.addEventListener('blur', this.boundMouseLeaveHandler);
|
120
|
+
this.forElement_.addEventListener('touchstart', this.boundMouseEnterHandler,
|
121
|
+
false);
|
122
|
+
this.forElement_.addEventListener('mouseleave', this.boundMouseLeaveHandler);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
};
|
126
|
+
|
127
|
+
/*
|
128
|
+
* Downgrade the component
|
129
|
+
*/
|
130
|
+
MaterialTooltip.prototype.mdlDowngrade_ = function() {
|
131
|
+
'use strict';
|
132
|
+
if (this.forElement_) {
|
133
|
+
this.forElement_.removeEventListener('mouseenter', this.boundMouseEnterHandler, false);
|
134
|
+
this.forElement_.removeEventListener('click', this.boundMouseEnterHandler, false);
|
135
|
+
this.forElement_.removeEventListener('touchstart', this.boundMouseEnterHandler, false);
|
136
|
+
this.forElement_.removeEventListener('mouseleave', this.boundMouseLeaveHandler);
|
137
|
+
}
|
138
|
+
};
|
139
|
+
|
140
|
+
// The component registers itself. It can assume componentHandler is available
|
141
|
+
// in the global scope.
|
142
|
+
componentHandler.register({
|
143
|
+
constructor: MaterialTooltip,
|
144
|
+
classAsString: 'MaterialTooltip',
|
145
|
+
cssClass: 'mdl-tooltip'
|
146
|
+
});
|