Skip to content

Commit

Permalink
Update to the correct 2.0 release
Browse files Browse the repository at this point in the history
Signed-off-by: Charlie Gracie <charlie.gracie@gmail.com>
  • Loading branch information
charliegracie committed Feb 7, 2017
1 parent fd73004 commit cfe5f2c
Showing 1 changed file with 217 additions and 2 deletions.
219 changes: 217 additions & 2 deletions js/retina.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,218 @@
// retina.js, a high-resolution image swapper (http://retinajs.com), v0.0.2
/*!
* Retina.js v2.0.0
*
* Copyright 2016 Axial, LLC
* Released under the MIT license
*
* Retina.js is an open source script that makes it easy to serve
* high-resolution images to devices with retina displays.
*/
'use strict';

(function(){function t(e){this.path=e;var t=this.path.split("."),n=t.slice(0,t.length-1).join("."),r=t[t.length-1];this.at_2x_path=n+"@2x."+r}function n(e){this.el=e,this.path=new t(this.el.getAttribute("src"));var n=this;this.path.check_2x_variant(function(e){e&&n.swap()})}var e=typeof exports=="undefined"?window:exports;e.RetinaImagePath=t,t.confirmed_paths=[],t.prototype.is_external=function(){return!!this.path.match(/^https?\:/i)&&!this.path.match("//"+document.domain)},t.prototype.check_2x_variant=function(e){var n,r=this;if(this.is_external())return e(!1);if(this.at_2x_path in t.confirmed_paths)return e(!0);n=new XMLHttpRequest,n.open("HEAD",this.at_2x_path),n.onreadystatechange=function(){return n.readyState!=4?e(!1):n.status>=200&&n.status<=399?(t.confirmed_paths.push(r.at_2x_path),e(!0)):e(!1)},n.send()},e.RetinaImage=n,n.prototype.swap=function(e){function n(){t.el.complete?(t.el.setAttribute("width",t.el.offsetWidth),t.el.setAttribute("height",t.el.offsetHeight),t.el.setAttribute("src",e)):setTimeout(n,5)}typeof e=="undefined"&&(e=this.path.at_2x_path);var t=this;n()},e.devicePixelRatio>1&&(window.onload=function(){var e=document.getElementsByTagName("img"),t=[],r,i;for(r=0;r<e.length;r++)i=e[r],t.push(new n(i))})})();
Object.defineProperty(exports, "__esModule", {
value: true
});
/*
* Determine whether or not `window` is available.
*/
var hasWindow = typeof window !== 'undefined';

/*
* Get the device pixel ratio per our environment.
* Default to 1.
*/
var environment = hasWindow ? window.devicePixelRatio || 1 : 1;

/*
* Define a pattern for capturing src url suffixes.
*/
var srcReplace = /(\.[A-z]{3,4}\/?(\?.*)?)$/;
var inlineReplace = /url\(('|")?([^\)'"]+)('|")?\)/i;

/*
* Define our selectors for elements to target.
*/
var selector = '[data-rjs]';

/**
* Chooses the actual image size to fetch, (for example 2 or 3) that
* will be used to create a suffix like "@2x" or "@3x".
*
* @param {String|Number} cap The number the user provided indicating that
* they have prepared images up to this size.
*
* @return {Number} The number we'll be using to create a suffix.
*/
function chooseCap(cap) {
var numericCap = parseInt(cap, 10);

/*
* If the environment's device pixel ratio is less than what the user
* provided, we'll only grab images at that size.
*/
if (environment < numericCap) {
return environment;

/*
* If the device pixel ratio is greater than or equal to what the
* user provided, we'll use what the user provided.
*/
} else {
return numericCap;
}
}

/**
* Makes sure that, since we are going to swap out the source of an image,
* the image does not change size on the page.
*
* @param {Element} image An image element in the DOM.
*
* @return {Element} The same element that was passed in.
*/
function forceOriginalDimensions(image) {
if (!image.hasAttribute('data-no-resize')) {
if (image.offsetWidth === 0 && image.offsetHeight === 0) {
image.setAttribute('width', image.naturalWidth);
image.setAttribute('height', image.naturalHeight);
} else {
image.setAttribute('width', image.offsetWidth);
image.setAttribute('height', image.offsetHeight);
}
}
return image;
}

/**
* Determines whether the retina image actually exists on the server.
* If so, swaps out the retina image for the standard one. If not,
* leaves the original image alone.
*
* @param {Element} image An image element in the DOM.
* @param {String} newSrc The url to the retina image.
*
* @return {undefined}
*/
function setSourceIfAvailable(image, retinaURL) {
var imgType = image.nodeName.toLowerCase();

/*
* Create a new image element and give it a load listener. When the
* load listener fires, it means the URL is correct and we will then
* attach it to the user's image.
*/
var testImage = document.createElement('img');
testImage.addEventListener('load', function () {
/*
* If we're dealing with an image tag, force it's dimensions
* and set the source attribute. If not, go after the background-image
* inline style.
*/
if (imgType === 'img') {
forceOriginalDimensions(image).setAttribute('src', retinaURL);
} else {
image.style.backgroundImage = 'url(' + retinaURL + ')';
}
});

/*
* Attach the retina URL to our proxy image to load in the new
* image resource.
*/
testImage.setAttribute('src', retinaURL);
}

/**
* Attempts to do an image url swap on a given image.
*
* @param {Element} image An image in the DOM.
* @param {String} src The original image source attribute.
* @param {String|Number} rjs The pixel density cap for images provided.
*
* @return {undefined}
*/
function dynamicSwapImage(image, src) {
var rjs = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];

var cap = chooseCap(rjs);

/*
* Don't do anything if the cap is less than 2 or there is no src.
*/
if (src && cap > 1) {
var newSrc = src.replace(srcReplace, '@' + cap + 'x$1');
setSourceIfAvailable(image, newSrc);
}
}

/**
* Performs an image url swap on a given image with a provided url.
*
* @param {Element} image An image in the DOM.
* @param {String} src The original image source attribute.
* @param {String} hdsrc The path for a 2x image.
*
* @return {undefined}
*/
function manualSwapImage(image, src, hdsrc) {
if (environment > 1) {
setSourceIfAvailable(image, hdsrc);
}
}

/**
* Collects all images matching our selector, and converts our
* NodeList into an Array so that Array methods will be available to it.
*
* @return {Array} Contains all elements matching our selector.
*/
function getImages() {
return typeof document !== 'undefined' ? Array.prototype.slice.call(document.querySelectorAll(selector)) : [];
}

/**
* Converts a string like "url(hello.png)" into "hello.png".
*
* @param {Element} img An HTML element with a background image.
*
* @return {String}
*/
function cleanBgImg(img) {
return img.style.backgroundImage.replace(inlineReplace, '$2');
}

/**
* Gets all participating images and dynamically swaps out each one for its
* retina equivalent taking into account the environment capabilities and
* the densities for which the user has provided images.
*
* @return {undefined}
*/
function retina() {
getImages().forEach(function (img) {
var isImg = img.nodeName.toLowerCase() === 'img';
var src = isImg ? img.getAttribute('src') : cleanBgImg(img);
var rjs = img.getAttribute('data-rjs');
var rjsIsNumber = !isNaN(parseInt(rjs, 10));

/*
* If the user provided a number, dynamically swap out the image.
* If the user provided a url, do it manually.
*/
if (rjsIsNumber) {
dynamicSwapImage(img, src, rjs);
} else {
manualSwapImage(img, src, rjs);
}
});
}

/*
* If this environment has `window`, activate the plugin.
*/
if (hasWindow) {
window.addEventListener('load', retina);
window.retinajs = retina;
}

exports.default = retina;

0 comments on commit cfe5f2c

Please sign in to comment.