'use strict';
/**
* standalone placeholder shim
* ===========================
* There are [a bunch of placeholder polyfills](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills#web-forms--input-placeholder) out there, but this one is different because:
* - it has no dependencies
* - it doesn't change the `value`
* - it works with weirdly-positioned elements (like `position: fixed`)
* - it can be manually triggered
* - the placeholder can be styled
* - it's made for IE8 and IE9 and no other browsers
*/
var CSS_PROPERTIES_TO_STEAL = [
'border-width',
'font',
'fontFamily',
'fontSize',
'fontSizeAdjust',
'fontStretch',
'fontStyle',
'fontVariant',
'fontVariantAlternates',
'fontVariantCaps',
'fontVariantEastAsian',
'fontVariantLigatures',
'fontVariantNumeric',
'fontWeight',
'lineHeight',
'padding',
'textAlign',
'textShadow'
];
var hasAddedGlobalStyles = false;
// the big kahuna
function placeholderShim(inputEl) {
var placeholderEl, displayShow;
var testInput = document.createElement('input');
var isNativelySupported = testInput.placeholder !== void 0; // eslint-disable-line no-void
if (isNativelySupported) {
// This browser supports placeholders natively, so do nothing.
return {};
}
addGlobalStyles();
placeholderEl = createPlaceholderFor(inputEl);
inputEl.parentNode.appendChild(placeholderEl);
displayShow = getStyle(inputEl, 'display') || 'block';
function update(force) {
var shouldShow = force == null ? !inputEl.value : force;
placeholderEl.style.display = shouldShow ? displayShow : 'none';
}
update();
if (inputEl.attachEvent) {
inputEl.attachEvent('onfocus', function () { update(false); });
inputEl.attachEvent('onblur', function () { update(); });
placeholderEl.attachEvent('onclick', function () { inputEl.focus(); });
}
return new Placeholder();
}
function Placeholder() {}
// TODO
extend(Placeholder.prototype, {
redraw: noop,
destroy: noop
});
// the private methods
function noop() {}
function extend(dest, source) {
var prop;
for (prop in source) {
if (source.hasOwnProperty(prop) && source[prop] != null) {
dest[prop] = source[prop];
}
}
}
function addGlobalStyles() {
var sheet, head, style;
if (hasAddedGlobalStyles) { return; }
sheet = document.styleSheets && document.styleSheets[0];
if (!sheet) {
head = document.head || document.getElementsByTagName('head')[0];
style = document.createElement('style');
head.appendChild(style);
sheet = style.sheet;
}
sheet.addRule('.placeholder-shim', 'color: #999;', 0);
hasAddedGlobalStyles = true;
}
function createPlaceholderFor(el) {
var result = document.createElement('div');
updateParentPositionFor(el);
addProperties(result);
stealStyles(el, result);
addStyles(result);
stealPlaceholder(el, result);
return result;
}
function addProperties(result) {
result.setAttribute('unselectable', 'on');
}
function stealStyles(src, dest) {
var newStyles = {
width: src.offsetWidth + 'px',
height: src.offsetHeight + 'px'
};
var i, property, zIndex, borderTop, borderLeft;
for (i = 0; i < CSS_PROPERTIES_TO_STEAL.length; i++) {
property = CSS_PROPERTIES_TO_STEAL[i];
newStyles[property] = getStyle(src, property);
}
zIndex = getStyle(src, 'zIndex');
newStyles.zIndex = typeof zIndex === 'number' ? zIndex + 1 : 999;
if (getStyle(src, 'position') === 'fixed') {
extend(newStyles, {
position: 'fixed',
margin: getStyle(src, 'margin'),
top: getStyle(src, 'top'),
left: getStyle(src, 'left'),
bottom: getStyle(src, 'bottom'),
right: getStyle(src, 'right')
});
} else {
borderTop = parseFloat(getStyle(src, 'borderTopWidth')) || 0;
borderLeft = parseFloat(getStyle(src, 'borderLeftWidth')) || 0;
extend(newStyles, {
position: 'absolute',
top: src.offsetTop + borderTop + 'px',
left: src.offsetLeft + borderLeft + 'px'
});
}
extend(dest.style, newStyles);
}
function addStyles(dest) {
dest.className = 'placeholder-shim';
extend(dest.style, {
boxSizing: 'border-box',
borderColor: 'transparent',
overflow: 'hidden',
whiteSpace: 'nowrap'
});
}
function updateParentPositionFor(el) {
var parent = el.offsetParent;
if (parent && getStyle(parent, 'position') === 'static') {
parent.style.position = 'relative';
}
}
function stealPlaceholder(src, dest) {
var result = src.getAttribute('placeholder') ||
src.attributes.placeholder && src.attributes.placeholder.nodeValue ||
'';
result = result.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
dest.innerHTML = result;
}
function getStyle(elem, prop) {
if (elem.currentStyle) {
return elem.currentStyle[prop];
} else if (window.getComputedStyle && elem instanceof HTMLElement) {
return document.defaultView.getComputedStyle(elem, null)[prop];
} else if (prop in elem.style) {
return elem.style[prop];
}
return null;
}
module.exports = placeholderShim;