eyjs 6.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,1154 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.eye = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * @typedef {Object} AttrMap
9
+ * @property {HTMLDivElement} parent - append newly created element to a parent
10
+ * @property {Array<String>|String} class - class or array of classes to set
11
+ * @property {String} id - set element ID
12
+ * @property {Object} data - dataset values to set
13
+ * @property {String} text - set element text
14
+ * @property {String} html - set element html
15
+ */
16
+
17
+ /**
18
+ * Returns the associated class event of that event
19
+ * example: for click event it returns new MouseEvent("click")
20
+ * @param {string} ev
21
+ */
22
+ function getEvent(type, options = {}) {
23
+ switch (type) {
24
+ // Mouse Events
25
+ case 'click':
26
+ case 'dblclick':
27
+ case 'mousedown':
28
+ case 'mouseup':
29
+ case 'mousemove':
30
+ case 'mouseenter':
31
+ case 'mouseleave':
32
+ case 'mouseover':
33
+ case 'mouseout':
34
+ return new MouseEvent(type, options);
35
+
36
+ // Pointer Events
37
+ case 'pointerdown':
38
+ case 'pointerup':
39
+ case 'pointermove':
40
+ case 'pointerenter':
41
+ case 'pointerleave':
42
+ case 'pointerover':
43
+ case 'pointerout':
44
+ return new PointerEvent(type, options);
45
+
46
+ // Keyboard Events
47
+ case 'keydown':
48
+ case 'keyup':
49
+ case 'keypress':
50
+ return new KeyboardEvent(type, options);
51
+
52
+ // Focus Events
53
+ case 'focus':
54
+ case 'blur':
55
+ case 'focusin':
56
+ case 'focusout':
57
+ return new FocusEvent(type, options);
58
+
59
+ // Input & Form Events
60
+ case 'input':
61
+ case 'change':
62
+ case 'submit':
63
+ case 'reset':
64
+ return new Event(type, options);
65
+
66
+ // Wheel
67
+ case 'wheel':
68
+ return new WheelEvent(type, options);
69
+
70
+ // Clipboard
71
+ case 'copy':
72
+ case 'cut':
73
+ case 'paste':
74
+ return new ClipboardEvent(type, options);
75
+
76
+ // UI
77
+ case 'scroll':
78
+ case 'resize':
79
+ return new UIEvent(type, options);
80
+
81
+ // Default: fallback to generic Event
82
+ default:
83
+ return new CustomEvent(type, options);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @typedef {EyeElement & {
89
+ * refresh: (attrs: AttrMap) => ModelEyeElement
90
+ * }} ModelEyeElement eye element definition for model elements
91
+ */
92
+
93
+ const events = [
94
+ // Mouse Events
95
+ "click",
96
+ "dblclick",
97
+ "mousedown",
98
+ "mouseup",
99
+ "mousemove",
100
+ "mouseenter",
101
+ "mouseleave",
102
+ "mouseover",
103
+ "mouseout",
104
+ "contextmenu",
105
+
106
+ // Keyboard Events
107
+ "keydown",
108
+ "keypress", // Deprecated
109
+ "keyup",
110
+
111
+ // Focus Events
112
+ "focus",
113
+ "blur",
114
+ "focusin",
115
+ "focusout",
116
+
117
+ // Form Events
118
+ "submit",
119
+ "change",
120
+ "input",
121
+ "reset",
122
+ "select",
123
+
124
+ // Touch Events (for mobile)
125
+ "touchstart",
126
+ "touchend",
127
+ "touchmove",
128
+ "touchcancel",
129
+
130
+ // Pointer Events
131
+ "pointerdown",
132
+ "pointerup",
133
+ "pointermove",
134
+ "pointerenter",
135
+ "pointerleave",
136
+ "pointercancel",
137
+
138
+ // Drag and Drop Events
139
+ "dragstart",
140
+ "dragend",
141
+ "dragenter",
142
+ "dragover",
143
+ "dragleave",
144
+ "drop",
145
+
146
+ // Window/Document Events
147
+ "resize",
148
+ "scroll",
149
+ "load",
150
+ "beforeunload",
151
+ "unload",
152
+
153
+ // Media Events
154
+ "play",
155
+ "pause",
156
+ "ended",
157
+ "volumechange",
158
+ "timeupdate",
159
+
160
+ // Clipboard Events
161
+ "copy",
162
+ "cut",
163
+ "paste",
164
+
165
+ // Animation and Transition Events
166
+ "animationstart",
167
+ "animationend",
168
+ "animationiteration",
169
+ "transitionstart",
170
+ "transitionend",
171
+
172
+ // Mutation Events
173
+ "DOMSubtreeModified",
174
+ "DOMNodeInserted",
175
+ "DOMNodeRemoved",
176
+
177
+ // Other Events
178
+ "error",
179
+ "hashchange",
180
+ "popstate",
181
+ ];
182
+
183
+ const htmlElements = [
184
+ // Metadata
185
+ "<base>",
186
+ "<head>",
187
+ "<link>",
188
+ "<meta>",
189
+ "<style>",
190
+ "<title>",
191
+
192
+ // Sections
193
+ "<body>",
194
+ "<address>",
195
+ "<article>",
196
+ "<aside>",
197
+ "<footer>",
198
+ "<header>",
199
+ "<h1>",
200
+ "<h2>",
201
+ "<h3>",
202
+ "<h4>",
203
+ "<h5>",
204
+ "<h6>",
205
+ "<main>",
206
+ "<nav>",
207
+ "<section>",
208
+
209
+ // Text content
210
+ "<blockquote>",
211
+ "<dd>",
212
+ "<div>",
213
+ "<dl>",
214
+ "<dt>",
215
+ "<figcaption>",
216
+ "<figure>",
217
+ "<hr>",
218
+ "<li>",
219
+ "<ol>",
220
+ "<p>",
221
+ "<pre>",
222
+ "<ul>",
223
+
224
+ // Inline text semantics
225
+ "<a>",
226
+ "<abbr>",
227
+ "<b>",
228
+ "<bdi>",
229
+ "<bdo>",
230
+ "<br>",
231
+ "<cite>",
232
+ "<code>",
233
+ "<data>",
234
+ "<dfn>",
235
+ "<em>",
236
+ "<i>",
237
+ "<kbd>",
238
+ "<mark>",
239
+ "<q>",
240
+ "<rp>",
241
+ "<rt>",
242
+ "<ruby>",
243
+ "<s>",
244
+ "<samp>",
245
+ "<small>",
246
+ "<span>",
247
+ "<strong>",
248
+ "<sub>",
249
+ "<sup>",
250
+ "<time>",
251
+ "<u>",
252
+ "<var>",
253
+ "<wbr>",
254
+
255
+ // Image and multimedia
256
+ "<area>",
257
+ "<audio>",
258
+ "<img>",
259
+ "<map>",
260
+ "<track>",
261
+ "<video>",
262
+
263
+ // Embedded content
264
+ "<embed>",
265
+ "<iframe>",
266
+ "<object>",
267
+ "<picture>",
268
+ "<portal>",
269
+ "<source>",
270
+
271
+ // Scripting
272
+ "<canvas>",
273
+ "<noscript>",
274
+ "<script>",
275
+
276
+ // Demarcating edits
277
+ "<del>",
278
+ "<ins>",
279
+
280
+ // Table content
281
+ "<caption>",
282
+ "<col>",
283
+ "<colgroup>",
284
+ "<table>",
285
+ "<tbody>",
286
+ "<td>",
287
+ "<tfoot>",
288
+ "<th>",
289
+ "<thead>",
290
+ "<tr>",
291
+
292
+ // Forms
293
+ "<button>",
294
+ "<datalist>",
295
+ "<fieldset>",
296
+ "<form>",
297
+ "<input>",
298
+ "<label>",
299
+ "<legend>",
300
+ "<meter>",
301
+ "<optgroup>",
302
+ "<option>",
303
+ "<output>",
304
+ "<progress>",
305
+ "<select>",
306
+ "<textarea>",
307
+
308
+ // Interactive elements
309
+ "<details>",
310
+ "<dialog>",
311
+ "<summary>",
312
+
313
+ // Web components / scripting base
314
+ "<slot>",
315
+ "<template>",
316
+ ];
317
+
318
+ function flat(word) {
319
+ let n = "";
320
+ for (let i = 0; i < word.length; i++) {
321
+ const t = word[i];
322
+ if (t === t.toUpperCase() && t !== t.toLowerCase()) n += "-" + t;
323
+ else n += t;
324
+ }
325
+ return n.toLowerCase();
326
+ }
327
+
328
+ const localdata = new WeakMap();
329
+
330
+ /**
331
+ * cmcl stands for Create Model Children Layers, recursively creates model layers one by one
332
+ * @param {EyeElement} parent
333
+ * @param {Object} layer
334
+ * @returns {Array<{name: string,set: (parent: EyeElement, value: String) =>}>}
335
+ */
336
+ function cmcl(parent, layer) {
337
+ let obj = [];
338
+ for (const key in layer) {
339
+ const subcontent = layer[key];
340
+ const [def, _set] = key.split(":");
341
+ const [tagName, ...cls] = def.split(".");
342
+ let [_set_name = null, _set_default = null] = (_set || "")
343
+ .split("-")
344
+ .map((a) => a.trim());
345
+
346
+ let elm = e(tagName.trim(), {
347
+ class: cls,
348
+ parent,
349
+ data: _set ? { value: _set_name } : undefined,
350
+ });
351
+
352
+ if (_set && _set_name) {
353
+ obj.push({
354
+ name: _set_name,
355
+ set(parent, value) {
356
+ let elm = parent.find(`[data-value="${_set_name}"]`);
357
+ elm.textContent = value ?? _set_default;
358
+ }
359
+ });
360
+ }
361
+
362
+ // recursive
363
+ if (
364
+ subcontent &&
365
+ typeof subcontent === "object" &&
366
+ !(subcontent instanceof Array)
367
+ )
368
+ obj = obj.concat(cmcl(elm, subcontent));
369
+ }
370
+ return obj;
371
+ }
372
+
373
+ let delegationEvents = ["click", "submit", "input", "change", "keydown", "keyup", "keypress", "focusin", "focusout", "mouseover", "mouseout"];
374
+ let normalSetterGetter = (action, v, elm) => v;
375
+
376
+ /**
377
+ * Eye wrapper offers a subset of functions that ease DOM minipulation! Power of JQuery with
378
+ * some a modern design and a bunch of new functions.
379
+ * @author Yousef Neji
380
+ */
381
+ class EyeElement {
382
+ /**
383
+ * Raw html element
384
+ * @type {HTMLElement}
385
+ */
386
+ #raw = null;
387
+
388
+ /**
389
+ * Used to store delegated events listeners
390
+ * @type {Map<String,Set<{callback, target: string}>>}
391
+ */
392
+ #dlgListeners = new Map();
393
+
394
+ /**
395
+ * Custom way or modifier that redefine the way you set/get
396
+ * this element `textContent` or `value`:
397
+ * - access this feature from `.redefine` method.
398
+ */
399
+ #customSet = {
400
+ value: normalSetterGetter,
401
+ text: normalSetterGetter
402
+ };
403
+
404
+ /**
405
+ * Called internally to initiate the main EyeElement functionalities
406
+ * @method EyeElement#init
407
+ * @param {string|HTMLElement} selector
408
+ * @param {AttrMap} attrs
409
+ * @param {Object} css
410
+ * @returns {EyeElement}
411
+ */
412
+ constructor(selector, attrs, css) {
413
+ let _this = this;
414
+ if (selector instanceof HTMLElement) {
415
+ this.#raw = selector;
416
+ } else if (htmlElements.includes(selector)) {
417
+ // creating a new element
418
+ this.#raw = document.createElement(selector.substring(1, selector.length - 1));
419
+ } else {
420
+ // selecting
421
+ let s = selector.slice(-1) === "!";
422
+ this.#raw = document.querySelectorAll(s ? selector.slice(0, -1) : selector);
423
+
424
+ if (this.#raw.length == 0) return null; // we stop everything here
425
+ if (this.length == 1 || s) this.#raw = this.#raw.item(0);
426
+ }
427
+
428
+ /**
429
+ * Handler used to integrate delegation concept/algorithme
430
+ * @param {Event} e
431
+ */
432
+ function handler(e) {
433
+ let name = e.type,
434
+ listeners = _this.#dlgListeners,
435
+ _etarget = e.target,
436
+ me = this; // refers to the element being listening to the event
437
+
438
+ if (listeners.has(name)) {
439
+ let cbs = listeners.get(name);
440
+ cbs?.forEach(({ callback, target }) => {
441
+ if (_etarget.closest(target)) {
442
+ // we hitting the target
443
+ callback(e, me);
444
+ }
445
+ });
446
+ }
447
+ }
448
+
449
+ this.each((elm, idx) => {
450
+ let parentElm = null;
451
+ if (attrs)
452
+ for (const key in attrs) {
453
+ const value = attrs[key];
454
+ if (key == "class")
455
+ elm.classList.add.apply(
456
+ elm.classList,
457
+ (value instanceof Array ? value : value.split(" ")).filter(a => a != "")
458
+ );
459
+ else if (key == "text") elm.textContent = value;
460
+ else if (key == "html") elm.innerHTML = value;
461
+ else if (key == "data") for (const k in value) elm.dataset[k] = value[k];
462
+ else if (key == "parent") parentElm = value;
463
+ else if (key in elm) elm[key] = value;
464
+ else if (key[0] != "_") elm.setAttribute(key, elm); // we must ignore _ started keys 'cause they are used by models
465
+ }
466
+ if (css)
467
+ for (const key in css)
468
+ if (key.indexOf("-") != -1) elm.style[key] = css[key];
469
+ else elm.style[flat(key)] = css[key];
470
+ if (parentElm instanceof EyeElement || parentElm instanceof HTMLElement) parentElm.append(elm);
471
+
472
+ // creating the delegation handling model
473
+ delegationEvents.forEach(ev => {
474
+ elm.addEventListener(ev, handler);
475
+ });
476
+ });
477
+
478
+ // creating/initiating events functions
479
+ events.forEach(ev => {
480
+ _this[ev] = function (cb) {
481
+ if (cb) {
482
+ if (typeof cb == "function") _this.on(ev, cb);
483
+ } else _this.trigger(ev);
484
+
485
+ return _this;
486
+ };
487
+ });
488
+
489
+
490
+ return this;
491
+ }
492
+
493
+ /**
494
+ * Length of current selection
495
+ * @type {Number}
496
+ */
497
+ get length() {
498
+ return this.#raw instanceof NodeList ? this.#raw.length : 1;
499
+ }
500
+
501
+ /**
502
+ * Raw html element
503
+ * @type {HTMLElement}
504
+ */
505
+ get raw() {
506
+ return this.#raw;
507
+ }
508
+
509
+ /**
510
+ * Run(loop) through selected NodeList, or run a single call for one single element
511
+ * @method EyeElement#each
512
+ * @param {(elm: HTMLElement, index: number, current: EyeElement)=>} cb
513
+ * @returns {EyeElement}
514
+ */
515
+ each(cb) {
516
+ (this.#raw instanceof NodeList ? [...this.#raw.entries()] : [[0, this.#raw]]).forEach(([idx, elm]) => {
517
+ cb(elm, idx, this);
518
+ });
519
+ return this;
520
+ }
521
+ /**
522
+ * Set or get element html
523
+ * @method EyeElement#html
524
+ * @param {string} [html]
525
+ * @returns {EyeElement|string}
526
+ */
527
+ html(html) {
528
+ let out = undefined;
529
+ this.each((elm, idx) => {
530
+ if (html === undefined) return out = elm.innerHTML;// getting the first one and exiting
531
+ elm.innerHTML = html;
532
+ });
533
+ return out != undefined ? out : this;
534
+ }
535
+ /**
536
+ * Set or get element text
537
+ * @method EyeElement#text
538
+ * @param {string} [text]
539
+ * @returns {EyeElement|string}
540
+ */
541
+ text(text) {
542
+ let out = undefined;
543
+ this.each((elm, idx) => {
544
+ if (text === undefined) return out = this.#customSet.text("get", elm.textContent, elm);
545
+ elm.textContent = this.#customSet.text("set", text, elm);
546
+ });
547
+ return out != undefined ? out : this;
548
+ }
549
+ /**
550
+ * Set or get element's data values
551
+ * @method EyeElement#data
552
+ * @param {string} key
553
+ * @param {*} [value]
554
+ * @returns {EyeElement|string}
555
+ */
556
+ data(key, value) {
557
+ if (!localdata.has(this)) localdata.set(this, {});
558
+ if (key) {
559
+ if (value != undefined) localdata.get(this)[key] = value;
560
+ else return localdata.get(this)[key];
561
+ }
562
+ return this;
563
+ }
564
+
565
+ /**
566
+ * Set or get an attribute value
567
+ * @method EyeElement#attr
568
+ * @param {string} name
569
+ * @param {*} [value]
570
+ * @returns {EyeElement|string}
571
+ */
572
+ attr(name, value) {
573
+ let out = "";
574
+ this.each((elm, idx) => {
575
+ if (name.indexOf("data-") === 0) {
576
+ let [key, val] = name.split("-").map((a) => a.trim());
577
+ // modify data
578
+ if (value == undefined) return out = elm.dataset[val];
579
+ elm.dataset[val] = value;
580
+ } else {
581
+ if (name in elm) {
582
+ if (value == undefined) return out = elm[name];
583
+ elm[name] = value;
584
+ } else if (name[0] != "_") {
585
+ if (value == undefined) return out = elm.getAttribute(name)
586
+ elm.setAttribute(name, value);
587
+ }
588
+ }
589
+ });
590
+ return out ? out : this;
591
+ }
592
+ /**
593
+ * Removing attribute of this element
594
+ * @type {string} attrName
595
+ * @returns {EyeElement}
596
+ */
597
+ rAttr(attrName) {
598
+ if (attrName) {
599
+ this.each((elm, idx) => {
600
+ elm.removeAttribute(attrName);
601
+ });
602
+ }
603
+ return this;
604
+ }
605
+ /**
606
+ * Super fancy class function that allows to modify class with different methods in one as follow:
607
+ * - `"classname"`: add classname to the element.
608
+ * - `"-classname"`: remove classname from class list.
609
+ * - `"%classname"`: toggle classname existing.
610
+ * - `"?classname"`: check classname existing in class list.
611
+ * - `"classnameA/classnameB"`: replace classnameA by classnameB
612
+ * @method EyeElement#class
613
+ * @param {string} actions
614
+ * @returns {EyeElement|string}
615
+ */
616
+ class(actions) {
617
+ let out = undefined;
618
+ this.each((elm, idx) => {
619
+ if (typeof actions === "number") return out = elm.classList.item(actions);
620
+
621
+ actions.split(" ").forEach((action) => {
622
+ if (action[0] == "-") {
623
+ elm.classList.remove(action.substring(1, action.length));
624
+ } else if (action[0] == "%") {
625
+ elm.classList.toggle(action.substring(1, action.length));
626
+ } else if (action[0] == "?") {
627
+ out = elm.classList.contains(action.substring(1, action.length));
628
+ } else if (action.indexOf("/") != -1) {
629
+ [v1, v2] = action.split("/");
630
+ elm.classList.replace(v1, v2);
631
+ } else {
632
+ elm.classList.add(action.substring(1, action.length));
633
+ }
634
+ });
635
+ if (out) return;
636
+ });
637
+
638
+ return out != undefined ? out : this;
639
+ }
640
+ /**
641
+ * Show/display the element
642
+ * @method EyeElement#show
643
+ * @param {string} cls
644
+ * @returns {EyeElement}
645
+ */
646
+ show(cls) {
647
+ this.each((elm, idx) => {
648
+ elm.style.display = cls ?? "inline-block";
649
+ });
650
+ return this;
651
+ }
652
+ /**
653
+ * Hide the element
654
+ * @method EyeElement#hide
655
+ * @param {boolean} opacity whether to hide by making invisible?
656
+ * @returns {EyeElement}
657
+ */
658
+ hide(opacity) {
659
+ this.each((elm, idx) => {
660
+ if (opacity) elm.style.opacity = 0;
661
+ else elm.style.display = "none";
662
+ });
663
+ return this;
664
+ }
665
+ /**
666
+ * Append one or more elements to the current element
667
+ * @method EyeElement#append
668
+ * @param {HTMLElement|Array<Node|EyeElement>} elm
669
+ * @param {"next" | "after" | "previous" | "before" | "first" | "afterbegin" | "last" | "beforeend"} [pos] [optional]
670
+ * @returns {EyeElement}
671
+ */
672
+ append(elm, pos) {
673
+ let nodes = [];
674
+ (Array.isArray(elm) ? elm : [elm]).forEach(item => {
675
+ if (item instanceof EyeElement) nodes.push(item.#raw);
676
+ else if (item instanceof HTMLElement) nodes.push(item);
677
+ });
678
+ if (this.#raw instanceof NodeList) {
679
+ console.warn(`[EyeJS] beware while using .append with multi selected elements`);
680
+ this.#raw.forEach((itm, idx) => {
681
+ if (!nodes[idx]) return;
682
+ itm.append(nodes[idx]);
683
+ });
684
+ return this;
685
+ }
686
+ if (!pos) this.#raw.append(...nodes);
687
+ else
688
+ switch (pos) {
689
+ case "next":
690
+ case "after":
691
+ this.#raw.after(...nodes);
692
+ break;
693
+ case "previous":
694
+ case "before":
695
+ this.#raw.before(...nodes);
696
+ break;
697
+ case "afterbegin":
698
+ case "first":
699
+ this.#raw.prepend(...nodes);
700
+ break;
701
+ case "beforeend":
702
+ case "last":
703
+ this.#raw.append(...nodes);
704
+
705
+ }
706
+ return this;
707
+ }
708
+ /**
709
+ * Insert element after this one
710
+ * @method EyeElement#after
711
+ * @param {EyeElement|HTMLElement} elm
712
+ * @returns {EyeElement}
713
+ */
714
+ after(elm) {
715
+ (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw).after(elm instanceof EyeElement ? elm.raw : elm);
716
+ return this;
717
+ }
718
+ /**
719
+ * Insert element before this one
720
+ * @method EyeElement#before
721
+ * @param {EyeElement|HTMLElement} elm
722
+ * @returns {EyeElement}
723
+ */
724
+ before(elm) {
725
+ (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw).before(elm instanceof EyeElement ? elm.raw : elm);
726
+ return this;
727
+ }
728
+ /**
729
+ * Replace current element with the new element, or multiple elements with multiple selected elements
730
+ * @method EyeElement#replaceWith
731
+ * @param {...HTMLElement|EyeElement} elms
732
+ * @param {string} [pos] [optional]
733
+ * @returns {EyeElement}
734
+ */
735
+ replaceWith(...elms) {
736
+ let nodes = [];
737
+ (Array.isArray(elms) ? elms : [elms]).forEach(item => {
738
+ if (item instanceof EyeElement) nodes.push(item.#raw);
739
+ else if (item instanceof HTMLElement) nodes.push(item);
740
+ });
741
+ if (this.#raw instanceof NodeList) {
742
+ [...this.#raw.entries()].forEach(([idx, elm]) => {
743
+ if (!nodes[idx]) return;
744
+ elm.replaceWith(nodes[idx]);
745
+ });
746
+ } else {
747
+ this.#raw.replaceWith(...nodes);
748
+ }
749
+ return this;
750
+ }
751
+ /**
752
+ * Get current element parent or append it to one
753
+ * @method EyeElement#parent
754
+ * @param {HTMLElement|EyeElement} par
755
+ * @returns {EyeElement}
756
+ */
757
+ parent(par) {
758
+ if (par) {
759
+ if (!(par instanceof HTMLElement) && !(par instanceof EyeElement))
760
+ throw new Error(
761
+ "[EyeJS] Unable to append current element to parent because it's not HTMLElement"
762
+ );
763
+ this.each((elm, idx) => {
764
+ par.append(elm);
765
+ });
766
+ return this;
767
+ }
768
+ return e(this.#raw instanceof NodeList ? this.#raw.item(0).parentElement : this.#raw.parentElement);
769
+ }
770
+ /**
771
+ * Returns whether current node is the same/equal(depending on `check`) as the passed node or not
772
+ * @method EyeElement#is
773
+ * @param {HTMLElement|EyeElement} node
774
+ * @param {"connected" | "same" | "equal"} [check] check type `same`, `equal`
775
+ * @returns {boolean}
776
+ */
777
+ is(node, check) {
778
+ node = node instanceof EyeElement ? node.#raw : node;
779
+ if (this.#raw instanceof NodeList) {
780
+ console.warn(`[EyeJS] .is is not functional with multi selected elements`);
781
+ return this;
782
+ }
783
+ if (node === "connected") return this.#raw.isConnected;
784
+ switch (check) {
785
+ case "same":
786
+ return this.#raw.isSameNode(node);
787
+ case "equal":
788
+ return this.#raw.isEqualNode(node);
789
+ default:
790
+ console.error(
791
+ `[EyeJS] Unknown check "${check}", possible values are ["same","equal","connected"]`
792
+ );
793
+ return false;
794
+ }
795
+ }
796
+ /**
797
+ * Set or get a css attribute
798
+ * @method EyeElement#css
799
+ * @param {string} attr
800
+ * @param {string|number} [value]
801
+ * @returns {EyeElement|string}
802
+ */
803
+ css(attr, value) {
804
+ if (attr) {
805
+ let out = undefined;
806
+ attr = flat(attr);
807
+ this.each((elm, idx) => {
808
+ if (value === undefined) return out = elm.style[attr];
809
+ elm.style[attr] = value;
810
+ });
811
+ return out != undefined ? out : this;
812
+ } else return console.error(`[EyeJS] mission argument "attr" in function .css`);
813
+ }
814
+ /**
815
+ * Remove current element
816
+ * @method EyeElement#remove
817
+ * @returns {EyeElement}
818
+ */
819
+ remove() {
820
+ this.each((elm, idx) => {
821
+ elm.remove();
822
+ });
823
+ return this;
824
+ }
825
+ /**
826
+ * @overload
827
+ * @param {string} ev
828
+ * @param {function} cb
829
+ */
830
+ /**
831
+ * @overload
832
+ * @param {string} ev
833
+ * @param {string} trg optionally define a target element for the event
834
+ * @param {function} cb
835
+ *
836
+ */
837
+ /**
838
+ * Attach an listener/handler to specific event or events
839
+ * @method EyeElement#on
840
+ * @param {string} ev may contain multiple events separated by " "(space)
841
+ * @param {string|function} arg2
842
+ * @param {function} [arg3]
843
+ * @returns {EyeElement|void}
844
+ */
845
+ on(ev, arg2, arg3) {
846
+ ev = ev.split(" ");
847
+ let target = typeof arg2 === "string" ? arg2 : null;
848
+ let cb = typeof arg2 === "function" ? arg2 : arg3;
849
+ let _this = this;
850
+ if (typeof cb !== "function")
851
+ return console.error(
852
+ "[EyeJS] .on method is missing the actuall callback `cb` or not of type function"
853
+ );
854
+
855
+ let elms = (this.#raw instanceof NodeList ? [...this.#raw.entries()] : [[0, this.#raw]]);
856
+
857
+ let outsider = null;
858
+ ev.forEach(evt => {
859
+ if (target) {
860
+ if (!delegationEvents.includes(evt))
861
+ return outsider = evt; // outsider events
862
+
863
+ if (!_this.#dlgListeners.has(evt))
864
+ _this.#dlgListeners.set(evt, new Set());
865
+ _this.#dlgListeners.get(evt).add({ callback: cb, target });
866
+ } else {
867
+ elms.forEach(([idx, elm]) => {
868
+ elm.addEventListener(evt, cb);
869
+ });
870
+ }
871
+ });
872
+
873
+ if (outsider !== null)
874
+ return console.error(`[EyeJS] trying to use delegation for an inappropriate event "${outsider}"`);
875
+
876
+ return this;
877
+ }
878
+ /**
879
+ * Remove event listener of a specific event
880
+ * @method EyeElement#off
881
+ * @param {string} ev
882
+ * @param {function} cb
883
+ * @returns {EyeElement|void}
884
+ */
885
+ off(ev, cb) {
886
+ let _this = this,
887
+ listeners = _this.#dlgListeners;
888
+ if (typeof cb != "function")
889
+ return console.error(
890
+ "[EyeJS] .off method is missing the actuall callback `cb` or not of type function"
891
+ );
892
+ ev = ev.split(" ");
893
+
894
+ this.each((elm, idx) => {
895
+ ev.forEach(evt => elm.removeEventListener(evt, cb));
896
+ });
897
+ // now delegated events
898
+ ev.forEach(evt => {
899
+ if (listeners.has(evt)) {
900
+ let set = listeners.get(evt);
901
+ for (const item of set) {
902
+ if (cb === item.callback) {
903
+ // found it & remove it
904
+ set.delete(item);
905
+ }
906
+ }
907
+ }
908
+ });
909
+ }
910
+ /**
911
+ * Trigger specific event for this element
912
+ * @method EyeElement#trigger
913
+ * @param {string} ev
914
+ * @returns {EyeElement}
915
+ */
916
+ trigger(ev) {
917
+ this.each((elm, idx) => {
918
+ elm.dispatchEvent(getEvent(ev));
919
+ });
920
+ return this;
921
+ }
922
+ /**
923
+ * Find one or multiple child elements by `selector`
924
+ * @method EyeElement#find
925
+ * @param {string} selector
926
+ */
927
+ find(selector) {
928
+ let found = [];
929
+ this.each((elm, idx) => {
930
+ elm.querySelectorAll(selector).forEach(res => found.push(res));
931
+ });
932
+ return found.length == 1 ? found[0] : found;
933
+ }
934
+ /**
935
+ * Returns a clone of current selected element/s
936
+ * @method EyeElement#clone
937
+ * @param {HTMLElement} [parent] optionally append new clone to a parent
938
+ * @returns {Array<EyeElement>|EyeElement}
939
+ */
940
+ clone(parent) {
941
+ if (this.#raw instanceof NodeList) {
942
+ let list = [];
943
+ this.#raw.forEach(nd => {
944
+ list.push(nd.cloneNode(true));
945
+ });
946
+ if (parent instanceof HTMLElement || parent instanceof EyeElement) list.forEach(el => parent.append(el));
947
+ return list;
948
+ } else {
949
+ let clone = this.#raw.cloneNode(true);
950
+ if (parent instanceof HTMLElement || parent instanceof EyeElement) parent.append(clone);
951
+ return clone;
952
+ }
953
+ }
954
+ /**
955
+ * Compute DOMRect or style declaration of current element
956
+ * @method EyeElement#compute
957
+ * @param {"bounds" | "style"} type
958
+ * @returns {DOMRect|CSSStyleDeclaration}
959
+ */
960
+ compute(type) {
961
+ type = type || "bounds";
962
+ if (type === "bounds")
963
+ return (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw).getBoundingClientRect();
964
+ else if (type == "style")
965
+ return getComputedStyle(this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw)
966
+ console.error(`[EyeJS] unkown type "${type}" in function .compute, possible values are "bounds" "style"`);
967
+ }
968
+
969
+ /**
970
+ * Get specific client informations.
971
+ * @param {"width" | "height" | "left" | "top"} attr
972
+ * @returns {EyeElement}
973
+ */
974
+ client(attr) {
975
+ if (['width', 'height', 'left', 'top'].includes(attr))
976
+ return (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw)[`client${attr[0].toUpperCase()}${attr.substring(1, attr.length)}`];
977
+ else console.error(`[EyeJS] Unknown client* attribute "${attr}" in .client(attr)`);
978
+ return this;
979
+ }
980
+ /**
981
+ * Activate/disactive different pointer features such as PointerLock, pointerCapture...
982
+ * @method EyeElement#pointer
983
+ * @param {"capture" | "lock"} action
984
+ * @param {boolean} status
985
+ * @param {string} [pid]
986
+ * @returns {EyeElement}
987
+ */
988
+ pointer(action, status, pid) {
989
+ this.each((elm, idx) => {
990
+ if (action === "capture") {
991
+ if (status === true) elm.setPointerCapture(pid);
992
+ else elm.releasePointerCapture(pid);
993
+ } else if (action === "lock") {
994
+ if (status === true) elm.requestPointerLock();
995
+ else document.exitPointerLock();
996
+ }
997
+ });
998
+ return this;
999
+ }
1000
+ /**
1001
+ * Returns the count of children for this element
1002
+ * @type {number}
1003
+ */
1004
+ get childlen() {
1005
+ return (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw)?.children.length;
1006
+ }
1007
+ /**
1008
+ * Select a child of this element
1009
+ * @method EyeElement#child
1010
+ * @param {number} index
1011
+ * @returns {EyeElement|null}
1012
+ */
1013
+ child(index) {
1014
+ let it = (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw);
1015
+ if (index === undefined) return it.children.length;
1016
+ if (it.children[index]) return e(it.children[index]);
1017
+ return null;
1018
+ }
1019
+ /**
1020
+ * Set/get the value of the current element
1021
+ * @method EyeElement#val
1022
+ * @param {*} value
1023
+ * @returns
1024
+ */
1025
+ val(value) {
1026
+ if (value != undefined) (this.#raw instanceof NodeList ? [...this.#raw.entries()] : [[0, this.#raw]]).forEach(([idx, a]) => a.value = this.#customSet.value("set", value, a));
1027
+ else {
1028
+ let it = (this.#raw instanceof NodeList ? this.#raw.item(0) : this.#raw);
1029
+ return this.#customSet.value("get", it.value, it);
1030
+ }
1031
+ return this;
1032
+ }
1033
+ /**
1034
+ * Serialize this element to send it over network, returns 3 formats `json`, `url` & `fd`(formData)
1035
+ * @method EyeElement#serialize
1036
+ * @param {{inputs: Array<string>}} opts
1037
+ * @returns {{json: Object, url: String, fd: FormData}}
1038
+ */
1039
+ serialize(opts) {
1040
+ opts = opts || {};
1041
+ let {
1042
+ inputs = ["input", "textarea", "select"],
1043
+ } = opts;
1044
+ if (this.#raw instanceof HTMLElement) {
1045
+ let out = {
1046
+ json: {},
1047
+ url: "",
1048
+ fd: new FormData()
1049
+ };
1050
+ this.#raw.querySelectorAll(inputs.join(','))
1051
+ .forEach((inp, i) => {
1052
+ let name = inp.name || inp.dataset.name;
1053
+ let value = inp.value || inp.textContent;
1054
+ if (typeof opts[name] === "function") value = opts[name](inp);
1055
+
1056
+ if (inp.type == "file")
1057
+ inp.files.forEach(file => {
1058
+ out.fd.append(name, file);
1059
+ });
1060
+ else {
1061
+ out.json[name] = value;
1062
+ out.fd.append(name, value);
1063
+ }
1064
+ });
1065
+
1066
+ out.url = new URLSearchParams(out.json).toString();
1067
+ return out;
1068
+ } else console.warn(`[EyeJS] this is a multi selection, it's not serializable!`);
1069
+ }
1070
+ /**
1071
+ * Redefine the way `.text` or `.val` set or get data to and from this element.
1072
+ * @method EyeElement#redefine
1073
+ * @param {"text" | "value"} type
1074
+ * @param {(action: "set" | "get", value: *, elm: EyeElement) => *} process
1075
+ * @returns {EyeElement}
1076
+ */
1077
+ redefine(type, process) {
1078
+ if (["text", "value"].includes(type) && typeof process == "function")
1079
+ this.#customSet[type] = process;
1080
+ return this;
1081
+ }
1082
+ /**
1083
+ * Animate current object
1084
+ * @method EyeElement#animate
1085
+ * @param {Array<Keyframe>} keyframes
1086
+ * @param {KeyframeAnimationOptions} opts
1087
+ * @returns {Array<Animation>|Animation}
1088
+ */
1089
+ animate(keyframes, opts) {
1090
+ /**
1091
+ * @type {Array<Animation>}
1092
+ */
1093
+ let anmts = [];
1094
+ opts.duration = opts.duration || 1000;
1095
+ this.each((elm, i) => {
1096
+ anmts.push(elm.animate(keyframes, opts));
1097
+ });
1098
+ return anmts.length == 1 ? anmts[0] : anmts;
1099
+ }
1100
+ }
1101
+ /**
1102
+ * Creates or select nodes using css selectors, offering a pack of useful functions to use around your code!
1103
+ * @param {String} tag
1104
+ * @param {AttrMap} attrs
1105
+ * @param {Object} css CSS styles to be applied to the element.
1106
+ * @returns {EyeElement}
1107
+ */
1108
+ function e(tag, attrs, css) {
1109
+ if (typeof tag === "string" && tag.indexOf("model:") === 0 || tag === "model") {
1110
+ if (!attrs) return console.error("[EyeJS] Model creation requires parameter 'attr' as prototype, none delivered!");
1111
+
1112
+ tag = tag.split(":");
1113
+ let cls = ["eye-model"];
1114
+ if (tag[1])
1115
+ cls = cls.concat(tag[1].split(" ").filter(a => a != ""));
1116
+ // creating a model
1117
+ let model = e("<div>", {
1118
+ class: cls.join(" "),
1119
+ });
1120
+
1121
+ let sets = cmcl(model, attrs);
1122
+
1123
+ /**
1124
+ * @param {string} attrs
1125
+ * @returns {ModelEyeElement}
1126
+ */
1127
+ return (attrs) => {
1128
+ let copy = e(model.clone(attrs?.parent));
1129
+ // define & attach the refresh function
1130
+ copy.refresh = function (attrs = {}) {
1131
+ let def = attrs.default === false ? false : true;
1132
+ sets.forEach((item) => {
1133
+ if (def === true || (!def && attrs.hasOwnProperty(item.name)))
1134
+ item.set(copy, attrs[item.name]);
1135
+ });
1136
+ return this;
1137
+ };
1138
+ return copy.refresh(attrs);
1139
+ };
1140
+ } else return new EyeElement(tag, attrs, css);
1141
+ }
1142
+
1143
+
1144
+ // gloablly exposed
1145
+ window.e = e;
1146
+ window.EyeElement = EyeElement;
1147
+
1148
+ exports.EyeElement = EyeElement;
1149
+ exports.default = e;
1150
+
1151
+ Object.defineProperty(exports, '__esModule', { value: true });
1152
+
1153
+ }));
1154
+ //# sourceMappingURL=eye.umd.js.map