mui-sass 0.4.2 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f47ba598013f481e02209323035f2b303241f1a
4
- data.tar.gz: ff59616b87976e183c4d138eaf4cad95fe1dfce5
3
+ metadata.gz: a2050f12dddeda8e3aef97f97647c8b68fb34404
4
+ data.tar.gz: 44f610c26efabbfcb61d9a9905a44c0852e0f2f9
5
5
  SHA512:
6
- metadata.gz: d6539d5ac8a3d0af8b8f64ed66b5c29c397eb4194a89471cd067d0a4e8ca759cafb1cf5632e2caefe416095e1d398012aff8f3bf492880181264ecadc3c11edc
7
- data.tar.gz: b8cb42a20da6d239c73a602f4a3874d7b91dc2518705003de835c756e2fe5d223e17bacb0bc03c2d984e5fd32cd8b6f97ab716cb620488d34f846736190a5260
6
+ metadata.gz: 24bb2735dfa831635f9cddc1fc6ca9e6a123472cd52907cc8303371087fab6812bea871d88d17d34b3450d0598867736a4822e2d00bc6052c2591907dd08519c
7
+ data.tar.gz: 469bd855a4955bd3d67bbf289b68efd11d4c8c29da22b85338b3a1c14d2d76d0bf8f806f893672f4e29a8e8376b20fc39f21337d0e7b9f3ac1e093b9689a18d4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.4.7 (2016-03-02)
2
+
3
+ - Update assets to match upstream version
4
+
5
+ Framework version: MUI v0.4.7
6
+
1
7
  ## 0.4.2 (2016-02-05)
2
8
 
3
9
  - Update assets to match upstream version
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  `mui-sass` is a Sass-powered version of MUI framework for your applications. It works with Ruby on Rails, Compass, Sprockets, etc.
9
9
 
10
- `mui-sass` allows to include MUI framework CSS and JavaScript components. HTML Email, React, WebComponents and Design Files are not included.
10
+ `mui-sass` allows to include MUI framework Sass and JavaScript components. React, Angular, HTML Email, WebComponents are not included.
11
11
 
12
12
  ## Installation
13
13
 
@@ -89,31 +89,38 @@ You can also import individual Sass components.
89
89
  First you need to include core components:
90
90
 
91
91
  ```scss
92
- @import 'mui/normalize-3.0.2';
92
+ // Normalizer
93
+ @import "mui/normalize-3.0.3";
94
+ // Core variables and mixins
93
95
  @import 'mui/colors';
94
96
  @import 'mui/variables';
95
97
  @import 'mui/mixins';
98
+ // CSS Reboot
99
+ @import "mui/reboot";
96
100
  ```
97
101
 
98
102
  Then include desired Sass component:
99
103
 
100
104
  ```scss
101
- @import 'mui/appbar';
102
- @import 'mui/buttons';
103
- @import 'mui/dividers';
104
- @import 'mui/dropdowns';
105
- @import 'mui/forms';
106
- @import 'mui/grid';
107
- @import 'mui/helpers';
108
- @import 'mui/layout';
109
- @import 'mui/overlay';
110
- @import 'mui/panel';
111
- @import 'mui/ripple';
112
- @import 'mui/scaffolding';
113
- @import 'mui/semantic-markup';
114
- @import 'mui/tables';
115
- @import 'mui/tabs';
116
- @import 'mui/typography';
105
+ // Components
106
+ @import "mui/appbar";
107
+ @import "mui/buttons";
108
+ @import "mui/checkbox-and-radio";
109
+ @import "mui/containers";
110
+ @import "mui/divider";
111
+ @import "mui/dropdown";
112
+ @import "mui/form";
113
+ @import "mui/grid";
114
+ @import "mui/panel";
115
+ @import "mui/select";
116
+ @import "mui/table";
117
+ @import "mui/tabs";
118
+ @import "mui/textfield";
119
+ // Miscellaneous
120
+ @import "mui/helpers";
121
+ @import "mui/overlay";
122
+ @import "mui/ripple";
123
+ @import "mui/typography";
117
124
  ```
118
125
 
119
126
  ### Variables
@@ -129,7 +136,7 @@ $mui-base-font-size: 16px !default;
129
136
 
130
137
  ## Versioning
131
138
 
132
- MUI for Sass follows the upstream version of MUI framework. But last version number may be ahead, in case there is a need to release project specific changes.
139
+ MUI for Sass follows the upstream version of MUI framework, but last version number may be ahead, in case there is a need to release project specific changes. Some upstream versions may be skipped if they include no Sass/JavaScript related changes.
133
140
 
134
141
  Please always refer to the [CHANGELOG](https://github.com/rubysamurai/mui-sass/blob/master/CHANGELOG.md) when upgrading.
135
142
 
@@ -1,5 +1,5 @@
1
1
  module Mui
2
2
  module Sass
3
- VERSION = '0.4.2'
3
+ VERSION = '0.4.7'
4
4
  end
5
5
  end
@@ -13,12 +13,12 @@
13
13
 
14
14
  // load dependencies
15
15
  var jqLite = require('src/js/lib/jqLite'),
16
- textfield = require('src/js/forms/textfield'),
17
- select = require('src/js/forms/select'),
18
- ripple = require('src/js/ripple'),
19
- dropdowns = require('src/js/dropdowns'),
16
+ dropdown = require('src/js/dropdown'),
17
+ overlay = require('src/js/overlay'),
18
+ ripple = require('src/js/ripple'),
19
+ select = require('src/js/select'),
20
20
  tabs = require('src/js/tabs'),
21
- overlay = require('src/js/overlay');
21
+ textfield = require('src/js/textfield');
22
22
 
23
23
  // expose api
24
24
  win.mui = {
@@ -31,12 +31,12 @@
31
31
  textfield.initListeners();
32
32
  select.initListeners();
33
33
  ripple.initListeners();
34
- dropdowns.initListeners();
34
+ dropdown.initListeners();
35
35
  tabs.initListeners();
36
36
  });
37
37
  })(window);
38
38
 
39
- },{"src/js/dropdowns":6,"src/js/forms/select":7,"src/js/forms/textfield":8,"src/js/lib/jqLite":9,"src/js/overlay":10,"src/js/ripple":11,"src/js/tabs":12}],2:[function(require,module,exports){
39
+ },{"src/js/dropdown":6,"src/js/lib/jqLite":7,"src/js/overlay":8,"src/js/ripple":9,"src/js/select":10,"src/js/tabs":11,"src/js/textfield":12}],2:[function(require,module,exports){
40
40
  /**
41
41
  * MUI config module
42
42
  * @module config
@@ -878,347 +878,287 @@ module.exports = {
878
878
  };
879
879
 
880
880
  },{"./lib/jqLite":4,"./lib/util":5}],7:[function(require,module,exports){
881
+ module.exports=require(4)
882
+ },{}],8:[function(require,module,exports){
881
883
  /**
882
- * MUI CSS/JS select module
883
- * @module forms/select
884
+ * MUI CSS/JS overlay module
885
+ * @module overlay
884
886
  */
885
887
 
886
888
  'use strict';
887
889
 
888
890
 
889
- var jqLite = require('../lib/jqLite'),
890
- util = require('../lib/util'),
891
- formlib = require('../lib/forms'),
892
- wrapperClass = 'mui-select',
893
- cssSelector = '.mui-select > select',
894
- menuClass = 'mui-select__menu',
895
- selectedClass = 'mui--is-selected',
896
- doc = document,
897
- win = window;
891
+ var util = require('./lib/util'),
892
+ jqLite = require('./lib/jqLite'),
893
+ overlayId = 'mui-overlay',
894
+ bodyClass = 'mui--overflow-hidden',
895
+ iosRegex = /(iPad|iPhone|iPod)/g;
898
896
 
899
897
 
900
898
  /**
901
- * Initialize select element.
902
- * @param {Element} selectEl - The select element.
899
+ * Turn overlay on/off.
900
+ * @param {string} action - Turn overlay "on"/"off".
901
+ * @param {object} [options]
902
+ * @config {boolean} [keyboard] - If true, close when escape key is pressed.
903
+ * @config {boolean} [static] - If false, close when backdrop is clicked.
904
+ * @config {Function} [onclose] - Callback function to execute on close
905
+ * @param {Element} [childElement] - Child element to add to overlay.
903
906
  */
904
- function initialize(selectEl) {
905
- // check flag
906
- if (selectEl._muiSelect === true) return;
907
- else selectEl._muiSelect = true;
907
+ function overlayFn(action) {
908
+ var overlayEl;
909
+
910
+ if (action === 'on') {
911
+ // extract arguments
912
+ var arg, options, childElement;
913
+
914
+ // pull options and childElement from arguments
915
+ for (var i=arguments.length - 1; i > 0; i--) {
916
+ arg = arguments[i];
908
917
 
909
- // use default behavior on touch devices
910
- if ('ontouchstart' in doc.documentElement) return;
918
+ if (jqLite.type(arg) === 'object') options = arg;
919
+ if (arg instanceof Element && arg.nodeType === 1) childElement = arg;
920
+ }
911
921
 
912
- // initialize element
913
- new Select(selectEl);
922
+ // option defaults
923
+ options = options || {};
924
+ if (options.keyboard === undefined) options.keyboard = true;
925
+ if (options.static === undefined) options.static = false;
926
+
927
+ // execute method
928
+ overlayEl = overlayOn(options, childElement);
929
+
930
+ } else if (action === 'off') {
931
+ overlayEl = overlayOff();
932
+
933
+ } else {
934
+ // raise error
935
+ util.raiseError("Expecting 'on' or 'off'");
936
+ }
937
+
938
+ return overlayEl;
914
939
  }
915
940
 
916
941
 
917
942
  /**
918
- * Creates a new Select object
919
- * @class
943
+ * Turn on overlay.
944
+ * @param {object} options - Overlay options.
945
+ * @param {Element} childElement - The child element.
920
946
  */
921
- function Select(selectEl) {
922
- // instance variables
923
- this.selectEl = selectEl;
924
- this.wrapperEl = selectEl.parentNode;
925
- this.useDefault = false; // currently unused but let's keep just in case
947
+ function overlayOn(options, childElement) {
948
+ var bodyEl = document.body,
949
+ overlayEl = document.getElementById(overlayId);
950
+
951
+ // add overlay
952
+ util.enableScrollLock();
953
+ //jqLite.addClass(bodyEl, bodyClass);
926
954
 
927
- // attach event handlers
928
- jqLite.on(selectEl, 'mousedown', util.callback(this, 'mousedownHandler'));
929
- jqLite.on(selectEl, 'focus', util.callback(this, 'focusHandler'));
930
- jqLite.on(selectEl, 'click', util.callback(this, 'clickHandler'));
931
-
932
- // make wrapper focusable and fix firefox bug
933
- this.wrapperEl.tabIndex = -1;
934
- var callbackFn = util.callback(this, 'wrapperFocusHandler');
935
- jqLite.on(this.wrapperEl, 'focus', callbackFn);
936
- }
955
+ if (!overlayEl) {
956
+ // create overlayEl
957
+ overlayEl = document.createElement('div');
958
+ overlayEl.setAttribute('id', overlayId);
959
+
960
+ // add child element
961
+ if (childElement) overlayEl.appendChild(childElement);
937
962
 
963
+ bodyEl.appendChild(overlayEl);
964
+
965
+ } else {
966
+ // remove existing children
967
+ while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
968
+
969
+ // add child element
970
+ if (childElement) overlayEl.appendChild(childElement);
971
+ }
938
972
 
939
- /**
940
- * Disable default dropdown on mousedown.
941
- * @param {Event} ev - The DOM event
942
- */
943
- Select.prototype.mousedownHandler = function(ev) {
944
- if (ev.button !== 0 || this.useDefault === true) return;
945
- ev.preventDefault();
973
+ // iOS bugfix
974
+ if (iosRegex.test(navigator.userAgent)) {
975
+ jqLite.css(overlayEl, 'cursor', 'pointer');
976
+ }
977
+
978
+ // handle options
979
+ if (options.keyboard) addKeyupHandler();
980
+ else removeKeyupHandler();
981
+
982
+ if (options.static) removeClickHandler(overlayEl);
983
+ else addClickHandler(overlayEl);
984
+
985
+ // attach options
986
+ overlayEl.muiOptions = options;
987
+
988
+ return overlayEl;
946
989
  }
947
990
 
948
991
 
949
992
  /**
950
- * Handle focus event on select element.
951
- * @param {Event} ev - The DOM event
993
+ * Turn off overlay.
952
994
  */
953
- Select.prototype.focusHandler = function(ev) {
954
- // check flag
955
- if (this.useDefault === true) return;
956
-
957
- var selectEl = this.selectEl,
958
- wrapperEl = this.wrapperEl,
959
- origIndex = selectEl.tabIndex,
960
- keydownFn = util.callback(this, 'keydownHandler');
995
+ function overlayOff() {
996
+ var overlayEl = document.getElementById(overlayId),
997
+ callbackFn;
961
998
 
962
- // attach keydown handler
963
- jqLite.on(doc, 'keydown', keydownFn);
999
+ if (overlayEl) {
1000
+ // remove children
1001
+ while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
964
1002
 
965
- // disable tabfocus once
966
- selectEl.tabIndex = -1;
967
- jqLite.one(wrapperEl, 'blur', function() {
968
- selectEl.tabIndex = origIndex;
969
- jqLite.off(doc, 'keydown', keydownFn);
970
- });
971
-
972
- // defer focus to parent
973
- wrapperEl.focus();
974
- }
1003
+ // remove overlay element
1004
+ overlayEl.parentNode.removeChild(overlayEl);
975
1005
 
1006
+ // callback reference
1007
+ callbackFn = overlayEl.muiOptions.onclose;
976
1008
 
977
- /**
978
- * Handle keydown events on doc
979
- **/
980
- Select.prototype.keydownHandler = function(ev) {
981
- // spacebar, down, up
982
- if (ev.keyCode === 32 || ev.keyCode === 38 || ev.keyCode === 40) {
983
- // prevent win scroll
984
- ev.preventDefault();
985
-
986
- if (this.selectEl.disabled !== true) this.renderMenu();
1009
+ // remove click handler
1010
+ removeClickHandler(overlayEl);
987
1011
  }
1012
+
1013
+ util.disableScrollLock();
1014
+
1015
+ // remove keyup handler
1016
+ removeKeyupHandler();
1017
+
1018
+ // execute callback
1019
+ if (callbackFn) callbackFn();
1020
+
1021
+ return overlayEl;
988
1022
  }
989
1023
 
990
1024
 
991
1025
  /**
992
- * Handle focus event on wrapper element.
1026
+ * Add keyup handler.
993
1027
  */
994
- Select.prototype.wrapperFocusHandler = function() {
995
- // firefox bugfix
996
- if (this.selectEl.disabled) return this.wrapperEl.blur();
1028
+ function addKeyupHandler() {
1029
+ jqLite.on(document, 'keyup', onKeyup);
997
1030
  }
998
1031
 
999
1032
 
1000
1033
  /**
1001
- * Handle click events on select element.
1002
- * @param {Event} ev - The DOM event
1034
+ * Remove keyup handler.
1003
1035
  */
1004
- Select.prototype.clickHandler = function(ev) {
1005
- // only left clicks
1006
- if (ev.button !== 0) return;
1007
- this.renderMenu();
1036
+ function removeKeyupHandler() {
1037
+ jqLite.off(document, 'keyup', onKeyup);
1008
1038
  }
1009
1039
 
1010
1040
 
1011
1041
  /**
1012
- * Render options dropdown.
1042
+ * Teardown overlay when escape key is pressed.
1013
1043
  */
1014
- Select.prototype.renderMenu = function() {
1015
- // check and reset flag
1016
- if (this.useDefault === true) return this.useDefault = false;
1017
-
1018
- new Menu(this.wrapperEl, this.selectEl);
1044
+ function onKeyup(ev) {
1045
+ if (ev.keyCode === 27) overlayOff();
1019
1046
  }
1020
1047
 
1021
1048
 
1022
1049
  /**
1023
- * Creates a new Menu
1024
- * @class
1050
+ * Add click handler.
1025
1051
  */
1026
- function Menu(wrapperEl, selectEl) {
1027
- // add scroll lock
1028
- util.enableScrollLock();
1029
-
1030
- // instance variables
1031
- this.origIndex = null;
1032
- this.currentIndex = null;
1033
- this.selectEl = selectEl;
1034
- this.menuEl = this._createMenuEl(wrapperEl, selectEl);
1035
- this.clickCallbackFn = util.callback(this, 'clickHandler');
1036
- this.keydownCallbackFn = util.callback(this, 'keydownHandler');
1037
- this.destroyCallbackFn = util.callback(this, 'destroy');
1038
-
1039
- // add to DOM
1040
- wrapperEl.appendChild(this.menuEl);
1041
- jqLite.scrollTop(this.menuEl, this.menuEl._muiScrollTop);
1042
-
1043
- // blur active element
1044
- setTimeout(function() {
1045
- // ie10 bugfix
1046
- if (doc.activeElement.nodeName.toLowerCase() !== "body") {
1047
- doc.activeElement.blur();
1048
- }
1049
- }, 0);
1052
+ function addClickHandler(overlayEl) {
1053
+ jqLite.on(overlayEl, 'click', onClick);
1054
+ }
1050
1055
 
1051
- // attach event handlers
1052
- jqLite.on(this.menuEl, 'click', this.clickCallbackFn);
1053
- jqLite.on(doc, 'keydown', this.keydownCallbackFn);
1054
- jqLite.on(win, 'resize', this.destroyCallbackFn);
1055
1056
 
1056
- // attach event handler after current event loop exits
1057
- var fn = this.destroyCallbackFn;
1058
- setTimeout(function() {jqLite.on(doc, 'click', fn);}, 0);
1057
+ /**
1058
+ * Remove click handler.
1059
+ */
1060
+ function removeClickHandler(overlayEl) {
1061
+ jqLite.off(overlayEl, 'click', onClick);
1059
1062
  }
1060
1063
 
1061
1064
 
1062
1065
  /**
1063
- * Create menu element
1064
- * @param {Element} selectEl - The select element
1066
+ * Teardown overlay when backdrop is clicked.
1065
1067
  */
1066
- Menu.prototype._createMenuEl = function(wrapperEl, selectEl) {
1067
- var menuEl = doc.createElement('div'),
1068
- optionEls = selectEl.children,
1069
- numOptions = optionEls.length,
1070
- selectedPos = 0,
1071
- optionEl,
1072
- itemEl,
1073
- i;
1074
-
1075
- menuEl.className = menuClass;
1076
-
1077
- // add options
1078
- for (i=0; i < numOptions; i++) {
1079
- optionEl = optionEls[i];
1080
-
1081
- itemEl = doc.createElement('div');
1082
- itemEl.textContent = optionEl.textContent;
1083
- itemEl._muiPos = i;
1084
-
1085
- if (optionEl.selected) {
1086
- itemEl.setAttribute('class', selectedClass);
1087
- selectedPos = i;
1088
- }
1089
-
1090
- menuEl.appendChild(itemEl);
1091
- }
1092
-
1093
- // save indices
1094
- this.origIndex = selectedPos;
1095
- this.currentIndex = selectedPos;
1096
-
1097
- // set position
1098
- var props = formlib.getMenuPositionalCSS(
1099
- wrapperEl,
1100
- numOptions,
1101
- selectedPos
1102
- );
1103
-
1104
- jqLite.css(menuEl, props);
1105
- menuEl._muiScrollTop = props.scrollTop;
1106
-
1107
- return menuEl;
1068
+ function onClick(ev) {
1069
+ if (ev.target.id === overlayId) overlayOff();
1108
1070
  }
1109
1071
 
1110
1072
 
1111
- /**
1112
- * Handle keydown events on doc element.
1113
- * @param {Event} ev - The DOM event
1114
- */
1115
- Menu.prototype.keydownHandler = function(ev) {
1116
- var keyCode = ev.keyCode;
1117
-
1118
- // tab
1119
- if (keyCode === 9) return this.destroy();
1120
-
1121
- // escape | up | down | enter
1122
- if (keyCode === 27 || keyCode === 40 || keyCode === 38 || keyCode === 13) {
1123
- ev.preventDefault();
1124
- }
1125
-
1126
- if (keyCode === 27) {
1127
- this.destroy();
1128
- } else if (keyCode === 40) {
1129
- this.increment();
1130
- } else if (keyCode === 38) {
1131
- this.decrement();
1132
- } else if (keyCode === 13) {
1133
- this.selectCurrent();
1134
- this.destroy();
1135
- }
1136
- }
1137
-
1073
+ /** Define module API */
1074
+ module.exports = overlayFn;
1138
1075
 
1076
+ },{"./lib/jqLite":4,"./lib/util":5}],9:[function(require,module,exports){
1139
1077
  /**
1140
- * Handle click events on menu element.
1141
- * @param {Event} ev - The DOM event
1078
+ * MUI CSS/JS ripple module
1079
+ * @module ripple
1142
1080
  */
1143
- Menu.prototype.clickHandler = function(ev) {
1144
- // don't allow events to bubble
1145
- ev.stopPropagation();
1146
-
1147
- var pos = ev.target._muiPos;
1148
1081
 
1149
- // ignore clicks on non-items
1150
- if (pos === undefined) return;
1082
+ 'use strict';
1151
1083
 
1152
- // select option
1153
- this.currentIndex = pos;
1154
- this.selectCurrent();
1155
1084
 
1156
- // destroy menu
1157
- this.destroy();
1158
- }
1085
+ var jqLite = require('./lib/jqLite'),
1086
+ util = require('./lib/util'),
1087
+ btnClass = 'mui-btn',
1088
+ btnFABClass = 'mui-btn--fab',
1089
+ rippleClass = 'mui-ripple-effect',
1090
+ animationName = 'mui-btn-inserted';
1159
1091
 
1160
1092
 
1161
1093
  /**
1162
- * Increment selected item
1094
+ * Add ripple effects to button element.
1095
+ * @param {Element} buttonEl - The button element.
1163
1096
  */
1164
- Menu.prototype.increment = function() {
1165
- if (this.currentIndex === this.menuEl.children.length - 1) return;
1097
+ function initialize(buttonEl) {
1098
+ // check flag
1099
+ if (buttonEl._muiRipple === true) return;
1100
+ else buttonEl._muiRipple = true;
1166
1101
 
1167
- var optionEls = this.menuEl.children;
1168
-
1169
- jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
1170
- this.currentIndex += 1;
1171
- jqLite.addClass(optionEls[this.currentIndex], selectedClass);
1102
+ // exit if element is INPUT (doesn't support absolute positioned children)
1103
+ if (buttonEl.tagName === 'INPUT') return;
1104
+
1105
+ // attach event handler
1106
+ jqLite.on(buttonEl, 'touchstart', eventHandler);
1107
+ jqLite.on(buttonEl, 'mousedown', eventHandler);
1172
1108
  }
1173
1109
 
1174
1110
 
1175
1111
  /**
1176
- * Decrement selected item
1112
+ * Event handler
1113
+ * @param {Event} ev - The DOM event
1177
1114
  */
1178
- Menu.prototype.decrement = function() {
1179
- if (this.currentIndex === 0) return;
1180
-
1181
- var optionEls = this.menuEl.children;
1182
-
1183
- jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
1184
- this.currentIndex -= 1;
1185
- jqLite.addClass(optionEls[this.currentIndex], selectedClass);
1186
- }
1115
+ function eventHandler(ev) {
1116
+ // only left clicks
1117
+ if (ev.button !== 0) return;
1187
1118
 
1119
+ var buttonEl = this;
1188
1120
 
1189
- /**
1190
- * Select current item
1191
- */
1192
- Menu.prototype.selectCurrent = function() {
1193
- if (this.currentIndex !== this.origIndex) {
1194
- var optionEls = this.selectEl.children;
1195
- optionEls[this.origIndex].selected = false;
1196
- optionEls[this.currentIndex].selected = true;
1121
+ // exit if button is disabled
1122
+ if (buttonEl.disabled === true) return;
1197
1123
 
1198
- // trigger change event
1199
- util.dispatchEvent(this.selectEl, 'change');
1124
+ // de-dupe touchstart and mousedown with 100msec flag
1125
+ if (buttonEl.touchFlag === true) {
1126
+ return;
1127
+ } else {
1128
+ buttonEl.touchFlag = true;
1129
+ setTimeout(function() {
1130
+ buttonEl.touchFlag = false;
1131
+ }, 100);
1200
1132
  }
1201
- }
1202
1133
 
1134
+ var rippleEl = document.createElement('div');
1135
+ rippleEl.className = rippleClass;
1203
1136
 
1204
- /**
1205
- * Destroy menu and detach event handlers
1206
- */
1207
- Menu.prototype.destroy = function() {
1208
- // remove element and focus element
1209
- var parentNode = this.menuEl.parentNode;
1210
- if (parentNode) parentNode.removeChild(this.menuEl);
1137
+ var offset = jqLite.offset(buttonEl),
1138
+ xPos = ev.pageX - offset.left,
1139
+ yPos = ev.pageY - offset.top,
1140
+ diameter,
1141
+ radius;
1211
1142
 
1212
- this.selectEl.focus();
1143
+ // get height
1144
+ if (jqLite.hasClass(buttonEl, btnFABClass)) diameter = offset.height / 2;
1145
+ else diameter = offset.height;
1213
1146
 
1214
- // remove scroll lock
1215
- util.disableScrollLock();
1147
+ radius = diameter / 2;
1148
+
1149
+ jqLite.css(rippleEl, {
1150
+ height: diameter + 'px',
1151
+ width: diameter + 'px',
1152
+ top: yPos - radius + 'px',
1153
+ left: xPos - radius + 'px'
1154
+ });
1216
1155
 
1217
- // remove event handlers
1218
- jqLite.off(this.menuEl, 'click', this.clickCallbackFn);
1219
- jqLite.off(doc, 'keydown', this.keydownCallbackFn);
1220
- jqLite.off(doc, 'click', this.destroyCallbackFn);
1221
- jqLite.off(win, 'resize', this.destroyCallbackFn);
1156
+ buttonEl.appendChild(rippleEl);
1157
+
1158
+ window.setTimeout(function() {
1159
+ var parentNode = rippleEl.parentNode;
1160
+ if (parentNode) parentNode.removeChild(rippleEl);
1161
+ }, 2000);
1222
1162
  }
1223
1163
 
1224
1164
 
@@ -1226,403 +1166,361 @@ Menu.prototype.destroy = function() {
1226
1166
  module.exports = {
1227
1167
  /** Initialize module listeners */
1228
1168
  initListeners: function() {
1169
+ var doc = document;
1170
+
1229
1171
  // markup elements available when method is called
1230
- var elList = doc.querySelectorAll(cssSelector);
1172
+ var elList = doc.getElementsByClassName(btnClass);
1231
1173
  for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
1232
1174
 
1233
1175
  // listen for new elements
1234
1176
  util.onNodeInserted(function(el) {
1235
- if (el.tagName === 'SELECT' &&
1236
- jqLite.hasClass(el.parentNode, wrapperClass)) {
1237
- initialize(el);
1238
- }
1177
+ if (jqLite.hasClass(el, btnClass)) initialize(el);
1239
1178
  });
1240
1179
  }
1241
1180
  };
1242
1181
 
1243
- },{"../lib/forms":3,"../lib/jqLite":4,"../lib/util":5}],8:[function(require,module,exports){
1182
+ },{"./lib/jqLite":4,"./lib/util":5}],10:[function(require,module,exports){
1244
1183
  /**
1245
- * MUI CSS/JS form-control module
1246
- * @module forms/form-control
1184
+ * MUI CSS/JS select module
1185
+ * @module forms/select
1247
1186
  */
1248
1187
 
1249
1188
  'use strict';
1250
1189
 
1251
1190
 
1252
- var jqLite = require('../lib/jqLite'),
1253
- util = require('../lib/util'),
1254
- cssSelector = '.mui-textfield > input, .mui-textfield > textarea',
1255
- emptyClass = 'mui--is-empty',
1256
- notEmptyClass = 'mui--is-not-empty',
1257
- dirtyClass = 'mui--is-dirty',
1258
- floatingLabelClass = 'mui-textfield--float-label';
1191
+ var jqLite = require('./lib/jqLite'),
1192
+ util = require('./lib/util'),
1193
+ formlib = require('./lib/forms'),
1194
+ wrapperClass = 'mui-select',
1195
+ cssSelector = '.mui-select > select',
1196
+ menuClass = 'mui-select__menu',
1197
+ selectedClass = 'mui--is-selected',
1198
+ doc = document,
1199
+ win = window;
1259
1200
 
1260
1201
 
1261
1202
  /**
1262
- * Initialize input element.
1263
- * @param {Element} inputEl - The input element.
1203
+ * Initialize select element.
1204
+ * @param {Element} selectEl - The select element.
1264
1205
  */
1265
- function initialize(inputEl) {
1206
+ function initialize(selectEl) {
1266
1207
  // check flag
1267
- if (inputEl._muiTextfield === true) return;
1268
- else inputEl._muiTextfield = true;
1269
-
1270
- if (inputEl.value.length) jqLite.addClass(inputEl, notEmptyClass);
1271
- else jqLite.addClass(inputEl, emptyClass);
1208
+ if (selectEl._muiSelect === true) return;
1209
+ else selectEl._muiSelect = true;
1272
1210
 
1273
- jqLite.on(inputEl, 'input', inputHandler);
1211
+ // use default behavior on touch devices
1212
+ if ('ontouchstart' in doc.documentElement) return;
1274
1213
 
1275
- // add dirty class on focus
1276
- jqLite.on(inputEl, 'focus', function(){jqLite.addClass(this, dirtyClass);});
1214
+ // initialize element
1215
+ new Select(selectEl);
1277
1216
  }
1278
1217
 
1279
1218
 
1280
1219
  /**
1281
- * Handle input events.
1220
+ * Creates a new Select object
1221
+ * @class
1282
1222
  */
1283
- function inputHandler() {
1284
- var inputEl = this;
1285
-
1286
- if (inputEl.value.length) {
1287
- jqLite.removeClass(inputEl, emptyClass);
1288
- jqLite.addClass(inputEl, notEmptyClass);
1289
- } else {
1290
- jqLite.removeClass(inputEl, notEmptyClass);
1291
- jqLite.addClass(inputEl, emptyClass)
1292
- }
1223
+ function Select(selectEl) {
1224
+ // instance variables
1225
+ this.selectEl = selectEl;
1226
+ this.wrapperEl = selectEl.parentNode;
1227
+ this.useDefault = false; // currently unused but let's keep just in case
1293
1228
 
1294
- jqLite.addClass(inputEl, dirtyClass);
1295
- }
1296
-
1297
-
1298
- /** Define module API */
1299
- module.exports = {
1300
- /** Initialize input elements */
1301
- initialize: initialize,
1229
+ // attach event handlers
1230
+ jqLite.on(selectEl, 'mousedown', util.callback(this, 'mousedownHandler'));
1231
+ jqLite.on(selectEl, 'focus', util.callback(this, 'focusHandler'));
1232
+ jqLite.on(selectEl, 'click', util.callback(this, 'clickHandler'));
1302
1233
 
1303
- /** Initialize module listeners */
1304
- initListeners: function() {
1305
- var doc = document;
1306
-
1307
- // markup elements available when method is called
1308
- var elList = doc.querySelectorAll(cssSelector);
1309
- for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
1234
+ // make wrapper focusable and fix firefox bug
1235
+ this.wrapperEl.tabIndex = -1;
1236
+ var callbackFn = util.callback(this, 'wrapperFocusHandler');
1237
+ jqLite.on(this.wrapperEl, 'focus', callbackFn);
1238
+ }
1310
1239
 
1311
- // listen for new elements
1312
- util.onNodeInserted(function(el) {
1313
- if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') initialize(el);
1314
- });
1315
1240
 
1316
- // add transition css for floating labels
1317
- setTimeout(function() {
1318
- var css = '.mui-textfield.mui-textfield--float-label > label {' + [
1319
- '-webkit-transition',
1320
- '-moz-transition',
1321
- '-o-transition',
1322
- 'transition',
1323
- ''
1324
- ].join(':all .15s ease-out;') + '}';
1325
-
1326
- util.loadStyle(css);
1327
- }, 150);
1328
-
1329
- // pointer-events shim for floating labels
1330
- if (util.supportsPointerEvents() === false) {
1331
- jqLite.on(document, 'click', function(ev) {
1332
- var targetEl = ev.target;
1241
+ /**
1242
+ * Disable default dropdown on mousedown.
1243
+ * @param {Event} ev - The DOM event
1244
+ */
1245
+ Select.prototype.mousedownHandler = function(ev) {
1246
+ if (ev.button !== 0 || this.useDefault === true) return;
1247
+ ev.preventDefault();
1248
+ }
1333
1249
 
1334
- if (targetEl.tagName === 'LABEL' &&
1335
- jqLite.hasClass(targetEl.parentNode, floatingLabelClass)) {
1336
- var inputEl = targetEl.previousElementSibling;
1337
- if (inputEl) inputEl.focus();
1338
- }
1339
- });
1340
- }
1341
- }
1342
- };
1343
1250
 
1344
- },{"../lib/jqLite":4,"../lib/util":5}],9:[function(require,module,exports){
1345
- module.exports=require(4)
1346
- },{}],10:[function(require,module,exports){
1347
1251
  /**
1348
- * MUI CSS/JS overlay module
1349
- * @module overlay
1252
+ * Handle focus event on select element.
1253
+ * @param {Event} ev - The DOM event
1350
1254
  */
1255
+ Select.prototype.focusHandler = function(ev) {
1256
+ // check flag
1257
+ if (this.useDefault === true) return;
1351
1258
 
1352
- 'use strict';
1259
+ var selectEl = this.selectEl,
1260
+ wrapperEl = this.wrapperEl,
1261
+ origIndex = selectEl.tabIndex,
1262
+ keydownFn = util.callback(this, 'keydownHandler');
1353
1263
 
1264
+ // attach keydown handler
1265
+ jqLite.on(doc, 'keydown', keydownFn);
1354
1266
 
1355
- var util = require('./lib/util'),
1356
- jqLite = require('./lib/jqLite'),
1357
- overlayId = 'mui-overlay',
1358
- bodyClass = 'mui--overflow-hidden',
1359
- iosRegex = /(iPad|iPhone|iPod)/g;
1267
+ // disable tabfocus once
1268
+ selectEl.tabIndex = -1;
1269
+ jqLite.one(wrapperEl, 'blur', function() {
1270
+ selectEl.tabIndex = origIndex;
1271
+ jqLite.off(doc, 'keydown', keydownFn);
1272
+ });
1273
+
1274
+ // defer focus to parent
1275
+ wrapperEl.focus();
1276
+ }
1360
1277
 
1361
1278
 
1362
1279
  /**
1363
- * Turn overlay on/off.
1364
- * @param {string} action - Turn overlay "on"/"off".
1365
- * @param {object} [options]
1366
- * @config {boolean} [keyboard] - If true, close when escape key is pressed.
1367
- * @config {boolean} [static] - If false, close when backdrop is clicked.
1368
- * @config {Function} [onclose] - Callback function to execute on close
1369
- * @param {Element} [childElement] - Child element to add to overlay.
1370
- */
1371
- function overlayFn(action) {
1372
- var overlayEl;
1373
-
1374
- if (action === 'on') {
1375
- // extract arguments
1376
- var arg, options, childElement;
1280
+ * Handle keydown events on doc
1281
+ **/
1282
+ Select.prototype.keydownHandler = function(ev) {
1283
+ // spacebar, down, up
1284
+ if (ev.keyCode === 32 || ev.keyCode === 38 || ev.keyCode === 40) {
1285
+ // prevent win scroll
1286
+ ev.preventDefault();
1377
1287
 
1378
- // pull options and childElement from arguments
1379
- for (var i=arguments.length - 1; i > 0; i--) {
1380
- arg = arguments[i];
1288
+ if (this.selectEl.disabled !== true) this.renderMenu();
1289
+ }
1290
+ }
1381
1291
 
1382
- if (jqLite.type(arg) === 'object') options = arg;
1383
- if (arg instanceof Element && arg.nodeType === 1) childElement = arg;
1384
- }
1385
1292
 
1386
- // option defaults
1387
- options = options || {};
1388
- if (options.keyboard === undefined) options.keyboard = true;
1389
- if (options.static === undefined) options.static = false;
1390
-
1391
- // execute method
1392
- overlayEl = overlayOn(options, childElement);
1393
-
1394
- } else if (action === 'off') {
1395
- overlayEl = overlayOff();
1293
+ /**
1294
+ * Handle focus event on wrapper element.
1295
+ */
1296
+ Select.prototype.wrapperFocusHandler = function() {
1297
+ // firefox bugfix
1298
+ if (this.selectEl.disabled) return this.wrapperEl.blur();
1299
+ }
1396
1300
 
1397
- } else {
1398
- // raise error
1399
- util.raiseError("Expecting 'on' or 'off'");
1400
- }
1401
1301
 
1402
- return overlayEl;
1302
+ /**
1303
+ * Handle click events on select element.
1304
+ * @param {Event} ev - The DOM event
1305
+ */
1306
+ Select.prototype.clickHandler = function(ev) {
1307
+ // only left clicks
1308
+ if (ev.button !== 0) return;
1309
+ this.renderMenu();
1403
1310
  }
1404
1311
 
1405
1312
 
1406
1313
  /**
1407
- * Turn on overlay.
1408
- * @param {object} options - Overlay options.
1409
- * @param {Element} childElement - The child element.
1314
+ * Render options dropdown.
1410
1315
  */
1411
- function overlayOn(options, childElement) {
1412
- var bodyEl = document.body,
1413
- overlayEl = document.getElementById(overlayId);
1414
-
1415
- // add overlay
1416
- util.enableScrollLock();
1417
- //jqLite.addClass(bodyEl, bodyClass);
1316
+ Select.prototype.renderMenu = function() {
1317
+ // check and reset flag
1318
+ if (this.useDefault === true) return this.useDefault = false;
1418
1319
 
1419
- if (!overlayEl) {
1420
- // create overlayEl
1421
- overlayEl = document.createElement('div');
1422
- overlayEl.setAttribute('id', overlayId);
1423
-
1424
- // add child element
1425
- if (childElement) overlayEl.appendChild(childElement);
1320
+ new Menu(this.wrapperEl, this.selectEl);
1321
+ }
1426
1322
 
1427
- bodyEl.appendChild(overlayEl);
1428
-
1429
- } else {
1430
- // remove existing children
1431
- while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
1432
-
1433
- // add child element
1434
- if (childElement) overlayEl.appendChild(childElement);
1435
- }
1436
1323
 
1437
- // iOS bugfix
1438
- if (iosRegex.test(navigator.userAgent)) {
1439
- jqLite.css(overlayEl, 'cursor', 'pointer');
1440
- }
1324
+ /**
1325
+ * Creates a new Menu
1326
+ * @class
1327
+ */
1328
+ function Menu(wrapperEl, selectEl) {
1329
+ // add scroll lock
1330
+ util.enableScrollLock();
1441
1331
 
1442
- // handle options
1443
- if (options.keyboard) addKeyupHandler();
1444
- else removeKeyupHandler();
1332
+ // instance variables
1333
+ this.origIndex = null;
1334
+ this.currentIndex = null;
1335
+ this.selectEl = selectEl;
1336
+ this.menuEl = this._createMenuEl(wrapperEl, selectEl);
1337
+ this.clickCallbackFn = util.callback(this, 'clickHandler');
1338
+ this.keydownCallbackFn = util.callback(this, 'keydownHandler');
1339
+ this.destroyCallbackFn = util.callback(this, 'destroy');
1445
1340
 
1446
- if (options.static) removeClickHandler(overlayEl);
1447
- else addClickHandler(overlayEl);
1341
+ // add to DOM
1342
+ wrapperEl.appendChild(this.menuEl);
1343
+ jqLite.scrollTop(this.menuEl, this.menuEl._muiScrollTop);
1448
1344
 
1449
- // attach options
1450
- overlayEl.muiOptions = options;
1345
+ // blur active element
1346
+ setTimeout(function() {
1347
+ // ie10 bugfix
1348
+ if (doc.activeElement.nodeName.toLowerCase() !== "body") {
1349
+ doc.activeElement.blur();
1350
+ }
1351
+ }, 0);
1451
1352
 
1452
- return overlayEl;
1353
+ // attach event handlers
1354
+ jqLite.on(this.menuEl, 'click', this.clickCallbackFn);
1355
+ jqLite.on(doc, 'keydown', this.keydownCallbackFn);
1356
+ jqLite.on(win, 'resize', this.destroyCallbackFn);
1357
+
1358
+ // attach event handler after current event loop exits
1359
+ var fn = this.destroyCallbackFn;
1360
+ setTimeout(function() {jqLite.on(doc, 'click', fn);}, 0);
1453
1361
  }
1454
1362
 
1455
1363
 
1456
1364
  /**
1457
- * Turn off overlay.
1365
+ * Create menu element
1366
+ * @param {Element} selectEl - The select element
1458
1367
  */
1459
- function overlayOff() {
1460
- var overlayEl = document.getElementById(overlayId),
1461
- callbackFn;
1368
+ Menu.prototype._createMenuEl = function(wrapperEl, selectEl) {
1369
+ var menuEl = doc.createElement('div'),
1370
+ optionEls = selectEl.children,
1371
+ numOptions = optionEls.length,
1372
+ selectedPos = 0,
1373
+ optionEl,
1374
+ itemEl,
1375
+ i;
1462
1376
 
1463
- if (overlayEl) {
1464
- // remove children
1465
- while (overlayEl.firstChild) overlayEl.removeChild(overlayEl.firstChild);
1377
+ menuEl.className = menuClass;
1466
1378
 
1467
- // remove overlay element
1468
- overlayEl.parentNode.removeChild(overlayEl);
1379
+ // add options
1380
+ for (i=0; i < numOptions; i++) {
1381
+ optionEl = optionEls[i];
1469
1382
 
1470
- // callback reference
1471
- callbackFn = overlayEl.muiOptions.onclose;
1383
+ itemEl = doc.createElement('div');
1384
+ itemEl.textContent = optionEl.textContent;
1385
+ itemEl._muiPos = i;
1472
1386
 
1473
- // remove click handler
1474
- removeClickHandler(overlayEl);
1387
+ if (optionEl.selected) {
1388
+ itemEl.setAttribute('class', selectedClass);
1389
+ selectedPos = i;
1390
+ }
1391
+
1392
+ menuEl.appendChild(itemEl);
1475
1393
  }
1476
1394
 
1477
- util.disableScrollLock();
1395
+ // save indices
1396
+ this.origIndex = selectedPos;
1397
+ this.currentIndex = selectedPos;
1478
1398
 
1479
- // remove keyup handler
1480
- removeKeyupHandler();
1399
+ // set position
1400
+ var props = formlib.getMenuPositionalCSS(
1401
+ wrapperEl,
1402
+ numOptions,
1403
+ selectedPos
1404
+ );
1481
1405
 
1482
- // execute callback
1483
- if (callbackFn) callbackFn();
1406
+ jqLite.css(menuEl, props);
1407
+ menuEl._muiScrollTop = props.scrollTop;
1484
1408
 
1485
- return overlayEl;
1409
+ return menuEl;
1486
1410
  }
1487
1411
 
1488
1412
 
1489
1413
  /**
1490
- * Add keyup handler.
1414
+ * Handle keydown events on doc element.
1415
+ * @param {Event} ev - The DOM event
1491
1416
  */
1492
- function addKeyupHandler() {
1493
- jqLite.on(document, 'keyup', onKeyup);
1494
- }
1417
+ Menu.prototype.keydownHandler = function(ev) {
1418
+ var keyCode = ev.keyCode;
1495
1419
 
1420
+ // tab
1421
+ if (keyCode === 9) return this.destroy();
1422
+
1423
+ // escape | up | down | enter
1424
+ if (keyCode === 27 || keyCode === 40 || keyCode === 38 || keyCode === 13) {
1425
+ ev.preventDefault();
1426
+ }
1496
1427
 
1497
- /**
1498
- * Remove keyup handler.
1499
- */
1500
- function removeKeyupHandler() {
1501
- jqLite.off(document, 'keyup', onKeyup);
1428
+ if (keyCode === 27) {
1429
+ this.destroy();
1430
+ } else if (keyCode === 40) {
1431
+ this.increment();
1432
+ } else if (keyCode === 38) {
1433
+ this.decrement();
1434
+ } else if (keyCode === 13) {
1435
+ this.selectCurrent();
1436
+ this.destroy();
1437
+ }
1502
1438
  }
1503
1439
 
1504
1440
 
1505
1441
  /**
1506
- * Teardown overlay when escape key is pressed.
1442
+ * Handle click events on menu element.
1443
+ * @param {Event} ev - The DOM event
1507
1444
  */
1508
- function onKeyup(ev) {
1509
- if (ev.keyCode === 27) overlayOff();
1510
- }
1445
+ Menu.prototype.clickHandler = function(ev) {
1446
+ // don't allow events to bubble
1447
+ ev.stopPropagation();
1511
1448
 
1449
+ var pos = ev.target._muiPos;
1512
1450
 
1513
- /**
1514
- * Add click handler.
1515
- */
1516
- function addClickHandler(overlayEl) {
1517
- jqLite.on(overlayEl, 'click', onClick);
1518
- }
1451
+ // ignore clicks on non-items
1452
+ if (pos === undefined) return;
1519
1453
 
1454
+ // select option
1455
+ this.currentIndex = pos;
1456
+ this.selectCurrent();
1520
1457
 
1521
- /**
1522
- * Remove click handler.
1523
- */
1524
- function removeClickHandler(overlayEl) {
1525
- jqLite.off(overlayEl, 'click', onClick);
1458
+ // destroy menu
1459
+ this.destroy();
1526
1460
  }
1527
1461
 
1528
1462
 
1529
1463
  /**
1530
- * Teardown overlay when backdrop is clicked.
1464
+ * Increment selected item
1531
1465
  */
1532
- function onClick(ev) {
1533
- if (ev.target.id === overlayId) overlayOff();
1534
- }
1466
+ Menu.prototype.increment = function() {
1467
+ if (this.currentIndex === this.menuEl.children.length - 1) return;
1535
1468
 
1469
+ var optionEls = this.menuEl.children;
1470
+
1471
+ jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
1472
+ this.currentIndex += 1;
1473
+ jqLite.addClass(optionEls[this.currentIndex], selectedClass);
1474
+ }
1536
1475
 
1537
- /** Define module API */
1538
- module.exports = overlayFn;
1539
1476
 
1540
- },{"./lib/jqLite":4,"./lib/util":5}],11:[function(require,module,exports){
1541
1477
  /**
1542
- * MUI CSS/JS ripple module
1543
- * @module ripple
1478
+ * Decrement selected item
1544
1479
  */
1480
+ Menu.prototype.decrement = function() {
1481
+ if (this.currentIndex === 0) return;
1545
1482
 
1546
- 'use strict';
1547
-
1483
+ var optionEls = this.menuEl.children;
1548
1484
 
1549
- var jqLite = require('./lib/jqLite'),
1550
- util = require('./lib/util'),
1551
- btnClass = 'mui-btn',
1552
- btnFABClass = 'mui-btn--fab',
1553
- rippleClass = 'mui-ripple-effect',
1554
- animationName = 'mui-btn-inserted';
1485
+ jqLite.removeClass(optionEls[this.currentIndex], selectedClass);
1486
+ this.currentIndex -= 1;
1487
+ jqLite.addClass(optionEls[this.currentIndex], selectedClass);
1488
+ }
1555
1489
 
1556
1490
 
1557
1491
  /**
1558
- * Add ripple effects to button element.
1559
- * @param {Element} buttonEl - The button element.
1492
+ * Select current item
1560
1493
  */
1561
- function initialize(buttonEl) {
1562
- // check flag
1563
- if (buttonEl._muiRipple === true) return;
1564
- else buttonEl._muiRipple = true;
1565
-
1566
- // exit if element is INPUT (doesn't support absolute positioned children)
1567
- if (buttonEl.tagName === 'INPUT') return;
1494
+ Menu.prototype.selectCurrent = function() {
1495
+ if (this.currentIndex !== this.origIndex) {
1496
+ var optionEls = this.selectEl.children;
1497
+ optionEls[this.origIndex].selected = false;
1498
+ optionEls[this.currentIndex].selected = true;
1568
1499
 
1569
- // attach event handler
1570
- jqLite.on(buttonEl, 'touchstart', eventHandler);
1571
- jqLite.on(buttonEl, 'mousedown', eventHandler);
1500
+ // trigger change event
1501
+ util.dispatchEvent(this.selectEl, 'change');
1502
+ }
1572
1503
  }
1573
1504
 
1574
1505
 
1575
1506
  /**
1576
- * Event handler
1577
- * @param {Event} ev - The DOM event
1507
+ * Destroy menu and detach event handlers
1578
1508
  */
1579
- function eventHandler(ev) {
1580
- // only left clicks
1581
- if (ev.button !== 0) return;
1582
-
1583
- var buttonEl = this;
1584
-
1585
- // exit if button is disabled
1586
- if (buttonEl.disabled === true) return;
1587
-
1588
- // de-dupe touchstart and mousedown with 100msec flag
1589
- if (buttonEl.touchFlag === true) {
1590
- return;
1591
- } else {
1592
- buttonEl.touchFlag = true;
1593
- setTimeout(function() {
1594
- buttonEl.touchFlag = false;
1595
- }, 100);
1596
- }
1597
-
1598
- var rippleEl = document.createElement('div');
1599
- rippleEl.className = rippleClass;
1600
-
1601
- var offset = jqLite.offset(buttonEl),
1602
- xPos = ev.pageX - offset.left,
1603
- yPos = ev.pageY - offset.top,
1604
- diameter,
1605
- radius;
1509
+ Menu.prototype.destroy = function() {
1510
+ // remove element and focus element
1511
+ var parentNode = this.menuEl.parentNode;
1512
+ if (parentNode) parentNode.removeChild(this.menuEl);
1606
1513
 
1607
- // get height
1608
- if (jqLite.hasClass(buttonEl, btnFABClass)) diameter = offset.height / 2;
1609
- else diameter = offset.height;
1514
+ this.selectEl.focus();
1610
1515
 
1611
- radius = diameter / 2;
1612
-
1613
- jqLite.css(rippleEl, {
1614
- height: diameter + 'px',
1615
- width: diameter + 'px',
1616
- top: yPos - radius + 'px',
1617
- left: xPos - radius + 'px'
1618
- });
1516
+ // remove scroll lock
1517
+ util.disableScrollLock();
1619
1518
 
1620
- buttonEl.appendChild(rippleEl);
1621
-
1622
- window.setTimeout(function() {
1623
- var parentNode = rippleEl.parentNode;
1624
- if (parentNode) parentNode.removeChild(rippleEl);
1625
- }, 2000);
1519
+ // remove event handlers
1520
+ jqLite.off(this.menuEl, 'click', this.clickCallbackFn);
1521
+ jqLite.off(doc, 'keydown', this.keydownCallbackFn);
1522
+ jqLite.off(doc, 'click', this.destroyCallbackFn);
1523
+ jqLite.off(win, 'resize', this.destroyCallbackFn);
1626
1524
  }
1627
1525
 
1628
1526
 
@@ -1630,20 +1528,21 @@ function eventHandler(ev) {
1630
1528
  module.exports = {
1631
1529
  /** Initialize module listeners */
1632
1530
  initListeners: function() {
1633
- var doc = document;
1634
-
1635
1531
  // markup elements available when method is called
1636
- var elList = doc.getElementsByClassName(btnClass);
1532
+ var elList = doc.querySelectorAll(cssSelector);
1637
1533
  for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
1638
1534
 
1639
1535
  // listen for new elements
1640
1536
  util.onNodeInserted(function(el) {
1641
- if (jqLite.hasClass(el, btnClass)) initialize(el);
1537
+ if (el.tagName === 'SELECT' &&
1538
+ jqLite.hasClass(el.parentNode, wrapperClass)) {
1539
+ initialize(el);
1540
+ }
1642
1541
  });
1643
1542
  }
1644
1543
  };
1645
1544
 
1646
- },{"./lib/jqLite":4,"./lib/util":5}],12:[function(require,module,exports){
1545
+ },{"./lib/forms":3,"./lib/jqLite":4,"./lib/util":5}],11:[function(require,module,exports){
1647
1546
  /**
1648
1547
  * MUI CSS/JS tabs module
1649
1548
  * @module tabs
@@ -1804,4 +1703,106 @@ module.exports = {
1804
1703
  }
1805
1704
  };
1806
1705
 
1706
+ },{"./lib/jqLite":4,"./lib/util":5}],12:[function(require,module,exports){
1707
+ /**
1708
+ * MUI CSS/JS form-control module
1709
+ * @module forms/form-control
1710
+ */
1711
+
1712
+ 'use strict';
1713
+
1714
+
1715
+ var jqLite = require('./lib/jqLite'),
1716
+ util = require('./lib/util'),
1717
+ cssSelector = '.mui-textfield > input, .mui-textfield > textarea',
1718
+ emptyClass = 'mui--is-empty',
1719
+ notEmptyClass = 'mui--is-not-empty',
1720
+ dirtyClass = 'mui--is-dirty',
1721
+ floatingLabelClass = 'mui-textfield--float-label';
1722
+
1723
+
1724
+ /**
1725
+ * Initialize input element.
1726
+ * @param {Element} inputEl - The input element.
1727
+ */
1728
+ function initialize(inputEl) {
1729
+ // check flag
1730
+ if (inputEl._muiTextfield === true) return;
1731
+ else inputEl._muiTextfield = true;
1732
+
1733
+ if (inputEl.value.length) jqLite.addClass(inputEl, notEmptyClass);
1734
+ else jqLite.addClass(inputEl, emptyClass);
1735
+
1736
+ jqLite.on(inputEl, 'input', inputHandler);
1737
+ jqLite.on(inputEl, 'change', inputHandler);
1738
+
1739
+ // add dirty class on focus
1740
+ jqLite.on(inputEl, 'focus', function(){jqLite.addClass(this, dirtyClass);});
1741
+ }
1742
+
1743
+
1744
+ /**
1745
+ * Handle input events.
1746
+ */
1747
+ function inputHandler() {
1748
+ var inputEl = this;
1749
+
1750
+ if (inputEl.value.length) {
1751
+ jqLite.removeClass(inputEl, emptyClass);
1752
+ jqLite.addClass(inputEl, notEmptyClass);
1753
+ } else {
1754
+ jqLite.removeClass(inputEl, notEmptyClass);
1755
+ jqLite.addClass(inputEl, emptyClass)
1756
+ }
1757
+
1758
+ jqLite.addClass(inputEl, dirtyClass);
1759
+ }
1760
+
1761
+
1762
+ /** Define module API */
1763
+ module.exports = {
1764
+ /** Initialize input elements */
1765
+ initialize: initialize,
1766
+
1767
+ /** Initialize module listeners */
1768
+ initListeners: function() {
1769
+ var doc = document;
1770
+
1771
+ // markup elements available when method is called
1772
+ var elList = doc.querySelectorAll(cssSelector);
1773
+ for (var i=elList.length - 1; i >= 0; i--) initialize(elList[i]);
1774
+
1775
+ // listen for new elements
1776
+ util.onNodeInserted(function(el) {
1777
+ if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA') initialize(el);
1778
+ });
1779
+
1780
+ // add transition css for floating labels
1781
+ setTimeout(function() {
1782
+ var css = '.mui-textfield.mui-textfield--float-label > label {' + [
1783
+ '-webkit-transition',
1784
+ '-moz-transition',
1785
+ '-o-transition',
1786
+ 'transition',
1787
+ ''
1788
+ ].join(':all .15s ease-out;') + '}';
1789
+
1790
+ util.loadStyle(css);
1791
+ }, 150);
1792
+
1793
+ // pointer-events shim for floating labels
1794
+ if (util.supportsPointerEvents() === false) {
1795
+ jqLite.on(document, 'click', function(ev) {
1796
+ var targetEl = ev.target;
1797
+
1798
+ if (targetEl.tagName === 'LABEL' &&
1799
+ jqLite.hasClass(targetEl.parentNode, floatingLabelClass)) {
1800
+ var inputEl = targetEl.previousElementSibling;
1801
+ if (inputEl) inputEl.focus();
1802
+ }
1803
+ });
1804
+ }
1805
+ }
1806
+ };
1807
+
1807
1808
  },{"./lib/jqLite":4,"./lib/util":5}]},{},[1])