123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- /*! npm.im/object-fit-images 3.2.4 */
- var objectFitImages = (function () {
- 'use strict';
- var OFI = 'fregante:object-fit-images';
- var propRegex = /(object-fit|object-position)\s*:\s*([-.\w\s%]+)/g;
- var testImg = typeof Image === 'undefined' ? {style: {'object-position': 1}} : new Image();
- var supportsObjectFit = 'object-fit' in testImg.style;
- var supportsObjectPosition = 'object-position' in testImg.style;
- var supportsOFI = 'background-size' in testImg.style;
- var supportsCurrentSrc = typeof testImg.currentSrc === 'string';
- var nativeGetAttribute = testImg.getAttribute;
- var nativeSetAttribute = testImg.setAttribute;
- var autoModeEnabled = false;
- function createPlaceholder(w, h) {
- return ("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='" + w + "' height='" + h + "'%3E%3C/svg%3E");
- }
- function polyfillCurrentSrc(el) {
- if (el.srcset && !supportsCurrentSrc && window.picturefill) {
- var pf = window.picturefill._;
- // parse srcset with picturefill where currentSrc isn't available
- if (!el[pf.ns] || !el[pf.ns].evaled) {
- // force synchronous srcset parsing
- pf.fillImg(el, {reselect: true});
- }
- if (!el[pf.ns].curSrc) {
- // force picturefill to parse srcset
- el[pf.ns].supported = false;
- pf.fillImg(el, {reselect: true});
- }
- // retrieve parsed currentSrc, if any
- el.currentSrc = el[pf.ns].curSrc || el.src;
- }
- }
- function getStyle(el) {
- var style = getComputedStyle(el).fontFamily;
- var parsed;
- var props = {};
- while ((parsed = propRegex.exec(style)) !== null) {
- props[parsed[1]] = parsed[2];
- }
- return props;
- }
- function setPlaceholder(img, width, height) {
- // Default: fill width, no height
- var placeholder = createPlaceholder(width || 1, height || 0);
- // Only set placeholder if it's different
- if (nativeGetAttribute.call(img, 'src') !== placeholder) {
- nativeSetAttribute.call(img, 'src', placeholder);
- }
- }
- function onImageReady(img, callback) {
- // naturalWidth is only available when the image headers are loaded,
- // this loop will poll it every 100ms.
- if (img.naturalWidth) {
- callback(img);
- } else {
- setTimeout(onImageReady, 100, img, callback);
- }
- }
- function fixOne(el) {
- var style = getStyle(el);
- var ofi = el[OFI];
- style['object-fit'] = style['object-fit'] || 'fill'; // default value
- // Avoid running where unnecessary, unless OFI had already done its deed
- if (!ofi.img) {
- // fill is the default behavior so no action is necessary
- if (style['object-fit'] === 'fill') {
- return;
- }
- // Where object-fit is supported and object-position isn't (Safari < 10)
- if (
- !ofi.skipTest && // unless user wants to apply regardless of browser support
- supportsObjectFit && // if browser already supports object-fit
- !style['object-position'] // unless object-position is used
- ) {
- return;
- }
- }
- // keep a clone in memory while resetting the original to a blank
- if (!ofi.img) {
- ofi.img = new Image(el.width, el.height);
- ofi.img.srcset = nativeGetAttribute.call(el, "data-ofi-srcset") || el.srcset;
- ofi.img.src = nativeGetAttribute.call(el, "data-ofi-src") || el.src;
- // preserve for any future cloneNode calls
- // https://github.com/fregante/object-fit-images/issues/53
- nativeSetAttribute.call(el, "data-ofi-src", el.src);
- if (el.srcset) {
- nativeSetAttribute.call(el, "data-ofi-srcset", el.srcset);
- }
- setPlaceholder(el, el.naturalWidth || el.width, el.naturalHeight || el.height);
- // remove srcset because it overrides src
- if (el.srcset) {
- el.srcset = '';
- }
- try {
- keepSrcUsable(el);
- } catch (err) {
- if (window.console) {
- console.warn('https://bit.ly/ofi-old-browser');
- }
- }
- }
- polyfillCurrentSrc(ofi.img);
- el.style.backgroundImage = "url(\"" + ((ofi.img.currentSrc || ofi.img.src).replace(/"/g, '\\"')) + "\")";
- el.style.backgroundPosition = style['object-position'] || 'center';
- el.style.backgroundRepeat = 'no-repeat';
- el.style.backgroundOrigin = 'content-box';
- if (/scale-down/.test(style['object-fit'])) {
- onImageReady(ofi.img, function () {
- if (ofi.img.naturalWidth > el.width || ofi.img.naturalHeight > el.height) {
- el.style.backgroundSize = 'contain';
- } else {
- el.style.backgroundSize = 'auto';
- }
- });
- } else {
- el.style.backgroundSize = style['object-fit'].replace('none', 'auto').replace('fill', '100% 100%');
- }
- onImageReady(ofi.img, function (img) {
- setPlaceholder(el, img.naturalWidth, img.naturalHeight);
- });
- }
- function keepSrcUsable(el) {
- var descriptors = {
- get: function get(prop) {
- return el[OFI].img[prop ? prop : 'src'];
- },
- set: function set(value, prop) {
- el[OFI].img[prop ? prop : 'src'] = value;
- nativeSetAttribute.call(el, ("data-ofi-" + prop), value); // preserve for any future cloneNode
- fixOne(el);
- return value;
- }
- };
- Object.defineProperty(el, 'src', descriptors);
- Object.defineProperty(el, 'currentSrc', {
- get: function () { return descriptors.get('currentSrc'); }
- });
- Object.defineProperty(el, 'srcset', {
- get: function () { return descriptors.get('srcset'); },
- set: function (ss) { return descriptors.set(ss, 'srcset'); }
- });
- }
- function hijackAttributes() {
- function getOfiImageMaybe(el, name) {
- return el[OFI] && el[OFI].img && (name === 'src' || name === 'srcset') ? el[OFI].img : el;
- }
- if (!supportsObjectPosition) {
- HTMLImageElement.prototype.getAttribute = function (name) {
- return nativeGetAttribute.call(getOfiImageMaybe(this, name), name);
- };
- HTMLImageElement.prototype.setAttribute = function (name, value) {
- return nativeSetAttribute.call(getOfiImageMaybe(this, name), name, String(value));
- };
- }
- }
- function fix(imgs, opts) {
- var startAutoMode = !autoModeEnabled && !imgs;
- opts = opts || {};
- imgs = imgs || 'img';
- if ((supportsObjectPosition && !opts.skipTest) || !supportsOFI) {
- return false;
- }
- // use imgs as a selector or just select all images
- if (imgs === 'img') {
- imgs = document.getElementsByTagName('img');
- } else if (typeof imgs === 'string') {
- imgs = document.querySelectorAll(imgs);
- } else if (!('length' in imgs)) {
- imgs = [imgs];
- }
- // apply fix to all
- for (var i = 0; i < imgs.length; i++) {
- imgs[i][OFI] = imgs[i][OFI] || {
- skipTest: opts.skipTest
- };
- fixOne(imgs[i]);
- }
- if (startAutoMode) {
- document.body.addEventListener('load', function (e) {
- if (e.target.tagName === 'IMG') {
- fix(e.target, {
- skipTest: opts.skipTest
- });
- }
- }, true);
- autoModeEnabled = true;
- imgs = 'img'; // reset to a generic selector for watchMQ
- }
- // if requested, watch media queries for object-fit change
- if (opts.watchMQ) {
- window.addEventListener('resize', fix.bind(null, imgs, {
- skipTest: opts.skipTest
- }));
- }
- }
- fix.supportsObjectFit = supportsObjectFit;
- fix.supportsObjectPosition = supportsObjectPosition;
- hijackAttributes();
- return fix;
- }());
|