@tko/binding.core 4.0.0-alpha8.0 → 4.0.0-beta1.0

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 (53) hide show
  1. package/dist/attr.js +36 -0
  2. package/dist/attr.js.map +7 -0
  3. package/dist/checked.js +94 -0
  4. package/dist/checked.js.map +7 -0
  5. package/dist/click.js +5 -0
  6. package/dist/click.js.map +7 -0
  7. package/dist/css.js +28 -0
  8. package/dist/css.js.map +7 -0
  9. package/dist/descendantsComplete.js +14 -0
  10. package/dist/descendantsComplete.js.map +7 -0
  11. package/dist/enableDisable.js +21 -0
  12. package/dist/enableDisable.js.map +7 -0
  13. package/dist/event.js +75 -0
  14. package/dist/event.js.map +7 -0
  15. package/dist/hasfocus.js +48 -0
  16. package/dist/hasfocus.js.map +7 -0
  17. package/dist/html.js +15 -0
  18. package/dist/html.js.map +7 -0
  19. package/dist/index.cjs +3956 -0
  20. package/dist/index.cjs.map +7 -0
  21. package/dist/index.js +50 -0
  22. package/dist/index.js.map +7 -0
  23. package/dist/index.mjs +50 -0
  24. package/dist/index.mjs.map +7 -0
  25. package/dist/let.js +12 -0
  26. package/dist/let.js.map +7 -0
  27. package/dist/options.js +130 -0
  28. package/dist/options.js.map +7 -0
  29. package/dist/selectedOptions.js +41 -0
  30. package/dist/selectedOptions.js.map +7 -0
  31. package/dist/style.js +30 -0
  32. package/dist/style.js.map +7 -0
  33. package/dist/submit.js +26 -0
  34. package/dist/submit.js.map +7 -0
  35. package/dist/test-helper.js +14 -0
  36. package/dist/test-helper.js.map +7 -0
  37. package/dist/text.js +13 -0
  38. package/dist/text.js.map +7 -0
  39. package/dist/textInput.js +151 -0
  40. package/dist/textInput.js.map +7 -0
  41. package/dist/uniqueName.js +13 -0
  42. package/dist/uniqueName.js.map +7 -0
  43. package/dist/using.js +12 -0
  44. package/dist/using.js.map +7 -0
  45. package/dist/value.js +103 -0
  46. package/dist/value.js.map +7 -0
  47. package/dist/visible.js +20 -0
  48. package/dist/visible.js.map +7 -0
  49. package/package.json +18 -28
  50. package/dist/binding.core.es6.js +0 -1044
  51. package/dist/binding.core.es6.js.map +0 -1
  52. package/dist/binding.core.js +0 -1143
  53. package/dist/binding.core.js.map +0 -1
@@ -1,1143 +0,0 @@
1
- /*!
2
- * TKO Core bindings 🥊 @tko/binding.core@4.0.0-alpha8.0
3
- * (c) The Knockout.js Team - https://tko.io
4
- * License: MIT (http://www.opensource.org/licenses/mit-license.php)
5
- */
6
-
7
- import { setElementName, objectForEach, registerEventHandler, arrayIndexOf, addOrRemoveItem, throttle, debounce, createSymbolOrString, toggleDomNodeCssClass, stringTrim, triggerEvent, setHtml, tagNameLower, arrayFilter, arrayMap, setTextContent, setOptionNodeSelectionState, ensureSelectElementIsRenderedCorrectly, selectExtensions, arrayForEach, options, domData, ieVersion, safeSetTimeout, stringStartsWith } from '@tko/utils';
8
- import { unwrap, dependencyDetection, isWriteableObservable } from '@tko/observable';
9
- import { computed, pureComputed } from '@tko/computed';
10
- import { BindingHandler, applyBindingsToDescendants, setDomNodeChildrenFromArrayMapping, applyBindingAccessorsToNode } from '@tko/bind';
11
-
12
- var attr = {
13
- update: function (element, valueAccessor, allBindings) {
14
- var value = unwrap(valueAccessor()) || {};
15
- objectForEach(value, function (attrName, attrValue) {
16
- attrValue = unwrap(attrValue);
17
- // Find the namespace of this attribute, if any.
18
- var prefixLen = attrName.indexOf(':');
19
- var namespace = prefixLen > 0 && element.lookupNamespaceURI(attrName.substr(0, prefixLen));
20
- // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
21
- // when someProp is a "no value"-like value (strictly null, false, or undefined)
22
- // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
23
- var toRemove = attrValue === false || attrValue === null || attrValue === undefined;
24
- if (toRemove) {
25
- if (namespace) {
26
- element.removeAttributeNS(namespace, attrName);
27
- }
28
- else {
29
- element.removeAttribute(attrName);
30
- }
31
- }
32
- else {
33
- attrValue = attrValue.toString();
34
- if (namespace) {
35
- element.setAttributeNS(namespace, attrName, attrValue);
36
- }
37
- else {
38
- element.setAttribute(attrName, attrValue);
39
- }
40
- }
41
- // Treat "name" specially - although you can think of it as an attribute, it also needs
42
- // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
43
- // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
44
- // entirely, and there's no strong reason to allow for such casing in HTML.
45
- if (attrName === 'name') {
46
- setElementName(element, toRemove ? '' : attrValue);
47
- }
48
- });
49
- }
50
- };
51
-
52
- var checked = {
53
- after: ['value', 'attr'],
54
- init: function (element, valueAccessor, allBindings) {
55
- var checkedValue = pureComputed(function () {
56
- // Treat "value" like "checkedValue" when it is included with "checked" binding
57
- if (allBindings.has('checkedValue')) {
58
- return unwrap(allBindings.get('checkedValue'));
59
- }
60
- else if (useElementValue) {
61
- if (allBindings.has('value')) {
62
- return unwrap(allBindings.get('value'));
63
- }
64
- else {
65
- return element.value;
66
- }
67
- }
68
- });
69
- function updateModel() {
70
- // This updates the model value from the view value.
71
- // It runs in response to DOM events (click) and changes in checkedValue.
72
- var isChecked = element.checked, elemValue = checkedValue();
73
- // When we're first setting up this computed, don't change any model state.
74
- if (dependencyDetection.isInitial()) {
75
- return;
76
- }
77
- // We can ignore unchecked radio buttons, because some other radio
78
- // button will be checked, and that one can take care of updating state.
79
- // button will be checked, and that one can take care of updating state
80
- if (!isChecked && (isRadio || dependencyDetection.getDependenciesCount())) {
81
- return;
82
- }
83
- var modelValue = dependencyDetection.ignore(valueAccessor);
84
- if (valueIsArray) {
85
- var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue, saveOldValue = oldElemValue;
86
- oldElemValue = elemValue;
87
- if (saveOldValue !== elemValue) {
88
- // When we're responding to the checkedValue changing, and the element is
89
- // currently checked, replace the old elem value with the new elem value
90
- // in the model array.
91
- if (isChecked) {
92
- addOrRemoveItem(writableValue, elemValue, true);
93
- addOrRemoveItem(writableValue, saveOldValue, false);
94
- }
95
- oldElemValue = elemValue;
96
- }
97
- else {
98
- // When we're responding to the user having checked/unchecked a checkbox,
99
- // add/remove the element value to the model array.
100
- addOrRemoveItem(writableValue, elemValue, isChecked);
101
- }
102
- if (rawValueIsNonArrayObservable && isWriteableObservable(modelValue)) {
103
- modelValue(writableValue);
104
- }
105
- }
106
- else {
107
- if (isCheckbox) {
108
- if (elemValue === undefined) {
109
- elemValue = isChecked;
110
- }
111
- else if (!isChecked) {
112
- elemValue = undefined;
113
- }
114
- }
115
- valueAccessor(elemValue, { onlyIfChanged: true });
116
- }
117
- }
118
- function updateView() {
119
- // This updates the view value from the model value.
120
- // It runs in response to changes in the bound (checked) value.
121
- var modelValue = modelValue = unwrap(valueAccessor());
122
- var elemValue = checkedValue();
123
- if (valueIsArray) {
124
- // When a checkbox is bound to an array, being checked represents its value being present in that array
125
- element.checked = arrayIndexOf(modelValue, elemValue) >= 0;
126
- oldElemValue = elemValue;
127
- }
128
- else if (isCheckbox && elemValue === undefined) {
129
- // When a checkbox is bound to any other value (not an array) and "checkedValue" is not defined,
130
- // being checked represents the value being trueish
131
- element.checked = !!modelValue;
132
- }
133
- else {
134
- // Otherwise, being checked means that the checkbox or radio button's value corresponds to the model value
135
- element.checked = (checkedValue() === modelValue);
136
- }
137
- }
138
- var isCheckbox = element.type == 'checkbox', isRadio = element.type == 'radio';
139
- // Only bind to check boxes and radio buttons
140
- if (!isCheckbox && !isRadio) {
141
- return;
142
- }
143
- var rawValue = valueAccessor(), valueIsArray = isCheckbox && (unwrap(rawValue) instanceof Array), rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice), useElementValue = isRadio || valueIsArray, oldElemValue = valueIsArray ? checkedValue() : undefined;
144
- // Set up two computeds to update the binding:
145
- // The first responds to changes in the checkedValue value and to element clicks
146
- computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
147
- registerEventHandler(element, 'click', updateModel);
148
- // The second responds to changes in the model value (the one associated with the checked binding)
149
- computed(updateView, null, { disposeWhenNodeIsRemoved: element });
150
- rawValue = undefined;
151
- }
152
- };
153
- var checkedValue = {
154
- update: function (element, valueAccessor) {
155
- element.value = unwrap(valueAccessor());
156
- }
157
- };
158
-
159
- /*! *****************************************************************************
160
- Copyright (c) Microsoft Corporation. All rights reserved.
161
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
162
- this file except in compliance with the License. You may obtain a copy of the
163
- License at http://www.apache.org/licenses/LICENSE-2.0
164
-
165
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
166
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
167
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
168
- MERCHANTABLITY OR NON-INFRINGEMENT.
169
-
170
- See the Apache Version 2.0 License for specific language governing permissions
171
- and limitations under the License.
172
- ***************************************************************************** */
173
- /* global Reflect, Promise */
174
-
175
- var extendStatics = Object.setPrototypeOf ||
176
- ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
177
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
178
-
179
- function __extends(d, b) {
180
- extendStatics(d, b);
181
- function __() { this.constructor = d; }
182
- d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
183
- }
184
-
185
- function __values(o) {
186
- var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
187
- if (m) return m.call(o);
188
- return {
189
- next: function () {
190
- if (o && i >= o.length) o = void 0;
191
- return { value: o && o[i++], done: !o };
192
- }
193
- };
194
- }
195
-
196
- function __read(o, n) {
197
- var m = typeof Symbol === "function" && o[Symbol.iterator];
198
- if (!m) return o;
199
- var i = m.call(o), r, ar = [], e;
200
- try {
201
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
202
- }
203
- catch (error) { e = { error: error }; }
204
- finally {
205
- try {
206
- if (r && !r.done && (m = i["return"])) m.call(i);
207
- }
208
- finally { if (e) throw e.error; }
209
- }
210
- return ar;
211
- }
212
-
213
- function __spread() {
214
- for (var ar = [], i = 0; i < arguments.length; i++)
215
- ar = ar.concat(__read(arguments[i]));
216
- return ar;
217
- }
218
-
219
- // For certain common events (currently just 'click'), allow a simplified data-binding syntax
220
- // e.g. click:handler instead of the usual full-length event:{click:handler}
221
- function makeEventHandlerShortcut(eventName) {
222
- return {
223
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
224
- var newValueAccessor = function () {
225
- var result = {};
226
- result[eventName] = valueAccessor();
227
- return result;
228
- };
229
- eventHandler.init.call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
230
- }
231
- };
232
- }
233
- function makeDescriptor(handlerOrObject) {
234
- return typeof handlerOrObject === 'function' ? { handler: handlerOrObject } : handlerOrObject || {};
235
- }
236
- var eventHandler = {
237
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
238
- var eventsToHandle = valueAccessor() || {};
239
- objectForEach(eventsToHandle, function (eventName, descriptor) {
240
- var _a = makeDescriptor(descriptor), passive = _a.passive, capture = _a.capture, once = _a.once, debounce$$1 = _a.debounce, throttle$$1 = _a.throttle;
241
- var eventOptions = (capture || passive || once) && { capture: capture, passive: passive, once: once };
242
- var eventHandlerFn = function (event) {
243
- var more = [];
244
- for (var _i = 1; _i < arguments.length; _i++) {
245
- more[_i - 1] = arguments[_i];
246
- }
247
- var handlerReturnValue;
248
- var _a = makeDescriptor(valueAccessor()[eventName]), handler = _a.handler, passive = _a.passive, bubble = _a.bubble;
249
- try {
250
- // Take all the event args, and prefix with the viewmodel
251
- if (handler) {
252
- var possiblyUpdatedViewModel = bindingContext.$data;
253
- var argsForHandler = __spread([possiblyUpdatedViewModel, event], more);
254
- handlerReturnValue = handler.apply(possiblyUpdatedViewModel, argsForHandler);
255
- }
256
- }
257
- finally {
258
- if (handlerReturnValue !== true) {
259
- // Normally we want to prevent default action. Developer can override this be explicitly returning true.
260
- // preventDefault will throw an error if the event is passive.
261
- if (event.preventDefault) {
262
- if (!passive) {
263
- event.preventDefault();
264
- }
265
- }
266
- else {
267
- event.returnValue = false;
268
- }
269
- }
270
- }
271
- var bubbleMark = allBindings.get(eventName + 'Bubble') !== false;
272
- if (bubble === false || !bubbleMark) {
273
- event.cancelBubble = true;
274
- if (event.stopPropagation) {
275
- event.stopPropagation();
276
- }
277
- }
278
- };
279
- if (debounce$$1) {
280
- eventHandlerFn = debounce(eventHandlerFn, debounce$$1);
281
- }
282
- if (throttle$$1) {
283
- eventHandlerFn = throttle(eventHandlerFn, throttle$$1);
284
- }
285
- registerEventHandler(element, eventName, eventHandlerFn, eventOptions || false);
286
- });
287
- }
288
- };
289
- var onHandler = {
290
- init: eventHandler.init,
291
- preprocess: function (value, key, addBinding) {
292
- addBinding(key.replace('on.', ''), '=>' + value);
293
- }
294
- };
295
-
296
- // 'click' is just a shorthand for the usual full-length event:{click:handler}
297
- var click = makeEventHandlerShortcut('click');
298
-
299
- var css = {
300
- aliases: ['class'],
301
- update: function (element, valueAccessor) {
302
- var value = unwrap(valueAccessor());
303
- if (value !== null && typeof value === 'object') {
304
- objectForEach(value, function (className, shouldHaveClass) {
305
- shouldHaveClass = unwrap(shouldHaveClass);
306
- toggleDomNodeCssClass(element, className, shouldHaveClass);
307
- });
308
- }
309
- else {
310
- value = stringTrim(String(value || '')); // Make sure we don't try to store or set a non-string value
311
- toggleDomNodeCssClass(element, element[css.classesWrittenByBindingKey], false);
312
- element[css.classesWrittenByBindingKey] = value;
313
- toggleDomNodeCssClass(element, value, true);
314
- }
315
- },
316
- classesWrittenByBindingKey: createSymbolOrString('__ko__cssValue')
317
- };
318
-
319
- var DescendantsCompleteHandler = /** @class */ (function (_super) {
320
- __extends(DescendantsCompleteHandler, _super);
321
- function DescendantsCompleteHandler() {
322
- return _super !== null && _super.apply(this, arguments) || this;
323
- }
324
- DescendantsCompleteHandler.prototype.onDescendantsComplete = function () {
325
- if (typeof this.value === 'function') {
326
- this.value(this.$element);
327
- }
328
- };
329
- Object.defineProperty(DescendantsCompleteHandler, "allowVirtualElements", {
330
- get: function () { return true; },
331
- enumerable: true,
332
- configurable: true
333
- });
334
- return DescendantsCompleteHandler;
335
- }(BindingHandler));
336
-
337
- var enable = {
338
- update: function (element, valueAccessor) {
339
- var value = unwrap(valueAccessor());
340
- if (value && element.disabled) {
341
- element.removeAttribute('disabled');
342
- }
343
- else if ((!value) && (!element.disabled)) {
344
- element.disabled = true;
345
- }
346
- }
347
- };
348
- var disable = {
349
- update: function (element, valueAccessor) {
350
- enable.update(element, function () { return !unwrap(valueAccessor()); });
351
- }
352
- };
353
-
354
- var hasfocusUpdatingProperty = createSymbolOrString('__ko_hasfocusUpdating');
355
- var hasfocusLastValue = createSymbolOrString('__ko_hasfocusLastValue');
356
- var hasfocus = {
357
- init: function (element, valueAccessor /*, allBindings */) {
358
- var handleElementFocusChange = function (isFocused) {
359
- // Where possible, ignore which event was raised and determine focus state using activeElement,
360
- // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
361
- // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
362
- // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
363
- // from calling 'blur()' on the element when it loses focus.
364
- // Discussion at https://github.com/SteveSanderson/knockout/pull/352
365
- element[hasfocusUpdatingProperty] = true;
366
- var ownerDoc = element.ownerDocument;
367
- if ('activeElement' in ownerDoc) {
368
- var active;
369
- try {
370
- active = ownerDoc.activeElement;
371
- }
372
- catch (e) {
373
- // IE9 throws if you access activeElement during page load (see issue #703)
374
- active = ownerDoc.body;
375
- }
376
- isFocused = (active === element);
377
- }
378
- // var modelValue = valueAccessor();
379
- valueAccessor(isFocused, { onlyIfChanged: true });
380
- // cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function
381
- element[hasfocusLastValue] = isFocused;
382
- element[hasfocusUpdatingProperty] = false;
383
- };
384
- var handleElementFocusIn = handleElementFocusChange.bind(null, true);
385
- var handleElementFocusOut = handleElementFocusChange.bind(null, false);
386
- registerEventHandler(element, 'focus', handleElementFocusIn);
387
- registerEventHandler(element, 'focusin', handleElementFocusIn); // For IE
388
- registerEventHandler(element, 'blur', handleElementFocusOut);
389
- registerEventHandler(element, 'focusout', handleElementFocusOut); // For IE
390
- },
391
- update: function (element, valueAccessor) {
392
- var value = !!unwrap(valueAccessor());
393
- if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {
394
- value ? element.focus() : element.blur();
395
- // In IE, the blur method doesn't always cause the element to lose focus (for example, if the window is not in focus).
396
- // Setting focus to the body element does seem to be reliable in IE, but should only be used if we know that the current
397
- // element was focused already.
398
- if (!value && element[hasfocusLastValue]) {
399
- element.ownerDocument.body.focus();
400
- }
401
- // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
402
- dependencyDetection.ignore(triggerEvent, null, [element, value ? 'focusin' : 'focusout']);
403
- }
404
- }
405
- };
406
-
407
- var html = {
408
- init: function () {
409
- // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
410
- return {
411
- 'controlsDescendantBindings': true
412
- };
413
- },
414
- //
415
- // Modify internal, per ko.punches and :
416
- // http://stackoverflow.com/a/15348139
417
- update: function (element, valueAccessor) {
418
- setHtml(element, valueAccessor());
419
- },
420
- allowVirtualElements: true
421
- };
422
-
423
- var $let = {
424
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
425
- // Make a modified binding context, with extra properties, and apply it to descendant elements
426
- var innerContext = bindingContext['extend'](valueAccessor);
427
- applyBindingsToDescendants(innerContext, element);
428
- return { 'controlsDescendantBindings': true };
429
- },
430
- allowVirtualElements: true
431
- };
432
-
433
- var captionPlaceholder = {};
434
- var options$1 = {
435
- init: function (element) {
436
- if (tagNameLower(element) !== 'select') {
437
- throw new Error('options binding applies only to SELECT elements');
438
- }
439
- // Remove all existing <option>s.
440
- while (element.length > 0) {
441
- element.remove(0);
442
- }
443
- // Ensures that the binding processor doesn't try to bind the options
444
- return { 'controlsDescendantBindings': true };
445
- },
446
- update: function (element, valueAccessor, allBindings) {
447
- function selectedOptions() {
448
- return arrayFilter(element.options, function (node) { return node.selected; });
449
- }
450
- var selectWasPreviouslyEmpty = element.length == 0, multiple = element.multiple, previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null, unwrappedArray = unwrap(valueAccessor()), valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'), includeDestroyed = allBindings.get('optionsIncludeDestroyed'), arrayToDomNodeChildrenOptions = {}, captionValue, filteredArray, previousSelectedValues = [];
451
- if (!valueAllowUnset) {
452
- if (multiple) {
453
- previousSelectedValues = arrayMap(selectedOptions(), selectExtensions.readValue);
454
- }
455
- else if (element.selectedIndex >= 0) {
456
- previousSelectedValues.push(selectExtensions.readValue(element.options[element.selectedIndex]));
457
- }
458
- }
459
- if (unwrappedArray) {
460
- if (typeof unwrappedArray.length === 'undefined') // Coerce single value into array
461
- {
462
- unwrappedArray = [unwrappedArray];
463
- }
464
- // Filter out any entries marked as destroyed
465
- filteredArray = arrayFilter(unwrappedArray, function (item) {
466
- return includeDestroyed || item === undefined || item === null || !unwrap(item['_destroy']);
467
- });
468
- // If caption is included, add it to the array
469
- if (allBindings['has']('optionsCaption')) {
470
- captionValue = unwrap(allBindings.get('optionsCaption'));
471
- // If caption value is null or undefined, don't show a caption
472
- if (captionValue !== null && captionValue !== undefined) {
473
- filteredArray.unshift(captionPlaceholder);
474
- }
475
- }
476
- }
477
- function applyToObject(object, predicate, defaultValue) {
478
- var predicateType = typeof predicate;
479
- if (predicateType == 'function') // Given a function; run it against the data value
480
- {
481
- return predicate(object);
482
- }
483
- else if (predicateType == 'string') // Given a string; treat it as a property name on the data value
484
- {
485
- return object[predicate];
486
- }
487
- else // Given no optionsText arg; use the data value itself
488
- {
489
- return defaultValue;
490
- }
491
- }
492
- // The following functions can run at two different times:
493
- // The first is when the whole array is being updated directly from this binding handler.
494
- // The second is when an observable value for a specific array entry is updated.
495
- // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
496
- var itemUpdate = false;
497
- function optionForArrayItem(arrayEntry, index, oldOptions) {
498
- if (oldOptions.length) {
499
- previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [selectExtensions.readValue(oldOptions[0])] : [];
500
- itemUpdate = true;
501
- }
502
- var option = element.ownerDocument.createElement('option');
503
- if (arrayEntry === captionPlaceholder) {
504
- setTextContent(option, allBindings.get('optionsCaption'));
505
- selectExtensions.writeValue(option, undefined);
506
- }
507
- else {
508
- // Apply a value to the option element
509
- var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);
510
- selectExtensions.writeValue(option, unwrap(optionValue));
511
- // Apply some text to the option element
512
- var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);
513
- setTextContent(option, optionText);
514
- }
515
- return [option];
516
- }
517
- // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
518
- // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
519
- arrayToDomNodeChildrenOptions['beforeRemove'] =
520
- function (option) {
521
- element.removeChild(option);
522
- };
523
- function setSelectionCallback(arrayEntry, newOptions) {
524
- if (itemUpdate && valueAllowUnset) {
525
- // The model value is authoritative, so make sure its value is the one selected
526
- // There is no need to use dependencyDetection.ignore since setDomNodeChildrenFromArrayMapping does so already.
527
- selectExtensions.writeValue(element, unwrap(allBindings.get('value')), true /* allowUnset */);
528
- }
529
- else if (previousSelectedValues.length) {
530
- // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
531
- // That's why we first added them without selection. Now it's time to set the selection.
532
- var isSelected = arrayIndexOf(previousSelectedValues, selectExtensions.readValue(newOptions[0])) >= 0;
533
- setOptionNodeSelectionState(newOptions[0], isSelected);
534
- // If this option was changed from being selected during a single-item update, notify the change
535
- if (itemUpdate && !isSelected) {
536
- dependencyDetection.ignore(triggerEvent, null, [element, 'change']);
537
- }
538
- }
539
- }
540
- var callback = setSelectionCallback;
541
- if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') === 'function') {
542
- callback = function (arrayEntry, newOptions) {
543
- setSelectionCallback(arrayEntry, newOptions);
544
- dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
545
- };
546
- }
547
- setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);
548
- dependencyDetection.ignore(function () {
549
- if (valueAllowUnset) {
550
- // The model value is authoritative, so make sure its value is the one selected
551
- selectExtensions.writeValue(element, unwrap(allBindings.get('value')), true /* allowUnset */);
552
- }
553
- else {
554
- // Determine if the selection has changed as a result of updating the options list
555
- var selectionChanged;
556
- if (multiple) {
557
- // For a multiple-select box, compare the new selection count to the previous one
558
- // But if nothing was selected before, the selection can't have changed
559
- selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
560
- }
561
- else {
562
- // For a single-select box, compare the current value to the previous value
563
- // But if nothing was selected before or nothing is selected now, just look for a change in selection
564
- selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
565
- ? (selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
566
- : (previousSelectedValues.length || element.selectedIndex >= 0);
567
- }
568
- // Ensure consistency between model value and selected option.
569
- // If the dropdown was changed so that selection is no longer the same,
570
- // notify the value or selectedOptions binding.
571
- if (selectionChanged) {
572
- triggerEvent(element, 'change');
573
- }
574
- }
575
- });
576
- // Workaround for IE bug
577
- ensureSelectElementIsRenderedCorrectly(element);
578
- if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20) {
579
- element.scrollTop = previousScrollTop;
580
- }
581
- }
582
- };
583
-
584
- var selectedOptions = {
585
- after: ['options', 'foreach'],
586
- init: function (element, valueAccessor, allBindings) {
587
- registerEventHandler(element, 'change', function () {
588
- var value = valueAccessor(), valueToWrite = [];
589
- arrayForEach(element.getElementsByTagName('option'), function (node) {
590
- if (node.selected) {
591
- valueToWrite.push(selectExtensions.readValue(node));
592
- }
593
- });
594
- valueAccessor(valueToWrite);
595
- });
596
- },
597
- update: function (element, valueAccessor) {
598
- if (tagNameLower(element) != 'select') {
599
- throw new Error('values binding applies only to SELECT elements');
600
- }
601
- var newValue = unwrap(valueAccessor()), previousScrollTop = element.scrollTop;
602
- if (newValue && typeof newValue.length === 'number') {
603
- arrayForEach(element.getElementsByTagName('option'), function (node) {
604
- var isSelected = arrayIndexOf(newValue, selectExtensions.readValue(node)) >= 0;
605
- if (node.selected != isSelected) { // This check prevents flashing of the select element in IE
606
- setOptionNodeSelectionState(node, isSelected);
607
- }
608
- });
609
- }
610
- element.scrollTop = previousScrollTop;
611
- }
612
- };
613
-
614
- var jQueryInstance = options.jQueryInstance;
615
- var style = {
616
- update: function (element, valueAccessor) {
617
- var value = unwrap(valueAccessor() || {});
618
- objectForEach(value, function (styleName, styleValue) {
619
- styleValue = unwrap(styleValue);
620
- if (styleValue === null || styleValue === undefined || styleValue === false) {
621
- // Empty string removes the value, whereas null/undefined have no effect
622
- styleValue = '';
623
- }
624
- if (jQueryInstance) {
625
- jQueryInstance(element).css(styleName, styleValue);
626
- }
627
- else {
628
- styleName = styleName.replace(/-(\w)/g, function (all, letter) { return letter.toUpperCase(); });
629
- var previousStyle = element.style[styleName];
630
- element.style[styleName] = styleValue;
631
- if (styleValue !== previousStyle && element.style[styleName] === previousStyle && !isNaN(styleValue)) {
632
- element.style[styleName] = styleValue + 'px';
633
- }
634
- }
635
- });
636
- }
637
- };
638
-
639
- var submit = {
640
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
641
- if (typeof valueAccessor() !== 'function') {
642
- throw new Error('The value for a submit binding must be a function');
643
- }
644
- registerEventHandler(element, 'submit', function (event) {
645
- var handlerReturnValue;
646
- var value = valueAccessor();
647
- try {
648
- handlerReturnValue = value.call(bindingContext['$data'], element);
649
- }
650
- finally {
651
- if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
652
- if (event.preventDefault) {
653
- event.preventDefault();
654
- }
655
- else {
656
- event.returnValue = false;
657
- }
658
- }
659
- }
660
- });
661
- }
662
- };
663
-
664
- var text = {
665
- init: function () {
666
- // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
667
- // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
668
- return { controlsDescendantBindings: true };
669
- },
670
- update: function (element, valueAccessor) {
671
- setTextContent(element, valueAccessor());
672
- },
673
- allowVirtualElements: true
674
- };
675
-
676
- var operaVersion, safariVersion, firefoxVersion;
677
- /**
678
- * TextInput binding handler for modern browsers (legacy below).
679
- * @extends BindingHandler
680
- */
681
- var TextInput = /** @class */ (function (_super) {
682
- __extends(TextInput, _super);
683
- function TextInput() {
684
- var e_1, _a, e_2, _b;
685
- var args = [];
686
- for (var _i = 0; _i < arguments.length; _i++) {
687
- args[_i] = arguments[_i];
688
- }
689
- var _this = _super.apply(this, __spread(args)) || this;
690
- _this.previousElementValue = _this.$element.value;
691
- if (options.debug && _this.constructor._forceUpdateOn) {
692
- // Provide a way for tests to specify exactly which events are bound
693
- arrayForEach(_this.constructor._forceUpdateOn, function (eventName) {
694
- if (eventName.slice(0, 5) === 'after') {
695
- _this.addEventListener(eventName.slice(5), 'deferUpdateModel');
696
- }
697
- else {
698
- _this.addEventListener(eventName, 'updateModel');
699
- }
700
- });
701
- }
702
- try {
703
- for (var _c = __values(_this.eventsIndicatingSyncValueChange()), _d = _c.next(); !_d.done; _d = _c.next()) {
704
- var eventName = _d.value;
705
- _this.addEventListener(eventName, 'updateModel');
706
- }
707
- }
708
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
709
- finally {
710
- try {
711
- if (_d && !_d.done && (_a = _c["return"])) _a.call(_c);
712
- }
713
- finally { if (e_1) throw e_1.error; }
714
- }
715
- try {
716
- for (var _e = __values(_this.eventsIndicatingDeferValueChange()), _f = _e.next(); !_f.done; _f = _e.next()) {
717
- var eventName = _f.value;
718
- _this.addEventListener(eventName, 'deferUpdateModel');
719
- }
720
- }
721
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
722
- finally {
723
- try {
724
- if (_f && !_f.done && (_b = _e["return"])) _b.call(_e);
725
- }
726
- finally { if (e_2) throw e_2.error; }
727
- }
728
- _this.computed('updateView');
729
- return _this;
730
- }
731
- Object.defineProperty(TextInput.prototype, "aliases", {
732
- get: function () { return 'textinput'; },
733
- enumerable: true,
734
- configurable: true
735
- });
736
- TextInput.prototype.eventsIndicatingSyncValueChange = function () {
737
- // input: Default, modern handler
738
- // change: Catch programmatic updates of the value that fire this event.
739
- // blur: To deal with browsers that don't notify any kind of event for some changes (IE, Safari, etc.)
740
- return ['input', 'change', 'blur'];
741
- };
742
- TextInput.prototype.eventsIndicatingDeferValueChange = function () {
743
- return [];
744
- };
745
- TextInput.prototype.updateModel = function (event) {
746
- var element = this.$element;
747
- clearTimeout(this.timeoutHandle);
748
- this.elementValueBeforeEvent = this.timeoutHandle = undefined;
749
- var elementValue = element.value;
750
- if (this.previousElementValue !== elementValue) {
751
- // Provide a way for tests to know exactly which event was processed
752
- if (options.debug && event) {
753
- element._ko_textInputProcessedEvent = event.type;
754
- }
755
- this.previousElementValue = elementValue;
756
- this.value = elementValue;
757
- }
758
- };
759
- TextInput.prototype.deferUpdateModel = function (event) {
760
- var element = this.$element;
761
- if (!this.timeoutHandle) {
762
- // The elementValueBeforeEvent variable is set *only* during the brief gap between an
763
- // event firing and the updateModel function running. This allows us to ignore model
764
- // updates that are from the previous state of the element, usually due to techniques
765
- // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
766
- this.elementValueBeforeEvent = element.value;
767
- var handler = options.debug ? this.updateModel.bind(this, { type: event.type }) : this.updateModel;
768
- this.timeoutHandle = safeSetTimeout(handler, 4);
769
- }
770
- };
771
- TextInput.prototype.updateView = function () {
772
- var modelValue = unwrap(this.value);
773
- if (modelValue === null || modelValue === undefined) {
774
- modelValue = '';
775
- }
776
- if (this.elementValueBeforeEvent !== undefined
777
- && modelValue === this.elementValueBeforeEvent) {
778
- setTimeout(this.updateView.bind(this), 4);
779
- }
780
- else if (this.$element.value !== modelValue) {
781
- // Update the element only if the element and model are different. On some browsers, updating the value
782
- // will move the cursor to the end of the input, which would be bad while the user is typing.
783
- this.previousElementValue = modelValue; // Make sure we ignore events (propertychange) that result from updating the value
784
- this.$element.value = modelValue;
785
- this.previousElementValue = this.$element.value; // In case the browser changes the value (see #2281)
786
- }
787
- };
788
- return TextInput;
789
- }(BindingHandler));
790
- /**
791
- * Legacy Input Classes, below
792
- */
793
- var TextInputIE = /** @class */ (function (_super) {
794
- __extends(TextInputIE, _super);
795
- function TextInputIE() {
796
- var args = [];
797
- for (var _i = 0; _i < arguments.length; _i++) {
798
- args[_i] = arguments[_i];
799
- }
800
- var _this = _super.apply(this, __spread(args)) || this;
801
- if (ieVersion < 11) {
802
- // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever
803
- // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,
804
- // but that's an acceptable compromise for this binding. IE 9 and 10 support 'input', but since they don't always
805
- // fire it when using autocomplete, we'll use 'propertychange' for them also.
806
- _this.addEventListener('propertychange', function (event) {
807
- return event.propertyName === 'value' && _this.updateModel(event);
808
- });
809
- }
810
- if (ieVersion >= 8 && ieVersion < 10) {
811
- _this.watchForSelectionChangeEvent();
812
- _this.addEventListener('dragend', 'deferUpdateModel');
813
- }
814
- return _this;
815
- }
816
- TextInputIE.prototype.eventsIndicatingSyncValueChange = function () {
817
- // keypress: All versions (including 11) of Internet Explorer have a bug that they don't generate an input or propertychange event when ESC is pressed
818
- return __spread(_super.prototype.eventsIndicatingValueChange.call(this), ['keypress']);
819
- };
820
- // IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
821
- // But it does fire the 'selectionchange' event on many of those, presumably because the
822
- // cursor is moving and that counts as the selection changing. The 'selectionchange' event is
823
- // fired at the document level only and doesn't directly indicate which element changed. We
824
- // set up just one event handler for the document and use 'activeElement' to determine which
825
- // element was changed.
826
- TextInputIE.prototype.selectionChangeHandler = function (event) {
827
- var target = this.activeElement;
828
- var handler = target && domData.get(target, selectionChangeHandlerName);
829
- if (handler) {
830
- handler(event);
831
- }
832
- };
833
- TextInputIE.prototype.watchForSelectionChangeEvent = function (element, ieUpdateModel) {
834
- var ownerDoc = element.ownerDocument;
835
- if (!domData.get(ownerDoc, selectionChangeRegisteredName)) {
836
- domData.set(ownerDoc, selectionChangeRegisteredName, true);
837
- registerEventHandler(ownerDoc, 'selectionchange', this.selectionChangeHandler.bind(ownerDoc));
838
- }
839
- domData.set(element, selectionChangeHandlerName, handler);
840
- };
841
- return TextInputIE;
842
- }(TextInput));
843
- // IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
844
- // But it does fire the 'selectionchange' event on many of those, presumably because the
845
- // cursor is moving and that counts as the selection changing. The 'selectionchange' event is
846
- // fired at the document level only and doesn't directly indicate which element changed. We
847
- // set up just one event handler for the document and use 'activeElement' to determine which
848
- // element was changed.
849
- var TextInputIE9 = /** @class */ (function (_super) {
850
- __extends(TextInputIE9, _super);
851
- function TextInputIE9() {
852
- return _super !== null && _super.apply(this, arguments) || this;
853
- }
854
- TextInputIE9.prototype.updateModel = function () {
855
- var args = [];
856
- for (var _i = 0; _i < arguments.length; _i++) {
857
- args[_i] = arguments[_i];
858
- }
859
- // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);
860
- // so we'll make sure all updates are asynchronous
861
- this.deferUpdateModel.apply(this, __spread(args));
862
- };
863
- return TextInputIE9;
864
- }(TextInputIE));
865
- var TextInputIE8 = /** @class */ (function (_super) {
866
- __extends(TextInputIE8, _super);
867
- function TextInputIE8() {
868
- return _super !== null && _super.apply(this, arguments) || this;
869
- }
870
- TextInputIE8.prototype.eventsIndicatingValueChange = function () {
871
- // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from
872
- // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following
873
- // events too.
874
- // keypress: All versions (including 11) of Internet Explorer have a bug that they don't generate an input or propertychange event when ESC is pressed
875
- // keyup: A single keystoke
876
- // keydown: First character when a key is held down
877
- return __spread(_super.prototype.eventsIndicatingValueChange.call(this), ['keyup', 'keydown']);
878
- };
879
- return TextInputIE8;
880
- }(TextInputIE));
881
- // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'
882
- // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.
883
- var TextInputLegacySafari = /** @class */ (function (_super) {
884
- __extends(TextInputLegacySafari, _super);
885
- function TextInputLegacySafari() {
886
- return _super !== null && _super.apply(this, arguments) || this;
887
- }
888
- TextInputLegacySafari.prototype.eventsIndicatingDeferValueChange = function () {
889
- return ['keydown', 'paste', 'cut'];
890
- };
891
- return TextInputLegacySafari;
892
- }(TextInput));
893
- var TextInputLegacyOpera = /** @class */ (function (_super) {
894
- __extends(TextInputLegacyOpera, _super);
895
- function TextInputLegacyOpera() {
896
- return _super !== null && _super.apply(this, arguments) || this;
897
- }
898
- TextInputLegacyOpera.prototype.eventsIndicatingDeferValueChange = function () {
899
- // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.
900
- // We can try to catch some of those using 'keydown'.
901
- return ['keydown'];
902
- };
903
- return TextInputLegacyOpera;
904
- }(TextInput));
905
- var TextInputLegacyFirefox = /** @class */ (function (_super) {
906
- __extends(TextInputLegacyFirefox, _super);
907
- function TextInputLegacyFirefox() {
908
- return _super !== null && _super.apply(this, arguments) || this;
909
- }
910
- TextInputLegacyFirefox.prototype.eventsIndicatingValueChange = function () {
911
- return __spread(_super.prototype.eventsIndicatingSyncValueChange.call(this), [
912
- // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete
913
- 'DOMAutoComplete',
914
- // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.
915
- 'dragdrop',
916
- 'drop' // 3.5
917
- ]);
918
- };
919
- return TextInputLegacyFirefox;
920
- }(TextInput));
921
- var w = options.global; // window / global
922
- if (w.navigator) {
923
- var parseVersion_1 = function (matches) { return matches && parseFloat(matches[1]); };
924
- var userAgent = w.navigator.userAgent;
925
- var isChrome = userAgent.match(/Chrome\/([^ ]+)/);
926
- // Detect various browser versions because some old versions don't fully support the 'input' event
927
- operaVersion = w.opera && w.opera.version && parseInt(w.opera.version());
928
- safariVersion = parseVersion_1(userAgent.match(/Version\/([^ ]+) Safari/));
929
- firefoxVersion = parseVersion_1(userAgent.match(/Firefox\/([^ ]*)/));
930
- }
931
- var textInput = ieVersion === 8 ? TextInputIE8
932
- : ieVersion === 9 ? TextInputIE9
933
- : ieVersion ? TextInputIE
934
- : safariVersion && safariVersion < 5 ? TextInputLegacySafari
935
- : operaVersion < 11 ? TextInputLegacyOpera
936
- : firefoxVersion && firefoxVersion < 4 ? TextInputLegacyFirefox
937
- : TextInput;
938
-
939
- var uniqueName = {
940
- init: function (element, valueAccessor) {
941
- if (valueAccessor()) {
942
- var name = 'ko_unique_' + (++uniqueName.currentIndex);
943
- setElementName(element, name);
944
- }
945
- },
946
- currentIndex: 0
947
- };
948
-
949
- var value = /** @class */ (function (_super) {
950
- __extends(value, _super);
951
- function value() {
952
- var args = [];
953
- for (var _i = 0; _i < arguments.length; _i++) {
954
- args[_i] = arguments[_i];
955
- }
956
- var _this = _super.apply(this, __spread(args)) || this;
957
- // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit
958
- if (_this.isCheckboxOrRadio) {
959
- applyBindingAccessorsToNode(_this.$element, { checkedValue: _this.valueAccessor });
960
- return _this;
961
- }
962
- _this.propertyChangedFired = false;
963
- _this.elementValueBeforeEvent = null;
964
- if (_this.ieAutoCompleteHackNeeded) {
965
- _this.addEventListener('propertyChange', function () { return _this.propertyChangedFired = true; });
966
- _this.addEventListener('focus', function () { return _this.propertyChangedFired = false; });
967
- _this.addEventListener('blur', function () { return _this.propertyChangeFired &&
968
- _this.valueUpdateHandler(); });
969
- }
970
- arrayForEach(_this.eventsToCatch, function (eventName) { return _this.registerEvent(eventName); });
971
- if (_this.isInput && _this.$element.type === 'file') {
972
- _this.updateFromModel = _this.updateFromModelForFile;
973
- }
974
- else {
975
- _this.updateFromModel = _this.updateFromModelForValue;
976
- }
977
- _this.computed('updateFromModel');
978
- return _this;
979
- }
980
- Object.defineProperty(value, "after", {
981
- get: function () { return ['options', 'foreach', 'template']; },
982
- enumerable: true,
983
- configurable: true
984
- });
985
- Object.defineProperty(value.prototype, "eventsToCatch", {
986
- get: function () {
987
- var requestedEventsToCatch = this.allBindings.get('valueUpdate');
988
- var requestedEventsArray = typeof requestedEventsToCatch === 'string' ?
989
- [requestedEventsToCatch] : requestedEventsToCatch || [];
990
- return __spread(new Set(__spread(['change'], requestedEventsArray)));
991
- },
992
- enumerable: true,
993
- configurable: true
994
- });
995
- Object.defineProperty(value.prototype, "isInput", {
996
- get: function () {
997
- return tagNameLower(this.$element) === 'input';
998
- },
999
- enumerable: true,
1000
- configurable: true
1001
- });
1002
- Object.defineProperty(value.prototype, "isCheckboxOrRadio", {
1003
- get: function () {
1004
- var e = this.$element;
1005
- return this.isInput && (e.type == 'checkbox' || e.type == 'radio');
1006
- },
1007
- enumerable: true,
1008
- configurable: true
1009
- });
1010
- Object.defineProperty(value.prototype, "ieAutoCompleteHackNeeded", {
1011
- // Workaround for https://github.com/SteveSanderson/knockout/issues/122
1012
- // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
1013
- get: function () {
1014
- return ieVersion && isInputElement &&
1015
- this.$element.type == 'text' && this.$element.autocomplete != 'off' &&
1016
- (!this.$element.form || this.$element.form.autocomplete != 'off');
1017
- },
1018
- enumerable: true,
1019
- configurable: true
1020
- });
1021
- value.prototype.valueUpdateHandler = function () {
1022
- this.elementValueBeforeEvent = null;
1023
- this.propertyChangedFired = false;
1024
- this.value = selectExtensions.readValue(this.$element);
1025
- };
1026
- value.prototype.registerEvent = function (eventName) {
1027
- var _this = this;
1028
- // The syntax "after<eventname>" means "run the handler asynchronously after the event"
1029
- // This is useful, for example, to catch "keydown" events after the browser has updated the control
1030
- // (otherwise, selectExtensions.readValue(this) will receive the control's value *before* the key event)
1031
- var handler = this.valueUpdateHandler.bind(this);
1032
- if (stringStartsWith(eventName, 'after')) {
1033
- handler = function () {
1034
- // The elementValueBeforeEvent variable is non-null *only* during the brief gap between
1035
- // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen
1036
- // at the earliest asynchronous opportunity. We store this temporary information so that
1037
- // if, between keyX and valueUpdateHandler, the underlying model value changes separately,
1038
- // we can overwrite that model value change with the value the user just typed. Otherwise,
1039
- // techniques like rateLimit can trigger model changes at critical moments that will
1040
- // override the user's inputs, causing keystrokes to be lost.
1041
- _this.elementValueBeforeEvent = selectExtensions.readValue(_this.$element);
1042
- safeSetTimeout(_this.valueUpdateHandler.bind(_this), 0);
1043
- };
1044
- eventName = eventName.substring(5 /* 'after'.length */);
1045
- }
1046
- this.addEventListener(eventName, handler);
1047
- };
1048
- value.prototype.updateFromModelForFile = function () {
1049
- // For file input elements, can only write the empty string
1050
- var newValue = unwrap(this.value);
1051
- if (newValue === null || newValue === undefined || newValue === '') {
1052
- this.$element.value = '';
1053
- }
1054
- else {
1055
- dependencyDetection.ignore(this.valueUpdateHandler, this); // reset the model to match the element
1056
- }
1057
- };
1058
- value.prototype.updateFromModelForValue = function () {
1059
- var element = this.$element;
1060
- var newValue = unwrap(this.value);
1061
- var elementValue = selectExtensions.readValue(element);
1062
- if (this.elementValueBeforeEvent !== null && newValue === this.elementValueBeforeEvent) {
1063
- safeSetTimeout(this.updateFromModel.bind(this), 0);
1064
- return;
1065
- }
1066
- if (newValue === elementValue && elementValue !== undefined) {
1067
- return;
1068
- }
1069
- if (tagNameLower(element) === 'select') {
1070
- var allowUnset = this.allBindings.get('valueAllowUnset');
1071
- selectExtensions.writeValue(element, newValue, allowUnset);
1072
- if (!allowUnset && newValue !== selectExtensions.readValue(element)) {
1073
- // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
1074
- // because you're not allowed to have a model value that disagrees with a visible UI selection.
1075
- dependencyDetection.ignore(this.valueUpdateHandler, this);
1076
- }
1077
- }
1078
- else {
1079
- selectExtensions.writeValue(element, newValue);
1080
- }
1081
- };
1082
- return value;
1083
- }(BindingHandler));
1084
-
1085
- var visible = {
1086
- update: function (element, valueAccessor) {
1087
- var value = unwrap(valueAccessor());
1088
- var isCurrentlyVisible = !(element.style.display === 'none');
1089
- if (value && !isCurrentlyVisible) {
1090
- element.style.display = '';
1091
- }
1092
- else if (!value && isCurrentlyVisible) {
1093
- element.style.display = 'none';
1094
- }
1095
- }
1096
- };
1097
- var hidden = {
1098
- update: function (element, valueAccessor) {
1099
- visible.update.call(this, element, function () { return !unwrap(valueAccessor()); });
1100
- }
1101
- };
1102
-
1103
- var using = {
1104
- init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
1105
- var innerContext = bindingContext.createChildContext(valueAccessor);
1106
- applyBindingsToDescendants(innerContext, element);
1107
- return { controlsDescendantBindings: true };
1108
- },
1109
- allowVirtualElements: true
1110
- };
1111
-
1112
- var bindings = {
1113
- attr: attr,
1114
- checked: checked,
1115
- checkedValue: checkedValue,
1116
- click: click,
1117
- css: css,
1118
- 'class': css,
1119
- descendantsComplete: DescendantsCompleteHandler,
1120
- enable: enable,
1121
- 'event': eventHandler,
1122
- disable: disable,
1123
- hasfocus: hasfocus,
1124
- hasFocus: hasfocus,
1125
- hidden: hidden,
1126
- html: html,
1127
- 'let': $let,
1128
- on: onHandler,
1129
- options: options$1,
1130
- selectedOptions: selectedOptions,
1131
- style: style,
1132
- submit: submit,
1133
- text: text,
1134
- textInput: textInput,
1135
- textinput: textInput,
1136
- uniqueName: uniqueName,
1137
- using: using,
1138
- value: value,
1139
- visible: visible
1140
- };
1141
-
1142
- export { bindings };
1143
- //# sourceMappingURL=binding.core.js.map