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