@angular-wave/angular.ts 0.0.40 → 0.0.41

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.
@@ -12,7 +12,6 @@ import {
12
12
  lowercase,
13
13
  nodeName_,
14
14
  shallowCopy,
15
- trim,
16
15
  } from "../../shared/utils";
17
16
  import { CACHE, EXPANDO } from "../../core/cache/cache";
18
17
 
@@ -50,7 +49,6 @@ import { CACHE, EXPANDO } from "../../core/cache/cache";
50
49
  * - [`html()`](http://api.jquery.com/html/)
51
50
  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
52
51
  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
53
- * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
54
52
  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
55
53
  * - [`prepend()`](http://api.jquery.com/prepend/)
56
54
  * - [`remove()`](http://api.jquery.com/remove/)
@@ -152,107 +150,40 @@ wrapMap.tbody =
152
150
  wrapMap.thead;
153
151
  wrapMap.th = wrapMap.td;
154
152
 
155
- /**
156
- * Checks if the string contains HTML tags or entities.
157
- * @param {string} html
158
- * @returns {boolean}
159
- */
160
- export function isTextNode(html) {
161
- return !/<|&#?\w+;/.test(html);
162
- }
153
+ export const BOOLEAN_ATTR = {};
154
+ "multiple,selected,checked,disabled,readOnly,required,open"
155
+ .split(",")
156
+ .forEach((value) => {
157
+ BOOLEAN_ATTR[lowercase(value)] = value;
158
+ });
159
+ const BOOLEAN_ELEMENTS = {};
160
+ "input,select,option,textarea,button,form,details"
161
+ .split(",")
162
+ .forEach((value) => {
163
+ BOOLEAN_ELEMENTS[value] = true;
164
+ });
163
165
 
164
166
  /**
167
+ * JQLite both a function and an array-like data structure for manipulation of DOM, linking elements to expando cache,
168
+ * and execution of chain functions.
165
169
  *
166
- * @param {Element} node
167
- * @returns {boolean}
170
+ * @param {string|Element|Document|Window|JQLite|ArrayLike<Element>|(() => void)} element
171
+ * @returns {JQLite}
168
172
  */
169
- function elementAcceptsData(node) {
170
- // The window object can accept data but has no nodeType
171
- // Otherwise we are only interested in elements (1) and documents (9)
172
- switch (node.nodeType) {
173
- case Node.ELEMENT_NODE:
174
- case Node.DOCUMENT_NODE:
175
- case undefined:
176
- return true;
177
- default:
178
- return false;
179
- }
180
- }
181
-
182
- export function JQLiteBuildFragment(html, context) {
183
- let tmp;
184
- let tag;
185
- let wrap;
186
- let finalHtml;
187
- const fragment = context.createDocumentFragment();
188
- let nodes = [];
189
- let i;
190
-
191
- if (isTextNode(html)) {
192
- // Convert non-html into a text node
193
- nodes.push(context.createTextNode(html));
194
- } else {
195
- // Convert html into DOM nodes
196
- tmp = fragment.appendChild(context.createElement("div"));
197
- tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
198
- finalHtml = html;
199
-
200
- wrap = wrapMap[tag] || [];
201
-
202
- // Create wrappers & descend into them
203
- i = wrap.length;
204
- while (--i > -1) {
205
- tmp.appendChild(window.document.createElement(wrap[i]));
206
- tmp = tmp.firstChild;
207
- }
208
-
209
- tmp.innerHTML = finalHtml;
210
-
211
- nodes = concat(nodes, tmp.childNodes);
212
-
213
- tmp = fragment.firstChild;
214
- tmp.textContent = "";
215
- }
216
-
217
- // Remove wrapper from fragment
218
- fragment.textContent = "";
219
- fragment.innerHTML = ""; // Clear inner HTML
220
- forEach(nodes, (node) => {
221
- fragment.appendChild(node);
222
- });
223
-
224
- return fragment;
225
- }
226
-
227
- function JQLiteParseHTML(html, context) {
228
- context = context || window.document;
229
- let parsed;
230
-
231
- if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
232
- return [context.createElement(parsed[1])];
233
- }
234
-
235
- if ((parsed = JQLiteBuildFragment(html, context))) {
236
- return parsed.childNodes;
237
- }
238
-
239
- return [];
240
- }
241
-
242
- /// //////////////////////////////////////////
243
173
  export function JQLite(element) {
244
174
  if (element instanceof JQLite) {
245
175
  return element;
246
176
  }
247
177
 
248
- let argIsString;
178
+ let argIsString = false;
249
179
 
250
180
  if (isString(element)) {
251
- element = trim(element);
181
+ element = /** @type {string} */ (element).trim();
252
182
  argIsString = true;
253
183
  }
184
+
254
185
  if (!(this instanceof JQLite)) {
255
- if (argIsString && element.charAt(0) !== "<") {
186
+ if (argIsString && /** @type {string} */ (element).charAt(0) !== "<") {
256
187
  throw JQLiteMinErr(
257
188
  "nosel",
258
189
  "Looking up elements via selectors is not supported by JQLite! See: http://docs.angularjs.org/api/angular.element",
@@ -262,49 +193,15 @@ export function JQLite(element) {
262
193
  }
263
194
 
264
195
  if (argIsString) {
265
- const parsed = JQLiteParseHTML(element);
196
+ const parsed = parseHtml(/** @type {string} */ (element));
266
197
  addNodes(this, parsed);
267
198
  } else if (isFunction(element)) {
268
- JQLiteReady(element);
199
+ onReady(/** @type {Function} */ (element));
269
200
  } else {
270
201
  addNodes(this, element);
271
202
  }
272
203
  }
273
204
 
274
- /**
275
- * @param {Element} element
276
- * @param {boolean} [onlyDescendants]
277
- * @returns {void}
278
- */
279
- export function dealoc(element, onlyDescendants) {
280
- if (!element) return;
281
- if (!onlyDescendants && elementAcceptsData(element))
282
- JQLiteCleanData([element]);
283
-
284
- if (element.querySelectorAll) {
285
- JQLiteCleanData(element.querySelectorAll("*"));
286
- }
287
- }
288
-
289
- /**
290
- * If `ExpandoStore.data` and `ExpandoStore.events` are empty,
291
- * then delete element's `ExpandoStore` and set its `ExpandoId`
292
- * to undefined.
293
- * @param {Element} element
294
- */
295
- function removeIfEmptyData(element) {
296
- const expandoId = element[EXPANDO];
297
- const { events, data } = CACHE.get(expandoId);
298
-
299
- if (
300
- (!data || !Object.keys(data).length) &&
301
- (!events || !Object.keys(events).length)
302
- ) {
303
- CACHE.delete(expandoId);
304
- element[EXPANDO] = undefined; // don't delete DOM expandos. Chrome don't like it
305
- }
306
- }
307
-
308
205
  function JQLiteOff(element, type, fn, unsupported) {
309
206
  if (isDefined(unsupported))
310
207
  throw JQLiteMinErr(
@@ -312,7 +209,7 @@ function JQLiteOff(element, type, fn, unsupported) {
312
209
  "jqLite#off() does not support the `selector` argument",
313
210
  );
314
211
 
315
- const expandoStore = JQLiteExpandoStore(element);
212
+ const expandoStore = getExpando(element);
316
213
  const events = expandoStore && expandoStore.events;
317
214
  const handle = expandoStore && expandoStore.handle;
318
215
 
@@ -355,7 +252,7 @@ function JQLiteOff(element, type, fn, unsupported) {
355
252
  * @param {Element} element
356
253
  * @param {string} [name] - key of field to remove
357
254
  */
358
- function JQLiteRemoveData(element, name) {
255
+ export function removeElementData(element, name) {
359
256
  const expandoId = element[EXPANDO];
360
257
  const expandoStore = expandoId && CACHE.get(expandoId);
361
258
 
@@ -379,7 +276,7 @@ function JQLiteRemoveData(element, name) {
379
276
  * @param {boolean} [createIfNecessary=false]
380
277
  * @returns {import("../../core/cache/cache").ExpandoStore}
381
278
  */
382
- function JQLiteExpandoStore(element, createIfNecessary = false) {
279
+ function getExpando(element, createIfNecessary = false) {
383
280
  let expandoId = element[EXPANDO];
384
281
  let expandoStore = expandoId && CACHE.get(expandoId);
385
282
 
@@ -396,14 +293,141 @@ function JQLiteExpandoStore(element, createIfNecessary = false) {
396
293
  return expandoStore;
397
294
  }
398
295
 
399
- function JQLiteData(element, key, value) {
296
+ /**
297
+ * Checks if the string contains HTML tags or entities.
298
+ * @param {string} html
299
+ * @returns {boolean} True if the string is plain text, false if it contains HTML tags or entities.
300
+ */
301
+ export function isTextNode(html) {
302
+ return !/<|&#?\w+;/.test(html);
303
+ }
304
+
305
+ /**
306
+ * Check if element can accept expando data
307
+ * @param {Element} node
308
+ * @returns {boolean}
309
+ */
310
+ function elementAcceptsData(node) {
311
+ // The window object can accept data but has no nodeType
312
+ // Otherwise we are only interested in elements (1) and documents (9)
313
+ switch (node.nodeType) {
314
+ case Node.ELEMENT_NODE:
315
+ case Node.DOCUMENT_NODE:
316
+ case undefined: // window.object
317
+ return true;
318
+ default:
319
+ return false;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * @param {string} html
325
+ * @returns {DocumentFragment}
326
+ */
327
+ export function buildFragment(html) {
328
+ let tmp;
329
+ let tag;
330
+ let wrap;
331
+ let tempFragment = document.createDocumentFragment();
332
+ let nodes = [];
333
+ let i;
334
+
335
+ if (isTextNode(html)) {
336
+ // Convert non-html into a text node
337
+ nodes.push(document.createTextNode(html));
338
+ } else {
339
+ // Convert html into DOM nodes
340
+ tmp = tempFragment.appendChild(document.createElement("div"));
341
+ tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
342
+
343
+ wrap = wrapMap[tag] || [];
344
+
345
+ // Create wrappers & descend into them
346
+ i = wrap.length;
347
+ while (--i > -1) {
348
+ tmp.appendChild(window.document.createElement(wrap[i]));
349
+ tmp = tmp.firstChild;
350
+ }
351
+ tmp.innerHTML = html;
352
+
353
+ nodes = concat(nodes, tmp.childNodes);
354
+
355
+ tmp = tempFragment.firstChild;
356
+ tmp.textContent = "";
357
+ }
358
+
359
+ let fragment = document.createDocumentFragment();
360
+ fragment.append(...nodes);
361
+ return fragment;
362
+ }
363
+
364
+ /**
365
+ * @param {string} html
366
+ * @returns {NodeListOf<ChildNode> | HTMLElement[]}
367
+ */
368
+ function parseHtml(html) {
369
+ let regEx = SINGLE_TAG_REGEXP.exec(html);
370
+ if (regEx) {
371
+ return [document.createElement(regEx[1])];
372
+ }
373
+ let fragment = buildFragment(html);
374
+ if (fragment) {
375
+ return fragment.childNodes;
376
+ }
377
+
378
+ return [];
379
+ }
380
+
381
+ /**
382
+ * @param {Element} element
383
+ * @param {boolean} [onlyDescendants]
384
+ * @returns {void}
385
+ */
386
+ export function dealoc(element, onlyDescendants) {
387
+ if (!element) return;
388
+ if (!onlyDescendants && elementAcceptsData(element))
389
+ cleanElementData([element]);
390
+
391
+ if (element.querySelectorAll) {
392
+ cleanElementData(element.querySelectorAll("*"));
393
+ }
394
+ }
395
+
396
+ /**
397
+ * If `ExpandoStore.data` and `ExpandoStore.events` are empty,
398
+ * then delete element's `ExpandoStore` and set its `ExpandoId`
399
+ * to undefined.
400
+ * @param {Element} element
401
+ */
402
+ function removeIfEmptyData(element) {
403
+ const expandoId = element[EXPANDO];
404
+ const { events, data } = CACHE.get(expandoId);
405
+
406
+ if (
407
+ (!data || !Object.keys(data).length) &&
408
+ (!events || !Object.keys(events).length)
409
+ ) {
410
+ CACHE.delete(expandoId);
411
+ element[EXPANDO] = undefined; // don't delete DOM expandos. Chrome don't like it
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Gets or sets cache data for a given element.
417
+ *
418
+ * @param {Element} element - The DOM element to get or set data on.
419
+ * @param {string|Object} key - The key (as a string) to get/set or an object for mass-setting.
420
+ * @param {*} [value] - The value to set. If not provided, the function acts as a getter.
421
+ * @returns {*} - The retrieved data if acting as a getter. Otherwise, returns undefined.
422
+ */
423
+ export function getOrSetCacheData(element, key, value) {
400
424
  if (elementAcceptsData(element)) {
401
425
  let prop;
402
426
 
403
427
  const isSimpleSetter = isDefined(value);
404
428
  const isSimpleGetter = !isSimpleSetter && key && !isObject(key);
405
429
  const massGetter = !key;
406
- const expandoStore = JQLiteExpandoStore(element, !isSimpleGetter);
430
+ const expandoStore = getExpando(element, !isSimpleGetter);
407
431
  const data = expandoStore && expandoStore.data;
408
432
 
409
433
  if (isSimpleSetter) {
@@ -421,6 +445,8 @@ function JQLiteData(element, key, value) {
421
445
  data[kebabToCamel(prop)] = key[prop];
422
446
  }
423
447
  }
448
+ } else {
449
+ // TODO: check should occur perhaps prior at compilation level that this is a valid element
424
450
  }
425
451
  }
426
452
 
@@ -468,7 +494,8 @@ function JQLiteInheritedData(element, name, value) {
468
494
 
469
495
  while (element) {
470
496
  for (let i = 0, ii = names.length; i < ii; i++) {
471
- if (isDefined((value = JQLiteData(element, names[i])))) return value;
497
+ if (isDefined((value = getOrSetCacheData(element, names[i]))))
498
+ return value;
472
499
  }
473
500
 
474
501
  // If dealing with a document fragment node with a host element, and no parent, use the host
@@ -480,37 +507,32 @@ function JQLiteInheritedData(element, name, value) {
480
507
  }
481
508
  }
482
509
 
483
- function JQLiteEmpty(element) {
484
- dealoc(element, true);
485
- while (element.firstChild) {
486
- element.removeChild(element.firstChild);
487
- }
488
- }
489
-
490
- export function JQLiteRemove(element, keepData) {
510
+ /**
511
+ *
512
+ * @param {Element} element
513
+ * @param {boolean} keepData
514
+ */
515
+ export function removeElement(element, keepData = false) {
491
516
  if (!keepData) dealoc(element);
492
517
  const parent = element.parentNode;
493
518
  if (parent) parent.removeChild(element);
494
519
  }
495
520
 
496
- function JQLiteReady(fn) {
521
+ /**
522
+ * Executea a function on `DOMContentLoaded`
523
+ * @param {Function} fn
524
+ */
525
+ function onReady(fn) {
497
526
  function trigger() {
498
527
  window.document.removeEventListener("DOMContentLoaded", trigger);
499
- window.removeEventListener("load", trigger);
500
528
  fn();
501
529
  }
502
-
503
530
  // check if document is already loaded
504
531
  if (window.document.readyState === "complete") {
505
532
  window.setTimeout(fn);
506
533
  } else {
507
- // We can not use JQLite since we are not done loading and jQuery could be loaded later.
508
-
509
- // Works for modern browsers and IE9
534
+ // We can not use JQLite since we are not done loading.
510
535
  window.document.addEventListener("DOMContentLoaded", trigger);
511
-
512
- // Fallback to window.onload for others
513
- window.addEventListener("load", trigger);
514
536
  }
515
537
  }
516
538
 
@@ -518,7 +540,6 @@ function JQLiteReady(fn) {
518
540
  // Functions which are declared directly.
519
541
  /// ///////////////////////////////////////
520
542
  JQLite.prototype = {
521
- ready: JQLiteReady,
522
543
  toString() {
523
544
  const value = [];
524
545
  forEach(this, (e) => {
@@ -532,28 +553,72 @@ JQLite.prototype = {
532
553
  },
533
554
 
534
555
  length: 0,
535
- push: [].push,
536
- sort: [].sort,
537
- splice: [].splice,
538
556
  };
539
557
 
540
- /// ///////////////////////////////////////
541
- // Functions iterating getter/setters.
542
- // these functions return self on setter and
543
- // value on get.
544
- /// ///////////////////////////////////////
545
- export const BOOLEAN_ATTR = {};
546
- "multiple,selected,checked,disabled,readOnly,required,open"
547
- .split(",")
548
- .forEach((value) => {
549
- BOOLEAN_ATTR[lowercase(value)] = value;
550
- });
551
- const BOOLEAN_ELEMENTS = {};
552
- "input,select,option,textarea,button,form,details"
553
- .split(",")
554
- .forEach((value) => {
555
- BOOLEAN_ELEMENTS[value] = true;
556
- });
558
+ /**
559
+ * Remove all child nodes of the set of matched elements from the DOM and clears CACHE data, associated with the node.
560
+ * @returns {JQLite} The current instance of JQLite.
561
+ */
562
+ JQLite.prototype.empty = function () {
563
+ for (let i = 0; i < this.length; i++) {
564
+ const element = this[i];
565
+ dealoc(element, true);
566
+ // we may run into situation where we empty a transcluded node
567
+ if (
568
+ [
569
+ Node.ELEMENT_NODE,
570
+ Node.DOCUMENT_NODE,
571
+ Node.DOCUMENT_FRAGMENT_NODE,
572
+ ].includes(element.nodeType)
573
+ ) {
574
+ element.replaceChildren();
575
+ }
576
+ }
577
+ return this;
578
+ };
579
+
580
+ /**
581
+ * Returns the `$scope` of the element.
582
+ * @returns {import("../../core/scope/scope").Scope}
583
+ */
584
+ JQLite.prototype.scope = function () {
585
+ // Can't use JQLiteData here directly so we stay compatible with jQuery!
586
+ return (
587
+ getOrSetCacheData(this[0], "$scope") ||
588
+ JQLiteInheritedData(this[0].parentNode || this[0], [
589
+ "$isolateScope",
590
+ "$scope",
591
+ ])
592
+ );
593
+ };
594
+
595
+ /**
596
+ * Returns the isolate `$scope` of the element.
597
+ * @returns {import("../../core/scope/scope").Scope}
598
+ */
599
+ JQLite.prototype.isolateScope = function () {
600
+ return (
601
+ getOrSetCacheData(this[0], "$isolateScope") ||
602
+ getOrSetCacheData(this[0], "$isolateScopeNoTemplate")
603
+ );
604
+ };
605
+
606
+ /**
607
+ * Return instance of controller attached to element
608
+ * @param {string} [name] - Controller name
609
+ * @returns {any}
610
+ */
611
+ JQLite.prototype.controller = function (name) {
612
+ return JQLiteController(this[0], name);
613
+ };
614
+
615
+ /**
616
+ * Return instance of injector attached to element
617
+ * @returns {import('../../types').angular.InjectorService}
618
+ */
619
+ JQLite.prototype.injector = function () {
620
+ return JQLiteInheritedData(this[0], "$injector");
621
+ };
557
622
 
558
623
  export function getBooleanAttrName(element, name) {
559
624
  // check dom last since we will most likely fail on name
@@ -563,58 +628,31 @@ export function getBooleanAttrName(element, name) {
563
628
  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
564
629
  }
565
630
 
566
- export function JQLiteCleanData(nodes) {
631
+ /**
632
+ * Takes an array of elements, calls any `$destroy` event handlers, removes any data in cache, and finally removes any
633
+ * listeners.
634
+ * @param {NodeListOf<Element>} nodes
635
+ */
636
+ export function cleanElementData(nodes) {
567
637
  for (let i = 0, ii = nodes.length; i < ii; i++) {
568
638
  var events = (CACHE.get(nodes[i][EXPANDO]) || {}).events;
569
639
  if (events && events.$destroy) {
570
640
  JQLite(nodes[i]).triggerHandler("$destroy");
571
641
  }
572
- JQLiteRemoveData(nodes[i]);
642
+ removeElementData(nodes[i]);
573
643
  JQLiteOff(nodes[i]);
574
644
  }
575
645
  }
576
646
 
647
+ /// ///////////////////////////////////////
648
+ // Functions iterating getter/setters.
649
+ // these functions return self on setter and
650
+ // value on get.
651
+ /// ///////////////////////////////////////
577
652
  forEach(
578
653
  {
579
- data: JQLiteData,
580
- removeData: JQLiteRemoveData,
581
- cleanData: JQLiteCleanData,
582
- },
583
- (fn, name) => {
584
- JQLite[name] = fn;
585
- },
586
- );
587
-
588
- forEach(
589
- {
590
- data: JQLiteData,
654
+ data: getOrSetCacheData,
591
655
  inheritedData: JQLiteInheritedData,
592
-
593
- scope(element) {
594
- // Can't use JQLiteData here directly so we stay compatible with jQuery!
595
- return (
596
- JQLiteData(element, "$scope") ||
597
- JQLiteInheritedData(element.parentNode || element, [
598
- "$isolateScope",
599
- "$scope",
600
- ])
601
- );
602
- },
603
-
604
- isolateScope(element) {
605
- // Can't use JQLiteData here directly so we stay compatible with jQuery!
606
- return (
607
- JQLiteData(element, "$isolateScope") ||
608
- JQLiteData(element, "$isolateScopeNoTemplate")
609
- );
610
- },
611
-
612
- controller: JQLiteController,
613
-
614
- injector(element) {
615
- return JQLiteInheritedData(element, "$injector");
616
- },
617
-
618
656
  attr(element, name, value) {
619
657
  let ret;
620
658
  const { nodeType } = element;
@@ -664,7 +702,6 @@ forEach(
664
702
  element.textContent = value;
665
703
  }
666
704
  })(),
667
-
668
705
  val(element, value) {
669
706
  if (isUndefined(value)) {
670
707
  if (element.multiple && nodeName_(element) === "select") {
@@ -680,7 +717,6 @@ forEach(
680
717
  }
681
718
  element.value = value;
682
719
  },
683
-
684
720
  html(element, value) {
685
721
  if (isUndefined(value)) {
686
722
  return element.innerHTML;
@@ -688,8 +724,6 @@ forEach(
688
724
  dealoc(element, true);
689
725
  element.innerHTML = value;
690
726
  },
691
-
692
- empty: JQLiteEmpty,
693
727
  },
694
728
  (fn, name) => {
695
729
  /**
@@ -702,13 +736,12 @@ forEach(
702
736
 
703
737
  // JQLiteEmpty takes no arguments but is a setter.
704
738
  if (
705
- fn !== JQLiteEmpty &&
706
739
  isUndefined(fn.length === 2 && fn !== JQLiteController ? arg1 : arg2)
707
740
  ) {
708
741
  if (isObject(arg1)) {
709
742
  // we are a write, but the object properties are the key/values
710
743
  for (i = 0; i < nodeCount; i++) {
711
- if (fn === JQLiteData) {
744
+ if (fn === getOrSetCacheData) {
712
745
  fn(this[i], arg1);
713
746
  } else {
714
747
  for (key in arg1) {
@@ -740,80 +773,6 @@ forEach(
740
773
  },
741
774
  );
742
775
 
743
- function createEventHandler(element, events) {
744
- const eventHandler = function (event, type) {
745
- // jQuery specific api
746
- event.isDefaultPrevented = function () {
747
- return event.defaultPrevented;
748
- };
749
-
750
- let eventFns = events[type || event.type];
751
- const eventFnsLength = eventFns ? eventFns.length : 0;
752
-
753
- if (!eventFnsLength) return;
754
-
755
- if (isUndefined(event.immediatePropagationStopped)) {
756
- const originalStopImmediatePropagation = event.stopImmediatePropagation;
757
- event.stopImmediatePropagation = function () {
758
- event.immediatePropagationStopped = true;
759
-
760
- if (event.stopPropagation) {
761
- event.stopPropagation();
762
- }
763
-
764
- if (originalStopImmediatePropagation) {
765
- originalStopImmediatePropagation.call(event);
766
- }
767
- };
768
- }
769
-
770
- event.isImmediatePropagationStopped = function () {
771
- return event.immediatePropagationStopped === true;
772
- };
773
-
774
- // Some events have special handlers that wrap the real handler
775
- const handlerWrapper =
776
- eventFns.specialHandlerWrapper || defaultHandlerWrapper;
777
-
778
- // Copy event handlers in case event handlers array is modified during execution.
779
- if (eventFnsLength > 1) {
780
- eventFns = shallowCopy(eventFns);
781
- }
782
-
783
- for (let i = 0; i < eventFnsLength; i++) {
784
- if (!event.isImmediatePropagationStopped()) {
785
- handlerWrapper(element, event, eventFns[i]);
786
- }
787
- }
788
- };
789
-
790
- // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
791
- // events on `element`
792
- eventHandler.elem = element;
793
- return eventHandler;
794
- }
795
-
796
- function defaultHandlerWrapper(element, event, handler) {
797
- handler.call(element, event);
798
- }
799
-
800
- /**
801
- * @param {Node} target
802
- * @param {*} event
803
- * @param {*} handler
804
- */
805
- function specialMouseHandlerWrapper(target, event, handler) {
806
- // Refer to jQuery's implementation of mouseenter & mouseleave
807
- // Read about mouseenter and mouseleave:
808
- // http://www.quirksmode.org/js/events_mouse.html#link8
809
- const related = event.relatedTarget;
810
- // For mousenter/leave call the handler if related is outside the target.
811
- // NB: No relatedTarget if the mouse left/entered the browser window
812
- if (!related || (related !== target && !target.contains(related))) {
813
- handler.call(target, event);
814
- }
815
- }
816
-
817
776
  /// ///////////////////////////////////////
818
777
  // Functions iterating traversal.
819
778
  // These functions chain results into a single
@@ -821,25 +780,17 @@ function specialMouseHandlerWrapper(target, event, handler) {
821
780
  /// ///////////////////////////////////////
822
781
  forEach(
823
782
  {
824
- removeData: JQLiteRemoveData,
825
- on: (element, type, fn, unsupported) => {
826
- if (isDefined(unsupported))
827
- throw JQLiteMinErr(
828
- "onargs",
829
- "jqLite#on() does not support the `selector` or `eventData` parameters",
830
- );
831
-
783
+ removeData: removeElementData,
784
+ on: (element, type, fn) => {
832
785
  // Do not add event handlers to non-elements because they will not be cleaned up.
833
786
  if (!elementAcceptsData(element)) {
834
787
  return;
835
788
  }
836
789
 
837
- const expandoStore = JQLiteExpandoStore(element, true);
838
- const { events } = expandoStore;
839
- let { handle } = expandoStore;
790
+ const expandoStore = getExpando(element, true);
840
791
 
841
- if (!handle) {
842
- handle = expandoStore.handle = createEventHandler(element, events);
792
+ if (!expandoStore.handle) {
793
+ expandoStore.handle = createEventHandler(element, expandoStore.events);
843
794
  }
844
795
 
845
796
  // http://jsperf.com/string-indexof-vs-split
@@ -851,13 +802,13 @@ forEach(
851
802
  specialHandlerWrapper,
852
803
  noEventListener,
853
804
  ) {
854
- let eventFns = events[type];
805
+ let eventFns = expandoStore.events[type];
855
806
 
856
807
  if (!eventFns) {
857
- eventFns = events[type] = [];
808
+ eventFns = expandoStore.events[type] = [];
858
809
  eventFns.specialHandlerWrapper = specialHandlerWrapper;
859
810
  if (type !== "$destroy" && !noEventListener) {
860
- element.addEventListener(type, handle);
811
+ element.addEventListener(type, expandoStore.handle);
861
812
  }
862
813
  }
863
814
 
@@ -874,9 +825,7 @@ forEach(
874
825
  }
875
826
  }
876
827
  },
877
-
878
828
  off: JQLiteOff,
879
-
880
829
  replaceWith(element, replaceNode) {
881
830
  let index;
882
831
  const parent = element.parentNode;
@@ -890,13 +839,11 @@ forEach(
890
839
  index = node;
891
840
  });
892
841
  },
893
-
894
842
  children(element) {
895
843
  return Array.from(element.childNodes).filter(
896
844
  (child) => child.nodeType === Node.ELEMENT_NODE,
897
845
  );
898
846
  },
899
-
900
847
  append(element, node) {
901
848
  const { nodeType } = element;
902
849
  if (
@@ -922,10 +869,10 @@ forEach(
922
869
  }
923
870
  },
924
871
 
925
- remove: JQLiteRemove,
872
+ remove: removeElement,
926
873
 
927
874
  detach(element) {
928
- JQLiteRemove(element, true);
875
+ removeElement(element, true);
929
876
  },
930
877
 
931
878
  after(element, newElement) {
@@ -963,7 +910,7 @@ forEach(
963
910
  let eventFnsCopy;
964
911
  let handlerArgs;
965
912
  const eventName = event.type || event;
966
- const expandoStore = JQLiteExpandoStore(element);
913
+ const expandoStore = getExpando(element);
967
914
  const events = expandoStore && expandoStore.events;
968
915
  const eventFns = events && events[eventName];
969
916
 
@@ -1029,6 +976,80 @@ forEach(
1029
976
  },
1030
977
  );
1031
978
 
979
+ function createEventHandler(element, events) {
980
+ const eventHandler = function (event, type) {
981
+ // jQuery specific api
982
+ event.isDefaultPrevented = function () {
983
+ return event.defaultPrevented;
984
+ };
985
+
986
+ let eventFns = events[type || event.type];
987
+ const eventFnsLength = eventFns ? eventFns.length : 0;
988
+
989
+ if (!eventFnsLength) return;
990
+
991
+ if (isUndefined(event.immediatePropagationStopped)) {
992
+ const originalStopImmediatePropagation = event.stopImmediatePropagation;
993
+ event.stopImmediatePropagation = function () {
994
+ event.immediatePropagationStopped = true;
995
+
996
+ if (event.stopPropagation) {
997
+ event.stopPropagation();
998
+ }
999
+
1000
+ if (originalStopImmediatePropagation) {
1001
+ originalStopImmediatePropagation.call(event);
1002
+ }
1003
+ };
1004
+ }
1005
+
1006
+ event.isImmediatePropagationStopped = function () {
1007
+ return event.immediatePropagationStopped === true;
1008
+ };
1009
+
1010
+ // Some events have special handlers that wrap the real handler
1011
+ const handlerWrapper =
1012
+ eventFns.specialHandlerWrapper || defaultHandlerWrapper;
1013
+
1014
+ // Copy event handlers in case event handlers array is modified during execution.
1015
+ if (eventFnsLength > 1) {
1016
+ eventFns = shallowCopy(eventFns);
1017
+ }
1018
+
1019
+ for (let i = 0; i < eventFnsLength; i++) {
1020
+ if (!event.isImmediatePropagationStopped()) {
1021
+ handlerWrapper(element, event, eventFns[i]);
1022
+ }
1023
+ }
1024
+ };
1025
+
1026
+ // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
1027
+ // events on `element`
1028
+ eventHandler.elem = element;
1029
+ return eventHandler;
1030
+ }
1031
+
1032
+ function defaultHandlerWrapper(element, event, handler) {
1033
+ handler.call(element, event);
1034
+ }
1035
+
1036
+ /**
1037
+ * @param {Node} target
1038
+ * @param {*} event
1039
+ * @param {*} handler
1040
+ */
1041
+ function specialMouseHandlerWrapper(target, event, handler) {
1042
+ // Refer to jQuery's implementation of mouseenter & mouseleave
1043
+ // Read about mouseenter and mouseleave:
1044
+ // http://www.quirksmode.org/js/events_mouse.html#link8
1045
+ const related = event.relatedTarget;
1046
+ // For mousenter/leave call the handler if related is outside the target.
1047
+ // NB: No relatedTarget if the mouse left/entered the browser window
1048
+ if (!related || (related !== target && !target.contains(related))) {
1049
+ handler.call(target, event);
1050
+ }
1051
+ }
1052
+
1032
1053
  /**
1033
1054
  * @param {string} elementStr
1034
1055
  * @returns {string} Returns the string representation of the element.
@@ -1053,7 +1074,7 @@ export function startingTag(elementStr) {
1053
1074
  /**
1054
1075
  * Return the DOM siblings between the first and last node in the given array.
1055
1076
  * @param {Array} nodes An array-like object
1056
- * @returns {Array} the inputted object or a JQLite collection containing the nodes
1077
+ * @returns {JQLite} the inputted object or a JQLite collection containing the nodes
1057
1078
  */
1058
1079
  export function getBlockNodes(nodes) {
1059
1080
  // TODO(perf): update `nodes` instead of creating a new object?
@@ -1065,11 +1086,11 @@ export function getBlockNodes(nodes) {
1065
1086
  if (blockNodes || nodes[i] !== node) {
1066
1087
  if (!blockNodes) {
1067
1088
  // use element to avoid circular dependency
1068
- blockNodes = JQLite(Array.prototype.slice.call(nodes, 0, i));
1089
+ blockNodes = Array.prototype.slice.call(nodes, 0, i);
1069
1090
  }
1070
1091
  blockNodes.push(node);
1071
1092
  }
1072
1093
  }
1073
1094
 
1074
- return blockNodes || nodes;
1095
+ return JQLite(blockNodes || nodes);
1075
1096
  }