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