PageSourceSearch

https://www.afm.es/gestor/script/ie/ie_placeholder.js

js afm.es collected 2026-10-02 05:53:02 UTC 19,274 bytes, 459 lines download raw bytes

1/* 
2 * The MIT License
3 *
4 * Copyright (c) 2012 James Allardice
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 
7 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
15 * THE SOFTWARE.
16 */
17
18// Defines the global Placeholders object along with various utility methods
19(function (global) {
20
21    "use strict";
22
23    // Cross-browser DOM event binding
24    function addEventListener(elem, event, fn) {
25        if (elem.addEventListener) {
26            return elem.addEventListener(event, fn, false);
27        }
28        if (elem.attachEvent) {
29            return elem.attachEvent("on" + event, fn);
30        }
31    }
32
33    // Check whether an item is in an array (we don't use Array.prototype.indexOf so we don't clobber any existing polyfills - this is a really simple alternative)
34    function inArray(arr, item) {
35        var i, len;
36        for (i = 0, len = arr.length; i < len; i++) {
37            if (arr[i] === item) {
38                return true;
39            }
40        }
41        return false;
42    }
43
44    // Move the caret to the index position specified. Assumes that the element has focus
45    function moveCaret(elem, index) {
46        var range;
47        if (elem.createTextRange) {
48            range = elem.createTextRange();
49            range.move("character", index);
50            range.select();
51        } else if (elem.selectionStart) {
52            elem.focus();
53            elem.setSelectionRange(index, index);
54        }
55    }
56
57    // Attempt to change the type property of an input element
58    function changeType(elem, type) {
59        try {
60            elem.type = type;
61            return true;
62        } catch (e) {
63            // You can't change input type in IE8 and below
64            return false;
65        }
66    }
67
68    // Expose public methods
69    global.Placeholders = {
70        Utils: {
71            addEventListener: addEventListener,
72            inArray: inArray,
73            moveCaret: moveCaret,
74            changeType: changeType
75        }
76    };
77
78}(this));
79
80(function (global) {
81
82    "use strict";
83
84    var validTypes = [
85            "text",
86            "search",
87            "url",
88            "tel",
89            "email",
90            "password",
91            "number",
92            "textarea"
93        ],
94
95        // The list of keycodes that are not allowed when the polyfill is configured to hide-on-input
96        badKeys = [
97
98            // The following keys all cause the caret to jump to the end of the input value
99            27, // Escape
100            33, // Page up
101            34, // Page down
102            35, // End
103            36, // Home
104
105            // Arrow keys allow you to move the caret manually, which should be prevented when the placeholder is visible
106            37, // Left
107            38, // Up
108            39, // Right
109            40, // Down
110
111            // The following keys allow you to modify the placeholder text by removing characters, which should be prevented when the placeholder is visible
112            8, // Backspace
113            46 // Delete
114        ],
115
116        // Styling variables
117        placeholderStyleColor = "#ccc",
118        placeholderClassName = "placeholdersjs",
119        classNameRegExp = new RegExp("(?:^|\\s)" + placeholderClassName + "(?!\\S)"),
120
121        // These will hold references to all elements that can be affected. NodeList objects are live, so we only need to get those references once
122        inputs, textareas,
123
124        // The various data-* attributes used by the polyfill
125        ATTR_CURRENT_VAL = "data-placeholder-value",
126        ATTR_ACTIVE = "data-placeholder-active",
127        ATTR_INPUT_TYPE = "data-placeholder-type",
128        ATTR_FORM_HANDLED = "data-placeholder-submit",
129        ATTR_EVENTS_BOUND = "data-placeholder-bound",
130        ATTR_OPTION_FOCUS = "data-placeholder-focus",
131        ATTR_OPTION_LIVE = "data-placeholder-live",
132        ATTR_MAXLENGTH = "data-placeholder-maxlength",
133
134        // Various other variables used throughout the rest of the script
135        test = document.createElement("input"),
136        head = document.getElementsByTagName("head")[0],
137        root = document.documentElement,
138        Placeholders = global.Placeholders,
139        Utils = Placeholders.Utils,
140        hideOnInput, liveUpdates, keydownVal, styleElem, styleRules, placeholder, timer, form, elem, len, i;
141
142    // No-op (used in place of public methods when native support is detected)
143    function noop() {}
144
145    // Avoid IE9 activeElement of death when an iframe is used.
146    // More info:
147    // http://bugs.jquery.com/ticket/13393
148    // https://github.com/jquery/jquery/commit/85fc5878b3c6af73f42d61eedf73013e7faae408
149    function safeActiveElement() {
150        try {
151            return document.activeElement;
152        } catch (err) {}
153    }
154
155    // Hide the placeholder value on a single element. Returns true if the placeholder was hidden and false if it was not (because it wasn't visible in the first place)
156    function hidePlaceholder(elem, keydownValue) {
157        var type,
158            maxLength,
159            valueChanged = (!!keydownValue && elem.value !== keydownValue),
160            isPlaceholderValue = (elem.value === elem.getAttribute(ATTR_CURRENT_VAL));
161
162        if ((valueChanged || isPlaceholderValue) && elem.getAttribute(ATTR_ACTIVE) === "true") {
163            elem.removeAttribute(ATTR_ACTIVE);
164            elem.value = elem.value.replace(elem.getAttribute(ATTR_CURRENT_VAL), "");
165            elem.className = elem.className.replace(classNameRegExp, "");
166
167            // Restore the maxlength value
168            maxLength = elem.getAttribute(ATTR_MAXLENGTH);
169            if (parseInt(maxLength, 10) >= 0) { // Old FF returns -1 if attribute not set (see GH-56)
170                elem.setAttribute("maxLength", maxLength);
171                elem.removeAttribute(ATTR_MAXLENGTH);
172            }
173
174            // If the polyfill has changed the type of the element we need to change it back
175            type = elem.getAttribute(ATTR_INPUT_TYPE);
176            if (type) {
177                elem.type = type;
178            }
179            return true;
180        }
181        return false;
182    }
183
184    // Show the placeholder value on a single element. Returns true if the placeholder was shown and false if it was not (because it was already visible)
185    function showPlaceholder(elem) {
186        var type,
187            maxLength,
188            val = elem.getAttribute(ATTR_CURRENT_VAL);
189        if (elem.value === "" && val) {
190            elem.setAttribute(ATTR_ACTIVE, "true");
191            elem.value = val;
192            elem.className += " " + placeholderClassName;
193
194            // Store and remove the maxlength value
195            maxLength = elem.getAttribute(ATTR_MAXLENGTH);
196            if (!maxLength) {
197                elem.setAttribute(ATTR_MAXLENGTH, elem.maxLength);
198                elem.removeAttribute("maxLength");
199            }
200
201            // If the type of element needs to change, change it (e.g. password inputs)
202            type = elem.getAttribute(ATTR_INPUT_TYPE);
203            if (type) {
204                elem.type = "text";
205            } else if (elem.type === "password") {
206                if (Utils.changeType(elem, "text")) {
207                    elem.setAttribute(ATTR_INPUT_TYPE, "password");
208                }
209            }
210            return true;
211        }
212        return false;
213    }
214
215    function handleElem(node, callback) {
216
217        var handleInputsLength, handleTextareasLength, handleInputs, handleTextareas, elem, len, i;
218
219        // Check if the passed in node is an input/textarea (in which case it can't have any affected descendants)
220        if (node && node.getAttribute(ATTR_CURRENT_VAL)) {
221            callback(node);
222        } else {
223
224            // If an element was passed in, get all affected descendants. Otherwise, get all affected elements in document
225            handleInputs = node ? node.getElementsByTagName("input") : inputs;
226            handleTextareas = node ? node.getElementsByTagName("textarea") : textareas;
227
228            handleInputsLength = handleInputs ? handleInputs.length : 0;
229            handleTextareasLength = handleTextareas ? handleTextareas.length : 0;
230
231            // Run the callback for each element
232            for (i = 0, len = handleInputsLength + handleTextareasLength; i < len; i++) {
233                elem = i < handleInputsLength ? handleInputs[i] : handleTextareas[i - handleInputsLength];
234                callback(elem);
235            }
236        }
237    }
238
239    // Return all affected elements to their normal state (remove placeholder value if present)
240    function disablePlaceholders(node) {
241        handleElem(node, hidePlaceholder);
242    }
243
244    // Show the placeholder value on all appropriate elements
245    function enablePlaceholders(node) {
246        handleElem(node, showPlaceholder);
247    }
248
249    // Returns a function that is used as a focus event handler
250    function makeFocusHandler(elem) {
251        return function () {
252
253            // Only hide the placeholder value if the (default) hide-on-focus behaviour is enabled
254            if (hideOnInput && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
255
256                // Move the caret to the start of the input (this mimics the behaviour of all browsers that do not hide the placeholder on focus)
257                Utils.moveCaret(elem, 0);
258
259            } else {
260
261                // Remove the placeholder
262                hidePlaceholder(elem);
263            }
264        };
265    }
266
267    // Returns a function that is used as a blur event handler
268    function makeBlurHandler(elem) {
269        return function () {
270            showPlaceholder(elem);
271        };
272    }
273
274    // Functions that are used as a event handlers when the hide-on-input behaviour has been activated - very basic implementation of the "input" event
275    function makeKeydownHandler(elem) {
276        return function (e) {
277            keydownVal = elem.value;
278
279            //Prevent the use of the arrow keys (try to keep the cursor before the placeholder)
280            if (elem.getAttribute(ATTR_ACTIVE) === "true") {
281                if (keydownVal === elem.getAttribute(ATTR_CURRENT_VAL) && Utils.inArray(badKeys, e.keyCode)) {
282                    if (e.preventDefault) {
283                        e.preventDefault();
284                    }
285                    return false;
286                }
287            }
288        };
289    }
290    function makeKeyupHandler(elem) {
291        return function () {
292            hidePlaceholder(elem, keydownVal);
293
294            // If the element is now empty we need to show the placeholder
295            if (elem.value === "") {
296                elem.blur();
297                Utils.moveCaret(elem, 0);
298            }
299        };
300    }
301    function makeClickHandler(elem) {
302        return function () {
303            if (elem === safeActiveElement() && elem.value === elem.getAttribute(ATTR_CURRENT_VAL) && elem.getAttribute(ATTR_ACTIVE) === "true") {
304                Utils.moveCaret(elem, 0);
305            }
306        };
307    }
308
309    // Returns a function that is used as a submit event handler on form elements that have children affected by this polyfill
310    function makeSubmitHandler(form) {
311        return function () {
312
313            // Turn off placeholders on all appropriate descendant elements
314            disablePlaceholders(form);
315        };
316    }
317
318    // Bind event handlers to an element that we need to affect with the polyfill
319    function newElement(elem) {
320
321        // If the element is part of a form, make sure the placeholder string is not submitted as a value
322        if (elem.form) {
323            form = elem.form;
324
325            // If the type of the property is a string then we have a "form" attribute and need to get the real form
326            if (typeof form === "string") {
327                form = document.getElementById(form);
328            }
329
330            // Set a flag on the form so we know it's been handled (forms can contain multiple inputs)
331            if (!form.getAttribute(ATTR_FORM_HANDLED)) {
332                Utils.addEventListener(form, "submit", makeSubmitHandler(form));
333                form.setAttribute(ATTR_FORM_HANDLED, "true");
334            }
335        }
336
337        // Bind event handlers to the element so we can hide/show the placeholder as appropriate
338        Utils.addEventListener(elem, "focus", makeFocusHandler(elem));
339        Utils.addEventListener(elem, "blur", makeBlurHandler(elem));
340
341        // If the placeholder should hide on input rather than on focus we need additional event handlers
342        if (hideOnInput) {
343            Utils.addEventListener(elem, "keydown", makeKeydownHandler(elem));
344            Utils.addEventListener(elem, "keyup", makeKeyupHandler(elem));
345            Utils.addEventListener(elem, "click", makeClickHandler(elem));
346        }
347
348        // Remember that we've bound event handlers to this element
349        elem.setAttribute(ATTR_EVENTS_BOUND, "true");
350        elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
351
352        // If the element doesn't have a value and is not focussed, set it to the placeholder string
353        if (hideOnInput || elem !== safeActiveElement()) {
354            showPlaceholder(elem);
355        }
356    }
357
358    Placeholders.nativeSupport = test.placeholder !== void 0;
359
360    if (!Placeholders.nativeSupport) {
361
362        // Get references to all the input and textarea elements currently in the DOM (live NodeList objects to we only need to do this once)
363        inputs = document.getElementsByTagName("input");
364        textareas = document.getElementsByTagName("textarea");
365
366        // Get any settings declared as data-* attributes on the root element (currently the only options are whether to hide the placeholder on focus or input and whether to auto-update)
367        hideOnInput = root.getAttribute(ATTR_OPTION_FOCUS) === "false";
368        liveUpdates = root.getAttribute(ATTR_OPTION_LIVE) !== "false";
369
370        // Create style element for placeholder styles (instead of directly setting style properties on elements - allows for better flexibility alongside user-defined styles)
371        styleElem = document.createElement("style");
372        styleElem.type = "text/css";
373
374        // Create style rules as text node
375        styleRules = document.createTextNode("." + placeholderClassName + " { color:" + placeholderStyleColor + "; }");
376
377        // Append style rules to newly created stylesheet
378        if (styleElem.styleSheet) {
379            styleElem.styleSheet.cssText = styleRules.nodeValue;
380        } else {
381            styleElem.appendChild(styleRules);
382        }
383
384        // Prepend new style element to the head (before any existing stylesheets, so user-defined rules take precedence)
385        head.insertBefore(styleElem, head.firstChild);
386
387        // Set up the placeholders
388        for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
389            elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
390
391            // Get the value of the placeholder attribute, if any. IE10 emulating IE7 fails with getAttribute, hence the use of the attributes node
392            placeholder = elem.attributes.placeholder;
393            if (placeholder) {
394
395                // IE returns an empty object instead of undefined if the attribute is not present
396                placeholder = placeholder.nodeValue;
397
398                // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
399                if (placeholder && Utils.inArray(validTypes, elem.type)) {
400                    newElement(elem);
401                }
402            }
403        }
404
405        // If enabled, the polyfill will repeatedly check for changed/added elements and apply to those as well
406        timer = setInterval(function () {
407            for (i = 0, len = inputs.length + textareas.length; i < len; i++) {
408                elem = i < inputs.length ? inputs[i] : textareas[i - inputs.length];
409
410                // Only apply the polyfill if this element is of a type that supports placeholders, and has a placeholder attribute with a non-empty value
411                placeholder = elem.attributes.placeholder;
412                if (placeholder) {
413                    placeholder = placeholder.nodeValue;
414                    if (placeholder && Utils.inArray(validTypes, elem.type)) {
415
416                        // If the element hasn't had event handlers bound to it then add them
417                        if (!elem.getAttribute(ATTR_EVENTS_BOUND)) {
418                            newElement(elem);
419                        }
420
421                        // If the placeholder value has changed or not been initialised yet we need to update the display
422                        if (placeholder !== elem.getAttribute(ATTR_CURRENT_VAL) || (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE))) {
423
424                            // Attempt to change the type of password inputs (fails in IE < 9)
425                            if (elem.type === "password" && !elem.getAttribute(ATTR_INPUT_TYPE) && Utils.changeType(elem, "text")) {
426                                elem.setAttribute(ATTR_INPUT_TYPE, "password");
427                            }
428
429                            // If the placeholder value has changed and the placeholder is currently on display we need to change it
430                            if (elem.value === elem.getAttribute(ATTR_CURRENT_VAL)) {
431                                elem.value = placeholder;
432                            }
433
434                            // Keep a reference to the current placeholder value in case it changes via another script
435                            elem.setAttribute(ATTR_CURRENT_VAL, placeholder);
436                        }
437                    }
438                } else if (elem.getAttribute(ATTR_ACTIVE)) {
439                    hidePlaceholder(elem);
440                    elem.removeAttribute(ATTR_CURRENT_VAL);
441                }
442            }
443
444            // If live updates are not enabled cancel the timer
445            if (!liveUpdates) {
446                clearInterval(timer);
447            }
448        }, 100);
449    }
450
451    Utils.addEventListener(global, "beforeunload", function () {
452        Placeholders.disable();
453    });
454
455    // Expose public methods
456    Placeholders.disable = Placeholders.nativeSupport ? noop : disablePlaceholders;
457    Placeholders.enable = Placeholders.nativeSupport ? noop : enablePlaceholders;
458
459}(this));

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.