@angular-wave/angular.ts 0.0.1

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 (231) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.cjs +29 -0
  3. package/.github/workflows/playwright.yml +27 -0
  4. package/CHANGELOG.md +17974 -0
  5. package/CODE_OF_CONDUCT.md +3 -0
  6. package/CONTRIBUTING.md +246 -0
  7. package/DEVELOPERS.md +488 -0
  8. package/LICENSE +22 -0
  9. package/Makefile +31 -0
  10. package/README.md +115 -0
  11. package/RELEASE.md +98 -0
  12. package/SECURITY.md +16 -0
  13. package/TRIAGING.md +135 -0
  14. package/css/angular.css +22 -0
  15. package/dist/angular-ts.cjs.js +36843 -0
  16. package/dist/angular-ts.esm.js +36841 -0
  17. package/dist/angular-ts.umd.js +36848 -0
  18. package/dist/build/angular-animate.js +4272 -0
  19. package/dist/build/angular-aria.js +426 -0
  20. package/dist/build/angular-message-format.js +1072 -0
  21. package/dist/build/angular-messages.js +829 -0
  22. package/dist/build/angular-mocks.js +3757 -0
  23. package/dist/build/angular-parse-ext.js +1275 -0
  24. package/dist/build/angular-resource.js +911 -0
  25. package/dist/build/angular-route.js +1266 -0
  26. package/dist/build/angular-sanitize.js +891 -0
  27. package/dist/build/angular-touch.js +368 -0
  28. package/dist/build/angular.js +36600 -0
  29. package/e2e/unit.spec.ts +15 -0
  30. package/images/android-chrome-192x192.png +0 -0
  31. package/images/android-chrome-512x512.png +0 -0
  32. package/images/apple-touch-icon.png +0 -0
  33. package/images/favicon-16x16.png +0 -0
  34. package/images/favicon-32x32.png +0 -0
  35. package/images/favicon.ico +0 -0
  36. package/images/site.webmanifest +1 -0
  37. package/index.html +104 -0
  38. package/package.json +47 -0
  39. package/playwright.config.ts +78 -0
  40. package/public/circle.html +1 -0
  41. package/public/my_child_directive.html +1 -0
  42. package/public/my_directive.html +1 -0
  43. package/public/my_other_directive.html +1 -0
  44. package/public/test.html +1 -0
  45. package/rollup.config.js +31 -0
  46. package/src/animations/animateCache.js +55 -0
  47. package/src/animations/animateChildrenDirective.js +105 -0
  48. package/src/animations/animateCss.js +1139 -0
  49. package/src/animations/animateCssDriver.js +291 -0
  50. package/src/animations/animateJs.js +367 -0
  51. package/src/animations/animateJsDriver.js +67 -0
  52. package/src/animations/animateQueue.js +851 -0
  53. package/src/animations/animation.js +506 -0
  54. package/src/animations/module.js +779 -0
  55. package/src/animations/ngAnimateSwap.js +119 -0
  56. package/src/animations/rafScheduler.js +50 -0
  57. package/src/animations/shared.js +378 -0
  58. package/src/constants.js +20 -0
  59. package/src/core/animate.js +845 -0
  60. package/src/core/animateCss.js +73 -0
  61. package/src/core/animateRunner.js +195 -0
  62. package/src/core/attributes.js +199 -0
  63. package/src/core/cache.js +45 -0
  64. package/src/core/compile.js +4727 -0
  65. package/src/core/controller.js +225 -0
  66. package/src/core/exceptionHandler.js +63 -0
  67. package/src/core/filter.js +146 -0
  68. package/src/core/interpolate.js +442 -0
  69. package/src/core/interval.js +188 -0
  70. package/src/core/intervalFactory.js +57 -0
  71. package/src/core/location.js +1086 -0
  72. package/src/core/parser/parse.js +2562 -0
  73. package/src/core/parser/parse.md +13 -0
  74. package/src/core/q.js +746 -0
  75. package/src/core/rootScope.js +1596 -0
  76. package/src/core/sanitizeUri.js +85 -0
  77. package/src/core/sce.js +1161 -0
  78. package/src/core/taskTrackerFactory.js +125 -0
  79. package/src/core/timeout.js +121 -0
  80. package/src/core/urlUtils.js +187 -0
  81. package/src/core/utils.js +1349 -0
  82. package/src/directive/a.js +37 -0
  83. package/src/directive/attrs.js +283 -0
  84. package/src/directive/bind.js +51 -0
  85. package/src/directive/bind.md +142 -0
  86. package/src/directive/change.js +12 -0
  87. package/src/directive/change.md +25 -0
  88. package/src/directive/cloak.js +12 -0
  89. package/src/directive/cloak.md +24 -0
  90. package/src/directive/events.js +75 -0
  91. package/src/directive/events.md +166 -0
  92. package/src/directive/form.js +725 -0
  93. package/src/directive/init.js +15 -0
  94. package/src/directive/init.md +41 -0
  95. package/src/directive/input.js +1783 -0
  96. package/src/directive/list.js +46 -0
  97. package/src/directive/list.md +22 -0
  98. package/src/directive/ngClass.js +249 -0
  99. package/src/directive/ngController.js +64 -0
  100. package/src/directive/ngCsp.js +82 -0
  101. package/src/directive/ngIf.js +134 -0
  102. package/src/directive/ngInclude.js +217 -0
  103. package/src/directive/ngModel.js +1356 -0
  104. package/src/directive/ngModelOptions.js +509 -0
  105. package/src/directive/ngOptions.js +670 -0
  106. package/src/directive/ngRef.js +90 -0
  107. package/src/directive/ngRepeat.js +650 -0
  108. package/src/directive/ngShowHide.js +255 -0
  109. package/src/directive/ngSwitch.js +178 -0
  110. package/src/directive/ngTransclude.js +98 -0
  111. package/src/directive/non-bindable.js +11 -0
  112. package/src/directive/non-bindable.md +17 -0
  113. package/src/directive/script.js +30 -0
  114. package/src/directive/select.js +624 -0
  115. package/src/directive/style.js +25 -0
  116. package/src/directive/style.md +23 -0
  117. package/src/directive/validators.js +329 -0
  118. package/src/exts/aria.js +544 -0
  119. package/src/exts/messages.js +852 -0
  120. package/src/filters/filter.js +207 -0
  121. package/src/filters/filter.md +69 -0
  122. package/src/filters/filters.js +239 -0
  123. package/src/filters/json.md +16 -0
  124. package/src/filters/limit-to.js +43 -0
  125. package/src/filters/limit-to.md +19 -0
  126. package/src/filters/order-by.js +183 -0
  127. package/src/filters/order-by.md +83 -0
  128. package/src/index.js +13 -0
  129. package/src/injector.js +1034 -0
  130. package/src/jqLite.js +1117 -0
  131. package/src/loader.js +1320 -0
  132. package/src/public.js +215 -0
  133. package/src/routeToRegExp.js +41 -0
  134. package/src/services/anchorScroll.js +135 -0
  135. package/src/services/browser.js +321 -0
  136. package/src/services/cacheFactory.js +398 -0
  137. package/src/services/cookieReader.js +72 -0
  138. package/src/services/document.js +64 -0
  139. package/src/services/http.js +1537 -0
  140. package/src/services/httpBackend.js +206 -0
  141. package/src/services/log.js +160 -0
  142. package/src/services/templateRequest.js +139 -0
  143. package/test/angular.spec.js +2153 -0
  144. package/test/aria/aria.spec.js +1245 -0
  145. package/test/binding.spec.js +504 -0
  146. package/test/build-test.html +14 -0
  147. package/test/injector.spec.js +2327 -0
  148. package/test/jasmine/jasmine-5.1.2/boot0.js +65 -0
  149. package/test/jasmine/jasmine-5.1.2/boot1.js +133 -0
  150. package/test/jasmine/jasmine-5.1.2/jasmine-html.js +963 -0
  151. package/test/jasmine/jasmine-5.1.2/jasmine.css +320 -0
  152. package/test/jasmine/jasmine-5.1.2/jasmine.js +10824 -0
  153. package/test/jasmine/jasmine-5.1.2/jasmine_favicon.png +0 -0
  154. package/test/jasmine/jasmine-browser.json +17 -0
  155. package/test/jasmine/jasmine.json +9 -0
  156. package/test/jqlite.spec.js +2133 -0
  157. package/test/loader.spec.js +219 -0
  158. package/test/messages/messages.spec.js +1146 -0
  159. package/test/min-err.spec.js +174 -0
  160. package/test/mock-test.html +13 -0
  161. package/test/module-test.html +15 -0
  162. package/test/ng/anomate.spec.js +606 -0
  163. package/test/ng/cache-factor.spec.js +334 -0
  164. package/test/ng/compile.spec.js +17956 -0
  165. package/test/ng/controller-provider.spec.js +227 -0
  166. package/test/ng/cookie-reader.spec.js +98 -0
  167. package/test/ng/directive/a.spec.js +192 -0
  168. package/test/ng/directive/bind.spec.js +334 -0
  169. package/test/ng/directive/boolean.spec.js +136 -0
  170. package/test/ng/directive/change.spec.js +71 -0
  171. package/test/ng/directive/class.spec.js +858 -0
  172. package/test/ng/directive/click.spec.js +38 -0
  173. package/test/ng/directive/cloak.spec.js +44 -0
  174. package/test/ng/directive/constoller.spec.js +194 -0
  175. package/test/ng/directive/element-style.spec.js +92 -0
  176. package/test/ng/directive/event.spec.js +282 -0
  177. package/test/ng/directive/form.spec.js +1518 -0
  178. package/test/ng/directive/href.spec.js +143 -0
  179. package/test/ng/directive/if.spec.js +402 -0
  180. package/test/ng/directive/include.spec.js +828 -0
  181. package/test/ng/directive/init.spec.js +68 -0
  182. package/test/ng/directive/input.spec.js +3810 -0
  183. package/test/ng/directive/list.spec.js +170 -0
  184. package/test/ng/directive/model-options.spec.js +1008 -0
  185. package/test/ng/directive/model.spec.js +1905 -0
  186. package/test/ng/directive/non-bindable.spec.js +55 -0
  187. package/test/ng/directive/options.spec.js +3583 -0
  188. package/test/ng/directive/ref.spec.js +575 -0
  189. package/test/ng/directive/repeat.spec.js +1675 -0
  190. package/test/ng/directive/script.spec.js +52 -0
  191. package/test/ng/directive/scrset.spec.js +67 -0
  192. package/test/ng/directive/select.spec.js +2541 -0
  193. package/test/ng/directive/show-hide.spec.js +253 -0
  194. package/test/ng/directive/src.spec.js +157 -0
  195. package/test/ng/directive/style.spec.js +178 -0
  196. package/test/ng/directive/switch.spec.js +647 -0
  197. package/test/ng/directive/validators.spec.js +717 -0
  198. package/test/ng/document.spec.js +52 -0
  199. package/test/ng/filter/filter.spec.js +714 -0
  200. package/test/ng/filter/filters.spec.js +35 -0
  201. package/test/ng/filter/limit-to.spec.js +251 -0
  202. package/test/ng/filter/order-by.spec.js +891 -0
  203. package/test/ng/filter.spec.js +149 -0
  204. package/test/ng/http-backend.spec.js +398 -0
  205. package/test/ng/http.spec.js +4071 -0
  206. package/test/ng/interpolate.spec.js +642 -0
  207. package/test/ng/interval.spec.js +343 -0
  208. package/test/ng/location.spec.js +3488 -0
  209. package/test/ng/on.spec.js +229 -0
  210. package/test/ng/parse.spec.js +4655 -0
  211. package/test/ng/prop.spec.js +805 -0
  212. package/test/ng/q.spec.js +2904 -0
  213. package/test/ng/root-element.spec.js +16 -0
  214. package/test/ng/sanitize-uri.spec.js +249 -0
  215. package/test/ng/sce.spec.js +660 -0
  216. package/test/ng/scope.spec.js +3442 -0
  217. package/test/ng/template-request.spec.js +236 -0
  218. package/test/ng/timeout.spec.js +351 -0
  219. package/test/ng/url-utils.spec.js +156 -0
  220. package/test/ng/utils.spec.js +144 -0
  221. package/test/original-test.html +21 -0
  222. package/test/public.spec.js +34 -0
  223. package/test/sanitize/bing-html.spec.js +36 -0
  224. package/test/server/express.js +158 -0
  225. package/test/test-utils.js +11 -0
  226. package/tsconfig.json +17 -0
  227. package/types/angular.d.ts +138 -0
  228. package/types/global.d.ts +9 -0
  229. package/types/index.d.ts +2357 -0
  230. package/types/jqlite.d.ts +558 -0
  231. package/vite.config.js +14 -0
@@ -0,0 +1,624 @@
1
+ import { jqLite } from "../jqLite";
2
+ import {
3
+ assertNotHasOwnProperty,
4
+ equals,
5
+ hashKey,
6
+ includes,
7
+ isDefined,
8
+ shallowCopy,
9
+ } from "../core/utils";
10
+
11
+ const noopNgModelController = { $setViewValue: () => {}, $render: () => {} };
12
+
13
+ function setOptionSelectedStatus(optionEl, value) {
14
+ optionEl.prop("selected", value);
15
+ /**
16
+ * When unselecting an option, setting the property to null / false should be enough
17
+ * However, screenreaders might react to the selected attribute instead, see
18
+ * https://github.com/angular/angular.js/issues/14419
19
+ * Note: "selected" is a boolean attr and will be removed when the "value" arg in attr() is false
20
+ * or null
21
+ */
22
+ optionEl.attr("selected", value);
23
+ }
24
+
25
+ /**
26
+ * @ngdoc type
27
+ * @name select.SelectController
28
+ *
29
+ * @description
30
+ * The controller for the {@link ng.select select} directive. The controller exposes
31
+ * a few utility methods that can be used to augment the behavior of a regular or an
32
+ * {@link ng.ngOptions ngOptions} select element.
33
+ *
34
+ */
35
+ var SelectController = [
36
+ "$element",
37
+ "$scope",
38
+ function ($element, $scope) {
39
+ const self = this;
40
+ const optionsMap = new Map();
41
+
42
+ self.selectValueMap = {}; // Keys are the hashed values, values the original values
43
+
44
+ // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
45
+ self.ngModelCtrl = noopNgModelController;
46
+ self.multiple = false;
47
+
48
+ // The "unknown" option is one that is prepended to the list if the viewValue
49
+ // does not match any of the options. When it is rendered the value of the unknown
50
+ // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
51
+ //
52
+ // Support: IE 9 only
53
+ // We can't just jqLite('<option>') since jqLite is not smart enough
54
+ // to create it in <select> and IE barfs otherwise.
55
+ self.unknownOption = jqLite(window.document.createElement("option"));
56
+
57
+ // The empty option is an option with the value '' that the application developer can
58
+ // provide inside the select. It is always selectable and indicates that a "null" selection has
59
+ // been made by the user.
60
+ // If the select has an empty option, and the model of the select is set to "undefined" or "null",
61
+ // the empty option is selected.
62
+ // If the model is set to a different unmatched value, the unknown option is rendered and
63
+ // selected, i.e both are present, because a "null" selection and an unknown value are different.
64
+ self.hasEmptyOption = false;
65
+ self.emptyOption = undefined;
66
+
67
+ self.renderUnknownOption = function (val) {
68
+ const unknownVal = self.generateUnknownOptionValue(val);
69
+ self.unknownOption.val(unknownVal);
70
+ $element.prepend(self.unknownOption);
71
+ setOptionSelectedStatus(self.unknownOption, true);
72
+ $element.val(unknownVal);
73
+ };
74
+
75
+ self.updateUnknownOption = function (val) {
76
+ const unknownVal = self.generateUnknownOptionValue(val);
77
+ self.unknownOption.val(unknownVal);
78
+ setOptionSelectedStatus(self.unknownOption, true);
79
+ $element.val(unknownVal);
80
+ };
81
+
82
+ self.generateUnknownOptionValue = function (val) {
83
+ return `? ${hashKey(val)} ?`;
84
+ };
85
+
86
+ self.removeUnknownOption = function () {
87
+ if (self.unknownOption.parent()) self.unknownOption.remove();
88
+ };
89
+
90
+ self.selectEmptyOption = function () {
91
+ if (self.emptyOption) {
92
+ $element.val("");
93
+ setOptionSelectedStatus(self.emptyOption, true);
94
+ }
95
+ };
96
+
97
+ self.unselectEmptyOption = function () {
98
+ if (self.hasEmptyOption) {
99
+ setOptionSelectedStatus(self.emptyOption, false);
100
+ }
101
+ };
102
+
103
+ $scope.$on("$destroy", () => {
104
+ // disable unknown option so that we don't do work when the whole select is being destroyed
105
+ self.renderUnknownOption = () => {};
106
+ });
107
+
108
+ // Read the value of the select control, the implementation of this changes depending
109
+ // upon whether the select can have multiple values and whether ngOptions is at work.
110
+ self.readValue = function readSingleValue() {
111
+ const val = $element.val();
112
+ // ngValue added option values are stored in the selectValueMap, normal interpolations are not
113
+ const realVal =
114
+ val in self.selectValueMap ? self.selectValueMap[val] : val;
115
+
116
+ if (self.hasOption(realVal)) {
117
+ return realVal;
118
+ }
119
+
120
+ return null;
121
+ };
122
+
123
+ // Write the value to the select control, the implementation of this changes depending
124
+ // upon whether the select can have multiple values and whether ngOptions is at work.
125
+ self.writeValue = function writeSingleValue(value) {
126
+ // Make sure to remove the selected attribute from the previously selected option
127
+ // Otherwise, screen readers might get confused
128
+ const currentlySelectedOption =
129
+ $element[0].options[$element[0].selectedIndex];
130
+ if (currentlySelectedOption)
131
+ setOptionSelectedStatus(jqLite(currentlySelectedOption), false);
132
+
133
+ if (self.hasOption(value)) {
134
+ self.removeUnknownOption();
135
+
136
+ const hashedVal = hashKey(value);
137
+ $element.val(hashedVal in self.selectValueMap ? hashedVal : value);
138
+
139
+ // Set selected attribute and property on selected option for screen readers
140
+ const selectedOption = $element[0].options[$element[0].selectedIndex];
141
+ setOptionSelectedStatus(jqLite(selectedOption), true);
142
+ } else {
143
+ self.selectUnknownOrEmptyOption(value);
144
+ }
145
+ };
146
+
147
+ // Tell the select control that an option, with the given value, has been added
148
+ self.addOption = function (value, element) {
149
+ // Skip comment nodes, as they only pollute the `optionsMap`
150
+ if (element[0].nodeType === Node.COMMENT_NODE) return;
151
+
152
+ assertNotHasOwnProperty(value, '"option value"');
153
+ if (value === "") {
154
+ self.hasEmptyOption = true;
155
+ self.emptyOption = element;
156
+ }
157
+ const count = optionsMap.get(value) || 0;
158
+ optionsMap.set(value, count + 1);
159
+ // Only render at the end of a digest. This improves render performance when many options
160
+ // are added during a digest and ensures all relevant options are correctly marked as selected
161
+ scheduleRender();
162
+ };
163
+
164
+ // Tell the select control that an option, with the given value, has been removed
165
+ self.removeOption = function (value) {
166
+ const count = optionsMap.get(value);
167
+ if (count) {
168
+ if (count === 1) {
169
+ optionsMap.delete(value);
170
+ if (value === "") {
171
+ self.hasEmptyOption = false;
172
+ self.emptyOption = undefined;
173
+ }
174
+ } else {
175
+ optionsMap.set(value, count - 1);
176
+ }
177
+ }
178
+ };
179
+
180
+ // Check whether the select control has an option matching the given value
181
+ self.hasOption = function (value) {
182
+ return !!optionsMap.get(value);
183
+ };
184
+
185
+ /**
186
+ * @ngdoc method
187
+ * @name select.SelectController#$hasEmptyOption
188
+ *
189
+ * @description
190
+ *
191
+ * Returns `true` if the select element currently has an empty option
192
+ * element, i.e. an option that signifies that the select is empty / the selection is null.
193
+ *
194
+ */
195
+ self.$hasEmptyOption = function () {
196
+ return self.hasEmptyOption;
197
+ };
198
+
199
+ /**
200
+ * @ngdoc method
201
+ * @name select.SelectController#$isUnknownOptionSelected
202
+ *
203
+ * @description
204
+ *
205
+ * Returns `true` if the select element's unknown option is selected. The unknown option is added
206
+ * and automatically selected whenever the select model doesn't match any option.
207
+ *
208
+ */
209
+ self.$isUnknownOptionSelected = function () {
210
+ // Presence of the unknown option means it is selected
211
+ return $element[0].options[0] === self.unknownOption[0];
212
+ };
213
+
214
+ /**
215
+ * @ngdoc method
216
+ * @name select.SelectController#$isEmptyOptionSelected
217
+ *
218
+ * @description
219
+ *
220
+ * Returns `true` if the select element has an empty option and this empty option is currently
221
+ * selected. Returns `false` if the select element has no empty option or it is not selected.
222
+ *
223
+ */
224
+ self.$isEmptyOptionSelected = function () {
225
+ return (
226
+ self.hasEmptyOption &&
227
+ $element[0].options[$element[0].selectedIndex] === self.emptyOption[0]
228
+ );
229
+ };
230
+
231
+ self.selectUnknownOrEmptyOption = function (value) {
232
+ if (value == null && self.emptyOption) {
233
+ self.removeUnknownOption();
234
+ self.selectEmptyOption();
235
+ } else if (self.unknownOption.parent().length) {
236
+ self.updateUnknownOption(value);
237
+ } else {
238
+ self.renderUnknownOption(value);
239
+ }
240
+ };
241
+
242
+ let renderScheduled = false;
243
+ function scheduleRender() {
244
+ if (renderScheduled) return;
245
+ renderScheduled = true;
246
+ $scope.$$postDigest(() => {
247
+ renderScheduled = false;
248
+ self.ngModelCtrl.$render();
249
+ });
250
+ }
251
+
252
+ let updateScheduled = false;
253
+ function scheduleViewValueUpdate(renderAfter) {
254
+ if (updateScheduled) return;
255
+
256
+ updateScheduled = true;
257
+
258
+ $scope.$$postDigest(() => {
259
+ if ($scope.$$destroyed) return;
260
+
261
+ updateScheduled = false;
262
+ self.ngModelCtrl.$setViewValue(self.readValue());
263
+ if (renderAfter) self.ngModelCtrl.$render();
264
+ });
265
+ }
266
+
267
+ self.registerOption = function (
268
+ optionScope,
269
+ optionElement,
270
+ optionAttrs,
271
+ interpolateValueFn,
272
+ interpolateTextFn,
273
+ ) {
274
+ let oldVal;
275
+ let hashedVal;
276
+ if (optionAttrs.$attr.ngValue) {
277
+ // The value attribute is set by ngValue
278
+
279
+ optionAttrs.$observe("value", (newVal) => {
280
+ let removal;
281
+ const previouslySelected = optionElement.prop("selected");
282
+
283
+ if (isDefined(hashedVal)) {
284
+ self.removeOption(oldVal);
285
+ delete self.selectValueMap[hashedVal];
286
+ removal = true;
287
+ }
288
+
289
+ hashedVal = hashKey(newVal);
290
+ oldVal = newVal;
291
+ self.selectValueMap[hashedVal] = newVal;
292
+ self.addOption(newVal, optionElement);
293
+ // Set the attribute directly instead of using optionAttrs.$set - this stops the observer
294
+ // from firing a second time. Other $observers on value will also get the result of the
295
+ // ngValue expression, not the hashed value
296
+ optionElement.attr("value", hashedVal);
297
+
298
+ if (removal && previouslySelected) {
299
+ scheduleViewValueUpdate();
300
+ }
301
+ });
302
+ } else if (interpolateValueFn) {
303
+ // The value attribute is interpolated
304
+ optionAttrs.$observe("value", (newVal) => {
305
+ // This method is overwritten in ngOptions and has side-effects!
306
+ self.readValue();
307
+
308
+ let removal;
309
+ const previouslySelected = optionElement.prop("selected");
310
+
311
+ if (isDefined(oldVal)) {
312
+ self.removeOption(oldVal);
313
+ removal = true;
314
+ }
315
+ oldVal = newVal;
316
+ self.addOption(newVal, optionElement);
317
+
318
+ if (removal && previouslySelected) {
319
+ scheduleViewValueUpdate();
320
+ }
321
+ });
322
+ } else if (interpolateTextFn) {
323
+ // The text content is interpolated
324
+ optionScope.$watch(interpolateTextFn, (newVal, oldVal) => {
325
+ optionAttrs.$set("value", newVal);
326
+ const previouslySelected = optionElement.prop("selected");
327
+ if (oldVal !== newVal) {
328
+ self.removeOption(oldVal);
329
+ }
330
+ self.addOption(newVal, optionElement);
331
+
332
+ if (oldVal && previouslySelected) {
333
+ scheduleViewValueUpdate();
334
+ }
335
+ });
336
+ } else {
337
+ // The value attribute is static
338
+ self.addOption(optionAttrs.value, optionElement);
339
+ }
340
+
341
+ optionAttrs.$observe("disabled", (newVal) => {
342
+ // Since model updates will also select disabled options (like ngOptions),
343
+ // we only have to handle options becoming disabled, not enabled
344
+
345
+ if (newVal === "true" || (newVal && optionElement.prop("selected"))) {
346
+ if (self.multiple) {
347
+ scheduleViewValueUpdate(true);
348
+ } else {
349
+ self.ngModelCtrl.$setViewValue(null);
350
+ self.ngModelCtrl.$render();
351
+ }
352
+ }
353
+ });
354
+
355
+ optionElement.on("$destroy", () => {
356
+ const currentValue = self.readValue();
357
+ const removeValue = optionAttrs.value;
358
+
359
+ self.removeOption(removeValue);
360
+ scheduleRender();
361
+
362
+ if (
363
+ (self.multiple &&
364
+ currentValue &&
365
+ currentValue.indexOf(removeValue) !== -1) ||
366
+ currentValue === removeValue
367
+ ) {
368
+ // When multiple (selected) options are destroyed at the same time, we don't want
369
+ // to run a model update for each of them. Instead, run a single update in the $$postDigest
370
+ scheduleViewValueUpdate(true);
371
+ }
372
+ });
373
+ };
374
+ },
375
+ ];
376
+
377
+ /**
378
+ * @ngdoc directive
379
+ * @name select
380
+ * @restrict E
381
+ *
382
+ * @description
383
+ * HTML `select` element with AngularJS data-binding.
384
+ *
385
+ * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
386
+ * between the scope and the `<select>` control (including setting default values).
387
+ * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
388
+ * {@link ngOptions `ngOptions`} directives.
389
+ *
390
+ * When an item in the `<select>` menu is selected, the value of the selected option will be bound
391
+ * to the model identified by the `ngModel` directive. With static or repeated options, this is
392
+ * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
393
+ * Value and textContent can be interpolated.
394
+ *
395
+ * The {@link select.SelectController select controller} exposes utility functions that can be used
396
+ * to manipulate the select's behavior.
397
+ *
398
+ * ## Matching model and option values
399
+ *
400
+ * In general, the match between the model and an option is evaluated by strictly comparing the model
401
+ * value against the value of the available options.
402
+ *
403
+ * If you are setting the option value with the option's `value` attribute, or textContent, the
404
+ * value will always be a `string` which means that the model value must also be a string.
405
+ * Otherwise the `select` directive cannot match them correctly.
406
+ *
407
+ * To bind the model to a non-string value, you can use one of the following strategies:
408
+ * - the {@link ng.ngOptions `ngOptions`} directive
409
+ * ({@link ng.select#using-select-with-ngoptions-and-setting-a-default-value})
410
+ * - the {@link ng.ngValue `ngValue`} directive, which allows arbitrary expressions to be
411
+ * option values ({@link ng.select#using-ngvalue-to-bind-the-model-to-an-array-of-objects Example})
412
+ * - model $parsers / $formatters to convert the string value
413
+ * ({@link ng.select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting Example})
414
+ *
415
+ * If the viewValue of `ngModel` does not match any of the options, then the control
416
+ * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
417
+ *
418
+ * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
419
+ * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
420
+ * option. See example below for demonstration.
421
+ *
422
+ * ## Choosing between `ngRepeat` and `ngOptions`
423
+ *
424
+ * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
425
+ * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits:
426
+ * - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
427
+ * comprehension expression
428
+ * - reduced memory consumption by not creating a new scope for each repeated instance
429
+ * - increased render speed by creating the options in a documentFragment instead of individually
430
+ *
431
+ * Specifically, select with repeated options slows down significantly starting at 2000 options in
432
+ * Chrome and Internet Explorer / Edge.
433
+ *
434
+ *
435
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
436
+ * @param {string=} name Property name of the form under which the control is published.
437
+ * @param {string=} multiple Allows multiple options to be selected. The selected values will be
438
+ * bound to the model as an array.
439
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
440
+ * @param {string=} ngRequired Adds required attribute and required validation constraint to
441
+ * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
442
+ * when you want to data-bind to the required attribute.
443
+ * @param {string=} ngChange AngularJS expression to be executed when selected option(s) changes due to user
444
+ * interaction with the select element.
445
+ * @param {string=} ngOptions sets the options that the select is populated with and defines what is
446
+ * set on the model on selection. See {@link ngOptions `ngOptions`}.
447
+ * @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
448
+ * {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
449
+ *
450
+ */
451
+ export const selectDirective = function () {
452
+ return {
453
+ restrict: "E",
454
+ require: ["select", "?ngModel"],
455
+ controller: SelectController,
456
+ priority: 1,
457
+ link: {
458
+ pre: selectPreLink,
459
+ post: selectPostLink,
460
+ },
461
+ };
462
+
463
+ function selectPreLink(scope, element, attr, ctrls) {
464
+ const selectCtrl = ctrls[0];
465
+ const ngModelCtrl = ctrls[1];
466
+
467
+ // if ngModel is not defined, we don't need to do anything but set the registerOption
468
+ // function to noop, so options don't get added internally
469
+ if (!ngModelCtrl) {
470
+ selectCtrl.registerOption = () => {};
471
+ return;
472
+ }
473
+
474
+ selectCtrl.ngModelCtrl = ngModelCtrl;
475
+
476
+ // When the selected item(s) changes we delegate getting the value of the select control
477
+ // to the `readValue` method, which can be changed if the select can have multiple
478
+ // selected values or if the options are being generated by `ngOptions`
479
+ element.on("change", () => {
480
+ selectCtrl.removeUnknownOption();
481
+ scope.$apply(() => {
482
+ ngModelCtrl.$setViewValue(selectCtrl.readValue());
483
+ });
484
+ });
485
+
486
+ // If the select allows multiple values then we need to modify how we read and write
487
+ // values from and to the control; also what it means for the value to be empty and
488
+ // we have to add an extra watch since ngModel doesn't work well with arrays - it
489
+ // doesn't trigger rendering if only an item in the array changes.
490
+ if (attr.multiple) {
491
+ selectCtrl.multiple = true;
492
+
493
+ // Read value now needs to check each option to see if it is selected
494
+ selectCtrl.readValue = function readMultipleValue() {
495
+ const array = [];
496
+ Array.from(element[0].getElementsByTagName("option")).forEach(
497
+ (option) => {
498
+ if (option.selected && !option.disabled) {
499
+ const val = option.value;
500
+ array.push(
501
+ val in selectCtrl.selectValueMap
502
+ ? selectCtrl.selectValueMap[val]
503
+ : val,
504
+ );
505
+ }
506
+ },
507
+ );
508
+ return array;
509
+ };
510
+
511
+ // Write value now needs to set the selected property of each matching option
512
+ selectCtrl.writeValue = function writeMultipleValue(value) {
513
+ Array.from(element[0].getElementsByTagName("option")).forEach(
514
+ (option) => {
515
+ const shouldBeSelected =
516
+ !!value &&
517
+ (includes(value, option.value) ||
518
+ includes(value, selectCtrl.selectValueMap[option.value]));
519
+ const currentlySelected = option.selected;
520
+
521
+ // Support: IE 9-11 only, Edge 12-15+
522
+ // In IE and Edge adding options to the selection via shift+click/UP/DOWN
523
+ // will de-select already selected options if "selected" on those options was set
524
+ // more than once (i.e. when the options were already selected)
525
+ // So we only modify the selected property if necessary.
526
+ // Note: this behavior cannot be replicated via unit tests because it only shows in the
527
+ // actual user interface.
528
+ if (shouldBeSelected !== currentlySelected) {
529
+ setOptionSelectedStatus(jqLite(option), shouldBeSelected);
530
+ }
531
+ },
532
+ );
533
+ };
534
+
535
+ // we have to do it on each watch since ngModel watches reference, but
536
+ // we need to work of an array, so we need to see if anything was inserted/removed
537
+ let lastView;
538
+ let lastViewRef = NaN;
539
+ scope.$watch(() => {
540
+ if (
541
+ lastViewRef === ngModelCtrl.$viewValue &&
542
+ !equals(lastView, ngModelCtrl.$viewValue)
543
+ ) {
544
+ lastView = shallowCopy(ngModelCtrl.$viewValue);
545
+ ngModelCtrl.$render();
546
+ }
547
+ lastViewRef = ngModelCtrl.$viewValue;
548
+ });
549
+
550
+ // If we are a multiple select then value is now a collection
551
+ // so the meaning of $isEmpty changes
552
+ ngModelCtrl.$isEmpty = function (value) {
553
+ return !value || value.length === 0;
554
+ };
555
+ }
556
+ }
557
+
558
+ function selectPostLink(scope, element, attrs, ctrls) {
559
+ // if ngModel is not defined, we don't need to do anything
560
+ const ngModelCtrl = ctrls[1];
561
+ if (!ngModelCtrl) return;
562
+
563
+ const selectCtrl = ctrls[0];
564
+
565
+ // We delegate rendering to the `writeValue` method, which can be changed
566
+ // if the select can have multiple selected values or if the options are being
567
+ // generated by `ngOptions`.
568
+ // This must be done in the postLink fn to prevent $render to be called before
569
+ // all nodes have been linked correctly.
570
+ ngModelCtrl.$render = function () {
571
+ selectCtrl.writeValue(ngModelCtrl.$viewValue);
572
+ };
573
+ }
574
+ };
575
+
576
+ // The option directive is purely designed to communicate the existence (or lack of)
577
+ // of dynamically created (and destroyed) option elements to their containing select
578
+ // directive via its controller.
579
+ export const optionDirective = [
580
+ "$interpolate",
581
+ function ($interpolate) {
582
+ return {
583
+ restrict: "E",
584
+ priority: 100,
585
+ compile(element, attr) {
586
+ let interpolateValueFn;
587
+ let interpolateTextFn;
588
+
589
+ if (isDefined(attr.ngValue)) {
590
+ // Will be handled by registerOption
591
+ } else if (isDefined(attr.value)) {
592
+ // If the value attribute is defined, check if it contains an interpolation
593
+ interpolateValueFn = $interpolate(attr.value, true);
594
+ } else {
595
+ // If the value attribute is not defined then we fall back to the
596
+ // text content of the option element, which may be interpolated
597
+ interpolateTextFn = $interpolate(element.text(), true);
598
+ if (!interpolateTextFn) {
599
+ attr.$set("value", element.text());
600
+ }
601
+ }
602
+
603
+ return function (scope, element, attr) {
604
+ // This is an optimization over using ^^ since we don't want to have to search
605
+ // all the way to the root of the DOM for every single option element
606
+ const selectCtrlName = "$selectController";
607
+ const parent = element.parent();
608
+ const selectCtrl =
609
+ parent.data(selectCtrlName) || parent.parent().data(selectCtrlName); // in case we are in optgroup
610
+
611
+ if (selectCtrl) {
612
+ selectCtrl.registerOption(
613
+ scope,
614
+ element,
615
+ attr,
616
+ interpolateValueFn,
617
+ interpolateTextFn,
618
+ );
619
+ }
620
+ };
621
+ },
622
+ };
623
+ },
624
+ ];
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @returns {angular.IDirective}
3
+ */
4
+ export function ngStyleDirective() {
5
+ return {
6
+ restrict: "EA",
7
+ link: (scope, element, attr) => {
8
+ scope.$watchCollection(attr.ngStyle, (newStyles, oldStyles) => {
9
+ if (oldStyles) {
10
+ const oldKeys = Object.keys(oldStyles);
11
+ for (let i = 0, length = oldKeys.length; i < length; i++) {
12
+ element[0].style[oldKeys[i]] = "";
13
+ }
14
+ }
15
+ if (newStyles) {
16
+ const newEntries = Object.entries(newStyles);
17
+ for (let i = 0, length = newEntries.length; i < length; i++) {
18
+ const [key, value] = newEntries[i];
19
+ element[0].style[key] = value;
20
+ }
21
+ }
22
+ });
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,23 @@
1
+ ## `ngStyle` Directive
2
+
3
+ ### Restrict
4
+
5
+ `AC`
6
+
7
+ ### Description
8
+
9
+ The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
10
+
11
+ ### Known Issue
12
+
13
+ You should not use [interpolation](guide/interpolation) in the value of the `style` attribute when using the `ngStyle` directive on the same element. See [here](guide/interpolation#known-issues) for more info.
14
+
15
+ ### Element
16
+
17
+ `ANY`
18
+
19
+ ### Parameter
20
+
21
+ - `{string} ngStyle`: [Expression](guide/expression) which evaluates to an object whose keys are CSS style names and values are corresponding values for those CSS keys.
22
+
23
+ Since some CSS style names are not valid keys for an object, they must be quoted. See the 'background-color' style in the example below.