jsl-ui 9.18.2 → 9.18.3

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.
Files changed (214) hide show
  1. package/lib/grid.css +0 -8
  2. package/lib/index.css.map +1 -1
  3. package/lib/index.js +10198 -61
  4. package/lib/index.js.map +1 -1
  5. package/package.json +1 -1
  6. package/lib/components/IntervalComponent.d.ts +0 -17
  7. package/lib/components/IntervalComponent.js +0 -68
  8. package/lib/components/auto-suggest/AutoSuggestComponent.d.ts +0 -22
  9. package/lib/components/auto-suggest/AutoSuggestComponent.js +0 -49
  10. package/lib/components/button/ButtonComponent.d.ts +0 -18
  11. package/lib/components/button/ButtonComponent.js +0 -46
  12. package/lib/components/checkbox/CheckBoxComponent.d.ts +0 -28
  13. package/lib/components/checkbox/CheckBoxComponent.js +0 -94
  14. package/lib/components/checkbox/CheckBoxStyle.scss +0 -86
  15. package/lib/components/date/DateComponent.d.ts +0 -32
  16. package/lib/components/date/DateComponent.js +0 -106
  17. package/lib/components/date-range/DateRangeComponent.d.ts +0 -35
  18. package/lib/components/date-range/DateRangeComponent.js +0 -136
  19. package/lib/components/date-range/DateRangeStyle.scss +0 -12
  20. package/lib/components/date-time/DateTimeComponent.d.ts +0 -15
  21. package/lib/components/date-time/DateTimeComponent.js +0 -53
  22. package/lib/components/date-time/DateTimeStyle.scss +0 -7
  23. package/lib/components/dialog/DialogComponent.d.ts +0 -67
  24. package/lib/components/dialog/DialogComponent.js +0 -242
  25. package/lib/components/drop-down/DropDownComponent.d.ts +0 -27
  26. package/lib/components/drop-down/DropDownComponent.js +0 -74
  27. package/lib/components/expander/ExpanderComponent.d.ts +0 -27
  28. package/lib/components/expander/ExpanderComponent.js +0 -90
  29. package/lib/components/expander/ExpanderStyle.scss +0 -47
  30. package/lib/components/expander/OldExpanderStyle.scss +0 -37
  31. package/lib/components/form-field/FormComponent.d.ts +0 -12
  32. package/lib/components/form-field/FormComponent.js +0 -26
  33. package/lib/components/form-field/FormFieldComponent.d.ts +0 -38
  34. package/lib/components/form-field/FormFieldComponent.js +0 -139
  35. package/lib/components/form-field/FormFieldStyle.scss +0 -87
  36. package/lib/components/grid/GridComponent.d.ts +0 -26
  37. package/lib/components/grid/GridComponent.js +0 -116
  38. package/lib/components/input/InputComponent.d.ts +0 -33
  39. package/lib/components/input/InputComponent.js +0 -144
  40. package/lib/components/loading/LoadingComponent.d.ts +0 -8
  41. package/lib/components/loading/LoadingComponent.js +0 -22
  42. package/lib/components/loading/LoadingStyle.css +0 -29
  43. package/lib/components/navigation/NavigationComponent.d.ts +0 -34
  44. package/lib/components/navigation/NavigationComponent.js +0 -70
  45. package/lib/components/navigation/NavigationStyle.scss +0 -226
  46. package/lib/components/notification/Notification.d.ts +0 -17
  47. package/lib/components/notification/Notification.js +0 -56
  48. package/lib/components/notification/Notification.scss +0 -19
  49. package/lib/components/number/NumberComponent.d.ts +0 -25
  50. package/lib/components/number/NumberComponent.js +0 -87
  51. package/lib/components/overlay/OverlayComponent.d.ts +0 -27
  52. package/lib/components/overlay/OverlayComponent.js +0 -149
  53. package/lib/components/overlay/overlay.css +0 -57
  54. package/lib/components/progress/ProgressComponent.d.ts +0 -18
  55. package/lib/components/progress/ProgressComponent.js +0 -42
  56. package/lib/components/progress/ProgressStyle.scss +0 -15
  57. package/lib/components/ribbon-menu/RibbonMenuComponent.d.ts +0 -12
  58. package/lib/components/ribbon-menu/RibbonMenuComponent.js +0 -34
  59. package/lib/components/ribbon-menu/RibbonMenuStyle.scss +0 -76
  60. package/lib/components/select/SelectComponent.d.ts +0 -79
  61. package/lib/components/select/SelectComponent.js +0 -362
  62. package/lib/components/select/SelectDDAreaComponent.d.ts +0 -32
  63. package/lib/components/select/SelectDDAreaComponent.js +0 -317
  64. package/lib/components/select/SelectStyle.scss +0 -187
  65. package/lib/components/slider/nouislider.css +0 -310
  66. package/lib/components/slider/nouislider.d.ts +0 -44
  67. package/lib/components/slider/nouislider.js +0 -2158
  68. package/lib/components/stack-panel/SplitterComponent.d.ts +0 -21
  69. package/lib/components/stack-panel/SplitterComponent.js +0 -126
  70. package/lib/components/stack-panel/SplitterStyle.scss +0 -45
  71. package/lib/components/stack-panel/StackPanelComponent.d.ts +0 -20
  72. package/lib/components/stack-panel/StackPanelComponent.js +0 -64
  73. package/lib/components/stack-panel/StackPanelStyle.scss +0 -53
  74. package/lib/components/tabs/TabsComponent.d.ts +0 -39
  75. package/lib/components/tabs/TabsComponent.js +0 -177
  76. package/lib/components/tabs/TabsStyle.scss +0 -76
  77. package/lib/components/time/TimeComponent.d.ts +0 -29
  78. package/lib/components/time/TimeComponent.js +0 -113
  79. package/lib/components/time/TimeComponent.scss +0 -4
  80. package/lib/components/tree-view/TreeViewComponent.d.ts +0 -23
  81. package/lib/components/tree-view/TreeViewComponent.js +0 -45
  82. package/lib/components/tree-view/TreeViewStyle.scss +0 -96
  83. package/lib/components/virtual-render/VirtualRenderComponent.d.ts +0 -30
  84. package/lib/components/virtual-render/VirtualRenderComponent.js +0 -104
  85. package/lib/components/virtual-render/VirtualRenderStyle.scss +0 -9
  86. package/lib/core/culture.d.ts +0 -5
  87. package/lib/core/culture.js +0 -385
  88. package/lib/core/date.d.ts +0 -14
  89. package/lib/core/date.js +0 -350
  90. package/lib/core/helper.d.ts +0 -12
  91. package/lib/core/helper.js +0 -101
  92. package/lib/core/jq.d.ts +0 -37
  93. package/lib/core/jq.js +0 -371
  94. package/lib/core/lang.d.ts +0 -24
  95. package/lib/core/lang.js +0 -28
  96. package/lib/core/numeric.d.ts +0 -7
  97. package/lib/core/numeric.js +0 -143
  98. package/lib/core/polyfills.d.ts +0 -0
  99. package/lib/core/polyfills.js +0 -22
  100. package/lib/core.d.ts +0 -6
  101. package/lib/core.js +0 -6
  102. package/lib/grid/controls/slick.columnpicker.css +0 -46
  103. package/lib/grid/controls/slick.draggablegrouping.css +0 -52
  104. package/lib/grid/controls/slick.gridmenu.css +0 -127
  105. package/lib/grid/controls/slick.pager.css +0 -41
  106. package/lib/grid/examples/examples.css +0 -203
  107. package/lib/grid/filterDialogs/dateRangeFilter.d.ts +0 -7
  108. package/lib/grid/filterDialogs/dateRangeFilter.js +0 -156
  109. package/lib/grid/filterDialogs/excelFilter.d.ts +0 -9
  110. package/lib/grid/filterDialogs/excelFilter.js +0 -313
  111. package/lib/grid/plugins/ext.overlay.css +0 -28
  112. package/lib/grid/plugins/ext.overlay.d.ts +0 -2
  113. package/lib/grid/plugins/ext.overlay.js +0 -291
  114. package/lib/grid/plugins/slick.cellrangedecorator.d.ts +0 -12
  115. package/lib/grid/plugins/slick.cellrangedecorator.js +0 -68
  116. package/lib/grid/plugins/slick.cellrangeselector.d.ts +0 -1
  117. package/lib/grid/plugins/slick.cellrangeselector.js +0 -144
  118. package/lib/grid/plugins/slick.cellselectionmodel.d.ts +0 -1
  119. package/lib/grid/plugins/slick.cellselectionmodel.js +0 -194
  120. package/lib/grid/plugins/slick.headerbuttons.css +0 -40
  121. package/lib/grid/plugins/slick.headerbuttons.d.ts +0 -55
  122. package/lib/grid/plugins/slick.headerbuttons.js +0 -156
  123. package/lib/grid/plugins/slick.headermenu.css +0 -101
  124. package/lib/grid/plugins/slick.headermenu.d.ts +0 -74
  125. package/lib/grid/plugins/slick.headermenu.js +0 -260
  126. package/lib/grid/plugins/slick.rowdetailview.css +0 -37
  127. package/lib/grid/plugins/slick.rowmovemanager.css +0 -8
  128. package/lib/grid/plugins/slick.rowmovemanager.d.ts +0 -18
  129. package/lib/grid/plugins/slick.rowmovemanager.js +0 -249
  130. package/lib/grid/plugins/slick.rowselectionmodel.d.ts +0 -1
  131. package/lib/grid/plugins/slick.rowselectionmodel.js +0 -167
  132. package/lib/grid/slick-default-theme.css +0 -154
  133. package/lib/grid/slick.core.d.ts +0 -90
  134. package/lib/grid/slick.core.js +0 -574
  135. package/lib/grid/slick.creator.d.ts +0 -80
  136. package/lib/grid/slick.creator.js +0 -723
  137. package/lib/grid/slick.dataview.d.ts +0 -71
  138. package/lib/grid/slick.dataview.js +0 -1080
  139. package/lib/grid/slick.editors.core.d.ts +0 -4
  140. package/lib/grid/slick.editors.core.js +0 -232
  141. package/lib/grid/slick.editors.date.d.ts +0 -2
  142. package/lib/grid/slick.editors.date.js +0 -125
  143. package/lib/grid/slick.editors.lookup.d.ts +0 -14
  144. package/lib/grid/slick.editors.lookup.js +0 -353
  145. package/lib/grid/slick.editors.nav.d.ts +0 -6
  146. package/lib/grid/slick.editors.nav.js +0 -22
  147. package/lib/grid/slick.formatters.d.ts +0 -17
  148. package/lib/grid/slick.formatters.js +0 -137
  149. package/lib/grid/slick.grid.css +0 -325
  150. package/lib/grid/slick.grid.d.ts +0 -284
  151. package/lib/grid/slick.grid.js +0 -5395
  152. package/lib/grid/slick.groupitemmetadataprovider.d.ts +0 -39
  153. package/lib/grid/slick.groupitemmetadataprovider.js +0 -165
  154. package/lib/grid/slick.tree.css +0 -20
  155. package/lib/grid/slick.tree.d.ts +0 -33
  156. package/lib/grid/slick.tree.js +0 -220
  157. package/lib/grid.d.ts +0 -13
  158. package/lib/grid.js +0 -13
  159. package/lib/index.css +0 -2584
  160. package/lib/index.d.ts +0 -56
  161. package/lib/interaction/dataconverter.d.ts +0 -4
  162. package/lib/interaction/dataconverter.js +0 -1
  163. package/lib/interaction/eventhandler.d.ts +0 -13
  164. package/lib/interaction/eventhandler.js +0 -42
  165. package/lib/interaction/moveable.css +0 -0
  166. package/lib/interaction/moveable.d.ts +0 -39
  167. package/lib/interaction/moveable.js +0 -172
  168. package/lib/interaction/resizable.css +0 -33
  169. package/lib/interaction/resizable.d.ts +0 -37
  170. package/lib/interaction/resizable.js +0 -123
  171. package/lib/ui/auto.suggest.css +0 -14
  172. package/lib/ui/auto.suggest.d.ts +0 -17
  173. package/lib/ui/auto.suggest.js +0 -255
  174. package/lib/ui/base.css +0 -150
  175. package/lib/ui/date.picker/css/date-range-picker.css +0 -87
  176. package/lib/ui/date.picker/css/tiny-date-picker.css +0 -326
  177. package/lib/ui/date.picker/date-picker-options.d.ts +0 -11
  178. package/lib/ui/date.picker/date-picker-options.js +0 -76
  179. package/lib/ui/date.picker/lib/date-manip.d.ts +0 -74
  180. package/lib/ui/date.picker/lib/date-manip.js +0 -120
  181. package/lib/ui/date.picker/lib/dom.d.ts +0 -23
  182. package/lib/ui/date.picker/lib/dom.js +0 -28
  183. package/lib/ui/date.picker/lib/emitter.d.ts +0 -13
  184. package/lib/ui/date.picker/lib/emitter.js +0 -49
  185. package/lib/ui/date.picker/lib/fns.d.ts +0 -23
  186. package/lib/ui/date.picker/lib/fns.js +0 -43
  187. package/lib/ui/date.picker/mode/base-mode.d.ts +0 -26
  188. package/lib/ui/date.picker/mode/base-mode.js +0 -248
  189. package/lib/ui/date.picker/mode/dropdown-mode.d.ts +0 -28
  190. package/lib/ui/date.picker/mode/dropdown-mode.js +0 -50
  191. package/lib/ui/date.picker/mode/index.d.ts +0 -28
  192. package/lib/ui/date.picker/mode/index.js +0 -18
  193. package/lib/ui/date.picker/mode/modal-mode.d.ts +0 -25
  194. package/lib/ui/date.picker/mode/modal-mode.js +0 -17
  195. package/lib/ui/date.picker/mode/permanent-mode.d.ts +0 -29
  196. package/lib/ui/date.picker/mode/permanent-mode.js +0 -19
  197. package/lib/ui/date.picker/views/day-picker.d.ts +0 -40
  198. package/lib/ui/date.picker/views/day-picker.js +0 -155
  199. package/lib/ui/date.picker/views/month-picker.d.ts +0 -26
  200. package/lib/ui/date.picker/views/month-picker.js +0 -65
  201. package/lib/ui/date.picker/views/year-picker.d.ts +0 -20
  202. package/lib/ui/date.picker/views/year-picker.js +0 -66
  203. package/lib/ui/date.picker.d.ts +0 -66
  204. package/lib/ui/date.picker.js +0 -32
  205. package/lib/ui/dialog.css +0 -109
  206. package/lib/ui/dialog.d.ts +0 -22
  207. package/lib/ui/dialog.js +0 -113
  208. package/lib/ui/drop.down.css +0 -472
  209. package/lib/ui/drop.down.d.ts +0 -52
  210. package/lib/ui/drop.down.js +0 -2112
  211. package/lib/ui/number.input.css +0 -3
  212. package/lib/ui/number.input.d.ts +0 -12
  213. package/lib/ui/number.input.js +0 -64
  214. package/lib/ui/tabs.css +0 -53
@@ -1,2112 +0,0 @@
1
- /*!
2
- * Selectr 2.4.12
3
- * http://mobius.ovh/docs/selectr
4
- *
5
- * Released under the MIT license
6
- */
7
- import "./drop.down.css";
8
- import { UILang } from "../core/lang";
9
- var Selectr;
10
- (function () {
11
- /**
12
- * Event Emitter
13
- */
14
- var Events = function () { };
15
- /**
16
- * Event Prototype
17
- * @type {Object}
18
- */
19
- Events.prototype = {
20
- /**
21
- * Add custom event listener
22
- * @param {String} event Event type
23
- * @param {Function} func Callback
24
- * @return {Void}
25
- */
26
- on: function (event, func) {
27
- this._events = this._events || {};
28
- this._events[event] = this._events[event] || [];
29
- this._events[event].push(func);
30
- },
31
- /**
32
- * Remove custom event listener
33
- * @param {String} event Event type
34
- * @param {Function} func Callback
35
- * @return {Void}
36
- */
37
- off: function (event, func) {
38
- this._events = this._events || {};
39
- if (event in this._events === false)
40
- return;
41
- this._events[event].splice(this._events[event].indexOf(func), 1);
42
- },
43
- /**
44
- * Fire a custom event
45
- * @param {String} event Event type
46
- * @return {Void}
47
- */
48
- emit: function (event /* , args... */) {
49
- this._events = this._events || {};
50
- if (event in this._events === false)
51
- return;
52
- for (var i = 0; i < this._events[event].length; i++) {
53
- this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
54
- }
55
- }
56
- };
57
- /**
58
- * Event mixin
59
- * @param {Object} obj
60
- * @return {Object}
61
- */
62
- Events.mixin = function (obj) {
63
- var props = ['on', 'off', 'emit'];
64
- for (var i = 0; i < props.length; i++) {
65
- if (typeof obj === 'function') {
66
- obj.prototype[props[i]] = Events.prototype[props[i]];
67
- }
68
- else {
69
- obj[props[i]] = Events.prototype[props[i]];
70
- }
71
- }
72
- return obj;
73
- };
74
- /**
75
- * Helpers
76
- * @type {Object}
77
- */
78
- var util = {
79
- escapeRegExp: function (str) {
80
- // source from lodash 3.0.0
81
- var _reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
82
- var _reHasRegExpChar = new RegExp(_reRegExpChar.source);
83
- return (str && _reHasRegExpChar.test(str)) ? str.replace(_reRegExpChar, '\\$&') : str;
84
- },
85
- extend: function (src, props) {
86
- for (var prop in props) {
87
- if (props.hasOwnProperty(prop)) {
88
- var val = props[prop];
89
- if (val && Object.prototype.toString.call(val) === "[object Object]") {
90
- src[prop] = src[prop] || {};
91
- util.extend(src[prop], val);
92
- }
93
- else {
94
- src[prop] = val;
95
- }
96
- }
97
- }
98
- return src;
99
- },
100
- each: function (a, b, c) {
101
- if ("[object Object]" === Object.prototype.toString.call(a)) {
102
- for (var d in a) {
103
- if (Object.prototype.hasOwnProperty.call(a, d)) {
104
- b.call(c, d, a[d], a);
105
- }
106
- }
107
- }
108
- else {
109
- for (var e = 0, f = a.length; e < f; e++) {
110
- b.call(c, e, a[e], a);
111
- }
112
- }
113
- },
114
- createElement: function (e, a) {
115
- var d = document, el = d.createElement(e);
116
- if (a && "[object Object]" === Object.prototype.toString.call(a)) {
117
- var i;
118
- for (i in a) {
119
- if (a[i] !== undefined) {
120
- if (i in el)
121
- el[i] = a[i];
122
- else if ("html" === i)
123
- el.innerHTML = a[i];
124
- else
125
- el.setAttribute(i, a[i]);
126
- }
127
- }
128
- }
129
- return el;
130
- },
131
- hasClass: function (a, b) {
132
- if (a) {
133
- // if (a.classList == null) {
134
- // debugger;
135
- // }
136
- return a.classList ? a.classList.contains(b) : !!a.className && !!a.className.match(new RegExp("(\\s|^)" + b + "(\\s|$)"));
137
- }
138
- },
139
- addClass: function (a, b) {
140
- if (!util.hasClass(a, b)) {
141
- if (a.classList) {
142
- a.classList.add(b);
143
- }
144
- else {
145
- a.className = a.className.trim() + " " + b;
146
- }
147
- }
148
- },
149
- removeClass: function (a, b) {
150
- if (util.hasClass(a, b)) {
151
- if (a.classList) {
152
- a.classList.remove(b);
153
- }
154
- else {
155
- a.className = a.className.replace(new RegExp("(^|\\s)" + b.split(" ").join("|") + "(\\s|$)", "gi"), " ");
156
- }
157
- }
158
- },
159
- closest: function (el, fn) {
160
- return el && el !== document.body && (fn(el) ? el : util.closest(el.parentNode, fn));
161
- },
162
- isInt: function (val) {
163
- return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
164
- },
165
- debounce: function (a, b, c) {
166
- var d;
167
- return function () {
168
- var e = this, f = arguments, g = function () {
169
- d = null;
170
- if (!c)
171
- a.apply(e, f);
172
- }, h = c && !d;
173
- clearTimeout(d);
174
- d = setTimeout(g, b);
175
- if (h) {
176
- a.apply(e, f);
177
- }
178
- };
179
- },
180
- rect: function (el, abs) {
181
- var w = window;
182
- var r = el.getBoundingClientRect();
183
- var x = abs ? w.pageXOffset : 0;
184
- var y = abs ? w.pageYOffset : 0;
185
- return {
186
- bottom: r.bottom + y,
187
- height: r.height,
188
- left: r.left + x,
189
- right: r.right + x,
190
- top: r.top + y,
191
- width: r.width
192
- };
193
- },
194
- includes: function (a, b) {
195
- return a.indexOf(b) > -1;
196
- },
197
- startsWith: function (a, b) {
198
- return a.substr(0, b.length) === b;
199
- },
200
- truncate: function (el) {
201
- while (el.firstChild) {
202
- el.removeChild(el.firstChild);
203
- }
204
- },
205
- toDom: function (item) {
206
- var elementData = {
207
- class: "jsl-option",
208
- role: "treeitem",
209
- "aria-selected": false,
210
- html: item.html,
211
- textContent: item.html ? undefined : item.text
212
- };
213
- var opt = util.createElement("li", elementData);
214
- opt.idx = item.idx;
215
- if (item.disabled) {
216
- opt.disabled = true;
217
- util.addClass(opt, "disabled");
218
- }
219
- if (item.active) {
220
- util.addClass(opt, "active");
221
- }
222
- if (item.selected) {
223
- util.addClass(opt, "selected");
224
- opt.selected = true;
225
- }
226
- return opt;
227
- }
228
- };
229
- function isset(obj, prop) {
230
- return obj.hasOwnProperty(prop) && (obj[prop] === true || obj[prop].length);
231
- }
232
- /**
233
- * Append an item to the list
234
- * @param {Object} item
235
- * @param {Object} custom
236
- * @return {Void}
237
- */
238
- function appendItem(vitem, parent, custom) {
239
- var item = vitem.dom = util.toDom(vitem);
240
- if (vitem.optgroup && vitem.optgroup.parentNode == null) {
241
- parent.appendChild(vitem.optgroup);
242
- }
243
- parent.appendChild(item);
244
- // if (item.parentNode) {
245
- // if (!item.parentNode.parentNode) {
246
- // parent.appendChild(item.parentNode);
247
- // }
248
- // } else
249
- // {
250
- // parent.appendChild(item);
251
- // }
252
- // util.removeClass(item, "excluded");
253
- if (!custom) {
254
- // remove any <span> highlighting, without xss
255
- item.textContent = item.textContent;
256
- }
257
- }
258
- /**
259
- * Render the item list
260
- * @return {Void}
261
- */
262
- var render = function () {
263
- if (this.items.length) {
264
- var f = document.createDocumentFragment();
265
- if (this.config.pagination) {
266
- var pages = this.pages.slice(0, this.pageIndex);
267
- util.each(pages, function (i, items) {
268
- util.each(items, function (j, item) {
269
- appendItem(item, f, this.customOption);
270
- }, this);
271
- }, this);
272
- }
273
- else {
274
- util.each(this.items, function (i, item) {
275
- appendItem(item, f, this.customOption);
276
- }, this);
277
- }
278
- // highlight first selected option if any; first option otherwise
279
- if (f.childElementCount || f.childNodes.length) {
280
- removeActive(this.tree);
281
- this.navIndex = (f.querySelector(".jsl-option.selected") ||
282
- f.querySelector(".jsl-option")).idx;
283
- if (!this.config.multiple) {
284
- util.addClass(this.items[this.navIndex].dom, "active");
285
- this.items[this.navIndex].active = true;
286
- }
287
- }
288
- this.tree.appendChild(f);
289
- }
290
- };
291
- /**
292
- * Dismiss / close the dropdown
293
- * @param {obj} e
294
- * @return {void}
295
- */
296
- var dismiss = function (e) {
297
- var target = e.target;
298
- if (!this.container.contains(target) && (this.opened || util.hasClass(this.container, "notice"))) {
299
- this.close();
300
- }
301
- };
302
- /**
303
- * Build a list item from the HTMLOptionElement
304
- * @param {int} i HTMLOptionElement index
305
- * @param {HTMLOptionElement} option
306
- * @param {bool} group Has parent optgroup
307
- * @return {void}
308
- */
309
- var createItem = function (option, data) {
310
- data = data || option;
311
- var elementData = {
312
- class: "jsl-option",
313
- role: "treeitem",
314
- "aria-selected": option.selected,
315
- html: undefined,
316
- textContent: undefined
317
- };
318
- if (this.customOption) {
319
- elementData.html = this.config.renderOption(data); // asume xss prevention in custom render function
320
- }
321
- else {
322
- elementData.textContent = option.textContent; // treat all as plain text
323
- }
324
- // var opt = util.createElement("li",elementData);
325
- var opt = { idx: 0, disabled: option.disabled, html: elementData.html, text: elementData.textContent, parent: null, selected: option.selected };
326
- opt.idx = option.idx;
327
- opt.parent = option.parent;
328
- this.items.push(opt);
329
- if (option.defaultSelected) {
330
- this.defaultSelected.push(option.idx);
331
- }
332
- // if (option.disabled) {
333
- // opt.disabled = true;
334
- // // util.addClass(opt, "disabled");
335
- // }
336
- // if (option.selected) {
337
- // opt.selected = true;
338
- // // util.addClass(opt, "selected");
339
- // }
340
- return opt;
341
- };
342
- var removeActive = function (container) {
343
- var items = container.querySelectorAll("li.active");
344
- for (var i = 0; i < items.length; i++) {
345
- items[i].classList.remove("active");
346
- }
347
- };
348
- /**
349
- * Build the container
350
- * @return {Void}
351
- */
352
- var build = function () {
353
- this.requiresPagination = this.config.pagination && this.config.pagination > 0;
354
- // Set width
355
- if (isset(this.config, "width")) {
356
- if (util.isInt(this.config.width)) {
357
- this.width = this.config.width + "px";
358
- }
359
- else {
360
- if (this.config.width === "auto") {
361
- this.width = "100%";
362
- }
363
- else { // if (util.includes(this.config.width, "%")) {
364
- this.width = this.config.width;
365
- }
366
- }
367
- }
368
- this.container = util.createElement("div", {
369
- class: "jsl-container"
370
- });
371
- // Custom className
372
- if (this.config.customClass) {
373
- util.addClass(this.container, this.config.customClass);
374
- }
375
- // Mobile device
376
- if (this.mobileDevice) {
377
- util.addClass(this.container, "jsl-mobile");
378
- }
379
- else {
380
- util.addClass(this.container, "jsl-desktop");
381
- }
382
- // Hide the HTMLSelectElement and prevent focus
383
- this.el.tabIndex = -1;
384
- // Native dropdown
385
- if (this.config.nativeDropdown || this.mobileDevice) {
386
- util.addClass(this.el, "jsl-visible");
387
- }
388
- else {
389
- util.addClass(this.el, "jsl-hidden");
390
- }
391
- this.selected = util.createElement("div", {
392
- class: "jsl-selected",
393
- disabled: this.disabled,
394
- tabIndex: 0,
395
- "aria-expanded": false
396
- });
397
- this.label = util.createElement(this.el.multiple ? "ul" : "span", {
398
- class: "jsl-label"
399
- });
400
- var dropdown = util.createElement("div", {
401
- class: "jsl-options-container"
402
- });
403
- this.tree = util.createElement("ul", {
404
- class: "jsl-options",
405
- role: "tree",
406
- "aria-hidden": true,
407
- "aria-expanded": false
408
- });
409
- this.notice = util.createElement("div", {
410
- class: "jsl-notice"
411
- });
412
- this.el.setAttribute("aria-hidden", true);
413
- if (this.disabled) {
414
- this.el.disabled = true;
415
- }
416
- if (this.el.multiple) {
417
- util.addClass(this.label, "jsl-tags");
418
- util.addClass(this.container, "multiple");
419
- // Collection of tags
420
- this.tags = [];
421
- // Collection of selected values
422
- // #93 defaultSelected = false did not work as expected
423
- this.selectedValues = (this.config.defaultSelected) ? this.getSelectedProperties('value') : [];
424
- // Collection of selected indexes
425
- this.selectedIndexes = this.getSelectedProperties('idx');
426
- }
427
- else {
428
- // #93 defaultSelected = false did not work as expected
429
- // these values were undefined
430
- this.selectedValue = null;
431
- this.selectedIndex = -1;
432
- }
433
- this.selected.appendChild(this.label);
434
- if (this.config.clearable) {
435
- this.selectClear = util.createElement("button", {
436
- class: "jsl-clear",
437
- type: "button"
438
- });
439
- this.container.appendChild(this.selectClear);
440
- util.addClass(this.container, "clearable");
441
- }
442
- if (this.config.taggable) {
443
- var li = util.createElement('li', {
444
- class: 'input-tag'
445
- });
446
- this.input = util.createElement("input", {
447
- class: "jsl-tag-input",
448
- placeholder: this.config.tagPlaceholder,
449
- tagIndex: 0,
450
- autocomplete: "off",
451
- autocorrect: "off",
452
- autocapitalize: "off",
453
- spellcheck: "false",
454
- role: "textbox",
455
- type: "search"
456
- });
457
- li.appendChild(this.input);
458
- this.label.appendChild(li);
459
- util.addClass(this.container, "taggable");
460
- this.tagSeperators = [","];
461
- if (this.config.tagSeperators) {
462
- this.tagSeperators = this.tagSeperators.concat(this.config.tagSeperators);
463
- var _aTempEscapedSeperators = [];
464
- for (var _nTagSeperatorStepCount = 0; _nTagSeperatorStepCount < this.tagSeperators.length; _nTagSeperatorStepCount++) {
465
- _aTempEscapedSeperators.push(util.escapeRegExp(this.tagSeperators[_nTagSeperatorStepCount]));
466
- }
467
- this.tagSeperatorsRegex = new RegExp(_aTempEscapedSeperators.join('|'), 'i');
468
- }
469
- else {
470
- this.tagSeperatorsRegex = new RegExp(',', 'i');
471
- }
472
- }
473
- if (this.config.searchable) {
474
- this.input = util.createElement("input", {
475
- class: "jsl-input",
476
- tagIndex: -1,
477
- autocomplete: "off",
478
- autocorrect: "off",
479
- autocapitalize: "off",
480
- spellcheck: "false",
481
- role: "textbox",
482
- // type: "search",
483
- type: "text",
484
- placeholder: this.config.messages.searchPlaceholder
485
- });
486
- this.inputClear = util.createElement("button", {
487
- class: "jsl-input-clear",
488
- type: "button"
489
- });
490
- this.inputContainer = util.createElement("div", {
491
- class: "jsl-input-container"
492
- });
493
- this.inputContainer.appendChild(this.input);
494
- this.inputContainer.appendChild(this.inputClear);
495
- dropdown.appendChild(this.inputContainer);
496
- }
497
- dropdown.appendChild(this.notice);
498
- dropdown.appendChild(this.tree);
499
- // List of items for the dropdown
500
- this.items = [];
501
- // Establish options
502
- this.options = [];
503
- // Check for options in the element
504
- if (this.el.options.length) {
505
- this.options = [].slice.call(this.el.options);
506
- }
507
- // Element may have optgroups so
508
- // iterate element.children instead of element.options
509
- var group = false, j = 0;
510
- if (this.el.children.length) {
511
- util.each(this.el.children, function (i, element) {
512
- if (element.nodeName === "OPTGROUP") {
513
- group = util.createElement("ul", {
514
- class: "jsl-optgroup",
515
- role: "group",
516
- html: "<li class='jsl-optgroup--label'>" + element.label + "</li>"
517
- });
518
- util.each(element.children, function (x, el) {
519
- el.idx = j;
520
- var itm = createItem.call(this, el, group);
521
- itm.optgroup = group;
522
- // group.appendChild(util.toDom(itm));
523
- j++;
524
- }, this);
525
- }
526
- else {
527
- element.idx = j;
528
- createItem.call(this, element);
529
- j++;
530
- }
531
- }, this);
532
- }
533
- // Options defined by the data option
534
- if (this.config.data && Array.isArray(this.config.data)) {
535
- this.data = [];
536
- var optgroup = false, option;
537
- group = false;
538
- j = 0;
539
- util.each(this.config.data, function (i, opt) {
540
- // Check for group options
541
- if (isset(opt, "children")) {
542
- optgroup = util.createElement("optgroup", {
543
- label: opt.text
544
- });
545
- group = util.createElement("ul", {
546
- class: "jsl-optgroup",
547
- role: "group",
548
- html: "<li class='jsl-optgroup--label'>" + opt.text + "</li>"
549
- });
550
- util.each(opt.children, function (x, data) {
551
- option = new Option(data.text, data.value, false, data.hasOwnProperty("selected") && data.selected === true);
552
- option.disabled = isset(data, "disabled");
553
- this.options.push(option);
554
- optgroup.appendChild(option);
555
- option.idx = j;
556
- var itm = createItem.call(this, option, data);
557
- itm.optgroup = group;
558
- // group.appendChild(util.toDom(itm));
559
- this.data[j] = data;
560
- j++;
561
- }, this);
562
- this.el.appendChild(optgroup);
563
- }
564
- else {
565
- option = new Option(opt.text, opt.value, false, opt.hasOwnProperty("selected") && opt.selected === true);
566
- option.disabled = isset(opt, "disabled");
567
- this.options.push(option);
568
- option.idx = j;
569
- createItem.call(this, option, opt);
570
- this.data[j] = opt;
571
- j++;
572
- }
573
- }, this);
574
- }
575
- this.setSelected(true);
576
- var first;
577
- this.navIndex = 0;
578
- for (var i = 0; i < this.items.length; i++) {
579
- first = this.items[i];
580
- if (!first.disabled) {
581
- first.active = true;
582
- this.navIndex = i;
583
- break;
584
- }
585
- // if (!util.hasClass(first, "disabled")) {
586
- // util.addClass(first, "active");
587
- // this.navIndex = i;
588
- // break;
589
- // }
590
- }
591
- // Check for pagination / infinite scroll
592
- this.pageIndex = 1;
593
- // Create the pages
594
- this.paginate();
595
- this.container.appendChild(this.selected);
596
- this.container.appendChild(dropdown);
597
- this.placeEl = util.createElement("div", {
598
- class: "jsl-placeholder"
599
- });
600
- // Set the placeholder
601
- this.setPlaceholder();
602
- this.selected.appendChild(this.placeEl);
603
- // Disable if required
604
- if (this.disabled) {
605
- this.disable();
606
- }
607
- this.el.parentNode.insertBefore(this.container, this.el);
608
- this.container.appendChild(this.el);
609
- };
610
- /**
611
- * Navigate through the dropdown
612
- * @param {obj} e
613
- * @return {void}
614
- */
615
- var navigate = function (e) {
616
- e = e || window.event;
617
- // Filter out the keys we don"t want
618
- if (!this.items.length || !this.opened || !util.includes([13, 38, 40], e.which)) {
619
- this.navigating = false;
620
- return;
621
- }
622
- e.preventDefault();
623
- if (e.which === 13) {
624
- if (this.noResults || (this.config.taggable && this.input.value.length > 0)) {
625
- return false;
626
- }
627
- return this.change(this.navIndex);
628
- }
629
- var direction, prevEl = this.items[this.navIndex];
630
- var lastIndex = this.navIndex;
631
- switch (e.which) {
632
- case 38:
633
- direction = 0;
634
- if (this.navIndex > 0) {
635
- this.navIndex--;
636
- }
637
- break;
638
- case 40:
639
- direction = 1;
640
- if (this.navIndex < this.items.length - 1) {
641
- this.navIndex++;
642
- }
643
- }
644
- this.navigating = true;
645
- function validForSelection(itm) {
646
- if (itm == null || itm.dom == null) {
647
- return false;
648
- }
649
- return !util.hasClass(itm.dom, "disabled") && !util.hasClass(itm.dom, "excluded");
650
- }
651
- // Instead of wasting memory holding a copy of this.items
652
- // with disabled / excluded options omitted, skip them instead
653
- // while (util.hasClass(this.items[this.navIndex], "disabled") || util.hasClass(this.items[this.navIndex], "excluded")) {
654
- while (!validForSelection(this.items[this.navIndex])) {
655
- if (this.navIndex > 0 && this.navIndex < this.items.length - 1) {
656
- if (direction) {
657
- this.navIndex++;
658
- }
659
- else {
660
- this.navIndex--;
661
- }
662
- }
663
- else {
664
- this.navIndex = lastIndex;
665
- break;
666
- }
667
- if (this.searching) {
668
- if (this.navIndex > this.tree.lastElementChild.idx) {
669
- this.navIndex = this.tree.lastElementChild.idx;
670
- break;
671
- }
672
- else if (this.navIndex < this.tree.firstElementChild.idx) {
673
- this.navIndex = this.tree.firstElementChild.idx;
674
- break;
675
- }
676
- }
677
- }
678
- // Autoscroll the dropdown during navigation
679
- var r = util.rect(this.items[this.navIndex].dom);
680
- if (!direction) {
681
- if (this.navIndex === 0) {
682
- this.tree.scrollTop = 0;
683
- }
684
- else if (r.top - this.optsRect.top < 0) {
685
- this.tree.scrollTop = this.tree.scrollTop + (r.top - this.optsRect.top);
686
- }
687
- }
688
- else {
689
- if (this.navIndex === 0) {
690
- this.tree.scrollTop = 0;
691
- }
692
- else if ((r.top + r.height) > (this.optsRect.top + this.optsRect.height)) {
693
- this.tree.scrollTop = this.tree.scrollTop + ((r.top + r.height) - (this.optsRect.top + this.optsRect.height));
694
- }
695
- // Load another page if needed
696
- if (this.navIndex === this.tree.childElementCount - 1 && this.requiresPagination) {
697
- load.call(this);
698
- }
699
- }
700
- if (prevEl) {
701
- removeActive(this.tree);
702
- prevEl.active = false;
703
- }
704
- util.addClass(this.items[this.navIndex].dom, "active");
705
- this.items[this.navIndex].active = true;
706
- };
707
- /**
708
- * Add a tag
709
- * @param {HTMLElement} item
710
- */
711
- var addTag = function (item) {
712
- var that = this, r;
713
- var docFrag = document.createDocumentFragment();
714
- var option = this.options[item.idx];
715
- var data = this.data ? this.data[item.idx] : option;
716
- var elementData = { class: "jsl-tag", html: undefined, textContent: undefined };
717
- if (this.customSelected) {
718
- elementData.html = this.config.renderSelection(data); // asume xss prevention in custom render function
719
- }
720
- else {
721
- elementData.textContent = option.textContent;
722
- }
723
- var tag = util.createElement("li", elementData);
724
- var btn = util.createElement("button", {
725
- class: "jsl-tag-remove",
726
- type: "button"
727
- });
728
- tag.appendChild(btn);
729
- // Set property to check against later
730
- tag.idx = item.idx;
731
- tag.tag = option.value;
732
- this.tags.push(tag);
733
- if (this.config.sortSelected) {
734
- var tags = this.tags.slice();
735
- // Deal with values that contain numbers
736
- r = function (val, arr) {
737
- val.replace(/(\d+)|(\D+)/g, function (that, $1, $2) {
738
- arr.push([$1 || Infinity, $2 || ""]);
739
- });
740
- };
741
- tags.sort(function (a, b) {
742
- var x = [], y = [], ac, bc;
743
- if (that.config.sortSelected === true) {
744
- ac = a.tag;
745
- bc = b.tag;
746
- }
747
- else if (that.config.sortSelected === 'text') {
748
- ac = a.textContent;
749
- bc = b.textContent;
750
- }
751
- r(ac, x);
752
- r(bc, y);
753
- while (x.length && y.length) {
754
- var ax = x.shift();
755
- var by = y.shift();
756
- var nn = (ax[0] - by[0]) || ax[1].localeCompare(by[1]);
757
- if (nn)
758
- return nn;
759
- }
760
- return x.length - y.length;
761
- });
762
- util.each(tags, function (i, tg) {
763
- docFrag.appendChild(tg);
764
- });
765
- this.label.innerHTML = "";
766
- }
767
- else {
768
- docFrag.appendChild(tag);
769
- }
770
- if (this.config.taggable) {
771
- this.label.insertBefore(docFrag, this.input.parentNode);
772
- }
773
- else {
774
- this.label.appendChild(docFrag);
775
- }
776
- };
777
- /**
778
- * Remove a tag
779
- * @param {HTMLElement} item
780
- * @return {void}
781
- */
782
- var removeTag = function (item) {
783
- var tag = false;
784
- util.each(this.tags, function (i, t) {
785
- if (t.idx === item.idx) {
786
- tag = t;
787
- }
788
- }, this);
789
- if (tag) {
790
- this.label.removeChild(tag);
791
- this.tags.splice(this.tags.indexOf(tag), 1);
792
- }
793
- };
794
- /**
795
- * Load the next page of items
796
- * @return {void}
797
- */
798
- var load = function () {
799
- // sometimes atBottom = false when atBottom < 0.xxx pixel smaller than "this.pageIndex < this.pages.length"
800
- var margin = 1; // solution: add a bit of margin
801
- var tree = this.tree;
802
- var scrollTop = tree.scrollTop;
803
- var scrollHeight = tree.scrollHeight;
804
- var offsetHeight = tree.offsetHeight;
805
- var atBottom = scrollTop + margin >= (scrollHeight - offsetHeight);
806
- if ((atBottom && this.pageIndex < this.pages.length)) {
807
- var f = document.createDocumentFragment();
808
- util.each(this.pages[this.pageIndex], function (i, item) {
809
- appendItem(item, f, this.customOption);
810
- }, this);
811
- tree.appendChild(f);
812
- this.pageIndex++;
813
- this.emit("selectr.paginate", {
814
- items: this.items.length,
815
- total: this.data.length,
816
- page: this.pageIndex,
817
- pages: this.pages.length
818
- });
819
- }
820
- };
821
- /**
822
- * Clear a search
823
- * @return {void}
824
- */
825
- var clearSearch = function () {
826
- this.searchResults = null;
827
- if (this.config.searchable || this.config.taggable) {
828
- this.input.value = null;
829
- this.searching = false;
830
- if (this.config.searchable) {
831
- util.removeClass(this.inputContainer, "active");
832
- }
833
- if (util.hasClass(this.container, "notice")) {
834
- util.removeClass(this.container, "notice");
835
- util.addClass(this.container, "open");
836
- this.input.focus();
837
- }
838
- util.each(this.items, function (i, item) {
839
- // Items that didn't match need the class
840
- // removing to make them visible again
841
- if (item.dom) {
842
- util.removeClass(item.dom, "excluded");
843
- }
844
- // Remove the span element for underlining matched items
845
- if (!this.customOption) {
846
- // without xss
847
- item.textContent = item.textContent;
848
- }
849
- }, this);
850
- this.pageIndex = 1;
851
- this.paginate();
852
- }
853
- };
854
- // /**
855
- // * Query matching for searches.
856
- // * Wraps matching text in a span.jsl-match.
857
- // *
858
- // * @param {string} query
859
- // * @param {HTMLOptionElement} option element
860
- // * @return {bool} true if matched; false otherwise
861
- // */
862
- // var match = function (query, option) {
863
- // var text = option.textContent;
864
- // var RX = new RegExp(query, "ig");
865
- // var result = RX.exec(text);
866
- // if (result) {
867
- // // #102 stop xss
868
- // option.innerHTML = "";
869
- // var span = document.createElement("span");
870
- // span.classList.add("jsl-match");
871
- // span.textContent = result[0];
872
- // option.appendChild(document.createTextNode(text.substring(0, result.index)));
873
- // option.appendChild(span);
874
- // option.appendChild(document.createTextNode(text.substring(RX.lastIndex)));
875
- // return true;
876
- // }
877
- // return false;
878
- // };
879
- // Main Lib
880
- Selectr = function (el, config) {
881
- if (!el) {
882
- throw new Error("You must supply either a HTMLSelectElement or a CSS3 selector string.");
883
- }
884
- this.el = el;
885
- // CSS3 selector string
886
- if (typeof el === "string") {
887
- this.el = document.querySelector(el);
888
- }
889
- if (this.el === null) {
890
- throw new Error("The element you passed to Selectr can not be found.");
891
- }
892
- if (this.el.nodeName.toLowerCase() !== "select") {
893
- throw new Error("The element you passed to Selectr is not a HTMLSelectElement.");
894
- }
895
- this.render(config);
896
- };
897
- /**
898
- * Render the instance
899
- * @param {object} config
900
- * @return {void}
901
- */
902
- Selectr.prototype.render = function (config) {
903
- if (this.rendered)
904
- return;
905
- /**
906
- * Default configuration options
907
- * @type {Object}
908
- */
909
- var defaultConfig = {
910
- /**
911
- * Emulates browser behaviour by selecting the first option by default
912
- * @type {Boolean}
913
- */
914
- defaultSelected: true,
915
- /**
916
- * Sets the width of the container
917
- * @type {String}
918
- */
919
- width: "auto",
920
- /**
921
- * Enables/ disables the container
922
- * @type {Boolean}
923
- */
924
- disabled: false,
925
- /**
926
- * Enables/ disables logic for mobile
927
- * @type {Boolean}
928
- */
929
- disabledMobile: true,
930
- /**
931
- * Enables / disables the search function
932
- * @type {Boolean}
933
- */
934
- searchable: true,
935
- /**
936
- * Enable disable the clear button
937
- * @type {Boolean}
938
- */
939
- clearable: false,
940
- /**
941
- * Sort the tags / multiselect options
942
- * @type {Boolean}
943
- */
944
- sortSelected: false,
945
- /**
946
- * Allow deselecting of select-one options
947
- * @type {Boolean}
948
- */
949
- allowDeselect: false,
950
- /**
951
- * Close the dropdown when scrolling (@AlexanderReiswich, #11)
952
- * @type {Boolean}
953
- */
954
- closeOnScroll: false,
955
- /**
956
- * Allow the use of the native dropdown (@jonnyscholes, #14)
957
- * @type {Boolean}
958
- */
959
- nativeDropdown: false,
960
- /**
961
- * Allow the use of native typing behavior for toggling, searching, selecting
962
- * @type {boolean}
963
- */
964
- nativeKeyboard: false,
965
- /**
966
- * Set the main placeholder
967
- * @type {String}
968
- */
969
- placeholder: UILang.dropDown.SelectOption,
970
- /**
971
- * Allow the tagging feature
972
- * @type {Boolean}
973
- */
974
- taggable: false,
975
- /**
976
- * Set the tag input placeholder (@labikmartin, #21, #22)
977
- * @type {String}
978
- */
979
- tagPlaceholder: UILang.dropDown.SelectOptionMultiple,
980
- messages: {
981
- noResults: UILang.dropDown.NoResults,
982
- noOptions: UILang.dropDown.NoOptions,
983
- maxSelections: UILang.dropDown.MaxSelection,
984
- tagDuplicate: UILang.dropDown.AlreadyInUse,
985
- searchPlaceholder: UILang.dropDown.Search
986
- }
987
- };
988
- // add instance reference (#87)
989
- this.el.selectr = this;
990
- // Merge defaults with user set config
991
- this.config = util.extend(defaultConfig, config);
992
- // Store type
993
- this.originalType = this.el.type;
994
- // Store tabIndex
995
- this.originalIndex = this.el.tabIndex;
996
- // Store defaultSelected options for form reset
997
- this.defaultSelected = [];
998
- // Store the original option count
999
- this.originalOptionCount = this.el.options.length;
1000
- if (this.config.multiple || this.config.taggable) {
1001
- this.el.multiple = true;
1002
- }
1003
- // Disabled?
1004
- this.disabled = isset(this.config, "disabled");
1005
- this.opened = false;
1006
- if (this.config.taggable) {
1007
- this.config.searchable = false;
1008
- }
1009
- this.navigating = false;
1010
- this.mobileDevice = false;
1011
- if (!this.config.disabledMobile && /Android|webOS|iPhone|iPad|BlackBerry|Windows Phone|Opera Mini|IEMobile|Mobile/i.test(navigator.userAgent)) {
1012
- this.mobileDevice = true;
1013
- }
1014
- this.customOption = this.config.hasOwnProperty("renderOption") && typeof this.config.renderOption === "function";
1015
- this.customSelected = this.config.hasOwnProperty("renderSelection") && typeof this.config.renderSelection === "function";
1016
- this.supportsEventPassiveOption = this.detectEventPassiveOption();
1017
- // Enable event emitter
1018
- Events.mixin(this);
1019
- build.call(this);
1020
- this.bindEvents();
1021
- this.update();
1022
- this.optsRect = util.rect(this.tree);
1023
- this.rendered = true;
1024
- // Fixes macOS Safari bug #28
1025
- if (!this.el.multiple) {
1026
- this.el.selectedIndex = this.selectedIndex;
1027
- }
1028
- var that = this;
1029
- setTimeout(function () {
1030
- that.emit("selectr.init");
1031
- }, 20);
1032
- };
1033
- Selectr.prototype.getSelected = function () {
1034
- var selected = this.el.querySelectorAll('option:checked');
1035
- return selected;
1036
- };
1037
- Selectr.prototype.getSelectedProperties = function (prop) {
1038
- var selected = this.getSelected();
1039
- var values = [].slice.call(selected)
1040
- .map(function (option) { return option[prop]; })
1041
- .filter(function (i) { return i !== null && i !== undefined; });
1042
- return values;
1043
- };
1044
- /**
1045
- * Feature detection: addEventListener passive option
1046
- * https://dom.spec.whatwg.org/#dom-addeventlisteneroptions-passive
1047
- * https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
1048
- */
1049
- Selectr.prototype.detectEventPassiveOption = function () {
1050
- var supportsPassiveOption = false;
1051
- try {
1052
- var opts = Object.defineProperty({}, 'passive', {
1053
- get: function () {
1054
- supportsPassiveOption = true;
1055
- }
1056
- });
1057
- window.addEventListener('test', null, opts);
1058
- }
1059
- catch (e) { }
1060
- return supportsPassiveOption;
1061
- };
1062
- /**
1063
- * Attach the required event listeners
1064
- */
1065
- Selectr.prototype.bindEvents = function () {
1066
- var that = this;
1067
- this.events = {};
1068
- this.events.dismiss = dismiss.bind(this);
1069
- this.events.navigate = navigate.bind(this);
1070
- this.events.reset = this.reset.bind(this);
1071
- if (this.config.nativeDropdown || this.mobileDevice) {
1072
- this.container.addEventListener("touchstart", function (e) {
1073
- if (e.changedTouches[0].target === that.el) {
1074
- that.toggle();
1075
- }
1076
- }, this.supportsEventPassiveOption ? { passive: true } : false);
1077
- this.container.addEventListener("click", function (e) {
1078
- if (e.target === that.el) {
1079
- that.toggle();
1080
- }
1081
- });
1082
- var getChangedOptions = function (last, current) {
1083
- var added = [], removed = last.slice(0);
1084
- var idx;
1085
- for (var i = 0; i < current.length; i++) {
1086
- idx = removed.indexOf(current[i]);
1087
- if (idx > -1)
1088
- removed.splice(idx, 1);
1089
- else
1090
- added.push(current[i]);
1091
- }
1092
- return [added, removed];
1093
- };
1094
- // Listen for the change on the native select
1095
- // and update accordingly
1096
- this.el.addEventListener("change", function (e) {
1097
- if (e.__selfTriggered) {
1098
- return;
1099
- }
1100
- if (that.el.multiple) {
1101
- var indexes = that.getSelectedProperties('idx');
1102
- var changes = getChangedOptions(that.selectedIndexes, indexes);
1103
- util.each(changes[0], function (i, idx) {
1104
- that.select(idx);
1105
- }, that);
1106
- util.each(changes[1], function (i, idx) {
1107
- that.deselect(idx);
1108
- }, that);
1109
- }
1110
- else {
1111
- if (that.el.selectedIndex > -1) {
1112
- that.select(that.el.selectedIndex);
1113
- }
1114
- }
1115
- });
1116
- }
1117
- // Open the dropdown with Enter key if focused
1118
- if (this.config.nativeDropdown) {
1119
- this.container.addEventListener("keydown", function (e) {
1120
- if (e.key === "Enter" && that.selected === document.activeElement) {
1121
- // show native dropdown
1122
- that.toggle();
1123
- // focus on it
1124
- setTimeout(function () {
1125
- that.el.focus();
1126
- }, 200);
1127
- }
1128
- });
1129
- }
1130
- // Non-native dropdown
1131
- this.selected.addEventListener("click", function (e) {
1132
- if (!that.disabled) {
1133
- that.toggle();
1134
- }
1135
- e.preventDefault();
1136
- });
1137
- if (this.config.nativeKeyboard) {
1138
- var typing = '';
1139
- var typingTimeout = null;
1140
- this.selected.addEventListener("keydown", function (e) {
1141
- // Do nothing if disabled, not focused, or modifier keys are pressed
1142
- if (that.disabled ||
1143
- that.selected !== document.activeElement ||
1144
- (e.altKey || e.ctrlKey || e.metaKey)) {
1145
- return;
1146
- }
1147
- // Open the dropdown on [enter], [ ], [↓], and [↑] keys
1148
- if (e.key === " " ||
1149
- (!that.opened && ["Enter", "ArrowUp", "ArrowDown"].indexOf(e.key) > -1)) {
1150
- that.toggle();
1151
- e.preventDefault();
1152
- e.stopPropagation();
1153
- return;
1154
- }
1155
- // Type to search if multiple; type to select otherwise
1156
- // make sure e.key is a single, printable character
1157
- // .length check is a short-circut to skip checking keys like "ArrowDown", etc.
1158
- // prefer "codePoint" methods; they work with the full range of unicode
1159
- if (e.key.length <= 2 &&
1160
- String[String.fromCodePoint ? "fromCodePoint" : "fromCharCode"](e.key[String.codePointAt ? "codePointAt" : "charCodeAt"](0)) === e.key) {
1161
- if (that.config.multiple) {
1162
- that.open();
1163
- if (that.config.searchable) {
1164
- that.input.value = e.key;
1165
- that.input.focus();
1166
- that.search(null, that.options.exactSearch);
1167
- }
1168
- }
1169
- else {
1170
- if (typingTimeout) {
1171
- clearTimeout(typingTimeout);
1172
- }
1173
- typing += e.key;
1174
- var found = that.search(typing, that.options.exactSearch);
1175
- if (found && found.length) {
1176
- that.clear();
1177
- that.setValue(found[0].value);
1178
- }
1179
- setTimeout(function () { typing = ''; }, 1000);
1180
- }
1181
- e.preventDefault();
1182
- e.stopPropagation();
1183
- return;
1184
- }
1185
- });
1186
- // Close the dropdown on [esc] key
1187
- this.container.addEventListener("keyup", function (e) {
1188
- if (that.opened && e.key === "Escape") {
1189
- that.close();
1190
- e.stopPropagation();
1191
- // keep focus so we can re-open easily if desired
1192
- that.selected.focus();
1193
- }
1194
- });
1195
- }
1196
- // Remove tag
1197
- this.label.addEventListener("click", function (e) {
1198
- if (!that.disabled && util.hasClass(e.target, "jsl-tag-remove")) {
1199
- that.deselect(e.target.parentNode.idx);
1200
- }
1201
- });
1202
- // Clear input
1203
- if (this.selectClear) {
1204
- this.selectClear.addEventListener("click", this.clear.bind(this));
1205
- }
1206
- // Prevent text selection
1207
- this.tree.addEventListener("mousedown", function (e) {
1208
- e.preventDefault();
1209
- });
1210
- // Select / deselect items
1211
- this.tree.addEventListener("click", function (e) {
1212
- var item = util.closest(e.target, function (el) {
1213
- return el && util.hasClass(el, "jsl-option");
1214
- });
1215
- if (item) {
1216
- if (!util.hasClass(item, "disabled")) {
1217
- if (util.hasClass(item, "selected")) {
1218
- if (that.el.multiple || !that.el.multiple && that.config.allowDeselect) {
1219
- that.deselect(item.idx);
1220
- }
1221
- }
1222
- else {
1223
- that.select(item.idx);
1224
- }
1225
- if (that.opened && !that.el.multiple) {
1226
- that.close();
1227
- }
1228
- }
1229
- }
1230
- e.preventDefault();
1231
- e.stopPropagation();
1232
- });
1233
- // Mouseover list items
1234
- this.tree.addEventListener("mouseover", function (e) {
1235
- if (util.hasClass(e.target, "jsl-option")) {
1236
- if (!util.hasClass(e.target, "disabled")) {
1237
- removeActive(that.tree);
1238
- util.addClass(e.target, "active");
1239
- that.navIndex = -1;
1240
- for (var idx = 0; idx < that.items.length; idx++) {
1241
- if (that.items[idx].dom === e.target) {
1242
- that.navIndex = idx;
1243
- }
1244
- }
1245
- // that.navIndex = [].slice.call(that.items).indexOf(e.target);
1246
- }
1247
- }
1248
- });
1249
- // Searchable
1250
- if (this.config.searchable) {
1251
- // Show / hide the search input clear button
1252
- this.input.addEventListener("focus", function (e) {
1253
- that.searching = true;
1254
- });
1255
- this.input.addEventListener("blur", function (e) {
1256
- that.searching = false;
1257
- });
1258
- this.input.addEventListener("input", function (e) {
1259
- that.search();
1260
- if (!that.config.taggable) {
1261
- // Show / hide the search input clear button
1262
- if (this.value.length) {
1263
- util.addClass(this.parentNode, "active");
1264
- }
1265
- else {
1266
- util.removeClass(this.parentNode, "active");
1267
- }
1268
- }
1269
- });
1270
- // Clear the search input
1271
- this.inputClear.addEventListener("click", function (e) {
1272
- that.input.value = null;
1273
- clearSearch.call(that);
1274
- if (!that.tree.childElementCount) {
1275
- render.call(that);
1276
- }
1277
- });
1278
- }
1279
- if (this.config.taggable) {
1280
- this.input.addEventListener("keyup", function (e) {
1281
- that.search();
1282
- if (that.config.taggable && this.value.length) {
1283
- var _sVal = this.value.trim();
1284
- if (_sVal.length && (e.which === 13 || that.tagSeperatorsRegex.test(_sVal))) {
1285
- var _sGrabbedTagValue = _sVal.replace(that.tagSeperatorsRegex, '');
1286
- _sGrabbedTagValue = util.escapeRegExp(_sGrabbedTagValue);
1287
- _sGrabbedTagValue = _sGrabbedTagValue.trim();
1288
- var _oOption;
1289
- if (_sGrabbedTagValue.length) {
1290
- _oOption = that.add({
1291
- value: _sGrabbedTagValue,
1292
- textContent: _sGrabbedTagValue,
1293
- selected: true
1294
- }, true);
1295
- }
1296
- if (_oOption) {
1297
- that.close();
1298
- clearSearch.call(that);
1299
- }
1300
- else {
1301
- this.value = '';
1302
- that.setMessage(that.config.messages.tagDuplicate);
1303
- }
1304
- }
1305
- }
1306
- });
1307
- }
1308
- this.update = util.debounce(function () {
1309
- // Optionally close dropdown on scroll / resize (#11)
1310
- if (that.opened && that.config.closeOnScroll) {
1311
- that.close();
1312
- }
1313
- if (that.width) {
1314
- that.container.style.width = that.width;
1315
- }
1316
- that.invert();
1317
- }, 50);
1318
- if (this.requiresPagination) {
1319
- this.paginateItems = util.debounce(function () {
1320
- load.call(this);
1321
- }, 50);
1322
- this.tree.addEventListener("scroll", this.paginateItems.bind(this));
1323
- }
1324
- // Dismiss when clicking outside the container
1325
- document.addEventListener("click", this.events.dismiss);
1326
- this.container.addEventListener("keydown", this.events.navigate);
1327
- window.addEventListener("resize", this.update);
1328
- window.addEventListener("scroll", this.update);
1329
- // remove event listeners on destroy()
1330
- this.on('selectr.destroy', function () {
1331
- document.removeEventListener("click", this.events.dismiss);
1332
- this.container.removeEventListener("keydown", this.events.navigate);
1333
- window.removeEventListener("resize", this.update);
1334
- window.removeEventListener("scroll", this.update);
1335
- });
1336
- // Listen for form.reset() (@ambrooks, #13)
1337
- if (this.el.form) {
1338
- this.el.form.addEventListener("reset", this.events.reset);
1339
- // remove listener on destroy()
1340
- this.on('selectr.destroy', function () {
1341
- this.el.form.removeEventListener("reset", this.events.reset);
1342
- });
1343
- }
1344
- };
1345
- /**
1346
- * Check for selected options
1347
- * @param {bool} reset
1348
- */
1349
- Selectr.prototype.setSelected = function (reset) {
1350
- // Select first option as with a native select-one element - #21, #24
1351
- if (!this.config.data && !this.el.multiple && this.el.options.length) {
1352
- // Browser has selected the first option by default
1353
- if (this.el.selectedIndex === 0) {
1354
- if (!this.el.options[0].defaultSelected && !this.config.defaultSelected) {
1355
- this.el.selectedIndex = -1;
1356
- }
1357
- }
1358
- this.selectedIndex = this.el.selectedIndex;
1359
- if (this.selectedIndex > -1) {
1360
- this.select(this.selectedIndex);
1361
- }
1362
- }
1363
- // If we're changing a select-one to select-multiple via the config
1364
- // and there are no selected options, the first option will be selected by the browser
1365
- // Let's prevent that here.
1366
- if (this.config.multiple && this.originalType === "select-one" && !this.config.data) {
1367
- if (this.el.options[0].selected && !this.el.options[0].defaultSelected) {
1368
- this.el.options[0].selected = false;
1369
- }
1370
- }
1371
- util.each(this.options, function (i, option) {
1372
- if (option.selected && option.defaultSelected) {
1373
- this.select(option.idx);
1374
- }
1375
- }, this);
1376
- if (this.config.selectedValue) {
1377
- this.setValue(this.config.selectedValue);
1378
- }
1379
- if (this.config.data) {
1380
- if (!this.el.multiple && this.config.defaultSelected && this.el.selectedIndex < 0 && this.config.data.length > 0) {
1381
- this.select(0);
1382
- }
1383
- var j = 0;
1384
- util.each(this.config.data, function (i, opt) {
1385
- // Check for group options
1386
- if (isset(opt, "children")) {
1387
- util.each(opt.children, function (x, item) {
1388
- if (item.hasOwnProperty("selected") && item.selected === true) {
1389
- this.select(j);
1390
- }
1391
- j++;
1392
- }, this);
1393
- }
1394
- else {
1395
- if (opt.hasOwnProperty("selected") && opt.selected === true) {
1396
- this.select(j);
1397
- }
1398
- j++;
1399
- }
1400
- }, this);
1401
- }
1402
- };
1403
- /**
1404
- * Destroy the instance
1405
- * @return {void}
1406
- */
1407
- Selectr.prototype.destroy = function () {
1408
- if (!this.rendered)
1409
- return;
1410
- this.emit("selectr.destroy");
1411
- // Revert to select-single if programtically set to multiple
1412
- if (this.originalType === 'select-one') {
1413
- this.el.multiple = false;
1414
- }
1415
- if (this.config.data) {
1416
- this.el.innerHTML = "";
1417
- }
1418
- // Remove the className from select element
1419
- util.removeClass(this.el, 'jsl-hidden');
1420
- // Replace the container with the original select element
1421
- this.container.parentNode.replaceChild(this.el, this.container);
1422
- this.rendered = false;
1423
- // remove reference
1424
- delete this.el.selectr;
1425
- };
1426
- /**
1427
- * Change an options state
1428
- * @param {Number} index
1429
- * @return {void}
1430
- */
1431
- Selectr.prototype.change = function (index) {
1432
- var item = this.items[index], option = this.options[index];
1433
- if (option.disabled) {
1434
- return;
1435
- }
1436
- if (option.selected && util.hasClass(item, "selected")) {
1437
- this.deselect(index);
1438
- }
1439
- else {
1440
- this.select(index);
1441
- }
1442
- if (this.opened && !this.el.multiple) {
1443
- this.close();
1444
- }
1445
- };
1446
- /**
1447
- * Select an option
1448
- * @param {Number} index
1449
- * @return {void}
1450
- */
1451
- Selectr.prototype.select = function (index) {
1452
- var item = this.items[index], options = [].slice.call(this.el.options), option = this.options[index];
1453
- if (this.el.multiple) {
1454
- if (util.includes(this.selectedIndexes, index)) {
1455
- return false;
1456
- }
1457
- if (this.config.maxSelections && this.tags.length === this.config.maxSelections) {
1458
- this.setMessage(this.config.messages.maxSelections.replace("{max}", this.config.maxSelections), true);
1459
- return false;
1460
- }
1461
- this.selectedValues.push(option.value);
1462
- this.selectedIndexes.push(index);
1463
- addTag.call(this, item);
1464
- }
1465
- else {
1466
- var data = this.data ? this.data[index] : option;
1467
- if (this.customSelected) {
1468
- this.label.innerHTML = this.config.renderSelection(data);
1469
- }
1470
- else {
1471
- // no xss
1472
- this.label.textContent = option.textContent;
1473
- }
1474
- this.selectedValue = option.value;
1475
- this.selectedIndex = index;
1476
- util.each(this.options, function (i, o) {
1477
- var opt = this.items[i];
1478
- if (i !== index) {
1479
- if (o) {
1480
- util.removeClass(o, "selected");
1481
- o.removeAttribute("selected");
1482
- }
1483
- opt.selected = false;
1484
- opt.active = false;
1485
- }
1486
- }, this);
1487
- }
1488
- if (!util.includes(options, option)) {
1489
- this.el.add(option);
1490
- }
1491
- item.selected = true;
1492
- // item.dom.setAttribute("aria-selected", true);
1493
- // util.addClass(item.dom, "selected");
1494
- util.addClass(this.container, "has-selected");
1495
- option.selected = true;
1496
- option.setAttribute("selected", "");
1497
- this.emit("selectr.change", option);
1498
- this.emit("selectr.select", option);
1499
- // fire native change event
1500
- if ("createEvent" in document) {
1501
- var evt = document.createEvent("HTMLEvents");
1502
- evt.initEvent("change", true, true);
1503
- evt.__selfTriggered = true;
1504
- this.el.dispatchEvent(evt);
1505
- }
1506
- else {
1507
- this.el.fireEvent("onchange");
1508
- }
1509
- };
1510
- /**
1511
- * Deselect an option
1512
- * @param {Number} index
1513
- * @return {void}
1514
- */
1515
- Selectr.prototype.deselect = function (index, force) {
1516
- var item = this.items[index], option = this.options[index];
1517
- if (this.el.multiple) {
1518
- var selIndex = this.selectedIndexes.indexOf(index);
1519
- this.selectedIndexes.splice(selIndex, 1);
1520
- var valIndex = this.selectedValues.indexOf(option.value);
1521
- this.selectedValues.splice(valIndex, 1);
1522
- removeTag.call(this, item);
1523
- if (!this.tags.length) {
1524
- util.removeClass(this.container, "has-selected");
1525
- }
1526
- }
1527
- else {
1528
- if (!force && !this.config.clearable && !this.config.allowDeselect) {
1529
- return false;
1530
- }
1531
- this.label.innerHTML = "";
1532
- this.selectedValue = null;
1533
- this.el.selectedIndex = this.selectedIndex = -1;
1534
- util.removeClass(this.container, "has-selected");
1535
- }
1536
- this.items[index].selected = false;
1537
- if (this.items[index].dom) {
1538
- this.items[index].dom.setAttribute("aria-selected", false);
1539
- util.removeClass(this.items[index].dom, "selected");
1540
- this.items[index].dom.selected = false;
1541
- }
1542
- option.selected = false;
1543
- option.removeAttribute("selected");
1544
- this.emit("selectr.change", null);
1545
- this.emit("selectr.deselect", option);
1546
- // fire native change event
1547
- if ("createEvent" in document) {
1548
- var evt = document.createEvent("HTMLEvents");
1549
- evt.initEvent("change", true, true);
1550
- evt.__selfTriggered = true;
1551
- this.el.dispatchEvent(evt);
1552
- }
1553
- else {
1554
- this.el.fireEvent("onchange");
1555
- }
1556
- };
1557
- /**
1558
- * Programmatically set selected values
1559
- * @param {String|Array} value - A string or an array of strings
1560
- */
1561
- Selectr.prototype.setValue = function (value) {
1562
- var isArray = Array.isArray(value);
1563
- if (!isArray) {
1564
- value = value.toString().trim();
1565
- }
1566
- // Can't pass array to select-one
1567
- if (!this.el.multiple && isArray) {
1568
- return false;
1569
- }
1570
- util.each(this.options, function (i, option) {
1571
- if (isArray && (value.indexOf(option.value) > -1) || option.value === value) {
1572
- this.change(option.idx);
1573
- }
1574
- }, this);
1575
- };
1576
- /**
1577
- * Set the selected value(s)
1578
- * @param {bool} toObject Return only the raw values or an object
1579
- * @param {bool} toJson Return the object as a JSON string
1580
- * @return {mixed} Array or String
1581
- */
1582
- Selectr.prototype.getValue = function (toObject, toJson) {
1583
- var value;
1584
- if (this.el.multiple) {
1585
- if (toObject) {
1586
- if (this.selectedIndexes.length) {
1587
- value = {};
1588
- value.values = [];
1589
- util.each(this.selectedIndexes, function (i, index) {
1590
- var option = this.options[index];
1591
- value.values[i] = {
1592
- value: option.value,
1593
- text: option.textContent
1594
- };
1595
- }, this);
1596
- }
1597
- }
1598
- else {
1599
- value = this.selectedValues.slice();
1600
- }
1601
- }
1602
- else {
1603
- if (toObject) {
1604
- var option = this.options[this.selectedIndex];
1605
- value = {
1606
- value: option.value,
1607
- text: option.textContent
1608
- };
1609
- }
1610
- else {
1611
- value = this.selectedValue;
1612
- }
1613
- }
1614
- if (toObject && toJson) {
1615
- value = JSON.stringify(value);
1616
- }
1617
- return value;
1618
- };
1619
- /**
1620
- * Add a new option or options
1621
- * @param {object} data
1622
- */
1623
- Selectr.prototype.add = function (data, checkDuplicate) {
1624
- if (data) {
1625
- this.data = this.data || [];
1626
- this.items = this.items || [];
1627
- this.options = this.options || [];
1628
- if (Array.isArray(data)) {
1629
- // We have an array on items
1630
- util.each(data, function (i, obj) {
1631
- this.add(obj, checkDuplicate);
1632
- }, this);
1633
- }
1634
- // User passed a single object to the method
1635
- // or Selectr passed an object from an array
1636
- else if ("[object Object]" === Object.prototype.toString.call(data)) {
1637
- if (checkDuplicate) {
1638
- var dupe = false;
1639
- util.each(this.options, function (i, option) {
1640
- if (option.value.toLowerCase() === data.value.toLowerCase()) {
1641
- dupe = true;
1642
- }
1643
- });
1644
- if (dupe) {
1645
- return false;
1646
- }
1647
- }
1648
- var option = util.createElement('option', data);
1649
- this.data.push(data);
1650
- // Add the new option to the list
1651
- this.options.push(option);
1652
- // Add the index for later use
1653
- option.idx = this.options.length > 0 ? this.options.length - 1 : 0;
1654
- // Create a new item
1655
- createItem.call(this, option);
1656
- // Select the item if required
1657
- if (data.selected) {
1658
- this.select(option.idx);
1659
- }
1660
- // We may have had an empty select so update
1661
- // the placeholder to reflect the changes.
1662
- this.setPlaceholder();
1663
- return option;
1664
- }
1665
- // Recount the pages
1666
- if (this.config.pagination) {
1667
- this.paginate();
1668
- }
1669
- return true;
1670
- }
1671
- };
1672
- /**
1673
- * Remove an option or options
1674
- * @param {Mixed} o Array, integer (index) or string (value)
1675
- * @return {Void}
1676
- */
1677
- Selectr.prototype.remove = function (o) {
1678
- var options = [];
1679
- if (Array.isArray(o)) {
1680
- util.each(o, function (i, opt) {
1681
- if (util.isInt(opt)) {
1682
- options.push(this.getOptionByIndex(opt));
1683
- }
1684
- else if (typeof opt === "string") {
1685
- options.push(this.getOptionByValue(opt));
1686
- }
1687
- }, this);
1688
- }
1689
- else if (util.isInt(o)) {
1690
- options.push(this.getOptionByIndex(o));
1691
- }
1692
- else if (typeof o === "string") {
1693
- options.push(this.getOptionByValue(o));
1694
- }
1695
- if (options.length) {
1696
- var index;
1697
- util.each(options, function (i, option) {
1698
- index = option.idx;
1699
- // Remove the HTMLOptionElement
1700
- this.el.remove(option);
1701
- // Remove the reference from the option array
1702
- this.options.splice(index, 1);
1703
- // If the item has a parentNode (group element) it needs to be removed
1704
- // otherwise the render function will still append it to the dropdown
1705
- var parentNode = this.items[index].parentNode;
1706
- if (parentNode) {
1707
- parentNode.removeChild(this.items[index]);
1708
- }
1709
- // Remove reference from the items array
1710
- this.items.splice(index, 1);
1711
- // Reset the indexes
1712
- util.each(this.options, function (i, opt) {
1713
- opt.idx = i;
1714
- this.items[i].idx = i;
1715
- }, this);
1716
- }, this);
1717
- // We may have had an empty select now so update
1718
- // the placeholder to reflect the changes.
1719
- this.setPlaceholder();
1720
- // Recount the pages
1721
- if (this.config.pagination) {
1722
- this.paginate();
1723
- }
1724
- }
1725
- };
1726
- /**
1727
- * Remove all options
1728
- */
1729
- Selectr.prototype.removeAll = function () {
1730
- // Clear any selected options
1731
- this.clear(true);
1732
- // Remove the HTMLOptionElements
1733
- util.each(this.el.options, function (i, option) {
1734
- this.el.remove(option);
1735
- }, this);
1736
- // Empty the dropdown
1737
- util.truncate(this.tree);
1738
- // Reset variables
1739
- this.items = [];
1740
- this.options = [];
1741
- this.data = [];
1742
- this.navIndex = 0;
1743
- if (this.requiresPagination) {
1744
- this.requiresPagination = false;
1745
- this.pageIndex = 1;
1746
- this.pages = [];
1747
- }
1748
- // Update the placeholder
1749
- this.setPlaceholder();
1750
- };
1751
- /**
1752
- * Perform a search
1753
- * @param {string}|{null} query The query string (taken from user input if null)
1754
- * @param {boolean} anchor Anchor search to beginning of strings (defaults to false)?
1755
- * @return {Array} Search results, as an array of {text, value} objects
1756
- */
1757
- Selectr.prototype.search = function (string, anchor) {
1758
- if (this.navigating) {
1759
- return;
1760
- }
1761
- // we're only going to alter the DOM for "live" searches
1762
- var live = false;
1763
- if (!string) {
1764
- string = this.input.value;
1765
- live = true;
1766
- // Remove message and clear dropdown
1767
- this.removeMessage();
1768
- util.truncate(this.tree);
1769
- }
1770
- var results = [];
1771
- var f = document.createDocumentFragment();
1772
- string = string.trim().toLowerCase();
1773
- if (string.length > 0) {
1774
- var compare = anchor ? util.startsWith : util.includes;
1775
- var counter = 0;
1776
- this.searchResults = [];
1777
- util.each(this.options, function (i, option) {
1778
- var item = this.items[option.idx];
1779
- var matches = compare(option.textContent.trim().toLowerCase(), string);
1780
- if (matches && !option.disabled) {
1781
- results.push({ text: option.textContent, value: option.value });
1782
- if (live) {
1783
- this.searchResults.push(item);
1784
- if (counter < 50) {
1785
- appendItem(item, f, this.customOption);
1786
- counter++;
1787
- util.removeClass(item.dom, "excluded");
1788
- }
1789
- // // Underline the matching results
1790
- // if (!this.customOption) {
1791
- // match(string, option);
1792
- // }
1793
- }
1794
- }
1795
- else if (live && item.dom) {
1796
- util.addClass(item.dom, "excluded");
1797
- }
1798
- }, this);
1799
- if (live) {
1800
- // Append results
1801
- if (!f.childElementCount && !f.childNodes.length) {
1802
- if (!this.config.taggable) {
1803
- this.noResults = true;
1804
- this.setMessage(this.config.messages.noResults);
1805
- }
1806
- }
1807
- else {
1808
- // Highlight top result (@binary-koan #26)
1809
- var prevEl = this.items[this.navIndex];
1810
- var firstEl = f.querySelector(".jsl-option:not(.excluded)");
1811
- this.noResults = false;
1812
- removeActive(this.tree);
1813
- // prevEl.active = false;
1814
- this.navIndex = firstEl.idx;
1815
- util.addClass(firstEl, "active");
1816
- }
1817
- this.tree.appendChild(f);
1818
- }
1819
- }
1820
- else {
1821
- clearSearch.call(this);
1822
- render.call(this);
1823
- return [];
1824
- }
1825
- this.pageIndex = 1;
1826
- this.paginate();
1827
- return results;
1828
- };
1829
- /**
1830
- * Toggle the dropdown
1831
- * @return {void}
1832
- */
1833
- Selectr.prototype.toggle = function () {
1834
- if (!this.disabled) {
1835
- if (this.opened) {
1836
- this.close();
1837
- }
1838
- else {
1839
- this.open();
1840
- }
1841
- }
1842
- };
1843
- /**
1844
- * Open the dropdown
1845
- * @return {void}
1846
- */
1847
- Selectr.prototype.open = function () {
1848
- var that = this;
1849
- if (!this.options.length) {
1850
- return false;
1851
- }
1852
- if (!this.opened) {
1853
- this.emit("selectr.open");
1854
- }
1855
- this.opened = true;
1856
- if (this.mobileDevice || this.config.nativeDropdown) {
1857
- util.addClass(this.container, "native-open");
1858
- if (this.config.data) {
1859
- // Dump the options into the select
1860
- // otherwise the native dropdown will be empty
1861
- util.each(this.options, function (i, option) {
1862
- this.el.add(option);
1863
- }, this);
1864
- }
1865
- return;
1866
- }
1867
- util.addClass(this.container, "open");
1868
- render.call(this);
1869
- this.invert();
1870
- this.tree.scrollTop = 0;
1871
- util.removeClass(this.container, "notice");
1872
- this.selected.setAttribute("aria-expanded", true);
1873
- this.tree.setAttribute("aria-hidden", false);
1874
- this.tree.setAttribute("aria-expanded", true);
1875
- if (this.config.searchable && !this.config.taggable) {
1876
- setTimeout(function () {
1877
- that.input.focus();
1878
- // Allow tab focus
1879
- that.input.tabIndex = 0;
1880
- }, 10);
1881
- }
1882
- };
1883
- /**
1884
- * Close the dropdown
1885
- * @return {void}
1886
- */
1887
- Selectr.prototype.close = function () {
1888
- if (this.opened) {
1889
- this.emit("selectr.close");
1890
- }
1891
- this.opened = false;
1892
- this.navigating = false;
1893
- if (this.mobileDevice || this.config.nativeDropdown) {
1894
- util.removeClass(this.container, "native-open");
1895
- return;
1896
- }
1897
- var notice = util.hasClass(this.container, "notice");
1898
- if (this.config.searchable && !notice) {
1899
- this.input.blur();
1900
- // Disable tab focus
1901
- this.input.tabIndex = -1;
1902
- this.searching = false;
1903
- }
1904
- if (notice) {
1905
- util.removeClass(this.container, "notice");
1906
- this.notice.textContent = "";
1907
- }
1908
- util.removeClass(this.container, "open");
1909
- util.removeClass(this.container, "native-open");
1910
- this.selected.setAttribute("aria-expanded", false);
1911
- this.tree.setAttribute("aria-hidden", true);
1912
- this.tree.setAttribute("aria-expanded", false);
1913
- util.truncate(this.tree);
1914
- clearSearch.call(this);
1915
- };
1916
- /**
1917
- * Enable the element
1918
- * @return {void}
1919
- */
1920
- Selectr.prototype.enable = function () {
1921
- this.disabled = false;
1922
- this.el.disabled = false;
1923
- this.selected.tabIndex = this.originalIndex;
1924
- if (this.el.multiple) {
1925
- util.each(this.tags, function (i, t) {
1926
- t.lastElementChild.tabIndex = 0;
1927
- });
1928
- }
1929
- util.removeClass(this.container, "jsl-disabled");
1930
- };
1931
- /**
1932
- * Disable the element
1933
- * @param {boolean} container Disable the container only (allow value submit with form)
1934
- * @return {void}
1935
- */
1936
- Selectr.prototype.disable = function (container) {
1937
- if (!container) {
1938
- this.el.disabled = true;
1939
- }
1940
- this.selected.tabIndex = -1;
1941
- if (this.el.multiple) {
1942
- util.each(this.tags, function (i, t) {
1943
- t.lastElementChild.tabIndex = -1;
1944
- });
1945
- }
1946
- this.disabled = true;
1947
- util.addClass(this.container, "jsl-disabled");
1948
- };
1949
- /**
1950
- * Reset to initial state
1951
- * @return {void}
1952
- */
1953
- Selectr.prototype.reset = function () {
1954
- if (!this.disabled) {
1955
- this.clear();
1956
- this.setSelected(true);
1957
- util.each(this.defaultSelected, function (i, idx) {
1958
- this.select(idx);
1959
- }, this);
1960
- this.emit("selectr.reset");
1961
- }
1962
- };
1963
- /**
1964
- * Clear all selections
1965
- * @return {void}
1966
- */
1967
- Selectr.prototype.clear = function (force, isClearLast) {
1968
- if (this.el.multiple) {
1969
- // Loop over the selectedIndexes so we don't have to loop over all the options
1970
- // which can be costly if there are a lot of them
1971
- if (this.selectedIndexes.length) {
1972
- // Copy the array or we'll get an error
1973
- var indexes = this.selectedIndexes.slice();
1974
- if (isClearLast) {
1975
- this.deselect(indexes.slice(-1)[0]);
1976
- }
1977
- else {
1978
- util.each(indexes, function (i, idx) {
1979
- this.deselect(idx);
1980
- }, this);
1981
- }
1982
- }
1983
- }
1984
- else {
1985
- if (this.selectedIndex > -1) {
1986
- this.deselect(this.selectedIndex, force);
1987
- }
1988
- }
1989
- this.emit("selectr.clear");
1990
- };
1991
- /**
1992
- * Return serialised data
1993
- * @param {boolean} toJson
1994
- * @return {mixed} Returns either an object or JSON string
1995
- */
1996
- Selectr.prototype.serialise = function (toJson) {
1997
- var data = [];
1998
- util.each(this.options, function (i, option) {
1999
- var obj = {
2000
- value: option.value,
2001
- text: option.textContent,
2002
- selected: undefined,
2003
- disabled: undefined
2004
- };
2005
- if (option.selected) {
2006
- obj.selected = true;
2007
- }
2008
- if (option.disabled) {
2009
- obj.disabled = true;
2010
- }
2011
- data[i] = obj;
2012
- });
2013
- return toJson ? JSON.stringify(data) : data;
2014
- };
2015
- /**
2016
- * Localised version of serialise() method
2017
- */
2018
- Selectr.prototype.serialize = function (toJson) {
2019
- return this.serialise(toJson);
2020
- };
2021
- /**
2022
- * Sets the placeholder
2023
- * @param {String} placeholder
2024
- */
2025
- Selectr.prototype.setPlaceholder = function (placeholder) {
2026
- // Set the placeholder
2027
- placeholder = placeholder || this.config.placeholder || this.el.getAttribute("placeholder");
2028
- if (!this.options.length) {
2029
- placeholder = this.config.messages.noOptions;
2030
- }
2031
- this.placeEl.innerHTML = placeholder;
2032
- };
2033
- /**
2034
- * Paginate the option list
2035
- * @return {Array}
2036
- */
2037
- Selectr.prototype.paginate = function () {
2038
- if (!this.requiresPagination) {
2039
- return;
2040
- }
2041
- var items = this.searching ? this.searchResults : this.items;
2042
- if (items.length) {
2043
- var that = this;
2044
- this.pages = items.map(function (v, i) {
2045
- return i % that.config.pagination === 0 ? items.slice(i, i + that.config.pagination) : null;
2046
- }).filter(function (pages) {
2047
- return pages;
2048
- });
2049
- return this.pages;
2050
- }
2051
- };
2052
- /**
2053
- * Display a message
2054
- * @param {String} message The message
2055
- */
2056
- Selectr.prototype.setMessage = function (message, close) {
2057
- if (close) {
2058
- this.close();
2059
- }
2060
- util.addClass(this.container, "notice");
2061
- this.notice.textContent = message;
2062
- };
2063
- /**
2064
- * Dismiss the current message
2065
- */
2066
- Selectr.prototype.removeMessage = function () {
2067
- util.removeClass(this.container, "notice");
2068
- this.notice.innerHTML = "";
2069
- };
2070
- /**
2071
- * Keep the dropdown within the window
2072
- * @return {void}
2073
- */
2074
- Selectr.prototype.invert = function () {
2075
- var rt = util.rect(this.selected), oh = this.tree.parentNode.offsetHeight, wh = window.innerHeight, doInvert = rt.top + rt.height + oh > wh;
2076
- if (doInvert) {
2077
- util.addClass(this.container, "inverted");
2078
- this.isInverted = true;
2079
- }
2080
- else {
2081
- util.removeClass(this.container, "inverted");
2082
- this.isInverted = false;
2083
- }
2084
- this.optsRect = util.rect(this.tree);
2085
- };
2086
- /**
2087
- * Get an option via it's index
2088
- * @param {Integer} index The index of the HTMLOptionElement required
2089
- * @return {HTMLOptionElement}
2090
- */
2091
- Selectr.prototype.getOptionByIndex = function (index) {
2092
- return this.options[index];
2093
- };
2094
- /**
2095
- * Get an option via it's value
2096
- * @param {String} value The value of the HTMLOptionElement required
2097
- * @return {HTMLOptionElement}
2098
- */
2099
- Selectr.prototype.getOptionByValue = function (value) {
2100
- var option = false;
2101
- for (var i = 0, l = this.options.length; i < l; i++) {
2102
- if (this.options[i].value.trim() === value.toString().trim()) {
2103
- option = this.options[i];
2104
- break;
2105
- }
2106
- }
2107
- return option;
2108
- };
2109
- })();
2110
- export var DropDown = function (input, config) {
2111
- return new Selectr(input, config);
2112
- };