@angular-wave/angular.ts 0.0.40 → 0.0.42

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.
Files changed (79) hide show
  1. package/README.md +28 -0
  2. package/dist/angular-ts.esm.js +2 -2
  3. package/dist/angular-ts.umd.js +2 -2
  4. package/package.json +1 -1
  5. package/src/animations/animate-queue.js +7 -4
  6. package/src/core/compile/compile.js +5 -3
  7. package/src/core/compile/compile.md +2 -5
  8. package/src/core/compile/compile.spec.js +2 -43
  9. package/src/core/exception-handler.js +6 -6
  10. package/src/core/interpolate/interpolate.js +1 -1
  11. package/src/core/location/location.spec.js +0 -4
  12. package/src/core/q/q.js +1 -1
  13. package/src/core/scope/scope.js +1 -1
  14. package/src/core/task-tracker-factory.js +2 -2
  15. package/src/core/timeout/timeout.js +1 -1
  16. package/src/core/url-utils/url-utils.js +0 -2
  17. package/src/directive/bind/bind.js +2 -2
  18. package/src/directive/change/change.js +1 -1
  19. package/src/directive/cloak/cloak.js +1 -1
  20. package/src/directive/events/events.js +1 -1
  21. package/src/directive/form/form.js +2 -2
  22. package/src/directive/include/include.js +5 -7
  23. package/src/directive/init/init.js +1 -1
  24. package/src/directive/list/list.js +1 -1
  25. package/src/directive/model/model.js +1 -1
  26. package/src/directive/model-options/model-options.js +56 -421
  27. package/src/directive/model-options/model-options.md +407 -0
  28. package/src/directive/model-options/model-options.spec.js +1 -1
  29. package/src/directive/non-bindable/non-bindable.js +1 -2
  30. package/src/directive/options/options.js +3 -3
  31. package/src/directive/style/style.js +1 -1
  32. package/src/directive/switch/switch.js +2 -2
  33. package/src/directive/transclude/transclude.js +2 -2
  34. package/src/index.js +0 -461
  35. package/src/loader.js +1 -1
  36. package/src/public.js +1 -1
  37. package/src/router/template-factory.js +2 -2
  38. package/src/router/view-scroll.js +1 -1
  39. package/src/services/browser.js +1 -1
  40. package/src/services/document.js +2 -2
  41. package/src/services/http/http.js +11 -7
  42. package/src/services/log.js +1 -1
  43. package/src/services/template-request.js +1 -1
  44. package/src/shared/jqlite/jqlite.js +380 -351
  45. package/src/shared/jqlite/jqlite.spec.js +73 -82
  46. package/src/shared/utils.js +1 -1
  47. package/src/types.js +451 -0
  48. package/tsconfig.json +1 -1
  49. package/types/animations/shared.d.ts +7 -2
  50. package/types/core/compile/compile.d.ts +2 -1
  51. package/types/core/exception-handler.d.ts +5 -7
  52. package/types/core/interpolate/interpolate.d.ts +1 -1
  53. package/types/core/q/q.d.ts +1 -1
  54. package/types/core/task-tracker-factory.d.ts +5 -5
  55. package/types/core/timeout/timeout.d.ts +2 -2
  56. package/types/directive/bind/bind.d.ts +4 -4
  57. package/types/directive/change/change.d.ts +2 -2
  58. package/types/directive/cloak/cloak.d.ts +2 -2
  59. package/types/directive/include/include.d.ts +2 -2
  60. package/types/directive/init/init.d.ts +2 -2
  61. package/types/directive/list/list.d.ts +2 -2
  62. package/types/directive/model/model.d.ts +13 -7
  63. package/types/directive/model-options/model-options.d.ts +49 -0
  64. package/types/directive/non-bindable/non-bindable.d.ts +2 -3
  65. package/types/directive/style/style.d.ts +2 -2
  66. package/types/directive/switch/switch.d.ts +4 -4
  67. package/types/index.d.ts +1 -702
  68. package/types/public.d.ts +2 -2
  69. package/types/router/template-factory.d.ts +4 -4
  70. package/types/services/browser.d.ts +3 -3
  71. package/types/services/document.d.ts +6 -7
  72. package/types/services/log.d.ts +2 -2
  73. package/types/services/template-request.d.ts +1 -1
  74. package/types/shared/jqlite/jqlite.d.ts +91 -21
  75. package/types/shared/utils.d.ts +2 -2
  76. package/types/types.d.ts +438 -0
  77. package/types-back/index.d.ts +1 -83
  78. package/types-back/jqlite.d.ts +1 -121
  79. package/types-back/global.d.ts +0 -11
@@ -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,123 @@ 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').InjectorService}
618
+ */
619
+ JQLite.prototype.injector = function () {
620
+ return JQLiteInheritedData(this[0], "$injector");
621
+ };
622
+
623
+ /**
624
+ * Adds an event listener to each element in the JQLite collection.
625
+ *
626
+ * @param {string} type - The event type(s) to listen for. Multiple event types can be specified, separated by a space.
627
+ * @param {Function} fn - The function to execute when the event is triggered.
628
+ * @returns {JQLite} The JQLite collection for chaining.
629
+ */
630
+ JQLite.prototype.on = function (type, fn) {
631
+ // Do not add event handlers to non-elements because they will not be cleaned up.
632
+ for (let i = 0, ii = this.length; i < ii; i++) {
633
+ const element = this[i];
634
+ if (!elementAcceptsData(element)) {
635
+ return;
636
+ }
637
+
638
+ const expandoStore = getExpando(element, true);
639
+
640
+ if (!expandoStore.handle) {
641
+ expandoStore.handle = createEventHandler(element, expandoStore.events);
642
+ }
643
+ // http://jsperf.com/string-indexof-vs-split
644
+ const types = type.indexOf(" ") >= 0 ? type.split(" ") : [type];
645
+ let j = types.length;
646
+
647
+ const addHandler = function (type, specialHandlerWrapper, noEventListener) {
648
+ let eventFns = expandoStore.events[type];
649
+
650
+ if (!eventFns) {
651
+ eventFns = expandoStore.events[type] = [];
652
+ eventFns.specialHandlerWrapper = specialHandlerWrapper;
653
+ if (type !== "$destroy" && !noEventListener) {
654
+ element.addEventListener(type, expandoStore.handle);
655
+ }
656
+ }
657
+
658
+ eventFns.push(fn);
659
+ };
660
+
661
+ while (j--) {
662
+ type = types[j];
663
+ if (MOUSE_EVENT_MAP[type]) {
664
+ addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
665
+ addHandler(type, undefined, true);
666
+ } else {
667
+ addHandler(type);
668
+ }
669
+ }
670
+ }
671
+ return this;
672
+ };
557
673
 
558
674
  export function getBooleanAttrName(element, name) {
559
675
  // check dom last since we will most likely fail on name
@@ -563,58 +679,31 @@ export function getBooleanAttrName(element, name) {
563
679
  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
564
680
  }
565
681
 
566
- export function JQLiteCleanData(nodes) {
682
+ /**
683
+ * Takes an array of elements, calls any `$destroy` event handlers, removes any data in cache, and finally removes any
684
+ * listeners.
685
+ * @param {NodeListOf<Element>} nodes
686
+ */
687
+ export function cleanElementData(nodes) {
567
688
  for (let i = 0, ii = nodes.length; i < ii; i++) {
568
689
  var events = (CACHE.get(nodes[i][EXPANDO]) || {}).events;
569
690
  if (events && events.$destroy) {
570
691
  JQLite(nodes[i]).triggerHandler("$destroy");
571
692
  }
572
- JQLiteRemoveData(nodes[i]);
693
+ removeElementData(nodes[i]);
573
694
  JQLiteOff(nodes[i]);
574
695
  }
575
696
  }
576
697
 
698
+ /// ///////////////////////////////////////
699
+ // Functions iterating getter/setters.
700
+ // these functions return self on setter and
701
+ // value on get.
702
+ /// ///////////////////////////////////////
577
703
  forEach(
578
704
  {
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,
705
+ data: getOrSetCacheData,
591
706
  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
707
  attr(element, name, value) {
619
708
  let ret;
620
709
  const { nodeType } = element;
@@ -664,7 +753,6 @@ forEach(
664
753
  element.textContent = value;
665
754
  }
666
755
  })(),
667
-
668
756
  val(element, value) {
669
757
  if (isUndefined(value)) {
670
758
  if (element.multiple && nodeName_(element) === "select") {
@@ -680,7 +768,6 @@ forEach(
680
768
  }
681
769
  element.value = value;
682
770
  },
683
-
684
771
  html(element, value) {
685
772
  if (isUndefined(value)) {
686
773
  return element.innerHTML;
@@ -688,8 +775,6 @@ forEach(
688
775
  dealoc(element, true);
689
776
  element.innerHTML = value;
690
777
  },
691
-
692
- empty: JQLiteEmpty,
693
778
  },
694
779
  (fn, name) => {
695
780
  /**
@@ -702,13 +787,12 @@ forEach(
702
787
 
703
788
  // JQLiteEmpty takes no arguments but is a setter.
704
789
  if (
705
- fn !== JQLiteEmpty &&
706
790
  isUndefined(fn.length === 2 && fn !== JQLiteController ? arg1 : arg2)
707
791
  ) {
708
792
  if (isObject(arg1)) {
709
793
  // we are a write, but the object properties are the key/values
710
794
  for (i = 0; i < nodeCount; i++) {
711
- if (fn === JQLiteData) {
795
+ if (fn === getOrSetCacheData) {
712
796
  fn(this[i], arg1);
713
797
  } else {
714
798
  for (key in arg1) {
@@ -740,80 +824,6 @@ forEach(
740
824
  },
741
825
  );
742
826
 
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
827
  /// ///////////////////////////////////////
818
828
  // Functions iterating traversal.
819
829
  // These functions chain results into a single
@@ -821,62 +831,9 @@ function specialMouseHandlerWrapper(target, event, handler) {
821
831
  /// ///////////////////////////////////////
822
832
  forEach(
823
833
  {
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
-
832
- // Do not add event handlers to non-elements because they will not be cleaned up.
833
- if (!elementAcceptsData(element)) {
834
- return;
835
- }
836
-
837
- const expandoStore = JQLiteExpandoStore(element, true);
838
- const { events } = expandoStore;
839
- let { handle } = expandoStore;
840
-
841
- if (!handle) {
842
- handle = expandoStore.handle = createEventHandler(element, events);
843
- }
844
-
845
- // http://jsperf.com/string-indexof-vs-split
846
- const types = type.indexOf(" ") >= 0 ? type.split(" ") : [type];
847
- let i = types.length;
848
-
849
- const addHandler = function (
850
- type,
851
- specialHandlerWrapper,
852
- noEventListener,
853
- ) {
854
- let eventFns = events[type];
855
-
856
- if (!eventFns) {
857
- eventFns = events[type] = [];
858
- eventFns.specialHandlerWrapper = specialHandlerWrapper;
859
- if (type !== "$destroy" && !noEventListener) {
860
- element.addEventListener(type, handle);
861
- }
862
- }
863
-
864
- eventFns.push(fn);
865
- };
866
-
867
- while (i--) {
868
- type = types[i];
869
- if (MOUSE_EVENT_MAP[type]) {
870
- addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
871
- addHandler(type, undefined, true);
872
- } else {
873
- addHandler(type);
874
- }
875
- }
876
- },
834
+ removeData: removeElementData,
877
835
 
878
836
  off: JQLiteOff,
879
-
880
837
  replaceWith(element, replaceNode) {
881
838
  let index;
882
839
  const parent = element.parentNode;
@@ -890,13 +847,11 @@ forEach(
890
847
  index = node;
891
848
  });
892
849
  },
893
-
894
850
  children(element) {
895
851
  return Array.from(element.childNodes).filter(
896
852
  (child) => child.nodeType === Node.ELEMENT_NODE,
897
853
  );
898
854
  },
899
-
900
855
  append(element, node) {
901
856
  const { nodeType } = element;
902
857
  if (
@@ -922,10 +877,10 @@ forEach(
922
877
  }
923
878
  },
924
879
 
925
- remove: JQLiteRemove,
880
+ remove: removeElement,
926
881
 
927
882
  detach(element) {
928
- JQLiteRemove(element, true);
883
+ removeElement(element, true);
929
884
  },
930
885
 
931
886
  after(element, newElement) {
@@ -963,7 +918,7 @@ forEach(
963
918
  let eventFnsCopy;
964
919
  let handlerArgs;
965
920
  const eventName = event.type || event;
966
- const expandoStore = JQLiteExpandoStore(element);
921
+ const expandoStore = getExpando(element);
967
922
  const events = expandoStore && expandoStore.events;
968
923
  const eventFns = events && events[eventName];
969
924
 
@@ -1029,6 +984,80 @@ forEach(
1029
984
  },
1030
985
  );
1031
986
 
987
+ function createEventHandler(element, events) {
988
+ const eventHandler = function (event, type) {
989
+ // jQuery specific api
990
+ event.isDefaultPrevented = function () {
991
+ return event.defaultPrevented;
992
+ };
993
+
994
+ let eventFns = events[type || event.type];
995
+ const eventFnsLength = eventFns ? eventFns.length : 0;
996
+
997
+ if (!eventFnsLength) return;
998
+
999
+ if (isUndefined(event.immediatePropagationStopped)) {
1000
+ const originalStopImmediatePropagation = event.stopImmediatePropagation;
1001
+ event.stopImmediatePropagation = function () {
1002
+ event.immediatePropagationStopped = true;
1003
+
1004
+ if (event.stopPropagation) {
1005
+ event.stopPropagation();
1006
+ }
1007
+
1008
+ if (originalStopImmediatePropagation) {
1009
+ originalStopImmediatePropagation.call(event);
1010
+ }
1011
+ };
1012
+ }
1013
+
1014
+ event.isImmediatePropagationStopped = function () {
1015
+ return event.immediatePropagationStopped === true;
1016
+ };
1017
+
1018
+ // Some events have special handlers that wrap the real handler
1019
+ const handlerWrapper =
1020
+ eventFns.specialHandlerWrapper || defaultHandlerWrapper;
1021
+
1022
+ // Copy event handlers in case event handlers array is modified during execution.
1023
+ if (eventFnsLength > 1) {
1024
+ eventFns = shallowCopy(eventFns);
1025
+ }
1026
+
1027
+ for (let i = 0; i < eventFnsLength; i++) {
1028
+ if (!event.isImmediatePropagationStopped()) {
1029
+ handlerWrapper(element, event, eventFns[i]);
1030
+ }
1031
+ }
1032
+ };
1033
+
1034
+ // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
1035
+ // events on `element`
1036
+ eventHandler.elem = element;
1037
+ return eventHandler;
1038
+ }
1039
+
1040
+ function defaultHandlerWrapper(element, event, handler) {
1041
+ handler.call(element, event);
1042
+ }
1043
+
1044
+ /**
1045
+ * @param {Node} target
1046
+ * @param {*} event
1047
+ * @param {*} handler
1048
+ */
1049
+ function specialMouseHandlerWrapper(target, event, handler) {
1050
+ // Refer to jQuery's implementation of mouseenter & mouseleave
1051
+ // Read about mouseenter and mouseleave:
1052
+ // http://www.quirksmode.org/js/events_mouse.html#link8
1053
+ const related = event.relatedTarget;
1054
+ // For mousenter/leave call the handler if related is outside the target.
1055
+ // NB: No relatedTarget if the mouse left/entered the browser window
1056
+ if (!related || (related !== target && !target.contains(related))) {
1057
+ handler.call(target, event);
1058
+ }
1059
+ }
1060
+
1032
1061
  /**
1033
1062
  * @param {string} elementStr
1034
1063
  * @returns {string} Returns the string representation of the element.
@@ -1053,7 +1082,7 @@ export function startingTag(elementStr) {
1053
1082
  /**
1054
1083
  * Return the DOM siblings between the first and last node in the given array.
1055
1084
  * @param {Array} nodes An array-like object
1056
- * @returns {Array} the inputted object or a JQLite collection containing the nodes
1085
+ * @returns {JQLite} the inputted object or a JQLite collection containing the nodes
1057
1086
  */
1058
1087
  export function getBlockNodes(nodes) {
1059
1088
  // TODO(perf): update `nodes` instead of creating a new object?
@@ -1065,11 +1094,11 @@ export function getBlockNodes(nodes) {
1065
1094
  if (blockNodes || nodes[i] !== node) {
1066
1095
  if (!blockNodes) {
1067
1096
  // use element to avoid circular dependency
1068
- blockNodes = JQLite(Array.prototype.slice.call(nodes, 0, i));
1097
+ blockNodes = Array.prototype.slice.call(nodes, 0, i);
1069
1098
  }
1070
1099
  blockNodes.push(node);
1071
1100
  }
1072
1101
  }
1073
1102
 
1074
- return blockNodes || nodes;
1103
+ return JQLite(blockNodes || nodes);
1075
1104
  }