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