@angular-wave/angular.ts 0.0.44 → 0.0.46
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.
- package/README.md +1 -1
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/angular.spec.js +5 -5
- package/src/core/compile/compile.js +6 -5
- package/src/core/compile/compile.spec.js +27 -27
- package/src/directive/ref/ref.js +2 -2
- package/src/router/directives/directives.test.js +1 -1
- package/src/router/state/state-service.js +0 -41
- package/src/router/state/state.spec.js +0 -6
- package/src/services/anchor-scroll.js +2 -2
- package/src/shared/jqlite/jqlite.js +762 -689
- package/src/shared/jqlite/jqlite.spec.js +0 -9
- package/src/shared/utils.js +16 -5
- package/src/src.test.js +1 -1
- package/src/types.js +2 -2
- package/types/shared/jqlite/jqlite.d.ts +71 -19
- package/types/shared/utils.d.ts +10 -2
- package/types/types.d.ts +2 -2
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isString,
|
|
11
11
|
isUndefined,
|
|
12
12
|
lowercase,
|
|
13
|
-
|
|
13
|
+
getNodeName,
|
|
14
14
|
shallowCopy,
|
|
15
15
|
} from "../../shared/utils";
|
|
16
16
|
import { CACHE, EXPANDO } from "../../core/cache/cache";
|
|
@@ -86,48 +86,17 @@ import { CACHE, EXPANDO } from "../../core/cache/cache";
|
|
|
86
86
|
* https://github.com/angular/angular.js/issues/14251 for more information.
|
|
87
87
|
*
|
|
88
88
|
* @param {string|Element} element HTML string or Element to be wrapped into jQuery.
|
|
89
|
-
* @returns {
|
|
89
|
+
* @returns {JQLite} jQuery object.
|
|
90
90
|
*/
|
|
91
91
|
|
|
92
92
|
/** @type {number} */
|
|
93
93
|
let jqId = 1;
|
|
94
94
|
|
|
95
|
-
function jqNextId() {
|
|
96
|
-
return ++jqId;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
95
|
const DASH_LOWERCASE_REGEXP = /-([a-z])/g;
|
|
100
96
|
const UNDERSCORE_LOWERCASE_REGEXP = /_([a-z])/g;
|
|
101
97
|
const MOUSE_EVENT_MAP = { mouseleave: "mouseout", mouseenter: "mouseover" };
|
|
102
98
|
const JQLiteMinErr = minErr("jqLite");
|
|
103
99
|
|
|
104
|
-
/**
|
|
105
|
-
* @param {string} _all
|
|
106
|
-
* @param {string} letter
|
|
107
|
-
* @returns {string}
|
|
108
|
-
*/
|
|
109
|
-
function fnCamelCaseReplace(_all, letter) {
|
|
110
|
-
return letter.toUpperCase();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Converts kebab-case to camelCase.
|
|
115
|
-
* @param {string} name Name to normalize
|
|
116
|
-
* @returns {string}
|
|
117
|
-
*/
|
|
118
|
-
export function kebabToCamel(name) {
|
|
119
|
-
return name.replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Converts sname to camelCase.
|
|
124
|
-
* @param {string} name
|
|
125
|
-
* @returns {string}
|
|
126
|
-
*/
|
|
127
|
-
export function snakeToCamel(name) {
|
|
128
|
-
return name.replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
100
|
const SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
|
|
132
101
|
const TAG_NAME_REGEXP = /<([\w:-]+)/;
|
|
133
102
|
|
|
@@ -172,7 +141,7 @@ const BOOLEAN_ELEMENTS = {};
|
|
|
172
141
|
*/
|
|
173
142
|
export function JQLite(element) {
|
|
174
143
|
if (element instanceof JQLite) {
|
|
175
|
-
return element;
|
|
144
|
+
return /** @type {JQLite} */ (element);
|
|
176
145
|
}
|
|
177
146
|
|
|
178
147
|
let argIsString = false;
|
|
@@ -202,787 +171,867 @@ export function JQLite(element) {
|
|
|
202
171
|
}
|
|
203
172
|
}
|
|
204
173
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
174
|
+
/// ///////////////////////////////////////
|
|
175
|
+
// Functions which are declared directly.
|
|
176
|
+
/// ///////////////////////////////////////
|
|
177
|
+
JQLite.prototype = {
|
|
178
|
+
toString() {
|
|
179
|
+
const value = [];
|
|
180
|
+
forEach(this, (e) => {
|
|
181
|
+
value.push(`${e}`);
|
|
182
|
+
});
|
|
183
|
+
return `[${value.join(", ")}]`;
|
|
184
|
+
},
|
|
211
185
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
186
|
+
eq(index) {
|
|
187
|
+
return index >= 0 ? JQLite(this[index]) : JQLite(this[this.length + index]);
|
|
188
|
+
},
|
|
215
189
|
|
|
216
|
-
|
|
190
|
+
length: 0,
|
|
191
|
+
};
|
|
217
192
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Remove all child nodes of the set of matched elements from the DOM and clears CACHE data, associated with the node.
|
|
195
|
+
* @returns {JQLite} The current instance of JQLite.
|
|
196
|
+
*/
|
|
197
|
+
JQLite.prototype.empty = function () {
|
|
198
|
+
for (let i = 0; i < this.length; i++) {
|
|
199
|
+
const element = this[i];
|
|
200
|
+
dealoc(element, true);
|
|
201
|
+
// we may run into situation where we empty a transcluded node
|
|
202
|
+
if (
|
|
203
|
+
[
|
|
204
|
+
Node.ELEMENT_NODE,
|
|
205
|
+
Node.DOCUMENT_NODE,
|
|
206
|
+
Node.DOCUMENT_FRAGMENT_NODE,
|
|
207
|
+
].includes(element.nodeType)
|
|
208
|
+
) {
|
|
209
|
+
element.replaceChildren();
|
|
224
210
|
}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
211
|
+
}
|
|
212
|
+
return this;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Returns the `$scope` of the element.
|
|
217
|
+
* @returns {import("../../core/scope/scope").Scope}
|
|
218
|
+
*/
|
|
219
|
+
JQLite.prototype.scope = function () {
|
|
220
|
+
// Can't use JQLiteData here directly so we stay compatible with jQuery!
|
|
221
|
+
return (
|
|
222
|
+
getOrSetCacheData(this[0], "$scope") ||
|
|
223
|
+
getInheritedData(this[0].parentNode || this[0], ["$isolateScope", "$scope"])
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Returns the isolate `$scope` of the element.
|
|
229
|
+
* @returns {import("../../core/scope/scope").Scope}
|
|
230
|
+
*/
|
|
231
|
+
JQLite.prototype.isolateScope = function () {
|
|
232
|
+
return (
|
|
233
|
+
getOrSetCacheData(this[0], "$isolateScope") ||
|
|
234
|
+
getOrSetCacheData(this[0], "$isolateScopeNoTemplate")
|
|
235
|
+
);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Return instance of controller attached to element
|
|
240
|
+
* @param {string} [name] - Controller name
|
|
241
|
+
* @returns {any}
|
|
242
|
+
*/
|
|
243
|
+
JQLite.prototype.controller = function (name) {
|
|
244
|
+
return getController(this[0], name);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Return instance of injector attached to element
|
|
249
|
+
* @returns {import('../../types').InjectorService}
|
|
250
|
+
*/
|
|
251
|
+
JQLite.prototype.injector = function () {
|
|
252
|
+
return getInheritedData(this[0], "$injector");
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Adds an event listener to each element in the JQLite collection.
|
|
257
|
+
*
|
|
258
|
+
* @param {string} type - The event type(s) to listen for. Multiple event types can be specified, separated by a space.
|
|
259
|
+
* @param {Function} fn - The function to execute when the event is triggered.
|
|
260
|
+
* @returns {JQLite} The JQLite collection for chaining.
|
|
261
|
+
*/
|
|
262
|
+
JQLite.prototype.on = function (type, fn) {
|
|
263
|
+
// Do not add event handlers to non-elements because they will not be cleaned up.
|
|
264
|
+
for (let i = 0; i < this.length; i++) {
|
|
265
|
+
const element = this[i];
|
|
266
|
+
if (!elementAcceptsData(element)) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const expandoStore = getExpando(element, true);
|
|
271
|
+
|
|
272
|
+
if (!expandoStore.handle) {
|
|
273
|
+
expandoStore.handle = createEventHandler(element, expandoStore.events);
|
|
274
|
+
}
|
|
275
|
+
// http://jsperf.com/string-indexof-vs-split
|
|
276
|
+
const types = type.indexOf(" ") >= 0 ? type.split(" ") : [type];
|
|
277
|
+
let j = types.length;
|
|
278
|
+
|
|
279
|
+
const addHandler = function (type, specialHandlerWrapper, noEventListener) {
|
|
280
|
+
let eventFns = expandoStore.events[type];
|
|
281
|
+
|
|
282
|
+
if (!eventFns) {
|
|
283
|
+
eventFns = expandoStore.events[type] = [];
|
|
284
|
+
eventFns.specialHandlerWrapper = specialHandlerWrapper;
|
|
285
|
+
if (type !== "$destroy" && !noEventListener) {
|
|
286
|
+
element.addEventListener(type, expandoStore.handle);
|
|
287
|
+
}
|
|
234
288
|
}
|
|
289
|
+
|
|
290
|
+
eventFns.push(fn);
|
|
235
291
|
};
|
|
236
292
|
|
|
237
|
-
|
|
238
|
-
|
|
293
|
+
while (j--) {
|
|
294
|
+
type = types[j];
|
|
239
295
|
if (MOUSE_EVENT_MAP[type]) {
|
|
240
|
-
|
|
296
|
+
addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
|
|
297
|
+
addHandler(type, undefined, true);
|
|
298
|
+
} else {
|
|
299
|
+
addHandler(type);
|
|
241
300
|
}
|
|
242
|
-
}
|
|
301
|
+
}
|
|
243
302
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
303
|
+
return this;
|
|
304
|
+
};
|
|
247
305
|
|
|
248
306
|
/**
|
|
249
|
-
* Removes
|
|
250
|
-
*
|
|
251
|
-
* from
|
|
252
|
-
* @param {
|
|
253
|
-
* @
|
|
307
|
+
* Removes an event listener to each element in JQLite collection.
|
|
308
|
+
*
|
|
309
|
+
* @param {string} type - The event type(s) to remove listener from
|
|
310
|
+
* @param {Function} fn - The function to remove from event type.
|
|
311
|
+
* @returns {JQLite}
|
|
254
312
|
*/
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
313
|
+
JQLite.prototype.off = function (type, fn) {
|
|
314
|
+
for (let i = 0; i < this.length; i++) {
|
|
315
|
+
const element = this[i];
|
|
316
|
+
const expandoStore = getExpando(element);
|
|
317
|
+
const events = expandoStore && expandoStore.events;
|
|
318
|
+
const handle = expandoStore && expandoStore.handle;
|
|
258
319
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
320
|
+
if (!handle) return; // no listeners registered
|
|
321
|
+
|
|
322
|
+
if (!type) {
|
|
323
|
+
for (type in events) {
|
|
324
|
+
if (type !== "$destroy") {
|
|
325
|
+
element.removeEventListener(type, handle);
|
|
326
|
+
}
|
|
327
|
+
delete events[type];
|
|
328
|
+
}
|
|
262
329
|
} else {
|
|
263
|
-
|
|
330
|
+
const removeHandler = function (type) {
|
|
331
|
+
const listenerFns = events[type];
|
|
332
|
+
if (isDefined(fn) && Array.isArray(listenerFns)) {
|
|
333
|
+
arrayRemove(listenerFns, fn);
|
|
334
|
+
}
|
|
335
|
+
if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
|
|
336
|
+
element.removeEventListener(type, handle);
|
|
337
|
+
delete events[type];
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
forEach(type.split(" "), (type) => {
|
|
342
|
+
removeHandler(type);
|
|
343
|
+
if (MOUSE_EVENT_MAP[type]) {
|
|
344
|
+
removeHandler(MOUSE_EVENT_MAP[type]);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
264
347
|
}
|
|
265
348
|
|
|
266
349
|
removeIfEmptyData(element);
|
|
267
350
|
}
|
|
268
|
-
|
|
351
|
+
return this;
|
|
352
|
+
};
|
|
269
353
|
|
|
270
354
|
/**
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
* @
|
|
274
|
-
*
|
|
275
|
-
* @param {Element} element
|
|
276
|
-
* @param {boolean} [createIfNecessary=false]
|
|
277
|
-
* @returns {import("../../core/cache/cache").ExpandoStore}
|
|
355
|
+
* Remove data by name from cache associated with each element in JQLite collection.
|
|
356
|
+
* @param {string} name - The key of the data associated with element
|
|
357
|
+
* @returns {JQLite}
|
|
278
358
|
*/
|
|
279
|
-
function
|
|
280
|
-
let
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (createIfNecessary && !expandoStore) {
|
|
284
|
-
element[EXPANDO] = expandoId = jqNextId();
|
|
285
|
-
expandoStore = {
|
|
286
|
-
events: {},
|
|
287
|
-
data: {},
|
|
288
|
-
handle: null,
|
|
289
|
-
};
|
|
290
|
-
CACHE.set(expandoId, expandoStore);
|
|
359
|
+
JQLite.prototype.removeData = function (name) {
|
|
360
|
+
for (let i = 0; i < this.length; i++) {
|
|
361
|
+
const element = this[i];
|
|
362
|
+
removeElementData(element, name);
|
|
291
363
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
364
|
+
return this;
|
|
365
|
+
};
|
|
295
366
|
|
|
296
367
|
/**
|
|
297
|
-
*
|
|
298
|
-
* @param {string}
|
|
299
|
-
* @
|
|
368
|
+
* Gets or sets data on a parent element
|
|
369
|
+
* @param {string} name
|
|
370
|
+
* @param {any} value
|
|
371
|
+
* @returns {JQLite|any}
|
|
300
372
|
*/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
373
|
+
JQLite.prototype.inheritedData = function (name, value) {
|
|
374
|
+
for (let i = 0; i < this.length; i++) {
|
|
375
|
+
const element = this[0];
|
|
376
|
+
let res = getInheritedData(element, name, value);
|
|
377
|
+
if (value) {
|
|
378
|
+
return this;
|
|
379
|
+
} else {
|
|
380
|
+
return res;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
};
|
|
304
384
|
|
|
305
385
|
/**
|
|
306
|
-
*
|
|
307
|
-
* @param {
|
|
308
|
-
* @returns {
|
|
386
|
+
* Gets or sets innerHTML on the first element in JQLite collection
|
|
387
|
+
* @param {string} value
|
|
388
|
+
* @returns {JQLite|any|undefined}
|
|
309
389
|
*/
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
case Node.DOCUMENT_NODE:
|
|
316
|
-
case undefined: // window.object
|
|
317
|
-
return true;
|
|
318
|
-
default:
|
|
319
|
-
return false;
|
|
390
|
+
JQLite.prototype.html = function (value) {
|
|
391
|
+
const element = this[0];
|
|
392
|
+
if (!element) return undefined;
|
|
393
|
+
if (isUndefined(value)) {
|
|
394
|
+
return element.innerHTML;
|
|
320
395
|
}
|
|
321
|
-
|
|
396
|
+
dealoc(element, true);
|
|
397
|
+
element.innerHTML = value;
|
|
398
|
+
return this;
|
|
399
|
+
};
|
|
322
400
|
|
|
323
401
|
/**
|
|
324
|
-
*
|
|
325
|
-
*
|
|
402
|
+
* Get the combined text contents of each element in the JQLite collection
|
|
403
|
+
* or set the text contents of all elements.
|
|
404
|
+
* @param {string} [value]
|
|
405
|
+
* @returns {JQLite|string}
|
|
326
406
|
*/
|
|
327
|
-
|
|
328
|
-
let
|
|
329
|
-
let
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
407
|
+
JQLite.prototype.text = function (value) {
|
|
408
|
+
let res = "";
|
|
409
|
+
for (let i = 0; i < this.length; i++) {
|
|
410
|
+
const element = this[i];
|
|
411
|
+
if (isUndefined(value)) {
|
|
412
|
+
// read
|
|
413
|
+
const { nodeType } = element;
|
|
414
|
+
res +=
|
|
415
|
+
nodeType === Node.ELEMENT_NODE || nodeType === Node.TEXT_NODE
|
|
416
|
+
? element.textContent
|
|
417
|
+
: "";
|
|
418
|
+
} else {
|
|
419
|
+
// write
|
|
420
|
+
element.textContent = value;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
334
423
|
|
|
335
|
-
if (
|
|
336
|
-
|
|
337
|
-
nodes.push(document.createTextNode(html));
|
|
424
|
+
if (isUndefined(value)) {
|
|
425
|
+
return res;
|
|
338
426
|
} else {
|
|
339
|
-
|
|
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 = "";
|
|
427
|
+
return this;
|
|
357
428
|
}
|
|
358
|
-
|
|
359
|
-
let fragment = document.createDocumentFragment();
|
|
360
|
-
fragment.append(...nodes);
|
|
361
|
-
return fragment;
|
|
362
|
-
}
|
|
429
|
+
};
|
|
363
430
|
|
|
364
431
|
/**
|
|
365
|
-
*
|
|
366
|
-
* @
|
|
432
|
+
* Gets or sets the values of form elements such as input, select and textarea in a JQLite collection.
|
|
433
|
+
* @param {any} value
|
|
434
|
+
* @returns {JQLite|any}
|
|
367
435
|
*/
|
|
368
|
-
function
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
436
|
+
JQLite.prototype.val = function (value) {
|
|
437
|
+
// We can only get or set a value of
|
|
438
|
+
for (let i = 0; i < this.length; i++) {
|
|
439
|
+
const element = this[i];
|
|
440
|
+
if (isUndefined(value)) {
|
|
441
|
+
// read
|
|
442
|
+
if (element.multiple && getNodeName(element) === "select") {
|
|
443
|
+
const result = [];
|
|
444
|
+
forEach(element.options, (option) => {
|
|
445
|
+
if (option.selected) {
|
|
446
|
+
result.push(option.value || option.text);
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
451
|
+
return element.value;
|
|
452
|
+
} else {
|
|
453
|
+
// write
|
|
454
|
+
element.value = value;
|
|
455
|
+
return this;
|
|
456
|
+
}
|
|
376
457
|
}
|
|
377
|
-
|
|
378
|
-
return [];
|
|
379
|
-
}
|
|
458
|
+
};
|
|
380
459
|
|
|
381
460
|
/**
|
|
382
|
-
* @param {
|
|
383
|
-
* @param {
|
|
384
|
-
* @returns
|
|
461
|
+
* @param {string|Object} name
|
|
462
|
+
* @param {any} value
|
|
463
|
+
* @returns
|
|
385
464
|
*/
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
465
|
+
JQLite.prototype.attr = function (name, value) {
|
|
466
|
+
for (let i = 0; i < this.length; i++) {
|
|
467
|
+
const element = this[i];
|
|
468
|
+
let ret;
|
|
469
|
+
const { nodeType } = element;
|
|
470
|
+
if (
|
|
471
|
+
nodeType === Node.TEXT_NODE ||
|
|
472
|
+
nodeType === Node.ATTRIBUTE_NODE ||
|
|
473
|
+
nodeType === Node.COMMENT_NODE ||
|
|
474
|
+
!element.getAttribute
|
|
475
|
+
) {
|
|
476
|
+
continue;
|
|
477
|
+
}
|
|
390
478
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
}
|
|
479
|
+
const lowercasedName = lowercase(name);
|
|
480
|
+
const isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
|
|
395
481
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
function removeIfEmptyData(element) {
|
|
403
|
-
const expandoId = element[EXPANDO];
|
|
404
|
-
const { events, data } = CACHE.get(expandoId);
|
|
482
|
+
if (isObject(name)) {
|
|
483
|
+
for (let key in name) {
|
|
484
|
+
element.setAttribute(key, isBooleanAttr ? lowercasedName : name[key]);
|
|
485
|
+
}
|
|
486
|
+
} else if (isDefined(value)) {
|
|
487
|
+
// setter
|
|
405
488
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
489
|
+
if (value === null || (value === false && isBooleanAttr)) {
|
|
490
|
+
element.removeAttribute(name);
|
|
491
|
+
} else {
|
|
492
|
+
element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
|
|
493
|
+
}
|
|
494
|
+
} else {
|
|
495
|
+
// getter
|
|
496
|
+
ret = element.getAttribute(name);
|
|
497
|
+
if (isBooleanAttr && ret !== null) {
|
|
498
|
+
ret = lowercasedName;
|
|
499
|
+
}
|
|
500
|
+
// Normalize non-existing attributes to undefined (as jQuery).
|
|
501
|
+
return ret === null ? undefined : ret;
|
|
502
|
+
}
|
|
412
503
|
}
|
|
413
|
-
|
|
504
|
+
|
|
505
|
+
if (isDefined(value) || isObject(name)) {
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
414
509
|
|
|
415
510
|
/**
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* @
|
|
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.
|
|
511
|
+
* @param {string|any} key - The key (as a string) to get/set or an object for mass-setting.
|
|
512
|
+
* @param {any} [value] - The value to set. If not provided, the function acts as a getter.
|
|
513
|
+
* @returns {JQLite|any} - The retrieved data if acting as a getter. Otherwise, returns undefined.
|
|
422
514
|
*/
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
515
|
+
JQLite.prototype.data = function (key, value) {
|
|
516
|
+
let i;
|
|
517
|
+
const nodeCount = this.length;
|
|
518
|
+
if (isUndefined(value)) {
|
|
519
|
+
if (isObject(key)) {
|
|
520
|
+
// we are a write, but the object properties are the key/values
|
|
521
|
+
for (i = 0; i < nodeCount; i++) {
|
|
522
|
+
getOrSetCacheData(this[i], key);
|
|
523
|
+
}
|
|
524
|
+
return this;
|
|
525
|
+
}
|
|
526
|
+
// we are a read, so read the first child.
|
|
527
|
+
const jj = isUndefined(value) ? Math.min(nodeCount, 1) : nodeCount;
|
|
528
|
+
for (let j = 0; j < jj; j++) {
|
|
529
|
+
const nodeValue = getOrSetCacheData(this[j], key, value);
|
|
530
|
+
value = value ? value + nodeValue : nodeValue;
|
|
531
|
+
}
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
// we are a write, so apply to all children
|
|
535
|
+
for (i = 0; i < nodeCount; i++) {
|
|
536
|
+
getOrSetCacheData(this[i], key, value);
|
|
537
|
+
}
|
|
538
|
+
return this;
|
|
539
|
+
};
|
|
426
540
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
541
|
+
/// ///////////////////////////////////////
|
|
542
|
+
// Functions iterating traversal.
|
|
543
|
+
// These functions chain results into a single
|
|
544
|
+
// selector.
|
|
545
|
+
/// ///////////////////////////////////////
|
|
546
|
+
forEach(
|
|
547
|
+
{
|
|
548
|
+
replaceWith(element, replaceNode) {
|
|
549
|
+
let index;
|
|
550
|
+
const parent = element.parentNode;
|
|
551
|
+
dealoc(element);
|
|
552
|
+
forEach(new JQLite(replaceNode), (node) => {
|
|
553
|
+
if (index) {
|
|
554
|
+
parent.insertBefore(node, index.nextSibling);
|
|
555
|
+
} else {
|
|
556
|
+
parent.replaceChild(node, element);
|
|
557
|
+
}
|
|
558
|
+
index = node;
|
|
559
|
+
});
|
|
560
|
+
},
|
|
561
|
+
children(element) {
|
|
562
|
+
return Array.from(element.childNodes).filter(
|
|
563
|
+
(child) => child.nodeType === Node.ELEMENT_NODE,
|
|
564
|
+
);
|
|
565
|
+
},
|
|
566
|
+
append(element, node) {
|
|
567
|
+
const { nodeType } = element;
|
|
568
|
+
if (
|
|
569
|
+
nodeType !== Node.ELEMENT_NODE &&
|
|
570
|
+
nodeType !== Node.DOCUMENT_FRAGMENT_NODE
|
|
571
|
+
)
|
|
572
|
+
return;
|
|
432
573
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
if (isSimpleGetter) {
|
|
440
|
-
// don't force creation of expandoStore if it doesn't exist yet
|
|
441
|
-
return data && data[kebabToCamel(key)];
|
|
574
|
+
node = new JQLite(node);
|
|
575
|
+
|
|
576
|
+
for (let i = 0, ii = node.length; i < ii; i++) {
|
|
577
|
+
const child = node[i];
|
|
578
|
+
element.appendChild(child);
|
|
442
579
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
prepend(element, node) {
|
|
583
|
+
if (element.nodeType === Node.ELEMENT_NODE) {
|
|
584
|
+
const index = element.firstChild;
|
|
585
|
+
forEach(new JQLite(node), (child) => {
|
|
586
|
+
element.insertBefore(child, index);
|
|
587
|
+
});
|
|
446
588
|
}
|
|
447
|
-
}
|
|
448
|
-
} else {
|
|
449
|
-
// TODO: check should occur perhaps prior at compilation level that this is a valid element
|
|
450
|
-
}
|
|
451
|
-
}
|
|
589
|
+
},
|
|
452
590
|
|
|
453
|
-
|
|
454
|
-
* Adds nodes or elements to the root array-like object.
|
|
455
|
-
*
|
|
456
|
-
* @param {Array} root - The array-like object to which elements will be added.
|
|
457
|
-
* @param {(Node|Array|NodeList|Object)} elements - The elements to add to the root. This can be a single DOM node, an array-like object (such as an Array or NodeList), or any other object.
|
|
458
|
-
*/
|
|
459
|
-
function addNodes(root, elements) {
|
|
460
|
-
// THIS CODE IS VERY HOT. Don't make changes without benchmarking.
|
|
591
|
+
remove: removeElement,
|
|
461
592
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
root[root.length++] = elements;
|
|
466
|
-
} else {
|
|
467
|
-
const { length } = elements;
|
|
593
|
+
detach(element) {
|
|
594
|
+
removeElement(element, true);
|
|
595
|
+
},
|
|
468
596
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
597
|
+
after(element, newElement) {
|
|
598
|
+
let index = element;
|
|
599
|
+
const parent = element.parentNode;
|
|
600
|
+
|
|
601
|
+
if (parent) {
|
|
602
|
+
newElement = new JQLite(newElement);
|
|
603
|
+
|
|
604
|
+
for (let i = 0, ii = newElement.length; i < ii; i++) {
|
|
605
|
+
const node = newElement[i];
|
|
606
|
+
parent.insertBefore(node, index.nextSibling);
|
|
607
|
+
index = node;
|
|
475
608
|
}
|
|
476
|
-
} else {
|
|
477
|
-
root[root.length++] = elements;
|
|
478
609
|
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
610
|
+
},
|
|
482
611
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
612
|
+
parent(element) {
|
|
613
|
+
const parent = element.parentNode;
|
|
614
|
+
return parent && parent.nodeType !== Node.DOCUMENT_FRAGMENT_NODE
|
|
615
|
+
? parent
|
|
616
|
+
: null;
|
|
617
|
+
},
|
|
486
618
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
619
|
+
// TODO: remove after migrating tests away from JQLite
|
|
620
|
+
find(element, selector) {
|
|
621
|
+
if (element.getElementsByTagName) {
|
|
622
|
+
return element.getElementsByTagName(selector);
|
|
623
|
+
}
|
|
624
|
+
return [];
|
|
625
|
+
},
|
|
494
626
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
627
|
+
triggerHandler(element, event, extraParameters) {
|
|
628
|
+
let dummyEvent;
|
|
629
|
+
let eventFnsCopy;
|
|
630
|
+
let handlerArgs;
|
|
631
|
+
const eventName = event.type || event;
|
|
632
|
+
const expandoStore = getExpando(element);
|
|
633
|
+
const events = expandoStore && expandoStore.events;
|
|
634
|
+
const eventFns = events && events[eventName];
|
|
500
635
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
636
|
+
if (eventFns) {
|
|
637
|
+
// Create a dummy event to pass to the handlers
|
|
638
|
+
dummyEvent = {
|
|
639
|
+
preventDefault() {
|
|
640
|
+
this.defaultPrevented = true;
|
|
641
|
+
},
|
|
642
|
+
isDefaultPrevented() {
|
|
643
|
+
return this.defaultPrevented === true;
|
|
644
|
+
},
|
|
645
|
+
stopImmediatePropagation() {
|
|
646
|
+
this.immediatePropagationStopped = true;
|
|
647
|
+
},
|
|
648
|
+
isImmediatePropagationStopped() {
|
|
649
|
+
return this.immediatePropagationStopped === true;
|
|
650
|
+
},
|
|
651
|
+
stopPropagation: () => {},
|
|
652
|
+
type: eventName,
|
|
653
|
+
target: element,
|
|
654
|
+
};
|
|
509
655
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
*/
|
|
515
|
-
export function removeElement(element, keepData = false) {
|
|
516
|
-
if (!keepData) dealoc(element);
|
|
517
|
-
const parent = element.parentNode;
|
|
518
|
-
if (parent) parent.removeChild(element);
|
|
519
|
-
}
|
|
656
|
+
// If a custom event was provided then extend our dummy event with it
|
|
657
|
+
if (event.type) {
|
|
658
|
+
dummyEvent = extend(dummyEvent, event);
|
|
659
|
+
}
|
|
520
660
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
function trigger() {
|
|
527
|
-
window.document.removeEventListener("DOMContentLoaded", trigger);
|
|
528
|
-
fn();
|
|
529
|
-
}
|
|
530
|
-
// check if document is already loaded
|
|
531
|
-
if (window.document.readyState === "complete") {
|
|
532
|
-
window.setTimeout(fn);
|
|
533
|
-
} else {
|
|
534
|
-
// We can not use JQLite since we are not done loading.
|
|
535
|
-
window.document.addEventListener("DOMContentLoaded", trigger);
|
|
536
|
-
}
|
|
537
|
-
}
|
|
661
|
+
// Copy event handlers in case event handlers array is modified during execution.
|
|
662
|
+
eventFnsCopy = shallowCopy(eventFns);
|
|
663
|
+
handlerArgs = extraParameters
|
|
664
|
+
? [dummyEvent].concat(extraParameters)
|
|
665
|
+
: [dummyEvent];
|
|
538
666
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
value.push(`${e}`);
|
|
547
|
-
});
|
|
548
|
-
return `[${value.join(", ")}]`;
|
|
667
|
+
forEach(eventFnsCopy, (fn) => {
|
|
668
|
+
if (!dummyEvent.isImmediatePropagationStopped()) {
|
|
669
|
+
fn.apply(element, handlerArgs);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
},
|
|
549
674
|
},
|
|
675
|
+
(fn, name) => {
|
|
676
|
+
/**
|
|
677
|
+
* chaining functions
|
|
678
|
+
*/
|
|
679
|
+
JQLite.prototype[name] = function (arg1, arg2, arg3) {
|
|
680
|
+
let value;
|
|
550
681
|
|
|
551
|
-
|
|
552
|
-
|
|
682
|
+
for (let i = 0, ii = this.length; i < ii; i++) {
|
|
683
|
+
if (isUndefined(value)) {
|
|
684
|
+
value = fn(this[i], arg1, arg2, arg3);
|
|
685
|
+
if (isDefined(value)) {
|
|
686
|
+
// any function which returns a value needs to be wrapped
|
|
687
|
+
value = JQLite(value);
|
|
688
|
+
}
|
|
689
|
+
} else {
|
|
690
|
+
addNodes(value, fn(this[i], arg1, arg2, arg3));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return isDefined(value) ? value : this;
|
|
694
|
+
};
|
|
553
695
|
},
|
|
696
|
+
);
|
|
554
697
|
|
|
555
|
-
|
|
556
|
-
|
|
698
|
+
///////////////////////////////////////////////////////////////////
|
|
699
|
+
//////////// HELPER FUNCTIONS /////////////////////////
|
|
700
|
+
///////////////////////////////////////////////////////////////////
|
|
557
701
|
|
|
558
702
|
/**
|
|
559
|
-
*
|
|
560
|
-
* @returns {
|
|
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}
|
|
703
|
+
*
|
|
704
|
+
* @returns {number} Next unique JQInstance id
|
|
583
705
|
*/
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
getOrSetCacheData(this[0], "$scope") ||
|
|
588
|
-
JQLiteInheritedData(this[0].parentNode || this[0], [
|
|
589
|
-
"$isolateScope",
|
|
590
|
-
"$scope",
|
|
591
|
-
])
|
|
592
|
-
);
|
|
593
|
-
};
|
|
706
|
+
function jqNextId() {
|
|
707
|
+
return ++jqId;
|
|
708
|
+
}
|
|
594
709
|
|
|
595
710
|
/**
|
|
596
|
-
*
|
|
597
|
-
* @
|
|
711
|
+
* @param {string} _all
|
|
712
|
+
* @param {string} letter
|
|
713
|
+
* @returns {string}
|
|
598
714
|
*/
|
|
599
|
-
|
|
600
|
-
return (
|
|
601
|
-
|
|
602
|
-
getOrSetCacheData(this[0], "$isolateScopeNoTemplate")
|
|
603
|
-
);
|
|
604
|
-
};
|
|
715
|
+
function fnCamelCaseReplace(_all, letter) {
|
|
716
|
+
return letter.toUpperCase();
|
|
717
|
+
}
|
|
605
718
|
|
|
606
719
|
/**
|
|
607
|
-
*
|
|
608
|
-
* @param {string}
|
|
609
|
-
* @returns {
|
|
720
|
+
* Converts kebab-case to camelCase.
|
|
721
|
+
* @param {string} name Name to normalize
|
|
722
|
+
* @returns {string}
|
|
610
723
|
*/
|
|
611
|
-
|
|
612
|
-
return
|
|
613
|
-
}
|
|
724
|
+
export function kebabToCamel(name) {
|
|
725
|
+
return name.replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
|
|
726
|
+
}
|
|
614
727
|
|
|
615
728
|
/**
|
|
616
|
-
*
|
|
617
|
-
* @
|
|
729
|
+
* Converts sname to camelCase.
|
|
730
|
+
* @param {string} name
|
|
731
|
+
* @returns {string}
|
|
618
732
|
*/
|
|
619
|
-
|
|
620
|
-
return
|
|
621
|
-
}
|
|
733
|
+
export function snakeToCamel(name) {
|
|
734
|
+
return name.replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace);
|
|
735
|
+
}
|
|
622
736
|
|
|
623
737
|
/**
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
* @param {
|
|
628
|
-
* @
|
|
738
|
+
* Removes expando data from this element. If key is provided, only
|
|
739
|
+
* its field is removed. If data is empty, also removes `ExpandoStore`
|
|
740
|
+
* from cache.
|
|
741
|
+
* @param {Element} element
|
|
742
|
+
* @param {string} [name] - key of field to remove
|
|
629
743
|
*/
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
const element = this[i];
|
|
634
|
-
if (!elementAcceptsData(element)) {
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const expandoStore = getExpando(element, true);
|
|
744
|
+
export function removeElementData(element, name) {
|
|
745
|
+
const expandoId = element[EXPANDO];
|
|
746
|
+
const expandoStore = expandoId && CACHE.get(expandoId);
|
|
639
747
|
|
|
640
|
-
|
|
641
|
-
|
|
748
|
+
if (expandoStore) {
|
|
749
|
+
if (name) {
|
|
750
|
+
delete expandoStore.data[name];
|
|
751
|
+
} else {
|
|
752
|
+
expandoStore.data = {};
|
|
642
753
|
}
|
|
643
|
-
// http://jsperf.com/string-indexof-vs-split
|
|
644
|
-
const types = type.indexOf(" ") >= 0 ? type.split(" ") : [type];
|
|
645
|
-
let j = types.length;
|
|
646
754
|
|
|
647
|
-
|
|
648
|
-
|
|
755
|
+
removeIfEmptyData(element);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
649
758
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
759
|
+
/**
|
|
760
|
+
* Stores data associated with an element inside the expando property of the DOM element.
|
|
761
|
+
*
|
|
762
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Glossary/Expando MDN Glossary: Expando}
|
|
763
|
+
*
|
|
764
|
+
* @param {Element} element
|
|
765
|
+
* @param {boolean} [createIfNecessary=false]
|
|
766
|
+
* @returns {import("../../core/cache/cache").ExpandoStore}
|
|
767
|
+
*/
|
|
768
|
+
function getExpando(element, createIfNecessary = false) {
|
|
769
|
+
let expandoId = element[EXPANDO];
|
|
770
|
+
let expandoStore = expandoId && CACHE.get(expandoId);
|
|
657
771
|
|
|
658
|
-
|
|
772
|
+
if (createIfNecessary && !expandoStore) {
|
|
773
|
+
element[EXPANDO] = expandoId = jqNextId();
|
|
774
|
+
expandoStore = {
|
|
775
|
+
events: {},
|
|
776
|
+
data: {},
|
|
777
|
+
handle: null,
|
|
659
778
|
};
|
|
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
|
-
}
|
|
779
|
+
CACHE.set(expandoId, expandoStore);
|
|
670
780
|
}
|
|
671
|
-
return this;
|
|
672
|
-
};
|
|
673
781
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
const booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
|
|
782
|
+
return expandoStore;
|
|
783
|
+
}
|
|
677
784
|
|
|
678
|
-
|
|
679
|
-
|
|
785
|
+
/**
|
|
786
|
+
* Checks if the string contains HTML tags or entities.
|
|
787
|
+
* @param {string} html
|
|
788
|
+
* @returns {boolean} True if the string is plain text, false if it contains HTML tags or entities.
|
|
789
|
+
*/
|
|
790
|
+
export function isTextNode(html) {
|
|
791
|
+
return !/<|&#?\w+;/.test(html);
|
|
680
792
|
}
|
|
681
793
|
|
|
682
794
|
/**
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
* @
|
|
795
|
+
* Check if element can accept expando data
|
|
796
|
+
* @param {Element} node
|
|
797
|
+
* @returns {boolean}
|
|
686
798
|
*/
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
799
|
+
function elementAcceptsData(node) {
|
|
800
|
+
// The window object can accept data but has no nodeType
|
|
801
|
+
// Otherwise we are only interested in elements (1) and documents (9)
|
|
802
|
+
switch (node.nodeType) {
|
|
803
|
+
case Node.ELEMENT_NODE:
|
|
804
|
+
case Node.DOCUMENT_NODE:
|
|
805
|
+
case undefined: // window.object
|
|
806
|
+
return true;
|
|
807
|
+
default:
|
|
808
|
+
return false;
|
|
695
809
|
}
|
|
696
810
|
}
|
|
697
811
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const { nodeType } = element;
|
|
710
|
-
if (
|
|
711
|
-
nodeType === Node.TEXT_NODE ||
|
|
712
|
-
nodeType === Node.ATTRIBUTE_NODE ||
|
|
713
|
-
nodeType === Node.COMMENT_NODE ||
|
|
714
|
-
!element.getAttribute
|
|
715
|
-
) {
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
const lowercasedName = lowercase(name);
|
|
720
|
-
const isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
|
|
721
|
-
|
|
722
|
-
if (isDefined(value)) {
|
|
723
|
-
// setter
|
|
812
|
+
/**
|
|
813
|
+
* @param {string} html
|
|
814
|
+
* @returns {DocumentFragment}
|
|
815
|
+
*/
|
|
816
|
+
export function buildFragment(html) {
|
|
817
|
+
let tmp;
|
|
818
|
+
let tag;
|
|
819
|
+
let wrap;
|
|
820
|
+
let tempFragment = document.createDocumentFragment();
|
|
821
|
+
let nodes = [];
|
|
822
|
+
let i;
|
|
724
823
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
824
|
+
if (isTextNode(html)) {
|
|
825
|
+
// Convert non-html into a text node
|
|
826
|
+
nodes.push(document.createTextNode(html));
|
|
827
|
+
} else {
|
|
828
|
+
// Convert html into DOM nodes
|
|
829
|
+
tmp = tempFragment.appendChild(document.createElement("div"));
|
|
830
|
+
tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
|
|
732
831
|
|
|
733
|
-
|
|
832
|
+
wrap = wrapMap[tag] || [];
|
|
734
833
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
text: (function () {
|
|
743
|
-
getText.$dv = "";
|
|
744
|
-
return getText;
|
|
834
|
+
// Create wrappers & descend into them
|
|
835
|
+
i = wrap.length;
|
|
836
|
+
while (--i > -1) {
|
|
837
|
+
tmp.appendChild(window.document.createElement(wrap[i]));
|
|
838
|
+
tmp = tmp.firstChild;
|
|
839
|
+
}
|
|
840
|
+
tmp.innerHTML = html;
|
|
745
841
|
|
|
746
|
-
|
|
747
|
-
if (isUndefined(value)) {
|
|
748
|
-
const { nodeType } = element;
|
|
749
|
-
return nodeType === Node.ELEMENT_NODE || nodeType === Node.TEXT_NODE
|
|
750
|
-
? element.textContent
|
|
751
|
-
: "";
|
|
752
|
-
}
|
|
753
|
-
element.textContent = value;
|
|
754
|
-
}
|
|
755
|
-
})(),
|
|
756
|
-
val(element, value) {
|
|
757
|
-
if (isUndefined(value)) {
|
|
758
|
-
if (element.multiple && nodeName_(element) === "select") {
|
|
759
|
-
const result = [];
|
|
760
|
-
forEach(element.options, (option) => {
|
|
761
|
-
if (option.selected) {
|
|
762
|
-
result.push(option.value || option.text);
|
|
763
|
-
}
|
|
764
|
-
});
|
|
765
|
-
return result;
|
|
766
|
-
}
|
|
767
|
-
return element.value;
|
|
768
|
-
}
|
|
769
|
-
element.value = value;
|
|
770
|
-
},
|
|
771
|
-
html(element, value) {
|
|
772
|
-
if (isUndefined(value)) {
|
|
773
|
-
return element.innerHTML;
|
|
774
|
-
}
|
|
775
|
-
dealoc(element, true);
|
|
776
|
-
element.innerHTML = value;
|
|
777
|
-
},
|
|
778
|
-
},
|
|
779
|
-
(fn, name) => {
|
|
780
|
-
/**
|
|
781
|
-
* Properties: writes return selection, reads return first value
|
|
782
|
-
*/
|
|
783
|
-
JQLite.prototype[name] = function (arg1, arg2) {
|
|
784
|
-
let i;
|
|
785
|
-
let key;
|
|
786
|
-
const nodeCount = this.length;
|
|
842
|
+
nodes = concat(nodes, tmp.childNodes);
|
|
787
843
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
) {
|
|
792
|
-
if (isObject(arg1)) {
|
|
793
|
-
// we are a write, but the object properties are the key/values
|
|
794
|
-
for (i = 0; i < nodeCount; i++) {
|
|
795
|
-
if (fn === getOrSetCacheData) {
|
|
796
|
-
fn(this[i], arg1);
|
|
797
|
-
} else {
|
|
798
|
-
for (key in arg1) {
|
|
799
|
-
fn(this[i], key, arg1[key]);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
// return self for chaining
|
|
804
|
-
return this;
|
|
805
|
-
}
|
|
806
|
-
// we are a read, so read the first child.
|
|
807
|
-
// TODO: do we still need this?
|
|
808
|
-
let value = fn.$dv;
|
|
809
|
-
// Only if we have $dv do we iterate over all, otherwise it is just the first element.
|
|
810
|
-
const jj = isUndefined(value) ? Math.min(nodeCount, 1) : nodeCount;
|
|
811
|
-
for (let j = 0; j < jj; j++) {
|
|
812
|
-
const nodeValue = fn(this[j], arg1, arg2);
|
|
813
|
-
value = value ? value + nodeValue : nodeValue;
|
|
814
|
-
}
|
|
815
|
-
return value;
|
|
816
|
-
}
|
|
817
|
-
// we are a write, so apply to all children
|
|
818
|
-
for (i = 0; i < nodeCount; i++) {
|
|
819
|
-
fn(this[i], arg1, arg2);
|
|
820
|
-
}
|
|
821
|
-
// return self for chaining
|
|
822
|
-
return this;
|
|
823
|
-
};
|
|
824
|
-
},
|
|
825
|
-
);
|
|
844
|
+
tmp = tempFragment.firstChild;
|
|
845
|
+
tmp.textContent = "";
|
|
846
|
+
}
|
|
826
847
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
/// ///////////////////////////////////////
|
|
832
|
-
forEach(
|
|
833
|
-
{
|
|
834
|
-
removeData: removeElementData,
|
|
848
|
+
let fragment = document.createDocumentFragment();
|
|
849
|
+
fragment.append(...nodes);
|
|
850
|
+
return fragment;
|
|
851
|
+
}
|
|
835
852
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
},
|
|
850
|
-
children(element) {
|
|
851
|
-
return Array.from(element.childNodes).filter(
|
|
852
|
-
(child) => child.nodeType === Node.ELEMENT_NODE,
|
|
853
|
-
);
|
|
854
|
-
},
|
|
855
|
-
append(element, node) {
|
|
856
|
-
const { nodeType } = element;
|
|
857
|
-
if (
|
|
858
|
-
nodeType !== Node.ELEMENT_NODE &&
|
|
859
|
-
nodeType !== Node.DOCUMENT_FRAGMENT_NODE
|
|
860
|
-
)
|
|
861
|
-
return;
|
|
853
|
+
/**
|
|
854
|
+
* @param {string} html
|
|
855
|
+
* @returns {NodeListOf<ChildNode> | HTMLElement[]}
|
|
856
|
+
*/
|
|
857
|
+
function parseHtml(html) {
|
|
858
|
+
let regEx = SINGLE_TAG_REGEXP.exec(html);
|
|
859
|
+
if (regEx) {
|
|
860
|
+
return [document.createElement(regEx[1])];
|
|
861
|
+
}
|
|
862
|
+
let fragment = buildFragment(html);
|
|
863
|
+
if (fragment) {
|
|
864
|
+
return fragment.childNodes;
|
|
865
|
+
}
|
|
862
866
|
|
|
863
|
-
|
|
867
|
+
return [];
|
|
868
|
+
}
|
|
864
869
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
+
/**
|
|
871
|
+
* @param {Element} element
|
|
872
|
+
* @param {boolean} [onlyDescendants]
|
|
873
|
+
* @returns {void}
|
|
874
|
+
*/
|
|
875
|
+
export function dealoc(element, onlyDescendants) {
|
|
876
|
+
if (!element) return;
|
|
877
|
+
if (!onlyDescendants && elementAcceptsData(element))
|
|
878
|
+
cleanElementData([element]);
|
|
870
879
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
element.insertBefore(child, index);
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
},
|
|
880
|
+
if (element.querySelectorAll) {
|
|
881
|
+
cleanElementData(element.querySelectorAll("*"));
|
|
882
|
+
}
|
|
883
|
+
}
|
|
879
884
|
|
|
880
|
-
|
|
885
|
+
/**
|
|
886
|
+
* If `ExpandoStore.data` and `ExpandoStore.events` are empty,
|
|
887
|
+
* then delete element's `ExpandoStore` and set its `ExpandoId`
|
|
888
|
+
* to undefined.
|
|
889
|
+
* @param {Element} element
|
|
890
|
+
*/
|
|
891
|
+
function removeIfEmptyData(element) {
|
|
892
|
+
const expandoId = element[EXPANDO];
|
|
893
|
+
const { events, data } = CACHE.get(expandoId);
|
|
881
894
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
895
|
+
if (
|
|
896
|
+
(!data || !Object.keys(data).length) &&
|
|
897
|
+
(!events || !Object.keys(events).length)
|
|
898
|
+
) {
|
|
899
|
+
CACHE.delete(expandoId);
|
|
900
|
+
element[EXPANDO] = undefined; // don't delete DOM expandos. Chrome don't like it
|
|
901
|
+
}
|
|
902
|
+
}
|
|
885
903
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
904
|
+
/**
|
|
905
|
+
* Gets or sets cache data for a given element.
|
|
906
|
+
*
|
|
907
|
+
* @param {Element} element - The DOM element to get or set data on.
|
|
908
|
+
* @param {string|Object} key - The key (as a string) to get/set or an object for mass-setting.
|
|
909
|
+
* @param {*} [value] - The value to set. If not provided, the function acts as a getter.
|
|
910
|
+
* @returns {*} - The retrieved data if acting as a getter. Otherwise, returns undefined.
|
|
911
|
+
*/
|
|
912
|
+
export function getOrSetCacheData(element, key, value) {
|
|
913
|
+
if (elementAcceptsData(element)) {
|
|
914
|
+
let prop;
|
|
889
915
|
|
|
890
|
-
|
|
891
|
-
|
|
916
|
+
const isSimpleSetter = isDefined(value);
|
|
917
|
+
const isSimpleGetter = !isSimpleSetter && key && !isObject(key);
|
|
918
|
+
const massGetter = !key;
|
|
919
|
+
const expandoStore = getExpando(element, !isSimpleGetter);
|
|
920
|
+
const data = expandoStore && expandoStore.data;
|
|
892
921
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
922
|
+
if (isSimpleSetter) {
|
|
923
|
+
data[kebabToCamel(key)] = value;
|
|
924
|
+
} else {
|
|
925
|
+
if (massGetter) {
|
|
926
|
+
return data;
|
|
898
927
|
}
|
|
899
|
-
|
|
928
|
+
if (isSimpleGetter) {
|
|
929
|
+
// don't force creation of expandoStore if it doesn't exist yet
|
|
930
|
+
return data && data[kebabToCamel(key)];
|
|
931
|
+
}
|
|
932
|
+
// mass-setter: data({key1: val1, key2: val2})
|
|
933
|
+
for (prop in key) {
|
|
934
|
+
data[kebabToCamel(prop)] = key[prop];
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
} else {
|
|
938
|
+
// TODO: check should occur perhaps prior at compilation level that this is a valid element
|
|
939
|
+
}
|
|
940
|
+
}
|
|
900
941
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
942
|
+
/**
|
|
943
|
+
* Adds nodes or elements to the root array-like object.
|
|
944
|
+
*
|
|
945
|
+
* @param {Array} root - The array-like object to which elements will be added.
|
|
946
|
+
* @param {(Node|Array|NodeList|Object)} elements - The elements to add to the root. This can be a single DOM node, an array-like object (such as an Array or NodeList), or any other object.
|
|
947
|
+
*/
|
|
948
|
+
function addNodes(root, elements) {
|
|
949
|
+
// THIS CODE IS VERY HOT. Don't make changes without benchmarking.
|
|
907
950
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
951
|
+
if (elements) {
|
|
952
|
+
// if a Node (the most common case)
|
|
953
|
+
if (elements.nodeType) {
|
|
954
|
+
root[root.length++] = elements;
|
|
955
|
+
} else {
|
|
956
|
+
const { length } = elements;
|
|
957
|
+
|
|
958
|
+
// if an Array or NodeList and not a Window
|
|
959
|
+
if (typeof length === "number" && elements.window !== elements) {
|
|
960
|
+
if (length) {
|
|
961
|
+
for (let i = 0; i < length; i++) {
|
|
962
|
+
root[root.length++] = elements[i];
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
root[root.length++] = elements;
|
|
912
967
|
}
|
|
913
|
-
|
|
914
|
-
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
}
|
|
915
971
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
let handlerArgs;
|
|
920
|
-
const eventName = event.type || event;
|
|
921
|
-
const expandoStore = getExpando(element);
|
|
922
|
-
const events = expandoStore && expandoStore.events;
|
|
923
|
-
const eventFns = events && events[eventName];
|
|
972
|
+
function getController(element, name) {
|
|
973
|
+
return getInheritedData(element, `$${name || "ngController"}Controller`);
|
|
974
|
+
}
|
|
924
975
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
stopPropagation: () => {},
|
|
941
|
-
type: eventName,
|
|
942
|
-
target: element,
|
|
943
|
-
};
|
|
976
|
+
/**
|
|
977
|
+
*
|
|
978
|
+
* @param {Element} element
|
|
979
|
+
* @param {string|string[]} name
|
|
980
|
+
* @param {any} [value]
|
|
981
|
+
* @returns
|
|
982
|
+
*/
|
|
983
|
+
function getInheritedData(element, name, value) {
|
|
984
|
+
// if element is the document object work with the html element instead
|
|
985
|
+
// this makes $(document).scope() possible
|
|
986
|
+
if (element.nodeType === Node.DOCUMENT_NODE) {
|
|
987
|
+
// TODO Fix types
|
|
988
|
+
element = element.documentElement;
|
|
989
|
+
}
|
|
990
|
+
const names = Array.isArray(name) ? name : [name];
|
|
944
991
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
992
|
+
while (element) {
|
|
993
|
+
for (let i = 0, ii = names.length; i < ii; i++) {
|
|
994
|
+
if (isDefined((value = getOrSetCacheData(element, names[i]))))
|
|
995
|
+
return value;
|
|
996
|
+
}
|
|
949
997
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
998
|
+
// If dealing with a document fragment node with a host element, and no parent, use the host
|
|
999
|
+
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
|
|
1000
|
+
// to lookup parent controllers.
|
|
1001
|
+
element =
|
|
1002
|
+
element.parentNode ||
|
|
1003
|
+
(element.nodeType === Node.DOCUMENT_FRAGMENT_NODE && element.host);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
955
1006
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
(
|
|
965
|
-
|
|
966
|
-
* chaining functions
|
|
967
|
-
*/
|
|
968
|
-
JQLite.prototype[name] = function (arg1, arg2, arg3) {
|
|
969
|
-
let value;
|
|
1007
|
+
/**
|
|
1008
|
+
*
|
|
1009
|
+
* @param {Element} element
|
|
1010
|
+
* @param {boolean} keepData
|
|
1011
|
+
*/
|
|
1012
|
+
export function removeElement(element, keepData = false) {
|
|
1013
|
+
if (!keepData) dealoc(element);
|
|
1014
|
+
const parent = element.parentNode;
|
|
1015
|
+
if (parent) parent.removeChild(element);
|
|
1016
|
+
}
|
|
970
1017
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
);
|
|
1018
|
+
/**
|
|
1019
|
+
* Executea a function on `DOMContentLoaded`
|
|
1020
|
+
* @param {Function} fn
|
|
1021
|
+
*/
|
|
1022
|
+
function onReady(fn) {
|
|
1023
|
+
function trigger() {
|
|
1024
|
+
window.document.removeEventListener("DOMContentLoaded", trigger);
|
|
1025
|
+
fn();
|
|
1026
|
+
}
|
|
1027
|
+
// check if document is already loaded
|
|
1028
|
+
if (window.document.readyState === "complete") {
|
|
1029
|
+
window.setTimeout(fn);
|
|
1030
|
+
} else {
|
|
1031
|
+
// We can not use JQLite since we are not done loading.
|
|
1032
|
+
window.document.addEventListener("DOMContentLoaded", trigger);
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
986
1035
|
|
|
987
1036
|
function createEventHandler(element, events) {
|
|
988
1037
|
const eventHandler = function (event, type) {
|
|
@@ -1102,3 +1151,27 @@ export function getBlockNodes(nodes) {
|
|
|
1102
1151
|
|
|
1103
1152
|
return JQLite(blockNodes || nodes);
|
|
1104
1153
|
}
|
|
1154
|
+
|
|
1155
|
+
export function getBooleanAttrName(element, name) {
|
|
1156
|
+
// check dom last since we will most likely fail on name
|
|
1157
|
+
const booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
|
|
1158
|
+
|
|
1159
|
+
// booleanAttr is here twice to minimize DOM access
|
|
1160
|
+
return booleanAttr && BOOLEAN_ELEMENTS[getNodeName(element)] && booleanAttr;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Takes an array of elements, calls any `$destroy` event handlers, removes any data in cache, and finally removes any
|
|
1165
|
+
* listeners.
|
|
1166
|
+
* @param {NodeListOf<Element>|Element[]} nodes
|
|
1167
|
+
*/
|
|
1168
|
+
export function cleanElementData(nodes) {
|
|
1169
|
+
for (let i = 0, ii = nodes.length; i < ii; i++) {
|
|
1170
|
+
var events = (CACHE.get(nodes[i][EXPANDO]) || {}).events;
|
|
1171
|
+
if (events && events.$destroy) {
|
|
1172
|
+
JQLite(nodes[i]).triggerHandler("$destroy");
|
|
1173
|
+
}
|
|
1174
|
+
removeElementData(nodes[i]);
|
|
1175
|
+
JQLite.prototype.off.call(JQLite(nodes[i]));
|
|
1176
|
+
}
|
|
1177
|
+
}
|