@angular-wave/angular.ts 0.0.70 → 0.0.71

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@angular-wave/angular.ts",
3
3
  "description": "A modern, optimized and typesafe version of AngularJS",
4
4
  "license": "MIT",
5
- "version": "0.0.70",
5
+ "version": "0.0.71",
6
6
  "type": "module",
7
7
  "main": "dist/angular-ts.esm.js",
8
8
  "browser": "dist/angular-ts.umd.js",
@@ -119,18 +119,23 @@ export function removeFromArray(arr, val) {
119
119
  }
120
120
  }
121
121
 
122
+ /**
123
+ *
124
+ * @param {JQLite|Node} element
125
+ * @returns {JQLite}
126
+ */
122
127
  export function stripCommentsFromElement(element) {
123
128
  if (element instanceof JQLite) {
124
129
  switch (element.length) {
125
130
  case 0:
126
- return element;
131
+ return /** @type {JQLite} */ (element);
127
132
 
128
133
  case 1:
129
134
  // there is no point of stripping anything if the element
130
135
  // is the only element within the JQLite wrapper.
131
136
  // (it's important that we retain the element instance.)
132
137
  if (element[0].nodeType === Node.ELEMENT_NODE) {
133
- return element;
138
+ return /** @type {JQLite} */ (element);
134
139
  }
135
140
  break;
136
141
 
@@ -139,14 +144,18 @@ export function stripCommentsFromElement(element) {
139
144
  }
140
145
  }
141
146
 
142
- if (element.nodeType === Node.ELEMENT_NODE) {
147
+ if (/** @type {Node} */ (element).nodeType === Node.ELEMENT_NODE) {
143
148
  return JQLite(element);
144
149
  }
145
150
  }
146
151
 
152
+ /**
153
+ * @param {JQLite|Node} element
154
+ * @returns {Node}
155
+ */
147
156
  export function extractElementNode(element) {
148
- if (!element[0]) return element;
149
- for (let i = 0; i < element.length; i++) {
157
+ if (!element[0]) return /** @type {Node} */ (element);
158
+ for (let i = 0; i < /** @type {JQLite} */ (element).length; i++) {
150
159
  const elm = element[i];
151
160
  if (elm.nodeType === Node.ELEMENT_NODE) {
152
161
  return elm;
@@ -0,0 +1,326 @@
1
+ import { getBooleanAttrName } from "../../shared/jqlite/jqlite";
2
+ import {
3
+ forEach,
4
+ isString,
5
+ snakeCase,
6
+ isUndefined,
7
+ arrayRemove,
8
+ minErr,
9
+ trim,
10
+ directiveNormalize,
11
+ } from "../../shared/utils";
12
+ import { ALIASED_ATTR } from "../../shared/constants";
13
+
14
+ const $compileMinErr = minErr("$compile");
15
+ const SIMPLE_ATTR_NAME = /^\w/;
16
+ const specialAttrHolder = window.document.createElement("div");
17
+
18
+ export class Attributes {
19
+ /**
20
+ *
21
+ * @param {import('../scope/scope').Scope} $rootScope
22
+ * @param {*} $animate
23
+ * @param {import("../exception-handler").ExceptionHandlerProvider} $exceptionHandler
24
+ * @param {*} $sce
25
+ * @param {import('../../shared/jqlite/jqlite').JQLite} [element]
26
+ * @param {*} [attributesToCopy]
27
+ */
28
+ constructor(
29
+ $rootScope,
30
+ $animate,
31
+ $exceptionHandler,
32
+ $sce,
33
+ element,
34
+ attributesToCopy,
35
+ ) {
36
+ this.$rootScope = $rootScope;
37
+ this.$animate = $animate;
38
+ this.$exceptionHandler = $exceptionHandler;
39
+ this.$sce = $sce;
40
+ if (attributesToCopy) {
41
+ const keys = Object.keys(attributesToCopy);
42
+ for (let i = 0, l = keys.length; i < l; i++) {
43
+ const key = keys[i];
44
+ this[key] = attributesToCopy[key];
45
+ }
46
+ } else {
47
+ this.$attr = {};
48
+ }
49
+ this.$$element = element;
50
+ }
51
+
52
+ /**
53
+ * @ngdoc method
54
+ * @name $compile.directive.Attributes#$normalize
55
+ * @kind function
56
+ *
57
+ * @description
58
+ * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
59
+ * `data-`) to its normalized, camelCase form.
60
+ *
61
+ * Also there is special case for Moz prefix starting with upper case letter.
62
+ *
63
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
64
+ *
65
+ * @param {string} name Name to normalize
66
+ */
67
+ $normalize = directiveNormalize;
68
+
69
+ /**
70
+ * @ngdoc method
71
+ * @name $compile.directive.Attributes#$addClass
72
+ * @kind function
73
+ *
74
+ * @description
75
+ * Adds the CSS class value specified by the classVal parameter to the element. If animations
76
+ * are enabled then an animation will be triggered for the class addition.
77
+ *
78
+ * @param {string} classVal The className value that will be added to the element
79
+ */
80
+ $addClass(classVal) {
81
+ if (classVal && classVal.length > 0) {
82
+ this.$animate.addClass(this.$$element, classVal);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * @ngdoc method
88
+ * @name $compile.directive.Attributes#$removeClass
89
+ * @kind function
90
+ *
91
+ * @description
92
+ * Removes the CSS class value specified by the classVal parameter from the element. If
93
+ * animations are enabled then an animation will be triggered for the class removal.
94
+ *
95
+ * @param {string} classVal The className value that will be removed from the element
96
+ */
97
+ $removeClass(classVal) {
98
+ if (classVal && classVal.length > 0) {
99
+ this.$animate.removeClass(this.$$element, classVal);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * @ngdoc method
105
+ * @name $compile.directive.Attributes#$updateClass
106
+ * @kind function
107
+ *
108
+ * @description
109
+ * Adds and removes the appropriate CSS class values to the element based on the difference
110
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
111
+ *
112
+ * @param {string} newClasses The current CSS className value
113
+ * @param {string} oldClasses The former CSS className value
114
+ */
115
+ $updateClass(newClasses, oldClasses) {
116
+ const toAdd = tokenDifference(newClasses, oldClasses);
117
+ if (toAdd && toAdd.length) {
118
+ this.$animate.addClass(this.$$element, toAdd);
119
+ }
120
+
121
+ const toRemove = tokenDifference(oldClasses, newClasses);
122
+ if (toRemove && toRemove.length) {
123
+ this.$animate.removeClass(this.$$element, toRemove);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Set a normalized attribute on the element in a way such that all directives
129
+ * can share the attribute. This function properly handles boolean attributes.
130
+ * @param {string} key Normalized key. (ie ngAttribute)
131
+ * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
132
+ * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
133
+ * Defaults to true.
134
+ * @param {string=} attrName Optional none normalized name. Defaults to key.
135
+ */
136
+ $set(key, value, writeAttr, attrName) {
137
+ // TODO: decide whether or not to throw an error if "class"
138
+ // is set through this function since it may cause $updateClass to
139
+ // become unstable.
140
+
141
+ const node = this.$$element[0];
142
+ const booleanKey = getBooleanAttrName(node, key);
143
+ const aliasedKey = ALIASED_ATTR[key];
144
+ let observer = key;
145
+
146
+ if (booleanKey) {
147
+ this.$$element[0][key] = value;
148
+ attrName = booleanKey;
149
+ } else if (aliasedKey) {
150
+ this[aliasedKey] = value;
151
+ observer = aliasedKey;
152
+ }
153
+
154
+ this[key] = value;
155
+
156
+ // translate normalized key to actual key
157
+ if (attrName) {
158
+ this.$attr[key] = attrName;
159
+ } else {
160
+ attrName = this.$attr[key];
161
+ if (!attrName) {
162
+ this.$attr[key] = attrName = snakeCase(key, "-");
163
+ }
164
+ }
165
+
166
+ let nodeName = this.$$element[0].nodeName.toLowerCase();
167
+
168
+ // Sanitize img[srcset] values.
169
+ if (nodeName === "img" && key === "srcset") {
170
+ this[key] = value = this.sanitizeSrcset(value, "$set('srcset', value)");
171
+ }
172
+
173
+ if (writeAttr !== false) {
174
+ if (value === null || isUndefined(value)) {
175
+ this.$$element[0].removeAttribute(attrName);
176
+ //
177
+ } else if (SIMPLE_ATTR_NAME.test(attrName)) {
178
+ // jQuery skips special boolean attrs treatment in XML nodes for
179
+ // historical reasons and hence AngularJS cannot freely call
180
+ // `.attr(attrName, false) with such attributes. To avoid issues
181
+ // in XHTML, call `removeAttr` in such cases instead.
182
+ // See https://github.com/jquery/jquery/issues/4249
183
+ if (booleanKey && value === false) {
184
+ this.$$element[0].removeAttribute(attrName);
185
+ } else {
186
+ this.$$element.attr(attrName, value);
187
+ }
188
+ } else {
189
+ this.setSpecialAttr(this.$$element[0], attrName, value);
190
+ }
191
+ }
192
+
193
+ // fire observers
194
+ const { $$observers } = this;
195
+ if ($$observers) {
196
+ forEach($$observers[observer], (fn) => {
197
+ try {
198
+ fn(value);
199
+ } catch (e) {
200
+ this.$exceptionHandler(e);
201
+ }
202
+ });
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Observes an interpolated attribute.
208
+ *
209
+ * The observer function will be invoked once during the next `$digest` following
210
+ * compilation. The observer is then invoked whenever the interpolated value
211
+ * changes.
212
+ *
213
+ * @param {string} key Normalized key. (ie ngAttribute) .
214
+ * @param {any} fn Function that will be called whenever
215
+ the interpolated value of the attribute changes.
216
+ * See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
217
+ * guide} for more info.
218
+ * @returns {function()} Returns a deregistration function for this observer.
219
+ */
220
+ $observe(key, fn) {
221
+ const $$observers =
222
+ this.$$observers || (this.$$observers = Object.create(null));
223
+ const listeners = $$observers[key] || ($$observers[key] = []);
224
+
225
+ listeners.push(fn);
226
+ this.$rootScope.$evalAsync(() => {
227
+ if (
228
+ !listeners.$$inter &&
229
+ Object.prototype.hasOwnProperty.call(this, key) &&
230
+ !isUndefined(this[key])
231
+ ) {
232
+ // no one registered attribute interpolation function, so lets call it manually
233
+ fn(this[key]);
234
+ }
235
+ });
236
+
237
+ return function () {
238
+ arrayRemove(listeners, fn);
239
+ };
240
+ }
241
+
242
+ setSpecialAttr(element, attrName, value) {
243
+ // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
244
+ // so we have to jump through some hoops to get such an attribute
245
+ // https://github.com/angular/angular.js/pull/13318
246
+ specialAttrHolder.innerHTML = `<span ${attrName}>`;
247
+ const { attributes } = /** @type {Element} */ (
248
+ specialAttrHolder.firstChild
249
+ );
250
+ const attribute = attributes[0];
251
+ // We have to remove the attribute from its container element before we can add it to the destination element
252
+ attributes.removeNamedItem(attribute.name);
253
+ attribute.value = value;
254
+ element.attributes.setNamedItem(attribute);
255
+ }
256
+
257
+ sanitizeSrcset(value, invokeType) {
258
+ if (!value) {
259
+ return value;
260
+ }
261
+ if (!isString(value)) {
262
+ throw $compileMinErr(
263
+ "srcset",
264
+ 'Can\'t pass trusted values to `{0}`: "{1}"',
265
+ invokeType,
266
+ value.toString(),
267
+ );
268
+ }
269
+
270
+ // Such values are a bit too complex to handle automatically inside $sce.
271
+ // Instead, we sanitize each of the URIs individually, which works, even dynamically.
272
+
273
+ // It's not possible to work around this using `$sce.trustAsMediaUrl`.
274
+ // If you want to programmatically set explicitly trusted unsafe URLs, you should use
275
+ // `$sce.trustAsHtml` on the whole `img` tag and inject it into the DOM using the
276
+ // `ng-bind-html` directive.
277
+
278
+ var result = "";
279
+
280
+ // first check if there are spaces because it's not the same pattern
281
+ var trimmedSrcset = trim(value);
282
+ // ( 999x ,| 999w ,| ,|, )
283
+ var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
284
+ var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
285
+
286
+ // split srcset into tuple of uri and descriptor except for the last item
287
+ var rawUris = trimmedSrcset.split(pattern);
288
+
289
+ // for each tuples
290
+ var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
291
+ for (var i = 0; i < nbrUrisWith2parts; i++) {
292
+ var innerIdx = i * 2;
293
+ // sanitize the uri
294
+ result += this.$sce.getTrustedMediaUrl(trim(rawUris[innerIdx]));
295
+ // add the descriptor
296
+ result += " " + trim(rawUris[innerIdx + 1]);
297
+ }
298
+
299
+ // split the last item into uri and descriptor
300
+ var lastTuple = trim(rawUris[i * 2]).split(/\s/);
301
+
302
+ // sanitize the last uri
303
+ result += this.$sce.getTrustedMediaUrl(trim(lastTuple[0]));
304
+
305
+ // and add the last descriptor if any
306
+ if (lastTuple.length === 2) {
307
+ result += " " + trim(lastTuple[1]);
308
+ }
309
+ return result;
310
+ }
311
+ }
312
+
313
+ function tokenDifference(str1, str2) {
314
+ let values = "";
315
+ const tokens1 = str1.split(/\s+/);
316
+ const tokens2 = str2.split(/\s+/);
317
+
318
+ outer: for (let i = 0; i < tokens1.length; i++) {
319
+ const token = tokens1[i];
320
+ for (let j = 0; j < tokens2.length; j++) {
321
+ if (token === tokens2[j]) continue outer;
322
+ }
323
+ values += (values.length > 0 ? " " : "") + token;
324
+ }
325
+ return values;
326
+ }