@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,1783 @@
1
+ import {
2
+ isDefined,
3
+ isUndefined,
4
+ isString,
5
+ lowercase,
6
+ trim,
7
+ isObject,
8
+ isNumber,
9
+ isNumberNaN,
10
+ isDate,
11
+ forEach,
12
+ convertTimezoneToLocal,
13
+ addDateMinutes,
14
+ timezoneToOffset,
15
+ nextUid,
16
+ equals,
17
+ } from "../core/utils";
18
+ import { ngModelMinErr } from "./ngModel";
19
+
20
+ // Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
21
+ export const ISO_DATE_REGEXP =
22
+ /^\d{4,}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z)$/;
23
+ // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
24
+ // Note: We are being more lenient, because browsers are too.
25
+ // 1. Scheme
26
+ // 2. Slashes
27
+ // 3. Username
28
+ // 4. Password
29
+ // 5. Hostname
30
+ // 6. Port
31
+ // 7. Path
32
+ // 8. Query
33
+ // 9. Fragment
34
+ // 1111111111111111 222 333333 44444 55555555555555555555555 666 77777777 8888888 999
35
+ export const URL_REGEXP =
36
+ /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
37
+ // eslint-disable-next-line max-len
38
+ export const EMAIL_REGEXP =
39
+ /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
40
+ const NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
41
+ const DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
42
+ const DATETIMELOCAL_REGEXP =
43
+ /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
44
+ const WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
45
+ const MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
46
+ const TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
47
+ // The name of a form control's ValidityState property.
48
+ // This is used so that it's possible for internal tests to create mock ValidityStates.
49
+ export const VALIDITY_STATE_PROPERTY = "validity";
50
+
51
+ const PARTIAL_VALIDATION_EVENTS = "keydown wheel mousedown";
52
+ /**
53
+ * @type {Map<string, boolean>}
54
+ */
55
+ const PARTIAL_VALIDATION_TYPES = new Map();
56
+ "date,datetime-local,month,time,week".split(",").forEach((type) => {
57
+ PARTIAL_VALIDATION_TYPES.set(type, true);
58
+ });
59
+
60
+ const inputType = {
61
+ /**
62
+ * @ngdoc input
63
+ * @name input[text]
64
+ *
65
+ * @description
66
+ * Standard HTML text input with AngularJS data binding, inherited by most of the `input` elements.
67
+ *
68
+ *
69
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
70
+ * @param {string=} name Property name of the form under which the control is published.
71
+ * @param {string=} required Adds `required` validation error key if the value is not entered.
72
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
73
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
74
+ * `required` when you want to data-bind to the `required` attribute.
75
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
76
+ * minlength.
77
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
78
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
79
+ * any length.
80
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
81
+ * that contains the regular expression body that will be converted to a regular expression
82
+ * as in the ngPattern directive.
83
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
84
+ * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
85
+ * If the expression evaluates to a RegExp object, then this is used directly.
86
+ * If the expression evaluates to a string, then it will be converted to a RegExp
87
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
88
+ * `new RegExp('^abc$')`.<br />
89
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
90
+ * start at the index of the last search's match, thus not taking the whole input value into
91
+ * account.
92
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
93
+ * interaction with the input element.
94
+ * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
95
+ * This parameter is ignored for input[type=password] controls, which will never trim the
96
+ * input.
97
+ */
98
+ text: textInputType,
99
+
100
+ /**
101
+ * @ngdoc input
102
+ * @name input[date]
103
+ *
104
+ * @description
105
+ * Input with date validation and transformation. In browsers that do not yet support
106
+ * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
107
+ * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
108
+ * modern browsers do not yet support this input type, it is important to provide cues to users on the
109
+ * expected input format via a placeholder or label.
110
+ *
111
+ * The model must always be a Date object, otherwise AngularJS will throw an error.
112
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
113
+ *
114
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
115
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
116
+ *
117
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
118
+ * @param {string=} name Property name of the form under which the control is published.
119
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
120
+ * valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
121
+ * (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
122
+ * constraint validation.
123
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
124
+ * a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
125
+ * (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
126
+ * constraint validation.
127
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
128
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
129
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
130
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
131
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
132
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
133
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
134
+ * `required` when you want to data-bind to the `required` attribute.
135
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
136
+ * interaction with the input element.
137
+ *
138
+ */
139
+ date: createDateInputType(
140
+ "date",
141
+ DATE_REGEXP,
142
+ createDateParser(DATE_REGEXP, ["yyyy", "MM", "dd"]),
143
+ "yyyy-MM-dd",
144
+ ),
145
+
146
+ /**
147
+ * @ngdoc input
148
+ * @name input[datetime-local]
149
+ *
150
+ * @description
151
+ * Input with datetime validation and transformation. In browsers that do not yet support
152
+ * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
153
+ * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
154
+ *
155
+ * The model must always be a Date object, otherwise AngularJS will throw an error.
156
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
157
+ *
158
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
159
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
160
+ *
161
+ * The format of the displayed time can be adjusted with the
162
+ * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
163
+ * and `timeStripZeroSeconds`.
164
+ *
165
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
166
+ * @param {string=} name Property name of the form under which the control is published.
167
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
168
+ * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
169
+ * inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
170
+ * Note that `min` will also add native HTML5 constraint validation.
171
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
172
+ * This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
173
+ * inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
174
+ * Note that `max` will also add native HTML5 constraint validation.
175
+ * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
176
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
177
+ * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
178
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
179
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
180
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
181
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
182
+ * `required` when you want to data-bind to the `required` attribute.
183
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
184
+ * interaction with the input element.
185
+ *
186
+ */
187
+ "datetime-local": createDateInputType(
188
+ "datetimelocal",
189
+ DATETIMELOCAL_REGEXP,
190
+ createDateParser(DATETIMELOCAL_REGEXP, [
191
+ "yyyy",
192
+ "MM",
193
+ "dd",
194
+ "HH",
195
+ "mm",
196
+ "ss",
197
+ "sss",
198
+ ]),
199
+ "yyyy-MM-ddTHH:mm:ss.sss",
200
+ ),
201
+
202
+ /**
203
+ * @ngdoc input
204
+ * @name input[time]
205
+ *
206
+ * @description
207
+ * Input with time validation and transformation. In browsers that do not yet support
208
+ * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
209
+ * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
210
+ * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
211
+ *
212
+ * The model must always be a Date object, otherwise AngularJS will throw an error.
213
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
214
+ *
215
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
216
+ * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions}. By default,
217
+ * this is the timezone of the browser.
218
+ *
219
+ * The format of the displayed time can be adjusted with the
220
+ * {@link ng.directive:ngModelOptions#ngModelOptions-arguments ngModelOptions} `timeSecondsFormat`
221
+ * and `timeStripZeroSeconds`.
222
+ *
223
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
224
+ * @param {string=} name Property name of the form under which the control is published.
225
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
226
+ * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
227
+ * attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
228
+ * native HTML5 constraint validation.
229
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
230
+ * This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
231
+ * attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
232
+ * native HTML5 constraint validation.
233
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
234
+ * `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
235
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
236
+ * `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
237
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
238
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
239
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
240
+ * `required` when you want to data-bind to the `required` attribute.
241
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
242
+ * interaction with the input element.
243
+ *
244
+ */
245
+ time: createDateInputType(
246
+ "time",
247
+ TIME_REGEXP,
248
+ createDateParser(TIME_REGEXP, ["HH", "mm", "ss", "sss"]),
249
+ "HH:mm:ss.sss",
250
+ ),
251
+
252
+ /**
253
+ * @ngdoc input
254
+ * @name input[week]
255
+ *
256
+ * @description
257
+ * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
258
+ * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
259
+ * week format (yyyy-W##), for example: `2013-W02`.
260
+ *
261
+ * The model must always be a Date object, otherwise AngularJS will throw an error.
262
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
263
+ *
264
+ * The value of the resulting Date object will be set to Thursday at 00:00:00 of the requested week,
265
+ * due to ISO-8601 week numbering standards. Information on ISO's system for numbering the weeks of the
266
+ * year can be found at: https://en.wikipedia.org/wiki/ISO_8601#Week_dates
267
+ *
268
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
269
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
270
+ *
271
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
272
+ * @param {string=} name Property name of the form under which the control is published.
273
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
274
+ * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
275
+ * attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
276
+ * native HTML5 constraint validation.
277
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
278
+ * This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
279
+ * attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
280
+ * native HTML5 constraint validation.
281
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
282
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
283
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
284
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
285
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
286
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
287
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
288
+ * `required` when you want to data-bind to the `required` attribute.
289
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
290
+ * interaction with the input element.
291
+ */
292
+ week: createDateInputType("week", WEEK_REGEXP, weekParser, "yyyy-Www"),
293
+
294
+ /**
295
+ * @ngdoc input
296
+ * @name input[month]
297
+ *
298
+ * @description
299
+ * Input with month validation and transformation. In browsers that do not yet support
300
+ * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
301
+ * month format (yyyy-MM), for example: `2009-01`.
302
+ *
303
+ * The model must always be a Date object, otherwise AngularJS will throw an error.
304
+ * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
305
+ * If the model is not set to the first of the month, the next view to model update will set it
306
+ * to the first of the month.
307
+ *
308
+ * The timezone to be used to read/write the `Date` instance in the model can be defined using
309
+ * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
310
+ *
311
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
312
+ * @param {string=} name Property name of the form under which the control is published.
313
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
314
+ * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
315
+ * attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
316
+ * native HTML5 constraint validation.
317
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
318
+ * This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
319
+ * attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
320
+ * native HTML5 constraint validation.
321
+ * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
322
+ * the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
323
+ * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
324
+ * the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
325
+
326
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
327
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
328
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
329
+ * `required` when you want to data-bind to the `required` attribute.
330
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
331
+ * interaction with the input element.
332
+ *
333
+ */
334
+ month: createDateInputType(
335
+ "month",
336
+ MONTH_REGEXP,
337
+ createDateParser(MONTH_REGEXP, ["yyyy", "MM"]),
338
+ "yyyy-MM",
339
+ ),
340
+
341
+ /**
342
+ * @ngdoc input
343
+ * @name input[number]
344
+ *
345
+ * @description
346
+ * Text input with number validation and transformation. Sets the `number` validation
347
+ * error if not a valid number.
348
+ *
349
+ * <div class="alert alert-warning">
350
+ * The model must always be of type `number` otherwise AngularJS will throw an error.
351
+ * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
352
+ * error docs for more information and an example of how to convert your model if necessary.
353
+ * </div>
354
+ *
355
+ *
356
+ *
357
+ * @knownIssue
358
+ *
359
+ * ### HTML5 constraint validation and `allowInvalid`
360
+ *
361
+ * In browsers that follow the
362
+ * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
363
+ * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
364
+ * If a non-number is entered in the input, the browser will report the value as an empty string,
365
+ * which means the view / model values in `ngModel` and subsequently the scope value
366
+ * will also be an empty string.
367
+ *
368
+ * @knownIssue
369
+ *
370
+ * ### Large numbers and `step` validation
371
+ *
372
+ * The `step` validation will not work correctly for very large numbers (e.g. 9999999999) due to
373
+ * Javascript's arithmetic limitations. If you need to handle large numbers, purpose-built
374
+ * libraries (e.g. https://github.com/MikeMcl/big.js/), can be included into AngularJS by
375
+ * {@link guide/forms#modifying-built-in-validators overwriting the validators}
376
+ * for `number` and / or `step`, or by {@link guide/forms#custom-validation applying custom validators}
377
+ * to an `input[text]` element. The source for `input[number]` type can be used as a starting
378
+ * point for both implementations.
379
+ *
380
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
381
+ * @param {string=} name Property name of the form under which the control is published.
382
+ * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
383
+ * Can be interpolated.
384
+ * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
385
+ * Can be interpolated.
386
+ * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
387
+ * but does not trigger HTML5 native validation. Takes an expression.
388
+ * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
389
+ * but does not trigger HTML5 native validation. Takes an expression.
390
+ * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
391
+ * Can be interpolated.
392
+ * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
393
+ * but does not trigger HTML5 native validation. Takes an expression.
394
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
395
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
396
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
397
+ * `required` when you want to data-bind to the `required` attribute.
398
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
399
+ * minlength.
400
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
401
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
402
+ * any length.
403
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
404
+ * that contains the regular expression body that will be converted to a regular expression
405
+ * as in the ngPattern directive.
406
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
407
+ * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
408
+ * If the expression evaluates to a RegExp object, then this is used directly.
409
+ * If the expression evaluates to a string, then it will be converted to a RegExp
410
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
411
+ * `new RegExp('^abc$')`.<br />
412
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
413
+ * start at the index of the last search's match, thus not taking the whole input value into
414
+ * account.
415
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
416
+ * interaction with the input element.
417
+ *
418
+ */
419
+ number: numberInputType,
420
+
421
+ /**
422
+ * @ngdoc input
423
+ * @name input[url]
424
+ *
425
+ * @description
426
+ * Text input with URL validation. Sets the `url` validation error key if the content is not a
427
+ * valid URL.
428
+ *
429
+ * <div class="alert alert-warning">
430
+ * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
431
+ * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
432
+ * the built-in validators (see the {@link guide/forms Forms guide})
433
+ * </div>
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=} required Sets `required` validation error key if the value is not entered.
438
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
439
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
440
+ * `required` when you want to data-bind to the `required` attribute.
441
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
442
+ * minlength.
443
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
444
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
445
+ * any length.
446
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
447
+ * that contains the regular expression body that will be converted to a regular expression
448
+ * as in the ngPattern directive.
449
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
450
+ * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
451
+ * If the expression evaluates to a RegExp object, then this is used directly.
452
+ * If the expression evaluates to a string, then it will be converted to a RegExp
453
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
454
+ * `new RegExp('^abc$')`.<br />
455
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
456
+ * start at the index of the last search's match, thus not taking the whole input value into
457
+ * account.
458
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
459
+ * interaction with the input element.
460
+ *
461
+ */
462
+ url: urlInputType,
463
+
464
+ /**
465
+ * @ngdoc input
466
+ * @name input[email]
467
+ *
468
+ * @description
469
+ * Text input with email validation. Sets the `email` validation error key if not a valid email
470
+ * address.
471
+ *
472
+ * <div class="alert alert-warning">
473
+ * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
474
+ * used in Chromium, which may not fulfill your app's requirements.
475
+ * If you need stricter (e.g. requiring a top-level domain), or more relaxed validation
476
+ * (e.g. allowing IPv6 address literals) you can use `ng-pattern` or
477
+ * modify the built-in validators (see the {@link guide/forms Forms guide}).
478
+ * </div>
479
+ *
480
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
481
+ * @param {string=} name Property name of the form under which the control is published.
482
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
483
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
484
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
485
+ * `required` when you want to data-bind to the `required` attribute.
486
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
487
+ * minlength.
488
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
489
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
490
+ * any length.
491
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
492
+ * that contains the regular expression body that will be converted to a regular expression
493
+ * as in the ngPattern directive.
494
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
495
+ * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
496
+ * If the expression evaluates to a RegExp object, then this is used directly.
497
+ * If the expression evaluates to a string, then it will be converted to a RegExp
498
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
499
+ * `new RegExp('^abc$')`.<br />
500
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
501
+ * start at the index of the last search's match, thus not taking the whole input value into
502
+ * account.
503
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
504
+ * interaction with the input element.
505
+ *
506
+ */
507
+ email: emailInputType,
508
+
509
+ /**
510
+ * @ngdoc input
511
+ * @name input[radio]
512
+ *
513
+ * @description
514
+ * HTML radio button.
515
+ *
516
+ * **Note:**<br>
517
+ * All inputs controlled by {@link ngModel ngModel} (including those of type `radio`) will use the
518
+ * value of their `name` attribute to determine the property under which their
519
+ * {@link ngModel.NgModelController NgModelController} will be published on the parent
520
+ * {@link form.FormController FormController}. Thus, if you use the same `name` for multiple
521
+ * inputs of a form (e.g. a group of radio inputs), only _one_ `NgModelController` will be
522
+ * published on the parent `FormController` under that name. The rest of the controllers will
523
+ * continue to work as expected, but you won't be able to access them as properties on the parent
524
+ * `FormController`.
525
+ *
526
+ * <div class="alert alert-info">
527
+ * <p>
528
+ * In plain HTML forms, the `name` attribute is used to identify groups of radio inputs, so
529
+ * that the browser can manage their state (checked/unchecked) based on the state of other
530
+ * inputs in the same group.
531
+ * </p>
532
+ * <p>
533
+ * In AngularJS forms, this is not necessary. The input's state will be updated based on the
534
+ * value of the underlying model data.
535
+ * </p>
536
+ * </div>
537
+ *
538
+ * <div class="alert alert-success">
539
+ * If you omit the `name` attribute on a radio input, `ngModel` will automatically assign it a
540
+ * unique name.
541
+ * </div>
542
+ *
543
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
544
+ * @param {string} value The value to which the `ngModel` expression should be set when selected.
545
+ * Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
546
+ * too. Use `ngValue` if you need complex models (`number`, `object`, ...).
547
+ * @param {string=} name Property name of the form under which the control is published.
548
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
549
+ * interaction with the input element.
550
+ * @param {string} ngValue AngularJS expression to which `ngModel` will be be set when the radio
551
+ * is selected. Should be used instead of the `value` attribute if you need
552
+ * a non-string `ngModel` (`boolean`, `array`, ...).
553
+ *
554
+ */
555
+ radio: radioInputType,
556
+
557
+ /**
558
+ * @ngdoc input
559
+ * @name input[range]
560
+ *
561
+ * @description
562
+ * Native range input with validation and transformation.
563
+ *
564
+ * The model for the range input must always be a `Number`.
565
+ *
566
+ * IE9 and other browsers that do not support the `range` type fall back
567
+ * to a text input without any default values for `min`, `max` and `step`. Model binding,
568
+ * validation and number parsing are nevertheless supported.
569
+ *
570
+ * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]`
571
+ * in a way that never allows the input to hold an invalid value. That means:
572
+ * - any non-numerical value is set to `(max + min) / 2`.
573
+ * - any numerical value that is less than the current min val, or greater than the current max val
574
+ * is set to the min / max val respectively.
575
+ * - additionally, the current `step` is respected, so the nearest value that satisfies a step
576
+ * is used.
577
+ *
578
+ * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range))
579
+ * for more info.
580
+ *
581
+ * This has the following consequences for AngularJS:
582
+ *
583
+ * Since the element value should always reflect the current model value, a range input
584
+ * will set the bound ngModel expression to the value that the browser has set for the
585
+ * input element. For example, in the following input `<input type="range" ng-model="model.value">`,
586
+ * if the application sets `model.value = null`, the browser will set the input to `'50'`.
587
+ * AngularJS will then set the model to `50`, to prevent input and model value being out of sync.
588
+ *
589
+ * That means the model for range will immediately be set to `50` after `ngModel` has been
590
+ * initialized. It also means a range input can never have the required error.
591
+ *
592
+ * This does not only affect changes to the model value, but also to the values of the `min`,
593
+ * `max`, and `step` attributes. When these change in a way that will cause the browser to modify
594
+ * the input value, AngularJS will also update the model value.
595
+ *
596
+ * Automatic value adjustment also means that a range input element can never have the `required`,
597
+ * `min`, or `max` errors.
598
+ *
599
+ * However, `step` is currently only fully implemented by Firefox. Other browsers have problems
600
+ * when the step value changes dynamically - they do not adjust the element value correctly, but
601
+ * instead may set the `stepMismatch` error. If that's the case, the AngularJS will set the `step`
602
+ * error on the input, and set the model to `undefined`.
603
+ *
604
+ * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
605
+ * not set the `min` and `max` attributes, which means that the browser won't automatically adjust
606
+ * the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
607
+ *
608
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
609
+ * @param {string=} name Property name of the form under which the control is published.
610
+ * @param {string=} min Sets the `min` validation to ensure that the value entered is greater
611
+ * than `min`. Can be interpolated.
612
+ * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`.
613
+ * Can be interpolated.
614
+ * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step`
615
+ * Can be interpolated.
616
+ * @param {expression=} ngChange AngularJS expression to be executed when the ngModel value changes due
617
+ * to user interaction with the input element.
618
+ * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the
619
+ * element. **Note** : `ngChecked` should not be used alongside `ngModel`.
620
+ * Checkout {@link ng.directive:ngChecked ngChecked} for usage.
621
+ *
622
+ * @example
623
+ <example name="range-input-directive" module="rangeExample">
624
+ <file name="index.html">
625
+ <script>
626
+ angular.module('rangeExample', [])
627
+ .controller('ExampleController', ['$scope', function($scope) {
628
+ $scope.value = 75;
629
+ $scope.min = 10;
630
+ $scope.max = 90;
631
+ }]);
632
+ </script>
633
+ <form name="myForm" ng-controller="ExampleController">
634
+
635
+ Model as range: <input type="range" name="range" ng-model="value" min="{{min}}" max="{{max}}">
636
+ <hr>
637
+ Model as number: <input type="number" ng-model="value"><br>
638
+ Min: <input type="number" ng-model="min"><br>
639
+ Max: <input type="number" ng-model="max"><br>
640
+ value = <code>{{value}}</code><br/>
641
+ myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
642
+ myForm.range.$error = <code>{{myForm.range.$error}}</code>
643
+ </form>
644
+ </file>
645
+ </example>
646
+
647
+ * ## Range Input with ngMin & ngMax attributes
648
+
649
+ * @example
650
+ <example name="range-input-directive-ng" module="rangeExample">
651
+ <file name="index.html">
652
+ <script>
653
+ angular.module('rangeExample', [])
654
+ .controller('ExampleController', ['$scope', function($scope) {
655
+ $scope.value = 75;
656
+ $scope.min = 10;
657
+ $scope.max = 90;
658
+ }]);
659
+ </script>
660
+ <form name="myForm" ng-controller="ExampleController">
661
+ Model as range: <input type="range" name="range" ng-model="value" ng-min="min" ng-max="max">
662
+ <hr>
663
+ Model as number: <input type="number" ng-model="value"><br>
664
+ Min: <input type="number" ng-model="min"><br>
665
+ Max: <input type="number" ng-model="max"><br>
666
+ value = <code>{{value}}</code><br/>
667
+ myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
668
+ myForm.range.$error = <code>{{myForm.range.$error}}</code>
669
+ </form>
670
+ </file>
671
+ </example>
672
+
673
+ */
674
+ range: rangeInputType,
675
+
676
+ /**
677
+ * @ngdoc input
678
+ * @name input[checkbox]
679
+ *
680
+ * @description
681
+ * HTML checkbox.
682
+ *
683
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
684
+ * @param {string=} name Property name of the form under which the control is published.
685
+ * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
686
+ * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
687
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
688
+ * interaction with the input element.
689
+ *
690
+ */
691
+ checkbox: checkboxInputType,
692
+
693
+ hidden: () => {},
694
+ button: () => {},
695
+ submit: () => {},
696
+ reset: () => {},
697
+ file: () => {},
698
+ };
699
+
700
+ function stringBasedInputType(ctrl) {
701
+ ctrl.$formatters.push((value) =>
702
+ ctrl.$isEmpty(value) ? value : value.toString(),
703
+ );
704
+ }
705
+
706
+ function textInputType(scope, element, attr, ctrl, $browser) {
707
+ baseInputType(scope, element, attr, ctrl, $browser);
708
+ stringBasedInputType(ctrl);
709
+ }
710
+
711
+ function baseInputType(scope, element, attr, ctrl, $browser) {
712
+ const type = lowercase(element[0].type);
713
+ let composing = false;
714
+ // In composition mode, users are still inputting intermediate text buffer,
715
+ // hold the listener until composition is done.
716
+ // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
717
+ element.on("compositionstart", () => {
718
+ composing = true;
719
+ });
720
+
721
+ element.on("compositionend", () => {
722
+ composing = false;
723
+ listener();
724
+ });
725
+
726
+ let timeout;
727
+
728
+ let listener = function (ev) {
729
+ if (timeout) {
730
+ $browser.defer.cancel(timeout);
731
+ timeout = null;
732
+ }
733
+ if (composing) return;
734
+ let value = element.val();
735
+ const event = ev && ev.type;
736
+
737
+ // By default we will trim the value
738
+ // If the attribute ng-trim exists we will avoid trimming
739
+ // If input type is 'password', the value is never trimmed
740
+ if (type !== "password" && (!attr.ngTrim || attr.ngTrim !== "false")) {
741
+ value = trim(value);
742
+ }
743
+
744
+ // If a control is suffering from bad input (due to native validators), browsers discard its
745
+ // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
746
+ // control's value is the same empty value twice in a row.
747
+ if (
748
+ ctrl.$viewValue !== value ||
749
+ (value === "" && ctrl.$$hasNativeValidators)
750
+ ) {
751
+ ctrl.$setViewValue(value, event);
752
+ }
753
+ };
754
+
755
+ ["input", "change", "paste", "drop", "cut"].forEach((event) => {
756
+ element.on(event, listener);
757
+ });
758
+
759
+ // Some native input types (date-family) have the ability to change validity without
760
+ // firing any input/change events.
761
+ // For these event types, when native validators are present and the browser supports the type,
762
+ // check for validity changes on various DOM events.
763
+ if (
764
+ PARTIAL_VALIDATION_TYPES[type] &&
765
+ ctrl.$$hasNativeValidators &&
766
+ type === attr.type
767
+ ) {
768
+ element.on(PARTIAL_VALIDATION_EVENTS, function (ev) {
769
+ if (!timeout) {
770
+ const validity = this[VALIDITY_STATE_PROPERTY];
771
+ const origBadInput = validity.badInput;
772
+ const origTypeMismatch = validity.typeMismatch;
773
+ timeout = $browser.defer(() => {
774
+ timeout = null;
775
+ if (
776
+ validity.badInput !== origBadInput ||
777
+ validity.typeMismatch !== origTypeMismatch
778
+ ) {
779
+ listener(ev);
780
+ }
781
+ });
782
+ }
783
+ });
784
+ }
785
+
786
+ ctrl.$render = function () {
787
+ // Workaround for Firefox validation #12102.
788
+ const value = ctrl.$isEmpty(ctrl.$viewValue) ? "" : ctrl.$viewValue;
789
+ if (element.val() !== value) {
790
+ element.val(value);
791
+ }
792
+ };
793
+ }
794
+
795
+ export function weekParser(isoWeek, existingDate) {
796
+ if (isDate(isoWeek)) {
797
+ return isoWeek;
798
+ }
799
+
800
+ function getFirstThursdayOfYear(year) {
801
+ // 0 = index of January
802
+ var dayOfWeekOnFirst = new Date(year, 0, 1).getDay();
803
+ // 4 = index of Thursday (+1 to account for 1st = 5)
804
+ // 11 = index of *next* Thursday (+1 account for 1st = 12)
805
+ return new Date(
806
+ year,
807
+ 0,
808
+ (dayOfWeekOnFirst <= 4 ? 5 : 12) - dayOfWeekOnFirst,
809
+ );
810
+ }
811
+
812
+ if (isString(isoWeek)) {
813
+ WEEK_REGEXP.lastIndex = 0;
814
+ const parts = WEEK_REGEXP.exec(isoWeek);
815
+ if (parts) {
816
+ const year = +parts[1];
817
+ const week = +parts[2];
818
+ let hours = 0;
819
+ let minutes = 0;
820
+ let seconds = 0;
821
+ let milliseconds = 0;
822
+ const firstThurs = getFirstThursdayOfYear(year);
823
+ const addDays = (week - 1) * 7;
824
+
825
+ if (existingDate) {
826
+ hours = existingDate.getHours();
827
+ minutes = existingDate.getMinutes();
828
+ seconds = existingDate.getSeconds();
829
+ milliseconds = existingDate.getMilliseconds();
830
+ }
831
+
832
+ return new Date(
833
+ year,
834
+ 0,
835
+ firstThurs.getDate() + addDays,
836
+ hours,
837
+ minutes,
838
+ seconds,
839
+ milliseconds,
840
+ );
841
+ }
842
+ }
843
+
844
+ return NaN;
845
+ }
846
+
847
+ export function createDateParser(regexp, mapping) {
848
+ return function (iso, previousDate) {
849
+ let parts;
850
+ let map;
851
+
852
+ if (isDate(iso)) {
853
+ return iso;
854
+ }
855
+
856
+ if (isString(iso)) {
857
+ // When a date is JSON'ified to wraps itself inside of an extra
858
+ // set of double quotes. This makes the date parsing code unable
859
+ // to match the date string and parse it as a date.
860
+ if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') {
861
+ iso = iso.substring(1, iso.length - 1);
862
+ }
863
+ if (ISO_DATE_REGEXP.test(iso)) {
864
+ return new Date(iso);
865
+ }
866
+ regexp.lastIndex = 0;
867
+ parts = regexp.exec(iso);
868
+
869
+ if (parts) {
870
+ parts.shift();
871
+ if (previousDate) {
872
+ map = {
873
+ yyyy: previousDate.getFullYear(),
874
+ MM: previousDate.getMonth() + 1,
875
+ dd: previousDate.getDate(),
876
+ HH: previousDate.getHours(),
877
+ mm: previousDate.getMinutes(),
878
+ ss: previousDate.getSeconds(),
879
+ sss: previousDate.getMilliseconds() / 1000,
880
+ };
881
+ } else {
882
+ map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
883
+ }
884
+
885
+ forEach(parts, (part, index) => {
886
+ if (index < mapping.length) {
887
+ map[mapping[index]] = +part;
888
+ }
889
+ });
890
+
891
+ const date = new Date(
892
+ map.yyyy,
893
+ map.MM - 1,
894
+ map.dd,
895
+ map.HH,
896
+ map.mm,
897
+ map.ss || 0,
898
+ map.sss * 1000 || 0,
899
+ );
900
+ if (map.yyyy < 100) {
901
+ // In the constructor, 2-digit years map to 1900-1999.
902
+ // Use `setFullYear()` to set the correct year.
903
+ date.setFullYear(map.yyyy);
904
+ }
905
+
906
+ return date;
907
+ }
908
+ }
909
+
910
+ return NaN;
911
+ };
912
+ }
913
+
914
+ const MONTH_INPUT_FORMAT = /\b\d{4}-(0[1-9]|1[0-2])\b/;
915
+
916
+ export function createDateInputType(type, regexp, parseDate) {
917
+ return function dynamicDateInputType(
918
+ scope,
919
+ element,
920
+ attr,
921
+ ctrl,
922
+ $browser,
923
+ $filter,
924
+ $parse,
925
+ ) {
926
+ badInputChecker(scope, element, attr, ctrl, type);
927
+ baseInputType(scope, element, attr, ctrl, $browser);
928
+ let previousDate;
929
+ let previousTimezone;
930
+
931
+ ctrl.$parsers.push((value) => {
932
+ if (ctrl.$isEmpty(value)) return null;
933
+
934
+ if (regexp.test(value)) {
935
+ // Do not convert for native HTML
936
+ if (["month", "week", "datetimelocal", "time", "date"].includes(type)) {
937
+ return value;
938
+ }
939
+
940
+ // Note: We cannot read ctrl.$modelValue, as there might be a different
941
+ // parser/formatter in the processing chain so that the model
942
+ // contains some different data format!
943
+ return parseDateAndConvertTimeZoneToLocal(value, previousDate);
944
+ }
945
+ ctrl.$$parserName = type;
946
+ return undefined;
947
+ });
948
+
949
+ ctrl.$formatters.push(function (value) {
950
+ if (value && !isString(value)) {
951
+ throw ngModelMinErr("datefmt", "Expected `{0}` to be a String", value);
952
+ }
953
+
954
+ if (type === "month") {
955
+ if (value == null) {
956
+ return "";
957
+ }
958
+ if (!MONTH_INPUT_FORMAT.test(value)) {
959
+ throw ngModelMinErr(
960
+ "datefmt",
961
+ "Expected month `{0}` to be a 'YYYY-DD'",
962
+ value,
963
+ );
964
+ }
965
+ }
966
+
967
+ if (type === "week") {
968
+ if (value == null) {
969
+ return "";
970
+ }
971
+ if (!WEEK_REGEXP.test(value)) {
972
+ throw ngModelMinErr(
973
+ "datefmt",
974
+ "Expected week `{0}` to be a 'yyyy-Www'",
975
+ value,
976
+ );
977
+ }
978
+ }
979
+
980
+ if (type === "datetimelocal") {
981
+ if (value == null) {
982
+ return "";
983
+ }
984
+ if (!DATETIMELOCAL_REGEXP.test(value)) {
985
+ throw ngModelMinErr(
986
+ "datefmt",
987
+ "Expected week `{0}` to be a in date time format. See: https://developer.mozilla.org/en-US/docs/Web/HTML/Date_and_time_formats#local_date_and_time_strings",
988
+ value,
989
+ );
990
+ }
991
+ }
992
+
993
+ return value;
994
+
995
+ // if (isValidDate(value)) {
996
+ // previousDate = value;
997
+ // const timezone = ctrl.$options.getOption("timezone");
998
+
999
+ // if (timezone) {
1000
+ // previousTimezone = timezone;
1001
+ // previousDate = convertTimezoneToLocal(previousDate, timezone, true);
1002
+ // }
1003
+
1004
+ // return value;
1005
+ // }
1006
+ // previousDate = null;
1007
+ // previousTimezone = null;
1008
+ // return "";
1009
+ });
1010
+
1011
+ if (isDefined(attr.min) || attr.ngMin) {
1012
+ let minVal = attr.min || $parse(attr.ngMin)(scope);
1013
+ let parsedMinVal = parseObservedDateValue(minVal);
1014
+
1015
+ ctrl.$validators.min = function (value) {
1016
+ if (type === "month") {
1017
+ return (
1018
+ isUndefined(parsedMinVal) ||
1019
+ parseDate(value) >= parseDate(parsedMinVal)
1020
+ );
1021
+ }
1022
+
1023
+ return (
1024
+ !isValidDate(value) ||
1025
+ isUndefined(parsedMinVal) ||
1026
+ parseDate(value) >= parsedMinVal
1027
+ );
1028
+ };
1029
+ attr.$observe("min", (val) => {
1030
+ if (val !== minVal) {
1031
+ parsedMinVal = parseObservedDateValue(val);
1032
+ minVal = val;
1033
+ ctrl.$validate();
1034
+ }
1035
+ });
1036
+ }
1037
+
1038
+ if (isDefined(attr.max) || attr.ngMax) {
1039
+ let maxVal = attr.max || $parse(attr.ngMax)(scope);
1040
+ let parsedMaxVal = parseObservedDateValue(maxVal);
1041
+
1042
+ ctrl.$validators.max = function (value) {
1043
+ if (type === "month") {
1044
+ return (
1045
+ isUndefined(parsedMaxVal) ||
1046
+ parseDate(value) <= parseDate(parsedMaxVal)
1047
+ );
1048
+ }
1049
+ return (
1050
+ !isValidDate(value) ||
1051
+ isUndefined(parsedMaxVal) ||
1052
+ parseDate(value) <= parsedMaxVal
1053
+ );
1054
+ };
1055
+ attr.$observe("max", (val) => {
1056
+ if (val !== maxVal) {
1057
+ parsedMaxVal = parseObservedDateValue(val);
1058
+ maxVal = val;
1059
+ ctrl.$validate();
1060
+ }
1061
+ });
1062
+ }
1063
+
1064
+ function isValidDate(value) {
1065
+ // Invalid Date: getTime() returns NaN
1066
+ return value && !(value.getTime && value.getTime() !== value.getTime());
1067
+ }
1068
+
1069
+ function parseObservedDateValue(val) {
1070
+ return isDefined(val) && !isDate(val)
1071
+ ? parseDateAndConvertTimeZoneToLocal(val) || undefined
1072
+ : val;
1073
+ }
1074
+
1075
+ function parseDateAndConvertTimeZoneToLocal(value, previousDate) {
1076
+ const timezone = ctrl.$options.getOption("timezone");
1077
+
1078
+ if (previousTimezone && previousTimezone !== timezone) {
1079
+ // If the timezone has changed, adjust the previousDate to the default timezone
1080
+ // so that the new date is converted with the correct timezone offset
1081
+ previousDate = addDateMinutes(
1082
+ previousDate,
1083
+ timezoneToOffset(previousTimezone),
1084
+ );
1085
+ }
1086
+
1087
+ let parsedDate = parseDate(value, previousDate);
1088
+
1089
+ if (!Number.isNaN(parsedDate) && timezone) {
1090
+ parsedDate = convertTimezoneToLocal(parsedDate, timezone);
1091
+ }
1092
+ return parsedDate;
1093
+ }
1094
+ };
1095
+ }
1096
+
1097
+ export function badInputChecker(scope, element, attr, ctrl, parserName) {
1098
+ const node = element[0];
1099
+ const nativeValidation = (ctrl.$$hasNativeValidators = isObject(
1100
+ node.validity,
1101
+ ));
1102
+
1103
+ if (nativeValidation) {
1104
+ ctrl.$parsers.push((value) => {
1105
+ const validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
1106
+ if (validity.badInput || validity.typeMismatch) {
1107
+ ctrl.$$parserName = parserName;
1108
+ return undefined;
1109
+ }
1110
+
1111
+ return value;
1112
+ });
1113
+ }
1114
+ }
1115
+
1116
+ export function numberFormatterParser(ctrl) {
1117
+ ctrl.$parsers.push((value) => {
1118
+ if (ctrl.$isEmpty(value)) return null;
1119
+ if (NUMBER_REGEXP.test(value)) return parseFloat(value);
1120
+
1121
+ ctrl.$$parserName = "number";
1122
+ return undefined;
1123
+ });
1124
+
1125
+ ctrl.$formatters.push((value) => {
1126
+ if (!ctrl.$isEmpty(value)) {
1127
+ if (!isNumber(value)) {
1128
+ throw ngModelMinErr("numfmt", "Expected `{0}` to be a number", value);
1129
+ }
1130
+ value = value.toString();
1131
+ }
1132
+ return value;
1133
+ });
1134
+ }
1135
+
1136
+ function parseNumberAttrVal(val) {
1137
+ if (isDefined(val) && !isNumber(val)) {
1138
+ val = parseFloat(val);
1139
+ }
1140
+ return !isNumberNaN(val) ? val : undefined;
1141
+ }
1142
+
1143
+ export function isNumberInteger(num) {
1144
+ // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066
1145
+ // (minus the assumption that `num` is a number)
1146
+
1147
+ // eslint-disable-next-line no-bitwise
1148
+ return (num | 0) === num;
1149
+ }
1150
+
1151
+ export function countDecimals(num) {
1152
+ const numString = num.toString();
1153
+ const decimalSymbolIndex = numString.indexOf(".");
1154
+
1155
+ if (decimalSymbolIndex === -1) {
1156
+ if (num > -1 && num < 1) {
1157
+ // It may be in the exponential notation format (`1e-X`)
1158
+ const match = /e-(\d+)$/.exec(numString);
1159
+
1160
+ if (match) {
1161
+ return Number(match[1]);
1162
+ }
1163
+ }
1164
+
1165
+ return 0;
1166
+ }
1167
+
1168
+ return numString.length - decimalSymbolIndex - 1;
1169
+ }
1170
+
1171
+ export function isValidForStep(viewValue, stepBase, step) {
1172
+ // At this point `stepBase` and `step` are expected to be non-NaN values
1173
+ // and `viewValue` is expected to be a valid stringified number.
1174
+ let value = Number(viewValue);
1175
+
1176
+ const isNonIntegerValue = !isNumberInteger(value);
1177
+ const isNonIntegerStepBase = !isNumberInteger(stepBase);
1178
+ const isNonIntegerStep = !isNumberInteger(step);
1179
+
1180
+ // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
1181
+ // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
1182
+ if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
1183
+ const valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
1184
+ const stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
1185
+ const stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
1186
+
1187
+ const decimalCount = Math.max(
1188
+ valueDecimals,
1189
+ stepBaseDecimals,
1190
+ stepDecimals,
1191
+ );
1192
+ const multiplier = 10 ** decimalCount;
1193
+
1194
+ value *= multiplier;
1195
+ stepBase *= multiplier;
1196
+ step *= multiplier;
1197
+
1198
+ if (isNonIntegerValue) value = Math.round(value);
1199
+ if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
1200
+ if (isNonIntegerStep) step = Math.round(step);
1201
+ }
1202
+
1203
+ return (value - stepBase) % step === 0;
1204
+ }
1205
+
1206
+ export function numberInputType(
1207
+ scope,
1208
+ element,
1209
+ attr,
1210
+ ctrl,
1211
+ $browser,
1212
+ $filter,
1213
+ $parse,
1214
+ ) {
1215
+ badInputChecker(scope, element, attr, ctrl, "number");
1216
+ numberFormatterParser(ctrl);
1217
+ baseInputType(scope, element, attr, ctrl, $browser);
1218
+
1219
+ let parsedMinVal;
1220
+
1221
+ if (isDefined(attr.min) || attr.ngMin) {
1222
+ let minVal = attr.min || $parse(attr.ngMin)(scope);
1223
+ parsedMinVal = parseNumberAttrVal(minVal);
1224
+
1225
+ ctrl.$validators.min = function (modelValue, viewValue) {
1226
+ return (
1227
+ ctrl.$isEmpty(viewValue) ||
1228
+ isUndefined(parsedMinVal) ||
1229
+ viewValue >= parsedMinVal
1230
+ );
1231
+ };
1232
+
1233
+ attr.$observe("min", (val) => {
1234
+ if (val !== minVal) {
1235
+ parsedMinVal = parseNumberAttrVal(val);
1236
+ minVal = val;
1237
+ // TODO(matsko): implement validateLater to reduce number of validations
1238
+ ctrl.$validate();
1239
+ }
1240
+ });
1241
+ }
1242
+
1243
+ if (isDefined(attr.max) || attr.ngMax) {
1244
+ let maxVal = attr.max || $parse(attr.ngMax)(scope);
1245
+ let parsedMaxVal = parseNumberAttrVal(maxVal);
1246
+
1247
+ ctrl.$validators.max = function (modelValue, viewValue) {
1248
+ return (
1249
+ ctrl.$isEmpty(viewValue) ||
1250
+ isUndefined(parsedMaxVal) ||
1251
+ viewValue <= parsedMaxVal
1252
+ );
1253
+ };
1254
+
1255
+ attr.$observe("max", (val) => {
1256
+ if (val !== maxVal) {
1257
+ parsedMaxVal = parseNumberAttrVal(val);
1258
+ maxVal = val;
1259
+ // TODO(matsko): implement validateLater to reduce number of validations
1260
+ ctrl.$validate();
1261
+ }
1262
+ });
1263
+ }
1264
+
1265
+ if (isDefined(attr.step) || attr.ngStep) {
1266
+ let stepVal = attr.step || $parse(attr.ngStep)(scope);
1267
+ let parsedStepVal = parseNumberAttrVal(stepVal);
1268
+
1269
+ ctrl.$validators.step = function (modelValue, viewValue) {
1270
+ return (
1271
+ ctrl.$isEmpty(viewValue) ||
1272
+ isUndefined(parsedStepVal) ||
1273
+ isValidForStep(viewValue, parsedMinVal || 0, parsedStepVal)
1274
+ );
1275
+ };
1276
+
1277
+ attr.$observe("step", (val) => {
1278
+ // TODO(matsko): implement validateLater to reduce number of validations
1279
+ if (val !== stepVal) {
1280
+ parsedStepVal = parseNumberAttrVal(val);
1281
+ stepVal = val;
1282
+ ctrl.$validate();
1283
+ }
1284
+ });
1285
+ }
1286
+ }
1287
+
1288
+ export function rangeInputType(scope, element, attr, ctrl, $browser) {
1289
+ badInputChecker(scope, element, attr, ctrl, "range");
1290
+ numberFormatterParser(ctrl);
1291
+ baseInputType(scope, element, attr, ctrl, $browser);
1292
+
1293
+ const supportsRange =
1294
+ ctrl.$$hasNativeValidators && element[0].type === "range";
1295
+ let minVal = supportsRange ? 0 : undefined;
1296
+ let maxVal = supportsRange ? 100 : undefined;
1297
+ let stepVal = supportsRange ? 1 : undefined;
1298
+ const { validity } = element[0];
1299
+ const hasMinAttr = isDefined(attr.min);
1300
+ const hasMaxAttr = isDefined(attr.max);
1301
+ const hasStepAttr = isDefined(attr.step);
1302
+
1303
+ const originalRender = ctrl.$render;
1304
+
1305
+ ctrl.$render =
1306
+ supportsRange &&
1307
+ isDefined(validity.rangeUnderflow) &&
1308
+ isDefined(validity.rangeOverflow)
1309
+ ? // Browsers that implement range will set these values automatically, but reading the adjusted values after
1310
+ // $render would cause the min / max validators to be applied with the wrong value
1311
+ function rangeRender() {
1312
+ originalRender();
1313
+ ctrl.$setViewValue(element.val());
1314
+ }
1315
+ : originalRender;
1316
+
1317
+ if (hasMinAttr) {
1318
+ minVal = parseNumberAttrVal(attr.min);
1319
+
1320
+ ctrl.$validators.min = supportsRange
1321
+ ? // Since all browsers set the input to a valid value, we don't need to check validity
1322
+ function noopMinValidator() {
1323
+ return true;
1324
+ }
1325
+ : // non-support browsers validate the min val
1326
+ function minValidator(modelValue, viewValue) {
1327
+ return (
1328
+ ctrl.$isEmpty(viewValue) ||
1329
+ isUndefined(minVal) ||
1330
+ viewValue >= minVal
1331
+ );
1332
+ };
1333
+
1334
+ setInitialValueAndObserver("min", minChange);
1335
+ }
1336
+
1337
+ if (hasMaxAttr) {
1338
+ maxVal = parseNumberAttrVal(attr.max);
1339
+
1340
+ ctrl.$validators.max = supportsRange
1341
+ ? // Since all browsers set the input to a valid value, we don't need to check validity
1342
+ function noopMaxValidator() {
1343
+ return true;
1344
+ }
1345
+ : // non-support browsers validate the max val
1346
+ function maxValidator(modelValue, viewValue) {
1347
+ return (
1348
+ ctrl.$isEmpty(viewValue) ||
1349
+ isUndefined(maxVal) ||
1350
+ viewValue <= maxVal
1351
+ );
1352
+ };
1353
+
1354
+ setInitialValueAndObserver("max", maxChange);
1355
+ }
1356
+
1357
+ if (hasStepAttr) {
1358
+ stepVal = parseNumberAttrVal(attr.step);
1359
+
1360
+ ctrl.$validators.step = supportsRange
1361
+ ? function nativeStepValidator() {
1362
+ // Currently, only FF implements the spec on step change correctly (i.e. adjusting the
1363
+ // input element value to a valid value). It's possible that other browsers set the stepMismatch
1364
+ // validity error instead, so we can at least report an error in that case.
1365
+ return !validity.stepMismatch;
1366
+ }
1367
+ : // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would
1368
+ function stepValidator(modelValue, viewValue) {
1369
+ return (
1370
+ ctrl.$isEmpty(viewValue) ||
1371
+ isUndefined(stepVal) ||
1372
+ isValidForStep(viewValue, minVal || 0, stepVal)
1373
+ );
1374
+ };
1375
+
1376
+ setInitialValueAndObserver("step", stepChange);
1377
+ }
1378
+
1379
+ function setInitialValueAndObserver(htmlAttrName, changeFn) {
1380
+ // interpolated attributes set the attribute value only after a digest, but we need the
1381
+ // attribute value when the input is first rendered, so that the browser can adjust the
1382
+ // input value based on the min/max value
1383
+ element.attr(htmlAttrName, attr[htmlAttrName]);
1384
+ let oldVal = attr[htmlAttrName];
1385
+ attr.$observe(htmlAttrName, (val) => {
1386
+ if (val !== oldVal) {
1387
+ oldVal = val;
1388
+ changeFn(val);
1389
+ }
1390
+ });
1391
+ }
1392
+
1393
+ function minChange(val) {
1394
+ minVal = parseNumberAttrVal(val);
1395
+ // ignore changes before model is initialized
1396
+ if (isNumberNaN(ctrl.$modelValue)) {
1397
+ return;
1398
+ }
1399
+
1400
+ if (supportsRange) {
1401
+ let elVal = element.val();
1402
+ // IE11 doesn't set the el val correctly if the minVal is greater than the element value
1403
+ if (minVal > elVal) {
1404
+ elVal = minVal;
1405
+ element.val(elVal);
1406
+ }
1407
+ ctrl.$setViewValue(elVal);
1408
+ } else {
1409
+ // TODO(matsko): implement validateLater to reduce number of validations
1410
+ ctrl.$validate();
1411
+ }
1412
+ }
1413
+
1414
+ function maxChange(val) {
1415
+ maxVal = parseNumberAttrVal(val);
1416
+ // ignore changes before model is initialized
1417
+ if (isNumberNaN(ctrl.$modelValue)) {
1418
+ return;
1419
+ }
1420
+
1421
+ if (supportsRange) {
1422
+ let elVal = element.val();
1423
+ // IE11 doesn't set the el val correctly if the maxVal is less than the element value
1424
+ if (maxVal < elVal) {
1425
+ element.val(maxVal);
1426
+ // IE11 and Chrome don't set the value to the minVal when max < min
1427
+ elVal = maxVal < minVal ? minVal : maxVal;
1428
+ }
1429
+ ctrl.$setViewValue(elVal);
1430
+ } else {
1431
+ // TODO(matsko): implement validateLater to reduce number of validations
1432
+ ctrl.$validate();
1433
+ }
1434
+ }
1435
+
1436
+ function stepChange(val) {
1437
+ stepVal = parseNumberAttrVal(val);
1438
+ // ignore changes before model is initialized
1439
+ if (isNumberNaN(ctrl.$modelValue)) {
1440
+ return;
1441
+ }
1442
+
1443
+ // Some browsers don't adjust the input value correctly, but set the stepMismatch error
1444
+ if (!supportsRange) {
1445
+ // TODO(matsko): implement validateLater to reduce number of validations
1446
+ ctrl.$validate();
1447
+ } else if (ctrl.$viewValue !== element.val()) {
1448
+ ctrl.$setViewValue(element.val());
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ function urlInputType(scope, element, attr, ctrl, $browser) {
1454
+ // Note: no badInputChecker here by purpose as `url` is only a validation
1455
+ // in browsers, i.e. we can always read out input.value even if it is not valid!
1456
+ baseInputType(scope, element, attr, ctrl, $browser);
1457
+ stringBasedInputType(ctrl);
1458
+
1459
+ ctrl.$validators.url = function (modelValue, viewValue) {
1460
+ const value = modelValue || viewValue;
1461
+ return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
1462
+ };
1463
+ }
1464
+
1465
+ function emailInputType(scope, element, attr, ctrl, $browser) {
1466
+ // Note: no badInputChecker here by purpose as `url` is only a validation
1467
+ // in browsers, i.e. we can always read out input.value even if it is not valid!
1468
+ baseInputType(scope, element, attr, ctrl, $browser);
1469
+ stringBasedInputType(ctrl);
1470
+
1471
+ ctrl.$validators.email = function (modelValue, viewValue) {
1472
+ const value = modelValue || viewValue;
1473
+ return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
1474
+ };
1475
+ }
1476
+
1477
+ function radioInputType(scope, element, attr, ctrl) {
1478
+ const doTrim = !attr.ngTrim || trim(attr.ngTrim) !== "false";
1479
+ // make the name unique, if not defined
1480
+ if (isUndefined(attr.name)) {
1481
+ element.attr("name", nextUid());
1482
+ }
1483
+
1484
+ const listener = function (ev) {
1485
+ let value;
1486
+ if (element[0].checked) {
1487
+ value = attr.value;
1488
+ if (doTrim) {
1489
+ value = trim(value);
1490
+ }
1491
+ ctrl.$setViewValue(value, ev && ev.type);
1492
+ }
1493
+ };
1494
+
1495
+ element.on("change", listener);
1496
+
1497
+ ctrl.$render = function () {
1498
+ let { value } = attr;
1499
+ if (doTrim) {
1500
+ value = trim(value);
1501
+ }
1502
+ element[0].checked = value === ctrl.$viewValue;
1503
+ };
1504
+
1505
+ attr.$observe("value", ctrl.$render);
1506
+ }
1507
+
1508
+ function parseConstantExpr($parse, context, name, expression, fallback) {
1509
+ let parseFn;
1510
+ if (isDefined(expression)) {
1511
+ parseFn = $parse(expression);
1512
+ if (!parseFn.constant) {
1513
+ throw ngModelMinErr(
1514
+ "constexpr",
1515
+ "Expected constant expression for `{0}`, but saw " + "`{1}`.",
1516
+ name,
1517
+ expression,
1518
+ );
1519
+ }
1520
+ return parseFn(context);
1521
+ }
1522
+ return fallback;
1523
+ }
1524
+
1525
+ function checkboxInputType(
1526
+ scope,
1527
+ element,
1528
+ attr,
1529
+ ctrl,
1530
+ $browser,
1531
+ $filter,
1532
+ $parse,
1533
+ ) {
1534
+ const trueValue = parseConstantExpr(
1535
+ $parse,
1536
+ scope,
1537
+ "ngTrueValue",
1538
+ attr.ngTrueValue,
1539
+ true,
1540
+ );
1541
+ const falseValue = parseConstantExpr(
1542
+ $parse,
1543
+ scope,
1544
+ "ngFalseValue",
1545
+ attr.ngFalseValue,
1546
+ false,
1547
+ );
1548
+
1549
+ const listener = function (ev) {
1550
+ ctrl.$setViewValue(element[0].checked, ev && ev.type);
1551
+ };
1552
+
1553
+ element.on("change", listener);
1554
+
1555
+ ctrl.$render = function () {
1556
+ element[0].checked = ctrl.$viewValue;
1557
+ };
1558
+
1559
+ // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
1560
+ // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
1561
+ // it to a boolean.
1562
+ ctrl.$isEmpty = function (value) {
1563
+ return value === false;
1564
+ };
1565
+
1566
+ ctrl.$formatters.push((value) => equals(value, trueValue));
1567
+
1568
+ ctrl.$parsers.push((value) => (value ? trueValue : falseValue));
1569
+ }
1570
+
1571
+ /**
1572
+ * @ngdoc directive
1573
+ * @name textarea
1574
+ * @restrict E
1575
+ *
1576
+ * @description
1577
+ * HTML textarea element control with AngularJS data-binding. The data-binding and validation
1578
+ * properties of this element are exactly the same as those of the
1579
+ * {@link ng.directive:input input element}.
1580
+ *
1581
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
1582
+ * @param {string=} name Property name of the form under which the control is published.
1583
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
1584
+ * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
1585
+ * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
1586
+ * `required` when you want to data-bind to the `required` attribute.
1587
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
1588
+ * minlength.
1589
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
1590
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
1591
+ * length.
1592
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
1593
+ * does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
1594
+ * If the expression evaluates to a RegExp object, then this is used directly.
1595
+ * If the expression evaluates to a string, then it will be converted to a RegExp
1596
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
1597
+ * `new RegExp('^abc$')`.<br />
1598
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
1599
+ * start at the index of the last search's match, thus not taking the whole input value into
1600
+ * account.
1601
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
1602
+ * interaction with the input element.
1603
+ * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
1604
+ *
1605
+ * @knownIssue
1606
+ *
1607
+ * When specifying the `placeholder` attribute of `<textarea>`, Internet Explorer will temporarily
1608
+ * insert the placeholder value as the textarea's content. If the placeholder value contains
1609
+ * interpolation (`{{ ... }}`), an error will be logged in the console when AngularJS tries to update
1610
+ * the value of the by-then-removed text node. This doesn't affect the functionality of the
1611
+ * textarea, but can be undesirable.
1612
+ *
1613
+ * You can work around this Internet Explorer issue by using `ng-attr-placeholder` instead of
1614
+ * `placeholder` on textareas, whenever you need interpolation in the placeholder value. You can
1615
+ * find more details on `ngAttr` in the
1616
+ * [Interpolation](guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes) section of the
1617
+ * Developer Guide.
1618
+ */
1619
+
1620
+ /**
1621
+ * @ngdoc directive
1622
+ * @name input
1623
+ * @restrict E
1624
+ *
1625
+ * @description
1626
+ * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
1627
+ * input state control, and validation.
1628
+ * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
1629
+ *
1630
+ * <div class="alert alert-warning">
1631
+ * **Note:** Not every feature offered is available for all input types.
1632
+ * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
1633
+ * </div>
1634
+ *
1635
+ * @param {string} ngModel Assignable AngularJS expression to data-bind to.
1636
+ * @param {string=} name Property name of the form under which the control is published.
1637
+ * @param {string=} required Sets `required` validation error key if the value is not entered.
1638
+ * @param {boolean=} ngRequired Sets `required` attribute if set to true
1639
+ * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
1640
+ * minlength.
1641
+ * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
1642
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
1643
+ * length.
1644
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
1645
+ * value does not match a RegExp found by evaluating the AngularJS expression given in the attribute value.
1646
+ * If the expression evaluates to a RegExp object, then this is used directly.
1647
+ * If the expression evaluates to a string, then it will be converted to a RegExp
1648
+ * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
1649
+ * `new RegExp('^abc$')`.<br />
1650
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
1651
+ * start at the index of the last search's match, thus not taking the whole input value into
1652
+ * account.
1653
+ * @param {string=} ngChange AngularJS expression to be executed when input changes due to user
1654
+ * interaction with the input element.
1655
+ * @param {boolean=} [ngTrim=true] If set to false AngularJS will not automatically trim the input.
1656
+ * This parameter is ignored for input[type=password] controls, which will never trim the
1657
+ * input.
1658
+ *
1659
+ */
1660
+ export const inputDirective = [
1661
+ "$browser",
1662
+ "$filter",
1663
+ "$parse",
1664
+ function ($browser, $filter, $parse) {
1665
+ return {
1666
+ restrict: "E",
1667
+ require: ["?ngModel"],
1668
+ link: {
1669
+ pre(scope, element, attr, ctrls) {
1670
+ if (ctrls[0]) {
1671
+ (inputType[lowercase(attr.type)] || inputType.text)(
1672
+ scope,
1673
+ element,
1674
+ attr,
1675
+ ctrls[0],
1676
+ $browser,
1677
+ $filter,
1678
+ $parse,
1679
+ );
1680
+ }
1681
+ },
1682
+ },
1683
+ };
1684
+ },
1685
+ ];
1686
+
1687
+ export function hiddenInputBrowserCacheDirective() {
1688
+ const valueProperty = {
1689
+ configurable: true,
1690
+ enumerable: false,
1691
+ get() {
1692
+ return this.getAttribute("value") || "";
1693
+ },
1694
+ set(val) {
1695
+ this.setAttribute("value", val);
1696
+ },
1697
+ };
1698
+
1699
+ return {
1700
+ restrict: "E",
1701
+ priority: 200,
1702
+ compile(_, attr) {
1703
+ if (lowercase(attr.type) !== "hidden") {
1704
+ return;
1705
+ }
1706
+
1707
+ return {
1708
+ pre(scope, element) {
1709
+ const node = element[0];
1710
+
1711
+ // Support: Edge
1712
+ // Moving the DOM around prevents autofillling
1713
+ if (node.parentNode) {
1714
+ node.parentNode.insertBefore(node, node.nextSibling);
1715
+ }
1716
+
1717
+ // Support: FF, IE
1718
+ // Avoiding direct assignment to .value prevents autofillling
1719
+ if (Object.defineProperty) {
1720
+ Object.defineProperty(node, "value", valueProperty);
1721
+ }
1722
+ },
1723
+ };
1724
+ },
1725
+ };
1726
+ }
1727
+
1728
+ const CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
1729
+ /**
1730
+ * @ngdoc directive
1731
+ * @name ngValue
1732
+ * @restrict A
1733
+ * @priority 100
1734
+ *
1735
+ * @description
1736
+ * Binds the given expression to the value of the element.
1737
+ *
1738
+ * It is mainly used on {@link input[radio] `input[radio]`} and option elements,
1739
+ * so that when the element is selected, the {@link ngModel `ngModel`} of that element (or its
1740
+ * {@link select `select`} parent element) is set to the bound value. It is especially useful
1741
+ * for dynamically generated lists using {@link ngRepeat `ngRepeat`}, as shown below.
1742
+ *
1743
+ * It can also be used to achieve one-way binding of a given expression to an input element
1744
+ * such as an `input[text]` or a `textarea`, when that element does not use ngModel.
1745
+ *
1746
+ * @element ANY
1747
+ * @param {string=} ngValue AngularJS expression, whose value will be bound to the `value` attribute
1748
+ * and `value` property of the element.
1749
+ *
1750
+ */
1751
+ export function ngValueDirective() {
1752
+ /**
1753
+ * inputs use the value attribute as their default value if the value property is not set.
1754
+ * Once the value property has been set (by adding input), it will not react to changes to
1755
+ * the value attribute anymore. Setting both attribute and property fixes this behavior, and
1756
+ * makes it possible to use ngValue as a sort of one-way bind.
1757
+ */
1758
+ function updateElementValue(element, attr, value) {
1759
+ // Support: IE9 only
1760
+ // In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
1761
+ const propValue = isDefined(value) ? value : null;
1762
+ element.prop("value", propValue);
1763
+ attr.$set("value", value);
1764
+ }
1765
+
1766
+ return {
1767
+ restrict: "A",
1768
+ priority: 100,
1769
+ compile(tpl, tplAttr) {
1770
+ if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
1771
+ return function ngValueConstantLink(scope, elm, attr) {
1772
+ const value = scope.$eval(attr.ngValue);
1773
+ updateElementValue(elm, attr, value);
1774
+ };
1775
+ }
1776
+ return function ngValueLink(scope, elm, attr) {
1777
+ scope.$watch(attr.ngValue, (value) => {
1778
+ updateElementValue(elm, attr, value);
1779
+ });
1780
+ };
1781
+ },
1782
+ };
1783
+ }