1/** 2 * jQuery "splendid textchange" plugin 3 * http://benalpert.com/2013/06/18/a-near-perfect-oninput-shim-for-ie-8-and-9.html 4 * 5 * (c) 2013 Ben Alpert, released under the MIT license 6 */ 7 8(function($) { 9 10 var testNode = document.createElement("input"); 11 var isInputSupported = "oninput" in testNode && 12 (!("documentMode" in document) || document.documentMode > 9); 13 14 var hasInputCapabilities = function(elem) { 15 // The HTML5 spec lists many more types than `text` and `password` on 16 // which the input event is triggered but none of them exist in IE 8 or 17 // 9, so we don't check them here. 18 // TODO: <textarea> should be supported too but IE seems to reset the 19 // selection when changing textarea contents during a selectionchange 20 // event so it's not listed here for now. 21 return elem.nodeName === "INPUT" && 22 (elem.type === "text" || elem.type === "password"); 23 }; 24 25 var activeElement = null; 26 var activeElementValue = null; 27 var activeElementValueProp = null; 28 29 /** 30 * (For old IE.) Replacement getter/setter for the `value` property that 31 * gets set on the active element. 32 */ 33 var newValueProp = { 34 get: function() { 35 return activeElementValueProp.get.call(this); 36 }, 37 set: function(val) { 38 activeElementValue = val; 39 activeElementValueProp.set.call(this, val); 40 } 41 }; 42 43 /** 44 * (For old IE.) Starts tracking propertychange events on the passed-in element 45 * and override the value property so that we can distinguish user events from 46 * value changes in JS. 47 */ 48 var startWatching = function(target) { 49 activeElement = target; 50 activeElementValue = target.value; 51 activeElementValueProp = Object.getOwnPropertyDescriptor( 52 target.constructor.prototype, "value"); 53 54 Object.defineProperty(activeElement, "value", newValueProp); 55 activeElement.attachEvent("onpropertychange", handlePropertyChange); 56 }; 57 58 /** 59 * (For old IE.) Removes the event listeners from the currently-tracked 60 * element, if any exists. 61 */ 62 var stopWatching = function() { 63 if (!activeElement) return; 64 65 // delete restores the original property definition 66 delete activeElement.value; 67 activeElement.detachEvent("onpropertychange", handlePropertyChange); 68 69 activeElement = null; 70 activeElementValue = null; 71 activeElementValueProp = null; 72 }; 73 74 /** 75 * (For old IE.) Handles a propertychange event, sending a textChange event if 76 * the value of the active element has changed. 77 */ 78 var handlePropertyChange = function(nativeEvent) { 79 if (nativeEvent.propertyName !== "value") return; 80 81 var value = nativeEvent.srcElement.value; 82 if (value === activeElementValue) return; 83 activeElementValue = value; 84 85 $(activeElement).trigger("textchange"); 86 }; 87 88 if (isInputSupported) { 89 $(document) 90 .on("input", function(e) { 91 // In modern browsers (i.e., not IE 8 or 9), the input event is 92 // exactly what we want so fall through here and trigger the 93 // event... 94 if (e.target.nodeName !== "TEXTAREA") { 95 // ...unless it's a textarea, in which case we don't fire an 96 // event (so that we have consistency with our old-IE shim). 97 $(e.target).trigger("textchange"); 98 } 99 }); 100 } else { 101 $(document) 102 .on("focusin", function(e) { 103 // In IE 8, we can capture almost all .value changes by adding a 104 // propertychange handler and looking for events with propertyName 105 // equal to 'value'. 106 // In IE 9, propertychange fires for most input events but is buggy 107 // and doesn't fire when text is deleted, but conveniently, 108 // selectionchange appears to fire in all of the remaining cases so 109 // we catch those and forward the event if the value has changed. 110 // In either case, we don't want to call the event handler if the 111 // value is changed from JS so we redefine a setter for `.value` 112 // that updates our activeElementValue variable, allowing us to 113 // ignore those changes. 114 if (hasInputCapabilities(e.target)) { 115 // stopWatching() should be a noop here but we call it just in 116 // case we missed a blur event somehow. 117 stopWatching(); 118 startWatching(e.target); 119 } 120 }) 121 122 .on("focusout", function() { 123 stopWatching(); 124 }) 125 126 .on("selectionchange keyup keydown", function() { 127 // On the selectionchange event, e.target is just document which 128 // isn't helpful for us so just check activeElement instead. 129 // 130 // 90% of the time, keydown and keyup aren't necessary. IE 8 fails 131 // to fire propertychange on the first input event after setting 132 // `value` from a script and fires only keydown, keypress, keyup. 133 // Catching keyup usually gets it and catching keydown lets us f
133ire 134 // an event for the first keystroke if user does a key repeat 135 // (it'll be a little delayed: right before the second keystroke). 136 // Other input methods (e.g., paste) seem to fire selectionchange 137 // normally. 138 if (activeElement && activeElement.value !== activeElementValue) { 139 activeElementValue = activeElement.value; 140 $(activeElement).trigger("textchange"); 141 } 142 }); 143 } 144 145})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.