j1-template 2022.0.17 → 2022.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/assets/error_pages/HTTP204.html +1 -1
- data/assets/error_pages/HTTP400.html +1 -1
- data/assets/error_pages/HTTP401.html +1 -1
- data/assets/error_pages/HTTP403.html +1 -1
- data/assets/error_pages/HTTP404.html +1 -1
- data/assets/error_pages/HTTP444.html +1 -1
- data/assets/error_pages/HTTP445.html +1 -1
- data/assets/error_pages/HTTP446.html +1 -1
- data/assets/error_pages/HTTP447.html +1 -1
- data/assets/error_pages/HTTP448.html +1 -1
- data/assets/error_pages/HTTP500.html +1 -1
- data/assets/error_pages/HTTP501.html +1 -1
- data/assets/error_pages/HTTP502.html +1 -1
- data/assets/error_pages/HTTP503.html +1 -1
- data/assets/themes/j1/adapter/js/customFunctions.js +221 -0
- data/assets/themes/j1/adapter/js/customModule.js +221 -0
- data/assets/themes/j1/adapter/js/dropdowns.js +319 -0
- data/assets/themes/j1/adapter/js/rtable.js +2 -6
- data/assets/themes/j1/modules/dropdowns/css/theme/uno/dropdowns.css +109 -0
- data/assets/themes/j1/modules/dropdowns/css/theme/uno/dropdowns.min.css +15 -0
- data/assets/themes/j1/modules/dropdowns/js/cash.js +978 -0
- data/assets/themes/j1/modules/dropdowns/js/dropdowns.js +864 -0
- data/lib/j1/commands/generate.rb +25 -14
- data/lib/j1/commands/rebuild.rb +1 -0
- data/lib/j1/commands/reset.rb +6 -3
- data/lib/j1/commands/setup.rb +18 -13
- data/lib/j1/commands/site.rb +2 -1
- data/lib/j1/utils/exec2.rb +33 -7
- data/lib/j1/version.rb +3 -3
- data/lib/starter_web/Gemfile +1 -1
- data/lib/starter_web/_config.yml +1 -1
- data/lib/starter_web/_data/apps/carousel.yml +138 -140
- data/lib/starter_web/_data/blocks/banner.yml +7 -7
- data/lib/starter_web/_data/modules/defaults/dropdowns.yml +164 -0
- data/lib/starter_web/_data/modules/dropdowns.yml +77 -0
- data/lib/starter_web/_data/resources.yml +73 -2
- data/lib/starter_web/_includes/attributes.asciidoc +1 -1
- data/lib/starter_web/_plugins/lunr_index.rb +2 -2
- data/lib/starter_web/package.json +2 -2
- data/lib/starter_web/pages/public/about/about_site.adoc +1 -1
- data/lib/starter_web/pages/public/asciidoc_skeletons/documentation/000_intro.adoc +1 -1
- data/lib/starter_web/pages/public/asciidoc_skeletons/documentation/documentation.adoc +1 -1
- data/lib/starter_web/pages/public/asciidoc_skeletons/multi-document/multi.adoc +1 -1
- data/lib/starter_web/pages/public/asciidoc_skeletons/simple-document/simple.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/100_present_images.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/100_present_images.ads.asciidoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/100_present_images.base.asciidoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/100_present_images.comments.asciidoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/200_typography.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/300_icon_fonts.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/400_asciidoc_extensions.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/410_bs_modals_extentions.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/420_responsive_tables_extensions.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/500_themes.adoc +1 -1
- data/lib/starter_web/pages/public/learn/roundtrip/600_quicksearch.adoc +1 -1
- data/lib/starter_web/pages/public/learn/where_to_go.adoc +1 -1
- data/lib/starter_web/pages/public/legal/en/100_copyright.adoc +1 -1
- data/lib/starter_web/pages/public/legal/en/200_impress.adoc +1 -1
- data/lib/starter_web/pages/public/legal/en/400_comment_policy.adoc +1 -1
- data/lib/starter_web/pages/public/manuals/j1-dropdown.adoc +294 -0
- data/lib/starter_web/pages/public/manuals/{dropdown-help.adoc → msdropdown.adoc} +0 -0
- data/lib/starter_web/pages/public/panels/intro_panel/panel.adoc +1 -1
- data/lib/starter_web/pages/public/previewer/preview_bootstrap_theme.adoc +1 -1
- data/lib/starter_web/utilsrv/_defaults/package.json +1 -1
- data/lib/starter_web/utilsrv/package.json +1 -1
- metadata +14 -6
- data/assets/themes/j1/modules/fab/css/theme/uno/fab.css +0 -373
- data/assets/themes/j1/modules/fab/css/theme/uno/fab.min.css +0 -15
@@ -0,0 +1,864 @@
|
|
1
|
+
/*
|
2
|
+
# -----------------------------------------------------------------------------
|
3
|
+
# ~/assets/themes/j1/modules/dropdowns/js/dropdowns.js
|
4
|
+
# MODIFIED DROPDOWN JS from project Materialize
|
5
|
+
# Provides JS Core funtions for the J1 DROPDOWNS Module
|
6
|
+
#
|
7
|
+
# Product/Info:
|
8
|
+
# https://jekyll.one
|
9
|
+
# https://github.com/Dogfalo/materialize
|
10
|
+
#
|
11
|
+
# Copyright (C) 2021 Juergen Adams
|
12
|
+
#
|
13
|
+
# J1 Template is licensed under the MIT License.
|
14
|
+
# See: https://github.com/jekyll-one-org/J1 Template/blob/master/LICENSE
|
15
|
+
# -----------------------------------------------------------------------------
|
16
|
+
# TODO:
|
17
|
+
# jadams, 2020-10-11: module needs to be rewitten to PURE jQuery
|
18
|
+
# -----------------------------------------------------------------------------
|
19
|
+
*/
|
20
|
+
'use strict';
|
21
|
+
|
22
|
+
// -----------------------------------------------------------------------------
|
23
|
+
// ESLint shimming
|
24
|
+
// -----------------------------------------------------------------------------
|
25
|
+
/* eslint indent: "off" */
|
26
|
+
/* eslint no-unused-vars: "off" */
|
27
|
+
/* eslint no-undef: "off" */
|
28
|
+
/* eslint no-redeclare: "off" */
|
29
|
+
/* eslint indent: "off" */
|
30
|
+
// -----------------------------------------------------------------------------
|
31
|
+
|
32
|
+
(function($, anim) {
|
33
|
+
|
34
|
+
var _defaults = {
|
35
|
+
direction: 'top',
|
36
|
+
hoverEnabled: true,
|
37
|
+
toolbarEnabled: false
|
38
|
+
};
|
39
|
+
|
40
|
+
$.fn.reverse = [].reverse;
|
41
|
+
|
42
|
+
// jadams, 2020-10-10, added class from main (materialize.js)
|
43
|
+
//
|
44
|
+
class Component {
|
45
|
+
|
46
|
+
constructor(classDef, el, options) {
|
47
|
+
// Display error if el is valid HTML Element
|
48
|
+
if (!(el instanceof Element)) {
|
49
|
+
console.error(Error(el + ' is not an HTML Element'));
|
50
|
+
}
|
51
|
+
|
52
|
+
// If exists, destroy and reinitialize in child
|
53
|
+
var ins = classDef.getInstance(el);
|
54
|
+
if (!!ins) {
|
55
|
+
ins.destroy();
|
56
|
+
}
|
57
|
+
|
58
|
+
this.el = el;
|
59
|
+
this.$el = cash(el);
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* Initializes components
|
64
|
+
* @param {class} classDef
|
65
|
+
* @param {Element | NodeList | jQuery} els
|
66
|
+
* @param {Object} options
|
67
|
+
*/
|
68
|
+
static init(classDef, els, options) {
|
69
|
+
var instances = null;
|
70
|
+
if (els instanceof Element) {
|
71
|
+
instances = new classDef(els, options);
|
72
|
+
} else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) {
|
73
|
+
var instancesArr = [];
|
74
|
+
for (var i = 0; i < els.length; i++) {
|
75
|
+
instancesArr.push(new classDef(els[i], options));
|
76
|
+
}
|
77
|
+
instances = instancesArr;
|
78
|
+
}
|
79
|
+
return instances;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Initialize jQuery wrapper for plugin
|
85
|
+
* @param {Class} plugin javascript class
|
86
|
+
* @param {string} pluginName jQuery plugin name
|
87
|
+
* @param {string} classRef Class reference name
|
88
|
+
*/
|
89
|
+
j1.initializeJqueryWrapper = function (plugin, pluginName, classRef) {
|
90
|
+
jQuery.fn[pluginName] = function (methodOrOptions) {
|
91
|
+
// Call plugin method if valid method name is passed in
|
92
|
+
if (plugin.prototype[methodOrOptions]) {
|
93
|
+
var params = Array.prototype.slice.call(arguments, 1);
|
94
|
+
|
95
|
+
// Getter methods
|
96
|
+
if (methodOrOptions.slice(0, 3) === 'get') {
|
97
|
+
var instance = this.first()[0][classRef];
|
98
|
+
return instance[methodOrOptions].apply(instance, params);
|
99
|
+
}
|
100
|
+
|
101
|
+
// Void methods
|
102
|
+
return this.each(function () {
|
103
|
+
var instance = this[classRef];
|
104
|
+
instance[methodOrOptions].apply(instance, params);
|
105
|
+
});
|
106
|
+
|
107
|
+
// Initialize plugin if options or no argument is passed in
|
108
|
+
} else if (typeof methodOrOptions === 'object' || !methodOrOptions) {
|
109
|
+
plugin.init(this, arguments[0]);
|
110
|
+
return this;
|
111
|
+
}
|
112
|
+
|
113
|
+
// Return error if an unrecognized method name is passed in
|
114
|
+
jQuery.error("Method " + methodOrOptions + " does not exist on jQuery." + pluginName);
|
115
|
+
};
|
116
|
+
};
|
117
|
+
|
118
|
+
/**
|
119
|
+
* @class
|
120
|
+
*/
|
121
|
+
class Dropdowns extends Component {
|
122
|
+
constructor(el, options) {
|
123
|
+
super(Dropdowns, el, options);
|
124
|
+
|
125
|
+
this.el.M_Dropdown = this;
|
126
|
+
Dropdowns._dropdowns.push(this);
|
127
|
+
|
128
|
+
this.id = this.getIdFromTrigger(el);
|
129
|
+
this.dropdownEl = document.getElementById(this.id);
|
130
|
+
this.$dropdownEl = $(this.dropdownEl);
|
131
|
+
|
132
|
+
/**
|
133
|
+
* Options for the dropdown
|
134
|
+
* @member Dropdowns#options
|
135
|
+
* @prop {String} [alignment='left'] - Edge which the dropdown is aligned to
|
136
|
+
* @prop {Boolean} [autoFocus=true] - Automatically focus dropdown el for keyboard
|
137
|
+
* @prop {Boolean} [constrainWidth=true] - Constrain width to width of the button
|
138
|
+
* @prop {Element} container - Container element to attach dropdown to (optional)
|
139
|
+
* @prop {Boolean} [coverTrigger=true] - Place dropdown over trigger
|
140
|
+
* @prop {Boolean} [closeOnClick=true] - Close on click of dropdown item
|
141
|
+
* @prop {Boolean} [hover=false] - Open dropdown on hover
|
142
|
+
* @prop {Number} [inDuration=150] - Duration of open animation in ms
|
143
|
+
* @prop {Number} [outDuration=250] - Duration of close animation in ms
|
144
|
+
* @prop {Function} onOpenStart - Function called when dropdown starts opening
|
145
|
+
* @prop {Function} onOpenEnd - Function called when dropdown finishes opening
|
146
|
+
* @prop {Function} onCloseStart - Function called when dropdown starts closing
|
147
|
+
* @prop {Function} onCloseEnd - Function called when dropdown finishes closing
|
148
|
+
*/
|
149
|
+
this.options = $.extend({}, Dropdowns.defaults, options);
|
150
|
+
|
151
|
+
/**
|
152
|
+
* Describes open/close state of dropdown
|
153
|
+
* @type {Boolean}
|
154
|
+
*/
|
155
|
+
this.isOpen = false;
|
156
|
+
|
157
|
+
/**
|
158
|
+
* Describes if dropdown content is scrollable
|
159
|
+
* @type {Boolean}
|
160
|
+
*/
|
161
|
+
this.isScrollable = false;
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Describes if touch moving on dropdown content
|
165
|
+
* @type {Boolean}
|
166
|
+
*/
|
167
|
+
this.isTouchMoving = false;
|
168
|
+
|
169
|
+
this.focusedIndex = -1;
|
170
|
+
this.filterQuery = [];
|
171
|
+
|
172
|
+
this.keys = {
|
173
|
+
TAB: 9,
|
174
|
+
ENTER: 13,
|
175
|
+
ESC: 27,
|
176
|
+
ARROW_UP: 38,
|
177
|
+
ARROW_DOWN: 40
|
178
|
+
};
|
179
|
+
|
180
|
+
// Move dropdown-content after dropdown-trigger
|
181
|
+
if (!!this.options.container) {
|
182
|
+
$(this.options.container).append(this.dropdownEl);
|
183
|
+
} else {
|
184
|
+
this.$el.after(this.dropdownEl);
|
185
|
+
}
|
186
|
+
|
187
|
+
this._makeDropdownFocusable();
|
188
|
+
this._resetFilterQueryBound = this._resetFilterQuery.bind(this);
|
189
|
+
this._handleDocumentClickBound = this._handleDocumentClick.bind(this);
|
190
|
+
this._handleDocumentTouchmoveBound = this._handleDocumentTouchmove.bind(this);
|
191
|
+
this._handleDropdownClickBound = this._handleDropdownClick.bind(this);
|
192
|
+
this._handleDropdownKeydownBound = this._handleDropdownKeydown.bind(this);
|
193
|
+
this._handleTriggerKeydownBound = this._handleTriggerKeydown.bind(this);
|
194
|
+
this._setupEventHandlers();
|
195
|
+
}
|
196
|
+
|
197
|
+
static get defaults() {
|
198
|
+
return _defaults;
|
199
|
+
}
|
200
|
+
|
201
|
+
static init(els, options) {
|
202
|
+
return super.init(this, els, options);
|
203
|
+
}
|
204
|
+
|
205
|
+
/**
|
206
|
+
* Get Instance
|
207
|
+
*/
|
208
|
+
static getInstance(el) {
|
209
|
+
let domElem = !!el.jquery ? el[0] : el;
|
210
|
+
return domElem.M_Dropdown;
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* Gets id of component from a trigger
|
215
|
+
* @param {Element} trigger trigger
|
216
|
+
* @returns {string}
|
217
|
+
*/
|
218
|
+
getIdFromTrigger (trigger) {
|
219
|
+
var id = trigger.getAttribute('data-target');
|
220
|
+
if (!id) {
|
221
|
+
id = trigger.getAttribute('href');
|
222
|
+
if (id) {
|
223
|
+
id = id.slice(1);
|
224
|
+
} else {
|
225
|
+
id = '';
|
226
|
+
}
|
227
|
+
}
|
228
|
+
return id;
|
229
|
+
}
|
230
|
+
|
231
|
+
// ---------------------------------------------------------------------------
|
232
|
+
// executeFunctionByName()
|
233
|
+
// execute a function by NAME (functionName) in a browser context
|
234
|
+
// (e.g. window) the function is published
|
235
|
+
// ---------------------------------------------------------------------------
|
236
|
+
executeFunctionByName (functionName, context /*, args */) {
|
237
|
+
var args = Array.prototype.slice.call(arguments, 2);
|
238
|
+
var namespaces = functionName.split('.');
|
239
|
+
var func = namespaces.pop();
|
240
|
+
for(var i = 0; i < namespaces.length; i++) {
|
241
|
+
context = context[namespaces[i]];
|
242
|
+
}
|
243
|
+
return context[func].apply(context, args);
|
244
|
+
}
|
245
|
+
|
246
|
+
checkPossibleAlignments (el, container, bounding, offset) {
|
247
|
+
var canAlign = {
|
248
|
+
top: true,
|
249
|
+
right: true,
|
250
|
+
bottom: true,
|
251
|
+
left: true,
|
252
|
+
spaceOnTop: null,
|
253
|
+
spaceOnRight: null,
|
254
|
+
spaceOnBottom: null,
|
255
|
+
spaceOnLeft: null
|
256
|
+
};
|
257
|
+
|
258
|
+
var containerAllowsOverflow = getComputedStyle(container).overflow === 'visible';
|
259
|
+
var containerRect = container.getBoundingClientRect();
|
260
|
+
var containerHeight = Math.min(containerRect.height, window.innerHeight);
|
261
|
+
var containerWidth = Math.min(containerRect.width, window.innerWidth);
|
262
|
+
var elOffsetRect = el.getBoundingClientRect();
|
263
|
+
|
264
|
+
var scrollLeft = container.scrollLeft;
|
265
|
+
var scrollTop = container.scrollTop;
|
266
|
+
|
267
|
+
var scrolledX = bounding.left - scrollLeft;
|
268
|
+
var scrolledYTopEdge = bounding.top - scrollTop;
|
269
|
+
var scrolledYBottomEdge = bounding.top + elOffsetRect.height - scrollTop;
|
270
|
+
|
271
|
+
// Check for container and viewport for left
|
272
|
+
canAlign.spaceOnRight = !containerAllowsOverflow ? containerWidth - (scrolledX + bounding.width) : window.innerWidth - (elOffsetRect.left + bounding.width);
|
273
|
+
if (canAlign.spaceOnRight < 0) {
|
274
|
+
canAlign.left = false;
|
275
|
+
}
|
276
|
+
|
277
|
+
// Check for container and viewport for Right
|
278
|
+
canAlign.spaceOnLeft = !containerAllowsOverflow ? scrolledX - bounding.width + elOffsetRect.width : elOffsetRect.right - bounding.width;
|
279
|
+
if (canAlign.spaceOnLeft < 0) {
|
280
|
+
canAlign.right = false;
|
281
|
+
}
|
282
|
+
|
283
|
+
// Check for container and viewport for Top
|
284
|
+
canAlign.spaceOnBottom = !containerAllowsOverflow ? containerHeight - (scrolledYTopEdge + bounding.height + offset) : window.innerHeight - (elOffsetRect.top + bounding.height + offset);
|
285
|
+
if (canAlign.spaceOnBottom < 0) {
|
286
|
+
canAlign.top = false;
|
287
|
+
}
|
288
|
+
|
289
|
+
// Check for container and viewport for Bottom
|
290
|
+
canAlign.spaceOnTop = !containerAllowsOverflow ? scrolledYBottomEdge - (bounding.height - offset) : elOffsetRect.bottom - (bounding.height + offset);
|
291
|
+
if (canAlign.spaceOnTop < 0) {
|
292
|
+
canAlign.bottom = false;
|
293
|
+
}
|
294
|
+
|
295
|
+
return canAlign;
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Teardown component
|
300
|
+
*/
|
301
|
+
destroy() {
|
302
|
+
this._resetDropdownStyles();
|
303
|
+
this._removeEventHandlers();
|
304
|
+
Dropdowns._dropdowns.splice(Dropdowns._dropdowns.indexOf(this), 1);
|
305
|
+
this.el.M_Dropdown = undefined;
|
306
|
+
}
|
307
|
+
|
308
|
+
/**
|
309
|
+
* Setup Event Handlers
|
310
|
+
*/
|
311
|
+
_setupEventHandlers() {
|
312
|
+
// Trigger keydown handler
|
313
|
+
this.el.addEventListener('keydown', this._handleTriggerKeydownBound);
|
314
|
+
|
315
|
+
// Item click handler
|
316
|
+
this.dropdownEl.addEventListener('click', this._handleDropdownClickBound);
|
317
|
+
|
318
|
+
// Hover event handlers
|
319
|
+
if (this.options.hover) {
|
320
|
+
this._handleMouseEnterBound = this._handleMouseEnter.bind(this);
|
321
|
+
this.el.addEventListener('mouseenter', this._handleMouseEnterBound);
|
322
|
+
this._handleMouseLeaveBound = this._handleMouseLeave.bind(this);
|
323
|
+
this.el.addEventListener('mouseleave', this._handleMouseLeaveBound);
|
324
|
+
this.dropdownEl.addEventListener('mouseleave', this._handleMouseLeaveBound);
|
325
|
+
|
326
|
+
// Click event handlers
|
327
|
+
} else {
|
328
|
+
this._handleClickBound = this._handleClick.bind(this);
|
329
|
+
this.el.addEventListener('click', this._handleClickBound);
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
/**
|
334
|
+
* Remove Event Handlers
|
335
|
+
*/
|
336
|
+
_removeEventHandlers() {
|
337
|
+
this.el.removeEventListener('keydown', this._handleTriggerKeydownBound);
|
338
|
+
this.dropdownEl.removeEventListener('click', this._handleDropdownClickBound);
|
339
|
+
|
340
|
+
if (this.options.hover) {
|
341
|
+
this.el.removeEventListener('mouseenter', this._handleMouseEnterBound);
|
342
|
+
this.el.removeEventListener('mouseleave', this._handleMouseLeaveBound);
|
343
|
+
this.dropdownEl.removeEventListener('mouseleave', this._handleMouseLeaveBound);
|
344
|
+
} else {
|
345
|
+
this.el.removeEventListener('click', this._handleClickBound);
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
349
|
+
_setupTemporaryEventHandlers() {
|
350
|
+
// Use capture phase event handler to prevent click
|
351
|
+
document.body.addEventListener('click', this._handleDocumentClickBound, true);
|
352
|
+
document.body.addEventListener('touchend', this._handleDocumentClickBound);
|
353
|
+
document.body.addEventListener('touchmove', this._handleDocumentTouchmoveBound);
|
354
|
+
this.dropdownEl.addEventListener('keydown', this._handleDropdownKeydownBound);
|
355
|
+
}
|
356
|
+
|
357
|
+
_removeTemporaryEventHandlers() {
|
358
|
+
// Use capture phase event handler to prevent click
|
359
|
+
document.body.removeEventListener('click', this._handleDocumentClickBound, true);
|
360
|
+
document.body.removeEventListener('touchend', this._handleDocumentClickBound);
|
361
|
+
document.body.removeEventListener('touchmove', this._handleDocumentTouchmoveBound);
|
362
|
+
this.dropdownEl.removeEventListener('keydown', this._handleDropdownKeydownBound);
|
363
|
+
}
|
364
|
+
|
365
|
+
_handleClick(e) {
|
366
|
+
e.preventDefault();
|
367
|
+
this.open();
|
368
|
+
}
|
369
|
+
|
370
|
+
_handleMouseEnter() {
|
371
|
+
this.open();
|
372
|
+
}
|
373
|
+
|
374
|
+
_handleMouseLeave(e) {
|
375
|
+
let toEl = e.toElement || e.relatedTarget;
|
376
|
+
let leaveToDropdownContent = !!$(toEl).closest('.dropdown-content').length;
|
377
|
+
let leaveToActiveDropdownTrigger = false;
|
378
|
+
|
379
|
+
let $closestTrigger = $(toEl).closest('.dropdowns');
|
380
|
+
if (
|
381
|
+
$closestTrigger.length &&
|
382
|
+
!!$closestTrigger[0].M_Dropdown &&
|
383
|
+
$closestTrigger[0].M_Dropdown.isOpen
|
384
|
+
) {
|
385
|
+
leaveToActiveDropdownTrigger = true;
|
386
|
+
}
|
387
|
+
|
388
|
+
// Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content
|
389
|
+
if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) {
|
390
|
+
this.close();
|
391
|
+
}
|
392
|
+
}
|
393
|
+
|
394
|
+
_handleDocumentClick(e) {
|
395
|
+
let $target = $(e.target);
|
396
|
+
if (
|
397
|
+
this.options.closeOnClick &&
|
398
|
+
$target.closest('.dropdown-content').length &&
|
399
|
+
!this.isTouchMoving
|
400
|
+
) {
|
401
|
+
// isTouchMoving to check if scrolling on mobile.
|
402
|
+
setTimeout(() => {
|
403
|
+
this.close();
|
404
|
+
}, 0);
|
405
|
+
} else if (
|
406
|
+
$target.closest('.dropdowns').length ||
|
407
|
+
!$target.closest('.dropdown-content').length
|
408
|
+
) {
|
409
|
+
setTimeout(() => {
|
410
|
+
this.close();
|
411
|
+
}, 0);
|
412
|
+
}
|
413
|
+
this.isTouchMoving = false;
|
414
|
+
}
|
415
|
+
|
416
|
+
_handleTriggerKeydown(e) {
|
417
|
+
// ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdowns
|
418
|
+
if ((e.which === this.keys.ARROW_DOWN || e.which === this.keys.ENTER) && !this.isOpen) {
|
419
|
+
e.preventDefault();
|
420
|
+
this.open();
|
421
|
+
}
|
422
|
+
}
|
423
|
+
|
424
|
+
/**
|
425
|
+
* Handle Document Touchmove
|
426
|
+
* @param {Event} e
|
427
|
+
*/
|
428
|
+
_handleDocumentTouchmove(e) {
|
429
|
+
let $target = $(e.target);
|
430
|
+
if ($target.closest('.dropdown-content').length) {
|
431
|
+
this.isTouchMoving = true;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
|
435
|
+
/**
|
436
|
+
* Handle Dropdowns Click
|
437
|
+
* @param {Event} e
|
438
|
+
*/
|
439
|
+
_handleDropdownClick(e) {
|
440
|
+
|
441
|
+
// onItemClick callback (by reference)
|
442
|
+
// if (typeof this.options.onItemClick === 'function') {
|
443
|
+
// let itemEl = $(e.target).closest('li')[0];
|
444
|
+
// this.options.onItemClick.call(this, itemEl);
|
445
|
+
// }
|
446
|
+
|
447
|
+
// onItemClick callback (by name)
|
448
|
+
if (this.options.onItemClick !== 'false') {
|
449
|
+
var _this = this;
|
450
|
+
// var itemEl = $(e.target).closest('li')[0];
|
451
|
+
this.executeFunctionByName(this.options.onItemClick, window, _this);
|
452
|
+
}
|
453
|
+
}
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Handle Dropdowns Keydown
|
457
|
+
* @param {Event} e
|
458
|
+
*/
|
459
|
+
_handleDropdownKeydown(e) {
|
460
|
+
if (e.which === this.keys.TAB) {
|
461
|
+
e.preventDefault();
|
462
|
+
this.close();
|
463
|
+
|
464
|
+
// Navigate down dropdown list
|
465
|
+
} else if ((e.which === this.keys.ARROW_DOWN || e.which === this.keys.ARROW_UP) && this.isOpen) {
|
466
|
+
e.preventDefault();
|
467
|
+
let direction = e.which === this.keys.ARROW_DOWN ? 1 : -1;
|
468
|
+
let newFocusedIndex = this.focusedIndex;
|
469
|
+
let foundNewIndex = false;
|
470
|
+
do {
|
471
|
+
newFocusedIndex = newFocusedIndex + direction;
|
472
|
+
|
473
|
+
if (
|
474
|
+
!!this.dropdownEl.children[newFocusedIndex] &&
|
475
|
+
this.dropdownEl.children[newFocusedIndex].tabIndex !== -1
|
476
|
+
) {
|
477
|
+
foundNewIndex = true;
|
478
|
+
break;
|
479
|
+
}
|
480
|
+
} while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0);
|
481
|
+
|
482
|
+
if (foundNewIndex) {
|
483
|
+
this.focusedIndex = newFocusedIndex;
|
484
|
+
this._focusFocusedItem();
|
485
|
+
}
|
486
|
+
|
487
|
+
// ENTER selects choice on focused item
|
488
|
+
} else if (e.which === this.keys.ENTER && this.isOpen) {
|
489
|
+
// Search for <a> and <button>
|
490
|
+
let focusedElement = this.dropdownEl.children[this.focusedIndex];
|
491
|
+
let $activatableElement = $(focusedElement)
|
492
|
+
.find('a, button')
|
493
|
+
.first();
|
494
|
+
|
495
|
+
// Click a or button tag if exists, otherwise click li tag
|
496
|
+
if (!!$activatableElement.length) {
|
497
|
+
$activatableElement[0].click();
|
498
|
+
} else if (!!focusedElement) {
|
499
|
+
focusedElement.click();
|
500
|
+
}
|
501
|
+
|
502
|
+
// Close dropdown on ESC
|
503
|
+
} else if (e.which === this.keys.ESC && this.isOpen) {
|
504
|
+
e.preventDefault();
|
505
|
+
this.close();
|
506
|
+
}
|
507
|
+
|
508
|
+
// CASE WHEN USER TYPE LETTERS
|
509
|
+
let letter = String.fromCharCode(e.which).toLowerCase(),
|
510
|
+
nonLetters = [9, 13, 27, 38, 40];
|
511
|
+
if (letter && nonLetters.indexOf(e.which) === -1) {
|
512
|
+
this.filterQuery.push(letter);
|
513
|
+
|
514
|
+
let string = this.filterQuery.join(''),
|
515
|
+
newOptionEl = $(this.dropdownEl)
|
516
|
+
.find('li')
|
517
|
+
.filter((el) => {
|
518
|
+
return (
|
519
|
+
$(el)
|
520
|
+
.text()
|
521
|
+
.toLowerCase()
|
522
|
+
.indexOf(string) === 0
|
523
|
+
);
|
524
|
+
})[0];
|
525
|
+
|
526
|
+
if (newOptionEl) {
|
527
|
+
this.focusedIndex = $(newOptionEl).index();
|
528
|
+
this._focusFocusedItem();
|
529
|
+
}
|
530
|
+
}
|
531
|
+
|
532
|
+
this.filterTimeout = setTimeout(this._resetFilterQueryBound, 1000);
|
533
|
+
}
|
534
|
+
|
535
|
+
/**
|
536
|
+
* Setup dropdown
|
537
|
+
*/
|
538
|
+
_resetFilterQuery() {
|
539
|
+
this.filterQuery = [];
|
540
|
+
}
|
541
|
+
|
542
|
+
_resetDropdownStyles() {
|
543
|
+
this.$dropdownEl.css({
|
544
|
+
display: '',
|
545
|
+
width: '',
|
546
|
+
height: '',
|
547
|
+
left: '',
|
548
|
+
top: '',
|
549
|
+
'transform-origin': '',
|
550
|
+
transform: '',
|
551
|
+
opacity: ''
|
552
|
+
});
|
553
|
+
}
|
554
|
+
|
555
|
+
_makeDropdownFocusable() {
|
556
|
+
// Needed for arrow key navigation
|
557
|
+
this.dropdownEl.tabIndex = 0;
|
558
|
+
|
559
|
+
// Only set tabindex if it hasn't been set by user
|
560
|
+
$(this.dropdownEl)
|
561
|
+
.children()
|
562
|
+
.each(function(el) {
|
563
|
+
if (!el.getAttribute('tabindex')) {
|
564
|
+
el.setAttribute('tabindex', 0);
|
565
|
+
}
|
566
|
+
});
|
567
|
+
}
|
568
|
+
|
569
|
+
_focusFocusedItem() {
|
570
|
+
if (
|
571
|
+
this.focusedIndex >= 0 &&
|
572
|
+
this.focusedIndex < this.dropdownEl.children.length &&
|
573
|
+
this.options.autoFocus
|
574
|
+
) {
|
575
|
+
this.dropdownEl.children[this.focusedIndex].focus();
|
576
|
+
}
|
577
|
+
}
|
578
|
+
|
579
|
+
_getDropdownPosition() {
|
580
|
+
let offsetParentBRect = this.el.offsetParent.getBoundingClientRect();
|
581
|
+
let triggerBRect = this.el.getBoundingClientRect();
|
582
|
+
let dropdownBRect = this.dropdownEl.getBoundingClientRect();
|
583
|
+
|
584
|
+
let idealHeight = dropdownBRect.height;
|
585
|
+
let idealWidth = dropdownBRect.width;
|
586
|
+
let idealXPos = triggerBRect.left - dropdownBRect.left;
|
587
|
+
let idealYPos = triggerBRect.top - dropdownBRect.top;
|
588
|
+
|
589
|
+
let dropdownBounds = {
|
590
|
+
left: idealXPos,
|
591
|
+
top: idealYPos,
|
592
|
+
height: idealHeight,
|
593
|
+
width: idealWidth
|
594
|
+
};
|
595
|
+
|
596
|
+
// Countainer here will be closest ancestor with overflow: hidden
|
597
|
+
let closestOverflowParent = !!this.dropdownEl.offsetParent
|
598
|
+
? this.dropdownEl.offsetParent
|
599
|
+
: this.dropdownEl.parentNode;
|
600
|
+
|
601
|
+
let alignments = this.checkPossibleAlignments(
|
602
|
+
this.el,
|
603
|
+
closestOverflowParent,
|
604
|
+
dropdownBounds,
|
605
|
+
this.options.coverTrigger ? 0 : triggerBRect.height
|
606
|
+
);
|
607
|
+
|
608
|
+
let verticalAlignment = 'top';
|
609
|
+
let horizontalAlignment = this.options.alignment;
|
610
|
+
idealYPos += this.options.coverTrigger ? 0 : triggerBRect.height;
|
611
|
+
|
612
|
+
// Reset isScrollable
|
613
|
+
this.isScrollable = false;
|
614
|
+
|
615
|
+
if (!alignments.top) {
|
616
|
+
if (alignments.bottom) {
|
617
|
+
verticalAlignment = 'bottom';
|
618
|
+
} else {
|
619
|
+
this.isScrollable = true;
|
620
|
+
|
621
|
+
// Determine which side has most space and cutoff at correct height
|
622
|
+
if (alignments.spaceOnTop > alignments.spaceOnBottom) {
|
623
|
+
verticalAlignment = 'bottom';
|
624
|
+
idealHeight += alignments.spaceOnTop;
|
625
|
+
idealYPos -= alignments.spaceOnTop;
|
626
|
+
} else {
|
627
|
+
idealHeight += alignments.spaceOnBottom;
|
628
|
+
}
|
629
|
+
}
|
630
|
+
}
|
631
|
+
|
632
|
+
// If preferred horizontal alignment is possible
|
633
|
+
if (!alignments[horizontalAlignment]) {
|
634
|
+
let oppositeAlignment = horizontalAlignment === 'left' ? 'right' : 'left';
|
635
|
+
if (alignments[oppositeAlignment]) {
|
636
|
+
horizontalAlignment = oppositeAlignment;
|
637
|
+
} else {
|
638
|
+
// Determine which side has most space and cutoff at correct height
|
639
|
+
if (alignments.spaceOnLeft > alignments.spaceOnRight) {
|
640
|
+
horizontalAlignment = 'right';
|
641
|
+
idealWidth += alignments.spaceOnLeft;
|
642
|
+
idealXPos -= alignments.spaceOnLeft;
|
643
|
+
} else {
|
644
|
+
horizontalAlignment = 'left';
|
645
|
+
idealWidth += alignments.spaceOnRight;
|
646
|
+
}
|
647
|
+
}
|
648
|
+
}
|
649
|
+
|
650
|
+
if (verticalAlignment === 'bottom') {
|
651
|
+
idealYPos =
|
652
|
+
idealYPos - dropdownBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
|
653
|
+
}
|
654
|
+
if (horizontalAlignment === 'right') {
|
655
|
+
idealXPos = idealXPos - dropdownBRect.width + triggerBRect.width;
|
656
|
+
}
|
657
|
+
return {
|
658
|
+
x: idealXPos,
|
659
|
+
y: idealYPos,
|
660
|
+
verticalAlignment: verticalAlignment,
|
661
|
+
horizontalAlignment: horizontalAlignment,
|
662
|
+
height: idealHeight,
|
663
|
+
width: idealWidth
|
664
|
+
};
|
665
|
+
}
|
666
|
+
|
667
|
+
/**
|
668
|
+
* Animate in dropdown
|
669
|
+
*/
|
670
|
+
_animateIn() {
|
671
|
+
anim.remove(this.dropdownEl);
|
672
|
+
anim({
|
673
|
+
targets: this.dropdownEl,
|
674
|
+
opacity: {
|
675
|
+
value: [0, 1],
|
676
|
+
easing: 'easeOutQuad'
|
677
|
+
},
|
678
|
+
scaleX: [0.3, 1],
|
679
|
+
scaleY: [0.3, 1],
|
680
|
+
duration: this.options.inDuration,
|
681
|
+
easing: 'easeOutQuint',
|
682
|
+
complete: (anim) => {
|
683
|
+
if (this.options.autoFocus) {
|
684
|
+
this.dropdownEl.focus();
|
685
|
+
}
|
686
|
+
|
687
|
+
// onOpenEnd callback (by reference)
|
688
|
+
if (typeof this.options.onOpenEnd === 'function') {
|
689
|
+
this.options.onOpenEnd.call(this, this.el);
|
690
|
+
}
|
691
|
+
}
|
692
|
+
});
|
693
|
+
}
|
694
|
+
|
695
|
+
/**
|
696
|
+
* Animate out dropdown
|
697
|
+
*/
|
698
|
+
_animateOut() {
|
699
|
+
anim.remove(this.dropdownEl);
|
700
|
+
anim({
|
701
|
+
targets: this.dropdownEl,
|
702
|
+
opacity: {
|
703
|
+
value: 0,
|
704
|
+
easing: 'easeOutQuint'
|
705
|
+
},
|
706
|
+
scaleX: 0.3,
|
707
|
+
scaleY: 0.3,
|
708
|
+
duration: this.options.outDuration,
|
709
|
+
easing: 'easeOutQuint',
|
710
|
+
complete: (anim) => {
|
711
|
+
this._resetDropdownStyles();
|
712
|
+
|
713
|
+
// onCloseEnd callback (by reference)
|
714
|
+
if (typeof this.options.onCloseEnd === 'function') {
|
715
|
+
this.options.onCloseEnd.call(this, this.el);
|
716
|
+
}
|
717
|
+
}
|
718
|
+
});
|
719
|
+
}
|
720
|
+
|
721
|
+
/**
|
722
|
+
* Place dropdown
|
723
|
+
*/
|
724
|
+
_placeDropdown() {
|
725
|
+
// Set width before calculating positionInfo
|
726
|
+
let idealWidth = this.options.constrainWidth
|
727
|
+
? this.el.getBoundingClientRect().width
|
728
|
+
: this.dropdownEl.getBoundingClientRect().width;
|
729
|
+
this.dropdownEl.style.width = idealWidth + 'px';
|
730
|
+
|
731
|
+
let positionInfo = this._getDropdownPosition();
|
732
|
+
this.dropdownEl.style.left = positionInfo.x + 'px';
|
733
|
+
this.dropdownEl.style.top = positionInfo.y + 'px';
|
734
|
+
this.dropdownEl.style.height = positionInfo.height + 'px';
|
735
|
+
this.dropdownEl.style.width = positionInfo.width + 'px';
|
736
|
+
this.dropdownEl.style.transformOrigin = `${
|
737
|
+
positionInfo.horizontalAlignment === 'left' ? '0' : '100%'
|
738
|
+
} ${positionInfo.verticalAlignment === 'top' ? '0' : '100%'}`;
|
739
|
+
}
|
740
|
+
|
741
|
+
/**
|
742
|
+
* Open Dropdowns
|
743
|
+
*/
|
744
|
+
open() {
|
745
|
+
if (this.isOpen) {
|
746
|
+
return;
|
747
|
+
}
|
748
|
+
this.isOpen = true;
|
749
|
+
|
750
|
+
// onOpen callback (by reference)
|
751
|
+
// if (typeof this.options.onOpen === 'function') {
|
752
|
+
// this.options.onOpen.call(this, this.el);
|
753
|
+
// }
|
754
|
+
|
755
|
+
var _this = this;
|
756
|
+
var listItems = '#' + _this.id + " li";
|
757
|
+
var menuItems = document.querySelectorAll(listItems);
|
758
|
+
|
759
|
+
// Loop through each <li> element
|
760
|
+
for (var i=0; i < menuItems.length; i++) {
|
761
|
+
// adding a event listener, mark selected menuItem by class active
|
762
|
+
menuItems[i].addEventListener('click', function(event) {
|
763
|
+
event.preventDefault();
|
764
|
+
for(var i=0; i < menuItems.length; i++) {
|
765
|
+
if (menuItems[i].classList.contains('active')) {
|
766
|
+
menuItems[i].classList.remove('active');
|
767
|
+
}
|
768
|
+
}
|
769
|
+
// add `active` to current clicked element
|
770
|
+
this.classList.add('active');
|
771
|
+
}, false);
|
772
|
+
}
|
773
|
+
|
774
|
+
// onOpen callback (ny name)
|
775
|
+
var _this = this;
|
776
|
+
if (this.options.onOpen) {
|
777
|
+
this.executeFunctionByName(this.options.onOpen, window, _this);
|
778
|
+
}
|
779
|
+
|
780
|
+
// Reset styles
|
781
|
+
this._resetDropdownStyles();
|
782
|
+
this.dropdownEl.style.display = 'block';
|
783
|
+
|
784
|
+
this._placeDropdown();
|
785
|
+
this._animateIn();
|
786
|
+
this._setupTemporaryEventHandlers();
|
787
|
+
}
|
788
|
+
|
789
|
+
/**
|
790
|
+
* Close Dropdowns
|
791
|
+
*/
|
792
|
+
close() {
|
793
|
+
if (!this.isOpen) {
|
794
|
+
return;
|
795
|
+
}
|
796
|
+
this.isOpen = false;
|
797
|
+
this.focusedIndex = -1;
|
798
|
+
|
799
|
+
// onClose callback (by reference)
|
800
|
+
// if (typeof this.options.onClose === 'function') {
|
801
|
+
// this.options.onCloseStart.call(this, this.el);
|
802
|
+
// }
|
803
|
+
|
804
|
+
// onClose callback (by name)
|
805
|
+
var _this = this;
|
806
|
+
if (this.options.onClose) {
|
807
|
+
this.executeFunctionByName(this.options.onClose, window, _this);
|
808
|
+
}
|
809
|
+
|
810
|
+
this._animateOut();
|
811
|
+
this._removeTemporaryEventHandlers();
|
812
|
+
|
813
|
+
if (this.options.autoFocus) {
|
814
|
+
this.el.focus();
|
815
|
+
}
|
816
|
+
}
|
817
|
+
|
818
|
+
/**
|
819
|
+
* Recalculate dimensions
|
820
|
+
*/
|
821
|
+
recalculateDimensions() {
|
822
|
+
if (this.isOpen) {
|
823
|
+
this.$dropdownEl.css({
|
824
|
+
width: '',
|
825
|
+
height: '',
|
826
|
+
left: '',
|
827
|
+
top: '',
|
828
|
+
'transform-origin': ''
|
829
|
+
});
|
830
|
+
this._placeDropdown();
|
831
|
+
}
|
832
|
+
}
|
833
|
+
}
|
834
|
+
|
835
|
+
/**
|
836
|
+
* @static
|
837
|
+
* @memberof Dropdowns
|
838
|
+
*/
|
839
|
+
Dropdowns._dropdowns = [];
|
840
|
+
|
841
|
+
// jadams, 2020-10-10: moved to j1 name space
|
842
|
+
//
|
843
|
+
// M.FloatingActionButton = FloatingActionButton;
|
844
|
+
j1.dropdowns = Dropdowns;
|
845
|
+
|
846
|
+
// jadams, 2020-10-10: check how to transform to jQuery
|
847
|
+
//
|
848
|
+
|
849
|
+
// Check for jQuery
|
850
|
+
//
|
851
|
+
j1.jQueryLoaded = !!window.jQuery;
|
852
|
+
|
853
|
+
if (j1.jQueryLoaded) {
|
854
|
+
j1.initializeJqueryWrapper (
|
855
|
+
Dropdowns,
|
856
|
+
'dropdown',
|
857
|
+
'M_Dropdown'
|
858
|
+
);
|
859
|
+
}
|
860
|
+
|
861
|
+
// jadams, 2020-10-10: TODO: check if anime could be a replacement
|
862
|
+
// for (huge) animate.css
|
863
|
+
// })($, j1.anime);
|
864
|
+
})(cash, j1.anime);
|