PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/js/vendor/knockout/src/binding/defaultBindings/textInput.js

https://gitlab.com/I-NOZex/quiz-template
JavaScript | 182 lines | 120 code | 22 blank | 40 comment | 37 complexity | d7b5745c1b2e78ccc7ca51bc0586663d MD5 | raw file
  1. (function () {
  2. if (window && window.navigator) {
  3. var parseVersion = function (matches) {
  4. if (matches) {
  5. return parseFloat(matches[1]);
  6. }
  7. };
  8. // Detect various browser versions because some old versions don't fully support the 'input' event
  9. var operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()),
  10. userAgent = window.navigator.userAgent,
  11. safariVersion = parseVersion(userAgent.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),
  12. firefoxVersion = parseVersion(userAgent.match(/Firefox\/([^ ]*)/));
  13. }
  14. // IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
  15. // But it does fire the 'selectionchange' event on many of those, presumably because the
  16. // cursor is moving and that counts as the selection changing. The 'selectionchange' event is
  17. // fired at the document level only and doesn't directly indicate which element changed. We
  18. // set up just one event handler for the document and use 'activeElement' to determine which
  19. // element was changed.
  20. if (ko.utils.ieVersion < 10) {
  21. var selectionChangeRegisteredName = ko.utils.domData.nextKey(),
  22. selectionChangeHandlerName = ko.utils.domData.nextKey();
  23. var selectionChangeHandler = function(event) {
  24. var target = this.activeElement,
  25. handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);
  26. if (handler) {
  27. handler(event);
  28. }
  29. };
  30. var registerForSelectionChangeEvent = function (element, handler) {
  31. var ownerDoc = element.ownerDocument;
  32. if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {
  33. ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);
  34. ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);
  35. }
  36. ko.utils.domData.set(element, selectionChangeHandlerName, handler);
  37. };
  38. }
  39. ko.bindingHandlers['textInput'] = {
  40. 'init': function (element, valueAccessor, allBindings) {
  41. var previousElementValue = element.value,
  42. timeoutHandle,
  43. elementValueBeforeEvent;
  44. var updateModel = function (event) {
  45. clearTimeout(timeoutHandle);
  46. elementValueBeforeEvent = timeoutHandle = undefined;
  47. var elementValue = element.value;
  48. if (previousElementValue !== elementValue) {
  49. // Provide a way for tests to know exactly which event was processed
  50. if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;
  51. previousElementValue = elementValue;
  52. ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);
  53. }
  54. };
  55. var deferUpdateModel = function (event) {
  56. if (!timeoutHandle) {
  57. // The elementValueBeforeEvent variable is set *only* during the brief gap between an
  58. // event firing and the updateModel function running. This allows us to ignore model
  59. // updates that are from the previous state of the element, usually due to techniques
  60. // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
  61. elementValueBeforeEvent = element.value;
  62. var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;
  63. timeoutHandle = ko.utils.setTimeout(handler, 4);
  64. }
  65. };
  66. // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);
  67. // so we'll make sure all updates are asynchronous
  68. var ieUpdateModel = ko.utils.ieVersion == 9 ? deferUpdateModel : updateModel;
  69. var updateView = function () {
  70. var modelValue = ko.utils.unwrapObservable(valueAccessor());
  71. if (modelValue === null || modelValue === undefined) {
  72. modelValue = '';
  73. }
  74. if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {
  75. ko.utils.setTimeout(updateView, 4);
  76. return;
  77. }
  78. // Update the element only if the element and model are different. On some browsers, updating the value
  79. // will move the cursor to the end of the input, which would be bad while the user is typing.
  80. if (element.value !== modelValue) {
  81. previousElementValue = modelValue; // Make sure we ignore events (propertychange) that result from updating the value
  82. element.value = modelValue;
  83. }
  84. };
  85. var onEvent = function (event, handler) {
  86. ko.utils.registerEventHandler(element, event, handler);
  87. };
  88. if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
  89. // Provide a way for tests to specify exactly which events are bound
  90. ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {
  91. if (eventName.slice(0,5) == 'after') {
  92. onEvent(eventName.slice(5), deferUpdateModel);
  93. } else {
  94. onEvent(eventName, updateModel);
  95. }
  96. });
  97. } else {
  98. if (ko.utils.ieVersion < 10) {
  99. // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever
  100. // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,
  101. // but that's an acceptable compromise for this binding. IE 9 does support 'input', but since it doesn't fire it
  102. // when using autocomplete, we'll use 'propertychange' for it also.
  103. onEvent('propertychange', function(event) {
  104. if (event.propertyName === 'value') {
  105. ieUpdateModel(event);
  106. }
  107. });
  108. if (ko.utils.ieVersion == 8) {
  109. // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from
  110. // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following
  111. // events too.
  112. onEvent('keyup', updateModel); // A single keystoke
  113. onEvent('keydown', updateModel); // The first character when a key is held down
  114. }
  115. if (ko.utils.ieVersion >= 8) {
  116. // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using
  117. // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text
  118. // out of the field, and cutting or deleting text using the context menu. 'selectionchange'
  119. // can detect all of those except dragging text out of the field, for which we use 'dragend'.
  120. // These are also needed in IE8 because of the bug described above.
  121. registerForSelectionChangeEvent(element, ieUpdateModel); // 'selectionchange' covers cut, paste, drop, delete, etc.
  122. onEvent('dragend', deferUpdateModel);
  123. }
  124. } else {
  125. // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed
  126. // through the user interface.
  127. onEvent('input', updateModel);
  128. if (safariVersion < 5 && ko.utils.tagNameLower(element) === "textarea") {
  129. // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'
  130. // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.
  131. onEvent('keydown', deferUpdateModel);
  132. onEvent('paste', deferUpdateModel);
  133. onEvent('cut', deferUpdateModel);
  134. } else if (operaVersion < 11) {
  135. // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.
  136. // We can try to catch some of those using 'keydown'.
  137. onEvent('keydown', deferUpdateModel);
  138. } else if (firefoxVersion < 4.0) {
  139. // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete
  140. onEvent('DOMAutoComplete', updateModel);
  141. // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.
  142. onEvent('dragdrop', updateModel); // <3.5
  143. onEvent('drop', updateModel); // 3.5
  144. }
  145. }
  146. }
  147. // Bind to the change event so that we can catch programmatic updates of the value that fire this event.
  148. onEvent('change', updateModel);
  149. ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
  150. }
  151. };
  152. ko.expressionRewriting.twoWayBindings['textInput'] = true;
  153. // textinput is an alias for textInput
  154. ko.bindingHandlers['textinput'] = {
  155. // preprocess is the only way to set up a full alias
  156. 'preprocess': function (value, name, addBinding) {
  157. addBinding('textInput', value);
  158. }
  159. };
  160. })();