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