/*!
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;
//