forEach支持IE11+,classList支持IE10+。
forEach、classList、details、closest、NodeList forEach support、hasAttribute、before()、after()、replaceWith()、append()、prepend()、remove()、document.scrollingElement、resize、placeholder
forEach
MDN官方polyfill,兼容IE9+
if ( !Array.prototype.forEach ) {
Array.prototype.forEach = function forEach( callback, thisArg ) {
var T, k;
if ( this == null ) {
throw new TypeError( "this is null or not defined" );
}
var O = Object(this);
var len = O.length >>> 0;
if ( typeof callback !== "function" ) {
throw new TypeError( callback + " is not a function" );
}
if ( arguments.length > 1 ) {
T = thisArg;
}
k = 0;
while( k < len ) {
var kValue;
if ( k in O ) {
kValue = O[ k ];
callback.call( T, kValue, k, O );
}
k++;
}
};
}
classList
兼容IE9+,包含add()
、remove()
、toggle()
、contains()
、items()
。
// polyfill classList
if (!("classList" in document.documentElement)) {
Object.defineProperty(HTMLElement.prototype, 'classList', {
get: function() {
var self = this;
function update(fn) {
return function(value) {
var classes = self.className.split(/\s+/g),
index = classes.indexOf(value);
fn(classes, index, value);
self.className = classes.join(" ");
}
}
return {
add: update(function(classes, index, value) {
if (!~index) classes.push(value);
}),
remove: update(function(classes, index) {
if (~index) classes.splice(index, 1);
}),
toggle: update(function(classes, index, value) {
if (~index)
classes.splice(index, 1);
else
classes.push(value);
}),
contains: function(value) {
return !!~self.className.split(/\s+/g).indexOf(value);
},
item: function(i) {
return self.className.split(/\s+/g)[i] || null;
}
};
}
});
}
details
来源:https://github.com/javan/details-element-polyfill
// details/summary polyfill
if (!('open' in document.createElement('details'))) {
document.addEventListener('click', function (event) {
var target = event.target;
var elSummary = $(target).parents('summary');
if (target.tagName == 'summary') {
elSummary = $(target);
}
if (elSummary.length) {
var elDetails = elSummary.parents('details');
var open = elDetails.attr('open');
if (typeof open == 'string') {
elDetails.removeAttr('open');
} else {
elDetails.attr('open', '');
}
}
});
}
/*
Details Element Polyfill 2.4.0
Copyright © 2019 Javan Makhmali
*/
(function() {
"use strict";
var element = document.createElement("details");
var elementIsNative = typeof HTMLDetailsElement != "undefined" && element instanceof HTMLDetailsElement;
var support = {
open: "open" in element || elementIsNative,
toggle: "ontoggle" in element
};
var styles = '\ndetails, summary {\n display: block;\n}\ndetails:not([open]) > *:not(summary) {\n display: none;\n}\nsummary::before {\n content: "►";\n padding-right: 0.3rem;\n font-size: 0.6rem;\n cursor: default;\n}\n[open] > summary::before {\n content: "▼";\n}\n';
var _ref = [], forEach = _ref.forEach, slice = _ref.slice;
if (!support.open) {
polyfillStyles();
polyfillProperties();
polyfillToggle();
polyfillAccessibility();
}
if (support.open && !support.toggle) {
polyfillToggleEvent();
}
function polyfillStyles() {
document.head.insertAdjacentHTML("afterbegin", "<style>" + styles + "</style>");
}
function polyfillProperties() {
var prototype = document.createElement("details").constructor.prototype;
var setAttribute = prototype.setAttribute, removeAttribute = prototype.removeAttribute;
var open = Object.getOwnPropertyDescriptor(prototype, "open");
Object.defineProperties(prototype, {
open: {
get: function get() {
if (this.tagName == "DETAILS") {
return this.hasAttribute("open");
} else {
if (open && open.get) {
return open.get.call(this);
}
}
},
set: function set(value) {
if (this.tagName == "DETAILS") {
return value ? this.setAttribute("open", "") : this.removeAttribute("open");
} else {
if (open && open.set) {
return open.set.call(this, value);
}
}
}
},
setAttribute: {
value: function value(name, _value) {
var _this = this;
var call = function call() {
return setAttribute.call(_this, name, _value);
};
if (name == "open" && this.tagName == "DETAILS") {
var wasOpen = this.hasAttribute("open");
var result = call();
if (!wasOpen) {
var summary = this.querySelector("summary");
if (summary) summary.setAttribute("aria-expanded", true);
triggerToggle(this);
}
return result;
}
return call();
}
},
removeAttribute: {
value: function value(name) {
var _this2 = this;
var call = function call() {
return removeAttribute.call(_this2, name);
};
if (name == "open" && this.tagName == "DETAILS") {
var wasOpen = this.hasAttribute("open");
var result = call();
if (wasOpen) {
var summary = this.querySelector("summary");
if (summary) summary.setAttribute("aria-expanded", false);
triggerToggle(this);
}
return result;
}
return call();
}
}
});
}
function polyfillToggle() {
onTogglingTrigger(function(element) {
element.hasAttribute("open") ? element.removeAttribute("open") : element.setAttribute("open", "");
});
}
function polyfillToggleEvent() {
if (window.MutationObserver) {
new MutationObserver(function(mutations) {
forEach.call(mutations, function(mutation) {
var target = mutation.target, attributeName = mutation.attributeName;
if (target.tagName == "DETAILS" && attributeName == "open") {
triggerToggle(target);
}
});
}).observe(document.documentElement, {
attributes: true,
subtree: true
});
} else {
onTogglingTrigger(function(element) {
var wasOpen = element.getAttribute("open");
setTimeout(function() {
var isOpen = element.getAttribute("open");
if (wasOpen != isOpen) {
triggerToggle(element);
}
}, 1);
});
}
}
function polyfillAccessibility() {
setAccessibilityAttributes(document);
if (window.MutationObserver) {
new MutationObserver(function(mutations) {
forEach.call(mutations, function(mutation) {
forEach.call(mutation.addedNodes, setAccessibilityAttributes);
});
}).observe(document.documentElement, {
subtree: true,
childList: true
});
} else {
document.addEventListener("DOMNodeInserted", function(event) {
setAccessibilityAttributes(event.target);
});
}
}
function setAccessibilityAttributes(root) {
findElementsWithTagName(root, "SUMMARY").forEach(function(summary) {
var details = findClosestElementWithTagName(summary, "DETAILS");
summary.setAttribute("aria-expanded", details.hasAttribute("open"));
if (!summary.hasAttribute("tabindex")) summary.setAttribute("tabindex", "0");
if (!summary.hasAttribute("role")) summary.setAttribute("role", "button");
});
}
function eventIsSignificant(event) {
return !(event.defaultPrevented || event.ctrlKey || event.metaKey || event.shiftKey || event.target.isContentEditable);
}
function onTogglingTrigger(callback) {
addEventListener("click", function(event) {
if (eventIsSignificant(event)) {
if (event.which <= 1) {
var element = findClosestElementWithTagName(event.target, "SUMMARY");
if (element && element.parentNode && element.parentNode.tagName == "DETAILS") {
callback(element.parentNode);
}
}
}
}, false);
addEventListener("keydown", function(event) {
if (eventIsSignificant(event)) {
if (event.keyCode == 13 || event.keyCode == 32) {
var element = findClosestElementWithTagName(event.target, "SUMMARY");
if (element && element.parentNode && element.parentNode.tagName == "DETAILS") {
callback(element.parentNode);
event.preventDefault();
}
}
}
}, false);
}
function triggerToggle(element) {
var event = document.createEvent("Event");
event.initEvent("toggle", false, false);
element.dispatchEvent(event);
}
function findElementsWithTagName(root, tagName) {
return (root.tagName == tagName ? [ root ] : []).concat(typeof root.getElementsByTagName == "function" ? slice.call(root.getElementsByTagName(tagName)) : []);
}
function findClosestElementWithTagName(element, tagName) {
if (typeof element.closest == "function") {
return element.closest(tagName);
} else {
while (element) {
if (element.tagName == tagName) {
return element;
} else {
element = element.parentNode;
}
}
}
}
})();
closest
closest polyfill
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
}
if (!Element.prototype.closest) {
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
NodeList forEach support
if (window.NodeList && !NodeList.prototype.forEach) {
NodeList.prototype.forEach = Array.prototype.forEach;
}
hasAttribute
(function (prototype) {
prototype.hasAttribute = prototype.hasAttribute || function (name) {
return !!(this.attributes[name] &&
this.attributes[name].specified);
};
})(Element.prototype);
before()
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('before')) {
return;
}
Object.defineProperty(item, 'before', {
configurable: true,
enumerable: true,
writable: true,
value: function before () {
var argArr = Array.prototype.slice.call(arguments);
var docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem) {
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
});
this.parentNode.insertBefore(docFrag, this);
}
});
});
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
after()
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('after')) {
return;
}
Object.defineProperty(item, 'after', {
configurable: true,
enumerable: true,
writable: true,
value: function after () {
var argArr = Array.prototype.slice.call(arguments);
var docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem) {
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
});
this.parentNode.insertBefore(docFrag, this.nextSibling);
}
});
});
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
replaceWith()
(function () {
var ReplaceWith = function (Ele) {
var parent = this.parentNode;
var i = arguments.length;
var firstIsNode = +(parent && typeof Ele === 'object');
if (!parent) return;
while (i-- > firstIsNode) {
if (parent && typeof arguments[i] !== 'object') {
arguments[i] = document.createTextNode(arguments[i]);
} if (!parent && arguments[i].parentNode) {
arguments[i].parentNode.removeChild(arguments[i]);
continue;
}
parent.insertBefore(this.previousSibling, arguments[i]);
}
if (firstIsNode) parent.replaceChild(this, Ele);
};
if (!Element.prototype.replaceWith) {
Element.prototype.replaceWith = ReplaceWith;
}
if (!CharacterData.prototype.replaceWith) {
CharacterData.prototype.replaceWith = ReplaceWith;
}
if (!DocumentType.prototype.replaceWith) {
CharacterData.prototype.replaceWith = ReplaceWith;
}
})();
append()
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('append')) {
return;
}
Object.defineProperty(item, 'append', {
configurable: true,
enumerable: true,
writable: true,
value: function append() {
var argArr = Array.prototype.slice.call(arguments);
var docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem) {
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
});
this.appendChild(docFrag);
}
});
});
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
prepend()
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('prepend')) {
return;
}
Object.defineProperty(item, 'prepend', {
configurable: true,
enumerable: true,
writable: true,
value: function prepend() {
var argArr = Array.prototype.slice.call(arguments);
var docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem) {
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
});
this.insertBefore(docFrag, this.firstChild);
}
});
});
})([Element.prototype, Document.prototype, DocumentFragment.prototype]);
remove()
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('remove')) {
return;
}
Object.defineProperty(item, 'remove', {
configurable: true,
enumerable: true,
writable: true,
value: function remove() {
if (this.parentNode === null) {
return;
}
this.parentNode.removeChild(this);
}
});
});
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
document.scrollingElement
https://mths.be/scrollingelement v1.5.2 by @diegoperini & @mathias | MIT license
if (!('scrollingElement' in document)) (function () {
function computeStyle(element) {
if (window.getComputedStyle) {
// Support Firefox < 4 which throws on a single parameter.
return getComputedStyle(element, null);
}
// Support Internet Explorer < 9.
return element.currentStyle;
}
function isBodyElement(element) {
// The `instanceof` check gives the correct result for e.g. `body` in a
// non-HTML namespace.
if (window.HTMLBodyElement) {
return element instanceof HTMLBodyElement;
}
// Fall back to a `tagName` check for old browsers.
return /body/i.test(element.tagName);
}
function getNextBodyElement(frameset) {
// We use this function to be correct per spec in case `document.body` is
// a `frameset` but there exists a later `body`. Since `document.body` is
// a `frameset`, we know the root is an `html`, and there was no `body`
// before the `frameset`, so we just need to look at siblings after the
// `frameset`.
var current = frameset;
while (current = current.nextSibling) {
if (current.nodeType == 1 && isBodyElement(current)) {
return current;
}
}
// No `body` found.
return null;
}
// Note: standards mode / quirks mode can be toggled at runtime via
// `document.write`.
var isCompliantCached;
var isCompliant = function () {
var isStandardsMode = /^CSS1/.test(document.compatMode);
if (!isStandardsMode) {
// In quirks mode, the result is equivalent to the non-compliant
// standards mode behavior.
return false;
}
if (isCompliantCached === void 0) {
// When called for the first time, check whether the browser is
// standard-compliant, and cache the result.
var iframe = document.createElement('iframe');
iframe.style.height = '1px';
(document.body || document.documentElement || document).appendChild(iframe);
var doc = iframe.contentWindow.document;
doc.write('<!DOCTYPE html><div style="height:9999em">x</div>');
doc.close();
isCompliantCached = doc.documentElement.scrollHeight > doc.body.scrollHeight;
iframe.parentNode.removeChild(iframe);
}
return isCompliantCached;
};
function isRendered(style) {
return style.display != 'none' && !(style.visibility == 'collapse' &&
/^table-(.+-group|row|column)$/.test(style.display));
}
function isScrollable(body) {
// A `body` element is scrollable if `body` and `html` both have
// non-`visible` overflow and are both being rendered.
var bodyStyle = computeStyle(body);
var htmlStyle = computeStyle(document.documentElement);
return bodyStyle.overflow != 'visible' && htmlStyle.overflow != 'visible' &&
isRendered(bodyStyle) && isRendered(htmlStyle);
}
var scrollingElement = function () {
if (isCompliant()) {
return document.documentElement;
}
var body = document.body;
// Note: `document.body` could be a `frameset` element, or `null`.
// `tagName` is uppercase in HTML, but lowercase in XML.
var isFrameset = body && !/body/i.test(body.tagName);
body = isFrameset ? getNextBodyElement(body) : body;
// If `body` is itself scrollable, it is not the `scrollingElement`.
return body && isScrollable(body) ? null : body;
};
if (Object.defineProperty) {
// Support modern browsers that lack a native implementation.
Object.defineProperty(document, 'scrollingElement', {
'get': scrollingElement
});
} else if (document.__defineGetter__) {
// Support Firefox ≤ 3.6.9, Safari ≤ 4.1.3.
document.__defineGetter__('scrollingElement', scrollingElement);
} else {
// IE ≤ 4 lacks `attachEvent`, so it only gets this one assignment. IE ≤ 7
// gets it too, but the value is updated later (see `propertychange`).
document.scrollingElement = scrollingElement();
document.attachEvent && document.attachEvent('onpropertychange', function () {
// This is for IE ≤ 7 only.
// A `propertychange` event fires when `<body>` is parsed because
// `document.activeElement` then changes.
if (window.event.propertyName == 'activeElement') {
document.scrollingElement = scrollingElement();
}
});
}
}());
resize
resize polyfill for IE/Edge. @author zhangxinxu(.com)
if (typeof window.getComputedStyle(document.body).resize == 'undefined' && window.HTMLTextAreaElement) {
HTMLTextAreaElement.prototype.setResize = function () {
// 元素
var textarea = this;
var target = textarea.data && textarea.data.resize;
var resize = null;
// 文本域的id
var id = textarea.id;
if (!id) {
id = ('r' + Math.random()).replace('0.', '');
textarea.id = id;
}
// 获取resize属性值
var attrResize = textarea.getAttribute('resize');
if (typeof attrResize == 'string' && attrResize != 'vertical' && attrResize != 'horizontal') {
attrResize = 'both';
}
if (typeof attrResize != 'string') {
return;
}
// 创建模拟拉伸的基本元素
if (!target) {
target = document.createElement('span');
resize = document.createElement('label');
resize.setAttribute('for', id);
target.appendChild(resize);
// 一些固定的样式设置
target.style.position = 'relative';
target.style.verticalAlign = window.getComputedStyle(textarea).verticalAlign;
resize.style.position = 'absolute';
resize.style.width = '17px';
resize.style.height = '17px';
resize.style.background = "url(\"data:image/svg+xml,%3Csvg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M765.558 510.004a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0zM765.558 821.46a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0zM422.15700000000004 821.46a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0zM422.15700000000004 510.004a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0zM765.558 202.54a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0zM66.77700000000002 821.46a93.65 93.65 0 1 0 191.665 0 93.65 93.65 0 1 0-191.665 0z' fill='%23BFBFBF'/%3E%3C/svg%3E\") no-repeat center";
resize.style.bottom = '0';
resize.style.right = '0';
resize.style.backgroundSize = '12px 12px';
// 在textarea元素后面显示
textarea.insertAdjacentElement('afterend', target);
textarea.data = textarea.data || {};
textarea.data.resize = target;
// 事件
var store = {};
resize.addEventListener('mousedown', function (event) {
store.resizing = true;
store.startX = event.pageX;
store.startY = event.pageY;
// 此时textarea的尺寸
store.offsetWidth = textarea.offsetWidth;
store.offsetHeight = textarea.offsetHeight;
event.preventDefault();
});
document.addEventListener('mousemove', function (event) {
if (!store.resizing) {
return;
}
event.preventDefault();
var currentX = event.pageX;
var currentY = event.pageY;
var moveX = currentX - store.startX;
var moveY = currentY - store.startY;
var currentWidth = store.offsetWidth + moveX;
var currentHeight = store.offsetHeight + moveY;
if (currentWidth < 40) {
currentWidth = 40;
}
if (currentHeight < 40) {
currentHeight = 40;
}
// 尺寸设置
if (attrResize == 'both' || attrResize == 'horizontal') {
textarea.style.width = currentWidth + 'px';
if (target.style.display == 'block') {
target.style.width = currentWidth + 'px';
}
}
if (attrResize == 'both' || attrResize == 'vertical') {
textarea.style.height = currentHeight + 'px';
if (/inline/.test(styleDisplay)) {
target.style.height = currentHeight + 'px';
}
}
});
document.addEventListener('mouseup', function () {
if (store.resizing) {
store.resizing = false;
}
});
}
// 样式的控制与处理
var styleDisplay = window.getComputedStyle(textarea).display;
if (styleDisplay == 'none') {
target.style.display = 'none';
} else if (/inline/.test(styleDisplay)) {
target.style.display = 'inline-block';
target.style.height = textarea.offsetHeight + 'px';
} else {
target.style.display = 'block';
target.style.width = textarea.offsetWidth + 'px';
}
};
HTMLTextAreaElement.prototype.initResize = function () {
// 避免重复初始化
if (this.isInitResize) {
return;
}
this.setResize();
// 更新与处理
this.addEventListener('DOMAttrModified', function () {
this.setResize();
}, false);
this.isInitResize = true;
};
window.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('textarea[resize]').forEach(function (textarea) {
textarea.initResize();
});
// 插入内容时候的自动初始化
document.body.addEventListener('DOMNodeInserted', function (event) {
// 插入的元素
var target = event.target;
// 非元素节点不处理
if (target.nodeType != 1) {
return;
}
if (target.matches('textarea[resize]') && (!target.data || !target.data.resize)) {
target.initResize();
}
});
});
}
placeholder
zhangxinxu(.com)
only support one line no consideration of settings placeholder attr
if (!('placeholder' in document.createElement('input')) && window.HTMLTextAreaElement) {
HTMLTextAreaElement.prototype.setPlaceholder = HTMLInputElement.prototype.setPlaceholder = function () {
var control = this;
var placeholder = control.getAttribute('placeholder');
if (!placeholder) {
control.style.backgroundPosition = '-2999px -2999px';
return;
}
// 获取此时control的字体和字号
var stylesControl = window.getComputedStyle(control);
// 实现原理:创建一个offset screen canvas,并把placeholder绘制在上面
// 一些样式
var fontSize = stylesControl.fontSize;
var fontFamily = stylesControl.fontFamily;
var lineHeight = parseInt(stylesControl.lineHeight) || 20;
// 起始坐标
var x = parseInt(stylesControl.paddingLeft) || 0;
var y = parseInt(stylesControl.paddingTop) || 0;
// 尺寸
var width = control.clientWidth;
var height = control.offsetHeight;
// 如果隐藏,则不处理
var display = stylesControl.display;
if (display == 'none' || width == 0) {
return;
}
// canvas的创建
control.data = control.data || {};
// 先判断有没有缓存住
var canvas = control.data.placeholder;
// 如果没有,创建
if (!canvas) {
canvas = document.createElement('canvas');
// 存储canvas对象
control.data.placeholder = canvas;
}
// 如果尺寸没变化,placeholder也没变化,则不处理
if (canvas.placeholder == placeholder && canvas.width == width) {
return;
}
var context = canvas.getContext('2d');
if (canvas.width) {
context.clearRect(0, 0, canvas.width, canvas.height);
}
// 记住占位符内容
canvas.placeholder = placeholder;
// 尺寸变化
canvas.width = width;
canvas.height = height;
// 设置样式
context.fillStyle = '#a2a9b6';
context.font = [fontSize, fontFamily].join(' ');
context.textBaseline = 'top';
// 字符分隔为数组
var arrText = placeholder.split('');
var line = '';
var maxWidth = width - x * 2;
for (var n = 0; n < arrText.length; n++) {
var testLine = line + arrText[n];
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
context.fillText(line, x, y);
line = arrText[n];
y += lineHeight;
} else {
line = testLine;
}
}
context.fillText(line, x, y);
var backgroundImage = canvas.toDataURL();
control.style.backgroundRepeat = 'no-repeat';
control.style.backgroundImage = 'url(' + backgroundImage + ')';
};
HTMLTextAreaElement.prototype.initPlaceholder = HTMLInputElement.prototype.initPlaceholder = function () {
// 避免重复初始化
if (this.isInitPlaceholder) {
return;
}
this.setPlaceholder();
// 更新与处理
this.addEventListener('DOMAttrModified', function () {
this.setPlaceholder();
}, false);
this.addEventListener('focus', function () {
this.style.backgroundPosition = '-2999px -2999px';
});
this.addEventListener('blur', function () {
if (this.value.trim() == '') {
this.style.backgroundPosition = '';
}
});
this.isInitPlaceholder = true;
};
window.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('textarea[placeholder], input[placeholder]').forEach(function (control) {
control.initPlaceholder();
});
// 插入内容时候的自动初始化
document.body.addEventListener('DOMNodeInserted', function (event) {
// 插入的Node节点
var target = event.target;
// 非元素节点不处理
if (target.nodeType != 1) {
return;
}
if (/^textarea|input$/i.test(target.tagName) && target.matches('[placeholder]') && (!target.data || !target.data.placeholder)) {
target.initPlaceholder();
}
});
});
}