/*!
Holder - client side image placeholders
Version 2.9.6+fblyy
漏 2018 Ivan Malopinsky - http://imsky.co
Site: http://holderjs.com
Issues: https://github.com/imsky/holder/issues
License: MIT
婕旂ず:
鍗犱綅鍥剧墖 涓嶆姤閿�(鍚庣画闇�鏇存敼);
鍗犱綅鍥剧墖 浼氭姤閿�
*/
(function (window) {
if (!window.document) return;
var document = window.document;
//https://github.com/inexorabletash/polyfill/blob/master/web.js
if (!document.querySelectorAll) {
document.querySelectorAll = function (selectors) {
var style = document.createElement('style'), elements = [], element;
document.documentElement.firstChild.appendChild(style);
document._qsa = [];
style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}';
window.scrollBy(0, 0);
style.parentNode.removeChild(style);
while (document._qsa.length) {
element = document._qsa.shift();
element.style.removeAttribute('x-qsa');
elements.push(element);
}
document._qsa = null;
return elements;
};
}
if (!document.querySelector) {
document.querySelector = function (selectors) {
var elements = document.querySelectorAll(selectors);
return (elements.length) ? elements[0] : null;
};
}
if (!document.getElementsByClassName) {
document.getElementsByClassName = function (classNames) {
classNames = String(classNames).replace(/^|\s+/g, '.');
return document.querySelectorAll(classNames);
};
}
//https://github.com/inexorabletash/polyfill
// ES5 15.2.3.14 Object.keys ( O )
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = function (o) {
if (o !== Object(o)) { throw TypeError('Object.keys called on non-object'); }
var ret = [], p;
for (p in o) {
if (Object.prototype.hasOwnProperty.call(o, p)) {
ret.push(p);
}
}
return ret;
};
}
// ES5 15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fun /*, thisp */) {
if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function") { throw TypeError(); }
var thisp = arguments[1], i;
for (i = 0; i < len; i++) {
if (i in t) {
fun.call(thisp, t[i], i, t);
}
}
};
}
//https://github.com/inexorabletash/polyfill/blob/master/web.js
(function (global) {
var B64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
global.atob = global.atob || function (input) {
input = String(input);
var position = 0,
output = [],
buffer = 0, bits = 0, n;
input = input.replace(/\s/g, '');
if ((input.length % 4) === 0) { input = input.replace(/=+$/, ''); }
if ((input.length % 4) === 1) { throw Error('InvalidCharacterError'); }
if (/[^+/0-9A-Za-z]/.test(input)) { throw Error('InvalidCharacterError'); }
while (position < input.length) {
n = B64_ALPHABET.indexOf(input.charAt(position));
buffer = (buffer << 6) | n;
bits += 6;
if (bits === 24) {
output.push(String.fromCharCode((buffer >> 16) & 0xFF));
output.push(String.fromCharCode((buffer >> 8) & 0xFF));
output.push(String.fromCharCode(buffer & 0xFF));
bits = 0;
buffer = 0;
}
position += 1;
}
if (bits === 12) {
buffer = buffer >> 4;
output.push(String.fromCharCode(buffer & 0xFF));
} else if (bits === 18) {
buffer = buffer >> 2;
output.push(String.fromCharCode((buffer >> 8) & 0xFF));
output.push(String.fromCharCode(buffer & 0xFF));
}
return output.join('');
};
global.btoa = global.btoa || function (input) {
input = String(input);
var position = 0,
out = [],
o1, o2, o3,
e1, e2, e3, e4;
if (/[^\x00-\xFF]/.test(input)) { throw Error('InvalidCharacterError'); }
while (position < input.length) {
o1 = input.charCodeAt(position++);
o2 = input.charCodeAt(position++);
o3 = input.charCodeAt(position++);
// 111111 112222 222233 333333
e1 = o1 >> 2;
e2 = ((o1 & 0x3) << 4) | (o2 >> 4);
e3 = ((o2 & 0xf) << 2) | (o3 >> 6);
e4 = o3 & 0x3f;
if (position === input.length + 2) {
e3 = 64; e4 = 64;
}
else if (position === input.length + 1) {
e4 = 64;
}
out.push(B64_ALPHABET.charAt(e1),
B64_ALPHABET.charAt(e2),
B64_ALPHABET.charAt(e3),
B64_ALPHABET.charAt(e4));
}
return out.join('');
};
}(window));
//https://gist.github.com/jimeh/332357
if (!Object.prototype.hasOwnProperty){
/*jshint -W001, -W103 */
Object.prototype.hasOwnProperty = function(prop) {
var proto = this.__proto__ || this.constructor.prototype;
return (prop in this) && (!(prop in proto) || proto[prop] !== this[prop]);
};
/*jshint +W001, +W103 */
}
// @license http://opensource.org/licenses/MIT
// copyright Paul Irish 2015
// Date.now() is supported everywhere except IE8. For IE8 we use the Date.now polyfill
// github.com/Financial-Times/polyfill-service/blob/master/polyfills/Date.now/polyfill.js
// as Safari 6 doesn't have support for NavigationTiming, we use a Date.now() timestamp for relative values
// if you want values similar to what you'd get with real perf.now, place this towards the head of the page
// but in reality, you're just getting the delta between now() calls, so it's not terribly important where it's placed
(function(){
if ('performance' in window === false) {
window.performance = {};
}
Date.now = (Date.now || function () { // thanks IE8
return new Date().getTime();
});
if ('now' in window.performance === false){
var nowOffset = Date.now();
if (performance.timing && performance.timing.navigationStart){
nowOffset = performance.timing.navigationStart;
}
window.performance.now = function now(){
return Date.now() - nowOffset;
};
}
})();
//requestAnimationFrame polyfill for older Firefox/Chrome versions
if (!window.requestAnimationFrame) {
if (window.webkitRequestAnimationFrame && window.webkitCancelAnimationFrame) {
//https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/requestAnimationFrame/polyfill-webkit.js
(function (global) {
global.requestAnimationFrame = function (callback) {
return webkitRequestAnimationFrame(function () {
callback(global.performance.now());
});
};
global.cancelAnimationFrame = global.webkitCancelAnimationFrame;
}(window));
} else if (window.mozRequestAnimationFrame && window.mozCancelAnimationFrame) {
//https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/requestAnimationFrame/polyfill-moz.js
(function (global) {
global.requestAnimationFrame = function (callback) {
return mozRequestAnimationFrame(function () {
callback(global.performance.now());
});
};
global.cancelAnimationFrame = global.mozCancelAnimationFrame;
}(window));
} else {
(function (global) {
global.requestAnimationFrame = function (callback) {
return global.setTimeout(callback, 1000 / 60);
};
global.cancelAnimationFrame = global.clearTimeout;
})(window);
}
}
})(this);
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Holder"] = factory();
else
root["Holder"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
/*
Holder.js - client side image placeholders
(c) 2012-2015 Ivan Malopinsky - http://imsky.co
*/
module.exports = __webpack_require__(1);
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {/*
Holder.js - client side image placeholders
(c) 2012-2016 Ivan Malopinsky - http://imsky.co
*/
//Libraries and functions
var onDomReady = __webpack_require__(2);
var querystring = __webpack_require__(3);
var SceneGraph = __webpack_require__(6);
var utils = __webpack_require__(7);
var SVG = __webpack_require__(8);
var DOM = __webpack_require__(9);
var Color = __webpack_require__(10);
var constants = __webpack_require__(11);
var svgRenderer = __webpack_require__(12);
var sgCanvasRenderer = __webpack_require__(15);
var extend = utils.extend;
var dimensionCheck = utils.dimensionCheck;
//Constants and definitions
var SVG_NS = constants.svg_ns;
var Holder = {
version: constants.version,
/**
* Adds a theme to default settings
*
* @param {string} name Theme name
* @param {Object} theme Theme object, with foreground, background, size, font, and fontweight properties.
*/
addTheme: function(name, theme) {
name != null && theme != null && (App.settings.themes[name] = theme);
delete App.vars.cache.themeKeys;
return this;
},
/**
* Appends a placeholder to an element
*
* @param {string} src Placeholder URL string
* @param el A selector or a reference to a DOM node
*/
addImage: function(src, el) {
//todo: use jquery fallback if available for all QSA references
var nodes = DOM.getNodeArray(el);
nodes.forEach(function (node) {
var img = DOM.newEl('img');
var domProps = {};
domProps[App.setup.dataAttr] = src;
DOM.setAttr(img, domProps);
node.appendChild(img);
});
return this;
},
/**
* Sets whether or not an image is updated on resize.
* If an image is set to be updated, it is immediately rendered.
*
* @param {Object} el Image DOM element
* @param {Boolean} value Resizable update flag value
*/
setResizeUpdate: function(el, value) {
if (el.holderData) {
el.holderData.resizeUpdate = !!value;
if (el.holderData.resizeUpdate) {
updateResizableElements(el);
}
}
},
/**
* Runs Holder with options. By default runs Holder on all images with "holder.js" in their source attributes.
*
* @param {Object} userOptions Options object, can contain domain, themes, images, and bgnodes properties
*/
run: function(userOptions) {
//todo: split processing into separate queues
userOptions = userOptions || {};
var engineSettings = {};
var options = extend(App.settings, userOptions);
App.vars.preempted = true;
App.vars.dataAttr = options.dataAttr || App.setup.dataAttr;
engineSettings.renderer = options.renderer ? options.renderer : App.setup.renderer;
if (App.setup.renderers.join(',').indexOf(engineSettings.renderer) === -1) {
engineSettings.renderer = App.setup.supportsSVG ? 'svg' : (App.setup.supportsCanvas ? 'canvas' : 'html');
}
var images = DOM.getNodeArray(options.images);
var bgnodes = DOM.getNodeArray(options.bgnodes);
var stylenodes = DOM.getNodeArray(options.stylenodes);
var objects = DOM.getNodeArray(options.objects);
engineSettings.stylesheets = [];
engineSettings.svgXMLStylesheet = true;
engineSettings.noFontFallback = !!options.noFontFallback;
engineSettings.noBackgroundSize = !!options.noBackgroundSize;
stylenodes.forEach(function (styleNode) {
if (styleNode.attributes.rel && styleNode.attributes.href && styleNode.attributes.rel.value == 'stylesheet') {
var href = styleNode.attributes.href.value;
//todo: write isomorphic relative-to-absolute URL function
var proxyLink = DOM.newEl('a');
proxyLink.href = href;
var stylesheetURL = proxyLink.protocol + '//' + proxyLink.host + proxyLink.pathname + proxyLink.search;
engineSettings.stylesheets.push(stylesheetURL);
}
});
bgnodes.forEach(function (bgNode) {
//Skip processing background nodes if getComputedStyle is unavailable, since only modern browsers would be able to use canvas or SVG to render to background
if (!global.getComputedStyle) return;
var backgroundImage = global.getComputedStyle(bgNode, null).getPropertyValue('background-image');
var dataBackgroundImage = bgNode.getAttribute('data-background-src');
var rawURL = dataBackgroundImage || backgroundImage;
var holderURL = null;
var holderString = options.domain + '/';
var holderStringIndex = rawURL.indexOf(holderString);
if (holderStringIndex === 0) {
holderURL = rawURL;
} else if (holderStringIndex === 1 && rawURL[0] === '?') {
holderURL = rawURL.slice(1);
} else {
var fragment = rawURL.substr(holderStringIndex).match(/([^\"]*)"?\)/);
if (fragment !== null) {
holderURL = fragment[1];
} else if (rawURL.indexOf('url(') === 0) {
throw 'Holder: unable to parse background URL: ' + rawURL;
}
}
if (holderURL) {
var holderFlags = parseURL(holderURL, options);
if (holderFlags) {
prepareDOMElement({
mode: 'background',
el: bgNode,
flags: holderFlags,
engineSettings: engineSettings
});
}
}
});
objects.forEach(function (object) {
var objectAttr = {};
try {
objectAttr.data = object.getAttribute('data');
objectAttr.dataSrc = object.getAttribute(App.vars.dataAttr);
} catch (e) {}
var objectHasSrcURL = objectAttr.data != null && objectAttr.data.indexOf(options.domain) === 0;
var objectHasDataSrcURL = objectAttr.dataSrc != null && objectAttr.dataSrc.indexOf(options.domain) === 0;
if (objectHasSrcURL) {
prepareImageElement(options, engineSettings, objectAttr.data, object);
} else if (objectHasDataSrcURL) {
prepareImageElement(options, engineSettings, objectAttr.dataSrc, object);
}
});
images.forEach(function (image) {
var imageAttr = {};
try {
imageAttr.src = image.getAttribute('src');
imageAttr.dataSrc = image.getAttribute(App.vars.dataAttr);
imageAttr.rendered = image.getAttribute('data-holder-rendered');
} catch (e) {}
var imageHasSrc = imageAttr.src != null;
var imageHasDataSrcURL = imageAttr.dataSrc != null && imageAttr.dataSrc.indexOf(options.domain) === 0;
var imageRendered = imageAttr.rendered != null && imageAttr.rendered == 'true';
if (imageHasSrc) {
if (imageAttr.src.indexOf(options.domain) === 0) {
prepareImageElement(options, engineSettings, imageAttr.src, image);
} else if (imageHasDataSrcURL) {
//Image has a valid data-src and an invalid src
if (imageRendered) {
//If the placeholder has already been render, re-render it
prepareImageElement(options, engineSettings, imageAttr.dataSrc, image);
} else {
//If the placeholder has not been rendered, check if the image exists and render a fallback if it doesn't
(function(src, options, engineSettings, dataSrc, image) {
utils.imageExists(src, function(exists) {
if (!exists) {
prepareImageElement(options, engineSettings, dataSrc, image);
}
});
})(imageAttr.src, options, engineSettings, imageAttr.dataSrc, image);
}
}
} else if (imageHasDataSrcURL) {
prepareImageElement(options, engineSettings, imageAttr.dataSrc, image);
}
});
return this;
}
};
var App = {
settings: {
domain: 'holder.js',
images: 'img',
objects: 'object',
bgnodes: 'body .holderjs',
stylenodes: 'head link.holderjs',
themes: {
'gray': {
bg: '#EEEEEE',
fg: '#AAAAAA'
},
'social': {
bg: '#3a5a97',
fg: '#FFFFFF'
},
'industrial': {
bg: '#434A52',
fg: '#C2F200'
},
'sky': {
bg: '#0D8FDB',
fg: '#FFFFFF'
},
'vine': {
bg: '#39DBAC',
fg: '#1E292C'
},
'lava': {
bg: '#F8591A',
fg: '#1C2846'
}
}
},
defaults: {
size: 10,
units: 'pt',
scale: 1 / 16
}
};
/**
* Processes provided source attribute and sets up the appropriate rendering workflow
*
* @private
* @param options Instance options from Holder.run
* @param renderSettings Instance configuration
* @param src Image URL
* @param el Image DOM element
*/
function prepareImageElement(options, engineSettings, src, el) {
var holderFlags = parseURL(src.substr(src.lastIndexOf(options.domain)), options);
if (holderFlags) {
prepareDOMElement({
mode: null,
el: el,
flags: holderFlags,
engineSettings: engineSettings
});
}
}
/**
* Processes a Holder URL and extracts configuration from query string
*
* @private
* @param url URL
* @param instanceOptions Instance options from Holder.run
*/
function parseURL(url, instanceOptions) {
var holder = {
theme: extend(App.settings.themes.gray, null),
stylesheets: instanceOptions.stylesheets,
instanceOptions: instanceOptions
};
var firstQuestionMark = url.indexOf('?');
var parts = [url];
if (firstQuestionMark !== -1) {
parts = [url.slice(0, firstQuestionMark), url.slice(firstQuestionMark + 1)];
}
var basics = parts[0].split('/');
holder.holderURL = url;
var dimensions = basics[1];
var dimensionData = dimensions.match(/([\d]+p?)x([\d]+p?)/);
if (!dimensionData) return false;
holder.fluid = dimensions.indexOf('p') !== -1;
holder.dimensions = {
width: dimensionData[1].replace('p', '%'),
height: dimensionData[2].replace('p', '%')
};
if (parts.length === 2) {
var options = querystring.parse(parts[1]);
// Dimensions
if (utils.truthy(options.ratio)) {
holder.fluid = true;
var ratioWidth = parseFloat(holder.dimensions.width.replace('%', ''));
var ratioHeight = parseFloat(holder.dimensions.height.replace('%', ''));
ratioHeight = Math.floor(100 * (ratioHeight / ratioWidth));
ratioWidth = 100;
holder.dimensions.width = ratioWidth + '%';
holder.dimensions.height = ratioHeight + '%';
}
holder.auto = utils.truthy(options.auto);
// Colors
if (options.bg) {
holder.theme.bg = utils.parseColor(options.bg);
}
if (options.fg) {
holder.theme.fg = utils.parseColor(options.fg);
}
//todo: add automatic foreground to themes without foreground
if (options.bg && !options.fg) {
holder.autoFg = true;
}
if (options.theme && holder.instanceOptions.themes.hasOwnProperty(options.theme)) {
holder.theme = extend(holder.instanceOptions.themes[options.theme], null);
}
// Text
if (options.text) {
holder.text = options.text;
}
if (options.textmode) {
holder.textmode = options.textmode;
}
if (options.size && parseFloat(options.size)) {
holder.size = parseFloat(options.size);
}
if (options.font) {
holder.font = options.font;
}
if (options.align) {
holder.align = options.align;
}
if (options.lineWrap) {
holder.lineWrap = options.lineWrap;
}
holder.nowrap = utils.truthy(options.nowrap);
// Miscellaneous
holder.outline = utils.truthy(options.outline);
if (utils.truthy(options.random)) {
App.vars.cache.themeKeys = App.vars.cache.themeKeys || Object.keys(holder.instanceOptions.themes);
var _theme = App.vars.cache.themeKeys[0 | Math.random() * App.vars.cache.themeKeys.length];
holder.theme = extend(holder.instanceOptions.themes[_theme], null);
}
}
return holder;
}
/**
* Modifies the DOM to fit placeholders and sets up resizable image callbacks (for fluid and automatically sized placeholders)
*
* @private
* @param settings DOM prep settings
*/
function prepareDOMElement(prepSettings) {
var mode = prepSettings.mode;
var el = prepSettings.el;
var flags = prepSettings.flags;
var _engineSettings = prepSettings.engineSettings;
var dimensions = flags.dimensions,
theme = flags.theme;
var dimensionsCaption = dimensions.width + 'x' + dimensions.height;
mode = mode == null ? (flags.fluid ? 'fluid' : 'image') : mode;
var holderTemplateRe = /holder_([a-z]+)/g;
var dimensionsInText = false;
if (flags.text != null) {
theme.text = flags.text;
//