diff --git a/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.js b/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.js new file mode 100644 index 0000000..db1e43b --- /dev/null +++ b/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.js @@ -0,0 +1,3063 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://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-2020 Ivan Malopinsky - https://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-2020 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; + + // SVG embedding doesn't parse Unicode properly + if (el.nodeName.toLowerCase() === 'object') { + var textLines = theme.text.split('\\n'); + for (var k = 0; k < textLines.length; k++) { + textLines[k] = utils.encodeHtmlEntity(textLines[k]); + } + theme.text = textLines.join('\\n'); + } + } + + if (theme.text) { + var holderTemplateMatches = theme.text.match(holderTemplateRe); + + if (holderTemplateMatches !== null) { + //todo: optimize template replacement + holderTemplateMatches.forEach(function (match) { + if (match === 'holder_dimensions') { + theme.text = theme.text.replace(match, dimensionsCaption); + } + }); + } + } + + var holderURL = flags.holderURL; + var engineSettings = extend(_engineSettings, null); + + if (flags.font) { + /* + If external fonts are used in a placeholder rendered with SVG, Holder falls back to canvas. + + This is done because Firefox and Chrome disallow embedded SVGs from referencing external assets. + The workaround is either to change the placeholder tag from to or to use the canvas renderer. + */ + theme.font = flags.font; + if (!engineSettings.noFontFallback && el.nodeName.toLowerCase() === 'img' && App.setup.supportsCanvas && engineSettings.renderer === 'svg') { + engineSettings = extend(engineSettings, { + renderer: 'canvas' + }); + } + } + + //Chrome and Opera require a quick 10ms re-render if web fonts are used with canvas + if (flags.font && engineSettings.renderer == 'canvas') { + engineSettings.reRender = true; + } + + if (mode == 'background') { + if (el.getAttribute('data-background-src') == null) { + DOM.setAttr(el, { + 'data-background-src': holderURL + }); + } + } else { + var domProps = {}; + domProps[App.vars.dataAttr] = holderURL; + DOM.setAttr(el, domProps); + } + + flags.theme = theme; + + //todo consider using all renderSettings in holderData + el.holderData = { + flags: flags, + engineSettings: engineSettings + }; + + if (mode == 'image' || mode == 'fluid') { + DOM.setAttr(el, { + 'alt': theme.text ? (dimensionsInText ? theme.text : theme.text + ' [' + dimensionsCaption + ']') : dimensionsCaption + }); + } + + var renderSettings = { + mode: mode, + el: el, + holderSettings: { + dimensions: dimensions, + theme: theme, + flags: flags + }, + engineSettings: engineSettings + }; + + if (mode == 'image') { + if (!flags.auto) { + el.style.width = dimensions.width + 'px'; + el.style.height = dimensions.height + 'px'; + } + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + render(renderSettings); + + if (flags.textmode == 'exact') { + el.holderData.resizeUpdate = true; + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } else if (mode == 'background' && engineSettings.renderer != 'html') { + render(renderSettings); + } else if (mode == 'fluid') { + el.holderData.resizeUpdate = true; + + if (dimensions.height.slice(-1) == '%') { + el.style.height = dimensions.height; + } else if (flags.auto == null || !flags.auto) { + el.style.height = dimensions.height + 'px'; + } + if (dimensions.width.slice(-1) == '%') { + el.style.width = dimensions.width; + } else if (flags.auto == null || !flags.auto) { + el.style.width = dimensions.width + 'px'; + } + if (el.style.display == 'inline' || el.style.display === '' || el.style.display == 'none') { + el.style.display = 'block'; + } + + setInitialDimensions(el); + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } + + /** + * Core function that takes output from renderers and sets it as the source or background-image of the target element + * + * @private + * @param renderSettings Renderer settings + */ + function render(renderSettings) { + var image = null; + var mode = renderSettings.mode; + var el = renderSettings.el; + var holderSettings = renderSettings.holderSettings; + var engineSettings = renderSettings.engineSettings; + + switch (engineSettings.renderer) { + case 'svg': + if (!App.setup.supportsSVG) return; + break; + case 'canvas': + if (!App.setup.supportsCanvas) return; + break; + default: + return; + } + + //todo: move generation of scene up to flag generation to reduce extra object creation + var scene = { + width: holderSettings.dimensions.width, + height: holderSettings.dimensions.height, + theme: holderSettings.theme, + flags: holderSettings.flags + }; + + var sceneGraph = buildSceneGraph(scene); + + function getRenderedImage() { + var image = null; + switch (engineSettings.renderer) { + case 'canvas': + image = sgCanvasRenderer(sceneGraph, renderSettings); + break; + case 'svg': + image = svgRenderer(sceneGraph, renderSettings); + break; + default: + throw 'Holder: invalid renderer: ' + engineSettings.renderer; + } + + return image; + } + + image = getRenderedImage(); + + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + + //todo: add canvas rendering + if (mode == 'background') { + el.style.backgroundImage = 'url(' + image + ')'; + + if (!engineSettings.noBackgroundSize) { + el.style.backgroundSize = scene.width + 'px ' + scene.height + 'px'; + } + } else { + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + if (engineSettings.reRender) { + global.setTimeout(function () { + var image = getRenderedImage(); + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + //todo: refactor this code into a function + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + }, 150); + } + } + //todo: account for re-rendering + DOM.setAttr(el, { + 'data-holder-rendered': true + }); + } + + /** + * Core function that takes a Holder scene description and builds a scene graph + * + * @private + * @param scene Holder scene object + */ + //todo: make this function reusable + //todo: merge app defaults and setup properties into the scene argument + function buildSceneGraph(scene) { + var fontSize = App.defaults.size; + if (parseFloat(scene.theme.size)) { + fontSize = scene.theme.size; + } else if (parseFloat(scene.flags.size)) { + fontSize = scene.flags.size; + } + + scene.font = { + family: scene.theme.font ? scene.theme.font : 'Arial, Helvetica, Open Sans, sans-serif', + size: textSize(scene.width, scene.height, fontSize, App.defaults.scale), + units: scene.theme.units ? scene.theme.units : App.defaults.units, + weight: scene.theme.fontweight ? scene.theme.fontweight : 'bold' + }; + + scene.text = scene.theme.text || Math.floor(scene.width) + 'x' + Math.floor(scene.height); + + scene.noWrap = scene.theme.nowrap || scene.flags.nowrap; + + scene.align = scene.theme.align || scene.flags.align || 'center'; + + switch (scene.flags.textmode) { + case 'literal': + scene.text = scene.flags.dimensions.width + 'x' + scene.flags.dimensions.height; + break; + case 'exact': + if (!scene.flags.exactDimensions) break; + scene.text = Math.floor(scene.flags.exactDimensions.width) + 'x' + Math.floor(scene.flags.exactDimensions.height); + break; + } + + var lineWrap = scene.flags.lineWrap || App.setup.lineWrapRatio; + var sceneMargin = scene.width * lineWrap; + var maxLineWidth = sceneMargin; + + var sceneGraph = new SceneGraph({ + width: scene.width, + height: scene.height + }); + + var Shape = sceneGraph.Shape; + + var holderBg = new Shape.Rect('holderBg', { + fill: scene.theme.bg + }); + + holderBg.resize(scene.width, scene.height); + sceneGraph.root.add(holderBg); + + if (scene.flags.outline) { + var outlineColor = new Color(holderBg.properties.fill); + outlineColor = outlineColor.lighten(outlineColor.lighterThan('7f7f7f') ? -0.1 : 0.1); + holderBg.properties.outline = { + fill: outlineColor.toHex(true), + width: 2 + }; + } + + var holderTextColor = scene.theme.fg; + + if (scene.flags.autoFg) { + var holderBgColor = new Color(holderBg.properties.fill); + var lightColor = new Color('fff'); + var darkColor = new Color('000', { + 'alpha': 0.285714 + }); + + holderTextColor = holderBgColor.blendAlpha(holderBgColor.lighterThan('7f7f7f') ? darkColor : lightColor).toHex(true); + } + + var holderTextGroup = new Shape.Group('holderTextGroup', { + text: scene.text, + align: scene.align, + font: scene.font, + fill: holderTextColor + }); + + holderTextGroup.moveTo(null, null, 1); + sceneGraph.root.add(holderTextGroup); + + var tpdata = holderTextGroup.textPositionData = stagingRenderer(sceneGraph); + if (!tpdata) { + throw 'Holder: staging fallback not supported yet.'; + } + holderTextGroup.properties.leading = tpdata.boundingBox.height; + + var textNode = null; + var line = null; + + function finalizeLine(parent, line, width, height) { + line.width = width; + line.height = height; + parent.width = Math.max(parent.width, line.width); + parent.height += line.height; + } + + if (tpdata.lineCount > 1) { + var offsetX = 0; + var offsetY = 0; + var lineIndex = 0; + var lineKey; + line = new Shape.Group('line' + lineIndex); + + //Double margin so that left/right-aligned next is not flush with edge of image + if (scene.align === 'left' || scene.align === 'right') { + maxLineWidth = scene.width * (1 - (1 - lineWrap) * 2); + } + + for (var i = 0; i < tpdata.words.length; i++) { + var word = tpdata.words[i]; + textNode = new Shape.Text(word.text); + var newline = word.text == '\\n'; + if (!scene.noWrap && (offsetX + word.width >= maxLineWidth || newline === true)) { + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + offsetX = 0; + offsetY += holderTextGroup.properties.leading; + lineIndex += 1; + line = new Shape.Group('line' + lineIndex); + line.y = offsetY; + } + if (newline === true) { + continue; + } + textNode.moveTo(offsetX, 0); + offsetX += tpdata.spaceWidth + word.width; + line.add(textNode); + } + + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo(scene.width - line.width, null, null); + } + + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo((holderTextGroup.width - line.width) / 2, null, null); + } + + holderTextGroup.moveTo((scene.width - holderTextGroup.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - holderTextGroup.height) / 2, null); + + //If the text exceeds vertical space, move it down so the first line is visible + if ((scene.height - holderTextGroup.height) / 2 < 0) { + holderTextGroup.moveTo(null, 0, null); + } + } else { + textNode = new Shape.Text(scene.text); + line = new Shape.Group('line0'); + line.add(textNode); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + holderTextGroup.moveTo((scene.width - tpdata.boundingBox.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - tpdata.boundingBox.height) / 2, null); + } + + //todo: renderlist + return sceneGraph; + } + + /** + * Adaptive text sizing function + * + * @private + * @param width Parent width + * @param height Parent height + * @param fontSize Requested text size + * @param scale Proportional scale of text + */ + function textSize(width, height, fontSize, scale) { + var stageWidth = parseInt(width, 10); + var stageHeight = parseInt(height, 10); + + var bigSide = Math.max(stageWidth, stageHeight); + var smallSide = Math.min(stageWidth, stageHeight); + + var newHeight = 0.8 * Math.min(smallSide, bigSide * scale); + return Math.round(Math.max(fontSize, newHeight)); + } + + /** + * Iterates over resizable (fluid or auto) placeholders and renders them + * + * @private + * @param element Optional element selector, specified only if a specific element needs to be re-rendered + */ + function updateResizableElements(element) { + var images; + if (element == null || element.nodeType == null) { + images = App.vars.resizableImages; + } else { + images = [element]; + } + for (var i = 0, l = images.length; i < l; i++) { + var el = images[i]; + if (el.holderData) { + var flags = el.holderData.flags; + var dimensions = dimensionCheck(el); + if (dimensions) { + if (!el.holderData.resizeUpdate) { + continue; + } + + if (flags.fluid && flags.auto) { + var fluidConfig = el.holderData.fluidConfig; + switch (fluidConfig.mode) { + case 'width': + dimensions.height = dimensions.width / fluidConfig.ratio; + break; + case 'height': + dimensions.width = dimensions.height * fluidConfig.ratio; + break; + } + } + + var settings = { + mode: 'image', + holderSettings: { + dimensions: dimensions, + theme: flags.theme, + flags: flags + }, + el: el, + engineSettings: el.holderData.engineSettings + }; + + if (flags.textmode == 'exact') { + flags.exactDimensions = dimensions; + settings.holderSettings.dimensions = flags.dimensions; + } + + render(settings); + } else { + setInvisible(el); + } + } + } + } + + /** + * Sets up aspect ratio metadata for fluid placeholders, in order to preserve proportions when resizing + * + * @private + * @param el Image DOM element + */ + function setInitialDimensions(el) { + if (el.holderData) { + var dimensions = dimensionCheck(el); + if (dimensions) { + var flags = el.holderData.flags; + + var fluidConfig = { + fluidHeight: flags.dimensions.height.slice(-1) == '%', + fluidWidth: flags.dimensions.width.slice(-1) == '%', + mode: null, + initialDimensions: dimensions + }; + + if (fluidConfig.fluidWidth && !fluidConfig.fluidHeight) { + fluidConfig.mode = 'width'; + fluidConfig.ratio = fluidConfig.initialDimensions.width / parseFloat(flags.dimensions.height); + } else if (!fluidConfig.fluidWidth && fluidConfig.fluidHeight) { + fluidConfig.mode = 'height'; + fluidConfig.ratio = parseFloat(flags.dimensions.width) / fluidConfig.initialDimensions.height; + } + + el.holderData.fluidConfig = fluidConfig; + } else { + setInvisible(el); + } + } + } + + /** + * Iterates through all current invisible images, and if they're visible, renders them and removes them from further checks. Runs every animation frame. + * + * @private + */ + function visibilityCheck() { + var renderableImages = []; + var keys = Object.keys(App.vars.invisibleImages); + var el; + + keys.forEach(function (key) { + el = App.vars.invisibleImages[key]; + if (dimensionCheck(el) && el.nodeName.toLowerCase() == 'img') { + renderableImages.push(el); + delete App.vars.invisibleImages[key]; + } + }); + + if (renderableImages.length) { + Holder.run({ + images: renderableImages + }); + } + + // Done to prevent 100% CPU usage via aggressive calling of requestAnimationFrame + setTimeout(function () { + global.requestAnimationFrame(visibilityCheck); + }, 10); + } + + /** + * Starts checking for invisible placeholders if not doing so yet. Does nothing otherwise. + * + * @private + */ + function startVisibilityCheck() { + if (!App.vars.visibilityCheckStarted) { + global.requestAnimationFrame(visibilityCheck); + App.vars.visibilityCheckStarted = true; + } + } + + /** + * Sets a unique ID for an image detected to be invisible and adds it to the map of invisible images checked by visibilityCheck + * + * @private + * @param el Invisible DOM element + */ + function setInvisible(el) { + if (!el.holderData.invisibleId) { + App.vars.invisibleId += 1; + App.vars.invisibleImages['i' + App.vars.invisibleId] = el; + el.holderData.invisibleId = App.vars.invisibleId; + } + } + + //todo: see if possible to convert stagingRenderer to use HTML only + var stagingRenderer = (function() { + var svg = null, + stagingText = null, + stagingTextNode = null; + return function(graph) { + var rootNode = graph.root; + if (App.setup.supportsSVG) { + var firstTimeSetup = false; + var tnode = function(text) { + return document.createTextNode(text); + }; + if (svg == null || svg.parentNode !== document.body) { + firstTimeSetup = true; + } + + svg = SVG.initSVG(svg, rootNode.properties.width, rootNode.properties.height); + //Show staging element before staging + svg.style.display = 'block'; + + if (firstTimeSetup) { + stagingText = DOM.newEl('text', SVG_NS); + stagingTextNode = tnode(null); + DOM.setAttr(stagingText, { + x: 0 + }); + stagingText.appendChild(stagingTextNode); + svg.appendChild(stagingText); + document.body.appendChild(svg); + svg.style.visibility = 'hidden'; + svg.style.position = 'absolute'; + svg.style.top = '-100%'; + svg.style.left = '-100%'; + //todo: workaround for zero-dimension tag in Opera 12 + //svg.setAttribute('width', 0); + //svg.setAttribute('height', 0); + } + + var holderTextGroup = rootNode.children.holderTextGroup; + var htgProps = holderTextGroup.properties; + DOM.setAttr(stagingText, { + 'y': htgProps.font.size, + 'style': utils.cssProps({ + 'font-weight': htgProps.font.weight, + 'font-size': htgProps.font.size + htgProps.font.units, + 'font-family': htgProps.font.family + }) + }); + + //Unescape HTML entities to get approximately the right width + var txt = DOM.newEl('textarea'); + txt.innerHTML = htgProps.text; + stagingTextNode.nodeValue = txt.value; + + //Get bounding box for the whole string (total width and height) + var stagingTextBBox = stagingText.getBBox(); + + //Get line count and split the string into words + var lineCount = Math.ceil(stagingTextBBox.width / rootNode.properties.width); + var words = htgProps.text.split(' '); + var newlines = htgProps.text.match(/\\n/g); + lineCount += newlines == null ? 0 : newlines.length; + + //Get bounding box for the string with spaces removed + stagingTextNode.nodeValue = htgProps.text.replace(/[ ]+/g, ''); + var computedNoSpaceLength = stagingText.getComputedTextLength(); + + //Compute average space width + var diffLength = stagingTextBBox.width - computedNoSpaceLength; + var spaceWidth = Math.round(diffLength / Math.max(1, words.length - 1)); + + //Get widths for every word with space only if there is more than one line + var wordWidths = []; + if (lineCount > 1) { + stagingTextNode.nodeValue = ''; + for (var i = 0; i < words.length; i++) { + if (words[i].length === 0) continue; + stagingTextNode.nodeValue = utils.decodeHtmlEntity(words[i]); + var bbox = stagingText.getBBox(); + wordWidths.push({ + text: words[i], + width: bbox.width + }); + } + } + + //Hide staging element after staging + svg.style.display = 'none'; + + return { + spaceWidth: spaceWidth, + lineCount: lineCount, + boundingBox: stagingTextBBox, + words: wordWidths + }; + } else { + //todo: canvas fallback for measuring text on android 2.3 + return false; + } + }; + })(); + + //Helpers + + /** + * Prevents a function from being called too often, waits until a timer elapses to call it again + * + * @param fn Function to call + */ + function debounce(fn) { + if (!App.vars.debounceTimer) fn.call(this); + if (App.vars.debounceTimer) global.clearTimeout(App.vars.debounceTimer); + App.vars.debounceTimer = global.setTimeout(function() { + App.vars.debounceTimer = null; + fn.call(this); + }, App.setup.debounce); + } + + /** + * Holder-specific resize/orientation change callback, debounced to prevent excessive execution + */ + function resizeEvent() { + debounce(function() { + updateResizableElements(null); + }); + } + + //Set up flags + + for (var flag in App.flags) { + if (!App.flags.hasOwnProperty(flag)) continue; + App.flags[flag].match = function(val) { + return val.match(this.regex); + }; + } + + //Properties set once on setup + + App.setup = { + renderer: 'html', + debounce: 100, + ratio: 1, + supportsCanvas: false, + supportsSVG: false, + lineWrapRatio: 0.9, + dataAttr: 'data-src', + renderers: ['html', 'canvas', 'svg'] + }; + + //Properties modified during runtime + + App.vars = { + preempted: false, + resizableImages: [], + invisibleImages: {}, + invisibleId: 0, + visibilityCheckStarted: false, + debounceTimer: null, + cache: {} + }; + + //Pre-flight + + (function() { + var canvas = DOM.newEl('canvas'); + + if (canvas.getContext) { + if (canvas.toDataURL('image/png').indexOf('data:image/png') != -1) { + App.setup.renderer = 'canvas'; + App.setup.supportsCanvas = true; + } + } + + if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) { + App.setup.renderer = 'svg'; + App.setup.supportsSVG = true; + } + })(); + + //Starts checking for invisible placeholders + startVisibilityCheck(); + + if (onDomReady) { + onDomReady(function() { + if (!App.vars.preempted) { + Holder.run(); + } + if (global.addEventListener) { + global.addEventListener('resize', resizeEvent, false); + global.addEventListener('orientationchange', resizeEvent, false); + } else { + global.attachEvent('onresize', resizeEvent); + } + + if (typeof global.Turbolinks == 'object') { + global.document.addEventListener('page:change', function() { + Holder.run(); + }); + } + }); + } + + module.exports = Holder; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + + /*! + * onDomReady.js 1.4.0 (c) 2013 Tubal Martin - MIT license + * + * Specially modified to work with Holder.js + */ + + function _onDomReady(win) { + //Lazy loading fix for Firefox < 3.6 + //http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + if (document.readyState == null && document.addEventListener) { + document.addEventListener("DOMContentLoaded", function DOMContentLoaded() { + document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); + document.readyState = "complete"; + }, false); + document.readyState = "loading"; + } + + var doc = win.document, + docElem = doc.documentElement, + + LOAD = "load", + FALSE = false, + ONLOAD = "on"+LOAD, + COMPLETE = "complete", + READYSTATE = "readyState", + ATTACHEVENT = "attachEvent", + DETACHEVENT = "detachEvent", + ADDEVENTLISTENER = "addEventListener", + DOMCONTENTLOADED = "DOMContentLoaded", + ONREADYSTATECHANGE = "onreadystatechange", + REMOVEEVENTLISTENER = "removeEventListener", + + // W3C Event model + w3c = ADDEVENTLISTENER in doc, + _top = FALSE, + + // isReady: Is the DOM ready to be used? Set to true once it occurs. + isReady = FALSE, + + // Callbacks pending execution until DOM is ready + callbacks = []; + + // Handle when the DOM is ready + function ready( fn ) { + if ( !isReady ) { + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !doc.body ) { + return defer( ready ); + } + + // Remember that the DOM is ready + isReady = true; + + // Execute all callbacks + while ( fn = callbacks.shift() ) { + defer( fn ); + } + } + } + + // The ready event handler + function completed( event ) { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( w3c || event.type === LOAD || doc[READYSTATE] === COMPLETE ) { + detach(); + ready(); + } + } + + // Clean-up method for dom ready events + function detach() { + if ( w3c ) { + doc[REMOVEEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + win[REMOVEEVENTLISTENER]( LOAD, completed, FALSE ); + } else { + doc[DETACHEVENT]( ONREADYSTATECHANGE, completed ); + win[DETACHEVENT]( ONLOAD, completed ); + } + } + + // Defers a function, scheduling it to run after the current call stack has cleared. + function defer( fn, wait ) { + // Allow 0 to be passed + setTimeout( fn, +wait >= 0 ? wait : 1 ); + } + + // Attach the listeners: + + // Catch cases where onDomReady is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( doc[READYSTATE] === COMPLETE ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + defer( ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( w3c ) { + // Use the handy event callback + doc[ADDEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + + // A fallback to window.onload, that will always work + win[ADDEVENTLISTENER]( LOAD, completed, FALSE ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + doc[ATTACHEVENT]( ONREADYSTATECHANGE, completed ); + + // A fallback to window.onload, that will always work + win[ATTACHEVENT]( ONLOAD, completed ); + + // If IE and not a frame + // continually check to see if the document is ready + try { + _top = win.frameElement == null && docElem; + } catch(e) {} + + if ( _top && _top.doScroll ) { + (function doScrollCheck() { + if ( !isReady ) { + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + _top.doScroll("left"); + } catch(e) { + return defer( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + ready(); + } + })(); + } + } + + function onDomReady( fn ) { + // If DOM is ready, execute the function (async), otherwise wait + isReady ? defer( fn ) : callbacks.push( fn ); + } + + // Add version + onDomReady.version = "1.4.0"; + // Add method to check if DOM is ready + onDomReady.isReady = function(){ + return isReady; + }; + + return onDomReady; + } + + module.exports = typeof window !== "undefined" && _onDomReady(window); + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + //Modified version of component/querystring + //Changes: updated dependencies, dot notation parsing, JSHint fixes + //Fork at https://github.com/imsky/querystring + + /** + * Module dependencies. + */ + + var encode = encodeURIComponent; + var decode = decodeURIComponent; + var trim = __webpack_require__(4); + var type = __webpack_require__(5); + + var arrayRegex = /(\w+)\[(\d+)\]/; + var objectRegex = /\w+\.\w+/; + + /** + * Parse the given query `str`. + * + * @param {String} str + * @return {Object} + * @api public + */ + + exports.parse = function(str){ + if ('string' !== typeof str) return {}; + + str = trim(str); + if ('' === str) return {}; + if ('?' === str.charAt(0)) str = str.slice(1); + + var obj = {}; + var pairs = str.split('&'); + for (var i = 0; i < pairs.length; i++) { + var parts = pairs[i].split('='); + var key = decode(parts[0]); + var m, ctx, prop; + + if (m = arrayRegex.exec(key)) { + obj[m[1]] = obj[m[1]] || []; + obj[m[1]][m[2]] = decode(parts[1]); + continue; + } + + if (m = objectRegex.test(key)) { + m = key.split('.'); + ctx = obj; + + while (m.length) { + prop = m.shift(); + + if (!prop.length) continue; + + if (!ctx[prop]) { + ctx[prop] = {}; + } else if (ctx[prop] && typeof ctx[prop] !== 'object') { + break; + } + + if (!m.length) { + ctx[prop] = decode(parts[1]); + } + + ctx = ctx[prop]; + } + + continue; + } + + obj[parts[0]] = null == parts[1] ? '' : decode(parts[1]); + } + + return obj; + }; + + /** + * Stringify the given `obj`. + * + * @param {Object} obj + * @return {String} + * @api public + */ + + exports.stringify = function(obj){ + if (!obj) return ''; + var pairs = []; + + for (var key in obj) { + var value = obj[key]; + + if ('array' == type(value)) { + for (var i = 0; i < value.length; ++i) { + pairs.push(encode(key + '[' + i + ']') + '=' + encode(value[i])); + } + continue; + } + + pairs.push(encode(key) + '=' + encode(obj[key])); + } + + return pairs.join('&'); + }; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + + exports = module.exports = trim; + + function trim(str){ + return str.replace(/^\s*|\s*$/g, ''); + } + + exports.left = function(str){ + return str.replace(/^\s*/, ''); + }; + + exports.right = function(str){ + return str.replace(/\s*$/, ''); + }; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + /** + * toString ref. + */ + + var toString = Object.prototype.toString; + + /** + * Return the type of `val`. + * + * @param {Mixed} val + * @return {String} + * @api public + */ + + module.exports = function(val){ + switch (toString.call(val)) { + case '[object Date]': return 'date'; + case '[object RegExp]': return 'regexp'; + case '[object Arguments]': return 'arguments'; + case '[object Array]': return 'array'; + case '[object Error]': return 'error'; + } + + if (val === null) return 'null'; + if (val === undefined) return 'undefined'; + if (val !== val) return 'nan'; + if (val && val.nodeType === 1) return 'element'; + + val = val.valueOf + ? val.valueOf() + : Object.prototype.valueOf.apply(val) + + return typeof val; + }; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports) { + + var SceneGraph = function(sceneProperties) { + var nodeCount = 1; + + //todo: move merge to helpers section + function merge(parent, child) { + for (var prop in child) { + parent[prop] = child[prop]; + } + return parent; + } + + var SceneNode = function(name) { + nodeCount++; + this.parent = null; + this.children = {}; + this.id = nodeCount; + this.name = 'n' + nodeCount; + if (typeof name !== 'undefined') { + this.name = name; + } + this.x = this.y = this.z = 0; + this.width = this.height = 0; + }; + + SceneNode.prototype.resize = function(width, height) { + if (width != null) { + this.width = width; + } + if (height != null) { + this.height = height; + } + }; + + SceneNode.prototype.moveTo = function(x, y, z) { + this.x = x != null ? x : this.x; + this.y = y != null ? y : this.y; + this.z = z != null ? z : this.z; + }; + + SceneNode.prototype.add = function(child) { + var name = child.name; + if (typeof this.children[name] === 'undefined') { + this.children[name] = child; + child.parent = this; + } else { + throw 'SceneGraph: child already exists: ' + name; + } + }; + + var RootNode = function() { + SceneNode.call(this, 'root'); + this.properties = sceneProperties; + }; + + RootNode.prototype = new SceneNode(); + + var Shape = function(name, props) { + SceneNode.call(this, name); + this.properties = { + 'fill': '#000000' + }; + if (typeof props !== 'undefined') { + merge(this.properties, props); + } else if (typeof name !== 'undefined' && typeof name !== 'string') { + throw 'SceneGraph: invalid node name'; + } + }; + + Shape.prototype = new SceneNode(); + + var Group = function() { + Shape.apply(this, arguments); + this.type = 'group'; + }; + + Group.prototype = new Shape(); + + var Rect = function() { + Shape.apply(this, arguments); + this.type = 'rect'; + }; + + Rect.prototype = new Shape(); + + var Text = function(text) { + Shape.call(this); + this.type = 'text'; + this.properties.text = text; + }; + + Text.prototype = new Shape(); + + var root = new RootNode(); + + this.Shape = { + 'Rect': Rect, + 'Text': Text, + 'Group': Group + }; + + this.root = root; + return this; + }; + + module.exports = SceneGraph; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Shallow object clone and merge + * + * @param a Object A + * @param b Object B + * @returns {Object} New object with all of A's properties, and all of B's properties, overwriting A's properties + */ + exports.extend = function(a, b) { + var c = {}; + for (var x in a) { + if (a.hasOwnProperty(x)) { + c[x] = a[x]; + } + } + if (b != null) { + for (var y in b) { + if (b.hasOwnProperty(y)) { + c[y] = b[y]; + } + } + } + return c; + }; + + /** + * Takes a k/v list of CSS properties and returns a rule + * + * @param props CSS properties object + */ + exports.cssProps = function(props) { + var ret = []; + for (var p in props) { + if (props.hasOwnProperty(p)) { + ret.push(p + ':' + props[p]); + } + } + return ret.join(';'); + }; + + /** + * Encodes HTML entities in a string + * + * @param str Input string + */ + exports.encodeHtmlEntity = function(str) { + var buf = []; + var charCode = 0; + for (var i = str.length - 1; i >= 0; i--) { + charCode = str.charCodeAt(i); + if (charCode > 128) { + buf.unshift(['&#', charCode, ';'].join('')); + } else { + buf.unshift(str[i]); + } + } + return buf.join(''); + }; + + /** + * Checks if an image exists + * + * @param src URL of image + * @param callback Callback to call once image status has been found + */ + exports.imageExists = function(src, callback) { + var image = new Image(); + image.onerror = function() { + callback.call(this, false); + }; + image.onload = function() { + callback.call(this, true); + }; + image.src = src; + }; + + /** + * Decodes HTML entities in a string + * + * @param str Input string + */ + exports.decodeHtmlEntity = function(str) { + return str.replace(/&#(\d+);/g, function(match, dec) { + return String.fromCharCode(dec); + }); + }; + + + /** + * Returns an element's dimensions if it's visible, `false` otherwise. + * + * @param el DOM element + */ + exports.dimensionCheck = function(el) { + var dimensions = { + height: el.clientHeight, + width: el.clientWidth + }; + + if (dimensions.height && dimensions.width) { + return dimensions; + } else { + return false; + } + }; + + + /** + * Returns true if value is truthy or if it is "semantically truthy" + * @param val + */ + exports.truthy = function(val) { + if (typeof val === 'string') { + return val === 'true' || val === 'yes' || val === '1' || val === 'on' || val === '✓'; + } + return !!val; + }; + + /** + * Parses input into a well-formed CSS color + * @param val + */ + exports.parseColor = function(val) { + var hexre = /(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i; + var rgbre = /^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/; + var rgbare = /^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/; + + var match = val.match(hexre); + var retval; + + if (match !== null) { + retval = match[1] || match[2]; + if (retval[0] !== '#') { + return '#' + retval; + } else { + return retval; + } + } + + match = val.match(rgbre); + + if (match !== null) { + retval = 'rgb(' + match.slice(1).join(',') + ')'; + return retval; + } + + match = val.match(rgbare); + + if (match !== null) { + const normalizeAlpha = function (a) { return '0.' + a.split('.')[1]; }; + const fixedMatch = match.slice(1).map(function (e, i) { + return (i === 3) ? normalizeAlpha(e) : e; + }); + retval = 'rgba(' + fixedMatch.join(',') + ')'; + return retval; + } + + return null; + }; + + /** + * Provides the correct scaling ratio for canvas drawing operations on HiDPI screens (e.g. Retina displays) + */ + exports.canvasRatio = function () { + var devicePixelRatio = 1; + var backingStoreRatio = 1; + + if (global.document) { + var canvas = global.document.createElement('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + devicePixelRatio = global.devicePixelRatio || 1; + backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; + } + } + + return devicePixelRatio / backingStoreRatio; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {var DOM = __webpack_require__(9); + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var NODE_TYPE_COMMENT = 8; + + /** + * Generic SVG element creation function + * + * @param svg SVG context, set to null if new + * @param width Document width + * @param height Document height + */ + exports.initSVG = function(svg, width, height) { + var defs, style, initialize = false; + + if (svg && svg.querySelector) { + style = svg.querySelector('style'); + if (style === null) { + initialize = true; + } + } else { + svg = DOM.newEl('svg', SVG_NS); + initialize = true; + } + + if (initialize) { + defs = DOM.newEl('defs', SVG_NS); + style = DOM.newEl('style', SVG_NS); + DOM.setAttr(style, { + 'type': 'text/css' + }); + defs.appendChild(style); + svg.appendChild(defs); + } + + //IE throws an exception if this is set and Chrome requires it to be set + if (svg.webkitMatchesSelector) { + svg.setAttribute('xmlns', SVG_NS); + } + + //Remove comment nodes + for (var i = 0; i < svg.childNodes.length; i++) { + if (svg.childNodes[i].nodeType === NODE_TYPE_COMMENT) { + svg.removeChild(svg.childNodes[i]); + } + } + + //Remove CSS + while (style.childNodes.length) { + style.removeChild(style.childNodes[0]); + } + + DOM.setAttr(svg, { + 'width': width, + 'height': height, + 'viewBox': '0 0 ' + width + ' ' + height, + 'preserveAspectRatio': 'none' + }); + + return svg; + }; + + /** + * Converts serialized SVG to a string suitable for data URI use + * @param svgString Serialized SVG string + * @param [base64] Use base64 encoding for data URI + */ + exports.svgStringToDataURI = function() { + var rawPrefix = 'data:image/svg+xml;charset=UTF-8,'; + var base64Prefix = 'data:image/svg+xml;charset=UTF-8;base64,'; + + return function(svgString, base64) { + if (base64) { + return base64Prefix + btoa(global.unescape(encodeURIComponent(svgString))); + } else { + return rawPrefix + encodeURIComponent(svgString); + } + }; + }(); + + /** + * Returns serialized SVG with XML processing instructions + * + * @param svg SVG context + * @param stylesheets CSS stylesheets to include + */ + exports.serializeSVG = function(svg, engineSettings) { + if (!global.XMLSerializer) return; + var serializer = new XMLSerializer(); + var svgCSS = ''; + var stylesheets = engineSettings.stylesheets; + + //External stylesheets: Processing Instruction method + if (engineSettings.svgXMLStylesheet) { + var xml = DOM.createXML(); + //Add directives + for (var i = stylesheets.length - 1; i >= 0; i--) { + var csspi = xml.createProcessingInstruction('xml-stylesheet', 'href="' + stylesheets[i] + '" rel="stylesheet"'); + xml.insertBefore(csspi, xml.firstChild); + } + + xml.removeChild(xml.documentElement); + svgCSS = serializer.serializeToString(xml); + } + + var svgText = serializer.serializeToString(svg); + svgText = svgText.replace(/\&(\#[0-9]{2,}\;)/g, '&$1'); + return svgCSS + svgText; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Generic new DOM element function + * + * @param tag Tag to create + * @param namespace Optional namespace value + */ + exports.newEl = function(tag, namespace) { + if (!global.document) return; + + if (namespace == null) { + return global.document.createElement(tag); + } else { + return global.document.createElementNS(namespace, tag); + } + }; + + /** + * Generic setAttribute function + * + * @param el Reference to DOM element + * @param attrs Object with attribute keys and values + */ + exports.setAttr = function (el, attrs) { + for (var a in attrs) { + el.setAttribute(a, attrs[a]); + } + }; + + /** + * Creates a XML document + * @private + */ + exports.createXML = function() { + if (!global.DOMParser) return; + return new DOMParser().parseFromString('', 'application/xml'); + }; + + /** + * Converts a value into an array of DOM nodes + * + * @param val A string, a NodeList, a Node, or an HTMLCollection + */ + exports.getNodeArray = function(val) { + var retval = null; + if (typeof(val) == 'string') { + retval = document.querySelectorAll(val); + } else if (global.NodeList && val instanceof global.NodeList) { + retval = val; + } else if (global.Node && val instanceof global.Node) { + retval = [val]; + } else if (global.HTMLCollection && val instanceof global.HTMLCollection) { + retval = val; + } else if (val instanceof Array) { + retval = val; + } else if (val === null) { + retval = []; + } + + retval = Array.prototype.slice.call(retval); + + return retval; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 10 */ +/***/ (function(module, exports) { + + var Color = function(color, options) { + //todo: support rgba, hsla, and rrggbbaa notation + //todo: use CIELAB internally + //todo: add clamp function (with sign) + if (typeof color !== 'string') return; + + this.original = color; + + if (color.charAt(0) === '#') { + color = color.slice(1); + } + + if (/[^a-f0-9]+/i.test(color)) return; + + if (color.length === 3) { + color = color.replace(/./g, '$&$&'); + } + + if (color.length !== 6) return; + + this.alpha = 1; + + if (options && options.alpha) { + this.alpha = options.alpha; + } + + this.set(parseInt(color, 16)); + }; + + //todo: jsdocs + Color.rgb2hex = function(r, g, b) { + function format (decimal) { + var hex = (decimal | 0).toString(16); + if (decimal < 16) { + hex = '0' + hex; + } + return hex; + } + + return [r, g, b].map(format).join(''); + }; + + //todo: jsdocs + Color.hsl2rgb = function (h, s, l) { + var H = h / 60; + var C = (1 - Math.abs(2 * l - 1)) * s; + var X = C * (1 - Math.abs(parseInt(H) % 2 - 1)); + var m = l - (C / 2); + + var r = 0, g = 0, b = 0; + + if (H >= 0 && H < 1) { + r = C; + g = X; + } else if (H >= 1 && H < 2) { + r = X; + g = C; + } else if (H >= 2 && H < 3) { + g = C; + b = X; + } else if (H >= 3 && H < 4) { + g = X; + b = C; + } else if (H >= 4 && H < 5) { + r = X; + b = C; + } else if (H >= 5 && H < 6) { + r = C; + b = X; + } + + r += m; + g += m; + b += m; + + r = parseInt(r * 255); + g = parseInt(g * 255); + b = parseInt(b * 255); + + return [r, g, b]; + }; + + /** + * Sets the color from a raw RGB888 integer + * @param raw RGB888 representation of color + */ + //todo: refactor into a static method + //todo: factor out individual color spaces + //todo: add HSL, CIELAB, and CIELUV + Color.prototype.set = function (val) { + this.raw = val; + + var r = (this.raw & 0xFF0000) >> 16; + var g = (this.raw & 0x00FF00) >> 8; + var b = (this.raw & 0x0000FF); + + // BT.709 + var y = 0.2126 * r + 0.7152 * g + 0.0722 * b; + var u = -0.09991 * r - 0.33609 * g + 0.436 * b; + var v = 0.615 * r - 0.55861 * g - 0.05639 * b; + + this.rgb = { + r: r, + g: g, + b: b + }; + + this.yuv = { + y: y, + u: u, + v: v + }; + + return this; + }; + + /** + * Lighten or darken a color + * @param multiplier Amount to lighten or darken (-1 to 1) + */ + Color.prototype.lighten = function(multiplier) { + var cm = Math.min(1, Math.max(0, Math.abs(multiplier))) * (multiplier < 0 ? -1 : 1); + var bm = (255 * cm) | 0; + var cr = Math.min(255, Math.max(0, this.rgb.r + bm)); + var cg = Math.min(255, Math.max(0, this.rgb.g + bm)); + var cb = Math.min(255, Math.max(0, this.rgb.b + bm)); + var hex = Color.rgb2hex(cr, cg, cb); + return new Color(hex); + }; + + /** + * Output color in hex format + * @param addHash Add a hash character to the beginning of the output + */ + Color.prototype.toHex = function(addHash) { + return (addHash ? '#' : '') + this.raw.toString(16); + }; + + /** + * Returns whether or not current color is lighter than another color + * @param color Color to compare against + */ + Color.prototype.lighterThan = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + return this.yuv.y > color.yuv.y; + }; + + /** + * Returns the result of mixing current color with another color + * @param color Color to mix with + * @param multiplier How much to mix with the other color + */ + /* + Color.prototype.mix = function (color, multiplier) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var r = this.rgb.r; + var g = this.rgb.g; + var b = this.rgb.b; + var a = this.alpha; + + var m = typeof multiplier !== 'undefined' ? multiplier : 0.5; + + //todo: write a lerp function + r = r + m * (color.rgb.r - r); + g = g + m * (color.rgb.g - g); + b = b + m * (color.rgb.b - b); + a = a + m * (color.alpha - a); + + return new Color(Color.rgbToHex(r, g, b), { + 'alpha': a + }); + }; + */ + + /** + * Returns the result of blending another color on top of current color with alpha + * @param color Color to blend on top of current color, i.e. "Ca" + */ + //todo: see if .blendAlpha can be merged into .mix + Color.prototype.blendAlpha = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var Ca = color; + var Cb = this; + + //todo: write alpha blending function + var r = Ca.alpha * Ca.rgb.r + (1 - Ca.alpha) * Cb.rgb.r; + var g = Ca.alpha * Ca.rgb.g + (1 - Ca.alpha) * Cb.rgb.g; + var b = Ca.alpha * Ca.rgb.b + (1 - Ca.alpha) * Cb.rgb.b; + + return new Color(Color.rgb2hex(r, g, b)); + }; + + module.exports = Color; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + module.exports = { + 'version': '2.9.7', + 'svg_ns': 'http://www.w3.org/2000/svg' + }; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + var shaven = __webpack_require__(13); + + var SVG = __webpack_require__(8); + var constants = __webpack_require__(11); + var utils = __webpack_require__(7); + + var SVG_NS = constants.svg_ns; + + var templates = { + 'element': function (options) { + var tag = options.tag; + var content = options.content || ''; + delete options.tag; + delete options.content; + return [tag, content, options]; + } + }; + + //todo: deprecate tag arg, infer tag from shape object + function convertShape (shape, tag) { + return templates.element({ + 'tag': tag, + 'width': shape.width, + 'height': shape.height, + 'fill': shape.properties.fill + }); + } + + function textCss (properties) { + return utils.cssProps({ + 'fill': properties.fill, + 'font-weight': properties.font.weight, + 'font-family': properties.font.family + ', monospace', + 'font-size': properties.font.size + properties.font.units + }); + } + + function outlinePath (bgWidth, bgHeight, outlineWidth) { + var outlineOffsetWidth = outlineWidth / 2; + + return [ + 'M', outlineOffsetWidth, outlineOffsetWidth, + 'H', bgWidth - outlineOffsetWidth, + 'V', bgHeight - outlineOffsetWidth, + 'H', outlineOffsetWidth, + 'V', 0, + 'M', 0, outlineOffsetWidth, + 'L', bgWidth, bgHeight - outlineOffsetWidth, + 'M', 0, bgHeight - outlineOffsetWidth, + 'L', bgWidth, outlineOffsetWidth + ].join(' '); + } + + module.exports = function (sceneGraph, renderSettings) { + var engineSettings = renderSettings.engineSettings; + var stylesheets = engineSettings.stylesheets; + var stylesheetXml = stylesheets.map(function (stylesheet) { + return ''; + }).join('\n'); + + var holderId = 'holder_' + Number(new Date()).toString(16); + + var root = sceneGraph.root; + var textGroup = root.children.holderTextGroup; + + var css = '#' + holderId + ' text { ' + textCss(textGroup.properties) + ' } '; + + // push text down to be equally vertically aligned with canvas renderer + textGroup.y += textGroup.textPositionData.boundingBox.height * 0.8; + + var wordTags = []; + + Object.keys(textGroup.children).forEach(function (lineKey) { + var line = textGroup.children[lineKey]; + + Object.keys(line.children).forEach(function (wordKey) { + var word = line.children[wordKey]; + var x = textGroup.x + line.x + word.x; + var y = textGroup.y + line.y + word.y; + var wordTag = templates.element({ + 'tag': 'text', + 'content': word.properties.text, + 'x': x, + 'y': y + }); + + wordTags.push(wordTag); + }); + }); + + var text = templates.element({ + 'tag': 'g', + 'content': wordTags + }); + + var outline = null; + + if (root.children.holderBg.properties.outline) { + var outlineProperties = root.children.holderBg.properties.outline; + outline = templates.element({ + 'tag': 'path', + 'd': outlinePath(root.children.holderBg.width, root.children.holderBg.height, outlineProperties.width), + 'stroke-width': outlineProperties.width, + 'stroke': outlineProperties.fill, + 'fill': 'none' + }); + } + + var bg = convertShape(root.children.holderBg, 'rect'); + + var sceneContent = []; + + sceneContent.push(bg); + if (outlineProperties) { + sceneContent.push(outline); + } + sceneContent.push(text); + + var scene = templates.element({ + 'tag': 'g', + 'id': holderId, + 'content': sceneContent + }); + + var style = templates.element({ + 'tag': 'style', + //todo: figure out how to add CDATA directive + 'content': css, + 'type': 'text/css' + }); + + var defs = templates.element({ + 'tag': 'defs', + 'content': style + }); + + var svg = templates.element({ + 'tag': 'svg', + 'content': [defs, scene], + 'width': root.properties.width, + 'height': root.properties.height, + 'xmlns': SVG_NS, + 'viewBox': [0, 0, root.properties.width, root.properties.height].join(' '), + 'preserveAspectRatio': 'none' + }); + + var output = shaven(svg); + + if (/\&(x)?#[0-9A-Fa-f]/.test(output[0])) { + output[0] = output[0].replace(/&#/gm, '&#'); + } + + output = stylesheetXml + output[0]; + + var svgString = SVG.svgStringToDataURI(output, renderSettings.mode === 'background'); + return svgString; + }; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + var escape = __webpack_require__(14) + + // TODO: remove namespace + + module.exports = function shaven (array, namespace, returnObject) { + + 'use strict' + + var i = 1 + var doesEscape = true + var HTMLString + var attributeKey + var callback + var key + + + returnObject = returnObject || {} + + + function createElement (sugarString) { + + var tags = sugarString.match(/^[\w-]+/) + var element = { + tag: tags ? tags[0] : 'div', + attr: {}, + children: [] + } + var id = sugarString.match(/#([\w-]+)/) + var reference = sugarString.match(/\$([\w-]+)/) + var classNames = sugarString.match(/\.[\w-]+/g) + + + // Assign id if is set + if (id) { + element.attr.id = id[1] + + // Add element to the return object + returnObject[id[1]] = element + } + + if (reference) + returnObject[reference[1]] = element + + if (classNames) + element.attr.class = classNames.join(' ').replace(/\./g, '') + + if (sugarString.match(/&$/g)) + doesEscape = false + + return element + } + + function replacer (key, value) { + + if (value === null || value === false || value === undefined) + return + + if (typeof value !== 'string' && typeof value !== 'object') + return String(value) + + return value + } + + function escapeAttribute (string) { + return (string || string === 0) ? + String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') : + '' + } + + function escapeHTML (string) { + return String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>') + } + + + if (typeof array[0] === 'string') + array[0] = createElement(array[0]) + + else if (Array.isArray(array[0])) + i = 0 + + else + throw new Error( + 'First element of array must be a string, ' + + 'or an array and not ' + JSON.stringify(array[0]) + ) + + + for (; i < array.length; i++) { + + // Don't render element if value is false or null + if (array[i] === false || array[i] === null) { + array[0] = false + break + } + + // Continue with next array value if current value is undefined or true + else if (array[i] === undefined || array[i] === true) { + continue + } + + else if (typeof array[i] === 'string') { + if (doesEscape) + array[i] = escapeHTML(array[i]) + + array[0].children.push(array[i]) + } + + else if (typeof array[i] === 'number') { + + array[0].children.push(array[i]) + } + + else if (Array.isArray(array[i])) { + + if (Array.isArray(array[i][0])) { + array[i].reverse().forEach(function (subArray) { + array.splice(i + 1, 0, subArray) + }) + + if (i !== 0) + continue + i++ + } + + shaven(array[i], namespace, returnObject) + + if (array[i][0]) + array[0].children.push(array[i][0]) + } + + else if (typeof array[i] === 'function') + callback = array[i] + + + else if (typeof array[i] === 'object') { + for (attributeKey in array[i]) + if (array[i].hasOwnProperty(attributeKey)) + if (array[i][attributeKey] !== null && + array[i][attributeKey] !== false) + if (attributeKey === 'style' && + typeof array[i][attributeKey] === 'object') + array[0].attr[attributeKey] = JSON + .stringify(array[i][attributeKey], replacer) + .slice(2, -2) + .replace(/","/g, ';') + .replace(/":"/g, ':') + .replace(/\\"/g, '\'') + + else + array[0].attr[attributeKey] = array[i][attributeKey] + } + + else + throw new TypeError('"' + array[i] + '" is not allowed as a value.') + } + + + if (array[0] !== false) { + + HTMLString = '<' + array[0].tag + + for (key in array[0].attr) + if (array[0].attr.hasOwnProperty(key)) + HTMLString += ' ' + key + '="' + + escapeAttribute(array[0].attr[key]) + '"' + + HTMLString += '>' + + array[0].children.forEach(function (child) { + HTMLString += child + }) + + HTMLString += '' + + array[0] = HTMLString + } + + // Return root element on index 0 + returnObject[0] = array[0] + + if (callback) + callback(array[0]) + + // returns object containing all elements with an id and the root element + return returnObject + } + + +/***/ }), +/* 14 */ +/***/ (function(module, exports) { + + /*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */ + + 'use strict'; + + /** + * Module variables. + * @private + */ + + var matchHtmlRegExp = /["'&<>]/; + + /** + * Module exports. + * @public + */ + + module.exports = escapeHtml; + + /** + * Escape special characters in the given string of html. + * + * @param {string} string The string to escape for inserting into HTML + * @return {string} + * @public + */ + + function escapeHtml(string) { + var str = '' + string; + var match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } + + var escape; + var html = ''; + var index = 0; + var lastIndex = 0; + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"'; + break; + case 38: // & + escape = '&'; + break; + case 39: // ' + escape = '''; + break; + case 60: // < + escape = '<'; + break; + case 62: // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html; + } + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + var DOM = __webpack_require__(9); + var utils = __webpack_require__(7); + + module.exports = (function() { + var canvas = DOM.newEl('canvas'); + var ctx = null; + + return function(sceneGraph) { + if (ctx == null) { + ctx = canvas.getContext('2d'); + } + + var dpr = utils.canvasRatio(); + var root = sceneGraph.root; + canvas.width = dpr * root.properties.width; + canvas.height = dpr * root.properties.height ; + ctx.textBaseline = 'middle'; + + var bg = root.children.holderBg; + var bgWidth = dpr * bg.width; + var bgHeight = dpr * bg.height; + //todo: parametrize outline width (e.g. in scene object) + var outlineWidth = 2; + var outlineOffsetWidth = outlineWidth / 2; + + ctx.fillStyle = bg.properties.fill; + ctx.fillRect(0, 0, bgWidth, bgHeight); + + if (bg.properties.outline) { + //todo: abstract this into a method + ctx.strokeStyle = bg.properties.outline.fill; + ctx.lineWidth = bg.properties.outline.width; + ctx.moveTo(outlineOffsetWidth, outlineOffsetWidth); + // TL, TR, BR, BL + ctx.lineTo(bgWidth - outlineOffsetWidth, outlineOffsetWidth); + ctx.lineTo(bgWidth - outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, outlineOffsetWidth); + // Diagonals + ctx.moveTo(0, outlineOffsetWidth); + ctx.lineTo(bgWidth, bgHeight - outlineOffsetWidth); + ctx.moveTo(0, bgHeight - outlineOffsetWidth); + ctx.lineTo(bgWidth, outlineOffsetWidth); + ctx.stroke(); + } + + var textGroup = root.children.holderTextGroup; + ctx.font = textGroup.properties.font.weight + ' ' + (dpr * textGroup.properties.font.size) + textGroup.properties.font.units + ' ' + textGroup.properties.font.family + ', monospace'; + ctx.fillStyle = textGroup.properties.fill; + + for (var lineKey in textGroup.children) { + var line = textGroup.children[lineKey]; + for (var wordKey in line.children) { + var word = line.children[wordKey]; + var x = dpr * (textGroup.x + line.x + word.x); + var y = dpr * (textGroup.y + line.y + word.y + (textGroup.properties.leading / 2)); + + ctx.fillText(word.properties.text, x, y); + } + } + + return canvas.toDataURL('image/png'); + }; + })(); + +/***/ }) +/******/ ]) +}); +; +(function(ctx, isMeteorPackage) { + if (isMeteorPackage) { + Holder = ctx.Holder; + } +})(this, typeof Meteor !== 'undefined' && typeof Package !== 'undefined'); diff --git a/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.min.js b/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.min.js new file mode 100644 index 0000000..6935bf1 --- /dev/null +++ b/BlazorStudy.Bootstrap4Study/wwwroot/plugs/holder/holder.min.js @@ -0,0 +1,14 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://imsky.co + +Site: http://holderjs.com +Issues: https://github.com/imsky/holder/issues +License: MIT + +*/ +!function(e){if(e.document){var t=e.document;t.querySelectorAll||(t.querySelectorAll=function(n){var r,i=t.createElement("style"),a=[];for(t.documentElement.firstChild.appendChild(i),t._qsa=[],i.styleSheet.cssText=n+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",e.scrollBy(0,0),i.parentNode.removeChild(i);t._qsa.length;)r=t._qsa.shift(),r.style.removeAttribute("x-qsa"),a.push(r);return t._qsa=null,a}),t.querySelector||(t.querySelector=function(e){var n=t.querySelectorAll(e);return n.length?n[0]:null}),t.getElementsByClassName||(t.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),t.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(t);return n}),Array.prototype.forEach||(Array.prototype.forEach=function(e){if(void 0===this||null===this)throw TypeError();var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;n>r;r++)r in t&&e.call(i,t[r],r,t)}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var n,r=0,i=[],a=0,o=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+\/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;r>16&255)),i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a)),o=0,a=0),r+=1;return 12===o?(a>>=4,i.push(String.fromCharCode(255&a))):18===o&&(a>>=2,i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,a,o,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,o=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(a),t.charAt(o),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame&&e.webkitCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame&&e.mozCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var o=i(n.substr(n.lastIndexOf(e.domain)),e);o&&a({mode:null,el:r,flags:o,engineSettings:t})}function i(e,t){var n={theme:T(O.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.indexOf("?"),i=[e];-1!==r&&(i=[e.slice(0,r),e.slice(r+1)]);var a=i[0].split("/");n.holderURL=e;var o=a[1],s=o.match(/([\d]+p?)x([\d]+p?)/);if(!s)return!1;if(n.fluid=-1!==o.indexOf("p"),n.dimensions={width:s[1].replace("p","%"),height:s[2].replace("p","%")},2===i.length){var l=v.parse(i[1]);if(w.truthy(l.ratio)){n.fluid=!0;var h=parseFloat(n.dimensions.width.replace("%","")),u=parseFloat(n.dimensions.height.replace("%",""));u=Math.floor(100*(u/h)),h=100,n.dimensions.width=h+"%",n.dimensions.height=u+"%"}if(n.auto=w.truthy(l.auto),l.bg&&(n.theme.bg=w.parseColor(l.bg)),l.fg&&(n.theme.fg=w.parseColor(l.fg)),l.bg&&!l.fg&&(n.autoFg=!0),l.theme&&n.instanceOptions.themes.hasOwnProperty(l.theme)&&(n.theme=T(n.instanceOptions.themes[l.theme],null)),l.text&&(n.text=l.text),l.textmode&&(n.textmode=l.textmode),l.size&&parseFloat(l.size)&&(n.size=parseFloat(l.size)),l.font&&(n.font=l.font),l.align&&(n.align=l.align),l.lineWrap&&(n.lineWrap=l.lineWrap),n.nowrap=w.truthy(l.nowrap),n.outline=w.truthy(l.outline),w.truthy(l.random)){O.vars.cache.themeKeys=O.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var d=O.vars.cache.themeKeys[0|Math.random()*O.vars.cache.themeKeys.length];n.theme=T(n.instanceOptions.themes[d],null)}}return n}function a(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,a=r.dimensions,s=r.theme,l=a.width+"x"+a.height;t=null==t?r.fluid?"fluid":"image":t;var d=/holder_([a-z]+)/g,c=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),("left"===e.align||"right"===e.align)&&(a=e.width*(1-2*(1-r)));for(var E=0;E=a||k===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),k!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+T.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return o}function l(e,t,n,r){var i=parseInt(e,10),a=parseInt(t,10),o=Math.max(i,a),s=Math.min(i,a),l=.8*Math.min(s,o*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?O.vars.resizableImages:[e];for(var n=0,r=t.length;r>n;n++){var i=t[n];if(i.holderData){var a=i.holderData.flags,s=k(i);if(s){if(!i.holderData.resizeUpdate)continue;if(a.fluid&&a.auto){var l=i.holderData.fluidConfig;switch(l.mode){case"width":s.height=s.width/l.ratio;break;case"height":s.width=s.height*l.ratio}}var h={mode:"image",holderSettings:{dimensions:s,theme:a.theme,flags:a},el:i,engineSettings:i.holderData.engineSettings};"exact"==a.textmode&&(a.exactDimensions=s,h.holderSettings.dimensions=a.dimensions),o(h)}else f(i)}}}function u(e){if(e.holderData){var t=k(e);if(t){var n=e.holderData.flags,r={fluidHeight:"%"==n.dimensions.height.slice(-1),fluidWidth:"%"==n.dimensions.width.slice(-1),mode:null,initialDimensions:t};r.fluidWidth&&!r.fluidHeight?(r.mode="width",r.ratio=r.initialDimensions.width/parseFloat(n.dimensions.height)):!r.fluidWidth&&r.fluidHeight&&(r.mode="height",r.ratio=parseFloat(n.dimensions.width)/r.initialDimensions.height),e.holderData.fluidConfig=r}else f(e)}}function d(){var e,n=[],r=Object.keys(O.vars.invisibleImages);r.forEach(function(t){e=O.vars.invisibleImages[t],k(e)&&"img"==e.nodeName.toLowerCase()&&(n.push(e),delete O.vars.invisibleImages[t])}),n.length&&j.run({images:n}),setTimeout(function(){t.requestAnimationFrame(d)},10)}function c(){O.vars.visibilityCheckStarted||(t.requestAnimationFrame(d),O.vars.visibilityCheckStarted=!0)}function f(e){e.holderData.invisibleId||(O.vars.invisibleId+=1,O.vars.invisibleImages["i"+O.vars.invisibleId]=e,e.holderData.invisibleId=O.vars.invisibleId)}function p(e){O.vars.debounceTimer||e.call(this),O.vars.debounceTimer&&t.clearTimeout(O.vars.debounceTimer),O.vars.debounceTimer=t.setTimeout(function(){O.vars.debounceTimer=null,e.call(this)},O.setup.debounce)}function g(){p(function(){h(null)})}var m=n(2),v=n(3),y=n(6),w=n(7),b=n(8),x=n(9),S=n(10),A=n(11),C=n(12),E=n(15),T=w.extend,k=w.dimensionCheck,F=A.svg_ns,j={version:A.version,addTheme:function(e,t){return null!=e&&null!=t&&(O.settings.themes[e]=t),delete O.vars.cache.themeKeys,this},addImage:function(e,t){var n=x.getNodeArray(t);return n.forEach(function(t){var n=x.newEl("img"),r={};r[O.setup.dataAttr]=e,x.setAttr(n,r),t.appendChild(n)}),this},setResizeUpdate:function(e,t){e.holderData&&(e.holderData.resizeUpdate=!!t,e.holderData.resizeUpdate&&h(e))},run:function(e){e=e||{};var n={},o=T(O.settings,e);O.vars.preempted=!0,O.vars.dataAttr=o.dataAttr||O.setup.dataAttr,n.renderer=o.renderer?o.renderer:O.setup.renderer,-1===O.setup.renderers.join(",").indexOf(n.renderer)&&(n.renderer=O.setup.supportsSVG?"svg":O.setup.supportsCanvas?"canvas":"html");var s=x.getNodeArray(o.images),l=x.getNodeArray(o.bgnodes),h=x.getNodeArray(o.stylenodes),u=x.getNodeArray(o.objects);return n.stylesheets=[],n.svgXMLStylesheet=!0,n.noFontFallback=!!o.noFontFallback,n.noBackgroundSize=!!o.noBackgroundSize,h.forEach(function(e){if(e.attributes.rel&&e.attributes.href&&"stylesheet"==e.attributes.rel.value){var t=e.attributes.href.value,r=x.newEl("a");r.href=t;var i=r.protocol+"//"+r.host+r.pathname+r.search;n.stylesheets.push(i)}}),l.forEach(function(e){if(t.getComputedStyle){var r=t.getComputedStyle(e,null).getPropertyValue("background-image"),s=e.getAttribute("data-background-src"),l=s||r,h=null,u=o.domain+"/",d=l.indexOf(u);if(0===d)h=l;else if(1===d&&"?"===l[0])h=l.slice(1);else{var c=l.substr(d).match(/([^\"]*)"?\)/);if(null!==c)h=c[1];else if(0===l.indexOf("url("))throw"Holder: unable to parse background URL: "+l}if(h){var f=i(h,o);f&&a({mode:"background",el:e,flags:f,engineSettings:n})}}}),u.forEach(function(e){var t={};try{t.data=e.getAttribute("data"),t.dataSrc=e.getAttribute(O.vars.dataAttr)}catch(i){}var a=null!=t.data&&0===t.data.indexOf(o.domain),s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain);a?r(o,n,t.data,e):s&&r(o,n,t.dataSrc,e)}),s.forEach(function(e){var t={};try{t.src=e.getAttribute("src"),t.dataSrc=e.getAttribute(O.vars.dataAttr),t.rendered=e.getAttribute("data-holder-rendered")}catch(i){}var a=null!=t.src,s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain),l=null!=t.rendered&&"true"==t.rendered;a?0===t.src.indexOf(o.domain)?r(o,n,t.src,e):s&&(l?r(o,n,t.dataSrc,e):!function(e,t,n,i,a){w.imageExists(e,function(e){e||r(t,n,i,a)})}(t.src,o,n,t.dataSrc,e)):s&&r(o,n,t.dataSrc,e)}),this}},O={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}},z=function(){var e=null,t=null,n=null;return function(r){var i=r.root;if(O.setup.supportsSVG){var a=!1,o=function(e){return document.createTextNode(e)};(null==e||e.parentNode!==document.body)&&(a=!0),e=b.initSVG(e,i.properties.width,i.properties.height),e.style.display="block",a&&(t=x.newEl("text",F),n=o(null),x.setAttr(t,{x:0}),t.appendChild(n),e.appendChild(t),document.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var s=i.children.holderTextGroup,l=s.properties;x.setAttr(t,{y:l.font.size,style:w.cssProps({"font-weight":l.font.weight,"font-size":l.font.size+l.font.units,"font-family":l.font.family})});var h=x.newEl("textarea");h.innerHTML=l.text,n.nodeValue=h.value;var u=t.getBBox(),d=Math.ceil(u.width/i.properties.width),c=l.text.split(" "),f=l.text.match(/\\n/g);d+=null==f?0:f.length,n.nodeValue=l.text.replace(/[ ]+/g,"");var p=t.getComputedTextLength(),g=u.width-p,m=Math.round(g/Math.max(1,c.length-1)),v=[];if(d>1){n.nodeValue="";for(var y=0;y=0?t:1)}function a(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var o=e.document,s=o.documentElement,l="load",h=!1,u="on"+l,d="complete",c="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in o,b=h,x=h,S=[];if(o[c]===d)i(t);else if(w)o[g](m,n,h),e[g](l,n,h);else{o[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return a.version="1.4.0",a.isReady=function(){return x},a}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,a=n(4),o=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=a(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),t.unshift(n>128?["&#",n,";"].join(""):e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return t.height&&t.width?t:!1},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/,a=e.match(n);if(null!==a)return t=a[1]||a[2],"#"!==t[0]?"#"+t:t;if(a=e.match(r),null!==a)return t="rgb("+a.slice(1).join(",")+")";if(a=e.match(i),null!==a){const o=function(e){return"0."+e.split(".")[1]},s=a.slice(1).map(function(e,t){return 3===t?o(e):e});return t="rgba("+s.join(",")+")"}return null},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",a=8;t.initSVG=function(e,t,n){var o,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(o=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),o.appendChild(s),e.appendChild(o)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+o[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),a=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),a+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){return e.document?null==n?e.document.createElement(t):e.document.createElementNS(n,t):void 0},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){return e.DOMParser?(new DOMParser).parseFromString("","application/xml"):void 0},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return 16>e&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,a=i*(1-Math.abs(parseInt(r)%2-1)),o=n-i/2,s=0,l=0,h=0;return r>=0&&1>r?(s=i,l=a):r>=1&&2>r?(s=a,l=i):r>=2&&3>r?(l=i,h=a):r>=3&&4>r?(l=a,h=i):r>=4&&5>r?(s=a,h=i):r>=5&&6>r&&(s=i,h=a),s+=o,l+=o,h+=o,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,a=-.09991*t-.33609*n+.436*r,o=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:a,v:o},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(0>e?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),a=Math.min(255,Math.max(0,this.rgb.g+r)),o=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,a,o);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,a=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,o=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,a,o))},e.exports=n},function(e,t){e.exports={version:"2.9.7",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return d.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function a(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var o=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,d={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),c="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+c+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,a=d.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(a)})});var v=d.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=d.element({tag:"path",d:a(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=d.element({tag:"g",id:c,content:x}),A=d.element({tag:"style",content:g,type:"text/css"}),C=d.element({tag:"defs",content:A}),E=d.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),T=o(E);/\&(x)?#[0-9A-Fa-f]/.test(T[0])&&(T[0]=T[0].replace(/&#/gm,"&#")),T=h+T[0];var k=s.svgStringToDataURI(T,"background"===t.mode);return k}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^[\w-]+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),a=e.match(/\$([\w-]+)/),o=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),a&&(n[a[1]]=r),o&&(r.attr["class"]=o.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function a(e,t){return null!==t&&t!==!1&&void 0!==t?"string"!=typeof t&&"object"!=typeof t?String(t):t:void 0}function o(e){return e||0===e?String(e).replace(/&/g,"&").replace(/"/g,"""):""}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,d,c=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));c=0}for(;c",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){"use strict";function n(e){var t=""+e,n=r.exec(t);if(!n)return t;var i,a="",o=0,s=0;for(o=n.index;o]/;e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),a=n.root;e.width=r*a.properties.width,e.height=r*a.properties.height,t.textBaseline="middle";var o=a.children.holderBg,s=r*o.width,l=r*o.height,h=2,u=h/2;t.fillStyle=o.properties.fill,t.fillRect(0,0,s,l),o.properties.outline&&(t.strokeStyle=o.properties.outline.fill,t.lineWidth=o.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var d=a.children.holderTextGroup;t.font=d.properties.font.weight+" "+r*d.properties.font.size+d.properties.font.units+" "+d.properties.font.family+", monospace",t.fillStyle=d.properties.fill;for(var c in d.children){var f=d.children[c];for(var p in f.children){var g=f.children[p],m=r*(d.x+f.x+g.x),v=r*(d.y+f.y+g.y+d.properties.leading/2); + +t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); \ No newline at end of file diff --git a/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.js b/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.js new file mode 100644 index 0000000..db1e43b --- /dev/null +++ b/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.js @@ -0,0 +1,3063 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://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-2020 Ivan Malopinsky - https://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-2020 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; + + // SVG embedding doesn't parse Unicode properly + if (el.nodeName.toLowerCase() === 'object') { + var textLines = theme.text.split('\\n'); + for (var k = 0; k < textLines.length; k++) { + textLines[k] = utils.encodeHtmlEntity(textLines[k]); + } + theme.text = textLines.join('\\n'); + } + } + + if (theme.text) { + var holderTemplateMatches = theme.text.match(holderTemplateRe); + + if (holderTemplateMatches !== null) { + //todo: optimize template replacement + holderTemplateMatches.forEach(function (match) { + if (match === 'holder_dimensions') { + theme.text = theme.text.replace(match, dimensionsCaption); + } + }); + } + } + + var holderURL = flags.holderURL; + var engineSettings = extend(_engineSettings, null); + + if (flags.font) { + /* + If external fonts are used in a placeholder rendered with SVG, Holder falls back to canvas. + + This is done because Firefox and Chrome disallow embedded SVGs from referencing external assets. + The workaround is either to change the placeholder tag from to or to use the canvas renderer. + */ + theme.font = flags.font; + if (!engineSettings.noFontFallback && el.nodeName.toLowerCase() === 'img' && App.setup.supportsCanvas && engineSettings.renderer === 'svg') { + engineSettings = extend(engineSettings, { + renderer: 'canvas' + }); + } + } + + //Chrome and Opera require a quick 10ms re-render if web fonts are used with canvas + if (flags.font && engineSettings.renderer == 'canvas') { + engineSettings.reRender = true; + } + + if (mode == 'background') { + if (el.getAttribute('data-background-src') == null) { + DOM.setAttr(el, { + 'data-background-src': holderURL + }); + } + } else { + var domProps = {}; + domProps[App.vars.dataAttr] = holderURL; + DOM.setAttr(el, domProps); + } + + flags.theme = theme; + + //todo consider using all renderSettings in holderData + el.holderData = { + flags: flags, + engineSettings: engineSettings + }; + + if (mode == 'image' || mode == 'fluid') { + DOM.setAttr(el, { + 'alt': theme.text ? (dimensionsInText ? theme.text : theme.text + ' [' + dimensionsCaption + ']') : dimensionsCaption + }); + } + + var renderSettings = { + mode: mode, + el: el, + holderSettings: { + dimensions: dimensions, + theme: theme, + flags: flags + }, + engineSettings: engineSettings + }; + + if (mode == 'image') { + if (!flags.auto) { + el.style.width = dimensions.width + 'px'; + el.style.height = dimensions.height + 'px'; + } + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + render(renderSettings); + + if (flags.textmode == 'exact') { + el.holderData.resizeUpdate = true; + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } else if (mode == 'background' && engineSettings.renderer != 'html') { + render(renderSettings); + } else if (mode == 'fluid') { + el.holderData.resizeUpdate = true; + + if (dimensions.height.slice(-1) == '%') { + el.style.height = dimensions.height; + } else if (flags.auto == null || !flags.auto) { + el.style.height = dimensions.height + 'px'; + } + if (dimensions.width.slice(-1) == '%') { + el.style.width = dimensions.width; + } else if (flags.auto == null || !flags.auto) { + el.style.width = dimensions.width + 'px'; + } + if (el.style.display == 'inline' || el.style.display === '' || el.style.display == 'none') { + el.style.display = 'block'; + } + + setInitialDimensions(el); + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } + + /** + * Core function that takes output from renderers and sets it as the source or background-image of the target element + * + * @private + * @param renderSettings Renderer settings + */ + function render(renderSettings) { + var image = null; + var mode = renderSettings.mode; + var el = renderSettings.el; + var holderSettings = renderSettings.holderSettings; + var engineSettings = renderSettings.engineSettings; + + switch (engineSettings.renderer) { + case 'svg': + if (!App.setup.supportsSVG) return; + break; + case 'canvas': + if (!App.setup.supportsCanvas) return; + break; + default: + return; + } + + //todo: move generation of scene up to flag generation to reduce extra object creation + var scene = { + width: holderSettings.dimensions.width, + height: holderSettings.dimensions.height, + theme: holderSettings.theme, + flags: holderSettings.flags + }; + + var sceneGraph = buildSceneGraph(scene); + + function getRenderedImage() { + var image = null; + switch (engineSettings.renderer) { + case 'canvas': + image = sgCanvasRenderer(sceneGraph, renderSettings); + break; + case 'svg': + image = svgRenderer(sceneGraph, renderSettings); + break; + default: + throw 'Holder: invalid renderer: ' + engineSettings.renderer; + } + + return image; + } + + image = getRenderedImage(); + + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + + //todo: add canvas rendering + if (mode == 'background') { + el.style.backgroundImage = 'url(' + image + ')'; + + if (!engineSettings.noBackgroundSize) { + el.style.backgroundSize = scene.width + 'px ' + scene.height + 'px'; + } + } else { + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + if (engineSettings.reRender) { + global.setTimeout(function () { + var image = getRenderedImage(); + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + //todo: refactor this code into a function + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + }, 150); + } + } + //todo: account for re-rendering + DOM.setAttr(el, { + 'data-holder-rendered': true + }); + } + + /** + * Core function that takes a Holder scene description and builds a scene graph + * + * @private + * @param scene Holder scene object + */ + //todo: make this function reusable + //todo: merge app defaults and setup properties into the scene argument + function buildSceneGraph(scene) { + var fontSize = App.defaults.size; + if (parseFloat(scene.theme.size)) { + fontSize = scene.theme.size; + } else if (parseFloat(scene.flags.size)) { + fontSize = scene.flags.size; + } + + scene.font = { + family: scene.theme.font ? scene.theme.font : 'Arial, Helvetica, Open Sans, sans-serif', + size: textSize(scene.width, scene.height, fontSize, App.defaults.scale), + units: scene.theme.units ? scene.theme.units : App.defaults.units, + weight: scene.theme.fontweight ? scene.theme.fontweight : 'bold' + }; + + scene.text = scene.theme.text || Math.floor(scene.width) + 'x' + Math.floor(scene.height); + + scene.noWrap = scene.theme.nowrap || scene.flags.nowrap; + + scene.align = scene.theme.align || scene.flags.align || 'center'; + + switch (scene.flags.textmode) { + case 'literal': + scene.text = scene.flags.dimensions.width + 'x' + scene.flags.dimensions.height; + break; + case 'exact': + if (!scene.flags.exactDimensions) break; + scene.text = Math.floor(scene.flags.exactDimensions.width) + 'x' + Math.floor(scene.flags.exactDimensions.height); + break; + } + + var lineWrap = scene.flags.lineWrap || App.setup.lineWrapRatio; + var sceneMargin = scene.width * lineWrap; + var maxLineWidth = sceneMargin; + + var sceneGraph = new SceneGraph({ + width: scene.width, + height: scene.height + }); + + var Shape = sceneGraph.Shape; + + var holderBg = new Shape.Rect('holderBg', { + fill: scene.theme.bg + }); + + holderBg.resize(scene.width, scene.height); + sceneGraph.root.add(holderBg); + + if (scene.flags.outline) { + var outlineColor = new Color(holderBg.properties.fill); + outlineColor = outlineColor.lighten(outlineColor.lighterThan('7f7f7f') ? -0.1 : 0.1); + holderBg.properties.outline = { + fill: outlineColor.toHex(true), + width: 2 + }; + } + + var holderTextColor = scene.theme.fg; + + if (scene.flags.autoFg) { + var holderBgColor = new Color(holderBg.properties.fill); + var lightColor = new Color('fff'); + var darkColor = new Color('000', { + 'alpha': 0.285714 + }); + + holderTextColor = holderBgColor.blendAlpha(holderBgColor.lighterThan('7f7f7f') ? darkColor : lightColor).toHex(true); + } + + var holderTextGroup = new Shape.Group('holderTextGroup', { + text: scene.text, + align: scene.align, + font: scene.font, + fill: holderTextColor + }); + + holderTextGroup.moveTo(null, null, 1); + sceneGraph.root.add(holderTextGroup); + + var tpdata = holderTextGroup.textPositionData = stagingRenderer(sceneGraph); + if (!tpdata) { + throw 'Holder: staging fallback not supported yet.'; + } + holderTextGroup.properties.leading = tpdata.boundingBox.height; + + var textNode = null; + var line = null; + + function finalizeLine(parent, line, width, height) { + line.width = width; + line.height = height; + parent.width = Math.max(parent.width, line.width); + parent.height += line.height; + } + + if (tpdata.lineCount > 1) { + var offsetX = 0; + var offsetY = 0; + var lineIndex = 0; + var lineKey; + line = new Shape.Group('line' + lineIndex); + + //Double margin so that left/right-aligned next is not flush with edge of image + if (scene.align === 'left' || scene.align === 'right') { + maxLineWidth = scene.width * (1 - (1 - lineWrap) * 2); + } + + for (var i = 0; i < tpdata.words.length; i++) { + var word = tpdata.words[i]; + textNode = new Shape.Text(word.text); + var newline = word.text == '\\n'; + if (!scene.noWrap && (offsetX + word.width >= maxLineWidth || newline === true)) { + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + offsetX = 0; + offsetY += holderTextGroup.properties.leading; + lineIndex += 1; + line = new Shape.Group('line' + lineIndex); + line.y = offsetY; + } + if (newline === true) { + continue; + } + textNode.moveTo(offsetX, 0); + offsetX += tpdata.spaceWidth + word.width; + line.add(textNode); + } + + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo(scene.width - line.width, null, null); + } + + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo((holderTextGroup.width - line.width) / 2, null, null); + } + + holderTextGroup.moveTo((scene.width - holderTextGroup.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - holderTextGroup.height) / 2, null); + + //If the text exceeds vertical space, move it down so the first line is visible + if ((scene.height - holderTextGroup.height) / 2 < 0) { + holderTextGroup.moveTo(null, 0, null); + } + } else { + textNode = new Shape.Text(scene.text); + line = new Shape.Group('line0'); + line.add(textNode); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + holderTextGroup.moveTo((scene.width - tpdata.boundingBox.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - tpdata.boundingBox.height) / 2, null); + } + + //todo: renderlist + return sceneGraph; + } + + /** + * Adaptive text sizing function + * + * @private + * @param width Parent width + * @param height Parent height + * @param fontSize Requested text size + * @param scale Proportional scale of text + */ + function textSize(width, height, fontSize, scale) { + var stageWidth = parseInt(width, 10); + var stageHeight = parseInt(height, 10); + + var bigSide = Math.max(stageWidth, stageHeight); + var smallSide = Math.min(stageWidth, stageHeight); + + var newHeight = 0.8 * Math.min(smallSide, bigSide * scale); + return Math.round(Math.max(fontSize, newHeight)); + } + + /** + * Iterates over resizable (fluid or auto) placeholders and renders them + * + * @private + * @param element Optional element selector, specified only if a specific element needs to be re-rendered + */ + function updateResizableElements(element) { + var images; + if (element == null || element.nodeType == null) { + images = App.vars.resizableImages; + } else { + images = [element]; + } + for (var i = 0, l = images.length; i < l; i++) { + var el = images[i]; + if (el.holderData) { + var flags = el.holderData.flags; + var dimensions = dimensionCheck(el); + if (dimensions) { + if (!el.holderData.resizeUpdate) { + continue; + } + + if (flags.fluid && flags.auto) { + var fluidConfig = el.holderData.fluidConfig; + switch (fluidConfig.mode) { + case 'width': + dimensions.height = dimensions.width / fluidConfig.ratio; + break; + case 'height': + dimensions.width = dimensions.height * fluidConfig.ratio; + break; + } + } + + var settings = { + mode: 'image', + holderSettings: { + dimensions: dimensions, + theme: flags.theme, + flags: flags + }, + el: el, + engineSettings: el.holderData.engineSettings + }; + + if (flags.textmode == 'exact') { + flags.exactDimensions = dimensions; + settings.holderSettings.dimensions = flags.dimensions; + } + + render(settings); + } else { + setInvisible(el); + } + } + } + } + + /** + * Sets up aspect ratio metadata for fluid placeholders, in order to preserve proportions when resizing + * + * @private + * @param el Image DOM element + */ + function setInitialDimensions(el) { + if (el.holderData) { + var dimensions = dimensionCheck(el); + if (dimensions) { + var flags = el.holderData.flags; + + var fluidConfig = { + fluidHeight: flags.dimensions.height.slice(-1) == '%', + fluidWidth: flags.dimensions.width.slice(-1) == '%', + mode: null, + initialDimensions: dimensions + }; + + if (fluidConfig.fluidWidth && !fluidConfig.fluidHeight) { + fluidConfig.mode = 'width'; + fluidConfig.ratio = fluidConfig.initialDimensions.width / parseFloat(flags.dimensions.height); + } else if (!fluidConfig.fluidWidth && fluidConfig.fluidHeight) { + fluidConfig.mode = 'height'; + fluidConfig.ratio = parseFloat(flags.dimensions.width) / fluidConfig.initialDimensions.height; + } + + el.holderData.fluidConfig = fluidConfig; + } else { + setInvisible(el); + } + } + } + + /** + * Iterates through all current invisible images, and if they're visible, renders them and removes them from further checks. Runs every animation frame. + * + * @private + */ + function visibilityCheck() { + var renderableImages = []; + var keys = Object.keys(App.vars.invisibleImages); + var el; + + keys.forEach(function (key) { + el = App.vars.invisibleImages[key]; + if (dimensionCheck(el) && el.nodeName.toLowerCase() == 'img') { + renderableImages.push(el); + delete App.vars.invisibleImages[key]; + } + }); + + if (renderableImages.length) { + Holder.run({ + images: renderableImages + }); + } + + // Done to prevent 100% CPU usage via aggressive calling of requestAnimationFrame + setTimeout(function () { + global.requestAnimationFrame(visibilityCheck); + }, 10); + } + + /** + * Starts checking for invisible placeholders if not doing so yet. Does nothing otherwise. + * + * @private + */ + function startVisibilityCheck() { + if (!App.vars.visibilityCheckStarted) { + global.requestAnimationFrame(visibilityCheck); + App.vars.visibilityCheckStarted = true; + } + } + + /** + * Sets a unique ID for an image detected to be invisible and adds it to the map of invisible images checked by visibilityCheck + * + * @private + * @param el Invisible DOM element + */ + function setInvisible(el) { + if (!el.holderData.invisibleId) { + App.vars.invisibleId += 1; + App.vars.invisibleImages['i' + App.vars.invisibleId] = el; + el.holderData.invisibleId = App.vars.invisibleId; + } + } + + //todo: see if possible to convert stagingRenderer to use HTML only + var stagingRenderer = (function() { + var svg = null, + stagingText = null, + stagingTextNode = null; + return function(graph) { + var rootNode = graph.root; + if (App.setup.supportsSVG) { + var firstTimeSetup = false; + var tnode = function(text) { + return document.createTextNode(text); + }; + if (svg == null || svg.parentNode !== document.body) { + firstTimeSetup = true; + } + + svg = SVG.initSVG(svg, rootNode.properties.width, rootNode.properties.height); + //Show staging element before staging + svg.style.display = 'block'; + + if (firstTimeSetup) { + stagingText = DOM.newEl('text', SVG_NS); + stagingTextNode = tnode(null); + DOM.setAttr(stagingText, { + x: 0 + }); + stagingText.appendChild(stagingTextNode); + svg.appendChild(stagingText); + document.body.appendChild(svg); + svg.style.visibility = 'hidden'; + svg.style.position = 'absolute'; + svg.style.top = '-100%'; + svg.style.left = '-100%'; + //todo: workaround for zero-dimension tag in Opera 12 + //svg.setAttribute('width', 0); + //svg.setAttribute('height', 0); + } + + var holderTextGroup = rootNode.children.holderTextGroup; + var htgProps = holderTextGroup.properties; + DOM.setAttr(stagingText, { + 'y': htgProps.font.size, + 'style': utils.cssProps({ + 'font-weight': htgProps.font.weight, + 'font-size': htgProps.font.size + htgProps.font.units, + 'font-family': htgProps.font.family + }) + }); + + //Unescape HTML entities to get approximately the right width + var txt = DOM.newEl('textarea'); + txt.innerHTML = htgProps.text; + stagingTextNode.nodeValue = txt.value; + + //Get bounding box for the whole string (total width and height) + var stagingTextBBox = stagingText.getBBox(); + + //Get line count and split the string into words + var lineCount = Math.ceil(stagingTextBBox.width / rootNode.properties.width); + var words = htgProps.text.split(' '); + var newlines = htgProps.text.match(/\\n/g); + lineCount += newlines == null ? 0 : newlines.length; + + //Get bounding box for the string with spaces removed + stagingTextNode.nodeValue = htgProps.text.replace(/[ ]+/g, ''); + var computedNoSpaceLength = stagingText.getComputedTextLength(); + + //Compute average space width + var diffLength = stagingTextBBox.width - computedNoSpaceLength; + var spaceWidth = Math.round(diffLength / Math.max(1, words.length - 1)); + + //Get widths for every word with space only if there is more than one line + var wordWidths = []; + if (lineCount > 1) { + stagingTextNode.nodeValue = ''; + for (var i = 0; i < words.length; i++) { + if (words[i].length === 0) continue; + stagingTextNode.nodeValue = utils.decodeHtmlEntity(words[i]); + var bbox = stagingText.getBBox(); + wordWidths.push({ + text: words[i], + width: bbox.width + }); + } + } + + //Hide staging element after staging + svg.style.display = 'none'; + + return { + spaceWidth: spaceWidth, + lineCount: lineCount, + boundingBox: stagingTextBBox, + words: wordWidths + }; + } else { + //todo: canvas fallback for measuring text on android 2.3 + return false; + } + }; + })(); + + //Helpers + + /** + * Prevents a function from being called too often, waits until a timer elapses to call it again + * + * @param fn Function to call + */ + function debounce(fn) { + if (!App.vars.debounceTimer) fn.call(this); + if (App.vars.debounceTimer) global.clearTimeout(App.vars.debounceTimer); + App.vars.debounceTimer = global.setTimeout(function() { + App.vars.debounceTimer = null; + fn.call(this); + }, App.setup.debounce); + } + + /** + * Holder-specific resize/orientation change callback, debounced to prevent excessive execution + */ + function resizeEvent() { + debounce(function() { + updateResizableElements(null); + }); + } + + //Set up flags + + for (var flag in App.flags) { + if (!App.flags.hasOwnProperty(flag)) continue; + App.flags[flag].match = function(val) { + return val.match(this.regex); + }; + } + + //Properties set once on setup + + App.setup = { + renderer: 'html', + debounce: 100, + ratio: 1, + supportsCanvas: false, + supportsSVG: false, + lineWrapRatio: 0.9, + dataAttr: 'data-src', + renderers: ['html', 'canvas', 'svg'] + }; + + //Properties modified during runtime + + App.vars = { + preempted: false, + resizableImages: [], + invisibleImages: {}, + invisibleId: 0, + visibilityCheckStarted: false, + debounceTimer: null, + cache: {} + }; + + //Pre-flight + + (function() { + var canvas = DOM.newEl('canvas'); + + if (canvas.getContext) { + if (canvas.toDataURL('image/png').indexOf('data:image/png') != -1) { + App.setup.renderer = 'canvas'; + App.setup.supportsCanvas = true; + } + } + + if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) { + App.setup.renderer = 'svg'; + App.setup.supportsSVG = true; + } + })(); + + //Starts checking for invisible placeholders + startVisibilityCheck(); + + if (onDomReady) { + onDomReady(function() { + if (!App.vars.preempted) { + Holder.run(); + } + if (global.addEventListener) { + global.addEventListener('resize', resizeEvent, false); + global.addEventListener('orientationchange', resizeEvent, false); + } else { + global.attachEvent('onresize', resizeEvent); + } + + if (typeof global.Turbolinks == 'object') { + global.document.addEventListener('page:change', function() { + Holder.run(); + }); + } + }); + } + + module.exports = Holder; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + + /*! + * onDomReady.js 1.4.0 (c) 2013 Tubal Martin - MIT license + * + * Specially modified to work with Holder.js + */ + + function _onDomReady(win) { + //Lazy loading fix for Firefox < 3.6 + //http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + if (document.readyState == null && document.addEventListener) { + document.addEventListener("DOMContentLoaded", function DOMContentLoaded() { + document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); + document.readyState = "complete"; + }, false); + document.readyState = "loading"; + } + + var doc = win.document, + docElem = doc.documentElement, + + LOAD = "load", + FALSE = false, + ONLOAD = "on"+LOAD, + COMPLETE = "complete", + READYSTATE = "readyState", + ATTACHEVENT = "attachEvent", + DETACHEVENT = "detachEvent", + ADDEVENTLISTENER = "addEventListener", + DOMCONTENTLOADED = "DOMContentLoaded", + ONREADYSTATECHANGE = "onreadystatechange", + REMOVEEVENTLISTENER = "removeEventListener", + + // W3C Event model + w3c = ADDEVENTLISTENER in doc, + _top = FALSE, + + // isReady: Is the DOM ready to be used? Set to true once it occurs. + isReady = FALSE, + + // Callbacks pending execution until DOM is ready + callbacks = []; + + // Handle when the DOM is ready + function ready( fn ) { + if ( !isReady ) { + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !doc.body ) { + return defer( ready ); + } + + // Remember that the DOM is ready + isReady = true; + + // Execute all callbacks + while ( fn = callbacks.shift() ) { + defer( fn ); + } + } + } + + // The ready event handler + function completed( event ) { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( w3c || event.type === LOAD || doc[READYSTATE] === COMPLETE ) { + detach(); + ready(); + } + } + + // Clean-up method for dom ready events + function detach() { + if ( w3c ) { + doc[REMOVEEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + win[REMOVEEVENTLISTENER]( LOAD, completed, FALSE ); + } else { + doc[DETACHEVENT]( ONREADYSTATECHANGE, completed ); + win[DETACHEVENT]( ONLOAD, completed ); + } + } + + // Defers a function, scheduling it to run after the current call stack has cleared. + function defer( fn, wait ) { + // Allow 0 to be passed + setTimeout( fn, +wait >= 0 ? wait : 1 ); + } + + // Attach the listeners: + + // Catch cases where onDomReady is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( doc[READYSTATE] === COMPLETE ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + defer( ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( w3c ) { + // Use the handy event callback + doc[ADDEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + + // A fallback to window.onload, that will always work + win[ADDEVENTLISTENER]( LOAD, completed, FALSE ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + doc[ATTACHEVENT]( ONREADYSTATECHANGE, completed ); + + // A fallback to window.onload, that will always work + win[ATTACHEVENT]( ONLOAD, completed ); + + // If IE and not a frame + // continually check to see if the document is ready + try { + _top = win.frameElement == null && docElem; + } catch(e) {} + + if ( _top && _top.doScroll ) { + (function doScrollCheck() { + if ( !isReady ) { + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + _top.doScroll("left"); + } catch(e) { + return defer( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + ready(); + } + })(); + } + } + + function onDomReady( fn ) { + // If DOM is ready, execute the function (async), otherwise wait + isReady ? defer( fn ) : callbacks.push( fn ); + } + + // Add version + onDomReady.version = "1.4.0"; + // Add method to check if DOM is ready + onDomReady.isReady = function(){ + return isReady; + }; + + return onDomReady; + } + + module.exports = typeof window !== "undefined" && _onDomReady(window); + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + //Modified version of component/querystring + //Changes: updated dependencies, dot notation parsing, JSHint fixes + //Fork at https://github.com/imsky/querystring + + /** + * Module dependencies. + */ + + var encode = encodeURIComponent; + var decode = decodeURIComponent; + var trim = __webpack_require__(4); + var type = __webpack_require__(5); + + var arrayRegex = /(\w+)\[(\d+)\]/; + var objectRegex = /\w+\.\w+/; + + /** + * Parse the given query `str`. + * + * @param {String} str + * @return {Object} + * @api public + */ + + exports.parse = function(str){ + if ('string' !== typeof str) return {}; + + str = trim(str); + if ('' === str) return {}; + if ('?' === str.charAt(0)) str = str.slice(1); + + var obj = {}; + var pairs = str.split('&'); + for (var i = 0; i < pairs.length; i++) { + var parts = pairs[i].split('='); + var key = decode(parts[0]); + var m, ctx, prop; + + if (m = arrayRegex.exec(key)) { + obj[m[1]] = obj[m[1]] || []; + obj[m[1]][m[2]] = decode(parts[1]); + continue; + } + + if (m = objectRegex.test(key)) { + m = key.split('.'); + ctx = obj; + + while (m.length) { + prop = m.shift(); + + if (!prop.length) continue; + + if (!ctx[prop]) { + ctx[prop] = {}; + } else if (ctx[prop] && typeof ctx[prop] !== 'object') { + break; + } + + if (!m.length) { + ctx[prop] = decode(parts[1]); + } + + ctx = ctx[prop]; + } + + continue; + } + + obj[parts[0]] = null == parts[1] ? '' : decode(parts[1]); + } + + return obj; + }; + + /** + * Stringify the given `obj`. + * + * @param {Object} obj + * @return {String} + * @api public + */ + + exports.stringify = function(obj){ + if (!obj) return ''; + var pairs = []; + + for (var key in obj) { + var value = obj[key]; + + if ('array' == type(value)) { + for (var i = 0; i < value.length; ++i) { + pairs.push(encode(key + '[' + i + ']') + '=' + encode(value[i])); + } + continue; + } + + pairs.push(encode(key) + '=' + encode(obj[key])); + } + + return pairs.join('&'); + }; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + + exports = module.exports = trim; + + function trim(str){ + return str.replace(/^\s*|\s*$/g, ''); + } + + exports.left = function(str){ + return str.replace(/^\s*/, ''); + }; + + exports.right = function(str){ + return str.replace(/\s*$/, ''); + }; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + /** + * toString ref. + */ + + var toString = Object.prototype.toString; + + /** + * Return the type of `val`. + * + * @param {Mixed} val + * @return {String} + * @api public + */ + + module.exports = function(val){ + switch (toString.call(val)) { + case '[object Date]': return 'date'; + case '[object RegExp]': return 'regexp'; + case '[object Arguments]': return 'arguments'; + case '[object Array]': return 'array'; + case '[object Error]': return 'error'; + } + + if (val === null) return 'null'; + if (val === undefined) return 'undefined'; + if (val !== val) return 'nan'; + if (val && val.nodeType === 1) return 'element'; + + val = val.valueOf + ? val.valueOf() + : Object.prototype.valueOf.apply(val) + + return typeof val; + }; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports) { + + var SceneGraph = function(sceneProperties) { + var nodeCount = 1; + + //todo: move merge to helpers section + function merge(parent, child) { + for (var prop in child) { + parent[prop] = child[prop]; + } + return parent; + } + + var SceneNode = function(name) { + nodeCount++; + this.parent = null; + this.children = {}; + this.id = nodeCount; + this.name = 'n' + nodeCount; + if (typeof name !== 'undefined') { + this.name = name; + } + this.x = this.y = this.z = 0; + this.width = this.height = 0; + }; + + SceneNode.prototype.resize = function(width, height) { + if (width != null) { + this.width = width; + } + if (height != null) { + this.height = height; + } + }; + + SceneNode.prototype.moveTo = function(x, y, z) { + this.x = x != null ? x : this.x; + this.y = y != null ? y : this.y; + this.z = z != null ? z : this.z; + }; + + SceneNode.prototype.add = function(child) { + var name = child.name; + if (typeof this.children[name] === 'undefined') { + this.children[name] = child; + child.parent = this; + } else { + throw 'SceneGraph: child already exists: ' + name; + } + }; + + var RootNode = function() { + SceneNode.call(this, 'root'); + this.properties = sceneProperties; + }; + + RootNode.prototype = new SceneNode(); + + var Shape = function(name, props) { + SceneNode.call(this, name); + this.properties = { + 'fill': '#000000' + }; + if (typeof props !== 'undefined') { + merge(this.properties, props); + } else if (typeof name !== 'undefined' && typeof name !== 'string') { + throw 'SceneGraph: invalid node name'; + } + }; + + Shape.prototype = new SceneNode(); + + var Group = function() { + Shape.apply(this, arguments); + this.type = 'group'; + }; + + Group.prototype = new Shape(); + + var Rect = function() { + Shape.apply(this, arguments); + this.type = 'rect'; + }; + + Rect.prototype = new Shape(); + + var Text = function(text) { + Shape.call(this); + this.type = 'text'; + this.properties.text = text; + }; + + Text.prototype = new Shape(); + + var root = new RootNode(); + + this.Shape = { + 'Rect': Rect, + 'Text': Text, + 'Group': Group + }; + + this.root = root; + return this; + }; + + module.exports = SceneGraph; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Shallow object clone and merge + * + * @param a Object A + * @param b Object B + * @returns {Object} New object with all of A's properties, and all of B's properties, overwriting A's properties + */ + exports.extend = function(a, b) { + var c = {}; + for (var x in a) { + if (a.hasOwnProperty(x)) { + c[x] = a[x]; + } + } + if (b != null) { + for (var y in b) { + if (b.hasOwnProperty(y)) { + c[y] = b[y]; + } + } + } + return c; + }; + + /** + * Takes a k/v list of CSS properties and returns a rule + * + * @param props CSS properties object + */ + exports.cssProps = function(props) { + var ret = []; + for (var p in props) { + if (props.hasOwnProperty(p)) { + ret.push(p + ':' + props[p]); + } + } + return ret.join(';'); + }; + + /** + * Encodes HTML entities in a string + * + * @param str Input string + */ + exports.encodeHtmlEntity = function(str) { + var buf = []; + var charCode = 0; + for (var i = str.length - 1; i >= 0; i--) { + charCode = str.charCodeAt(i); + if (charCode > 128) { + buf.unshift(['&#', charCode, ';'].join('')); + } else { + buf.unshift(str[i]); + } + } + return buf.join(''); + }; + + /** + * Checks if an image exists + * + * @param src URL of image + * @param callback Callback to call once image status has been found + */ + exports.imageExists = function(src, callback) { + var image = new Image(); + image.onerror = function() { + callback.call(this, false); + }; + image.onload = function() { + callback.call(this, true); + }; + image.src = src; + }; + + /** + * Decodes HTML entities in a string + * + * @param str Input string + */ + exports.decodeHtmlEntity = function(str) { + return str.replace(/&#(\d+);/g, function(match, dec) { + return String.fromCharCode(dec); + }); + }; + + + /** + * Returns an element's dimensions if it's visible, `false` otherwise. + * + * @param el DOM element + */ + exports.dimensionCheck = function(el) { + var dimensions = { + height: el.clientHeight, + width: el.clientWidth + }; + + if (dimensions.height && dimensions.width) { + return dimensions; + } else { + return false; + } + }; + + + /** + * Returns true if value is truthy or if it is "semantically truthy" + * @param val + */ + exports.truthy = function(val) { + if (typeof val === 'string') { + return val === 'true' || val === 'yes' || val === '1' || val === 'on' || val === '✓'; + } + return !!val; + }; + + /** + * Parses input into a well-formed CSS color + * @param val + */ + exports.parseColor = function(val) { + var hexre = /(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i; + var rgbre = /^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/; + var rgbare = /^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/; + + var match = val.match(hexre); + var retval; + + if (match !== null) { + retval = match[1] || match[2]; + if (retval[0] !== '#') { + return '#' + retval; + } else { + return retval; + } + } + + match = val.match(rgbre); + + if (match !== null) { + retval = 'rgb(' + match.slice(1).join(',') + ')'; + return retval; + } + + match = val.match(rgbare); + + if (match !== null) { + const normalizeAlpha = function (a) { return '0.' + a.split('.')[1]; }; + const fixedMatch = match.slice(1).map(function (e, i) { + return (i === 3) ? normalizeAlpha(e) : e; + }); + retval = 'rgba(' + fixedMatch.join(',') + ')'; + return retval; + } + + return null; + }; + + /** + * Provides the correct scaling ratio for canvas drawing operations on HiDPI screens (e.g. Retina displays) + */ + exports.canvasRatio = function () { + var devicePixelRatio = 1; + var backingStoreRatio = 1; + + if (global.document) { + var canvas = global.document.createElement('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + devicePixelRatio = global.devicePixelRatio || 1; + backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; + } + } + + return devicePixelRatio / backingStoreRatio; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {var DOM = __webpack_require__(9); + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var NODE_TYPE_COMMENT = 8; + + /** + * Generic SVG element creation function + * + * @param svg SVG context, set to null if new + * @param width Document width + * @param height Document height + */ + exports.initSVG = function(svg, width, height) { + var defs, style, initialize = false; + + if (svg && svg.querySelector) { + style = svg.querySelector('style'); + if (style === null) { + initialize = true; + } + } else { + svg = DOM.newEl('svg', SVG_NS); + initialize = true; + } + + if (initialize) { + defs = DOM.newEl('defs', SVG_NS); + style = DOM.newEl('style', SVG_NS); + DOM.setAttr(style, { + 'type': 'text/css' + }); + defs.appendChild(style); + svg.appendChild(defs); + } + + //IE throws an exception if this is set and Chrome requires it to be set + if (svg.webkitMatchesSelector) { + svg.setAttribute('xmlns', SVG_NS); + } + + //Remove comment nodes + for (var i = 0; i < svg.childNodes.length; i++) { + if (svg.childNodes[i].nodeType === NODE_TYPE_COMMENT) { + svg.removeChild(svg.childNodes[i]); + } + } + + //Remove CSS + while (style.childNodes.length) { + style.removeChild(style.childNodes[0]); + } + + DOM.setAttr(svg, { + 'width': width, + 'height': height, + 'viewBox': '0 0 ' + width + ' ' + height, + 'preserveAspectRatio': 'none' + }); + + return svg; + }; + + /** + * Converts serialized SVG to a string suitable for data URI use + * @param svgString Serialized SVG string + * @param [base64] Use base64 encoding for data URI + */ + exports.svgStringToDataURI = function() { + var rawPrefix = 'data:image/svg+xml;charset=UTF-8,'; + var base64Prefix = 'data:image/svg+xml;charset=UTF-8;base64,'; + + return function(svgString, base64) { + if (base64) { + return base64Prefix + btoa(global.unescape(encodeURIComponent(svgString))); + } else { + return rawPrefix + encodeURIComponent(svgString); + } + }; + }(); + + /** + * Returns serialized SVG with XML processing instructions + * + * @param svg SVG context + * @param stylesheets CSS stylesheets to include + */ + exports.serializeSVG = function(svg, engineSettings) { + if (!global.XMLSerializer) return; + var serializer = new XMLSerializer(); + var svgCSS = ''; + var stylesheets = engineSettings.stylesheets; + + //External stylesheets: Processing Instruction method + if (engineSettings.svgXMLStylesheet) { + var xml = DOM.createXML(); + //Add directives + for (var i = stylesheets.length - 1; i >= 0; i--) { + var csspi = xml.createProcessingInstruction('xml-stylesheet', 'href="' + stylesheets[i] + '" rel="stylesheet"'); + xml.insertBefore(csspi, xml.firstChild); + } + + xml.removeChild(xml.documentElement); + svgCSS = serializer.serializeToString(xml); + } + + var svgText = serializer.serializeToString(svg); + svgText = svgText.replace(/\&(\#[0-9]{2,}\;)/g, '&$1'); + return svgCSS + svgText; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Generic new DOM element function + * + * @param tag Tag to create + * @param namespace Optional namespace value + */ + exports.newEl = function(tag, namespace) { + if (!global.document) return; + + if (namespace == null) { + return global.document.createElement(tag); + } else { + return global.document.createElementNS(namespace, tag); + } + }; + + /** + * Generic setAttribute function + * + * @param el Reference to DOM element + * @param attrs Object with attribute keys and values + */ + exports.setAttr = function (el, attrs) { + for (var a in attrs) { + el.setAttribute(a, attrs[a]); + } + }; + + /** + * Creates a XML document + * @private + */ + exports.createXML = function() { + if (!global.DOMParser) return; + return new DOMParser().parseFromString('', 'application/xml'); + }; + + /** + * Converts a value into an array of DOM nodes + * + * @param val A string, a NodeList, a Node, or an HTMLCollection + */ + exports.getNodeArray = function(val) { + var retval = null; + if (typeof(val) == 'string') { + retval = document.querySelectorAll(val); + } else if (global.NodeList && val instanceof global.NodeList) { + retval = val; + } else if (global.Node && val instanceof global.Node) { + retval = [val]; + } else if (global.HTMLCollection && val instanceof global.HTMLCollection) { + retval = val; + } else if (val instanceof Array) { + retval = val; + } else if (val === null) { + retval = []; + } + + retval = Array.prototype.slice.call(retval); + + return retval; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 10 */ +/***/ (function(module, exports) { + + var Color = function(color, options) { + //todo: support rgba, hsla, and rrggbbaa notation + //todo: use CIELAB internally + //todo: add clamp function (with sign) + if (typeof color !== 'string') return; + + this.original = color; + + if (color.charAt(0) === '#') { + color = color.slice(1); + } + + if (/[^a-f0-9]+/i.test(color)) return; + + if (color.length === 3) { + color = color.replace(/./g, '$&$&'); + } + + if (color.length !== 6) return; + + this.alpha = 1; + + if (options && options.alpha) { + this.alpha = options.alpha; + } + + this.set(parseInt(color, 16)); + }; + + //todo: jsdocs + Color.rgb2hex = function(r, g, b) { + function format (decimal) { + var hex = (decimal | 0).toString(16); + if (decimal < 16) { + hex = '0' + hex; + } + return hex; + } + + return [r, g, b].map(format).join(''); + }; + + //todo: jsdocs + Color.hsl2rgb = function (h, s, l) { + var H = h / 60; + var C = (1 - Math.abs(2 * l - 1)) * s; + var X = C * (1 - Math.abs(parseInt(H) % 2 - 1)); + var m = l - (C / 2); + + var r = 0, g = 0, b = 0; + + if (H >= 0 && H < 1) { + r = C; + g = X; + } else if (H >= 1 && H < 2) { + r = X; + g = C; + } else if (H >= 2 && H < 3) { + g = C; + b = X; + } else if (H >= 3 && H < 4) { + g = X; + b = C; + } else if (H >= 4 && H < 5) { + r = X; + b = C; + } else if (H >= 5 && H < 6) { + r = C; + b = X; + } + + r += m; + g += m; + b += m; + + r = parseInt(r * 255); + g = parseInt(g * 255); + b = parseInt(b * 255); + + return [r, g, b]; + }; + + /** + * Sets the color from a raw RGB888 integer + * @param raw RGB888 representation of color + */ + //todo: refactor into a static method + //todo: factor out individual color spaces + //todo: add HSL, CIELAB, and CIELUV + Color.prototype.set = function (val) { + this.raw = val; + + var r = (this.raw & 0xFF0000) >> 16; + var g = (this.raw & 0x00FF00) >> 8; + var b = (this.raw & 0x0000FF); + + // BT.709 + var y = 0.2126 * r + 0.7152 * g + 0.0722 * b; + var u = -0.09991 * r - 0.33609 * g + 0.436 * b; + var v = 0.615 * r - 0.55861 * g - 0.05639 * b; + + this.rgb = { + r: r, + g: g, + b: b + }; + + this.yuv = { + y: y, + u: u, + v: v + }; + + return this; + }; + + /** + * Lighten or darken a color + * @param multiplier Amount to lighten or darken (-1 to 1) + */ + Color.prototype.lighten = function(multiplier) { + var cm = Math.min(1, Math.max(0, Math.abs(multiplier))) * (multiplier < 0 ? -1 : 1); + var bm = (255 * cm) | 0; + var cr = Math.min(255, Math.max(0, this.rgb.r + bm)); + var cg = Math.min(255, Math.max(0, this.rgb.g + bm)); + var cb = Math.min(255, Math.max(0, this.rgb.b + bm)); + var hex = Color.rgb2hex(cr, cg, cb); + return new Color(hex); + }; + + /** + * Output color in hex format + * @param addHash Add a hash character to the beginning of the output + */ + Color.prototype.toHex = function(addHash) { + return (addHash ? '#' : '') + this.raw.toString(16); + }; + + /** + * Returns whether or not current color is lighter than another color + * @param color Color to compare against + */ + Color.prototype.lighterThan = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + return this.yuv.y > color.yuv.y; + }; + + /** + * Returns the result of mixing current color with another color + * @param color Color to mix with + * @param multiplier How much to mix with the other color + */ + /* + Color.prototype.mix = function (color, multiplier) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var r = this.rgb.r; + var g = this.rgb.g; + var b = this.rgb.b; + var a = this.alpha; + + var m = typeof multiplier !== 'undefined' ? multiplier : 0.5; + + //todo: write a lerp function + r = r + m * (color.rgb.r - r); + g = g + m * (color.rgb.g - g); + b = b + m * (color.rgb.b - b); + a = a + m * (color.alpha - a); + + return new Color(Color.rgbToHex(r, g, b), { + 'alpha': a + }); + }; + */ + + /** + * Returns the result of blending another color on top of current color with alpha + * @param color Color to blend on top of current color, i.e. "Ca" + */ + //todo: see if .blendAlpha can be merged into .mix + Color.prototype.blendAlpha = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var Ca = color; + var Cb = this; + + //todo: write alpha blending function + var r = Ca.alpha * Ca.rgb.r + (1 - Ca.alpha) * Cb.rgb.r; + var g = Ca.alpha * Ca.rgb.g + (1 - Ca.alpha) * Cb.rgb.g; + var b = Ca.alpha * Ca.rgb.b + (1 - Ca.alpha) * Cb.rgb.b; + + return new Color(Color.rgb2hex(r, g, b)); + }; + + module.exports = Color; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + module.exports = { + 'version': '2.9.7', + 'svg_ns': 'http://www.w3.org/2000/svg' + }; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + var shaven = __webpack_require__(13); + + var SVG = __webpack_require__(8); + var constants = __webpack_require__(11); + var utils = __webpack_require__(7); + + var SVG_NS = constants.svg_ns; + + var templates = { + 'element': function (options) { + var tag = options.tag; + var content = options.content || ''; + delete options.tag; + delete options.content; + return [tag, content, options]; + } + }; + + //todo: deprecate tag arg, infer tag from shape object + function convertShape (shape, tag) { + return templates.element({ + 'tag': tag, + 'width': shape.width, + 'height': shape.height, + 'fill': shape.properties.fill + }); + } + + function textCss (properties) { + return utils.cssProps({ + 'fill': properties.fill, + 'font-weight': properties.font.weight, + 'font-family': properties.font.family + ', monospace', + 'font-size': properties.font.size + properties.font.units + }); + } + + function outlinePath (bgWidth, bgHeight, outlineWidth) { + var outlineOffsetWidth = outlineWidth / 2; + + return [ + 'M', outlineOffsetWidth, outlineOffsetWidth, + 'H', bgWidth - outlineOffsetWidth, + 'V', bgHeight - outlineOffsetWidth, + 'H', outlineOffsetWidth, + 'V', 0, + 'M', 0, outlineOffsetWidth, + 'L', bgWidth, bgHeight - outlineOffsetWidth, + 'M', 0, bgHeight - outlineOffsetWidth, + 'L', bgWidth, outlineOffsetWidth + ].join(' '); + } + + module.exports = function (sceneGraph, renderSettings) { + var engineSettings = renderSettings.engineSettings; + var stylesheets = engineSettings.stylesheets; + var stylesheetXml = stylesheets.map(function (stylesheet) { + return ''; + }).join('\n'); + + var holderId = 'holder_' + Number(new Date()).toString(16); + + var root = sceneGraph.root; + var textGroup = root.children.holderTextGroup; + + var css = '#' + holderId + ' text { ' + textCss(textGroup.properties) + ' } '; + + // push text down to be equally vertically aligned with canvas renderer + textGroup.y += textGroup.textPositionData.boundingBox.height * 0.8; + + var wordTags = []; + + Object.keys(textGroup.children).forEach(function (lineKey) { + var line = textGroup.children[lineKey]; + + Object.keys(line.children).forEach(function (wordKey) { + var word = line.children[wordKey]; + var x = textGroup.x + line.x + word.x; + var y = textGroup.y + line.y + word.y; + var wordTag = templates.element({ + 'tag': 'text', + 'content': word.properties.text, + 'x': x, + 'y': y + }); + + wordTags.push(wordTag); + }); + }); + + var text = templates.element({ + 'tag': 'g', + 'content': wordTags + }); + + var outline = null; + + if (root.children.holderBg.properties.outline) { + var outlineProperties = root.children.holderBg.properties.outline; + outline = templates.element({ + 'tag': 'path', + 'd': outlinePath(root.children.holderBg.width, root.children.holderBg.height, outlineProperties.width), + 'stroke-width': outlineProperties.width, + 'stroke': outlineProperties.fill, + 'fill': 'none' + }); + } + + var bg = convertShape(root.children.holderBg, 'rect'); + + var sceneContent = []; + + sceneContent.push(bg); + if (outlineProperties) { + sceneContent.push(outline); + } + sceneContent.push(text); + + var scene = templates.element({ + 'tag': 'g', + 'id': holderId, + 'content': sceneContent + }); + + var style = templates.element({ + 'tag': 'style', + //todo: figure out how to add CDATA directive + 'content': css, + 'type': 'text/css' + }); + + var defs = templates.element({ + 'tag': 'defs', + 'content': style + }); + + var svg = templates.element({ + 'tag': 'svg', + 'content': [defs, scene], + 'width': root.properties.width, + 'height': root.properties.height, + 'xmlns': SVG_NS, + 'viewBox': [0, 0, root.properties.width, root.properties.height].join(' '), + 'preserveAspectRatio': 'none' + }); + + var output = shaven(svg); + + if (/\&(x)?#[0-9A-Fa-f]/.test(output[0])) { + output[0] = output[0].replace(/&#/gm, '&#'); + } + + output = stylesheetXml + output[0]; + + var svgString = SVG.svgStringToDataURI(output, renderSettings.mode === 'background'); + return svgString; + }; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + var escape = __webpack_require__(14) + + // TODO: remove namespace + + module.exports = function shaven (array, namespace, returnObject) { + + 'use strict' + + var i = 1 + var doesEscape = true + var HTMLString + var attributeKey + var callback + var key + + + returnObject = returnObject || {} + + + function createElement (sugarString) { + + var tags = sugarString.match(/^[\w-]+/) + var element = { + tag: tags ? tags[0] : 'div', + attr: {}, + children: [] + } + var id = sugarString.match(/#([\w-]+)/) + var reference = sugarString.match(/\$([\w-]+)/) + var classNames = sugarString.match(/\.[\w-]+/g) + + + // Assign id if is set + if (id) { + element.attr.id = id[1] + + // Add element to the return object + returnObject[id[1]] = element + } + + if (reference) + returnObject[reference[1]] = element + + if (classNames) + element.attr.class = classNames.join(' ').replace(/\./g, '') + + if (sugarString.match(/&$/g)) + doesEscape = false + + return element + } + + function replacer (key, value) { + + if (value === null || value === false || value === undefined) + return + + if (typeof value !== 'string' && typeof value !== 'object') + return String(value) + + return value + } + + function escapeAttribute (string) { + return (string || string === 0) ? + String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') : + '' + } + + function escapeHTML (string) { + return String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>') + } + + + if (typeof array[0] === 'string') + array[0] = createElement(array[0]) + + else if (Array.isArray(array[0])) + i = 0 + + else + throw new Error( + 'First element of array must be a string, ' + + 'or an array and not ' + JSON.stringify(array[0]) + ) + + + for (; i < array.length; i++) { + + // Don't render element if value is false or null + if (array[i] === false || array[i] === null) { + array[0] = false + break + } + + // Continue with next array value if current value is undefined or true + else if (array[i] === undefined || array[i] === true) { + continue + } + + else if (typeof array[i] === 'string') { + if (doesEscape) + array[i] = escapeHTML(array[i]) + + array[0].children.push(array[i]) + } + + else if (typeof array[i] === 'number') { + + array[0].children.push(array[i]) + } + + else if (Array.isArray(array[i])) { + + if (Array.isArray(array[i][0])) { + array[i].reverse().forEach(function (subArray) { + array.splice(i + 1, 0, subArray) + }) + + if (i !== 0) + continue + i++ + } + + shaven(array[i], namespace, returnObject) + + if (array[i][0]) + array[0].children.push(array[i][0]) + } + + else if (typeof array[i] === 'function') + callback = array[i] + + + else if (typeof array[i] === 'object') { + for (attributeKey in array[i]) + if (array[i].hasOwnProperty(attributeKey)) + if (array[i][attributeKey] !== null && + array[i][attributeKey] !== false) + if (attributeKey === 'style' && + typeof array[i][attributeKey] === 'object') + array[0].attr[attributeKey] = JSON + .stringify(array[i][attributeKey], replacer) + .slice(2, -2) + .replace(/","/g, ';') + .replace(/":"/g, ':') + .replace(/\\"/g, '\'') + + else + array[0].attr[attributeKey] = array[i][attributeKey] + } + + else + throw new TypeError('"' + array[i] + '" is not allowed as a value.') + } + + + if (array[0] !== false) { + + HTMLString = '<' + array[0].tag + + for (key in array[0].attr) + if (array[0].attr.hasOwnProperty(key)) + HTMLString += ' ' + key + '="' + + escapeAttribute(array[0].attr[key]) + '"' + + HTMLString += '>' + + array[0].children.forEach(function (child) { + HTMLString += child + }) + + HTMLString += '' + + array[0] = HTMLString + } + + // Return root element on index 0 + returnObject[0] = array[0] + + if (callback) + callback(array[0]) + + // returns object containing all elements with an id and the root element + return returnObject + } + + +/***/ }), +/* 14 */ +/***/ (function(module, exports) { + + /*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */ + + 'use strict'; + + /** + * Module variables. + * @private + */ + + var matchHtmlRegExp = /["'&<>]/; + + /** + * Module exports. + * @public + */ + + module.exports = escapeHtml; + + /** + * Escape special characters in the given string of html. + * + * @param {string} string The string to escape for inserting into HTML + * @return {string} + * @public + */ + + function escapeHtml(string) { + var str = '' + string; + var match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } + + var escape; + var html = ''; + var index = 0; + var lastIndex = 0; + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"'; + break; + case 38: // & + escape = '&'; + break; + case 39: // ' + escape = '''; + break; + case 60: // < + escape = '<'; + break; + case 62: // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html; + } + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + var DOM = __webpack_require__(9); + var utils = __webpack_require__(7); + + module.exports = (function() { + var canvas = DOM.newEl('canvas'); + var ctx = null; + + return function(sceneGraph) { + if (ctx == null) { + ctx = canvas.getContext('2d'); + } + + var dpr = utils.canvasRatio(); + var root = sceneGraph.root; + canvas.width = dpr * root.properties.width; + canvas.height = dpr * root.properties.height ; + ctx.textBaseline = 'middle'; + + var bg = root.children.holderBg; + var bgWidth = dpr * bg.width; + var bgHeight = dpr * bg.height; + //todo: parametrize outline width (e.g. in scene object) + var outlineWidth = 2; + var outlineOffsetWidth = outlineWidth / 2; + + ctx.fillStyle = bg.properties.fill; + ctx.fillRect(0, 0, bgWidth, bgHeight); + + if (bg.properties.outline) { + //todo: abstract this into a method + ctx.strokeStyle = bg.properties.outline.fill; + ctx.lineWidth = bg.properties.outline.width; + ctx.moveTo(outlineOffsetWidth, outlineOffsetWidth); + // TL, TR, BR, BL + ctx.lineTo(bgWidth - outlineOffsetWidth, outlineOffsetWidth); + ctx.lineTo(bgWidth - outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, outlineOffsetWidth); + // Diagonals + ctx.moveTo(0, outlineOffsetWidth); + ctx.lineTo(bgWidth, bgHeight - outlineOffsetWidth); + ctx.moveTo(0, bgHeight - outlineOffsetWidth); + ctx.lineTo(bgWidth, outlineOffsetWidth); + ctx.stroke(); + } + + var textGroup = root.children.holderTextGroup; + ctx.font = textGroup.properties.font.weight + ' ' + (dpr * textGroup.properties.font.size) + textGroup.properties.font.units + ' ' + textGroup.properties.font.family + ', monospace'; + ctx.fillStyle = textGroup.properties.fill; + + for (var lineKey in textGroup.children) { + var line = textGroup.children[lineKey]; + for (var wordKey in line.children) { + var word = line.children[wordKey]; + var x = dpr * (textGroup.x + line.x + word.x); + var y = dpr * (textGroup.y + line.y + word.y + (textGroup.properties.leading / 2)); + + ctx.fillText(word.properties.text, x, y); + } + } + + return canvas.toDataURL('image/png'); + }; + })(); + +/***/ }) +/******/ ]) +}); +; +(function(ctx, isMeteorPackage) { + if (isMeteorPackage) { + Holder = ctx.Holder; + } +})(this, typeof Meteor !== 'undefined' && typeof Package !== 'undefined'); diff --git a/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.min.js b/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.min.js new file mode 100644 index 0000000..6935bf1 --- /dev/null +++ b/BlazorStudy.Bootstrap5Study/wwwroot/plugs/holder/holder.min.js @@ -0,0 +1,14 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://imsky.co + +Site: http://holderjs.com +Issues: https://github.com/imsky/holder/issues +License: MIT + +*/ +!function(e){if(e.document){var t=e.document;t.querySelectorAll||(t.querySelectorAll=function(n){var r,i=t.createElement("style"),a=[];for(t.documentElement.firstChild.appendChild(i),t._qsa=[],i.styleSheet.cssText=n+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",e.scrollBy(0,0),i.parentNode.removeChild(i);t._qsa.length;)r=t._qsa.shift(),r.style.removeAttribute("x-qsa"),a.push(r);return t._qsa=null,a}),t.querySelector||(t.querySelector=function(e){var n=t.querySelectorAll(e);return n.length?n[0]:null}),t.getElementsByClassName||(t.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),t.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(t);return n}),Array.prototype.forEach||(Array.prototype.forEach=function(e){if(void 0===this||null===this)throw TypeError();var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;n>r;r++)r in t&&e.call(i,t[r],r,t)}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var n,r=0,i=[],a=0,o=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+\/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;r>16&255)),i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a)),o=0,a=0),r+=1;return 12===o?(a>>=4,i.push(String.fromCharCode(255&a))):18===o&&(a>>=2,i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,a,o,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,o=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(a),t.charAt(o),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame&&e.webkitCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame&&e.mozCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var o=i(n.substr(n.lastIndexOf(e.domain)),e);o&&a({mode:null,el:r,flags:o,engineSettings:t})}function i(e,t){var n={theme:T(O.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.indexOf("?"),i=[e];-1!==r&&(i=[e.slice(0,r),e.slice(r+1)]);var a=i[0].split("/");n.holderURL=e;var o=a[1],s=o.match(/([\d]+p?)x([\d]+p?)/);if(!s)return!1;if(n.fluid=-1!==o.indexOf("p"),n.dimensions={width:s[1].replace("p","%"),height:s[2].replace("p","%")},2===i.length){var l=v.parse(i[1]);if(w.truthy(l.ratio)){n.fluid=!0;var h=parseFloat(n.dimensions.width.replace("%","")),u=parseFloat(n.dimensions.height.replace("%",""));u=Math.floor(100*(u/h)),h=100,n.dimensions.width=h+"%",n.dimensions.height=u+"%"}if(n.auto=w.truthy(l.auto),l.bg&&(n.theme.bg=w.parseColor(l.bg)),l.fg&&(n.theme.fg=w.parseColor(l.fg)),l.bg&&!l.fg&&(n.autoFg=!0),l.theme&&n.instanceOptions.themes.hasOwnProperty(l.theme)&&(n.theme=T(n.instanceOptions.themes[l.theme],null)),l.text&&(n.text=l.text),l.textmode&&(n.textmode=l.textmode),l.size&&parseFloat(l.size)&&(n.size=parseFloat(l.size)),l.font&&(n.font=l.font),l.align&&(n.align=l.align),l.lineWrap&&(n.lineWrap=l.lineWrap),n.nowrap=w.truthy(l.nowrap),n.outline=w.truthy(l.outline),w.truthy(l.random)){O.vars.cache.themeKeys=O.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var d=O.vars.cache.themeKeys[0|Math.random()*O.vars.cache.themeKeys.length];n.theme=T(n.instanceOptions.themes[d],null)}}return n}function a(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,a=r.dimensions,s=r.theme,l=a.width+"x"+a.height;t=null==t?r.fluid?"fluid":"image":t;var d=/holder_([a-z]+)/g,c=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),("left"===e.align||"right"===e.align)&&(a=e.width*(1-2*(1-r)));for(var E=0;E=a||k===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),k!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+T.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return o}function l(e,t,n,r){var i=parseInt(e,10),a=parseInt(t,10),o=Math.max(i,a),s=Math.min(i,a),l=.8*Math.min(s,o*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?O.vars.resizableImages:[e];for(var n=0,r=t.length;r>n;n++){var i=t[n];if(i.holderData){var a=i.holderData.flags,s=k(i);if(s){if(!i.holderData.resizeUpdate)continue;if(a.fluid&&a.auto){var l=i.holderData.fluidConfig;switch(l.mode){case"width":s.height=s.width/l.ratio;break;case"height":s.width=s.height*l.ratio}}var h={mode:"image",holderSettings:{dimensions:s,theme:a.theme,flags:a},el:i,engineSettings:i.holderData.engineSettings};"exact"==a.textmode&&(a.exactDimensions=s,h.holderSettings.dimensions=a.dimensions),o(h)}else f(i)}}}function u(e){if(e.holderData){var t=k(e);if(t){var n=e.holderData.flags,r={fluidHeight:"%"==n.dimensions.height.slice(-1),fluidWidth:"%"==n.dimensions.width.slice(-1),mode:null,initialDimensions:t};r.fluidWidth&&!r.fluidHeight?(r.mode="width",r.ratio=r.initialDimensions.width/parseFloat(n.dimensions.height)):!r.fluidWidth&&r.fluidHeight&&(r.mode="height",r.ratio=parseFloat(n.dimensions.width)/r.initialDimensions.height),e.holderData.fluidConfig=r}else f(e)}}function d(){var e,n=[],r=Object.keys(O.vars.invisibleImages);r.forEach(function(t){e=O.vars.invisibleImages[t],k(e)&&"img"==e.nodeName.toLowerCase()&&(n.push(e),delete O.vars.invisibleImages[t])}),n.length&&j.run({images:n}),setTimeout(function(){t.requestAnimationFrame(d)},10)}function c(){O.vars.visibilityCheckStarted||(t.requestAnimationFrame(d),O.vars.visibilityCheckStarted=!0)}function f(e){e.holderData.invisibleId||(O.vars.invisibleId+=1,O.vars.invisibleImages["i"+O.vars.invisibleId]=e,e.holderData.invisibleId=O.vars.invisibleId)}function p(e){O.vars.debounceTimer||e.call(this),O.vars.debounceTimer&&t.clearTimeout(O.vars.debounceTimer),O.vars.debounceTimer=t.setTimeout(function(){O.vars.debounceTimer=null,e.call(this)},O.setup.debounce)}function g(){p(function(){h(null)})}var m=n(2),v=n(3),y=n(6),w=n(7),b=n(8),x=n(9),S=n(10),A=n(11),C=n(12),E=n(15),T=w.extend,k=w.dimensionCheck,F=A.svg_ns,j={version:A.version,addTheme:function(e,t){return null!=e&&null!=t&&(O.settings.themes[e]=t),delete O.vars.cache.themeKeys,this},addImage:function(e,t){var n=x.getNodeArray(t);return n.forEach(function(t){var n=x.newEl("img"),r={};r[O.setup.dataAttr]=e,x.setAttr(n,r),t.appendChild(n)}),this},setResizeUpdate:function(e,t){e.holderData&&(e.holderData.resizeUpdate=!!t,e.holderData.resizeUpdate&&h(e))},run:function(e){e=e||{};var n={},o=T(O.settings,e);O.vars.preempted=!0,O.vars.dataAttr=o.dataAttr||O.setup.dataAttr,n.renderer=o.renderer?o.renderer:O.setup.renderer,-1===O.setup.renderers.join(",").indexOf(n.renderer)&&(n.renderer=O.setup.supportsSVG?"svg":O.setup.supportsCanvas?"canvas":"html");var s=x.getNodeArray(o.images),l=x.getNodeArray(o.bgnodes),h=x.getNodeArray(o.stylenodes),u=x.getNodeArray(o.objects);return n.stylesheets=[],n.svgXMLStylesheet=!0,n.noFontFallback=!!o.noFontFallback,n.noBackgroundSize=!!o.noBackgroundSize,h.forEach(function(e){if(e.attributes.rel&&e.attributes.href&&"stylesheet"==e.attributes.rel.value){var t=e.attributes.href.value,r=x.newEl("a");r.href=t;var i=r.protocol+"//"+r.host+r.pathname+r.search;n.stylesheets.push(i)}}),l.forEach(function(e){if(t.getComputedStyle){var r=t.getComputedStyle(e,null).getPropertyValue("background-image"),s=e.getAttribute("data-background-src"),l=s||r,h=null,u=o.domain+"/",d=l.indexOf(u);if(0===d)h=l;else if(1===d&&"?"===l[0])h=l.slice(1);else{var c=l.substr(d).match(/([^\"]*)"?\)/);if(null!==c)h=c[1];else if(0===l.indexOf("url("))throw"Holder: unable to parse background URL: "+l}if(h){var f=i(h,o);f&&a({mode:"background",el:e,flags:f,engineSettings:n})}}}),u.forEach(function(e){var t={};try{t.data=e.getAttribute("data"),t.dataSrc=e.getAttribute(O.vars.dataAttr)}catch(i){}var a=null!=t.data&&0===t.data.indexOf(o.domain),s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain);a?r(o,n,t.data,e):s&&r(o,n,t.dataSrc,e)}),s.forEach(function(e){var t={};try{t.src=e.getAttribute("src"),t.dataSrc=e.getAttribute(O.vars.dataAttr),t.rendered=e.getAttribute("data-holder-rendered")}catch(i){}var a=null!=t.src,s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain),l=null!=t.rendered&&"true"==t.rendered;a?0===t.src.indexOf(o.domain)?r(o,n,t.src,e):s&&(l?r(o,n,t.dataSrc,e):!function(e,t,n,i,a){w.imageExists(e,function(e){e||r(t,n,i,a)})}(t.src,o,n,t.dataSrc,e)):s&&r(o,n,t.dataSrc,e)}),this}},O={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}},z=function(){var e=null,t=null,n=null;return function(r){var i=r.root;if(O.setup.supportsSVG){var a=!1,o=function(e){return document.createTextNode(e)};(null==e||e.parentNode!==document.body)&&(a=!0),e=b.initSVG(e,i.properties.width,i.properties.height),e.style.display="block",a&&(t=x.newEl("text",F),n=o(null),x.setAttr(t,{x:0}),t.appendChild(n),e.appendChild(t),document.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var s=i.children.holderTextGroup,l=s.properties;x.setAttr(t,{y:l.font.size,style:w.cssProps({"font-weight":l.font.weight,"font-size":l.font.size+l.font.units,"font-family":l.font.family})});var h=x.newEl("textarea");h.innerHTML=l.text,n.nodeValue=h.value;var u=t.getBBox(),d=Math.ceil(u.width/i.properties.width),c=l.text.split(" "),f=l.text.match(/\\n/g);d+=null==f?0:f.length,n.nodeValue=l.text.replace(/[ ]+/g,"");var p=t.getComputedTextLength(),g=u.width-p,m=Math.round(g/Math.max(1,c.length-1)),v=[];if(d>1){n.nodeValue="";for(var y=0;y=0?t:1)}function a(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var o=e.document,s=o.documentElement,l="load",h=!1,u="on"+l,d="complete",c="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in o,b=h,x=h,S=[];if(o[c]===d)i(t);else if(w)o[g](m,n,h),e[g](l,n,h);else{o[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return a.version="1.4.0",a.isReady=function(){return x},a}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,a=n(4),o=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=a(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),t.unshift(n>128?["&#",n,";"].join(""):e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return t.height&&t.width?t:!1},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/,a=e.match(n);if(null!==a)return t=a[1]||a[2],"#"!==t[0]?"#"+t:t;if(a=e.match(r),null!==a)return t="rgb("+a.slice(1).join(",")+")";if(a=e.match(i),null!==a){const o=function(e){return"0."+e.split(".")[1]},s=a.slice(1).map(function(e,t){return 3===t?o(e):e});return t="rgba("+s.join(",")+")"}return null},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",a=8;t.initSVG=function(e,t,n){var o,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(o=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),o.appendChild(s),e.appendChild(o)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+o[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),a=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),a+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){return e.document?null==n?e.document.createElement(t):e.document.createElementNS(n,t):void 0},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){return e.DOMParser?(new DOMParser).parseFromString("","application/xml"):void 0},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return 16>e&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,a=i*(1-Math.abs(parseInt(r)%2-1)),o=n-i/2,s=0,l=0,h=0;return r>=0&&1>r?(s=i,l=a):r>=1&&2>r?(s=a,l=i):r>=2&&3>r?(l=i,h=a):r>=3&&4>r?(l=a,h=i):r>=4&&5>r?(s=a,h=i):r>=5&&6>r&&(s=i,h=a),s+=o,l+=o,h+=o,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,a=-.09991*t-.33609*n+.436*r,o=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:a,v:o},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(0>e?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),a=Math.min(255,Math.max(0,this.rgb.g+r)),o=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,a,o);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,a=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,o=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,a,o))},e.exports=n},function(e,t){e.exports={version:"2.9.7",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return d.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function a(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var o=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,d={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),c="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+c+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,a=d.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(a)})});var v=d.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=d.element({tag:"path",d:a(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=d.element({tag:"g",id:c,content:x}),A=d.element({tag:"style",content:g,type:"text/css"}),C=d.element({tag:"defs",content:A}),E=d.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),T=o(E);/\&(x)?#[0-9A-Fa-f]/.test(T[0])&&(T[0]=T[0].replace(/&#/gm,"&#")),T=h+T[0];var k=s.svgStringToDataURI(T,"background"===t.mode);return k}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^[\w-]+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),a=e.match(/\$([\w-]+)/),o=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),a&&(n[a[1]]=r),o&&(r.attr["class"]=o.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function a(e,t){return null!==t&&t!==!1&&void 0!==t?"string"!=typeof t&&"object"!=typeof t?String(t):t:void 0}function o(e){return e||0===e?String(e).replace(/&/g,"&").replace(/"/g,"""):""}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,d,c=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));c=0}for(;c",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){"use strict";function n(e){var t=""+e,n=r.exec(t);if(!n)return t;var i,a="",o=0,s=0;for(o=n.index;o]/;e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),a=n.root;e.width=r*a.properties.width,e.height=r*a.properties.height,t.textBaseline="middle";var o=a.children.holderBg,s=r*o.width,l=r*o.height,h=2,u=h/2;t.fillStyle=o.properties.fill,t.fillRect(0,0,s,l),o.properties.outline&&(t.strokeStyle=o.properties.outline.fill,t.lineWidth=o.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var d=a.children.holderTextGroup;t.font=d.properties.font.weight+" "+r*d.properties.font.size+d.properties.font.units+" "+d.properties.font.family+", monospace",t.fillStyle=d.properties.fill;for(var c in d.children){var f=d.children[c];for(var p in f.children){var g=f.children[p],m=r*(d.x+f.x+g.x),v=r*(d.y+f.y+g.y+d.properties.leading/2); + +t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); \ No newline at end of file diff --git a/文件下载/holder-v2.9.8.zip b/文件下载/holder-v2.9.8.zip new file mode 100644 index 0000000..4388b49 Binary files /dev/null and b/文件下载/holder-v2.9.8.zip differ diff --git a/静态站点/Bootstrap4/plugs/holder/holder.js b/静态站点/Bootstrap4/plugs/holder/holder.js new file mode 100644 index 0000000..db1e43b --- /dev/null +++ b/静态站点/Bootstrap4/plugs/holder/holder.js @@ -0,0 +1,3063 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://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-2020 Ivan Malopinsky - https://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-2020 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; + + // SVG embedding doesn't parse Unicode properly + if (el.nodeName.toLowerCase() === 'object') { + var textLines = theme.text.split('\\n'); + for (var k = 0; k < textLines.length; k++) { + textLines[k] = utils.encodeHtmlEntity(textLines[k]); + } + theme.text = textLines.join('\\n'); + } + } + + if (theme.text) { + var holderTemplateMatches = theme.text.match(holderTemplateRe); + + if (holderTemplateMatches !== null) { + //todo: optimize template replacement + holderTemplateMatches.forEach(function (match) { + if (match === 'holder_dimensions') { + theme.text = theme.text.replace(match, dimensionsCaption); + } + }); + } + } + + var holderURL = flags.holderURL; + var engineSettings = extend(_engineSettings, null); + + if (flags.font) { + /* + If external fonts are used in a placeholder rendered with SVG, Holder falls back to canvas. + + This is done because Firefox and Chrome disallow embedded SVGs from referencing external assets. + The workaround is either to change the placeholder tag from to or to use the canvas renderer. + */ + theme.font = flags.font; + if (!engineSettings.noFontFallback && el.nodeName.toLowerCase() === 'img' && App.setup.supportsCanvas && engineSettings.renderer === 'svg') { + engineSettings = extend(engineSettings, { + renderer: 'canvas' + }); + } + } + + //Chrome and Opera require a quick 10ms re-render if web fonts are used with canvas + if (flags.font && engineSettings.renderer == 'canvas') { + engineSettings.reRender = true; + } + + if (mode == 'background') { + if (el.getAttribute('data-background-src') == null) { + DOM.setAttr(el, { + 'data-background-src': holderURL + }); + } + } else { + var domProps = {}; + domProps[App.vars.dataAttr] = holderURL; + DOM.setAttr(el, domProps); + } + + flags.theme = theme; + + //todo consider using all renderSettings in holderData + el.holderData = { + flags: flags, + engineSettings: engineSettings + }; + + if (mode == 'image' || mode == 'fluid') { + DOM.setAttr(el, { + 'alt': theme.text ? (dimensionsInText ? theme.text : theme.text + ' [' + dimensionsCaption + ']') : dimensionsCaption + }); + } + + var renderSettings = { + mode: mode, + el: el, + holderSettings: { + dimensions: dimensions, + theme: theme, + flags: flags + }, + engineSettings: engineSettings + }; + + if (mode == 'image') { + if (!flags.auto) { + el.style.width = dimensions.width + 'px'; + el.style.height = dimensions.height + 'px'; + } + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + render(renderSettings); + + if (flags.textmode == 'exact') { + el.holderData.resizeUpdate = true; + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } else if (mode == 'background' && engineSettings.renderer != 'html') { + render(renderSettings); + } else if (mode == 'fluid') { + el.holderData.resizeUpdate = true; + + if (dimensions.height.slice(-1) == '%') { + el.style.height = dimensions.height; + } else if (flags.auto == null || !flags.auto) { + el.style.height = dimensions.height + 'px'; + } + if (dimensions.width.slice(-1) == '%') { + el.style.width = dimensions.width; + } else if (flags.auto == null || !flags.auto) { + el.style.width = dimensions.width + 'px'; + } + if (el.style.display == 'inline' || el.style.display === '' || el.style.display == 'none') { + el.style.display = 'block'; + } + + setInitialDimensions(el); + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } + + /** + * Core function that takes output from renderers and sets it as the source or background-image of the target element + * + * @private + * @param renderSettings Renderer settings + */ + function render(renderSettings) { + var image = null; + var mode = renderSettings.mode; + var el = renderSettings.el; + var holderSettings = renderSettings.holderSettings; + var engineSettings = renderSettings.engineSettings; + + switch (engineSettings.renderer) { + case 'svg': + if (!App.setup.supportsSVG) return; + break; + case 'canvas': + if (!App.setup.supportsCanvas) return; + break; + default: + return; + } + + //todo: move generation of scene up to flag generation to reduce extra object creation + var scene = { + width: holderSettings.dimensions.width, + height: holderSettings.dimensions.height, + theme: holderSettings.theme, + flags: holderSettings.flags + }; + + var sceneGraph = buildSceneGraph(scene); + + function getRenderedImage() { + var image = null; + switch (engineSettings.renderer) { + case 'canvas': + image = sgCanvasRenderer(sceneGraph, renderSettings); + break; + case 'svg': + image = svgRenderer(sceneGraph, renderSettings); + break; + default: + throw 'Holder: invalid renderer: ' + engineSettings.renderer; + } + + return image; + } + + image = getRenderedImage(); + + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + + //todo: add canvas rendering + if (mode == 'background') { + el.style.backgroundImage = 'url(' + image + ')'; + + if (!engineSettings.noBackgroundSize) { + el.style.backgroundSize = scene.width + 'px ' + scene.height + 'px'; + } + } else { + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + if (engineSettings.reRender) { + global.setTimeout(function () { + var image = getRenderedImage(); + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + //todo: refactor this code into a function + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + }, 150); + } + } + //todo: account for re-rendering + DOM.setAttr(el, { + 'data-holder-rendered': true + }); + } + + /** + * Core function that takes a Holder scene description and builds a scene graph + * + * @private + * @param scene Holder scene object + */ + //todo: make this function reusable + //todo: merge app defaults and setup properties into the scene argument + function buildSceneGraph(scene) { + var fontSize = App.defaults.size; + if (parseFloat(scene.theme.size)) { + fontSize = scene.theme.size; + } else if (parseFloat(scene.flags.size)) { + fontSize = scene.flags.size; + } + + scene.font = { + family: scene.theme.font ? scene.theme.font : 'Arial, Helvetica, Open Sans, sans-serif', + size: textSize(scene.width, scene.height, fontSize, App.defaults.scale), + units: scene.theme.units ? scene.theme.units : App.defaults.units, + weight: scene.theme.fontweight ? scene.theme.fontweight : 'bold' + }; + + scene.text = scene.theme.text || Math.floor(scene.width) + 'x' + Math.floor(scene.height); + + scene.noWrap = scene.theme.nowrap || scene.flags.nowrap; + + scene.align = scene.theme.align || scene.flags.align || 'center'; + + switch (scene.flags.textmode) { + case 'literal': + scene.text = scene.flags.dimensions.width + 'x' + scene.flags.dimensions.height; + break; + case 'exact': + if (!scene.flags.exactDimensions) break; + scene.text = Math.floor(scene.flags.exactDimensions.width) + 'x' + Math.floor(scene.flags.exactDimensions.height); + break; + } + + var lineWrap = scene.flags.lineWrap || App.setup.lineWrapRatio; + var sceneMargin = scene.width * lineWrap; + var maxLineWidth = sceneMargin; + + var sceneGraph = new SceneGraph({ + width: scene.width, + height: scene.height + }); + + var Shape = sceneGraph.Shape; + + var holderBg = new Shape.Rect('holderBg', { + fill: scene.theme.bg + }); + + holderBg.resize(scene.width, scene.height); + sceneGraph.root.add(holderBg); + + if (scene.flags.outline) { + var outlineColor = new Color(holderBg.properties.fill); + outlineColor = outlineColor.lighten(outlineColor.lighterThan('7f7f7f') ? -0.1 : 0.1); + holderBg.properties.outline = { + fill: outlineColor.toHex(true), + width: 2 + }; + } + + var holderTextColor = scene.theme.fg; + + if (scene.flags.autoFg) { + var holderBgColor = new Color(holderBg.properties.fill); + var lightColor = new Color('fff'); + var darkColor = new Color('000', { + 'alpha': 0.285714 + }); + + holderTextColor = holderBgColor.blendAlpha(holderBgColor.lighterThan('7f7f7f') ? darkColor : lightColor).toHex(true); + } + + var holderTextGroup = new Shape.Group('holderTextGroup', { + text: scene.text, + align: scene.align, + font: scene.font, + fill: holderTextColor + }); + + holderTextGroup.moveTo(null, null, 1); + sceneGraph.root.add(holderTextGroup); + + var tpdata = holderTextGroup.textPositionData = stagingRenderer(sceneGraph); + if (!tpdata) { + throw 'Holder: staging fallback not supported yet.'; + } + holderTextGroup.properties.leading = tpdata.boundingBox.height; + + var textNode = null; + var line = null; + + function finalizeLine(parent, line, width, height) { + line.width = width; + line.height = height; + parent.width = Math.max(parent.width, line.width); + parent.height += line.height; + } + + if (tpdata.lineCount > 1) { + var offsetX = 0; + var offsetY = 0; + var lineIndex = 0; + var lineKey; + line = new Shape.Group('line' + lineIndex); + + //Double margin so that left/right-aligned next is not flush with edge of image + if (scene.align === 'left' || scene.align === 'right') { + maxLineWidth = scene.width * (1 - (1 - lineWrap) * 2); + } + + for (var i = 0; i < tpdata.words.length; i++) { + var word = tpdata.words[i]; + textNode = new Shape.Text(word.text); + var newline = word.text == '\\n'; + if (!scene.noWrap && (offsetX + word.width >= maxLineWidth || newline === true)) { + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + offsetX = 0; + offsetY += holderTextGroup.properties.leading; + lineIndex += 1; + line = new Shape.Group('line' + lineIndex); + line.y = offsetY; + } + if (newline === true) { + continue; + } + textNode.moveTo(offsetX, 0); + offsetX += tpdata.spaceWidth + word.width; + line.add(textNode); + } + + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo(scene.width - line.width, null, null); + } + + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo((holderTextGroup.width - line.width) / 2, null, null); + } + + holderTextGroup.moveTo((scene.width - holderTextGroup.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - holderTextGroup.height) / 2, null); + + //If the text exceeds vertical space, move it down so the first line is visible + if ((scene.height - holderTextGroup.height) / 2 < 0) { + holderTextGroup.moveTo(null, 0, null); + } + } else { + textNode = new Shape.Text(scene.text); + line = new Shape.Group('line0'); + line.add(textNode); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + holderTextGroup.moveTo((scene.width - tpdata.boundingBox.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - tpdata.boundingBox.height) / 2, null); + } + + //todo: renderlist + return sceneGraph; + } + + /** + * Adaptive text sizing function + * + * @private + * @param width Parent width + * @param height Parent height + * @param fontSize Requested text size + * @param scale Proportional scale of text + */ + function textSize(width, height, fontSize, scale) { + var stageWidth = parseInt(width, 10); + var stageHeight = parseInt(height, 10); + + var bigSide = Math.max(stageWidth, stageHeight); + var smallSide = Math.min(stageWidth, stageHeight); + + var newHeight = 0.8 * Math.min(smallSide, bigSide * scale); + return Math.round(Math.max(fontSize, newHeight)); + } + + /** + * Iterates over resizable (fluid or auto) placeholders and renders them + * + * @private + * @param element Optional element selector, specified only if a specific element needs to be re-rendered + */ + function updateResizableElements(element) { + var images; + if (element == null || element.nodeType == null) { + images = App.vars.resizableImages; + } else { + images = [element]; + } + for (var i = 0, l = images.length; i < l; i++) { + var el = images[i]; + if (el.holderData) { + var flags = el.holderData.flags; + var dimensions = dimensionCheck(el); + if (dimensions) { + if (!el.holderData.resizeUpdate) { + continue; + } + + if (flags.fluid && flags.auto) { + var fluidConfig = el.holderData.fluidConfig; + switch (fluidConfig.mode) { + case 'width': + dimensions.height = dimensions.width / fluidConfig.ratio; + break; + case 'height': + dimensions.width = dimensions.height * fluidConfig.ratio; + break; + } + } + + var settings = { + mode: 'image', + holderSettings: { + dimensions: dimensions, + theme: flags.theme, + flags: flags + }, + el: el, + engineSettings: el.holderData.engineSettings + }; + + if (flags.textmode == 'exact') { + flags.exactDimensions = dimensions; + settings.holderSettings.dimensions = flags.dimensions; + } + + render(settings); + } else { + setInvisible(el); + } + } + } + } + + /** + * Sets up aspect ratio metadata for fluid placeholders, in order to preserve proportions when resizing + * + * @private + * @param el Image DOM element + */ + function setInitialDimensions(el) { + if (el.holderData) { + var dimensions = dimensionCheck(el); + if (dimensions) { + var flags = el.holderData.flags; + + var fluidConfig = { + fluidHeight: flags.dimensions.height.slice(-1) == '%', + fluidWidth: flags.dimensions.width.slice(-1) == '%', + mode: null, + initialDimensions: dimensions + }; + + if (fluidConfig.fluidWidth && !fluidConfig.fluidHeight) { + fluidConfig.mode = 'width'; + fluidConfig.ratio = fluidConfig.initialDimensions.width / parseFloat(flags.dimensions.height); + } else if (!fluidConfig.fluidWidth && fluidConfig.fluidHeight) { + fluidConfig.mode = 'height'; + fluidConfig.ratio = parseFloat(flags.dimensions.width) / fluidConfig.initialDimensions.height; + } + + el.holderData.fluidConfig = fluidConfig; + } else { + setInvisible(el); + } + } + } + + /** + * Iterates through all current invisible images, and if they're visible, renders them and removes them from further checks. Runs every animation frame. + * + * @private + */ + function visibilityCheck() { + var renderableImages = []; + var keys = Object.keys(App.vars.invisibleImages); + var el; + + keys.forEach(function (key) { + el = App.vars.invisibleImages[key]; + if (dimensionCheck(el) && el.nodeName.toLowerCase() == 'img') { + renderableImages.push(el); + delete App.vars.invisibleImages[key]; + } + }); + + if (renderableImages.length) { + Holder.run({ + images: renderableImages + }); + } + + // Done to prevent 100% CPU usage via aggressive calling of requestAnimationFrame + setTimeout(function () { + global.requestAnimationFrame(visibilityCheck); + }, 10); + } + + /** + * Starts checking for invisible placeholders if not doing so yet. Does nothing otherwise. + * + * @private + */ + function startVisibilityCheck() { + if (!App.vars.visibilityCheckStarted) { + global.requestAnimationFrame(visibilityCheck); + App.vars.visibilityCheckStarted = true; + } + } + + /** + * Sets a unique ID for an image detected to be invisible and adds it to the map of invisible images checked by visibilityCheck + * + * @private + * @param el Invisible DOM element + */ + function setInvisible(el) { + if (!el.holderData.invisibleId) { + App.vars.invisibleId += 1; + App.vars.invisibleImages['i' + App.vars.invisibleId] = el; + el.holderData.invisibleId = App.vars.invisibleId; + } + } + + //todo: see if possible to convert stagingRenderer to use HTML only + var stagingRenderer = (function() { + var svg = null, + stagingText = null, + stagingTextNode = null; + return function(graph) { + var rootNode = graph.root; + if (App.setup.supportsSVG) { + var firstTimeSetup = false; + var tnode = function(text) { + return document.createTextNode(text); + }; + if (svg == null || svg.parentNode !== document.body) { + firstTimeSetup = true; + } + + svg = SVG.initSVG(svg, rootNode.properties.width, rootNode.properties.height); + //Show staging element before staging + svg.style.display = 'block'; + + if (firstTimeSetup) { + stagingText = DOM.newEl('text', SVG_NS); + stagingTextNode = tnode(null); + DOM.setAttr(stagingText, { + x: 0 + }); + stagingText.appendChild(stagingTextNode); + svg.appendChild(stagingText); + document.body.appendChild(svg); + svg.style.visibility = 'hidden'; + svg.style.position = 'absolute'; + svg.style.top = '-100%'; + svg.style.left = '-100%'; + //todo: workaround for zero-dimension tag in Opera 12 + //svg.setAttribute('width', 0); + //svg.setAttribute('height', 0); + } + + var holderTextGroup = rootNode.children.holderTextGroup; + var htgProps = holderTextGroup.properties; + DOM.setAttr(stagingText, { + 'y': htgProps.font.size, + 'style': utils.cssProps({ + 'font-weight': htgProps.font.weight, + 'font-size': htgProps.font.size + htgProps.font.units, + 'font-family': htgProps.font.family + }) + }); + + //Unescape HTML entities to get approximately the right width + var txt = DOM.newEl('textarea'); + txt.innerHTML = htgProps.text; + stagingTextNode.nodeValue = txt.value; + + //Get bounding box for the whole string (total width and height) + var stagingTextBBox = stagingText.getBBox(); + + //Get line count and split the string into words + var lineCount = Math.ceil(stagingTextBBox.width / rootNode.properties.width); + var words = htgProps.text.split(' '); + var newlines = htgProps.text.match(/\\n/g); + lineCount += newlines == null ? 0 : newlines.length; + + //Get bounding box for the string with spaces removed + stagingTextNode.nodeValue = htgProps.text.replace(/[ ]+/g, ''); + var computedNoSpaceLength = stagingText.getComputedTextLength(); + + //Compute average space width + var diffLength = stagingTextBBox.width - computedNoSpaceLength; + var spaceWidth = Math.round(diffLength / Math.max(1, words.length - 1)); + + //Get widths for every word with space only if there is more than one line + var wordWidths = []; + if (lineCount > 1) { + stagingTextNode.nodeValue = ''; + for (var i = 0; i < words.length; i++) { + if (words[i].length === 0) continue; + stagingTextNode.nodeValue = utils.decodeHtmlEntity(words[i]); + var bbox = stagingText.getBBox(); + wordWidths.push({ + text: words[i], + width: bbox.width + }); + } + } + + //Hide staging element after staging + svg.style.display = 'none'; + + return { + spaceWidth: spaceWidth, + lineCount: lineCount, + boundingBox: stagingTextBBox, + words: wordWidths + }; + } else { + //todo: canvas fallback for measuring text on android 2.3 + return false; + } + }; + })(); + + //Helpers + + /** + * Prevents a function from being called too often, waits until a timer elapses to call it again + * + * @param fn Function to call + */ + function debounce(fn) { + if (!App.vars.debounceTimer) fn.call(this); + if (App.vars.debounceTimer) global.clearTimeout(App.vars.debounceTimer); + App.vars.debounceTimer = global.setTimeout(function() { + App.vars.debounceTimer = null; + fn.call(this); + }, App.setup.debounce); + } + + /** + * Holder-specific resize/orientation change callback, debounced to prevent excessive execution + */ + function resizeEvent() { + debounce(function() { + updateResizableElements(null); + }); + } + + //Set up flags + + for (var flag in App.flags) { + if (!App.flags.hasOwnProperty(flag)) continue; + App.flags[flag].match = function(val) { + return val.match(this.regex); + }; + } + + //Properties set once on setup + + App.setup = { + renderer: 'html', + debounce: 100, + ratio: 1, + supportsCanvas: false, + supportsSVG: false, + lineWrapRatio: 0.9, + dataAttr: 'data-src', + renderers: ['html', 'canvas', 'svg'] + }; + + //Properties modified during runtime + + App.vars = { + preempted: false, + resizableImages: [], + invisibleImages: {}, + invisibleId: 0, + visibilityCheckStarted: false, + debounceTimer: null, + cache: {} + }; + + //Pre-flight + + (function() { + var canvas = DOM.newEl('canvas'); + + if (canvas.getContext) { + if (canvas.toDataURL('image/png').indexOf('data:image/png') != -1) { + App.setup.renderer = 'canvas'; + App.setup.supportsCanvas = true; + } + } + + if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) { + App.setup.renderer = 'svg'; + App.setup.supportsSVG = true; + } + })(); + + //Starts checking for invisible placeholders + startVisibilityCheck(); + + if (onDomReady) { + onDomReady(function() { + if (!App.vars.preempted) { + Holder.run(); + } + if (global.addEventListener) { + global.addEventListener('resize', resizeEvent, false); + global.addEventListener('orientationchange', resizeEvent, false); + } else { + global.attachEvent('onresize', resizeEvent); + } + + if (typeof global.Turbolinks == 'object') { + global.document.addEventListener('page:change', function() { + Holder.run(); + }); + } + }); + } + + module.exports = Holder; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + + /*! + * onDomReady.js 1.4.0 (c) 2013 Tubal Martin - MIT license + * + * Specially modified to work with Holder.js + */ + + function _onDomReady(win) { + //Lazy loading fix for Firefox < 3.6 + //http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + if (document.readyState == null && document.addEventListener) { + document.addEventListener("DOMContentLoaded", function DOMContentLoaded() { + document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); + document.readyState = "complete"; + }, false); + document.readyState = "loading"; + } + + var doc = win.document, + docElem = doc.documentElement, + + LOAD = "load", + FALSE = false, + ONLOAD = "on"+LOAD, + COMPLETE = "complete", + READYSTATE = "readyState", + ATTACHEVENT = "attachEvent", + DETACHEVENT = "detachEvent", + ADDEVENTLISTENER = "addEventListener", + DOMCONTENTLOADED = "DOMContentLoaded", + ONREADYSTATECHANGE = "onreadystatechange", + REMOVEEVENTLISTENER = "removeEventListener", + + // W3C Event model + w3c = ADDEVENTLISTENER in doc, + _top = FALSE, + + // isReady: Is the DOM ready to be used? Set to true once it occurs. + isReady = FALSE, + + // Callbacks pending execution until DOM is ready + callbacks = []; + + // Handle when the DOM is ready + function ready( fn ) { + if ( !isReady ) { + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !doc.body ) { + return defer( ready ); + } + + // Remember that the DOM is ready + isReady = true; + + // Execute all callbacks + while ( fn = callbacks.shift() ) { + defer( fn ); + } + } + } + + // The ready event handler + function completed( event ) { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( w3c || event.type === LOAD || doc[READYSTATE] === COMPLETE ) { + detach(); + ready(); + } + } + + // Clean-up method for dom ready events + function detach() { + if ( w3c ) { + doc[REMOVEEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + win[REMOVEEVENTLISTENER]( LOAD, completed, FALSE ); + } else { + doc[DETACHEVENT]( ONREADYSTATECHANGE, completed ); + win[DETACHEVENT]( ONLOAD, completed ); + } + } + + // Defers a function, scheduling it to run after the current call stack has cleared. + function defer( fn, wait ) { + // Allow 0 to be passed + setTimeout( fn, +wait >= 0 ? wait : 1 ); + } + + // Attach the listeners: + + // Catch cases where onDomReady is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( doc[READYSTATE] === COMPLETE ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + defer( ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( w3c ) { + // Use the handy event callback + doc[ADDEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + + // A fallback to window.onload, that will always work + win[ADDEVENTLISTENER]( LOAD, completed, FALSE ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + doc[ATTACHEVENT]( ONREADYSTATECHANGE, completed ); + + // A fallback to window.onload, that will always work + win[ATTACHEVENT]( ONLOAD, completed ); + + // If IE and not a frame + // continually check to see if the document is ready + try { + _top = win.frameElement == null && docElem; + } catch(e) {} + + if ( _top && _top.doScroll ) { + (function doScrollCheck() { + if ( !isReady ) { + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + _top.doScroll("left"); + } catch(e) { + return defer( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + ready(); + } + })(); + } + } + + function onDomReady( fn ) { + // If DOM is ready, execute the function (async), otherwise wait + isReady ? defer( fn ) : callbacks.push( fn ); + } + + // Add version + onDomReady.version = "1.4.0"; + // Add method to check if DOM is ready + onDomReady.isReady = function(){ + return isReady; + }; + + return onDomReady; + } + + module.exports = typeof window !== "undefined" && _onDomReady(window); + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + //Modified version of component/querystring + //Changes: updated dependencies, dot notation parsing, JSHint fixes + //Fork at https://github.com/imsky/querystring + + /** + * Module dependencies. + */ + + var encode = encodeURIComponent; + var decode = decodeURIComponent; + var trim = __webpack_require__(4); + var type = __webpack_require__(5); + + var arrayRegex = /(\w+)\[(\d+)\]/; + var objectRegex = /\w+\.\w+/; + + /** + * Parse the given query `str`. + * + * @param {String} str + * @return {Object} + * @api public + */ + + exports.parse = function(str){ + if ('string' !== typeof str) return {}; + + str = trim(str); + if ('' === str) return {}; + if ('?' === str.charAt(0)) str = str.slice(1); + + var obj = {}; + var pairs = str.split('&'); + for (var i = 0; i < pairs.length; i++) { + var parts = pairs[i].split('='); + var key = decode(parts[0]); + var m, ctx, prop; + + if (m = arrayRegex.exec(key)) { + obj[m[1]] = obj[m[1]] || []; + obj[m[1]][m[2]] = decode(parts[1]); + continue; + } + + if (m = objectRegex.test(key)) { + m = key.split('.'); + ctx = obj; + + while (m.length) { + prop = m.shift(); + + if (!prop.length) continue; + + if (!ctx[prop]) { + ctx[prop] = {}; + } else if (ctx[prop] && typeof ctx[prop] !== 'object') { + break; + } + + if (!m.length) { + ctx[prop] = decode(parts[1]); + } + + ctx = ctx[prop]; + } + + continue; + } + + obj[parts[0]] = null == parts[1] ? '' : decode(parts[1]); + } + + return obj; + }; + + /** + * Stringify the given `obj`. + * + * @param {Object} obj + * @return {String} + * @api public + */ + + exports.stringify = function(obj){ + if (!obj) return ''; + var pairs = []; + + for (var key in obj) { + var value = obj[key]; + + if ('array' == type(value)) { + for (var i = 0; i < value.length; ++i) { + pairs.push(encode(key + '[' + i + ']') + '=' + encode(value[i])); + } + continue; + } + + pairs.push(encode(key) + '=' + encode(obj[key])); + } + + return pairs.join('&'); + }; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + + exports = module.exports = trim; + + function trim(str){ + return str.replace(/^\s*|\s*$/g, ''); + } + + exports.left = function(str){ + return str.replace(/^\s*/, ''); + }; + + exports.right = function(str){ + return str.replace(/\s*$/, ''); + }; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + /** + * toString ref. + */ + + var toString = Object.prototype.toString; + + /** + * Return the type of `val`. + * + * @param {Mixed} val + * @return {String} + * @api public + */ + + module.exports = function(val){ + switch (toString.call(val)) { + case '[object Date]': return 'date'; + case '[object RegExp]': return 'regexp'; + case '[object Arguments]': return 'arguments'; + case '[object Array]': return 'array'; + case '[object Error]': return 'error'; + } + + if (val === null) return 'null'; + if (val === undefined) return 'undefined'; + if (val !== val) return 'nan'; + if (val && val.nodeType === 1) return 'element'; + + val = val.valueOf + ? val.valueOf() + : Object.prototype.valueOf.apply(val) + + return typeof val; + }; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports) { + + var SceneGraph = function(sceneProperties) { + var nodeCount = 1; + + //todo: move merge to helpers section + function merge(parent, child) { + for (var prop in child) { + parent[prop] = child[prop]; + } + return parent; + } + + var SceneNode = function(name) { + nodeCount++; + this.parent = null; + this.children = {}; + this.id = nodeCount; + this.name = 'n' + nodeCount; + if (typeof name !== 'undefined') { + this.name = name; + } + this.x = this.y = this.z = 0; + this.width = this.height = 0; + }; + + SceneNode.prototype.resize = function(width, height) { + if (width != null) { + this.width = width; + } + if (height != null) { + this.height = height; + } + }; + + SceneNode.prototype.moveTo = function(x, y, z) { + this.x = x != null ? x : this.x; + this.y = y != null ? y : this.y; + this.z = z != null ? z : this.z; + }; + + SceneNode.prototype.add = function(child) { + var name = child.name; + if (typeof this.children[name] === 'undefined') { + this.children[name] = child; + child.parent = this; + } else { + throw 'SceneGraph: child already exists: ' + name; + } + }; + + var RootNode = function() { + SceneNode.call(this, 'root'); + this.properties = sceneProperties; + }; + + RootNode.prototype = new SceneNode(); + + var Shape = function(name, props) { + SceneNode.call(this, name); + this.properties = { + 'fill': '#000000' + }; + if (typeof props !== 'undefined') { + merge(this.properties, props); + } else if (typeof name !== 'undefined' && typeof name !== 'string') { + throw 'SceneGraph: invalid node name'; + } + }; + + Shape.prototype = new SceneNode(); + + var Group = function() { + Shape.apply(this, arguments); + this.type = 'group'; + }; + + Group.prototype = new Shape(); + + var Rect = function() { + Shape.apply(this, arguments); + this.type = 'rect'; + }; + + Rect.prototype = new Shape(); + + var Text = function(text) { + Shape.call(this); + this.type = 'text'; + this.properties.text = text; + }; + + Text.prototype = new Shape(); + + var root = new RootNode(); + + this.Shape = { + 'Rect': Rect, + 'Text': Text, + 'Group': Group + }; + + this.root = root; + return this; + }; + + module.exports = SceneGraph; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Shallow object clone and merge + * + * @param a Object A + * @param b Object B + * @returns {Object} New object with all of A's properties, and all of B's properties, overwriting A's properties + */ + exports.extend = function(a, b) { + var c = {}; + for (var x in a) { + if (a.hasOwnProperty(x)) { + c[x] = a[x]; + } + } + if (b != null) { + for (var y in b) { + if (b.hasOwnProperty(y)) { + c[y] = b[y]; + } + } + } + return c; + }; + + /** + * Takes a k/v list of CSS properties and returns a rule + * + * @param props CSS properties object + */ + exports.cssProps = function(props) { + var ret = []; + for (var p in props) { + if (props.hasOwnProperty(p)) { + ret.push(p + ':' + props[p]); + } + } + return ret.join(';'); + }; + + /** + * Encodes HTML entities in a string + * + * @param str Input string + */ + exports.encodeHtmlEntity = function(str) { + var buf = []; + var charCode = 0; + for (var i = str.length - 1; i >= 0; i--) { + charCode = str.charCodeAt(i); + if (charCode > 128) { + buf.unshift(['&#', charCode, ';'].join('')); + } else { + buf.unshift(str[i]); + } + } + return buf.join(''); + }; + + /** + * Checks if an image exists + * + * @param src URL of image + * @param callback Callback to call once image status has been found + */ + exports.imageExists = function(src, callback) { + var image = new Image(); + image.onerror = function() { + callback.call(this, false); + }; + image.onload = function() { + callback.call(this, true); + }; + image.src = src; + }; + + /** + * Decodes HTML entities in a string + * + * @param str Input string + */ + exports.decodeHtmlEntity = function(str) { + return str.replace(/&#(\d+);/g, function(match, dec) { + return String.fromCharCode(dec); + }); + }; + + + /** + * Returns an element's dimensions if it's visible, `false` otherwise. + * + * @param el DOM element + */ + exports.dimensionCheck = function(el) { + var dimensions = { + height: el.clientHeight, + width: el.clientWidth + }; + + if (dimensions.height && dimensions.width) { + return dimensions; + } else { + return false; + } + }; + + + /** + * Returns true if value is truthy or if it is "semantically truthy" + * @param val + */ + exports.truthy = function(val) { + if (typeof val === 'string') { + return val === 'true' || val === 'yes' || val === '1' || val === 'on' || val === '✓'; + } + return !!val; + }; + + /** + * Parses input into a well-formed CSS color + * @param val + */ + exports.parseColor = function(val) { + var hexre = /(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i; + var rgbre = /^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/; + var rgbare = /^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/; + + var match = val.match(hexre); + var retval; + + if (match !== null) { + retval = match[1] || match[2]; + if (retval[0] !== '#') { + return '#' + retval; + } else { + return retval; + } + } + + match = val.match(rgbre); + + if (match !== null) { + retval = 'rgb(' + match.slice(1).join(',') + ')'; + return retval; + } + + match = val.match(rgbare); + + if (match !== null) { + const normalizeAlpha = function (a) { return '0.' + a.split('.')[1]; }; + const fixedMatch = match.slice(1).map(function (e, i) { + return (i === 3) ? normalizeAlpha(e) : e; + }); + retval = 'rgba(' + fixedMatch.join(',') + ')'; + return retval; + } + + return null; + }; + + /** + * Provides the correct scaling ratio for canvas drawing operations on HiDPI screens (e.g. Retina displays) + */ + exports.canvasRatio = function () { + var devicePixelRatio = 1; + var backingStoreRatio = 1; + + if (global.document) { + var canvas = global.document.createElement('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + devicePixelRatio = global.devicePixelRatio || 1; + backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; + } + } + + return devicePixelRatio / backingStoreRatio; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {var DOM = __webpack_require__(9); + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var NODE_TYPE_COMMENT = 8; + + /** + * Generic SVG element creation function + * + * @param svg SVG context, set to null if new + * @param width Document width + * @param height Document height + */ + exports.initSVG = function(svg, width, height) { + var defs, style, initialize = false; + + if (svg && svg.querySelector) { + style = svg.querySelector('style'); + if (style === null) { + initialize = true; + } + } else { + svg = DOM.newEl('svg', SVG_NS); + initialize = true; + } + + if (initialize) { + defs = DOM.newEl('defs', SVG_NS); + style = DOM.newEl('style', SVG_NS); + DOM.setAttr(style, { + 'type': 'text/css' + }); + defs.appendChild(style); + svg.appendChild(defs); + } + + //IE throws an exception if this is set and Chrome requires it to be set + if (svg.webkitMatchesSelector) { + svg.setAttribute('xmlns', SVG_NS); + } + + //Remove comment nodes + for (var i = 0; i < svg.childNodes.length; i++) { + if (svg.childNodes[i].nodeType === NODE_TYPE_COMMENT) { + svg.removeChild(svg.childNodes[i]); + } + } + + //Remove CSS + while (style.childNodes.length) { + style.removeChild(style.childNodes[0]); + } + + DOM.setAttr(svg, { + 'width': width, + 'height': height, + 'viewBox': '0 0 ' + width + ' ' + height, + 'preserveAspectRatio': 'none' + }); + + return svg; + }; + + /** + * Converts serialized SVG to a string suitable for data URI use + * @param svgString Serialized SVG string + * @param [base64] Use base64 encoding for data URI + */ + exports.svgStringToDataURI = function() { + var rawPrefix = 'data:image/svg+xml;charset=UTF-8,'; + var base64Prefix = 'data:image/svg+xml;charset=UTF-8;base64,'; + + return function(svgString, base64) { + if (base64) { + return base64Prefix + btoa(global.unescape(encodeURIComponent(svgString))); + } else { + return rawPrefix + encodeURIComponent(svgString); + } + }; + }(); + + /** + * Returns serialized SVG with XML processing instructions + * + * @param svg SVG context + * @param stylesheets CSS stylesheets to include + */ + exports.serializeSVG = function(svg, engineSettings) { + if (!global.XMLSerializer) return; + var serializer = new XMLSerializer(); + var svgCSS = ''; + var stylesheets = engineSettings.stylesheets; + + //External stylesheets: Processing Instruction method + if (engineSettings.svgXMLStylesheet) { + var xml = DOM.createXML(); + //Add directives + for (var i = stylesheets.length - 1; i >= 0; i--) { + var csspi = xml.createProcessingInstruction('xml-stylesheet', 'href="' + stylesheets[i] + '" rel="stylesheet"'); + xml.insertBefore(csspi, xml.firstChild); + } + + xml.removeChild(xml.documentElement); + svgCSS = serializer.serializeToString(xml); + } + + var svgText = serializer.serializeToString(svg); + svgText = svgText.replace(/\&(\#[0-9]{2,}\;)/g, '&$1'); + return svgCSS + svgText; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Generic new DOM element function + * + * @param tag Tag to create + * @param namespace Optional namespace value + */ + exports.newEl = function(tag, namespace) { + if (!global.document) return; + + if (namespace == null) { + return global.document.createElement(tag); + } else { + return global.document.createElementNS(namespace, tag); + } + }; + + /** + * Generic setAttribute function + * + * @param el Reference to DOM element + * @param attrs Object with attribute keys and values + */ + exports.setAttr = function (el, attrs) { + for (var a in attrs) { + el.setAttribute(a, attrs[a]); + } + }; + + /** + * Creates a XML document + * @private + */ + exports.createXML = function() { + if (!global.DOMParser) return; + return new DOMParser().parseFromString('', 'application/xml'); + }; + + /** + * Converts a value into an array of DOM nodes + * + * @param val A string, a NodeList, a Node, or an HTMLCollection + */ + exports.getNodeArray = function(val) { + var retval = null; + if (typeof(val) == 'string') { + retval = document.querySelectorAll(val); + } else if (global.NodeList && val instanceof global.NodeList) { + retval = val; + } else if (global.Node && val instanceof global.Node) { + retval = [val]; + } else if (global.HTMLCollection && val instanceof global.HTMLCollection) { + retval = val; + } else if (val instanceof Array) { + retval = val; + } else if (val === null) { + retval = []; + } + + retval = Array.prototype.slice.call(retval); + + return retval; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 10 */ +/***/ (function(module, exports) { + + var Color = function(color, options) { + //todo: support rgba, hsla, and rrggbbaa notation + //todo: use CIELAB internally + //todo: add clamp function (with sign) + if (typeof color !== 'string') return; + + this.original = color; + + if (color.charAt(0) === '#') { + color = color.slice(1); + } + + if (/[^a-f0-9]+/i.test(color)) return; + + if (color.length === 3) { + color = color.replace(/./g, '$&$&'); + } + + if (color.length !== 6) return; + + this.alpha = 1; + + if (options && options.alpha) { + this.alpha = options.alpha; + } + + this.set(parseInt(color, 16)); + }; + + //todo: jsdocs + Color.rgb2hex = function(r, g, b) { + function format (decimal) { + var hex = (decimal | 0).toString(16); + if (decimal < 16) { + hex = '0' + hex; + } + return hex; + } + + return [r, g, b].map(format).join(''); + }; + + //todo: jsdocs + Color.hsl2rgb = function (h, s, l) { + var H = h / 60; + var C = (1 - Math.abs(2 * l - 1)) * s; + var X = C * (1 - Math.abs(parseInt(H) % 2 - 1)); + var m = l - (C / 2); + + var r = 0, g = 0, b = 0; + + if (H >= 0 && H < 1) { + r = C; + g = X; + } else if (H >= 1 && H < 2) { + r = X; + g = C; + } else if (H >= 2 && H < 3) { + g = C; + b = X; + } else if (H >= 3 && H < 4) { + g = X; + b = C; + } else if (H >= 4 && H < 5) { + r = X; + b = C; + } else if (H >= 5 && H < 6) { + r = C; + b = X; + } + + r += m; + g += m; + b += m; + + r = parseInt(r * 255); + g = parseInt(g * 255); + b = parseInt(b * 255); + + return [r, g, b]; + }; + + /** + * Sets the color from a raw RGB888 integer + * @param raw RGB888 representation of color + */ + //todo: refactor into a static method + //todo: factor out individual color spaces + //todo: add HSL, CIELAB, and CIELUV + Color.prototype.set = function (val) { + this.raw = val; + + var r = (this.raw & 0xFF0000) >> 16; + var g = (this.raw & 0x00FF00) >> 8; + var b = (this.raw & 0x0000FF); + + // BT.709 + var y = 0.2126 * r + 0.7152 * g + 0.0722 * b; + var u = -0.09991 * r - 0.33609 * g + 0.436 * b; + var v = 0.615 * r - 0.55861 * g - 0.05639 * b; + + this.rgb = { + r: r, + g: g, + b: b + }; + + this.yuv = { + y: y, + u: u, + v: v + }; + + return this; + }; + + /** + * Lighten or darken a color + * @param multiplier Amount to lighten or darken (-1 to 1) + */ + Color.prototype.lighten = function(multiplier) { + var cm = Math.min(1, Math.max(0, Math.abs(multiplier))) * (multiplier < 0 ? -1 : 1); + var bm = (255 * cm) | 0; + var cr = Math.min(255, Math.max(0, this.rgb.r + bm)); + var cg = Math.min(255, Math.max(0, this.rgb.g + bm)); + var cb = Math.min(255, Math.max(0, this.rgb.b + bm)); + var hex = Color.rgb2hex(cr, cg, cb); + return new Color(hex); + }; + + /** + * Output color in hex format + * @param addHash Add a hash character to the beginning of the output + */ + Color.prototype.toHex = function(addHash) { + return (addHash ? '#' : '') + this.raw.toString(16); + }; + + /** + * Returns whether or not current color is lighter than another color + * @param color Color to compare against + */ + Color.prototype.lighterThan = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + return this.yuv.y > color.yuv.y; + }; + + /** + * Returns the result of mixing current color with another color + * @param color Color to mix with + * @param multiplier How much to mix with the other color + */ + /* + Color.prototype.mix = function (color, multiplier) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var r = this.rgb.r; + var g = this.rgb.g; + var b = this.rgb.b; + var a = this.alpha; + + var m = typeof multiplier !== 'undefined' ? multiplier : 0.5; + + //todo: write a lerp function + r = r + m * (color.rgb.r - r); + g = g + m * (color.rgb.g - g); + b = b + m * (color.rgb.b - b); + a = a + m * (color.alpha - a); + + return new Color(Color.rgbToHex(r, g, b), { + 'alpha': a + }); + }; + */ + + /** + * Returns the result of blending another color on top of current color with alpha + * @param color Color to blend on top of current color, i.e. "Ca" + */ + //todo: see if .blendAlpha can be merged into .mix + Color.prototype.blendAlpha = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var Ca = color; + var Cb = this; + + //todo: write alpha blending function + var r = Ca.alpha * Ca.rgb.r + (1 - Ca.alpha) * Cb.rgb.r; + var g = Ca.alpha * Ca.rgb.g + (1 - Ca.alpha) * Cb.rgb.g; + var b = Ca.alpha * Ca.rgb.b + (1 - Ca.alpha) * Cb.rgb.b; + + return new Color(Color.rgb2hex(r, g, b)); + }; + + module.exports = Color; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + module.exports = { + 'version': '2.9.7', + 'svg_ns': 'http://www.w3.org/2000/svg' + }; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + var shaven = __webpack_require__(13); + + var SVG = __webpack_require__(8); + var constants = __webpack_require__(11); + var utils = __webpack_require__(7); + + var SVG_NS = constants.svg_ns; + + var templates = { + 'element': function (options) { + var tag = options.tag; + var content = options.content || ''; + delete options.tag; + delete options.content; + return [tag, content, options]; + } + }; + + //todo: deprecate tag arg, infer tag from shape object + function convertShape (shape, tag) { + return templates.element({ + 'tag': tag, + 'width': shape.width, + 'height': shape.height, + 'fill': shape.properties.fill + }); + } + + function textCss (properties) { + return utils.cssProps({ + 'fill': properties.fill, + 'font-weight': properties.font.weight, + 'font-family': properties.font.family + ', monospace', + 'font-size': properties.font.size + properties.font.units + }); + } + + function outlinePath (bgWidth, bgHeight, outlineWidth) { + var outlineOffsetWidth = outlineWidth / 2; + + return [ + 'M', outlineOffsetWidth, outlineOffsetWidth, + 'H', bgWidth - outlineOffsetWidth, + 'V', bgHeight - outlineOffsetWidth, + 'H', outlineOffsetWidth, + 'V', 0, + 'M', 0, outlineOffsetWidth, + 'L', bgWidth, bgHeight - outlineOffsetWidth, + 'M', 0, bgHeight - outlineOffsetWidth, + 'L', bgWidth, outlineOffsetWidth + ].join(' '); + } + + module.exports = function (sceneGraph, renderSettings) { + var engineSettings = renderSettings.engineSettings; + var stylesheets = engineSettings.stylesheets; + var stylesheetXml = stylesheets.map(function (stylesheet) { + return ''; + }).join('\n'); + + var holderId = 'holder_' + Number(new Date()).toString(16); + + var root = sceneGraph.root; + var textGroup = root.children.holderTextGroup; + + var css = '#' + holderId + ' text { ' + textCss(textGroup.properties) + ' } '; + + // push text down to be equally vertically aligned with canvas renderer + textGroup.y += textGroup.textPositionData.boundingBox.height * 0.8; + + var wordTags = []; + + Object.keys(textGroup.children).forEach(function (lineKey) { + var line = textGroup.children[lineKey]; + + Object.keys(line.children).forEach(function (wordKey) { + var word = line.children[wordKey]; + var x = textGroup.x + line.x + word.x; + var y = textGroup.y + line.y + word.y; + var wordTag = templates.element({ + 'tag': 'text', + 'content': word.properties.text, + 'x': x, + 'y': y + }); + + wordTags.push(wordTag); + }); + }); + + var text = templates.element({ + 'tag': 'g', + 'content': wordTags + }); + + var outline = null; + + if (root.children.holderBg.properties.outline) { + var outlineProperties = root.children.holderBg.properties.outline; + outline = templates.element({ + 'tag': 'path', + 'd': outlinePath(root.children.holderBg.width, root.children.holderBg.height, outlineProperties.width), + 'stroke-width': outlineProperties.width, + 'stroke': outlineProperties.fill, + 'fill': 'none' + }); + } + + var bg = convertShape(root.children.holderBg, 'rect'); + + var sceneContent = []; + + sceneContent.push(bg); + if (outlineProperties) { + sceneContent.push(outline); + } + sceneContent.push(text); + + var scene = templates.element({ + 'tag': 'g', + 'id': holderId, + 'content': sceneContent + }); + + var style = templates.element({ + 'tag': 'style', + //todo: figure out how to add CDATA directive + 'content': css, + 'type': 'text/css' + }); + + var defs = templates.element({ + 'tag': 'defs', + 'content': style + }); + + var svg = templates.element({ + 'tag': 'svg', + 'content': [defs, scene], + 'width': root.properties.width, + 'height': root.properties.height, + 'xmlns': SVG_NS, + 'viewBox': [0, 0, root.properties.width, root.properties.height].join(' '), + 'preserveAspectRatio': 'none' + }); + + var output = shaven(svg); + + if (/\&(x)?#[0-9A-Fa-f]/.test(output[0])) { + output[0] = output[0].replace(/&#/gm, '&#'); + } + + output = stylesheetXml + output[0]; + + var svgString = SVG.svgStringToDataURI(output, renderSettings.mode === 'background'); + return svgString; + }; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + var escape = __webpack_require__(14) + + // TODO: remove namespace + + module.exports = function shaven (array, namespace, returnObject) { + + 'use strict' + + var i = 1 + var doesEscape = true + var HTMLString + var attributeKey + var callback + var key + + + returnObject = returnObject || {} + + + function createElement (sugarString) { + + var tags = sugarString.match(/^[\w-]+/) + var element = { + tag: tags ? tags[0] : 'div', + attr: {}, + children: [] + } + var id = sugarString.match(/#([\w-]+)/) + var reference = sugarString.match(/\$([\w-]+)/) + var classNames = sugarString.match(/\.[\w-]+/g) + + + // Assign id if is set + if (id) { + element.attr.id = id[1] + + // Add element to the return object + returnObject[id[1]] = element + } + + if (reference) + returnObject[reference[1]] = element + + if (classNames) + element.attr.class = classNames.join(' ').replace(/\./g, '') + + if (sugarString.match(/&$/g)) + doesEscape = false + + return element + } + + function replacer (key, value) { + + if (value === null || value === false || value === undefined) + return + + if (typeof value !== 'string' && typeof value !== 'object') + return String(value) + + return value + } + + function escapeAttribute (string) { + return (string || string === 0) ? + String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') : + '' + } + + function escapeHTML (string) { + return String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>') + } + + + if (typeof array[0] === 'string') + array[0] = createElement(array[0]) + + else if (Array.isArray(array[0])) + i = 0 + + else + throw new Error( + 'First element of array must be a string, ' + + 'or an array and not ' + JSON.stringify(array[0]) + ) + + + for (; i < array.length; i++) { + + // Don't render element if value is false or null + if (array[i] === false || array[i] === null) { + array[0] = false + break + } + + // Continue with next array value if current value is undefined or true + else if (array[i] === undefined || array[i] === true) { + continue + } + + else if (typeof array[i] === 'string') { + if (doesEscape) + array[i] = escapeHTML(array[i]) + + array[0].children.push(array[i]) + } + + else if (typeof array[i] === 'number') { + + array[0].children.push(array[i]) + } + + else if (Array.isArray(array[i])) { + + if (Array.isArray(array[i][0])) { + array[i].reverse().forEach(function (subArray) { + array.splice(i + 1, 0, subArray) + }) + + if (i !== 0) + continue + i++ + } + + shaven(array[i], namespace, returnObject) + + if (array[i][0]) + array[0].children.push(array[i][0]) + } + + else if (typeof array[i] === 'function') + callback = array[i] + + + else if (typeof array[i] === 'object') { + for (attributeKey in array[i]) + if (array[i].hasOwnProperty(attributeKey)) + if (array[i][attributeKey] !== null && + array[i][attributeKey] !== false) + if (attributeKey === 'style' && + typeof array[i][attributeKey] === 'object') + array[0].attr[attributeKey] = JSON + .stringify(array[i][attributeKey], replacer) + .slice(2, -2) + .replace(/","/g, ';') + .replace(/":"/g, ':') + .replace(/\\"/g, '\'') + + else + array[0].attr[attributeKey] = array[i][attributeKey] + } + + else + throw new TypeError('"' + array[i] + '" is not allowed as a value.') + } + + + if (array[0] !== false) { + + HTMLString = '<' + array[0].tag + + for (key in array[0].attr) + if (array[0].attr.hasOwnProperty(key)) + HTMLString += ' ' + key + '="' + + escapeAttribute(array[0].attr[key]) + '"' + + HTMLString += '>' + + array[0].children.forEach(function (child) { + HTMLString += child + }) + + HTMLString += '' + + array[0] = HTMLString + } + + // Return root element on index 0 + returnObject[0] = array[0] + + if (callback) + callback(array[0]) + + // returns object containing all elements with an id and the root element + return returnObject + } + + +/***/ }), +/* 14 */ +/***/ (function(module, exports) { + + /*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */ + + 'use strict'; + + /** + * Module variables. + * @private + */ + + var matchHtmlRegExp = /["'&<>]/; + + /** + * Module exports. + * @public + */ + + module.exports = escapeHtml; + + /** + * Escape special characters in the given string of html. + * + * @param {string} string The string to escape for inserting into HTML + * @return {string} + * @public + */ + + function escapeHtml(string) { + var str = '' + string; + var match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } + + var escape; + var html = ''; + var index = 0; + var lastIndex = 0; + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"'; + break; + case 38: // & + escape = '&'; + break; + case 39: // ' + escape = '''; + break; + case 60: // < + escape = '<'; + break; + case 62: // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html; + } + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + var DOM = __webpack_require__(9); + var utils = __webpack_require__(7); + + module.exports = (function() { + var canvas = DOM.newEl('canvas'); + var ctx = null; + + return function(sceneGraph) { + if (ctx == null) { + ctx = canvas.getContext('2d'); + } + + var dpr = utils.canvasRatio(); + var root = sceneGraph.root; + canvas.width = dpr * root.properties.width; + canvas.height = dpr * root.properties.height ; + ctx.textBaseline = 'middle'; + + var bg = root.children.holderBg; + var bgWidth = dpr * bg.width; + var bgHeight = dpr * bg.height; + //todo: parametrize outline width (e.g. in scene object) + var outlineWidth = 2; + var outlineOffsetWidth = outlineWidth / 2; + + ctx.fillStyle = bg.properties.fill; + ctx.fillRect(0, 0, bgWidth, bgHeight); + + if (bg.properties.outline) { + //todo: abstract this into a method + ctx.strokeStyle = bg.properties.outline.fill; + ctx.lineWidth = bg.properties.outline.width; + ctx.moveTo(outlineOffsetWidth, outlineOffsetWidth); + // TL, TR, BR, BL + ctx.lineTo(bgWidth - outlineOffsetWidth, outlineOffsetWidth); + ctx.lineTo(bgWidth - outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, outlineOffsetWidth); + // Diagonals + ctx.moveTo(0, outlineOffsetWidth); + ctx.lineTo(bgWidth, bgHeight - outlineOffsetWidth); + ctx.moveTo(0, bgHeight - outlineOffsetWidth); + ctx.lineTo(bgWidth, outlineOffsetWidth); + ctx.stroke(); + } + + var textGroup = root.children.holderTextGroup; + ctx.font = textGroup.properties.font.weight + ' ' + (dpr * textGroup.properties.font.size) + textGroup.properties.font.units + ' ' + textGroup.properties.font.family + ', monospace'; + ctx.fillStyle = textGroup.properties.fill; + + for (var lineKey in textGroup.children) { + var line = textGroup.children[lineKey]; + for (var wordKey in line.children) { + var word = line.children[wordKey]; + var x = dpr * (textGroup.x + line.x + word.x); + var y = dpr * (textGroup.y + line.y + word.y + (textGroup.properties.leading / 2)); + + ctx.fillText(word.properties.text, x, y); + } + } + + return canvas.toDataURL('image/png'); + }; + })(); + +/***/ }) +/******/ ]) +}); +; +(function(ctx, isMeteorPackage) { + if (isMeteorPackage) { + Holder = ctx.Holder; + } +})(this, typeof Meteor !== 'undefined' && typeof Package !== 'undefined'); diff --git a/静态站点/Bootstrap4/plugs/holder/holder.min.js b/静态站点/Bootstrap4/plugs/holder/holder.min.js new file mode 100644 index 0000000..6935bf1 --- /dev/null +++ b/静态站点/Bootstrap4/plugs/holder/holder.min.js @@ -0,0 +1,14 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://imsky.co + +Site: http://holderjs.com +Issues: https://github.com/imsky/holder/issues +License: MIT + +*/ +!function(e){if(e.document){var t=e.document;t.querySelectorAll||(t.querySelectorAll=function(n){var r,i=t.createElement("style"),a=[];for(t.documentElement.firstChild.appendChild(i),t._qsa=[],i.styleSheet.cssText=n+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",e.scrollBy(0,0),i.parentNode.removeChild(i);t._qsa.length;)r=t._qsa.shift(),r.style.removeAttribute("x-qsa"),a.push(r);return t._qsa=null,a}),t.querySelector||(t.querySelector=function(e){var n=t.querySelectorAll(e);return n.length?n[0]:null}),t.getElementsByClassName||(t.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),t.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(t);return n}),Array.prototype.forEach||(Array.prototype.forEach=function(e){if(void 0===this||null===this)throw TypeError();var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;n>r;r++)r in t&&e.call(i,t[r],r,t)}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var n,r=0,i=[],a=0,o=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+\/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;r>16&255)),i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a)),o=0,a=0),r+=1;return 12===o?(a>>=4,i.push(String.fromCharCode(255&a))):18===o&&(a>>=2,i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,a,o,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,o=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(a),t.charAt(o),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame&&e.webkitCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame&&e.mozCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var o=i(n.substr(n.lastIndexOf(e.domain)),e);o&&a({mode:null,el:r,flags:o,engineSettings:t})}function i(e,t){var n={theme:T(O.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.indexOf("?"),i=[e];-1!==r&&(i=[e.slice(0,r),e.slice(r+1)]);var a=i[0].split("/");n.holderURL=e;var o=a[1],s=o.match(/([\d]+p?)x([\d]+p?)/);if(!s)return!1;if(n.fluid=-1!==o.indexOf("p"),n.dimensions={width:s[1].replace("p","%"),height:s[2].replace("p","%")},2===i.length){var l=v.parse(i[1]);if(w.truthy(l.ratio)){n.fluid=!0;var h=parseFloat(n.dimensions.width.replace("%","")),u=parseFloat(n.dimensions.height.replace("%",""));u=Math.floor(100*(u/h)),h=100,n.dimensions.width=h+"%",n.dimensions.height=u+"%"}if(n.auto=w.truthy(l.auto),l.bg&&(n.theme.bg=w.parseColor(l.bg)),l.fg&&(n.theme.fg=w.parseColor(l.fg)),l.bg&&!l.fg&&(n.autoFg=!0),l.theme&&n.instanceOptions.themes.hasOwnProperty(l.theme)&&(n.theme=T(n.instanceOptions.themes[l.theme],null)),l.text&&(n.text=l.text),l.textmode&&(n.textmode=l.textmode),l.size&&parseFloat(l.size)&&(n.size=parseFloat(l.size)),l.font&&(n.font=l.font),l.align&&(n.align=l.align),l.lineWrap&&(n.lineWrap=l.lineWrap),n.nowrap=w.truthy(l.nowrap),n.outline=w.truthy(l.outline),w.truthy(l.random)){O.vars.cache.themeKeys=O.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var d=O.vars.cache.themeKeys[0|Math.random()*O.vars.cache.themeKeys.length];n.theme=T(n.instanceOptions.themes[d],null)}}return n}function a(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,a=r.dimensions,s=r.theme,l=a.width+"x"+a.height;t=null==t?r.fluid?"fluid":"image":t;var d=/holder_([a-z]+)/g,c=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),("left"===e.align||"right"===e.align)&&(a=e.width*(1-2*(1-r)));for(var E=0;E=a||k===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),k!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+T.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return o}function l(e,t,n,r){var i=parseInt(e,10),a=parseInt(t,10),o=Math.max(i,a),s=Math.min(i,a),l=.8*Math.min(s,o*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?O.vars.resizableImages:[e];for(var n=0,r=t.length;r>n;n++){var i=t[n];if(i.holderData){var a=i.holderData.flags,s=k(i);if(s){if(!i.holderData.resizeUpdate)continue;if(a.fluid&&a.auto){var l=i.holderData.fluidConfig;switch(l.mode){case"width":s.height=s.width/l.ratio;break;case"height":s.width=s.height*l.ratio}}var h={mode:"image",holderSettings:{dimensions:s,theme:a.theme,flags:a},el:i,engineSettings:i.holderData.engineSettings};"exact"==a.textmode&&(a.exactDimensions=s,h.holderSettings.dimensions=a.dimensions),o(h)}else f(i)}}}function u(e){if(e.holderData){var t=k(e);if(t){var n=e.holderData.flags,r={fluidHeight:"%"==n.dimensions.height.slice(-1),fluidWidth:"%"==n.dimensions.width.slice(-1),mode:null,initialDimensions:t};r.fluidWidth&&!r.fluidHeight?(r.mode="width",r.ratio=r.initialDimensions.width/parseFloat(n.dimensions.height)):!r.fluidWidth&&r.fluidHeight&&(r.mode="height",r.ratio=parseFloat(n.dimensions.width)/r.initialDimensions.height),e.holderData.fluidConfig=r}else f(e)}}function d(){var e,n=[],r=Object.keys(O.vars.invisibleImages);r.forEach(function(t){e=O.vars.invisibleImages[t],k(e)&&"img"==e.nodeName.toLowerCase()&&(n.push(e),delete O.vars.invisibleImages[t])}),n.length&&j.run({images:n}),setTimeout(function(){t.requestAnimationFrame(d)},10)}function c(){O.vars.visibilityCheckStarted||(t.requestAnimationFrame(d),O.vars.visibilityCheckStarted=!0)}function f(e){e.holderData.invisibleId||(O.vars.invisibleId+=1,O.vars.invisibleImages["i"+O.vars.invisibleId]=e,e.holderData.invisibleId=O.vars.invisibleId)}function p(e){O.vars.debounceTimer||e.call(this),O.vars.debounceTimer&&t.clearTimeout(O.vars.debounceTimer),O.vars.debounceTimer=t.setTimeout(function(){O.vars.debounceTimer=null,e.call(this)},O.setup.debounce)}function g(){p(function(){h(null)})}var m=n(2),v=n(3),y=n(6),w=n(7),b=n(8),x=n(9),S=n(10),A=n(11),C=n(12),E=n(15),T=w.extend,k=w.dimensionCheck,F=A.svg_ns,j={version:A.version,addTheme:function(e,t){return null!=e&&null!=t&&(O.settings.themes[e]=t),delete O.vars.cache.themeKeys,this},addImage:function(e,t){var n=x.getNodeArray(t);return n.forEach(function(t){var n=x.newEl("img"),r={};r[O.setup.dataAttr]=e,x.setAttr(n,r),t.appendChild(n)}),this},setResizeUpdate:function(e,t){e.holderData&&(e.holderData.resizeUpdate=!!t,e.holderData.resizeUpdate&&h(e))},run:function(e){e=e||{};var n={},o=T(O.settings,e);O.vars.preempted=!0,O.vars.dataAttr=o.dataAttr||O.setup.dataAttr,n.renderer=o.renderer?o.renderer:O.setup.renderer,-1===O.setup.renderers.join(",").indexOf(n.renderer)&&(n.renderer=O.setup.supportsSVG?"svg":O.setup.supportsCanvas?"canvas":"html");var s=x.getNodeArray(o.images),l=x.getNodeArray(o.bgnodes),h=x.getNodeArray(o.stylenodes),u=x.getNodeArray(o.objects);return n.stylesheets=[],n.svgXMLStylesheet=!0,n.noFontFallback=!!o.noFontFallback,n.noBackgroundSize=!!o.noBackgroundSize,h.forEach(function(e){if(e.attributes.rel&&e.attributes.href&&"stylesheet"==e.attributes.rel.value){var t=e.attributes.href.value,r=x.newEl("a");r.href=t;var i=r.protocol+"//"+r.host+r.pathname+r.search;n.stylesheets.push(i)}}),l.forEach(function(e){if(t.getComputedStyle){var r=t.getComputedStyle(e,null).getPropertyValue("background-image"),s=e.getAttribute("data-background-src"),l=s||r,h=null,u=o.domain+"/",d=l.indexOf(u);if(0===d)h=l;else if(1===d&&"?"===l[0])h=l.slice(1);else{var c=l.substr(d).match(/([^\"]*)"?\)/);if(null!==c)h=c[1];else if(0===l.indexOf("url("))throw"Holder: unable to parse background URL: "+l}if(h){var f=i(h,o);f&&a({mode:"background",el:e,flags:f,engineSettings:n})}}}),u.forEach(function(e){var t={};try{t.data=e.getAttribute("data"),t.dataSrc=e.getAttribute(O.vars.dataAttr)}catch(i){}var a=null!=t.data&&0===t.data.indexOf(o.domain),s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain);a?r(o,n,t.data,e):s&&r(o,n,t.dataSrc,e)}),s.forEach(function(e){var t={};try{t.src=e.getAttribute("src"),t.dataSrc=e.getAttribute(O.vars.dataAttr),t.rendered=e.getAttribute("data-holder-rendered")}catch(i){}var a=null!=t.src,s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain),l=null!=t.rendered&&"true"==t.rendered;a?0===t.src.indexOf(o.domain)?r(o,n,t.src,e):s&&(l?r(o,n,t.dataSrc,e):!function(e,t,n,i,a){w.imageExists(e,function(e){e||r(t,n,i,a)})}(t.src,o,n,t.dataSrc,e)):s&&r(o,n,t.dataSrc,e)}),this}},O={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}},z=function(){var e=null,t=null,n=null;return function(r){var i=r.root;if(O.setup.supportsSVG){var a=!1,o=function(e){return document.createTextNode(e)};(null==e||e.parentNode!==document.body)&&(a=!0),e=b.initSVG(e,i.properties.width,i.properties.height),e.style.display="block",a&&(t=x.newEl("text",F),n=o(null),x.setAttr(t,{x:0}),t.appendChild(n),e.appendChild(t),document.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var s=i.children.holderTextGroup,l=s.properties;x.setAttr(t,{y:l.font.size,style:w.cssProps({"font-weight":l.font.weight,"font-size":l.font.size+l.font.units,"font-family":l.font.family})});var h=x.newEl("textarea");h.innerHTML=l.text,n.nodeValue=h.value;var u=t.getBBox(),d=Math.ceil(u.width/i.properties.width),c=l.text.split(" "),f=l.text.match(/\\n/g);d+=null==f?0:f.length,n.nodeValue=l.text.replace(/[ ]+/g,"");var p=t.getComputedTextLength(),g=u.width-p,m=Math.round(g/Math.max(1,c.length-1)),v=[];if(d>1){n.nodeValue="";for(var y=0;y=0?t:1)}function a(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var o=e.document,s=o.documentElement,l="load",h=!1,u="on"+l,d="complete",c="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in o,b=h,x=h,S=[];if(o[c]===d)i(t);else if(w)o[g](m,n,h),e[g](l,n,h);else{o[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return a.version="1.4.0",a.isReady=function(){return x},a}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,a=n(4),o=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=a(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),t.unshift(n>128?["&#",n,";"].join(""):e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return t.height&&t.width?t:!1},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/,a=e.match(n);if(null!==a)return t=a[1]||a[2],"#"!==t[0]?"#"+t:t;if(a=e.match(r),null!==a)return t="rgb("+a.slice(1).join(",")+")";if(a=e.match(i),null!==a){const o=function(e){return"0."+e.split(".")[1]},s=a.slice(1).map(function(e,t){return 3===t?o(e):e});return t="rgba("+s.join(",")+")"}return null},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",a=8;t.initSVG=function(e,t,n){var o,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(o=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),o.appendChild(s),e.appendChild(o)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+o[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),a=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),a+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){return e.document?null==n?e.document.createElement(t):e.document.createElementNS(n,t):void 0},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){return e.DOMParser?(new DOMParser).parseFromString("","application/xml"):void 0},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return 16>e&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,a=i*(1-Math.abs(parseInt(r)%2-1)),o=n-i/2,s=0,l=0,h=0;return r>=0&&1>r?(s=i,l=a):r>=1&&2>r?(s=a,l=i):r>=2&&3>r?(l=i,h=a):r>=3&&4>r?(l=a,h=i):r>=4&&5>r?(s=a,h=i):r>=5&&6>r&&(s=i,h=a),s+=o,l+=o,h+=o,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,a=-.09991*t-.33609*n+.436*r,o=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:a,v:o},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(0>e?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),a=Math.min(255,Math.max(0,this.rgb.g+r)),o=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,a,o);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,a=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,o=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,a,o))},e.exports=n},function(e,t){e.exports={version:"2.9.7",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return d.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function a(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var o=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,d={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),c="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+c+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,a=d.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(a)})});var v=d.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=d.element({tag:"path",d:a(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=d.element({tag:"g",id:c,content:x}),A=d.element({tag:"style",content:g,type:"text/css"}),C=d.element({tag:"defs",content:A}),E=d.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),T=o(E);/\&(x)?#[0-9A-Fa-f]/.test(T[0])&&(T[0]=T[0].replace(/&#/gm,"&#")),T=h+T[0];var k=s.svgStringToDataURI(T,"background"===t.mode);return k}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^[\w-]+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),a=e.match(/\$([\w-]+)/),o=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),a&&(n[a[1]]=r),o&&(r.attr["class"]=o.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function a(e,t){return null!==t&&t!==!1&&void 0!==t?"string"!=typeof t&&"object"!=typeof t?String(t):t:void 0}function o(e){return e||0===e?String(e).replace(/&/g,"&").replace(/"/g,"""):""}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,d,c=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));c=0}for(;c",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){"use strict";function n(e){var t=""+e,n=r.exec(t);if(!n)return t;var i,a="",o=0,s=0;for(o=n.index;o]/;e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),a=n.root;e.width=r*a.properties.width,e.height=r*a.properties.height,t.textBaseline="middle";var o=a.children.holderBg,s=r*o.width,l=r*o.height,h=2,u=h/2;t.fillStyle=o.properties.fill,t.fillRect(0,0,s,l),o.properties.outline&&(t.strokeStyle=o.properties.outline.fill,t.lineWidth=o.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var d=a.children.holderTextGroup;t.font=d.properties.font.weight+" "+r*d.properties.font.size+d.properties.font.units+" "+d.properties.font.family+", monospace",t.fillStyle=d.properties.fill;for(var c in d.children){var f=d.children[c];for(var p in f.children){var g=f.children[p],m=r*(d.x+f.x+g.x),v=r*(d.y+f.y+g.y+d.properties.leading/2); + +t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); \ No newline at end of file diff --git a/静态站点/Bootstrap5/pages/test.css b/静态站点/Bootstrap5/pages/test.css new file mode 100644 index 0000000..e69de29 diff --git a/静态站点/Bootstrap5/pages/test.html b/静态站点/Bootstrap5/pages/test.html new file mode 100644 index 0000000..3d99e8d --- /dev/null +++ b/静态站点/Bootstrap5/pages/test.html @@ -0,0 +1,25 @@ + + + + + + + BootstrapStudy + + + + + + + + +
+ ... +
+ + + + + + + diff --git a/静态站点/Bootstrap5/pages/test.js b/静态站点/Bootstrap5/pages/test.js new file mode 100644 index 0000000..f525482 --- /dev/null +++ b/静态站点/Bootstrap5/pages/test.js @@ -0,0 +1 @@ +console.log("来自 test.js 的日志"); \ No newline at end of file diff --git a/静态站点/Bootstrap5/plugs/holder/holder.js b/静态站点/Bootstrap5/plugs/holder/holder.js new file mode 100644 index 0000000..db1e43b --- /dev/null +++ b/静态站点/Bootstrap5/plugs/holder/holder.js @@ -0,0 +1,3063 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://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-2020 Ivan Malopinsky - https://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-2020 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; + + // SVG embedding doesn't parse Unicode properly + if (el.nodeName.toLowerCase() === 'object') { + var textLines = theme.text.split('\\n'); + for (var k = 0; k < textLines.length; k++) { + textLines[k] = utils.encodeHtmlEntity(textLines[k]); + } + theme.text = textLines.join('\\n'); + } + } + + if (theme.text) { + var holderTemplateMatches = theme.text.match(holderTemplateRe); + + if (holderTemplateMatches !== null) { + //todo: optimize template replacement + holderTemplateMatches.forEach(function (match) { + if (match === 'holder_dimensions') { + theme.text = theme.text.replace(match, dimensionsCaption); + } + }); + } + } + + var holderURL = flags.holderURL; + var engineSettings = extend(_engineSettings, null); + + if (flags.font) { + /* + If external fonts are used in a placeholder rendered with SVG, Holder falls back to canvas. + + This is done because Firefox and Chrome disallow embedded SVGs from referencing external assets. + The workaround is either to change the placeholder tag from to or to use the canvas renderer. + */ + theme.font = flags.font; + if (!engineSettings.noFontFallback && el.nodeName.toLowerCase() === 'img' && App.setup.supportsCanvas && engineSettings.renderer === 'svg') { + engineSettings = extend(engineSettings, { + renderer: 'canvas' + }); + } + } + + //Chrome and Opera require a quick 10ms re-render if web fonts are used with canvas + if (flags.font && engineSettings.renderer == 'canvas') { + engineSettings.reRender = true; + } + + if (mode == 'background') { + if (el.getAttribute('data-background-src') == null) { + DOM.setAttr(el, { + 'data-background-src': holderURL + }); + } + } else { + var domProps = {}; + domProps[App.vars.dataAttr] = holderURL; + DOM.setAttr(el, domProps); + } + + flags.theme = theme; + + //todo consider using all renderSettings in holderData + el.holderData = { + flags: flags, + engineSettings: engineSettings + }; + + if (mode == 'image' || mode == 'fluid') { + DOM.setAttr(el, { + 'alt': theme.text ? (dimensionsInText ? theme.text : theme.text + ' [' + dimensionsCaption + ']') : dimensionsCaption + }); + } + + var renderSettings = { + mode: mode, + el: el, + holderSettings: { + dimensions: dimensions, + theme: theme, + flags: flags + }, + engineSettings: engineSettings + }; + + if (mode == 'image') { + if (!flags.auto) { + el.style.width = dimensions.width + 'px'; + el.style.height = dimensions.height + 'px'; + } + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + render(renderSettings); + + if (flags.textmode == 'exact') { + el.holderData.resizeUpdate = true; + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } else if (mode == 'background' && engineSettings.renderer != 'html') { + render(renderSettings); + } else if (mode == 'fluid') { + el.holderData.resizeUpdate = true; + + if (dimensions.height.slice(-1) == '%') { + el.style.height = dimensions.height; + } else if (flags.auto == null || !flags.auto) { + el.style.height = dimensions.height + 'px'; + } + if (dimensions.width.slice(-1) == '%') { + el.style.width = dimensions.width; + } else if (flags.auto == null || !flags.auto) { + el.style.width = dimensions.width + 'px'; + } + if (el.style.display == 'inline' || el.style.display === '' || el.style.display == 'none') { + el.style.display = 'block'; + } + + setInitialDimensions(el); + + if (engineSettings.renderer == 'html') { + el.style.backgroundColor = theme.bg; + } else { + App.vars.resizableImages.push(el); + updateResizableElements(el); + } + } + } + + /** + * Core function that takes output from renderers and sets it as the source or background-image of the target element + * + * @private + * @param renderSettings Renderer settings + */ + function render(renderSettings) { + var image = null; + var mode = renderSettings.mode; + var el = renderSettings.el; + var holderSettings = renderSettings.holderSettings; + var engineSettings = renderSettings.engineSettings; + + switch (engineSettings.renderer) { + case 'svg': + if (!App.setup.supportsSVG) return; + break; + case 'canvas': + if (!App.setup.supportsCanvas) return; + break; + default: + return; + } + + //todo: move generation of scene up to flag generation to reduce extra object creation + var scene = { + width: holderSettings.dimensions.width, + height: holderSettings.dimensions.height, + theme: holderSettings.theme, + flags: holderSettings.flags + }; + + var sceneGraph = buildSceneGraph(scene); + + function getRenderedImage() { + var image = null; + switch (engineSettings.renderer) { + case 'canvas': + image = sgCanvasRenderer(sceneGraph, renderSettings); + break; + case 'svg': + image = svgRenderer(sceneGraph, renderSettings); + break; + default: + throw 'Holder: invalid renderer: ' + engineSettings.renderer; + } + + return image; + } + + image = getRenderedImage(); + + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + + //todo: add canvas rendering + if (mode == 'background') { + el.style.backgroundImage = 'url(' + image + ')'; + + if (!engineSettings.noBackgroundSize) { + el.style.backgroundSize = scene.width + 'px ' + scene.height + 'px'; + } + } else { + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + if (engineSettings.reRender) { + global.setTimeout(function () { + var image = getRenderedImage(); + if (image == null) { + throw 'Holder: couldn\'t render placeholder'; + } + //todo: refactor this code into a function + if (el.nodeName.toLowerCase() === 'img') { + DOM.setAttr(el, { + 'src': image + }); + } else if (el.nodeName.toLowerCase() === 'object') { + DOM.setAttr(el, { + 'data': image, + 'type': 'image/svg+xml' + }); + } + }, 150); + } + } + //todo: account for re-rendering + DOM.setAttr(el, { + 'data-holder-rendered': true + }); + } + + /** + * Core function that takes a Holder scene description and builds a scene graph + * + * @private + * @param scene Holder scene object + */ + //todo: make this function reusable + //todo: merge app defaults and setup properties into the scene argument + function buildSceneGraph(scene) { + var fontSize = App.defaults.size; + if (parseFloat(scene.theme.size)) { + fontSize = scene.theme.size; + } else if (parseFloat(scene.flags.size)) { + fontSize = scene.flags.size; + } + + scene.font = { + family: scene.theme.font ? scene.theme.font : 'Arial, Helvetica, Open Sans, sans-serif', + size: textSize(scene.width, scene.height, fontSize, App.defaults.scale), + units: scene.theme.units ? scene.theme.units : App.defaults.units, + weight: scene.theme.fontweight ? scene.theme.fontweight : 'bold' + }; + + scene.text = scene.theme.text || Math.floor(scene.width) + 'x' + Math.floor(scene.height); + + scene.noWrap = scene.theme.nowrap || scene.flags.nowrap; + + scene.align = scene.theme.align || scene.flags.align || 'center'; + + switch (scene.flags.textmode) { + case 'literal': + scene.text = scene.flags.dimensions.width + 'x' + scene.flags.dimensions.height; + break; + case 'exact': + if (!scene.flags.exactDimensions) break; + scene.text = Math.floor(scene.flags.exactDimensions.width) + 'x' + Math.floor(scene.flags.exactDimensions.height); + break; + } + + var lineWrap = scene.flags.lineWrap || App.setup.lineWrapRatio; + var sceneMargin = scene.width * lineWrap; + var maxLineWidth = sceneMargin; + + var sceneGraph = new SceneGraph({ + width: scene.width, + height: scene.height + }); + + var Shape = sceneGraph.Shape; + + var holderBg = new Shape.Rect('holderBg', { + fill: scene.theme.bg + }); + + holderBg.resize(scene.width, scene.height); + sceneGraph.root.add(holderBg); + + if (scene.flags.outline) { + var outlineColor = new Color(holderBg.properties.fill); + outlineColor = outlineColor.lighten(outlineColor.lighterThan('7f7f7f') ? -0.1 : 0.1); + holderBg.properties.outline = { + fill: outlineColor.toHex(true), + width: 2 + }; + } + + var holderTextColor = scene.theme.fg; + + if (scene.flags.autoFg) { + var holderBgColor = new Color(holderBg.properties.fill); + var lightColor = new Color('fff'); + var darkColor = new Color('000', { + 'alpha': 0.285714 + }); + + holderTextColor = holderBgColor.blendAlpha(holderBgColor.lighterThan('7f7f7f') ? darkColor : lightColor).toHex(true); + } + + var holderTextGroup = new Shape.Group('holderTextGroup', { + text: scene.text, + align: scene.align, + font: scene.font, + fill: holderTextColor + }); + + holderTextGroup.moveTo(null, null, 1); + sceneGraph.root.add(holderTextGroup); + + var tpdata = holderTextGroup.textPositionData = stagingRenderer(sceneGraph); + if (!tpdata) { + throw 'Holder: staging fallback not supported yet.'; + } + holderTextGroup.properties.leading = tpdata.boundingBox.height; + + var textNode = null; + var line = null; + + function finalizeLine(parent, line, width, height) { + line.width = width; + line.height = height; + parent.width = Math.max(parent.width, line.width); + parent.height += line.height; + } + + if (tpdata.lineCount > 1) { + var offsetX = 0; + var offsetY = 0; + var lineIndex = 0; + var lineKey; + line = new Shape.Group('line' + lineIndex); + + //Double margin so that left/right-aligned next is not flush with edge of image + if (scene.align === 'left' || scene.align === 'right') { + maxLineWidth = scene.width * (1 - (1 - lineWrap) * 2); + } + + for (var i = 0; i < tpdata.words.length; i++) { + var word = tpdata.words[i]; + textNode = new Shape.Text(word.text); + var newline = word.text == '\\n'; + if (!scene.noWrap && (offsetX + word.width >= maxLineWidth || newline === true)) { + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + offsetX = 0; + offsetY += holderTextGroup.properties.leading; + lineIndex += 1; + line = new Shape.Group('line' + lineIndex); + line.y = offsetY; + } + if (newline === true) { + continue; + } + textNode.moveTo(offsetX, 0); + offsetX += tpdata.spaceWidth + word.width; + line.add(textNode); + } + + finalizeLine(holderTextGroup, line, offsetX, holderTextGroup.properties.leading); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo(scene.width - line.width, null, null); + } + + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + for (lineKey in holderTextGroup.children) { + line = holderTextGroup.children[lineKey]; + line.moveTo((holderTextGroup.width - line.width) / 2, null, null); + } + + holderTextGroup.moveTo((scene.width - holderTextGroup.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - holderTextGroup.height) / 2, null); + + //If the text exceeds vertical space, move it down so the first line is visible + if ((scene.height - holderTextGroup.height) / 2 < 0) { + holderTextGroup.moveTo(null, 0, null); + } + } else { + textNode = new Shape.Text(scene.text); + line = new Shape.Group('line0'); + line.add(textNode); + holderTextGroup.add(line); + + if (scene.align === 'left') { + holderTextGroup.moveTo(scene.width - sceneMargin, null, null); + } else if (scene.align === 'right') { + holderTextGroup.moveTo(0 - (scene.width - sceneMargin), null, null); + } else { + holderTextGroup.moveTo((scene.width - tpdata.boundingBox.width) / 2, null, null); + } + + holderTextGroup.moveTo(null, (scene.height - tpdata.boundingBox.height) / 2, null); + } + + //todo: renderlist + return sceneGraph; + } + + /** + * Adaptive text sizing function + * + * @private + * @param width Parent width + * @param height Parent height + * @param fontSize Requested text size + * @param scale Proportional scale of text + */ + function textSize(width, height, fontSize, scale) { + var stageWidth = parseInt(width, 10); + var stageHeight = parseInt(height, 10); + + var bigSide = Math.max(stageWidth, stageHeight); + var smallSide = Math.min(stageWidth, stageHeight); + + var newHeight = 0.8 * Math.min(smallSide, bigSide * scale); + return Math.round(Math.max(fontSize, newHeight)); + } + + /** + * Iterates over resizable (fluid or auto) placeholders and renders them + * + * @private + * @param element Optional element selector, specified only if a specific element needs to be re-rendered + */ + function updateResizableElements(element) { + var images; + if (element == null || element.nodeType == null) { + images = App.vars.resizableImages; + } else { + images = [element]; + } + for (var i = 0, l = images.length; i < l; i++) { + var el = images[i]; + if (el.holderData) { + var flags = el.holderData.flags; + var dimensions = dimensionCheck(el); + if (dimensions) { + if (!el.holderData.resizeUpdate) { + continue; + } + + if (flags.fluid && flags.auto) { + var fluidConfig = el.holderData.fluidConfig; + switch (fluidConfig.mode) { + case 'width': + dimensions.height = dimensions.width / fluidConfig.ratio; + break; + case 'height': + dimensions.width = dimensions.height * fluidConfig.ratio; + break; + } + } + + var settings = { + mode: 'image', + holderSettings: { + dimensions: dimensions, + theme: flags.theme, + flags: flags + }, + el: el, + engineSettings: el.holderData.engineSettings + }; + + if (flags.textmode == 'exact') { + flags.exactDimensions = dimensions; + settings.holderSettings.dimensions = flags.dimensions; + } + + render(settings); + } else { + setInvisible(el); + } + } + } + } + + /** + * Sets up aspect ratio metadata for fluid placeholders, in order to preserve proportions when resizing + * + * @private + * @param el Image DOM element + */ + function setInitialDimensions(el) { + if (el.holderData) { + var dimensions = dimensionCheck(el); + if (dimensions) { + var flags = el.holderData.flags; + + var fluidConfig = { + fluidHeight: flags.dimensions.height.slice(-1) == '%', + fluidWidth: flags.dimensions.width.slice(-1) == '%', + mode: null, + initialDimensions: dimensions + }; + + if (fluidConfig.fluidWidth && !fluidConfig.fluidHeight) { + fluidConfig.mode = 'width'; + fluidConfig.ratio = fluidConfig.initialDimensions.width / parseFloat(flags.dimensions.height); + } else if (!fluidConfig.fluidWidth && fluidConfig.fluidHeight) { + fluidConfig.mode = 'height'; + fluidConfig.ratio = parseFloat(flags.dimensions.width) / fluidConfig.initialDimensions.height; + } + + el.holderData.fluidConfig = fluidConfig; + } else { + setInvisible(el); + } + } + } + + /** + * Iterates through all current invisible images, and if they're visible, renders them and removes them from further checks. Runs every animation frame. + * + * @private + */ + function visibilityCheck() { + var renderableImages = []; + var keys = Object.keys(App.vars.invisibleImages); + var el; + + keys.forEach(function (key) { + el = App.vars.invisibleImages[key]; + if (dimensionCheck(el) && el.nodeName.toLowerCase() == 'img') { + renderableImages.push(el); + delete App.vars.invisibleImages[key]; + } + }); + + if (renderableImages.length) { + Holder.run({ + images: renderableImages + }); + } + + // Done to prevent 100% CPU usage via aggressive calling of requestAnimationFrame + setTimeout(function () { + global.requestAnimationFrame(visibilityCheck); + }, 10); + } + + /** + * Starts checking for invisible placeholders if not doing so yet. Does nothing otherwise. + * + * @private + */ + function startVisibilityCheck() { + if (!App.vars.visibilityCheckStarted) { + global.requestAnimationFrame(visibilityCheck); + App.vars.visibilityCheckStarted = true; + } + } + + /** + * Sets a unique ID for an image detected to be invisible and adds it to the map of invisible images checked by visibilityCheck + * + * @private + * @param el Invisible DOM element + */ + function setInvisible(el) { + if (!el.holderData.invisibleId) { + App.vars.invisibleId += 1; + App.vars.invisibleImages['i' + App.vars.invisibleId] = el; + el.holderData.invisibleId = App.vars.invisibleId; + } + } + + //todo: see if possible to convert stagingRenderer to use HTML only + var stagingRenderer = (function() { + var svg = null, + stagingText = null, + stagingTextNode = null; + return function(graph) { + var rootNode = graph.root; + if (App.setup.supportsSVG) { + var firstTimeSetup = false; + var tnode = function(text) { + return document.createTextNode(text); + }; + if (svg == null || svg.parentNode !== document.body) { + firstTimeSetup = true; + } + + svg = SVG.initSVG(svg, rootNode.properties.width, rootNode.properties.height); + //Show staging element before staging + svg.style.display = 'block'; + + if (firstTimeSetup) { + stagingText = DOM.newEl('text', SVG_NS); + stagingTextNode = tnode(null); + DOM.setAttr(stagingText, { + x: 0 + }); + stagingText.appendChild(stagingTextNode); + svg.appendChild(stagingText); + document.body.appendChild(svg); + svg.style.visibility = 'hidden'; + svg.style.position = 'absolute'; + svg.style.top = '-100%'; + svg.style.left = '-100%'; + //todo: workaround for zero-dimension tag in Opera 12 + //svg.setAttribute('width', 0); + //svg.setAttribute('height', 0); + } + + var holderTextGroup = rootNode.children.holderTextGroup; + var htgProps = holderTextGroup.properties; + DOM.setAttr(stagingText, { + 'y': htgProps.font.size, + 'style': utils.cssProps({ + 'font-weight': htgProps.font.weight, + 'font-size': htgProps.font.size + htgProps.font.units, + 'font-family': htgProps.font.family + }) + }); + + //Unescape HTML entities to get approximately the right width + var txt = DOM.newEl('textarea'); + txt.innerHTML = htgProps.text; + stagingTextNode.nodeValue = txt.value; + + //Get bounding box for the whole string (total width and height) + var stagingTextBBox = stagingText.getBBox(); + + //Get line count and split the string into words + var lineCount = Math.ceil(stagingTextBBox.width / rootNode.properties.width); + var words = htgProps.text.split(' '); + var newlines = htgProps.text.match(/\\n/g); + lineCount += newlines == null ? 0 : newlines.length; + + //Get bounding box for the string with spaces removed + stagingTextNode.nodeValue = htgProps.text.replace(/[ ]+/g, ''); + var computedNoSpaceLength = stagingText.getComputedTextLength(); + + //Compute average space width + var diffLength = stagingTextBBox.width - computedNoSpaceLength; + var spaceWidth = Math.round(diffLength / Math.max(1, words.length - 1)); + + //Get widths for every word with space only if there is more than one line + var wordWidths = []; + if (lineCount > 1) { + stagingTextNode.nodeValue = ''; + for (var i = 0; i < words.length; i++) { + if (words[i].length === 0) continue; + stagingTextNode.nodeValue = utils.decodeHtmlEntity(words[i]); + var bbox = stagingText.getBBox(); + wordWidths.push({ + text: words[i], + width: bbox.width + }); + } + } + + //Hide staging element after staging + svg.style.display = 'none'; + + return { + spaceWidth: spaceWidth, + lineCount: lineCount, + boundingBox: stagingTextBBox, + words: wordWidths + }; + } else { + //todo: canvas fallback for measuring text on android 2.3 + return false; + } + }; + })(); + + //Helpers + + /** + * Prevents a function from being called too often, waits until a timer elapses to call it again + * + * @param fn Function to call + */ + function debounce(fn) { + if (!App.vars.debounceTimer) fn.call(this); + if (App.vars.debounceTimer) global.clearTimeout(App.vars.debounceTimer); + App.vars.debounceTimer = global.setTimeout(function() { + App.vars.debounceTimer = null; + fn.call(this); + }, App.setup.debounce); + } + + /** + * Holder-specific resize/orientation change callback, debounced to prevent excessive execution + */ + function resizeEvent() { + debounce(function() { + updateResizableElements(null); + }); + } + + //Set up flags + + for (var flag in App.flags) { + if (!App.flags.hasOwnProperty(flag)) continue; + App.flags[flag].match = function(val) { + return val.match(this.regex); + }; + } + + //Properties set once on setup + + App.setup = { + renderer: 'html', + debounce: 100, + ratio: 1, + supportsCanvas: false, + supportsSVG: false, + lineWrapRatio: 0.9, + dataAttr: 'data-src', + renderers: ['html', 'canvas', 'svg'] + }; + + //Properties modified during runtime + + App.vars = { + preempted: false, + resizableImages: [], + invisibleImages: {}, + invisibleId: 0, + visibilityCheckStarted: false, + debounceTimer: null, + cache: {} + }; + + //Pre-flight + + (function() { + var canvas = DOM.newEl('canvas'); + + if (canvas.getContext) { + if (canvas.toDataURL('image/png').indexOf('data:image/png') != -1) { + App.setup.renderer = 'canvas'; + App.setup.supportsCanvas = true; + } + } + + if (!!document.createElementNS && !!document.createElementNS(SVG_NS, 'svg').createSVGRect) { + App.setup.renderer = 'svg'; + App.setup.supportsSVG = true; + } + })(); + + //Starts checking for invisible placeholders + startVisibilityCheck(); + + if (onDomReady) { + onDomReady(function() { + if (!App.vars.preempted) { + Holder.run(); + } + if (global.addEventListener) { + global.addEventListener('resize', resizeEvent, false); + global.addEventListener('orientationchange', resizeEvent, false); + } else { + global.attachEvent('onresize', resizeEvent); + } + + if (typeof global.Turbolinks == 'object') { + global.document.addEventListener('page:change', function() { + Holder.run(); + }); + } + }); + } + + module.exports = Holder; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 2 */ +/***/ (function(module, exports) { + + /*! + * onDomReady.js 1.4.0 (c) 2013 Tubal Martin - MIT license + * + * Specially modified to work with Holder.js + */ + + function _onDomReady(win) { + //Lazy loading fix for Firefox < 3.6 + //http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + if (document.readyState == null && document.addEventListener) { + document.addEventListener("DOMContentLoaded", function DOMContentLoaded() { + document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false); + document.readyState = "complete"; + }, false); + document.readyState = "loading"; + } + + var doc = win.document, + docElem = doc.documentElement, + + LOAD = "load", + FALSE = false, + ONLOAD = "on"+LOAD, + COMPLETE = "complete", + READYSTATE = "readyState", + ATTACHEVENT = "attachEvent", + DETACHEVENT = "detachEvent", + ADDEVENTLISTENER = "addEventListener", + DOMCONTENTLOADED = "DOMContentLoaded", + ONREADYSTATECHANGE = "onreadystatechange", + REMOVEEVENTLISTENER = "removeEventListener", + + // W3C Event model + w3c = ADDEVENTLISTENER in doc, + _top = FALSE, + + // isReady: Is the DOM ready to be used? Set to true once it occurs. + isReady = FALSE, + + // Callbacks pending execution until DOM is ready + callbacks = []; + + // Handle when the DOM is ready + function ready( fn ) { + if ( !isReady ) { + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !doc.body ) { + return defer( ready ); + } + + // Remember that the DOM is ready + isReady = true; + + // Execute all callbacks + while ( fn = callbacks.shift() ) { + defer( fn ); + } + } + } + + // The ready event handler + function completed( event ) { + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( w3c || event.type === LOAD || doc[READYSTATE] === COMPLETE ) { + detach(); + ready(); + } + } + + // Clean-up method for dom ready events + function detach() { + if ( w3c ) { + doc[REMOVEEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + win[REMOVEEVENTLISTENER]( LOAD, completed, FALSE ); + } else { + doc[DETACHEVENT]( ONREADYSTATECHANGE, completed ); + win[DETACHEVENT]( ONLOAD, completed ); + } + } + + // Defers a function, scheduling it to run after the current call stack has cleared. + function defer( fn, wait ) { + // Allow 0 to be passed + setTimeout( fn, +wait >= 0 ? wait : 1 ); + } + + // Attach the listeners: + + // Catch cases where onDomReady is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( doc[READYSTATE] === COMPLETE ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + defer( ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( w3c ) { + // Use the handy event callback + doc[ADDEVENTLISTENER]( DOMCONTENTLOADED, completed, FALSE ); + + // A fallback to window.onload, that will always work + win[ADDEVENTLISTENER]( LOAD, completed, FALSE ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + doc[ATTACHEVENT]( ONREADYSTATECHANGE, completed ); + + // A fallback to window.onload, that will always work + win[ATTACHEVENT]( ONLOAD, completed ); + + // If IE and not a frame + // continually check to see if the document is ready + try { + _top = win.frameElement == null && docElem; + } catch(e) {} + + if ( _top && _top.doScroll ) { + (function doScrollCheck() { + if ( !isReady ) { + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + _top.doScroll("left"); + } catch(e) { + return defer( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + ready(); + } + })(); + } + } + + function onDomReady( fn ) { + // If DOM is ready, execute the function (async), otherwise wait + isReady ? defer( fn ) : callbacks.push( fn ); + } + + // Add version + onDomReady.version = "1.4.0"; + // Add method to check if DOM is ready + onDomReady.isReady = function(){ + return isReady; + }; + + return onDomReady; + } + + module.exports = typeof window !== "undefined" && _onDomReady(window); + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + //Modified version of component/querystring + //Changes: updated dependencies, dot notation parsing, JSHint fixes + //Fork at https://github.com/imsky/querystring + + /** + * Module dependencies. + */ + + var encode = encodeURIComponent; + var decode = decodeURIComponent; + var trim = __webpack_require__(4); + var type = __webpack_require__(5); + + var arrayRegex = /(\w+)\[(\d+)\]/; + var objectRegex = /\w+\.\w+/; + + /** + * Parse the given query `str`. + * + * @param {String} str + * @return {Object} + * @api public + */ + + exports.parse = function(str){ + if ('string' !== typeof str) return {}; + + str = trim(str); + if ('' === str) return {}; + if ('?' === str.charAt(0)) str = str.slice(1); + + var obj = {}; + var pairs = str.split('&'); + for (var i = 0; i < pairs.length; i++) { + var parts = pairs[i].split('='); + var key = decode(parts[0]); + var m, ctx, prop; + + if (m = arrayRegex.exec(key)) { + obj[m[1]] = obj[m[1]] || []; + obj[m[1]][m[2]] = decode(parts[1]); + continue; + } + + if (m = objectRegex.test(key)) { + m = key.split('.'); + ctx = obj; + + while (m.length) { + prop = m.shift(); + + if (!prop.length) continue; + + if (!ctx[prop]) { + ctx[prop] = {}; + } else if (ctx[prop] && typeof ctx[prop] !== 'object') { + break; + } + + if (!m.length) { + ctx[prop] = decode(parts[1]); + } + + ctx = ctx[prop]; + } + + continue; + } + + obj[parts[0]] = null == parts[1] ? '' : decode(parts[1]); + } + + return obj; + }; + + /** + * Stringify the given `obj`. + * + * @param {Object} obj + * @return {String} + * @api public + */ + + exports.stringify = function(obj){ + if (!obj) return ''; + var pairs = []; + + for (var key in obj) { + var value = obj[key]; + + if ('array' == type(value)) { + for (var i = 0; i < value.length; ++i) { + pairs.push(encode(key + '[' + i + ']') + '=' + encode(value[i])); + } + continue; + } + + pairs.push(encode(key) + '=' + encode(obj[key])); + } + + return pairs.join('&'); + }; + + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + + exports = module.exports = trim; + + function trim(str){ + return str.replace(/^\s*|\s*$/g, ''); + } + + exports.left = function(str){ + return str.replace(/^\s*/, ''); + }; + + exports.right = function(str){ + return str.replace(/\s*$/, ''); + }; + + +/***/ }), +/* 5 */ +/***/ (function(module, exports) { + + /** + * toString ref. + */ + + var toString = Object.prototype.toString; + + /** + * Return the type of `val`. + * + * @param {Mixed} val + * @return {String} + * @api public + */ + + module.exports = function(val){ + switch (toString.call(val)) { + case '[object Date]': return 'date'; + case '[object RegExp]': return 'regexp'; + case '[object Arguments]': return 'arguments'; + case '[object Array]': return 'array'; + case '[object Error]': return 'error'; + } + + if (val === null) return 'null'; + if (val === undefined) return 'undefined'; + if (val !== val) return 'nan'; + if (val && val.nodeType === 1) return 'element'; + + val = val.valueOf + ? val.valueOf() + : Object.prototype.valueOf.apply(val) + + return typeof val; + }; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports) { + + var SceneGraph = function(sceneProperties) { + var nodeCount = 1; + + //todo: move merge to helpers section + function merge(parent, child) { + for (var prop in child) { + parent[prop] = child[prop]; + } + return parent; + } + + var SceneNode = function(name) { + nodeCount++; + this.parent = null; + this.children = {}; + this.id = nodeCount; + this.name = 'n' + nodeCount; + if (typeof name !== 'undefined') { + this.name = name; + } + this.x = this.y = this.z = 0; + this.width = this.height = 0; + }; + + SceneNode.prototype.resize = function(width, height) { + if (width != null) { + this.width = width; + } + if (height != null) { + this.height = height; + } + }; + + SceneNode.prototype.moveTo = function(x, y, z) { + this.x = x != null ? x : this.x; + this.y = y != null ? y : this.y; + this.z = z != null ? z : this.z; + }; + + SceneNode.prototype.add = function(child) { + var name = child.name; + if (typeof this.children[name] === 'undefined') { + this.children[name] = child; + child.parent = this; + } else { + throw 'SceneGraph: child already exists: ' + name; + } + }; + + var RootNode = function() { + SceneNode.call(this, 'root'); + this.properties = sceneProperties; + }; + + RootNode.prototype = new SceneNode(); + + var Shape = function(name, props) { + SceneNode.call(this, name); + this.properties = { + 'fill': '#000000' + }; + if (typeof props !== 'undefined') { + merge(this.properties, props); + } else if (typeof name !== 'undefined' && typeof name !== 'string') { + throw 'SceneGraph: invalid node name'; + } + }; + + Shape.prototype = new SceneNode(); + + var Group = function() { + Shape.apply(this, arguments); + this.type = 'group'; + }; + + Group.prototype = new Shape(); + + var Rect = function() { + Shape.apply(this, arguments); + this.type = 'rect'; + }; + + Rect.prototype = new Shape(); + + var Text = function(text) { + Shape.call(this); + this.type = 'text'; + this.properties.text = text; + }; + + Text.prototype = new Shape(); + + var root = new RootNode(); + + this.Shape = { + 'Rect': Rect, + 'Text': Text, + 'Group': Group + }; + + this.root = root; + return this; + }; + + module.exports = SceneGraph; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Shallow object clone and merge + * + * @param a Object A + * @param b Object B + * @returns {Object} New object with all of A's properties, and all of B's properties, overwriting A's properties + */ + exports.extend = function(a, b) { + var c = {}; + for (var x in a) { + if (a.hasOwnProperty(x)) { + c[x] = a[x]; + } + } + if (b != null) { + for (var y in b) { + if (b.hasOwnProperty(y)) { + c[y] = b[y]; + } + } + } + return c; + }; + + /** + * Takes a k/v list of CSS properties and returns a rule + * + * @param props CSS properties object + */ + exports.cssProps = function(props) { + var ret = []; + for (var p in props) { + if (props.hasOwnProperty(p)) { + ret.push(p + ':' + props[p]); + } + } + return ret.join(';'); + }; + + /** + * Encodes HTML entities in a string + * + * @param str Input string + */ + exports.encodeHtmlEntity = function(str) { + var buf = []; + var charCode = 0; + for (var i = str.length - 1; i >= 0; i--) { + charCode = str.charCodeAt(i); + if (charCode > 128) { + buf.unshift(['&#', charCode, ';'].join('')); + } else { + buf.unshift(str[i]); + } + } + return buf.join(''); + }; + + /** + * Checks if an image exists + * + * @param src URL of image + * @param callback Callback to call once image status has been found + */ + exports.imageExists = function(src, callback) { + var image = new Image(); + image.onerror = function() { + callback.call(this, false); + }; + image.onload = function() { + callback.call(this, true); + }; + image.src = src; + }; + + /** + * Decodes HTML entities in a string + * + * @param str Input string + */ + exports.decodeHtmlEntity = function(str) { + return str.replace(/&#(\d+);/g, function(match, dec) { + return String.fromCharCode(dec); + }); + }; + + + /** + * Returns an element's dimensions if it's visible, `false` otherwise. + * + * @param el DOM element + */ + exports.dimensionCheck = function(el) { + var dimensions = { + height: el.clientHeight, + width: el.clientWidth + }; + + if (dimensions.height && dimensions.width) { + return dimensions; + } else { + return false; + } + }; + + + /** + * Returns true if value is truthy or if it is "semantically truthy" + * @param val + */ + exports.truthy = function(val) { + if (typeof val === 'string') { + return val === 'true' || val === 'yes' || val === '1' || val === 'on' || val === '✓'; + } + return !!val; + }; + + /** + * Parses input into a well-formed CSS color + * @param val + */ + exports.parseColor = function(val) { + var hexre = /(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i; + var rgbre = /^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/; + var rgbare = /^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/; + + var match = val.match(hexre); + var retval; + + if (match !== null) { + retval = match[1] || match[2]; + if (retval[0] !== '#') { + return '#' + retval; + } else { + return retval; + } + } + + match = val.match(rgbre); + + if (match !== null) { + retval = 'rgb(' + match.slice(1).join(',') + ')'; + return retval; + } + + match = val.match(rgbare); + + if (match !== null) { + const normalizeAlpha = function (a) { return '0.' + a.split('.')[1]; }; + const fixedMatch = match.slice(1).map(function (e, i) { + return (i === 3) ? normalizeAlpha(e) : e; + }); + retval = 'rgba(' + fixedMatch.join(',') + ')'; + return retval; + } + + return null; + }; + + /** + * Provides the correct scaling ratio for canvas drawing operations on HiDPI screens (e.g. Retina displays) + */ + exports.canvasRatio = function () { + var devicePixelRatio = 1; + var backingStoreRatio = 1; + + if (global.document) { + var canvas = global.document.createElement('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + devicePixelRatio = global.devicePixelRatio || 1; + backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; + } + } + + return devicePixelRatio / backingStoreRatio; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(global) {var DOM = __webpack_require__(9); + + var SVG_NS = 'http://www.w3.org/2000/svg'; + var NODE_TYPE_COMMENT = 8; + + /** + * Generic SVG element creation function + * + * @param svg SVG context, set to null if new + * @param width Document width + * @param height Document height + */ + exports.initSVG = function(svg, width, height) { + var defs, style, initialize = false; + + if (svg && svg.querySelector) { + style = svg.querySelector('style'); + if (style === null) { + initialize = true; + } + } else { + svg = DOM.newEl('svg', SVG_NS); + initialize = true; + } + + if (initialize) { + defs = DOM.newEl('defs', SVG_NS); + style = DOM.newEl('style', SVG_NS); + DOM.setAttr(style, { + 'type': 'text/css' + }); + defs.appendChild(style); + svg.appendChild(defs); + } + + //IE throws an exception if this is set and Chrome requires it to be set + if (svg.webkitMatchesSelector) { + svg.setAttribute('xmlns', SVG_NS); + } + + //Remove comment nodes + for (var i = 0; i < svg.childNodes.length; i++) { + if (svg.childNodes[i].nodeType === NODE_TYPE_COMMENT) { + svg.removeChild(svg.childNodes[i]); + } + } + + //Remove CSS + while (style.childNodes.length) { + style.removeChild(style.childNodes[0]); + } + + DOM.setAttr(svg, { + 'width': width, + 'height': height, + 'viewBox': '0 0 ' + width + ' ' + height, + 'preserveAspectRatio': 'none' + }); + + return svg; + }; + + /** + * Converts serialized SVG to a string suitable for data URI use + * @param svgString Serialized SVG string + * @param [base64] Use base64 encoding for data URI + */ + exports.svgStringToDataURI = function() { + var rawPrefix = 'data:image/svg+xml;charset=UTF-8,'; + var base64Prefix = 'data:image/svg+xml;charset=UTF-8;base64,'; + + return function(svgString, base64) { + if (base64) { + return base64Prefix + btoa(global.unescape(encodeURIComponent(svgString))); + } else { + return rawPrefix + encodeURIComponent(svgString); + } + }; + }(); + + /** + * Returns serialized SVG with XML processing instructions + * + * @param svg SVG context + * @param stylesheets CSS stylesheets to include + */ + exports.serializeSVG = function(svg, engineSettings) { + if (!global.XMLSerializer) return; + var serializer = new XMLSerializer(); + var svgCSS = ''; + var stylesheets = engineSettings.stylesheets; + + //External stylesheets: Processing Instruction method + if (engineSettings.svgXMLStylesheet) { + var xml = DOM.createXML(); + //Add directives + for (var i = stylesheets.length - 1; i >= 0; i--) { + var csspi = xml.createProcessingInstruction('xml-stylesheet', 'href="' + stylesheets[i] + '" rel="stylesheet"'); + xml.insertBefore(csspi, xml.firstChild); + } + + xml.removeChild(xml.documentElement); + svgCSS = serializer.serializeToString(xml); + } + + var svgText = serializer.serializeToString(svg); + svgText = svgText.replace(/\&(\#[0-9]{2,}\;)/g, '&$1'); + return svgCSS + svgText; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 9 */ +/***/ (function(module, exports) { + + /* WEBPACK VAR INJECTION */(function(global) {/** + * Generic new DOM element function + * + * @param tag Tag to create + * @param namespace Optional namespace value + */ + exports.newEl = function(tag, namespace) { + if (!global.document) return; + + if (namespace == null) { + return global.document.createElement(tag); + } else { + return global.document.createElementNS(namespace, tag); + } + }; + + /** + * Generic setAttribute function + * + * @param el Reference to DOM element + * @param attrs Object with attribute keys and values + */ + exports.setAttr = function (el, attrs) { + for (var a in attrs) { + el.setAttribute(a, attrs[a]); + } + }; + + /** + * Creates a XML document + * @private + */ + exports.createXML = function() { + if (!global.DOMParser) return; + return new DOMParser().parseFromString('', 'application/xml'); + }; + + /** + * Converts a value into an array of DOM nodes + * + * @param val A string, a NodeList, a Node, or an HTMLCollection + */ + exports.getNodeArray = function(val) { + var retval = null; + if (typeof(val) == 'string') { + retval = document.querySelectorAll(val); + } else if (global.NodeList && val instanceof global.NodeList) { + retval = val; + } else if (global.Node && val instanceof global.Node) { + retval = [val]; + } else if (global.HTMLCollection && val instanceof global.HTMLCollection) { + retval = val; + } else if (val instanceof Array) { + retval = val; + } else if (val === null) { + retval = []; + } + + retval = Array.prototype.slice.call(retval); + + return retval; + }; + + /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) + +/***/ }), +/* 10 */ +/***/ (function(module, exports) { + + var Color = function(color, options) { + //todo: support rgba, hsla, and rrggbbaa notation + //todo: use CIELAB internally + //todo: add clamp function (with sign) + if (typeof color !== 'string') return; + + this.original = color; + + if (color.charAt(0) === '#') { + color = color.slice(1); + } + + if (/[^a-f0-9]+/i.test(color)) return; + + if (color.length === 3) { + color = color.replace(/./g, '$&$&'); + } + + if (color.length !== 6) return; + + this.alpha = 1; + + if (options && options.alpha) { + this.alpha = options.alpha; + } + + this.set(parseInt(color, 16)); + }; + + //todo: jsdocs + Color.rgb2hex = function(r, g, b) { + function format (decimal) { + var hex = (decimal | 0).toString(16); + if (decimal < 16) { + hex = '0' + hex; + } + return hex; + } + + return [r, g, b].map(format).join(''); + }; + + //todo: jsdocs + Color.hsl2rgb = function (h, s, l) { + var H = h / 60; + var C = (1 - Math.abs(2 * l - 1)) * s; + var X = C * (1 - Math.abs(parseInt(H) % 2 - 1)); + var m = l - (C / 2); + + var r = 0, g = 0, b = 0; + + if (H >= 0 && H < 1) { + r = C; + g = X; + } else if (H >= 1 && H < 2) { + r = X; + g = C; + } else if (H >= 2 && H < 3) { + g = C; + b = X; + } else if (H >= 3 && H < 4) { + g = X; + b = C; + } else if (H >= 4 && H < 5) { + r = X; + b = C; + } else if (H >= 5 && H < 6) { + r = C; + b = X; + } + + r += m; + g += m; + b += m; + + r = parseInt(r * 255); + g = parseInt(g * 255); + b = parseInt(b * 255); + + return [r, g, b]; + }; + + /** + * Sets the color from a raw RGB888 integer + * @param raw RGB888 representation of color + */ + //todo: refactor into a static method + //todo: factor out individual color spaces + //todo: add HSL, CIELAB, and CIELUV + Color.prototype.set = function (val) { + this.raw = val; + + var r = (this.raw & 0xFF0000) >> 16; + var g = (this.raw & 0x00FF00) >> 8; + var b = (this.raw & 0x0000FF); + + // BT.709 + var y = 0.2126 * r + 0.7152 * g + 0.0722 * b; + var u = -0.09991 * r - 0.33609 * g + 0.436 * b; + var v = 0.615 * r - 0.55861 * g - 0.05639 * b; + + this.rgb = { + r: r, + g: g, + b: b + }; + + this.yuv = { + y: y, + u: u, + v: v + }; + + return this; + }; + + /** + * Lighten or darken a color + * @param multiplier Amount to lighten or darken (-1 to 1) + */ + Color.prototype.lighten = function(multiplier) { + var cm = Math.min(1, Math.max(0, Math.abs(multiplier))) * (multiplier < 0 ? -1 : 1); + var bm = (255 * cm) | 0; + var cr = Math.min(255, Math.max(0, this.rgb.r + bm)); + var cg = Math.min(255, Math.max(0, this.rgb.g + bm)); + var cb = Math.min(255, Math.max(0, this.rgb.b + bm)); + var hex = Color.rgb2hex(cr, cg, cb); + return new Color(hex); + }; + + /** + * Output color in hex format + * @param addHash Add a hash character to the beginning of the output + */ + Color.prototype.toHex = function(addHash) { + return (addHash ? '#' : '') + this.raw.toString(16); + }; + + /** + * Returns whether or not current color is lighter than another color + * @param color Color to compare against + */ + Color.prototype.lighterThan = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + return this.yuv.y > color.yuv.y; + }; + + /** + * Returns the result of mixing current color with another color + * @param color Color to mix with + * @param multiplier How much to mix with the other color + */ + /* + Color.prototype.mix = function (color, multiplier) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var r = this.rgb.r; + var g = this.rgb.g; + var b = this.rgb.b; + var a = this.alpha; + + var m = typeof multiplier !== 'undefined' ? multiplier : 0.5; + + //todo: write a lerp function + r = r + m * (color.rgb.r - r); + g = g + m * (color.rgb.g - g); + b = b + m * (color.rgb.b - b); + a = a + m * (color.alpha - a); + + return new Color(Color.rgbToHex(r, g, b), { + 'alpha': a + }); + }; + */ + + /** + * Returns the result of blending another color on top of current color with alpha + * @param color Color to blend on top of current color, i.e. "Ca" + */ + //todo: see if .blendAlpha can be merged into .mix + Color.prototype.blendAlpha = function(color) { + if (!(color instanceof Color)) { + color = new Color(color); + } + + var Ca = color; + var Cb = this; + + //todo: write alpha blending function + var r = Ca.alpha * Ca.rgb.r + (1 - Ca.alpha) * Cb.rgb.r; + var g = Ca.alpha * Ca.rgb.g + (1 - Ca.alpha) * Cb.rgb.g; + var b = Ca.alpha * Ca.rgb.b + (1 - Ca.alpha) * Cb.rgb.b; + + return new Color(Color.rgb2hex(r, g, b)); + }; + + module.exports = Color; + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + module.exports = { + 'version': '2.9.7', + 'svg_ns': 'http://www.w3.org/2000/svg' + }; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + + var shaven = __webpack_require__(13); + + var SVG = __webpack_require__(8); + var constants = __webpack_require__(11); + var utils = __webpack_require__(7); + + var SVG_NS = constants.svg_ns; + + var templates = { + 'element': function (options) { + var tag = options.tag; + var content = options.content || ''; + delete options.tag; + delete options.content; + return [tag, content, options]; + } + }; + + //todo: deprecate tag arg, infer tag from shape object + function convertShape (shape, tag) { + return templates.element({ + 'tag': tag, + 'width': shape.width, + 'height': shape.height, + 'fill': shape.properties.fill + }); + } + + function textCss (properties) { + return utils.cssProps({ + 'fill': properties.fill, + 'font-weight': properties.font.weight, + 'font-family': properties.font.family + ', monospace', + 'font-size': properties.font.size + properties.font.units + }); + } + + function outlinePath (bgWidth, bgHeight, outlineWidth) { + var outlineOffsetWidth = outlineWidth / 2; + + return [ + 'M', outlineOffsetWidth, outlineOffsetWidth, + 'H', bgWidth - outlineOffsetWidth, + 'V', bgHeight - outlineOffsetWidth, + 'H', outlineOffsetWidth, + 'V', 0, + 'M', 0, outlineOffsetWidth, + 'L', bgWidth, bgHeight - outlineOffsetWidth, + 'M', 0, bgHeight - outlineOffsetWidth, + 'L', bgWidth, outlineOffsetWidth + ].join(' '); + } + + module.exports = function (sceneGraph, renderSettings) { + var engineSettings = renderSettings.engineSettings; + var stylesheets = engineSettings.stylesheets; + var stylesheetXml = stylesheets.map(function (stylesheet) { + return ''; + }).join('\n'); + + var holderId = 'holder_' + Number(new Date()).toString(16); + + var root = sceneGraph.root; + var textGroup = root.children.holderTextGroup; + + var css = '#' + holderId + ' text { ' + textCss(textGroup.properties) + ' } '; + + // push text down to be equally vertically aligned with canvas renderer + textGroup.y += textGroup.textPositionData.boundingBox.height * 0.8; + + var wordTags = []; + + Object.keys(textGroup.children).forEach(function (lineKey) { + var line = textGroup.children[lineKey]; + + Object.keys(line.children).forEach(function (wordKey) { + var word = line.children[wordKey]; + var x = textGroup.x + line.x + word.x; + var y = textGroup.y + line.y + word.y; + var wordTag = templates.element({ + 'tag': 'text', + 'content': word.properties.text, + 'x': x, + 'y': y + }); + + wordTags.push(wordTag); + }); + }); + + var text = templates.element({ + 'tag': 'g', + 'content': wordTags + }); + + var outline = null; + + if (root.children.holderBg.properties.outline) { + var outlineProperties = root.children.holderBg.properties.outline; + outline = templates.element({ + 'tag': 'path', + 'd': outlinePath(root.children.holderBg.width, root.children.holderBg.height, outlineProperties.width), + 'stroke-width': outlineProperties.width, + 'stroke': outlineProperties.fill, + 'fill': 'none' + }); + } + + var bg = convertShape(root.children.holderBg, 'rect'); + + var sceneContent = []; + + sceneContent.push(bg); + if (outlineProperties) { + sceneContent.push(outline); + } + sceneContent.push(text); + + var scene = templates.element({ + 'tag': 'g', + 'id': holderId, + 'content': sceneContent + }); + + var style = templates.element({ + 'tag': 'style', + //todo: figure out how to add CDATA directive + 'content': css, + 'type': 'text/css' + }); + + var defs = templates.element({ + 'tag': 'defs', + 'content': style + }); + + var svg = templates.element({ + 'tag': 'svg', + 'content': [defs, scene], + 'width': root.properties.width, + 'height': root.properties.height, + 'xmlns': SVG_NS, + 'viewBox': [0, 0, root.properties.width, root.properties.height].join(' '), + 'preserveAspectRatio': 'none' + }); + + var output = shaven(svg); + + if (/\&(x)?#[0-9A-Fa-f]/.test(output[0])) { + output[0] = output[0].replace(/&#/gm, '&#'); + } + + output = stylesheetXml + output[0]; + + var svgString = SVG.svgStringToDataURI(output, renderSettings.mode === 'background'); + return svgString; + }; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + var escape = __webpack_require__(14) + + // TODO: remove namespace + + module.exports = function shaven (array, namespace, returnObject) { + + 'use strict' + + var i = 1 + var doesEscape = true + var HTMLString + var attributeKey + var callback + var key + + + returnObject = returnObject || {} + + + function createElement (sugarString) { + + var tags = sugarString.match(/^[\w-]+/) + var element = { + tag: tags ? tags[0] : 'div', + attr: {}, + children: [] + } + var id = sugarString.match(/#([\w-]+)/) + var reference = sugarString.match(/\$([\w-]+)/) + var classNames = sugarString.match(/\.[\w-]+/g) + + + // Assign id if is set + if (id) { + element.attr.id = id[1] + + // Add element to the return object + returnObject[id[1]] = element + } + + if (reference) + returnObject[reference[1]] = element + + if (classNames) + element.attr.class = classNames.join(' ').replace(/\./g, '') + + if (sugarString.match(/&$/g)) + doesEscape = false + + return element + } + + function replacer (key, value) { + + if (value === null || value === false || value === undefined) + return + + if (typeof value !== 'string' && typeof value !== 'object') + return String(value) + + return value + } + + function escapeAttribute (string) { + return (string || string === 0) ? + String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') : + '' + } + + function escapeHTML (string) { + return String(string) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>') + } + + + if (typeof array[0] === 'string') + array[0] = createElement(array[0]) + + else if (Array.isArray(array[0])) + i = 0 + + else + throw new Error( + 'First element of array must be a string, ' + + 'or an array and not ' + JSON.stringify(array[0]) + ) + + + for (; i < array.length; i++) { + + // Don't render element if value is false or null + if (array[i] === false || array[i] === null) { + array[0] = false + break + } + + // Continue with next array value if current value is undefined or true + else if (array[i] === undefined || array[i] === true) { + continue + } + + else if (typeof array[i] === 'string') { + if (doesEscape) + array[i] = escapeHTML(array[i]) + + array[0].children.push(array[i]) + } + + else if (typeof array[i] === 'number') { + + array[0].children.push(array[i]) + } + + else if (Array.isArray(array[i])) { + + if (Array.isArray(array[i][0])) { + array[i].reverse().forEach(function (subArray) { + array.splice(i + 1, 0, subArray) + }) + + if (i !== 0) + continue + i++ + } + + shaven(array[i], namespace, returnObject) + + if (array[i][0]) + array[0].children.push(array[i][0]) + } + + else if (typeof array[i] === 'function') + callback = array[i] + + + else if (typeof array[i] === 'object') { + for (attributeKey in array[i]) + if (array[i].hasOwnProperty(attributeKey)) + if (array[i][attributeKey] !== null && + array[i][attributeKey] !== false) + if (attributeKey === 'style' && + typeof array[i][attributeKey] === 'object') + array[0].attr[attributeKey] = JSON + .stringify(array[i][attributeKey], replacer) + .slice(2, -2) + .replace(/","/g, ';') + .replace(/":"/g, ':') + .replace(/\\"/g, '\'') + + else + array[0].attr[attributeKey] = array[i][attributeKey] + } + + else + throw new TypeError('"' + array[i] + '" is not allowed as a value.') + } + + + if (array[0] !== false) { + + HTMLString = '<' + array[0].tag + + for (key in array[0].attr) + if (array[0].attr.hasOwnProperty(key)) + HTMLString += ' ' + key + '="' + + escapeAttribute(array[0].attr[key]) + '"' + + HTMLString += '>' + + array[0].children.forEach(function (child) { + HTMLString += child + }) + + HTMLString += '' + + array[0] = HTMLString + } + + // Return root element on index 0 + returnObject[0] = array[0] + + if (callback) + callback(array[0]) + + // returns object containing all elements with an id and the root element + return returnObject + } + + +/***/ }), +/* 14 */ +/***/ (function(module, exports) { + + /*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */ + + 'use strict'; + + /** + * Module variables. + * @private + */ + + var matchHtmlRegExp = /["'&<>]/; + + /** + * Module exports. + * @public + */ + + module.exports = escapeHtml; + + /** + * Escape special characters in the given string of html. + * + * @param {string} string The string to escape for inserting into HTML + * @return {string} + * @public + */ + + function escapeHtml(string) { + var str = '' + string; + var match = matchHtmlRegExp.exec(str); + + if (!match) { + return str; + } + + var escape; + var html = ''; + var index = 0; + var lastIndex = 0; + + for (index = match.index; index < str.length; index++) { + switch (str.charCodeAt(index)) { + case 34: // " + escape = '"'; + break; + case 38: // & + escape = '&'; + break; + case 39: // ' + escape = '''; + break; + case 60: // < + escape = '<'; + break; + case 62: // > + escape = '>'; + break; + default: + continue; + } + + if (lastIndex !== index) { + html += str.substring(lastIndex, index); + } + + lastIndex = index + 1; + html += escape; + } + + return lastIndex !== index + ? html + str.substring(lastIndex, index) + : html; + } + + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + + var DOM = __webpack_require__(9); + var utils = __webpack_require__(7); + + module.exports = (function() { + var canvas = DOM.newEl('canvas'); + var ctx = null; + + return function(sceneGraph) { + if (ctx == null) { + ctx = canvas.getContext('2d'); + } + + var dpr = utils.canvasRatio(); + var root = sceneGraph.root; + canvas.width = dpr * root.properties.width; + canvas.height = dpr * root.properties.height ; + ctx.textBaseline = 'middle'; + + var bg = root.children.holderBg; + var bgWidth = dpr * bg.width; + var bgHeight = dpr * bg.height; + //todo: parametrize outline width (e.g. in scene object) + var outlineWidth = 2; + var outlineOffsetWidth = outlineWidth / 2; + + ctx.fillStyle = bg.properties.fill; + ctx.fillRect(0, 0, bgWidth, bgHeight); + + if (bg.properties.outline) { + //todo: abstract this into a method + ctx.strokeStyle = bg.properties.outline.fill; + ctx.lineWidth = bg.properties.outline.width; + ctx.moveTo(outlineOffsetWidth, outlineOffsetWidth); + // TL, TR, BR, BL + ctx.lineTo(bgWidth - outlineOffsetWidth, outlineOffsetWidth); + ctx.lineTo(bgWidth - outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, bgHeight - outlineOffsetWidth); + ctx.lineTo(outlineOffsetWidth, outlineOffsetWidth); + // Diagonals + ctx.moveTo(0, outlineOffsetWidth); + ctx.lineTo(bgWidth, bgHeight - outlineOffsetWidth); + ctx.moveTo(0, bgHeight - outlineOffsetWidth); + ctx.lineTo(bgWidth, outlineOffsetWidth); + ctx.stroke(); + } + + var textGroup = root.children.holderTextGroup; + ctx.font = textGroup.properties.font.weight + ' ' + (dpr * textGroup.properties.font.size) + textGroup.properties.font.units + ' ' + textGroup.properties.font.family + ', monospace'; + ctx.fillStyle = textGroup.properties.fill; + + for (var lineKey in textGroup.children) { + var line = textGroup.children[lineKey]; + for (var wordKey in line.children) { + var word = line.children[wordKey]; + var x = dpr * (textGroup.x + line.x + word.x); + var y = dpr * (textGroup.y + line.y + word.y + (textGroup.properties.leading / 2)); + + ctx.fillText(word.properties.text, x, y); + } + } + + return canvas.toDataURL('image/png'); + }; + })(); + +/***/ }) +/******/ ]) +}); +; +(function(ctx, isMeteorPackage) { + if (isMeteorPackage) { + Holder = ctx.Holder; + } +})(this, typeof Meteor !== 'undefined' && typeof Package !== 'undefined'); diff --git a/静态站点/Bootstrap5/plugs/holder/holder.min.js b/静态站点/Bootstrap5/plugs/holder/holder.min.js new file mode 100644 index 0000000..6935bf1 --- /dev/null +++ b/静态站点/Bootstrap5/plugs/holder/holder.min.js @@ -0,0 +1,14 @@ +/*! + +Holder - client side image placeholders +Version 2.9.7+5g5ho +© 2020 Ivan Malopinsky - https://imsky.co + +Site: http://holderjs.com +Issues: https://github.com/imsky/holder/issues +License: MIT + +*/ +!function(e){if(e.document){var t=e.document;t.querySelectorAll||(t.querySelectorAll=function(n){var r,i=t.createElement("style"),a=[];for(t.documentElement.firstChild.appendChild(i),t._qsa=[],i.styleSheet.cssText=n+"{x-qsa:expression(document._qsa && document._qsa.push(this))}",e.scrollBy(0,0),i.parentNode.removeChild(i);t._qsa.length;)r=t._qsa.shift(),r.style.removeAttribute("x-qsa"),a.push(r);return t._qsa=null,a}),t.querySelector||(t.querySelector=function(e){var n=t.querySelectorAll(e);return n.length?n[0]:null}),t.getElementsByClassName||(t.getElementsByClassName=function(e){return e=String(e).replace(/^|\s+/g,"."),t.querySelectorAll(e)}),Object.keys||(Object.keys=function(e){if(e!==Object(e))throw TypeError("Object.keys called on non-object");var t,n=[];for(t in e)Object.prototype.hasOwnProperty.call(e,t)&&n.push(t);return n}),Array.prototype.forEach||(Array.prototype.forEach=function(e){if(void 0===this||null===this)throw TypeError();var t=Object(this),n=t.length>>>0;if("function"!=typeof e)throw TypeError();var r,i=arguments[1];for(r=0;n>r;r++)r in t&&e.call(i,t[r],r,t)}),function(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";e.atob=e.atob||function(e){e=String(e);var n,r=0,i=[],a=0,o=0;if(e=e.replace(/\s/g,""),e.length%4===0&&(e=e.replace(/=+$/,"")),e.length%4===1)throw Error("InvalidCharacterError");if(/[^+\/0-9A-Za-z]/.test(e))throw Error("InvalidCharacterError");for(;r>16&255)),i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a)),o=0,a=0),r+=1;return 12===o?(a>>=4,i.push(String.fromCharCode(255&a))):18===o&&(a>>=2,i.push(String.fromCharCode(a>>8&255)),i.push(String.fromCharCode(255&a))),i.join("")},e.btoa=e.btoa||function(e){e=String(e);var n,r,i,a,o,s,l,h=0,u=[];if(/[^\x00-\xFF]/.test(e))throw Error("InvalidCharacterError");for(;h>2,o=(3&n)<<4|r>>4,s=(15&r)<<2|i>>6,l=63&i,h===e.length+2?(s=64,l=64):h===e.length+1&&(l=64),u.push(t.charAt(a),t.charAt(o),t.charAt(s),t.charAt(l));return u.join("")}}(e),Object.prototype.hasOwnProperty||(Object.prototype.hasOwnProperty=function(e){var t=this.__proto__||this.constructor.prototype;return e in this&&(!(e in t)||t[e]!==this[e])}),function(){if("performance"in e==!1&&(e.performance={}),Date.now=Date.now||function(){return(new Date).getTime()},"now"in e.performance==!1){var t=Date.now();performance.timing&&performance.timing.navigationStart&&(t=performance.timing.navigationStart),e.performance.now=function(){return Date.now()-t}}}(),e.requestAnimationFrame||(e.webkitRequestAnimationFrame&&e.webkitCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return webkitRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.webkitCancelAnimationFrame}(e):e.mozRequestAnimationFrame&&e.mozCancelAnimationFrame?!function(e){e.requestAnimationFrame=function(t){return mozRequestAnimationFrame(function(){t(e.performance.now())})},e.cancelAnimationFrame=e.mozCancelAnimationFrame}(e):!function(e){e.requestAnimationFrame=function(t){return e.setTimeout(t,1e3/60)},e.cancelAnimationFrame=e.clearTimeout}(e))}}(this),function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Holder=t():e.Holder=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){(function(t){function r(e,t,n,r){var o=i(n.substr(n.lastIndexOf(e.domain)),e);o&&a({mode:null,el:r,flags:o,engineSettings:t})}function i(e,t){var n={theme:T(O.settings.themes.gray,null),stylesheets:t.stylesheets,instanceOptions:t},r=e.indexOf("?"),i=[e];-1!==r&&(i=[e.slice(0,r),e.slice(r+1)]);var a=i[0].split("/");n.holderURL=e;var o=a[1],s=o.match(/([\d]+p?)x([\d]+p?)/);if(!s)return!1;if(n.fluid=-1!==o.indexOf("p"),n.dimensions={width:s[1].replace("p","%"),height:s[2].replace("p","%")},2===i.length){var l=v.parse(i[1]);if(w.truthy(l.ratio)){n.fluid=!0;var h=parseFloat(n.dimensions.width.replace("%","")),u=parseFloat(n.dimensions.height.replace("%",""));u=Math.floor(100*(u/h)),h=100,n.dimensions.width=h+"%",n.dimensions.height=u+"%"}if(n.auto=w.truthy(l.auto),l.bg&&(n.theme.bg=w.parseColor(l.bg)),l.fg&&(n.theme.fg=w.parseColor(l.fg)),l.bg&&!l.fg&&(n.autoFg=!0),l.theme&&n.instanceOptions.themes.hasOwnProperty(l.theme)&&(n.theme=T(n.instanceOptions.themes[l.theme],null)),l.text&&(n.text=l.text),l.textmode&&(n.textmode=l.textmode),l.size&&parseFloat(l.size)&&(n.size=parseFloat(l.size)),l.font&&(n.font=l.font),l.align&&(n.align=l.align),l.lineWrap&&(n.lineWrap=l.lineWrap),n.nowrap=w.truthy(l.nowrap),n.outline=w.truthy(l.outline),w.truthy(l.random)){O.vars.cache.themeKeys=O.vars.cache.themeKeys||Object.keys(n.instanceOptions.themes);var d=O.vars.cache.themeKeys[0|Math.random()*O.vars.cache.themeKeys.length];n.theme=T(n.instanceOptions.themes[d],null)}}return n}function a(e){var t=e.mode,n=e.el,r=e.flags,i=e.engineSettings,a=r.dimensions,s=r.theme,l=a.width+"x"+a.height;t=null==t?r.fluid?"fluid":"image":t;var d=/holder_([a-z]+)/g,c=!1;if(null!=r.text&&(s.text=r.text,"object"===n.nodeName.toLowerCase())){for(var f=s.text.split("\\n"),p=0;p1){var b,x=0,A=0,C=0;w=new s.Group("line"+C),("left"===e.align||"right"===e.align)&&(a=e.width*(1-2*(1-r)));for(var E=0;E=a||k===!0)&&(t(g,w,x,g.properties.leading),g.add(w),x=0,A+=g.properties.leading,C+=1,w=new s.Group("line"+C),w.y=A),k!==!0&&(v.moveTo(x,0),x+=m.spaceWidth+T.width,w.add(v))}if(t(g,w,x,g.properties.leading),g.add(w),"left"===e.align)g.moveTo(e.width-i,null,null);else if("right"===e.align){for(b in g.children)w=g.children[b],w.moveTo(e.width-w.width,null,null);g.moveTo(0-(e.width-i),null,null)}else{for(b in g.children)w=g.children[b],w.moveTo((g.width-w.width)/2,null,null);g.moveTo((e.width-g.width)/2,null,null)}g.moveTo(null,(e.height-g.height)/2,null),(e.height-g.height)/2<0&&g.moveTo(null,0,null)}else v=new s.Text(e.text),w=new s.Group("line0"),w.add(v),g.add(w),"left"===e.align?g.moveTo(e.width-i,null,null):"right"===e.align?g.moveTo(0-(e.width-i),null,null):g.moveTo((e.width-m.boundingBox.width)/2,null,null),g.moveTo(null,(e.height-m.boundingBox.height)/2,null);return o}function l(e,t,n,r){var i=parseInt(e,10),a=parseInt(t,10),o=Math.max(i,a),s=Math.min(i,a),l=.8*Math.min(s,o*r);return Math.round(Math.max(n,l))}function h(e){var t;t=null==e||null==e.nodeType?O.vars.resizableImages:[e];for(var n=0,r=t.length;r>n;n++){var i=t[n];if(i.holderData){var a=i.holderData.flags,s=k(i);if(s){if(!i.holderData.resizeUpdate)continue;if(a.fluid&&a.auto){var l=i.holderData.fluidConfig;switch(l.mode){case"width":s.height=s.width/l.ratio;break;case"height":s.width=s.height*l.ratio}}var h={mode:"image",holderSettings:{dimensions:s,theme:a.theme,flags:a},el:i,engineSettings:i.holderData.engineSettings};"exact"==a.textmode&&(a.exactDimensions=s,h.holderSettings.dimensions=a.dimensions),o(h)}else f(i)}}}function u(e){if(e.holderData){var t=k(e);if(t){var n=e.holderData.flags,r={fluidHeight:"%"==n.dimensions.height.slice(-1),fluidWidth:"%"==n.dimensions.width.slice(-1),mode:null,initialDimensions:t};r.fluidWidth&&!r.fluidHeight?(r.mode="width",r.ratio=r.initialDimensions.width/parseFloat(n.dimensions.height)):!r.fluidWidth&&r.fluidHeight&&(r.mode="height",r.ratio=parseFloat(n.dimensions.width)/r.initialDimensions.height),e.holderData.fluidConfig=r}else f(e)}}function d(){var e,n=[],r=Object.keys(O.vars.invisibleImages);r.forEach(function(t){e=O.vars.invisibleImages[t],k(e)&&"img"==e.nodeName.toLowerCase()&&(n.push(e),delete O.vars.invisibleImages[t])}),n.length&&j.run({images:n}),setTimeout(function(){t.requestAnimationFrame(d)},10)}function c(){O.vars.visibilityCheckStarted||(t.requestAnimationFrame(d),O.vars.visibilityCheckStarted=!0)}function f(e){e.holderData.invisibleId||(O.vars.invisibleId+=1,O.vars.invisibleImages["i"+O.vars.invisibleId]=e,e.holderData.invisibleId=O.vars.invisibleId)}function p(e){O.vars.debounceTimer||e.call(this),O.vars.debounceTimer&&t.clearTimeout(O.vars.debounceTimer),O.vars.debounceTimer=t.setTimeout(function(){O.vars.debounceTimer=null,e.call(this)},O.setup.debounce)}function g(){p(function(){h(null)})}var m=n(2),v=n(3),y=n(6),w=n(7),b=n(8),x=n(9),S=n(10),A=n(11),C=n(12),E=n(15),T=w.extend,k=w.dimensionCheck,F=A.svg_ns,j={version:A.version,addTheme:function(e,t){return null!=e&&null!=t&&(O.settings.themes[e]=t),delete O.vars.cache.themeKeys,this},addImage:function(e,t){var n=x.getNodeArray(t);return n.forEach(function(t){var n=x.newEl("img"),r={};r[O.setup.dataAttr]=e,x.setAttr(n,r),t.appendChild(n)}),this},setResizeUpdate:function(e,t){e.holderData&&(e.holderData.resizeUpdate=!!t,e.holderData.resizeUpdate&&h(e))},run:function(e){e=e||{};var n={},o=T(O.settings,e);O.vars.preempted=!0,O.vars.dataAttr=o.dataAttr||O.setup.dataAttr,n.renderer=o.renderer?o.renderer:O.setup.renderer,-1===O.setup.renderers.join(",").indexOf(n.renderer)&&(n.renderer=O.setup.supportsSVG?"svg":O.setup.supportsCanvas?"canvas":"html");var s=x.getNodeArray(o.images),l=x.getNodeArray(o.bgnodes),h=x.getNodeArray(o.stylenodes),u=x.getNodeArray(o.objects);return n.stylesheets=[],n.svgXMLStylesheet=!0,n.noFontFallback=!!o.noFontFallback,n.noBackgroundSize=!!o.noBackgroundSize,h.forEach(function(e){if(e.attributes.rel&&e.attributes.href&&"stylesheet"==e.attributes.rel.value){var t=e.attributes.href.value,r=x.newEl("a");r.href=t;var i=r.protocol+"//"+r.host+r.pathname+r.search;n.stylesheets.push(i)}}),l.forEach(function(e){if(t.getComputedStyle){var r=t.getComputedStyle(e,null).getPropertyValue("background-image"),s=e.getAttribute("data-background-src"),l=s||r,h=null,u=o.domain+"/",d=l.indexOf(u);if(0===d)h=l;else if(1===d&&"?"===l[0])h=l.slice(1);else{var c=l.substr(d).match(/([^\"]*)"?\)/);if(null!==c)h=c[1];else if(0===l.indexOf("url("))throw"Holder: unable to parse background URL: "+l}if(h){var f=i(h,o);f&&a({mode:"background",el:e,flags:f,engineSettings:n})}}}),u.forEach(function(e){var t={};try{t.data=e.getAttribute("data"),t.dataSrc=e.getAttribute(O.vars.dataAttr)}catch(i){}var a=null!=t.data&&0===t.data.indexOf(o.domain),s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain);a?r(o,n,t.data,e):s&&r(o,n,t.dataSrc,e)}),s.forEach(function(e){var t={};try{t.src=e.getAttribute("src"),t.dataSrc=e.getAttribute(O.vars.dataAttr),t.rendered=e.getAttribute("data-holder-rendered")}catch(i){}var a=null!=t.src,s=null!=t.dataSrc&&0===t.dataSrc.indexOf(o.domain),l=null!=t.rendered&&"true"==t.rendered;a?0===t.src.indexOf(o.domain)?r(o,n,t.src,e):s&&(l?r(o,n,t.dataSrc,e):!function(e,t,n,i,a){w.imageExists(e,function(e){e||r(t,n,i,a)})}(t.src,o,n,t.dataSrc,e)):s&&r(o,n,t.dataSrc,e)}),this}},O={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}},z=function(){var e=null,t=null,n=null;return function(r){var i=r.root;if(O.setup.supportsSVG){var a=!1,o=function(e){return document.createTextNode(e)};(null==e||e.parentNode!==document.body)&&(a=!0),e=b.initSVG(e,i.properties.width,i.properties.height),e.style.display="block",a&&(t=x.newEl("text",F),n=o(null),x.setAttr(t,{x:0}),t.appendChild(n),e.appendChild(t),document.body.appendChild(e),e.style.visibility="hidden",e.style.position="absolute",e.style.top="-100%",e.style.left="-100%");var s=i.children.holderTextGroup,l=s.properties;x.setAttr(t,{y:l.font.size,style:w.cssProps({"font-weight":l.font.weight,"font-size":l.font.size+l.font.units,"font-family":l.font.family})});var h=x.newEl("textarea");h.innerHTML=l.text,n.nodeValue=h.value;var u=t.getBBox(),d=Math.ceil(u.width/i.properties.width),c=l.text.split(" "),f=l.text.match(/\\n/g);d+=null==f?0:f.length,n.nodeValue=l.text.replace(/[ ]+/g,"");var p=t.getComputedTextLength(),g=u.width-p,m=Math.round(g/Math.max(1,c.length-1)),v=[];if(d>1){n.nodeValue="";for(var y=0;y=0?t:1)}function a(e){x?i(e):S.push(e)}null==document.readyState&&document.addEventListener&&(document.addEventListener("DOMContentLoaded",function C(){document.removeEventListener("DOMContentLoaded",C,!1),document.readyState="complete"},!1),document.readyState="loading");var o=e.document,s=o.documentElement,l="load",h=!1,u="on"+l,d="complete",c="readyState",f="attachEvent",p="detachEvent",g="addEventListener",m="DOMContentLoaded",v="onreadystatechange",y="removeEventListener",w=g in o,b=h,x=h,S=[];if(o[c]===d)i(t);else if(w)o[g](m,n,h),e[g](l,n,h);else{o[f](v,n),e[f](u,n);try{b=null==e.frameElement&&s}catch(A){}b&&b.doScroll&&!function E(){if(!x){try{b.doScroll("left")}catch(e){return i(E,50)}r(),t()}}()}return a.version="1.4.0",a.isReady=function(){return x},a}e.exports="undefined"!=typeof window&&n(window)},function(e,t,n){var r=encodeURIComponent,i=decodeURIComponent,a=n(4),o=n(5),s=/(\w+)\[(\d+)\]/,l=/\w+\.\w+/;t.parse=function(e){if("string"!=typeof e)return{};if(e=a(e),""===e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t={},n=e.split("&"),r=0;r=0;r--)n=e.charCodeAt(r),t.unshift(n>128?["&#",n,";"].join(""):e[r]);return t.join("")},t.imageExists=function(e,t){var n=new Image;n.onerror=function(){t.call(this,!1)},n.onload=function(){t.call(this,!0)},n.src=e},t.decodeHtmlEntity=function(e){return e.replace(/&#(\d+);/g,function(e,t){return String.fromCharCode(t)})},t.dimensionCheck=function(e){var t={height:e.clientHeight,width:e.clientWidth};return t.height&&t.width?t:!1},t.truthy=function(e){return"string"==typeof e?"true"===e||"yes"===e||"1"===e||"on"===e||"✓"===e:!!e},t.parseColor=function(e){var t,n=/(^(?:#?)[0-9a-f]{6}$)|(^(?:#?)[0-9a-f]{3}$)/i,r=/^rgb\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/,i=/^rgba\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0*\.\d{1,}|1)\)$/,a=e.match(n);if(null!==a)return t=a[1]||a[2],"#"!==t[0]?"#"+t:t;if(a=e.match(r),null!==a)return t="rgb("+a.slice(1).join(",")+")";if(a=e.match(i),null!==a){const o=function(e){return"0."+e.split(".")[1]},s=a.slice(1).map(function(e,t){return 3===t?o(e):e});return t="rgba("+s.join(",")+")"}return null},t.canvasRatio=function(){var t=1,n=1;if(e.document){var r=e.document.createElement("canvas");if(r.getContext){var i=r.getContext("2d");t=e.devicePixelRatio||1,n=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1}}return t/n}}).call(t,function(){return this}())},function(e,t,n){(function(e){var r=n(9),i="http://www.w3.org/2000/svg",a=8;t.initSVG=function(e,t,n){var o,s,l=!1;e&&e.querySelector?(s=e.querySelector("style"),null===s&&(l=!0)):(e=r.newEl("svg",i),l=!0),l&&(o=r.newEl("defs",i),s=r.newEl("style",i),r.setAttr(s,{type:"text/css"}),o.appendChild(s),e.appendChild(o)),e.webkitMatchesSelector&&e.setAttribute("xmlns",i);for(var h=0;h=0;l--){var h=s.createProcessingInstruction("xml-stylesheet",'href="'+o[l]+'" rel="stylesheet"');s.insertBefore(h,s.firstChild)}s.removeChild(s.documentElement),a=i.serializeToString(s)}var u=i.serializeToString(t);return u=u.replace(/\&(\#[0-9]{2,}\;)/g,"&$1"),a+u}}}).call(t,function(){return this}())},function(e,t){(function(e){t.newEl=function(t,n){return e.document?null==n?e.document.createElement(t):e.document.createElementNS(n,t):void 0},t.setAttr=function(e,t){for(var n in t)e.setAttribute(n,t[n])},t.createXML=function(){return e.DOMParser?(new DOMParser).parseFromString("","application/xml"):void 0},t.getNodeArray=function(t){var n=null;return"string"==typeof t?n=document.querySelectorAll(t):e.NodeList&&t instanceof e.NodeList?n=t:e.Node&&t instanceof e.Node?n=[t]:e.HTMLCollection&&t instanceof e.HTMLCollection?n=t:t instanceof Array?n=t:null===t&&(n=[]),n=Array.prototype.slice.call(n)}}).call(t,function(){return this}())},function(e,t){var n=function(e,t){"string"==typeof e&&(this.original=e,"#"===e.charAt(0)&&(e=e.slice(1)),/[^a-f0-9]+/i.test(e)||(3===e.length&&(e=e.replace(/./g,"$&$&")),6===e.length&&(this.alpha=1,t&&t.alpha&&(this.alpha=t.alpha),this.set(parseInt(e,16)))))};n.rgb2hex=function(e,t,n){function r(e){var t=(0|e).toString(16);return 16>e&&(t="0"+t),t}return[e,t,n].map(r).join("")},n.hsl2rgb=function(e,t,n){var r=e/60,i=(1-Math.abs(2*n-1))*t,a=i*(1-Math.abs(parseInt(r)%2-1)),o=n-i/2,s=0,l=0,h=0;return r>=0&&1>r?(s=i,l=a):r>=1&&2>r?(s=a,l=i):r>=2&&3>r?(l=i,h=a):r>=3&&4>r?(l=a,h=i):r>=4&&5>r?(s=a,h=i):r>=5&&6>r&&(s=i,h=a),s+=o,l+=o,h+=o,s=parseInt(255*s),l=parseInt(255*l),h=parseInt(255*h),[s,l,h]},n.prototype.set=function(e){this.raw=e;var t=(16711680&this.raw)>>16,n=(65280&this.raw)>>8,r=255&this.raw,i=.2126*t+.7152*n+.0722*r,a=-.09991*t-.33609*n+.436*r,o=.615*t-.55861*n-.05639*r;return this.rgb={r:t,g:n,b:r},this.yuv={y:i,u:a,v:o},this},n.prototype.lighten=function(e){var t=Math.min(1,Math.max(0,Math.abs(e)))*(0>e?-1:1),r=255*t|0,i=Math.min(255,Math.max(0,this.rgb.r+r)),a=Math.min(255,Math.max(0,this.rgb.g+r)),o=Math.min(255,Math.max(0,this.rgb.b+r)),s=n.rgb2hex(i,a,o);return new n(s)},n.prototype.toHex=function(e){return(e?"#":"")+this.raw.toString(16)},n.prototype.lighterThan=function(e){return e instanceof n||(e=new n(e)),this.yuv.y>e.yuv.y},n.prototype.blendAlpha=function(e){e instanceof n||(e=new n(e));var t=e,r=this,i=t.alpha*t.rgb.r+(1-t.alpha)*r.rgb.r,a=t.alpha*t.rgb.g+(1-t.alpha)*r.rgb.g,o=t.alpha*t.rgb.b+(1-t.alpha)*r.rgb.b;return new n(n.rgb2hex(i,a,o))},e.exports=n},function(e,t){e.exports={version:"2.9.7",svg_ns:"http://www.w3.org/2000/svg"}},function(e,t,n){function r(e,t){return d.element({tag:t,width:e.width,height:e.height,fill:e.properties.fill})}function i(e){return h.cssProps({fill:e.fill,"font-weight":e.font.weight,"font-family":e.font.family+", monospace","font-size":e.font.size+e.font.units})}function a(e,t,n){var r=n/2;return["M",r,r,"H",e-r,"V",t-r,"H",r,"V",0,"M",0,r,"L",e,t-r,"M",0,t-r,"L",e,r].join(" ")}var o=n(13),s=n(8),l=n(11),h=n(7),u=l.svg_ns,d={element:function(e){var t=e.tag,n=e.content||"";return delete e.tag,delete e.content,[t,n,e]}};e.exports=function(e,t){var n=t.engineSettings,l=n.stylesheets,h=l.map(function(e){return''}).join("\n"),c="holder_"+Number(new Date).toString(16),f=e.root,p=f.children.holderTextGroup,g="#"+c+" text { "+i(p.properties)+" } ";p.y+=.8*p.textPositionData.boundingBox.height;var m=[];Object.keys(p.children).forEach(function(e){var t=p.children[e];Object.keys(t.children).forEach(function(e){var n=t.children[e],r=p.x+t.x+n.x,i=p.y+t.y+n.y,a=d.element({tag:"text",content:n.properties.text,x:r,y:i});m.push(a)})});var v=d.element({tag:"g",content:m}),y=null;if(f.children.holderBg.properties.outline){var w=f.children.holderBg.properties.outline;y=d.element({tag:"path",d:a(f.children.holderBg.width,f.children.holderBg.height,w.width),"stroke-width":w.width,stroke:w.fill,fill:"none"})}var b=r(f.children.holderBg,"rect"),x=[];x.push(b),w&&x.push(y),x.push(v);var S=d.element({tag:"g",id:c,content:x}),A=d.element({tag:"style",content:g,type:"text/css"}),C=d.element({tag:"defs",content:A}),E=d.element({tag:"svg",content:[C,S],width:f.properties.width,height:f.properties.height,xmlns:u,viewBox:[0,0,f.properties.width,f.properties.height].join(" "),preserveAspectRatio:"none"}),T=o(E);/\&(x)?#[0-9A-Fa-f]/.test(T[0])&&(T[0]=T[0].replace(/&#/gm,"&#")),T=h+T[0];var k=s.svgStringToDataURI(T,"background"===t.mode);return k}},function(e,t,n){n(14);e.exports=function r(e,t,n){"use strict";function i(e){var t=e.match(/^[\w-]+/),r={tag:t?t[0]:"div",attr:{},children:[]},i=e.match(/#([\w-]+)/),a=e.match(/\$([\w-]+)/),o=e.match(/\.[\w-]+/g);return i&&(r.attr.id=i[1],n[i[1]]=r),a&&(n[a[1]]=r),o&&(r.attr["class"]=o.join(" ").replace(/\./g,"")),e.match(/&$/g)&&(f=!1),r}function a(e,t){return null!==t&&t!==!1&&void 0!==t?"string"!=typeof t&&"object"!=typeof t?String(t):t:void 0}function o(e){return e||0===e?String(e).replace(/&/g,"&").replace(/"/g,"""):""}function s(e){return String(e).replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(//g,">")}var l,h,u,d,c=1,f=!0;if(n=n||{},"string"==typeof e[0])e[0]=i(e[0]);else{if(!Array.isArray(e[0]))throw new Error("First element of array must be a string, or an array and not "+JSON.stringify(e[0]));c=0}for(;c",e[0]=l}return n[0]=e[0],u&&u(e[0]),n}},function(e,t){"use strict";function n(e){var t=""+e,n=r.exec(t);if(!n)return t;var i,a="",o=0,s=0;for(o=n.index;o]/;e.exports=n},function(e,t,n){var r=n(9),i=n(7);e.exports=function(){var e=r.newEl("canvas"),t=null;return function(n){null==t&&(t=e.getContext("2d"));var r=i.canvasRatio(),a=n.root;e.width=r*a.properties.width,e.height=r*a.properties.height,t.textBaseline="middle";var o=a.children.holderBg,s=r*o.width,l=r*o.height,h=2,u=h/2;t.fillStyle=o.properties.fill,t.fillRect(0,0,s,l),o.properties.outline&&(t.strokeStyle=o.properties.outline.fill,t.lineWidth=o.properties.outline.width,t.moveTo(u,u),t.lineTo(s-u,u),t.lineTo(s-u,l-u),t.lineTo(u,l-u),t.lineTo(u,u),t.moveTo(0,u),t.lineTo(s,l-u),t.moveTo(0,l-u),t.lineTo(s,u),t.stroke());var d=a.children.holderTextGroup;t.font=d.properties.font.weight+" "+r*d.properties.font.size+d.properties.font.units+" "+d.properties.font.family+", monospace",t.fillStyle=d.properties.fill;for(var c in d.children){var f=d.children[c];for(var p in f.children){var g=f.children[p],m=r*(d.x+f.x+g.x),v=r*(d.y+f.y+g.y+d.properties.leading/2); + +t.fillText(g.properties.text,m,v)}}return e.toDataURL("image/png")}}()}])}),function(e,t){t&&(Holder=e.Holder)}(this,"undefined"!=typeof Meteor&&"undefined"!=typeof Package); \ No newline at end of file