jqx-es 1.0.0

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.
@@ -0,0 +1,541 @@
1
+ import {createElementFromHtmlString, insertPositions} from "./DOM.js";
2
+ import {
3
+ IS,
4
+ addHandlerId,
5
+ isNode,
6
+ randomString,
7
+ inject2DOMTree,
8
+ isCommentOrTextNode,
9
+ truncateHtmlStr,
10
+ systemLog,
11
+ } from "./JQxExtensionHelpers.js";
12
+ import {ATTRS} from "./EmbedResources.js";
13
+ import jqx from "../index.js";
14
+ import {ExamineElementFeatureFactory, toDashedNotation, toCamelcase, escHtml} from "./Utilities.js";
15
+ import {debugLog} from "./JQxLog.js";
16
+ const loop = (instance, callback) => {
17
+ const cleanCollection = instance.collection.filter(el => !isCommentOrTextNode(el));
18
+ for (let i = 0; i < cleanCollection.length; i += 1) {
19
+ callback(cleanCollection[i], i); }
20
+ return instance;
21
+ };
22
+ const isIt = ExamineElementFeatureFactory();
23
+ const emptyElement = el => el && (el.textContent = "");
24
+ const compareCI = (key, compareTo) => key.toLowerCase().trim() === compareTo.trim().toLowerCase();
25
+ const cloneAndDestroy = elem => {
26
+ const cloned = elem.cloneNode(true)
27
+ cloned.removeAttribute && cloned.removeAttribute(`id`);
28
+ elem.isConnected ? elem.remove() : elem = null;
29
+ return cloned;
30
+ };
31
+ const setData = (el, keyValuePairs) => {
32
+ el && IS(keyValuePairs, Object) &&
33
+ Object.entries(keyValuePairs).forEach(([key, value]) => el.setAttribute(`data-${toDashedNotation(key)}`, value));
34
+ };
35
+ const before = (instance, elem2AddBefore) => {
36
+ return instance.andThen(elem2AddBefore, true);
37
+ };
38
+ const after = (instance, elem2AddAfter) => {
39
+ return instance.andThen(elem2AddAfter);
40
+ };
41
+ const checkProp = prop => prop.startsWith(`data`) || ATTRS.html.find(attr => prop.toLowerCase() === attr);
42
+ const css = (el, keyOrKvPairs, value) => {
43
+ if (value && IS(keyOrKvPairs, String)) {
44
+ keyOrKvPairs = {[keyOrKvPairs]: value === "-" ? "" : value};
45
+ }
46
+
47
+ let nwClass = undefined;
48
+
49
+ if (keyOrKvPairs.className) {
50
+ nwClass = keyOrKvPairs.className;
51
+ delete keyOrKvPairs.className;
52
+ }
53
+
54
+ const classExists = ([...el.classList].find(c => c.startsWith(`JQxClass-`) || nwClass && c === nwClass));
55
+ nwClass = classExists || nwClass || `JQxClass-${randomString().slice(1)}`;
56
+ jqx.editCssRule(`.${nwClass}`, keyOrKvPairs);
57
+ el.classList.add(nwClass);
58
+ };
59
+ const assignAttrValues = (/*NODOC*/el, keyValuePairs) => {
60
+ el && Object.entries(keyValuePairs).forEach(([key, value]) => {
61
+ if (key.toLowerCase().startsWith(`data`)) {
62
+ return setData(el, value);
63
+ }
64
+
65
+ if (IS(value, String) && checkProp(key)) {
66
+ el.setAttribute(key, value.split(/[, ]/)?.join(` `));
67
+ }
68
+ });
69
+ };
70
+ const applyStyle = (el, rules) => {
71
+ if (IS(rules, Object)) {
72
+ Object.entries(rules).forEach(([key, value]) => {
73
+ let priority;
74
+ if (/!important/i.test(value)) {
75
+ value = value.slice(0, value.indexOf(`!`)).trim();
76
+ priority = 'important';
77
+ }
78
+
79
+ el.style.setProperty(toDashedNotation(key), value, priority)
80
+ } );
81
+ }
82
+ };
83
+ const datasetKeyProxy = { get(obj, key) { return obj[toCamelcase(key)] || obj[key]; }, enumerable: false, configurable: false };
84
+ const logDebug = (...args) => { debugLog.log(`❗` + args.map(v => String(v)).join(`, `) ) ; }
85
+
86
+ export default {
87
+ factoryExtensions: {
88
+ data: instance => ({
89
+ get all() { return new Proxy(instance[0]?.dataset ?? {}, datasetKeyProxy); },
90
+ set: (valuesObj = {}) => {
91
+ !instance.is.empty && IS(valuesObj, Object) && Object.entries(valuesObj)
92
+ .forEach( ([key,value]) => instance.setData( { [key]: value} ) );
93
+ return instance;
94
+ },
95
+ get: (key, whenUndefined) => instance.data.all[key] ?? whenUndefined,
96
+ add: (valuesObj = {}) => {
97
+ !instance.is.empty && IS(valuesObj, Object) && Object.entries(valuesObj)
98
+ .forEach( ([key,value]) => instance.setData( { [key]: value} ) );
99
+ return instance;
100
+ },
101
+ remove: key => {
102
+ instance[0]?.removeAttribute(`data-${toDashedNotation(key)}`);
103
+ return instance;
104
+ },
105
+ }),
106
+ dimensions: instance => instance.first()?.getBoundingClientRect(),
107
+ HTML: instance => ({
108
+ get: (outer, escaped) => {
109
+ if (instance.is.empty) {
110
+ return `NO ELEMENTS IN COLLECTION`;
111
+ }
112
+ const html = outer ? instance.outerHtml : instance.html();
113
+ return escaped ? escHtml(html) : html;
114
+ },
115
+ set: (content, append = false, escape = false) => {
116
+ content = content.isJQx ? content.HTML.get(1) : content;
117
+ const isString = IS(content, String);
118
+ content = isString && escape ? escHtml(content) : content;
119
+ if (isString && (content || ``).trim().length) { instance.html(content, append); }
120
+ return instance;
121
+ },
122
+ replace: (content, escape = false) => {
123
+ return instance.HTML.set(content, false, escape);
124
+ },
125
+ append: (content, escape = false) => {
126
+ content = IS(content, HTMLElement)
127
+ ? jqx(content).HTML.get(1) : content.isJQx ? content.HTML.get(1) : content;
128
+ return instance.HTML.set(content, true, escape);
129
+ },
130
+ insert: (content, escape = false) => {
131
+ content = IS(content, HTMLElement)
132
+ ? jqx(content).HTML.get(1) : content.isJQx ? content.HTML.get(1) : content;
133
+ return instance.HTML.set(content + instance.HTML.get(), false, escape);
134
+ },
135
+ }),
136
+ is: instance => isIt(instance),
137
+ length: instance => instance.collection.length,
138
+ outerHtml: instance => (instance.first() || {outerHTML: undefined}).outerHTML,
139
+ parent: instance =>{
140
+ const tryParent = jqx(instance[0]?.parentNode);
141
+ return !tryParent.is.empty ? tryParent : instance;
142
+ },
143
+ render: instance => !instance.is.empty && instance.toDOM() || (jqx.log(`[JQx.render]: empty collection`), undefined),
144
+ Style: instance => ({
145
+ get computed() { return !instance.is.empty ? getComputedStyle(instance[0]) : {}; },
146
+ inline: styleObj => instance.style(styleObj),
147
+ inSheet: styleObj => instance.css(styleObj),
148
+ valueOf: key => {
149
+ return !instance.is.empty ? getComputedStyle(instance[0])[toDashedNotation(key)] : undefined;
150
+ },
151
+ nwRule: rule => instance.Style.byRule({rules: rule}),
152
+ byRule: ({classes2Apply = [], rules = []} = {}) => {
153
+ const isSingleRule = IS(rules, String);
154
+ const addClassNameOrID = isSingleRule && !classes2Apply.length ? rules.split(`{`)[0].trim() : ``;
155
+ rules = rules && IS(rules, String) ? [rules] : rules;
156
+ classes2Apply = classes2Apply && IS(classes2Apply, String) ? [classes2Apply] : classes2Apply;
157
+
158
+ if (rules?.length || classes2Apply?.length) {
159
+ rules?.length && jqx.editCssRules(...rules);
160
+ classes2Apply?.forEach(selector => instance.addClass(selector));
161
+ }
162
+
163
+ if (addClassNameOrID?.startsWith(`.`)) {
164
+ instance.addClass(addClassNameOrID.slice(1));
165
+ }
166
+
167
+ if (addClassNameOrID?.startsWith(`#`) && !instance.attr(`id`)) {
168
+ instance.prop({id: addClassNameOrID.slice(1)});
169
+ }
170
+
171
+ return instance;
172
+ },
173
+ }),
174
+ },
175
+ instanceExtensions: {
176
+ addClass: (instance, ...classNames) => loop(instance, el => el && classNames.forEach(cn => el.classList.add(cn))),
177
+ after,
178
+ afterMe: after,
179
+ andThen: (instance, elem2Add, before = false) => {
180
+ if (!elem2Add || !IS(elem2Add, String, Node, Proxy)) {
181
+ logDebug(`[JQx instance].[beforeMe | afterMe | andThen]: insufficient input [${elem2Add}]`, );
182
+ return instance;
183
+ }
184
+
185
+ elem2Add = elem2Add?.isJQx
186
+ ? elem2Add.collection
187
+ : IS(elem2Add, Node) ? jqx.virtual(elem2Add).collection
188
+ : jqx.virtual(createElementFromHtmlString(elem2Add)).collection;
189
+
190
+ const [index, method, reCollected] = before
191
+ ? [0, `before`, elem2Add.concat(instance.collection)]
192
+ : [instance.collection.length - 1, `after`, instance.collection.concat(elem2Add)];
193
+
194
+ instance[index][method](...elem2Add);
195
+ instance.collection = reCollected;
196
+ return instance;
197
+ },
198
+ append: (instance, ...elems2Append) => {
199
+ if (!instance.is.empty && elems2Append.length) {
200
+ const shouldMove = instance.length === 1;
201
+
202
+ for (let elem2Append of elems2Append) {
203
+ if (!elem2Append.isJQx && IS(elem2Append, String)) {
204
+ const elem2Append4Test = elem2Append.trim();
205
+ const isPlainString = !/^<(.+)[^>]+>$/m.test(elem2Append4Test);
206
+ let toAppend = isPlainString ? jqx.text(elem2Append) : createElementFromHtmlString(elem2Append);
207
+ loop(instance, el => el.append(shouldMove ? toAppend : cloneAndDestroy(toAppend)));
208
+ }
209
+
210
+ if (isNode(elem2Append)) {
211
+ loop(instance, el => el.append(shouldMove ? elem2Append : cloneAndDestroy(elem2Append)));
212
+ }
213
+
214
+ if (elem2Append.isJQx && !elem2Append.is.empty) {
215
+ loop(instance, el =>
216
+ elem2Append.collection.forEach(elem =>
217
+ el.append(shouldMove ? elem : cloneAndDestroy(elem)))
218
+ );
219
+ }
220
+ }
221
+ }
222
+ return instance;
223
+ },
224
+ appendTo: (instance, appendTo) => {
225
+ if (!appendTo.isJQx) {
226
+ appendTo = jqx(appendTo);
227
+ }
228
+ appendTo.append(instance);
229
+ return instance;
230
+ },
231
+ attr: (instance, keyOrObj, value) => {
232
+ const firstElem = instance[0];
233
+
234
+ if (!firstElem) { return instance }
235
+
236
+ if (!value && IS(keyOrObj, String)) {
237
+ if (keyOrObj === `class`) {
238
+ return [...firstElem?.classList]?.join(` `);
239
+ }
240
+
241
+ return firstElem?.getAttribute(keyOrObj);
242
+ }
243
+
244
+ if (IS(keyOrObj, String) && value) {
245
+ keyOrObj = { [keyOrObj]: value };
246
+ }
247
+
248
+ if (IS(keyOrObj, Object) && !instance.is.empty) {
249
+ assignAttrValues(firstElem, keyOrObj);
250
+ }
251
+
252
+ return instance;
253
+ },
254
+ before,
255
+ beforeMe: before,
256
+ clear: instance => loop(instance, emptyElement),
257
+ closest: (instance, selector) => {
258
+ const theClosest = IS(selector, String) ? instance[0].closest(selector) : null;
259
+ return theClosest ? jqx(theClosest) : instance
260
+ },
261
+ computedStyle: (instance, property) => instance.first() && getComputedStyle(instance.first())[property],
262
+ css: (instance, keyOrKvPairs, value) => loop(instance, el => css(el, keyOrKvPairs, value)),
263
+ duplicate: (instance, toDOM = false, root = document.body) => {
264
+ const nodes = instance.toNodeList().map(el => el.removeAttribute && el.removeAttribute(`id`) || el);
265
+ const nwJQx = jqx.virtual(nodes);
266
+ return toDOM ? nwJQx.toDOM(root) : nwJQx;
267
+ },
268
+ each: (instance, cb) => loop(instance, cb),
269
+ empty: instance => loop(instance, emptyElement),
270
+ find: (instance, selector) =>
271
+ instance.collection.length > 0 ? [...instance.first()?.querySelectorAll(selector)] : [],
272
+ find$: (instance, selector) => { return instance.collection.length > 0 ? jqx(selector, instance) : instance; },
273
+ first: (instance, asJQxInstance = false) => {
274
+ if (instance.collection.length > 0) {
275
+ return asJQxInstance
276
+ ? instance.single()
277
+ : instance.collection[0];
278
+ }
279
+ return undefined;
280
+ },
281
+ first$: (instance, indexOrSelector) => instance.single(indexOrSelector),
282
+ getData: (instance, dataAttribute, valueWhenFalsy) =>
283
+ instance.first() && instance.first().dataset?.[dataAttribute] || valueWhenFalsy,
284
+ hasClass: (instance, ...classNames) => {
285
+ const firstElem = instance[0];
286
+ return !firstElem || !firstElem.classList.length
287
+ ? false : classNames.find(cn => firstElem.classList.contains(cn)) && true || false;
288
+ },
289
+ hide: instance => loop(instance, el => applyStyle(el, {display: `none !important`})),
290
+ html: (instance, htmlValue, append) => {
291
+ if (htmlValue === undefined) {
292
+ return instance[0]?.getHTML();
293
+ }
294
+
295
+ if (!instance.isEmpty()) {
296
+ const nwElement = createElementFromHtmlString(`<div>${htmlValue.isJQx ? htmlValue.HTML.get(true) : htmlValue}</div>`);
297
+
298
+ if (!IS(nwElement, Comment)) {
299
+ const cb = el => {
300
+ if (!append) { el.textContent = ``; }
301
+
302
+ return el.insertAdjacentHTML(jqx.at.end, nwElement.getHTML());
303
+ }
304
+ return loop(instance, cb);
305
+ }
306
+ }
307
+
308
+ return instance;
309
+ },
310
+ htmlFor: (instance, forQuery, htmlString = "", append = false) => {
311
+ if (forQuery && instance.collection.length) {
312
+ if (!forQuery || !IS(htmlString, String)) { return instance; }
313
+
314
+ const el2Change = instance.find$(forQuery);
315
+
316
+ if (el2Change.length < 1) { return instance; }
317
+
318
+ const nwElement = createElementFromHtmlString(`<span>${htmlString}</span>`);
319
+
320
+ el2Change.each(el => {
321
+ if (!append) { el.textContent = ``; }
322
+ el.insertAdjacentHTML(jqx.at.end, nwElement.getHTML());
323
+ });
324
+
325
+ }
326
+
327
+ return instance;
328
+ },
329
+ isEmpty: instance => instance.collection.length < 1,
330
+ nth$: (instance, indexOrSelector) => instance.single(indexOrSelector),
331
+ on: (instance, type, ...callback) => {
332
+ if (instance.collection.length) {
333
+ callback?.forEach(cb => {
334
+ const cssSelector4Handler = addHandlerId(instance);
335
+ jqx.delegate(type, cssSelector4Handler, cb);
336
+ });
337
+ }
338
+
339
+ return instance;
340
+ },
341
+ prepend: (instance, ...elems2Prepend) => {
342
+ if (!instance.is.empty && elems2Prepend) {
343
+ const shouldMove = instance.length === 1;
344
+
345
+ for (let elem2Prepend of elems2Prepend) {
346
+ if (IS(elem2Prepend, String)) {
347
+ elem2Prepend = elem2Prepend.trim();
348
+ const isPlainString = !/^<(.+)[^>]+>$/m.test(elem2Prepend);
349
+ let toPrepend = isPlainString ? jqx.text(elem2Prepend) : createElementFromHtmlString(elem2Prepend);
350
+ toPrepend = shouldMove ? toPrepend : cloneAndDestroy(toPrepend);
351
+ loop(instance, el => el.prepend(toPrepend.cloneNode(true)));
352
+ }
353
+
354
+ if (isNode(elem2Prepend)) {
355
+ loop(instance, el => el.prepend(shouldMove ? elem2Prepend : cloneAndDestroy(elem2Prepend)));
356
+ }
357
+
358
+ if (elem2Prepend.isJQx && !elem2Prepend.is.empty) {
359
+ elem2Prepend.collection.length > 1 && elem2Prepend.collection.reverse();
360
+ loop(instance, el => loop( elem2Prepend, elem => el.prepend(shouldMove ? elem : cloneAndDestroy(elem)) ) );
361
+ elem2Prepend.collection.reverse();
362
+ }
363
+ }
364
+ }
365
+
366
+ return instance;
367
+ },
368
+ prependTo: (instance, prependTo) => {
369
+ if (!prependTo.isJQx) {
370
+ prependTo = jqx.virtual(prependTo);
371
+ }
372
+
373
+ prependTo.prepend(instance);
374
+ return instance;
375
+ },
376
+ prop: (instance, nameOrProperties, value) => {
377
+ if (IS(nameOrProperties, String) && !value) {
378
+ return nameOrProperties.startsWith(`data`)
379
+ ? instance[0]?.dataset[nameOrProperties.slice(nameOrProperties.indexOf(`-`)+1)]
380
+ : instance[0]?.[nameOrProperties];
381
+ }
382
+
383
+ const props = !IS(nameOrProperties, Object) ? { [nameOrProperties]: value } : nameOrProperties;
384
+ Object.entries(props).forEach( ([propName, propValue]) => {
385
+ propName = propName.trim();
386
+
387
+ if (propValue && !checkProp(propName) || !propValue) {
388
+ return false;
389
+ }
390
+
391
+ const isId = propName.toLowerCase() === `id`;
392
+
393
+ if (isId) { return instance[0].id = propValue; }
394
+
395
+ loop(instance, el => {
396
+ if (propName.startsWith(`data`)) {
397
+ return el.dataset[propName.slice(propName.indexOf(`-`)+1)] = propValue;
398
+ }
399
+
400
+ el[propName] = propValue;
401
+ });
402
+ });
403
+
404
+ return instance;
405
+ },
406
+ remove: (instance, selector) => {
407
+ systemLog(`remove ${truncateHtmlStr(instance.HTML.get(1), 40)}${selector ? ` /w selector ${selector}` : ``}`);
408
+ const remover = el => el.remove();
409
+ const removeFromCollection = () =>
410
+ instance.collection = instance.collection.filter(el => document.documentElement.contains(el));
411
+
412
+ if (selector) {
413
+ const selectedElements = instance.find$(selector);
414
+ if (!selectedElements.is.empty) {
415
+ loop(selectedElements, remover);
416
+ removeFromCollection();
417
+ }
418
+ return instance;
419
+ }
420
+ loop(instance, remover);
421
+ removeFromCollection();
422
+ return instance;
423
+ },
424
+ removeAttribute: (instance, attrName) => loop(instance, el => el.removeAttribute(attrName)),
425
+ removeClass: (instance, ...classNames) =>
426
+ loop(instance, el => el && classNames.forEach(cn => el.classList.remove(cn))),
427
+ renderTo: (instance, root = document.body, at = jqx.insertPositions.end) => {
428
+ instance.toDOM(root, at);
429
+ return instance;
430
+ },
431
+ replace: (instance, oldChild, newChild) => {
432
+ const firstElem = instance[0];
433
+
434
+ if (!oldChild || (!newChild || !IS(newChild, HTMLElement) && !newChild.isJQx)) {
435
+ console.error(`JQx replace: invalid replacement value`);
436
+ return instance;
437
+ }
438
+
439
+ if (newChild.isJQx) {
440
+ newChild = newChild[0];
441
+ }
442
+
443
+ if (IS(newChild, NodeList)) {
444
+ newChild = newChild[0];
445
+ }
446
+
447
+ if (firstElem && oldChild) {
448
+ oldChild = IS(oldChild, String)
449
+ ? firstElem.querySelectorAll(oldChild)
450
+ : oldChild.isJQx
451
+ ? oldChild.collection
452
+ : oldChild;
453
+
454
+ if (IS(oldChild, HTMLElement, NodeList, Array) && IS(newChild, HTMLElement)) {
455
+ (IS(oldChild, HTMLElement) ? [oldChild] : [...oldChild])
456
+ .forEach(chld => chld.replaceWith(newChild.cloneNode(true)));
457
+ }
458
+ }
459
+
460
+ return instance;
461
+ },
462
+ replaceClass: (instance, className, ...nwClassNames) => loop( instance, el => {
463
+ el.classList.remove(className);
464
+ nwClassNames.forEach(name => el.classList.add(name));
465
+ } ),
466
+ replaceMe: (instance, newChild) => /*NODOC*/ instance.replaceWith(newChild),
467
+ replaceWith: (instance, newChild) => {
468
+ newChild = IS(newChild, Element) ? newChild : newChild.isJQx ? newChild[0] : undefined;
469
+
470
+ if (newChild) {
471
+ instance[0].replaceWith(newChild);
472
+ instance = jqx.virtual(newChild);
473
+ }
474
+
475
+ return instance;
476
+ },
477
+ setData: (instance, keyValuePairs) => loop(instance, el => setData(el, keyValuePairs)),
478
+ show: instance => loop(instance, el => applyStyle(el, {display: `revert-layer !important`})),
479
+ single: (instance, indexOrSelector) => {
480
+ if (instance.collection.length > 0) {
481
+ if (IS(indexOrSelector, String)) {
482
+ return instance.find$(indexOrSelector);
483
+ }
484
+
485
+ if (IS(indexOrSelector, Number)) {
486
+ return jqx(instance.collection[indexOrSelector]);
487
+ }
488
+
489
+ return jqx(instance.collection[0]);
490
+ }
491
+
492
+ return instance;
493
+ },
494
+ style: (instance, keyOrKvPairs, value) => {
495
+ const loopCollectionLambda = el => {
496
+ if (value && IS(keyOrKvPairs, String)) {
497
+ keyOrKvPairs = { [keyOrKvPairs]: value || `none` };
498
+ }
499
+
500
+ applyStyle(el, keyOrKvPairs);
501
+ };
502
+ return loop(instance, loopCollectionLambda);
503
+ },
504
+ text: (instance, textValue, append = false) => {
505
+ if (instance.isEmpty()) { return instance; }
506
+ if (!IS(textValue, String)) { return instance.first().textContent; }
507
+ const loopCollectionLambda = el => el.textContent = append ? el.textContent + textValue : textValue;
508
+ return loop(instance, loopCollectionLambda);
509
+ },
510
+ toDOM: (instance, root = document.body, position = insertPositions.BeforeEnd) => {
511
+ if (instance.isVirtual) { instance.isVirtual = false; }
512
+ instance.collection = inject2DOMTree(instance.collection, root, position);
513
+
514
+ return instance;
515
+ },
516
+ toggleClass: (instance, className) => loop(instance, el => el.classList.toggle(className)),
517
+ toNodeList: instance => [...instance.collection].map(el => document.importNode(el, true)),
518
+ trigger: (instance, evtType, SpecifiedEvent = Event, options = {}) => {
519
+ if (instance.collection.length) {
520
+ const evObj = new SpecifiedEvent( evtType, { ...options, bubbles: options.bubbles??true} );
521
+ for( let elem of instance.collection ) { elem.dispatchEvent(evObj); }
522
+ }
523
+ return instance;
524
+ },
525
+ val: (instance, newValue) => {
526
+ const firstElem = instance[0];
527
+
528
+ if (!firstElem || !IS(firstElem, HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement)) {
529
+ return instance;
530
+ }
531
+
532
+ if (newValue === undefined) {
533
+ return firstElem.value;
534
+ }
535
+
536
+ firstElem.value = !IS(newValue, String) ? "" : newValue;
537
+
538
+ return instance;
539
+ },
540
+ },
541
+ };
package/src/Popup.js ADDED
@@ -0,0 +1,89 @@
1
+ import { popupStyling } from "./EmbedResources.js";
2
+ import { randomString } from "./Utilities.js";
3
+
4
+ export default newPopupFactory;
5
+
6
+ function newPopupFactory($) {
7
+ const editRule = $.createStyle(`JQxPopupCSS`);
8
+ popupStyling.forEach( rule => editRule(rule) );
9
+ let callbackOnClose = {};
10
+ let isModal, modalWarning, timeout;
11
+ const warnTemplate = $.virtual(`<div class="popup-warn">`);
12
+ const popupContainer = $(`<div class="popupContainer">`)
13
+ .append( $(`<span class="closeHandleIcon">`) )
14
+ .append( $(`<div class="content">`) );
15
+ const [closer, txtBox] = [$(`.popupContainer > .closeHandleIcon`), $( `.popupContainer > .content` )];
16
+ const positionCloser = () => {
17
+ if ( closer.hasClass(`popup-active`) ) {
18
+ const {x, y, width} = txtBox.dimensions;
19
+ closer.style({top: `${y - 12}px`, left: `${x + width - 12}px`});
20
+ } };
21
+ const warn = () => {
22
+ modalWarning && $(`.popup-warn`).clear().append($(`<div>${modalWarning}</div>`));
23
+ txtBox.addClass(`popup-warn-active`); };
24
+ const removeModal = () => { isModal = false; remove(closer.first()); };
25
+ const timed = (seconds, callback) => timeout = setTimeout( () => remove(closer[0]), +seconds * 1000 );
26
+ $.delegate(`click`, `.popupContainer, .closeHandleIcon`, evt => remove(evt.target));
27
+ $.delegate(`click`, `.popupContainer .content`, (_, self) => isModal && self.removeClass(`popup-warn-active`));
28
+ $.delegate(`resize`, positionCloser);
29
+
30
+ return {
31
+ show: createAndShowPupup,
32
+ create: (message, isModalOrCallback, modalCallback, modalWarning) => { /*legacy*/
33
+ const isModal = $.IS(isModalOrCallback, Boolean) ? isModalOrCallback : false;
34
+ createAndShowPupup({
35
+ content: message, modal: isModal,
36
+ callback: isModal ? modalCallback : isModalOrCallback, warnMessage: modalWarning, }); },
37
+ createTimed: (message, closeAfter, callback) => /*legacy*/
38
+ createAndShowPupup({content: message, closeAfter, callback}),
39
+ removeModal,
40
+ };
41
+
42
+ function createAndShowPupup( { content, modal, closeAfter, callback, warnMessage } ) {
43
+ if (content) {
44
+ content = $.IS(content, Node) ? jqx(content) : content;
45
+ clearTimeout(timeout);
46
+ isModal = modal ?? false;
47
+ modalWarning = $.IS(warnMessage, String) && `${warnMessage?.trim()}`.length || warnMessage?.isJQx
48
+ ? warnMessage : undefined;
49
+ txtBox.clear().append(content.isJQx ? content : $(`<div>${content}</div>`));
50
+ isModal && warnMessage && txtBox.append(warnTemplate.duplicate());
51
+ popupContainer.addClass(`popup-active`);
52
+
53
+ if ($.IS(callback, Function)) {
54
+ const tmpId = randomString();
55
+ popupContainer.data.set( {callbackId: tmpId} );
56
+ callbackOnClose[tmpId] = callback;
57
+ }
58
+
59
+ if (!isModal) {
60
+ if ($.IS(+closeAfter, Number)) {
61
+ const callbackId = popupContainer.data.get(`callbackId`);
62
+ const callback = callbackId && callbackOnClose[callbackId];
63
+ timed(closeAfter, callback);
64
+ }
65
+ closer.addClass(`popup-active`);
66
+ positionCloser();
67
+ }
68
+
69
+ return true;
70
+ }
71
+ return console.error(`Popup creation needs at least some text to show`);
72
+ }
73
+
74
+ function remove(origin) {
75
+ if (!isModal && !origin.closest(`.content`)) {
76
+ clearTimeout(timeout);
77
+ txtBox.clear();
78
+ const callbackId = popupContainer.data.get(`callbackId`);
79
+ popupContainer.data.remove(`callbackId`);
80
+ $(`.popup-active`).removeClass(`popup-active`);
81
+ const cb = callbackId && callbackOnClose[callbackId];
82
+ if ($.IS(cb, Function)) { cb(); }
83
+ if (callbackId) { delete callbackOnClose[callbackId]; }
84
+ modalWarning = ``;
85
+ return;
86
+ }
87
+ return isModal && warn();
88
+ }
89
+ }