Skip to content
Browse files

Merge branch 'v2.0' into v2.0-umd-browserify

Conflicts:
	build/mobify.js
	build/mobify.min.js
  • Loading branch information...
2 parents 5e41119 + 21f0bce commit 2e073bcbb46bb07d3a2a44e0468207e6f22ea0f1 @jansepar jansepar committed Mar 3, 2014
Showing with 411 additions and 69 deletions.
  1. +3 −0 CHANGELOG
  2. +4 −2 Gruntfile.js
  3. +1 −1 bower.json
  4. +124 −21 build/mobify.js
  5. +1 −1 build/mobify.min.js
  6. +1 −1 package.json
  7. +85 −21 src/resizeImages.js
  8. +39 −1 src/utils.js
  9. +99 −2 tests/resizeImages.html
  10. +46 −15 tests/utils.html
  11. +1 −1 www/docs/konf-reference.md
  12. +5 −1 www/v2/docs/image-resizer.md
  13. +2 −2 www/v2/docs/index.md
View
3 CHANGELOG
@@ -1,3 +1,6 @@
+2.0.7 - Allow specifying quality parameter without it defaulting the format
+ to JPG.
+ Added a flag that allows you to turn resizing to auto/on/off.
2.0.6 - Fixed issue where we were not passing in the prefix when
using `render` with an HTML string, causing assets to not get enabled.
2.0.5 - Add API for fixing Anchor Tags on Firefox when using Capturing.
View
6 Gruntfile.js
@@ -36,7 +36,8 @@ module.exports = function(grunt) {
'http://localhost:3000/tests/supported-browser.html',
'http://localhost:3000/tests/tag.html',
'http://localhost:3000/tests/tag-integration-tests.html',
- 'http://localhost:3000/tests/tag-old-browser.html'
+ 'http://localhost:3000/tests/tag-old-browser.html',
+ 'http://localhost:3000/tests/utils.html'
]
}
}
@@ -117,7 +118,8 @@ module.exports = function(grunt) {
'http://localhost:3000/tests/anchor-test.html',
'http://localhost:3000/tests/supported-browser.html',
'http://localhost:3000/tests/tag.html',
- 'http://localhost:3000/tests/tag-integration-tests.html'
+ 'http://localhost:3000/tests/tag-integration-tests.html',
+ 'http://localhost:3000/tests/utils.html'
],
concurrency: 16,
tunneled: true,
View
2 bower.json
@@ -1,6 +1,6 @@
{
"name": "mobifyjs",
- "version": "2.0.6",
+ "version": "2.0.7",
"main": "build/mobify.min.js",
"ignore": [
"node_modules",
View
145 build/mobify.js
@@ -1689,41 +1689,95 @@ ResizeImages._getBinnedDimension = function(dim) {
};
/**
+ * Returns a boolean that indicates whether images should be resized.
+ * Looks for the viewport meta tag and parses it to determine whether the
+ * website is responsive (the viewport is set to the device's width). This
+ * ensures that images that are part of a larger viewport are not scaled.
+ */
+ResizeImages._shouldResize = function(document) {
+ var metaViewport = Utils.getMetaViewportProperties(document);
+ if (!metaViewport) {
+ return false;
+ }
+
+ // It's complicated, but what we want to know is whether the viewport
+ // matches the 'ideal viewport'. If either `initial-scale` is 1 or `width`
+ // is device-width or both, then the viewport will match the 'ideal
+ // viewport'. There are a few other special circumstances under which the
+ // viewport could be ideal, but we can't test for them.
+ //
+ // See: http://www.quirksmode.org/mobile/metaviewport/
+
+ // Ideal viewport when width=device-width
+ if (!metaViewport['initial-scale'] && metaViewport['width']) {
+ return metaViewport['width'] == 'device-width';
+ }
+
+ // Ideal viewport when initial-scale=1
+ if (!metaViewport['width'] && metaViewport['initial-scale']) {
+ return metaViewport['initial-scale'] == '1';
+ }
+
+ // Ideal viewport when width=device-width and the intial-scale is 1 or more
+ // (in that case it's just zoomed)
+ if (metaViewport['width'] && metaViewport['initial-scale']) {
+ initialScale = parseInt(metaViewport['initial-scale']);
+ return initialScale >= 1 && metaViewport['width'] == 'device-width';
+ }
+
+ return false
+};
+
+/**
* Processes options passed to `resize()`. Takes an options object that
* potentially has height and width set in css pixels, returns an object where
* they are expressed in device pixels, and other default options are set.
*/
-ResizeImages.processOptions = function(options) {
+ResizeImages.processOptions = function(options) {
var opts = Utils.clone(ResizeImages.defaults);
if (options) {
Utils.extend(opts, options);
}
- var dpr = opts.devicePixelRatio || window.devicePixelRatio;
-
- var screenSize = Utils.getPhysicalScreenSize(dpr);
-
- // If maxHeight/maxWidth are not specified, use screen dimensions
- // in device pixels
- var width = opts.maxWidth || ResizeImages._getBinnedDimension(screenSize.width);
- var height = opts.maxHeight || undefined;
+ // A null value for `resize` triggers the auto detect functionality. This
+ // uses the document to determine whether images should be resized and sets
+ // it as the new default.
+ if (opts.resize == null && options.document) {
+ var resize = ResizeImages._shouldResize(options.document);
+ ResizeImages.defaults.resize = opts.resize = resize;
+ }
- // Otherwise, compute device pixels
- if (dpr && opts.maxWidth) {
- width = width * dpr;
- if (opts.maxHeight) {
- height = height * dpr;
- }
+ if (!opts.format && opts.webp) {
+ opts.format = "webp";
}
- // round up in case of non-integer device pixel ratios
- opts.maxWidth = Math.ceil(width);
- if (opts.maxHeight && height) {
- opts.maxHeight = Math.ceil(height);
+ // Without `resize` images are served through IR without changing their dimensions
+ if (!opts.resize) {
+ opts.maxWidth = opts.maxHeight = opts.devicePixelRatio = null;
}
+ else {
+ var dpr = opts.devicePixelRatio || window.devicePixelRatio;
- if (!opts.format && opts.webp) {
- opts.format = "webp";
+ var screenSize = Utils.getPhysicalScreenSize(dpr);
+
+ // If maxHeight/maxWidth are not specified, use screen dimensions
+ // in device pixels
+ var width = opts.maxWidth || ResizeImages._getBinnedDimension(screenSize.width);
+ var height = opts.maxHeight || undefined;
+
+ // Otherwise, compute device pixels
+ if (dpr && opts.maxWidth) {
+ width = width * dpr;
+ if (opts.maxHeight) {
+ height = height * dpr;
+ }
+ }
+
+ // round up in case of non-integer device pixel ratios
+ opts.maxWidth = Math.ceil(width);
+ if (opts.maxHeight && height) {
+ opts.maxHeight = Math.ceil(height);
+ }
}
return opts;
@@ -1735,6 +1789,15 @@ ResizeImages.processOptions = function(options) {
* resized.
*/
ResizeImages.resize = function(elements, options) {
+ // Return early if elements is empty
+ if (!elements.length) {
+ return;
+ }
+
+ // Supplement `options` with the document from the first element
+ if (options && !options.document) {
+ options.document = elements[0].ownerDocument;
+ }
var opts = ResizeImages.processOptions(options);
for(var i=0; i < elements.length; i++) {
@@ -1773,6 +1836,7 @@ ResizeImages.defaults = {
sourceAttribute: "x-src",
targetAttribute: (capturing ? "x-src" : "src"),
webp: ResizeImages.supportsWebp(),
+ resize: true,
onerror: 'ResizeImages.restoreOriginalSrc(event);'
};
@@ -1942,6 +2006,44 @@ Utils.getDoctype = function(doc) {
+ '>';
};
+/**
+ * Returns an object that represents the parsed content attribute of the
+ * viewport meta tag. Returns false if no viewport meta tag is present.
+ */
+Utils.getMetaViewportProperties = function(doc) {
+ // Regex to split comma-delimited viewport meta tag properties
+ var SPLIT_PROPERTIES_REGEX = /,\s?/;
+
+ doc = doc || document;
+ var parsedProperties = {}
+
+ // Get the viewport meta tag
+ var viewport = doc.querySelectorAll('meta[name="viewport"]');
+ if (viewport.length == 0) {
+ return false;
+ }
+
+ // Split its properties
+ var content = viewport[0].getAttribute('content');
+ if (content == null) {
+ return false;
+ }
+ var properties = content.split(SPLIT_PROPERTIES_REGEX);
+
+ // Parse the properties into an object
+ for (var i = 0; i < properties.length; i++) {
+ var property = properties[i].split('=')
+
+ if (property.length >= 2) {
+ var key = property[0];
+ var value = property[1];
+ parsedProperties[key] = value;
+ }
+ }
+
+ return parsedProperties;
+}
+
Utils.removeBySelector = function(selector, doc) {
doc = doc || document;
@@ -2102,4 +2204,5 @@ Utils.waitForReady = function(doc, callback) {
return Utils;
}));
+
},{}]},{},[4])
View
2 build/mobify.min.js
@@ -1 +1 @@
-!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){!function(d,e){"function"==typeof define&&define.amd?define(["mobifyjs/utils","mobifyjs/patchAnchorLinks"],e):"object"==typeof c?b.exports=e(a("./utils.js"),a("./patchAnchorLinks.js")):d.Capture=e(d.Utils,d.patchAnchorLinks)}(this,function(a,b){function c(a){return a.nodeName.toLowerCase()}function d(a){return a.replace('"',"&quot;")}function e(b){return b?[].map.call(b.childNodes,function(b){var d=c(b);return"#comment"==d?"<!--"+b.textContent+"-->":"plaintext"==d?b.textContent:"script"==d&&(/mobify/.test(b.src)||/mobify/i.test(b.textContent))?"":b.outerHTML||b.nodeValue||a.outerHTML(b)}).join(""):""}window.Mobify&&!window.Mobify.capturing&&document.getElementsByTagName("plaintext").length&&(window.Mobify.capturing=!0);var f=/(<script[\s\S]*?>)/gi,g={style:' media="mobify-media"',script:' type="text/mobify-script"'},h=new RegExp(a.values(g).join("|"),"g"),i={img:["src"],source:["src"],iframe:["src"],script:["src","type"],link:["href"],style:["media"]},j=new RegExp("<("+a.keys(i).join("|")+")([\\s\\S]*?)>","gi"),k={},l={};for(var m in i)if(i.hasOwnProperty(m)){var n=i[m];n.forEach(function(a){l[a]=!0}),k[m]=new RegExp("\\s+((?:"+n.join("|")+")\\s*=\\s*(?:('|\")[\\s\\S]+?\\2))","gi")}var o=document.createElement("div"),p=function(a,b){this.sourceDoc=a,this.prefix=b||"x-",window.Mobify&&(window.Mobify.prefix=this.prefix)};return p.init=p.initCapture=function(b,c,d){var c=c||document,e=function(b,c,d){var e=new p(c,d),f=p.createDocumentFragmentsStrings(e.sourceDoc);a.extend(e,f);var g=e.createDocumentFragments();a.extend(e,g),b(e)};if(a.domIsReady(c))e(b,c,d);else{var f=!1,g=function(){f||(f=!0,h&&clearInterval(h),e(b,c,d))},h=setInterval(function(){a.domIsReady(c)&&g()},100);c.addEventListener("readystatechange",g,!1)}},p.removeClosingTagsAtEndOfString=function(a){var b=a.match(/((<\/[^>]+>)+)$/);return b?a.substring(0,a.length-b[0].length):a},p.removeTargetSelf=function(a){return a.replace(/target=("_self"|\'_self\')/gi,"")},p.cloneAttributes=function(a,b){var c=a.match(/^<(\w+)([\s\S]*)$/i);return o.innerHTML="<div"+c[2],[].forEach.call(o.firstChild.attributes,function(a){try{b.setAttribute(a.nodeName,a.nodeValue)}catch(c){console.error("Error copying attributes while capturing: ",c)}}),b},p.disable=function(a,b){var c=function(){return function(a,c,d){return lowercaseTagName=c.toLowerCase(),result="<"+lowercaseTagName+(g[lowercaseTagName]||"")+d.replace(k[lowercaseTagName]," "+b+"$1")+">"}}(),d=/(<!--[\s\S]*?-->)|(?=<\/script)/i,e=a.split(d),h=e.map(function(a){var b;return a?/^<!--/.test(a)?a:(b=a.split(f),b[0]=b[0].replace(j,c),b[1]&&(b[1]=b[1].replace(j,c)),b):""});return[].concat.apply([],h).join("")},p.enable=function(b,c){var d=new RegExp("\\s"+c+"("+a.keys(l).join("|")+")","gi");return b.replace(d," $1").replace(h,"")},p.openTag=function(a){if(!a)return"";a.length&&(a=a[0]);var b=[];return[].forEach.call(a.attributes,function(a){b.push(" ",a.name,'="',d(a.value),'"')}),"<"+c(a)+b.join("")+">"},p.setElementContentFromString=function(a,b){for(o.innerHTML=b;o.firstChild;a.appendChild(o.firstChild));},p.createDocumentFragmentsStrings=function(b){var c=b.getElementsByTagName("head")[0]||b.createElement("head"),d=b.getElementsByTagName("body")[0]||b.createElement("body"),f=b.getElementsByTagName("html")[0];captured={doctype:a.getDoctype(b),htmlOpenTag:p.openTag(f),headOpenTag:p.openTag(c),bodyOpenTag:p.openTag(d),headContent:e(c),bodyContent:e(d)},captured.all=function(a){return this.doctype+this.htmlOpenTag+this.headOpenTag+(a||"")+this.headContent+this.bodyContent};var g=/<!--(?:[\s\S]*?)-->|(<\/head\s*>|<body[\s\S]*$)/gi,h=captured.bodyContent=captured.headContent+captured.bodyContent;captured.headContent="";for(var i;i=g.exec(h);i)if(i[1]){captured.headContent=h.slice(0,i.index);var j=new RegExp("^\\s*(<head(?:[^>'\"]*|'[^']*?'|\"[^\"]*?\")*>)([\\s\\S]*)$").exec(captured.headContent);if(j&&(captured.headOpenTag=j[1],captured.headContent=j[2]),"/"!=i[1][1]){captured.bodyContent=i[0];var k=/^((?:[^>'"]*|'[^']*?'|"[^"]*?")*>)([\s\S]*)$/.exec(captured.bodyContent);k&&(captured.bodyOpenTag=k[1],captured.bodyContent=k[2]);break}captured.bodyContent=h.slice(i.index+i[1].length)}return captured},p.prototype.restore=function(){var b=this,c=b.sourceDoc,d=function(){c.removeEventListener("readystatechange",d,!1),setTimeout(function(){c.open(),c.write(b.all()),c.close()},15)};a.domIsReady(c)?d():c.addEventListener("readystatechange",d,!1)},p.prototype.createDocumentFragments=function(){var a={},b=a.capturedDoc=document.implementation.createHTMLDocument(""),c=a.htmlEl=b.documentElement,d=a.headEl=c.firstChild,e=a.bodyEl=c.lastChild;p.cloneAttributes(this.htmlOpenTag,c),p.cloneAttributes(this.headOpenTag,d),p.cloneAttributes(this.bodyOpenTag,e),e.innerHTML=p.disable(this.bodyContent,this.prefix);var f=b.querySelectorAll("head");if(f.length>1)for(;f[1].hasChildNodes();)f[1].removeChild(f[1].lastChild);var g=p.disable(this.headContent,this.prefix);try{d.innerHTML=g}catch(h){var i=d.getElementsByTagName("title")[0];i&&d.removeChild(i),p.setElementContentFromString(d,g)}return a},p.prototype.escapedHTMLString=function(){var b=this.capturedDoc,c=p.enable(a.outerHTML(b.documentElement),this.prefix),d=this.doctype+c;return d},p.prototype.render=function(a){var b;b=a?p.enable(a,this.prefix):this.escapedHTMLString();var c=this.sourceDoc;window.Mobify&&(window.Mobify.capturing=!1),setTimeout(function(){c.open("text/html","replace"),c.write(b),c.close()})},p.prototype.getCapturedDoc=function(){return this.capturedDoc},p.getMobifyLibrary=function(a){var a=a||document,b=a.getElementById("mobify-js");return b||(b=a.getElementsByTagName("script")[0],b.id="mobify-js",b.setAttribute("class","mobify")),b},p.getPostload=function(a){var a=a||document,b=void 0,c=window.Mobify.Tag&&window.Mobify.Tag.options&&window.Mobify.Tag.getOptions(Mobify.Tag.options)||{},d=c.post&&c.post.toString()||window.Mobify.mainExecutable;return d?(b=document.createElement("script"),b.innerHTML="var postload = "+d+"; postload();",b.id="postload",b.setAttribute("class","mobify")):b=a.getElementById("main-executable"),b},p.insertMobifyScripts=function(a,b){var c=p.getMobifyLibrary(a),d=b.head||b.getElementsByTagName("head")[0];if(d){var e=p.getPostload(a);if(e){var f=b.importNode(e,!1);e.src||(f.innerHTML=e.innerHTML),d.insertBefore(f,d.firstChild)}var g=b.importNode(c,!1);d.insertBefore(g,d.firstChild)}},p.prototype.renderCapturedDoc=function(){if(p.insertMobifyScripts(this.sourceDoc,this.capturedDoc),window.Mobify&&window.Mobify.points){var a=this.bodyEl,b=this.capturedDoc.createElement("div");b.id="mobify-point",b.setAttribute("style","display: none;"),b.innerHTML=window.Mobify.points[0],a.insertBefore(b,a.firstChild)}this.render()},p.patchAnchorLinks=b,p})},{"./patchAnchorLinks.js":5,"./utils.js":8}],2:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.CssOptimize=e(d.Utils)}(this,function(a){var b=window.cssOptimize={};b.getCssUrl=function(b,d){var e=a.extend({},c,d),f=[e.protoAndHost];return e.projectName&&f.push("project-"+e.projectName),f.push(e.endpoint),f.push(b),f.join("/")},b._rewriteHref=function(c,d){var e,f=c.getAttribute(d.targetAttribute);f&&(e=a.absolutify(f),a.httpUrl(e)&&(c.setAttribute("data-orig-href",f),c.setAttribute(d.targetAttribute,b.getCssUrl(e,d)),d.onerror&&c.setAttribute("onerror",d.onerror)))},b.optimize=function(d,e){for(var f,g=a.extend({},c,e),h=0,i=d.length;i>h;h++)f=d[h],"LINK"===f.nodeName&&"stylesheet"===f.getAttribute("rel")&&f.getAttribute(g.targetAttribute)&&!f.hasAttribute("mobify-optimized")&&(f.setAttribute("mobify-optimized",""),b._rewriteHref(f,g))};var c=(b.restoreOriginalHref=function(a){var b;a.target.removeAttribute("onerror"),(b=a.target.getAttribute("data-orig-href"))&&a.target.setAttribute("href",b)},b._defaults={protoAndHost:"//jazzcat.mobify.com",endpoint:"cssoptimizer",projectName:"oss-"+location.hostname.replace(/[^\w]/g,"-"),targetAttribute:"x-href",onerror:"Mobify.CssOptimize.restoreOriginalHref(event);"});return b})},{"./utils.js":8}],3:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.Jazzcat=e(d.Utils)}(this,function(a){var b={cache:{},options:{},utils:{}},c="Mobify-Jazzcat-Cache-v1.0";b.reset=function(a){b.cache=a||{}},b.get=function(a,c){var d=b.cache[a.split("#")[0]];return d&&c&&(d.lastUsed=Date.now()),d},b.set=function(a,c){b.cache[a]=c},b.load=function(a){var d,e,f=localStorage.getItem(c);if(a&&void 0!==a.overrideTime&&(e={overrideTime:a.overrideTime}),f){try{f=JSON.parse(f)}catch(g){return}for(d in f)f.hasOwnProperty(d)&&!b.utils.isStale(f[d],e)&&b.set(d,f[d])}};var d=!0;b.save=function(e){var f,g=10;return d?(d=!1,void function h(){var i=function(){var i,j,k,l=9007199254740991;f=f||a.clone(b.cache);try{j=JSON.stringify(f)}catch(m){return d=!0,e&&e(m)}try{localStorage.setItem(c,j)}catch(m){if(!--g)return d=!0,e&&e(m);for(var n in f)if(f.hasOwnProperty(n)){if(i=f[n],!i.lastUsed){k=n,l=0;break}i.lastUsed<=l&&(k=n,l=i.lastUsed)}return delete f[k],h()}d=!0,e&&e()};a.domIsReady()?i():setTimeout(h,15)}()):e&&e("Save currently in progress")};var e=/^\s*(public|private|no-cache|no-store)\s*$/,f=/^\s*(max-age)\s*=\s*(\d+)\s*$/;b.utils.ccParse=function(a){var b,c={};return a.split(",").forEach(function(a){(b=e.exec(a))?c[b[1]]=!0:(b=f.exec(a))&&(c[b[1]]=parseInt(b[2],10))}),c},b.utils.isStale=function(a,c){var d,e,f,g,h=864e5,i=a.headers||{},j=i["cache-control"],k=Date.now(),l=Date.parse(i.date),m=i["last-modified"];return l&&l+6e5>k?!1:c&&(g=c.overrideTime)&&l?k>l+60*g*1e3:j&&l?(j=b.utils.ccParse(j),!j["max-age"]||j["no-store"]||j["no-cache"]?!0:k>l+1e3*j["max-age"]):i.expires&&(d=Date.parse(i.expires))?k>d:m&&(m=Date.parse(m))&&l&&(f=l-m,e=k-l,.1*f>e&&h>e)?!1:!0};var g=window.Jazzcat={httpCache:b,write:document.write};g.isIncompatibleBrowser=function(b){var c=/(firefox)[\/\s](\d+)|(opera[\s\S]*version[\/\s](11|12))/i.exec(b||navigator.userAgent);return c&&c[1]&&+c[2]<12||c&&c[3]||!a.supportsLocalStorage()||!window.JSON?!0:!1},g.cacheLoaderInserted=!1,g.optimizeScripts=function(c,d){if(d&&void 0!==d.cacheOverrideTime&&a.extend(b.options,{overrideTime:d.cacheOverrideTime}),c=Array.prototype.slice.call(c),!c.length||g.isIncompatibleBrowser())return c;d=a.extend({},g.defaults,d||{});for(var e,f="jsonp"===d.responseType,h=d.concat,i=function(a,b){if(a){var c=g.getLoaderScript(b,d);a.parentNode.insertBefore(c,a)}},j={head:{firstScript:void 0,urls:[]},body:{firstScript:void 0,urls:[]}},k=0,l=c.length;l>k;k++){var m=c[k];if(!(m.hasAttribute("mobify-optimized")||m.hasAttribute("skip-optimize")||/mobify/i.test(m.className))&&(e=m.getAttribute(d.attribute),e&&(e=a.absolutify(e),a.httpUrl(e)))){if(f&&!g.cacheLoaderInserted){b.load(b.options);var n=g.getHttpCacheLoaderScript();m.parentNode.insertBefore(n,m),g.cacheLoaderInserted=!0}var o="HEAD"===m.parentNode.nodeName?"head":"body";if(f){if(b.get(e)||(h?(void 0===j[o].firstScript&&(j[o].firstScript=m),j[o].urls.push(e)):i(m,[e])),m.type="text/mobify-script",m.hasAttribute("onload")){var p=m.getAttribute("onload");m.innerHTML=d.execCallback+"('"+e+"', '"+p.replace(/'/g,"\\'")+"');",m.removeAttribute("onload")}else m.innerHTML=d.execCallback+"('"+e+"');";m.removeAttribute(d.attribute)}else if(h)void 0===j[o].firstScript&&(j[o].firstScript=m),j[o].urls.push(e);else{var q=g.getURL([e],d);m.setAttribute(d.attribute,q)}}}if(h&&(i(j.head.firstScript,j.head.urls),i(j.body.firstScript,j.body.urls)),!f&&h)for(var k=0,l=c.length;l>k;k++){var m=c[k];m.getAttribute(d.attribute)&&m.parentNode.removeChild(m)}return c},g.getHttpCacheLoaderScript=function(){var a=document.createElement("script");return a.type="text/mobify-script",a.innerHTML=b.options.overrideTime?"Jazzcat.httpCache.load("+JSON.stringify(b.options)+");":"Jazzcat.httpCache.load();",a},g.getLoaderScript=function(a,b){var c;return a&&a.length&&(c=document.createElement("script"),c.setAttribute("mobify-optimized",""),c.setAttribute(b.attribute,g.getURL(a,b))),c},g.getURL=function(b,c){var c=a.extend({},g.defaults,c||{});return c.base+(c.projectName?"/project-"+c.projectName:"")+"/"+c.responseType+("jsonp"===c.responseType?"/"+c.loadCallback:"")+"/"+encodeURIComponent(JSON.stringify(b.slice().sort()))};var h=/(<\/scr)(ipt\s*>)/gi;return g.exec=function(a,c){var d,e=b.get(a,!0),f="";c?(c=";"+c+";",f=' onload="'+c+'"'):c="",e?(d='data-orig-src="'+a+'"',d+=">"+e.body.replace(h,"$1\\$2")+c):d='src="'+a+'"'+f+">",g.write.call(document,"<script "+d+"</script>")},g.load=function(a){var c,d=0,e=!1;if(a){for(;c=a[d++];)"ready"==c.status&&c.statusCode>=200&&c.statusCode<300&&(e=!0,b.set(encodeURI(c.url),c));e&&b.save()}},g.defaults={selector:"script",attribute:"x-src",base:"//jazzcat.mobify.com",responseType:"jsonp",execCallback:"Jazzcat.exec",loadCallback:"Jazzcat.load",concat:!1,projectName:""},g})},{"./utils.js":8}],4:[function(a,b,c){!function(d,e){if("function"==typeof a&&"function"==typeof define&&define.amd)a(["mobifyjs/utils","mobifyjs/capture","mobifyjs/resizeImages","mobifyjs/jazzcat","mobifyjs/unblockify","mobifyjs/cssOptimize","mobifyjs/external/picturefill"],e,void 0,!0);else if("object"==typeof c){var f=a("./utils"),g=a("./capture"),h=a("./resizeImages"),i=a("./jazzcat"),j=a("./cssOptimize"),k=a("./unblockify");b.exports=e(f,g,h,i,k,j)}}(this,function(a,b,c,d,e,f){var g=window.Mobify=window.Mobify||{};return g.Utils=a,g.Capture=b,g.ResizeImages=c,g.Jazzcat=d,g.CssOptimize=f,g.Unblockify=e,g.api="2.0",g})},{"./capture":1,"./cssOptimize":2,"./jazzcat":3,"./resizeImages":6,"./unblockify":7,"./utils":8}],5:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.Jazzcat=e(d.Utils)}(this,function(a){var b=function(a){return a=window.navigator.userAgent,/firefox|fennec/i.test(a)},c=function(a){var b=a.body;if(b&&b.addEventListener){var c=function(a){var b=a.target,c=function(a){return"A"==a.nodeName&&/^#/.test(a.getAttribute("href"))};if(c(b)){var e="undefined"!=typeof a.defaultPrevented?a.defaultPrevented:a.getPreventDefault&&a.getPreventDefault();if(!e){a.preventDefault(),a.defaultPrevented=!1;var f=!0;a.preventDefault=function(){a.defaultPrevented=!0,f=!1},setTimeout(function(){f&&d(b.getAttribute("href"))},50)}}},d=function(b){var c,d=/^#([^\s]*)/,e=b.match(d);if(e&&""===e[1])c=a.body;else if(e&&e[1])var c=a.getElementById(e[1]);c&&c.scrollIntoView&&c.scrollIntoView()};b.addEventListener("click",c,!1)}},d=function(){b()&&a.waitForReady(document,c)};return d})},{"./utils.js":8}],6:[function(a,b,c){!function(d,e){"function"==typeof define&&define.amd?define(["mobifyjs/utils"],e):"object"==typeof c?b.exports=e(a("./utils.js")):d.ResizeImages=e(d.Utils)}(this,function(a){function b(b){if(a.supportsLocalStorage()){var c={supported:b,date:Date.now()};localStorage.setItem(d,JSON.stringify(c))}}var c=window.ResizeImages={},d="Mobify-Webp-Support-v2";c.userAgentWebpDetect=function(a){var b=/(Android\s|Chrome\/|Opera9.8*Version\/..\.|Opera..\.)/i,c=new RegExp("(Android\\s(0|1|2|3|(4(?!.*Chrome)))\\.)|(Chrome\\/[0-8]\\.)|(Chrome\\/9\\.0\\.)|(Chrome\\/1[4-6]\\.)|(Android\\sChrome\\/1.\\.)|(Android\\sChrome\\/20\\.)|(Chrome\\/(1.|20|21|22)\\.)|(Opera.*(Version/|Opera\\s)(10|11)\\.)","i");return b.test(a)?c.test(a)?!1:!0:!1},c.dataUriWebpDetect=function(a){var c=new Image;c.onload=function(){var d=1===c.width?!0:!1;b(d),a&&a(d)},c.src="data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQABgBwlpAADcAD+/gbQAA=="},c.supportsWebp=function(e){if(a.supportsLocalStorage()){var f,g=localStorage.getItem(d);if(g&&(f=JSON.parse(g)),f&&Date.now()-f.date<6048e5)return f.supported}c.dataUriWebpDetect(e);var h=c.userAgentWebpDetect(navigator.userAgent);return b(h),h},c.getImageURL=function(a,b){var d=b;d||(d=c.processOptions());var e=[d.proto+d.host];if(d.projectName){var f="project-"+d.projectName;e.push(f)}return d.cacheHours&&e.push("c"+d.cacheHours),d.format?e.push(d.format+(d.quality||"")):d.quality&&e.push("q"+d.quality),d.maxWidth&&(e.push(d.maxWidth),d.maxHeight&&e.push(d.maxHeight)),e.push(a),e.join("/")},c._rewriteSrcAttribute=function(b,d,e){if(e=b.getAttribute(d.sourceAttribute)||e){var g=a.absolutify(e);a.httpUrl(g)&&(d.onerror&&b.setAttribute("onerror",d.onerror),b.setAttribute(d.targetAttribute,c.getImageURL(g,d)),b.setAttribute("data-orig-src",e),f||d.sourceAttribute==d.targetAttribute||b.removeAttribute(d.sourceAttribute))}},c._resizeSourceElement=function(b,d,e){var f=b.getAttribute("data-width"),g=d;f&&(g=a.clone(d),g.maxWidth=f),c._rewriteSrcAttribute(b,g,e)},c._crawlPictureElement=function(a,b){var d=a.getElementsByTagName("source");if(0!==d.length&&!a.hasAttribute("mobify-optimized")){a.setAttribute("mobify-optimized","");for(var e=a.getAttribute("data-src"),f=0,g=d.length;g>f;f++)c._resizeSourceElement(d[f],b,e)}};var e=[320,640,768,1080,1536,2048,4e3];c._getBinnedDimension=function(a){for(var b=0,c=0,d=e.length;d>c&&(b=e[c],!(b>=a));c++);return b},c.processOptions=function(b){var d=a.clone(c.defaults);b&&a.extend(d,b);var e=d.devicePixelRatio||window.devicePixelRatio,f=a.getPhysicalScreenSize(e),g=d.maxWidth||c._getBinnedDimension(f.width),h=d.maxHeight||void 0;return e&&d.maxWidth&&(g*=e,d.maxHeight&&(h*=e)),d.maxWidth=Math.ceil(g),d.maxHeight&&h&&(d.maxHeight=Math.ceil(h)),!d.format&&d.webp&&(d.format="webp"),d},c.resize=function(a,b){for(var d=c.processOptions(b),e=0;e<a.length;e++){var f=a[e];"IMG"!==f.nodeName||f.hasAttribute("mobify-optimized")?"PICTURE"===f.nodeName&&c._crawlPictureElement(f,d):(f.setAttribute("mobify-optimized",""),c._rewriteSrcAttribute(f,d))}return a},c.restoreOriginalSrc=function(a){var b;a.target.removeAttribute("onerror"),b=a.target.getAttribute("data-orig-src"),b&&a.target.setAttribute("src",b)};var f=window.Mobify&&window.Mobify.capturing||!1;return c.defaults={proto:"//",host:"ir0.mobify.com",projectName:"oss-"+location.hostname.replace(/[^\w]/g,"-"),sourceAttribute:"x-src",targetAttribute:f?"x-src":"src",webp:c.supportsWebp(),onerror:"ResizeImages.restoreOriginalSrc(event);"},c})},{"./utils.js":8}],7:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils","mobifyjs/capture"],e);else if("object"==typeof c){var f=a("./utils.js"),g=a("./capture.js");b.exports=e(f,g)}else d.Unblockify=e(d.Utils,d.Capture)}(this,function(a,b){var c={};return c.moveScripts=function(b,c){a.removeElements(b,c);for(var d=0,e=b.length;e>d;d++){var f=b[d];c.body.appendChild(f)}},c.unblock=function(a){var d=b.prototype.insertMobifyScripts;b.prototype.insertMobifyScripts=function(){d.call(this);var b=this.capturedDoc;c.moveScripts(a,b)}},c})},{"./capture.js":1,"./utils.js":8}],8:[function(a,b,c){!function(a,d){"function"==typeof define&&define.amd?define([],d):"object"==typeof c?b.exports=d():a.Utils=d()}(this,function(){var a={};a.extend=function(a){return[].slice.call(arguments,1).forEach(function(b){for(var c in b)void 0!==b[c]&&(a[c]=b[c])}),a},a.keys=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},a.values=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(a[c]);return b},a.clone=function(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b};var b=document.createElement("a");a.absolutify=function(a){return b.href=a,b.href};var c=/^https?/;a.httpUrl=function(a){return c.test(a)},a.outerHTML=function(a){if(a.outerHTML)return a.outerHTML;var b=document.createElement("div");b.appendChild(a.cloneNode(!0));var c=b.innerHTML;return b=null,c},a.getDoctype=function(a){a=a||document;var b=a.doctype||[].filter.call(a.childNodes,function(a){return a.nodeType==Node.DOCUMENT_TYPE_NODE})[0];return b?"<!DOCTYPE HTML"+(b.publicId?' PUBLIC "'+b.publicId+'"':"")+(b.systemId?' "'+b.systemId+'"':"")+">":""},a.removeBySelector=function(b,c){c=c||document;var d=c.querySelectorAll(b);return a.removeElements(d,c)},a.removeElements=function(a,b){b=b||document;for(var c=0,d=a.length;d>c;c++){var e=a[c];e.parentNode.removeChild(e)}return a};var d;return a.supportsLocalStorage=function(){if(void 0!==d)return d;var a="modernizr";try{localStorage.setItem(a,a),localStorage.removeItem(a),d=!0}catch(b){d=!1}return d},a.matchMedia=function(a){"use strict";var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}},a.domIsReady=function(a){var a=a||document;return a.attachEvent?"complete"===a.readyState:"loading"!==a.readyState},a.getPhysicalScreenSize=function(a){function b(b){var c=a||window.devicePixelRatio||1;return b.width=Math.round(b.width*c),b.height=Math.round(b.height*c),b}var c=navigator.userAgent.match(/ip(hone|od|ad)/i),d=(navigator.userAgent.match(/android (\d)/i)||{})[1],e={width:window.outerWidth,height:window.outerHeight};if(!c)return d>3?b(e):e;var f=window.orientation%180;return f?(e.height=screen.width,e.width=screen.height):(e.width=screen.width,e.height=screen.height),b(e)},a.waitForReady=function(b,c){var d=!1,e=function(){d||(d=!0,f&&clearInterval(f),c(b))},f=setInterval(function(){a.domIsReady(b)&&e()},100);b.addEventListener("readystatechange",e,!1)},a})},{}]},{},[4]);
+!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){!function(d,e){"function"==typeof define&&define.amd?define(["mobifyjs/utils","mobifyjs/patchAnchorLinks"],e):"object"==typeof c?b.exports=e(a("./utils.js"),a("./patchAnchorLinks.js")):d.Capture=e(d.Utils,d.patchAnchorLinks)}(this,function(a,b){function c(a){return a.nodeName.toLowerCase()}function d(a){return a.replace('"',"&quot;")}function e(b){return b?[].map.call(b.childNodes,function(b){var d=c(b);return"#comment"==d?"<!--"+b.textContent+"-->":"plaintext"==d?b.textContent:"script"==d&&(/mobify/.test(b.src)||/mobify/i.test(b.textContent))?"":b.outerHTML||b.nodeValue||a.outerHTML(b)}).join(""):""}window.Mobify&&!window.Mobify.capturing&&document.getElementsByTagName("plaintext").length&&(window.Mobify.capturing=!0);var f=/(<script[\s\S]*?>)/gi,g={style:' media="mobify-media"',script:' type="text/mobify-script"'},h=new RegExp(a.values(g).join("|"),"g"),i={img:["src"],source:["src"],iframe:["src"],script:["src","type"],link:["href"],style:["media"]},j=new RegExp("<("+a.keys(i).join("|")+")([\\s\\S]*?)>","gi"),k={},l={};for(var m in i)if(i.hasOwnProperty(m)){var n=i[m];n.forEach(function(a){l[a]=!0}),k[m]=new RegExp("\\s+((?:"+n.join("|")+")\\s*=\\s*(?:('|\")[\\s\\S]+?\\2))","gi")}var o=document.createElement("div"),p=function(a,b){this.sourceDoc=a,this.prefix=b||"x-",window.Mobify&&(window.Mobify.prefix=this.prefix)};return p.init=p.initCapture=function(b,c,d){var c=c||document,e=function(b,c,d){var e=new p(c,d),f=p.createDocumentFragmentsStrings(e.sourceDoc);a.extend(e,f);var g=e.createDocumentFragments();a.extend(e,g),b(e)};if(a.domIsReady(c))e(b,c,d);else{var f=!1,g=function(){f||(f=!0,h&&clearInterval(h),e(b,c,d))},h=setInterval(function(){a.domIsReady(c)&&g()},100);c.addEventListener("readystatechange",g,!1)}},p.removeClosingTagsAtEndOfString=function(a){var b=a.match(/((<\/[^>]+>)+)$/);return b?a.substring(0,a.length-b[0].length):a},p.removeTargetSelf=function(a){return a.replace(/target=("_self"|\'_self\')/gi,"")},p.cloneAttributes=function(a,b){var c=a.match(/^<(\w+)([\s\S]*)$/i);return o.innerHTML="<div"+c[2],[].forEach.call(o.firstChild.attributes,function(a){try{b.setAttribute(a.nodeName,a.nodeValue)}catch(c){console.error("Error copying attributes while capturing: ",c)}}),b},p.disable=function(a,b){var c=function(){return function(a,c,d){return lowercaseTagName=c.toLowerCase(),result="<"+lowercaseTagName+(g[lowercaseTagName]||"")+d.replace(k[lowercaseTagName]," "+b+"$1")+">"}}(),d=/(<!--[\s\S]*?-->)|(?=<\/script)/i,e=a.split(d),h=e.map(function(a){var b;return a?/^<!--/.test(a)?a:(b=a.split(f),b[0]=b[0].replace(j,c),b[1]&&(b[1]=b[1].replace(j,c)),b):""});return[].concat.apply([],h).join("")},p.enable=function(b,c){var d=new RegExp("\\s"+c+"("+a.keys(l).join("|")+")","gi");return b.replace(d," $1").replace(h,"")},p.openTag=function(a){if(!a)return"";a.length&&(a=a[0]);var b=[];return[].forEach.call(a.attributes,function(a){b.push(" ",a.name,'="',d(a.value),'"')}),"<"+c(a)+b.join("")+">"},p.setElementContentFromString=function(a,b){for(o.innerHTML=b;o.firstChild;a.appendChild(o.firstChild));},p.createDocumentFragmentsStrings=function(b){var c=b.getElementsByTagName("head")[0]||b.createElement("head"),d=b.getElementsByTagName("body")[0]||b.createElement("body"),f=b.getElementsByTagName("html")[0];captured={doctype:a.getDoctype(b),htmlOpenTag:p.openTag(f),headOpenTag:p.openTag(c),bodyOpenTag:p.openTag(d),headContent:e(c),bodyContent:e(d)},captured.all=function(a){return this.doctype+this.htmlOpenTag+this.headOpenTag+(a||"")+this.headContent+this.bodyContent};var g=/<!--(?:[\s\S]*?)-->|(<\/head\s*>|<body[\s\S]*$)/gi,h=captured.bodyContent=captured.headContent+captured.bodyContent;captured.headContent="";for(var i;i=g.exec(h);i)if(i[1]){captured.headContent=h.slice(0,i.index);var j=new RegExp("^\\s*(<head(?:[^>'\"]*|'[^']*?'|\"[^\"]*?\")*>)([\\s\\S]*)$").exec(captured.headContent);if(j&&(captured.headOpenTag=j[1],captured.headContent=j[2]),"/"!=i[1][1]){captured.bodyContent=i[0];var k=/^((?:[^>'"]*|'[^']*?'|"[^"]*?")*>)([\s\S]*)$/.exec(captured.bodyContent);k&&(captured.bodyOpenTag=k[1],captured.bodyContent=k[2]);break}captured.bodyContent=h.slice(i.index+i[1].length)}return captured},p.prototype.restore=function(){var b=this,c=b.sourceDoc,d=function(){c.removeEventListener("readystatechange",d,!1),setTimeout(function(){c.open(),c.write(b.all()),c.close()},15)};a.domIsReady(c)?d():c.addEventListener("readystatechange",d,!1)},p.prototype.createDocumentFragments=function(){var a={},b=a.capturedDoc=document.implementation.createHTMLDocument(""),c=a.htmlEl=b.documentElement,d=a.headEl=c.firstChild,e=a.bodyEl=c.lastChild;p.cloneAttributes(this.htmlOpenTag,c),p.cloneAttributes(this.headOpenTag,d),p.cloneAttributes(this.bodyOpenTag,e),e.innerHTML=p.disable(this.bodyContent,this.prefix);var f=b.querySelectorAll("head");if(f.length>1)for(;f[1].hasChildNodes();)f[1].removeChild(f[1].lastChild);var g=p.disable(this.headContent,this.prefix);try{d.innerHTML=g}catch(h){var i=d.getElementsByTagName("title")[0];i&&d.removeChild(i),p.setElementContentFromString(d,g)}return a},p.prototype.escapedHTMLString=function(){var b=this.capturedDoc,c=p.enable(a.outerHTML(b.documentElement),this.prefix),d=this.doctype+c;return d},p.prototype.render=function(a){var b;b=a?p.enable(a,this.prefix):this.escapedHTMLString();var c=this.sourceDoc;window.Mobify&&(window.Mobify.capturing=!1),setTimeout(function(){c.open("text/html","replace"),c.write(b),c.close()})},p.prototype.getCapturedDoc=function(){return this.capturedDoc},p.getMobifyLibrary=function(a){var a=a||document,b=a.getElementById("mobify-js");return b||(b=a.getElementsByTagName("script")[0],b.id="mobify-js",b.setAttribute("class","mobify")),b},p.getPostload=function(a){var a=a||document,b=void 0,c=window.Mobify.Tag&&window.Mobify.Tag.options&&window.Mobify.Tag.getOptions(Mobify.Tag.options)||{},d=c.post&&c.post.toString()||window.Mobify.mainExecutable;return d?(b=document.createElement("script"),b.innerHTML="var postload = "+d+"; postload();",b.id="postload",b.setAttribute("class","mobify")):b=a.getElementById("main-executable"),b},p.insertMobifyScripts=function(a,b){var c=p.getMobifyLibrary(a),d=b.head||b.getElementsByTagName("head")[0];if(d){var e=p.getPostload(a);if(e){var f=b.importNode(e,!1);e.src||(f.innerHTML=e.innerHTML),d.insertBefore(f,d.firstChild)}var g=b.importNode(c,!1);d.insertBefore(g,d.firstChild)}},p.prototype.renderCapturedDoc=function(){if(p.insertMobifyScripts(this.sourceDoc,this.capturedDoc),window.Mobify&&window.Mobify.points){var a=this.bodyEl,b=this.capturedDoc.createElement("div");b.id="mobify-point",b.setAttribute("style","display: none;"),b.innerHTML=window.Mobify.points[0],a.insertBefore(b,a.firstChild)}this.render()},p.patchAnchorLinks=b,p})},{"./patchAnchorLinks.js":5,"./utils.js":8}],2:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.CssOptimize=e(d.Utils)}(this,function(a){var b=window.cssOptimize={};b.getCssUrl=function(b,d){var e=a.extend({},c,d),f=[e.protoAndHost];return e.projectName&&f.push("project-"+e.projectName),f.push(e.endpoint),f.push(b),f.join("/")},b._rewriteHref=function(c,d){var e,f=c.getAttribute(d.targetAttribute);f&&(e=a.absolutify(f),a.httpUrl(e)&&(c.setAttribute("data-orig-href",f),c.setAttribute(d.targetAttribute,b.getCssUrl(e,d)),d.onerror&&c.setAttribute("onerror",d.onerror)))},b.optimize=function(d,e){for(var f,g=a.extend({},c,e),h=0,i=d.length;i>h;h++)f=d[h],"LINK"===f.nodeName&&"stylesheet"===f.getAttribute("rel")&&f.getAttribute(g.targetAttribute)&&!f.hasAttribute("mobify-optimized")&&(f.setAttribute("mobify-optimized",""),b._rewriteHref(f,g))};var c=(b.restoreOriginalHref=function(a){var b;a.target.removeAttribute("onerror"),(b=a.target.getAttribute("data-orig-href"))&&a.target.setAttribute("href",b)},b._defaults={protoAndHost:"//jazzcat.mobify.com",endpoint:"cssoptimizer",projectName:"oss-"+location.hostname.replace(/[^\w]/g,"-"),targetAttribute:"x-href",onerror:"Mobify.CssOptimize.restoreOriginalHref(event);"});return b})},{"./utils.js":8}],3:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.Jazzcat=e(d.Utils)}(this,function(a){var b={cache:{},options:{},utils:{}},c="Mobify-Jazzcat-Cache-v1.0";b.reset=function(a){b.cache=a||{}},b.get=function(a,c){var d=b.cache[a.split("#")[0]];return d&&c&&(d.lastUsed=Date.now()),d},b.set=function(a,c){b.cache[a]=c},b.load=function(a){var d,e,f=localStorage.getItem(c);if(a&&void 0!==a.overrideTime&&(e={overrideTime:a.overrideTime}),f){try{f=JSON.parse(f)}catch(g){return}for(d in f)f.hasOwnProperty(d)&&!b.utils.isStale(f[d],e)&&b.set(d,f[d])}};var d=!0;b.save=function(e){var f,g=10;return d?(d=!1,void function h(){var i=function(){var i,j,k,l=9007199254740991;f=f||a.clone(b.cache);try{j=JSON.stringify(f)}catch(m){return d=!0,e&&e(m)}try{localStorage.setItem(c,j)}catch(m){if(!--g)return d=!0,e&&e(m);for(var n in f)if(f.hasOwnProperty(n)){if(i=f[n],!i.lastUsed){k=n,l=0;break}i.lastUsed<=l&&(k=n,l=i.lastUsed)}return delete f[k],h()}d=!0,e&&e()};a.domIsReady()?i():setTimeout(h,15)}()):e&&e("Save currently in progress")};var e=/^\s*(public|private|no-cache|no-store)\s*$/,f=/^\s*(max-age)\s*=\s*(\d+)\s*$/;b.utils.ccParse=function(a){var b,c={};return a.split(",").forEach(function(a){(b=e.exec(a))?c[b[1]]=!0:(b=f.exec(a))&&(c[b[1]]=parseInt(b[2],10))}),c},b.utils.isStale=function(a,c){var d,e,f,g,h=864e5,i=a.headers||{},j=i["cache-control"],k=Date.now(),l=Date.parse(i.date),m=i["last-modified"];return l&&l+6e5>k?!1:c&&(g=c.overrideTime)&&l?k>l+60*g*1e3:j&&l?(j=b.utils.ccParse(j),!j["max-age"]||j["no-store"]||j["no-cache"]?!0:k>l+1e3*j["max-age"]):i.expires&&(d=Date.parse(i.expires))?k>d:m&&(m=Date.parse(m))&&l&&(f=l-m,e=k-l,.1*f>e&&h>e)?!1:!0};var g=window.Jazzcat={httpCache:b,write:document.write};g.isIncompatibleBrowser=function(b){var c=/(firefox)[\/\s](\d+)|(opera[\s\S]*version[\/\s](11|12))/i.exec(b||navigator.userAgent);return c&&c[1]&&+c[2]<12||c&&c[3]||!a.supportsLocalStorage()||!window.JSON?!0:!1},g.cacheLoaderInserted=!1,g.optimizeScripts=function(c,d){if(d&&void 0!==d.cacheOverrideTime&&a.extend(b.options,{overrideTime:d.cacheOverrideTime}),c=Array.prototype.slice.call(c),!c.length||g.isIncompatibleBrowser())return c;d=a.extend({},g.defaults,d||{});for(var e,f="jsonp"===d.responseType,h=d.concat,i=function(a,b){if(a){var c=g.getLoaderScript(b,d);a.parentNode.insertBefore(c,a)}},j={head:{firstScript:void 0,urls:[]},body:{firstScript:void 0,urls:[]}},k=0,l=c.length;l>k;k++){var m=c[k];if(!(m.hasAttribute("mobify-optimized")||m.hasAttribute("skip-optimize")||/mobify/i.test(m.className))&&(e=m.getAttribute(d.attribute),e&&(e=a.absolutify(e),a.httpUrl(e)))){if(f&&!g.cacheLoaderInserted){b.load(b.options);var n=g.getHttpCacheLoaderScript();m.parentNode.insertBefore(n,m),g.cacheLoaderInserted=!0}var o="HEAD"===m.parentNode.nodeName?"head":"body";if(f){if(b.get(e)||(h?(void 0===j[o].firstScript&&(j[o].firstScript=m),j[o].urls.push(e)):i(m,[e])),m.type="text/mobify-script",m.hasAttribute("onload")){var p=m.getAttribute("onload");m.innerHTML=d.execCallback+"('"+e+"', '"+p.replace(/'/g,"\\'")+"');",m.removeAttribute("onload")}else m.innerHTML=d.execCallback+"('"+e+"');";m.removeAttribute(d.attribute)}else if(h)void 0===j[o].firstScript&&(j[o].firstScript=m),j[o].urls.push(e);else{var q=g.getURL([e],d);m.setAttribute(d.attribute,q)}}}if(h&&(i(j.head.firstScript,j.head.urls),i(j.body.firstScript,j.body.urls)),!f&&h)for(var k=0,l=c.length;l>k;k++){var m=c[k];m.getAttribute(d.attribute)&&m.parentNode.removeChild(m)}return c},g.getHttpCacheLoaderScript=function(){var a=document.createElement("script");return a.type="text/mobify-script",a.innerHTML=b.options.overrideTime?"Jazzcat.httpCache.load("+JSON.stringify(b.options)+");":"Jazzcat.httpCache.load();",a},g.getLoaderScript=function(a,b){var c;return a&&a.length&&(c=document.createElement("script"),c.setAttribute("mobify-optimized",""),c.setAttribute(b.attribute,g.getURL(a,b))),c},g.getURL=function(b,c){var c=a.extend({},g.defaults,c||{});return c.base+(c.projectName?"/project-"+c.projectName:"")+"/"+c.responseType+("jsonp"===c.responseType?"/"+c.loadCallback:"")+"/"+encodeURIComponent(JSON.stringify(b.slice().sort()))};var h=/(<\/scr)(ipt\s*>)/gi;return g.exec=function(a,c){var d,e=b.get(a,!0),f="";c?(c=";"+c+";",f=' onload="'+c+'"'):c="",e?(d='data-orig-src="'+a+'"',d+=">"+e.body.replace(h,"$1\\$2")+c):d='src="'+a+'"'+f+">",g.write.call(document,"<script "+d+"</script>")},g.load=function(a){var c,d=0,e=!1;if(a){for(;c=a[d++];)"ready"==c.status&&c.statusCode>=200&&c.statusCode<300&&(e=!0,b.set(encodeURI(c.url),c));e&&b.save()}},g.defaults={selector:"script",attribute:"x-src",base:"//jazzcat.mobify.com",responseType:"jsonp",execCallback:"Jazzcat.exec",loadCallback:"Jazzcat.load",concat:!1,projectName:""},g})},{"./utils.js":8}],4:[function(a,b,c){!function(d,e){if("function"==typeof a&&"function"==typeof define&&define.amd)a(["mobifyjs/utils","mobifyjs/capture","mobifyjs/resizeImages","mobifyjs/jazzcat","mobifyjs/unblockify","mobifyjs/cssOptimize","mobifyjs/external/picturefill"],e,void 0,!0);else if("object"==typeof c){var f=a("./utils"),g=a("./capture"),h=a("./resizeImages"),i=a("./jazzcat"),j=a("./cssOptimize"),k=a("./unblockify");b.exports=e(f,g,h,i,k,j)}}(this,function(a,b,c,d,e,f){var g=window.Mobify=window.Mobify||{};return g.Utils=a,g.Capture=b,g.ResizeImages=c,g.Jazzcat=d,g.CssOptimize=f,g.Unblockify=e,g.api="2.0",g})},{"./capture":1,"./cssOptimize":2,"./jazzcat":3,"./resizeImages":6,"./unblockify":7,"./utils":8}],5:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils"],e);else if("object"==typeof c){var f=a("./utils.js");b.exports=e(f)}else d.Jazzcat=e(d.Utils)}(this,function(a){var b=function(a){return a=window.navigator.userAgent,/firefox|fennec/i.test(a)},c=function(a){var b=a.body;if(b&&b.addEventListener){var c=function(a){var b=a.target,c=function(a){return"A"==a.nodeName&&/^#/.test(a.getAttribute("href"))};if(c(b)){var e="undefined"!=typeof a.defaultPrevented?a.defaultPrevented:a.getPreventDefault&&a.getPreventDefault();if(!e){a.preventDefault(),a.defaultPrevented=!1;var f=!0;a.preventDefault=function(){a.defaultPrevented=!0,f=!1},setTimeout(function(){f&&d(b.getAttribute("href"))},50)}}},d=function(b){var c,d=/^#([^\s]*)/,e=b.match(d);if(e&&""===e[1])c=a.body;else if(e&&e[1])var c=a.getElementById(e[1]);c&&c.scrollIntoView&&c.scrollIntoView()};b.addEventListener("click",c,!1)}},d=function(){b()&&a.waitForReady(document,c)};return d})},{"./utils.js":8}],6:[function(a,b,c){!function(d,e){"function"==typeof define&&define.amd?define(["mobifyjs/utils"],e):"object"==typeof c?b.exports=e(a("./utils.js")):d.ResizeImages=e(d.Utils)}(this,function(a){function b(b){if(a.supportsLocalStorage()){var c={supported:b,date:Date.now()};localStorage.setItem(d,JSON.stringify(c))}}var c=window.ResizeImages={},d="Mobify-Webp-Support-v2";c.userAgentWebpDetect=function(a){var b=/(Android\s|Chrome\/|Opera9.8*Version\/..\.|Opera..\.)/i,c=new RegExp("(Android\\s(0|1|2|3|(4(?!.*Chrome)))\\.)|(Chrome\\/[0-8]\\.)|(Chrome\\/9\\.0\\.)|(Chrome\\/1[4-6]\\.)|(Android\\sChrome\\/1.\\.)|(Android\\sChrome\\/20\\.)|(Chrome\\/(1.|20|21|22)\\.)|(Opera.*(Version/|Opera\\s)(10|11)\\.)","i");return b.test(a)?c.test(a)?!1:!0:!1},c.dataUriWebpDetect=function(a){var c=new Image;c.onload=function(){var d=1===c.width?!0:!1;b(d),a&&a(d)},c.src="data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQABgBwlpAADcAD+/gbQAA=="},c.supportsWebp=function(e){if(a.supportsLocalStorage()){var f,g=localStorage.getItem(d);if(g&&(f=JSON.parse(g)),f&&Date.now()-f.date<6048e5)return f.supported}c.dataUriWebpDetect(e);var h=c.userAgentWebpDetect(navigator.userAgent);return b(h),h},c.getImageURL=function(a,b){var d=b;d||(d=c.processOptions());var e=[d.proto+d.host];if(d.projectName){var f="project-"+d.projectName;e.push(f)}return d.cacheHours&&e.push("c"+d.cacheHours),d.format?e.push(d.format+(d.quality||"")):d.quality&&e.push("q"+d.quality),d.maxWidth&&(e.push(d.maxWidth),d.maxHeight&&e.push(d.maxHeight)),e.push(a),e.join("/")},c._rewriteSrcAttribute=function(b,d,e){if(e=b.getAttribute(d.sourceAttribute)||e){var g=a.absolutify(e);a.httpUrl(g)&&(d.onerror&&b.setAttribute("onerror",d.onerror),b.setAttribute(d.targetAttribute,c.getImageURL(g,d)),b.setAttribute("data-orig-src",e),f||d.sourceAttribute==d.targetAttribute||b.removeAttribute(d.sourceAttribute))}},c._resizeSourceElement=function(b,d,e){var f=b.getAttribute("data-width"),g=d;f&&(g=a.clone(d),g.maxWidth=f),c._rewriteSrcAttribute(b,g,e)},c._crawlPictureElement=function(a,b){var d=a.getElementsByTagName("source");if(0!==d.length&&!a.hasAttribute("mobify-optimized")){a.setAttribute("mobify-optimized","");for(var e=a.getAttribute("data-src"),f=0,g=d.length;g>f;f++)c._resizeSourceElement(d[f],b,e)}};var e=[320,640,768,1080,1536,2048,4e3];c._getBinnedDimension=function(a){for(var b=0,c=0,d=e.length;d>c&&(b=e[c],!(b>=a));c++);return b},c._shouldResize=function(b){var c=a.getMetaViewportProperties(b);return c?!c["initial-scale"]&&c.width?"device-width"==c.width:!c.width&&c["initial-scale"]?"1"==c["initial-scale"]:c.width&&c["initial-scale"]?(initialScale=parseInt(c["initial-scale"]),initialScale>=1&&"device-width"==c.width):!1:!1},c.processOptions=function(b){var d=a.clone(c.defaults);if(b&&a.extend(d,b),null==d.resize&&b.document){var e=c._shouldResize(b.document);c.defaults.resize=d.resize=e}if(!d.format&&d.webp&&(d.format="webp"),d.resize){var f=d.devicePixelRatio||window.devicePixelRatio,g=a.getPhysicalScreenSize(f),h=d.maxWidth||c._getBinnedDimension(g.width),i=d.maxHeight||void 0;f&&d.maxWidth&&(h*=f,d.maxHeight&&(i*=f)),d.maxWidth=Math.ceil(h),d.maxHeight&&i&&(d.maxHeight=Math.ceil(i))}else d.maxWidth=d.maxHeight=d.devicePixelRatio=null;return d},c.resize=function(a,b){if(a.length){b&&!b.document&&(b.document=a[0].ownerDocument);for(var d=c.processOptions(b),e=0;e<a.length;e++){var f=a[e];"IMG"!==f.nodeName||f.hasAttribute("mobify-optimized")?"PICTURE"===f.nodeName&&c._crawlPictureElement(f,d):(f.setAttribute("mobify-optimized",""),c._rewriteSrcAttribute(f,d))}return a}},c.restoreOriginalSrc=function(a){var b;a.target.removeAttribute("onerror"),b=a.target.getAttribute("data-orig-src"),b&&a.target.setAttribute("src",b)};var f=window.Mobify&&window.Mobify.capturing||!1;return c.defaults={proto:"//",host:"ir0.mobify.com",projectName:"oss-"+location.hostname.replace(/[^\w]/g,"-"),sourceAttribute:"x-src",targetAttribute:f?"x-src":"src",webp:c.supportsWebp(),resize:!0,onerror:"ResizeImages.restoreOriginalSrc(event);"},c})},{"./utils.js":8}],7:[function(a,b,c){!function(d,e){if("function"==typeof define&&define.amd)define(["mobifyjs/utils","mobifyjs/capture"],e);else if("object"==typeof c){var f=a("./utils.js"),g=a("./capture.js");b.exports=e(f,g)}else d.Unblockify=e(d.Utils,d.Capture)}(this,function(a,b){var c={};return c.moveScripts=function(b,c){a.removeElements(b,c);for(var d=0,e=b.length;e>d;d++){var f=b[d];c.body.appendChild(f)}},c.unblock=function(a){var d=b.prototype.insertMobifyScripts;b.prototype.insertMobifyScripts=function(){d.call(this);var b=this.capturedDoc;c.moveScripts(a,b)}},c})},{"./capture.js":1,"./utils.js":8}],8:[function(a,b,c){!function(a,d){"function"==typeof define&&define.amd?define([],d):"object"==typeof c?b.exports=d():a.Utils=d()}(this,function(){var a={};a.extend=function(a){return[].slice.call(arguments,1).forEach(function(b){for(var c in b)void 0!==b[c]&&(a[c]=b[c])}),a},a.keys=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b},a.values=function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(a[c]);return b},a.clone=function(a){var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b};var b=document.createElement("a");a.absolutify=function(a){return b.href=a,b.href};var c=/^https?/;a.httpUrl=function(a){return c.test(a)},a.outerHTML=function(a){if(a.outerHTML)return a.outerHTML;var b=document.createElement("div");b.appendChild(a.cloneNode(!0));var c=b.innerHTML;return b=null,c},a.getDoctype=function(a){a=a||document;var b=a.doctype||[].filter.call(a.childNodes,function(a){return a.nodeType==Node.DOCUMENT_TYPE_NODE})[0];return b?"<!DOCTYPE HTML"+(b.publicId?' PUBLIC "'+b.publicId+'"':"")+(b.systemId?' "'+b.systemId+'"':"")+">":""},a.getMetaViewportProperties=function(a){var b=/,\s?/;a=a||document;var c={},d=a.querySelectorAll('meta[name="viewport"]');if(0==d.length)return!1;var e=d[0].getAttribute("content");if(null==e)return!1;for(var f=e.split(b),g=0;g<f.length;g++){var h=f[g].split("=");if(h.length>=2){var i=h[0],j=h[1];c[i]=j}}return c},a.removeBySelector=function(b,c){c=c||document;var d=c.querySelectorAll(b);return a.removeElements(d,c)},a.removeElements=function(a,b){b=b||document;for(var c=0,d=a.length;d>c;c++){var e=a[c];e.parentNode.removeChild(e)}return a};var d;return a.supportsLocalStorage=function(){if(void 0!==d)return d;var a="modernizr";try{localStorage.setItem(a,a),localStorage.removeItem(a),d=!0}catch(b){d=!1}return d},a.matchMedia=function(a){"use strict";var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}},a.domIsReady=function(a){var a=a||document;return a.attachEvent?"complete"===a.readyState:"loading"!==a.readyState},a.getPhysicalScreenSize=function(a){function b(b){var c=a||window.devicePixelRatio||1;return b.width=Math.round(b.width*c),b.height=Math.round(b.height*c),b}var c=navigator.userAgent.match(/ip(hone|od|ad)/i),d=(navigator.userAgent.match(/android (\d)/i)||{})[1],e={width:window.outerWidth,height:window.outerHeight};if(!c)return d>3?b(e):e;var f=window.orientation%180;return f?(e.height=screen.width,e.width=screen.height):(e.width=screen.width,e.height=screen.height),b(e)},a.waitForReady=function(b,c){var d=!1,e=function(){d||(d=!0,f&&clearInterval(f),c(b))},f=setInterval(function(){a.domIsReady(b)&&e()},100);b.addEventListener("readystatechange",e,!1)},a})},{}]},{},[4]);
View
2 package.json
@@ -1,6 +1,6 @@
{
"name": "mobifyjs",
- "version": "2.0.6",
+ "version": "2.0.7",
"description": "The Mobify.js client side adaptation library.",
"author": "Mobify <dev@mobify.com>",
"devDependencies": {
View
106 src/resizeImages.js
@@ -246,41 +246,95 @@ ResizeImages._getBinnedDimension = function(dim) {
};
/**
+ * Returns a boolean that indicates whether images should be resized.
+ * Looks for the viewport meta tag and parses it to determine whether the
+ * website is responsive (the viewport is set to the device's width). This
+ * ensures that images that are part of a larger viewport are not scaled.
+ */
+ResizeImages._shouldResize = function(document) {
+ var metaViewport = Utils.getMetaViewportProperties(document);
+ if (!metaViewport) {
+ return false;
+ }
+
+ // It's complicated, but what we want to know is whether the viewport
+ // matches the 'ideal viewport'. If either `initial-scale` is 1 or `width`
+ // is device-width or both, then the viewport will match the 'ideal
+ // viewport'. There are a few other special circumstances under which the
+ // viewport could be ideal, but we can't test for them.
+ //
+ // See: http://www.quirksmode.org/mobile/metaviewport/
+
+ // Ideal viewport when width=device-width
+ if (!metaViewport['initial-scale'] && metaViewport['width']) {
+ return metaViewport['width'] == 'device-width';
+ }
+
+ // Ideal viewport when initial-scale=1
+ if (!metaViewport['width'] && metaViewport['initial-scale']) {
+ return metaViewport['initial-scale'] == '1';
+ }
+
+ // Ideal viewport when width=device-width and the intial-scale is 1 or more
+ // (in that case it's just zoomed)
+ if (metaViewport['width'] && metaViewport['initial-scale']) {
+ initialScale = parseInt(metaViewport['initial-scale']);
+ return initialScale >= 1 && metaViewport['width'] == 'device-width';
+ }
+
+ return false
+};
+
+/**
* Processes options passed to `resize()`. Takes an options object that
* potentially has height and width set in css pixels, returns an object where
* they are expressed in device pixels, and other default options are set.
*/
-ResizeImages.processOptions = function(options) {
+ResizeImages.processOptions = function(options) {
var opts = Utils.clone(ResizeImages.defaults);
if (options) {
Utils.extend(opts, options);
}
- var dpr = opts.devicePixelRatio || window.devicePixelRatio;
-
- var screenSize = Utils.getPhysicalScreenSize(dpr);
-
- // If maxHeight/maxWidth are not specified, use screen dimensions
- // in device pixels
- var width = opts.maxWidth || ResizeImages._getBinnedDimension(screenSize.width);
- var height = opts.maxHeight || undefined;
+ // A null value for `resize` triggers the auto detect functionality. This
+ // uses the document to determine whether images should be resized and sets
+ // it as the new default.
+ if (opts.resize == null && options.document) {
+ var resize = ResizeImages._shouldResize(options.document);
+ ResizeImages.defaults.resize = opts.resize = resize;
+ }
- // Otherwise, compute device pixels
- if (dpr && opts.maxWidth) {
- width = width * dpr;
- if (opts.maxHeight) {
- height = height * dpr;
- }
+ if (!opts.format && opts.webp) {
+ opts.format = "webp";
}
- // round up in case of non-integer device pixel ratios
- opts.maxWidth = Math.ceil(width);
- if (opts.maxHeight && height) {
- opts.maxHeight = Math.ceil(height);
+ // Without `resize` images are served through IR without changing their dimensions
+ if (!opts.resize) {
+ opts.maxWidth = opts.maxHeight = opts.devicePixelRatio = null;
}
+ else {
+ var dpr = opts.devicePixelRatio || window.devicePixelRatio;
- if (!opts.format && opts.webp) {
- opts.format = "webp";
+ var screenSize = Utils.getPhysicalScreenSize(dpr);
+
+ // If maxHeight/maxWidth are not specified, use screen dimensions
+ // in device pixels
+ var width = opts.maxWidth || ResizeImages._getBinnedDimension(screenSize.width);
+ var height = opts.maxHeight || undefined;
+
+ // Otherwise, compute device pixels
+ if (dpr && opts.maxWidth) {
+ width = width * dpr;
+ if (opts.maxHeight) {
+ height = height * dpr;
+ }
+ }
+
+ // round up in case of non-integer device pixel ratios
+ opts.maxWidth = Math.ceil(width);
+ if (opts.maxHeight && height) {
+ opts.maxHeight = Math.ceil(height);
+ }
}
return opts;
@@ -292,6 +346,15 @@ ResizeImages.processOptions = function(options) {
* resized.
*/
ResizeImages.resize = function(elements, options) {
+ // Return early if elements is empty
+ if (!elements.length) {
+ return;
+ }
+
+ // Supplement `options` with the document from the first element
+ if (options && !options.document) {
+ options.document = elements[0].ownerDocument;
+ }
var opts = ResizeImages.processOptions(options);
for(var i=0; i < elements.length; i++) {
@@ -330,6 +393,7 @@ ResizeImages.defaults = {
sourceAttribute: "x-src",
targetAttribute: (capturing ? "x-src" : "src"),
webp: ResizeImages.supportsWebp(),
+ resize: true,
onerror: 'ResizeImages.restoreOriginalSrc(event);'
};
View
40 src/utils.js
@@ -109,6 +109,44 @@ Utils.getDoctype = function(doc) {
+ '>';
};
+/**
+ * Returns an object that represents the parsed content attribute of the
+ * viewport meta tag. Returns false if no viewport meta tag is present.
+ */
+Utils.getMetaViewportProperties = function(doc) {
+ // Regex to split comma-delimited viewport meta tag properties
+ var SPLIT_PROPERTIES_REGEX = /,\s?/;
+
+ doc = doc || document;
+ var parsedProperties = {}
+
+ // Get the viewport meta tag
+ var viewport = doc.querySelectorAll('meta[name="viewport"]');
+ if (viewport.length == 0) {
+ return false;
+ }
+
+ // Split its properties
+ var content = viewport[0].getAttribute('content');
+ if (content == null) {
+ return false;
+ }
+ var properties = content.split(SPLIT_PROPERTIES_REGEX);
+
+ // Parse the properties into an object
+ for (var i = 0; i < properties.length; i++) {
+ var property = properties[i].split('=')
+
+ if (property.length >= 2) {
+ var key = property[0];
+ var value = property[1];
+ parsedProperties[key] = value;
+ }
+ }
+
+ return parsedProperties;
+}
+
Utils.removeBySelector = function(selector, doc) {
doc = doc || document;
@@ -268,4 +306,4 @@ Utils.waitForReady = function(doc, callback) {
return Utils;
-}));
+}));
View
101 tests/resizeImages.html
@@ -2,7 +2,10 @@
<html class="foo">
<head>
<meta charset="utf-8">
+ <meta name="viewport" content="width=device-width">
+
<title>resizeImages.js Tests</title>
+
<link rel="stylesheet" href="/tests/resources/qunit-1.10.0.css">
<script src="/tests/resources/qunit-1.10.0.js"></script>
<script src="/tests/resources/require.js" id="requirejs"></script>
@@ -15,6 +18,10 @@
<div id="qunit-fixture">
+ <div id="resizeImages-detect">
+ <img x-src="http://www.mobify.com/i/phone-tablet.png" />
+ </div>
+
<div id="resizeImages">
<img x-src="http://www.mobify.com/i/phone-tablet.png" />
</div>
@@ -35,6 +42,14 @@
<img data-src="http://www.mobify.com/i/phone-tablet.png"/>
</div>
+ <div id="resizeImages-resize-option-false">
+ <img x-src="http://www.mobify.com/i/phone-tablet.png" />
+ </div>
+
+ <div id="resizeImages-resize-option-true">
+ <img x-src="http://www.mobify.com/i/phone-tablet.png" />
+ </div>
+
<div id="resizeImages-picture-element">
<picture data-src="http://www.mobify.com/i/phone-tablet.png">
@@ -77,6 +92,13 @@
});
require(["mobifyjs/utils", "mobifyjs/resizeImages"], function(Utils, ResizeImages) {
QUnit.start();
+
+ var mockDocument = function(body) {
+ var doc = document.implementation.createHTMLDocument("");
+ doc.body.innerHTML = body;
+ return doc
+ };
+
module("processOptions");
test('processOptions - adds a default project name', function() {
expectedProjectName = "oss-localhost";
@@ -175,7 +197,7 @@
});
- test('_rewirteSrcAttribute - adds an original src data attribute', function() {
+ test('_rewriteSrcAttribute - adds an original src data attribute', function() {
var images = document.querySelectorAll("#resizeImages-adds-data-orig-src img");
var originalSrcs = [].map.call(images, function(img) {
@@ -311,7 +333,83 @@
strictEqual(gbd(4001), 4000);
});
+ module("_shouldResize");
+ test('_shouldResize', function() {
+ var tests = [
+ ['<meta name="viewport" content="initial-scale=1">', true],
+ ['<meta name="viewport" content="width=device-width">', true],
+ ['<meta name="viewport" content="initial-scale=2,width=device-width">', true],
+
+ ['<meta name="viewport" content="initial-scale=2">', false],
+ ['<meta name="viewport" content="width=480">', false],
+ ['<meta name="viewport" content="width=device-width,initial-scale=0.5>', false]
+ ];
+
+ for (var i = 0; i < tests.length; i++) {
+ var body = tests[i][0];
+ var expected = tests[i][1];
+
+ var doc = mockDocument(body);
+ equal(ResizeImages._shouldResize(doc), expected);
+ }
+ });
+
module("resize");
+ test('resize images - auto detects resize from meta tag', function() {
+ var images = document.querySelectorAll('#resizeImages-detect img');
+
+ // Use the auto detect functionality
+ ResizeImages.defaults.resize = null;
+
+ // Remove the viewport meta tag, shouldn't resize
+ var metaTag = $('meta[name="viewport"]').detach();
+ ResizeImages.resize(images, {});
+ equal(ResizeImages.defaults.resize, false, 'auto detect should not resize');
+
+ ResizeImages.defaults.resize = null; // reset
+
+ // Add the viewport meta tag back in, should resize
+ $('head').prepend(metaTag);
+ ResizeImages.resize(images, {});
+ equal(ResizeImages.defaults.resize, true, 'auto detect should resize');
+
+ });
+
+ test('resize images - resize option false', function() {
+ var images = document.querySelectorAll('#resizeImages-resize-option-false img');
+
+ ResizeImages.resize(images, {
+ projectName: 'test1',
+ resize: false,
+ webp: false,
+ // With `resize` false, the following options should be ignored:
+ maxWidth: 320,
+ maxHeight: 480,
+ devicePixelRatio: 2
+ });
+
+ var src = $('#resizeImages-resize-option-false img').attr('src');
+
+ equal(src, '//ir0.mobify.com/project-test1/http://www.mobify.com/i/phone-tablet.png', 'resize false img should not resize');
+ });
+
+ test('resize images - resize option true', function() {
+ var images = document.querySelectorAll('#resizeImages-resize-option-true img');
+
+ ResizeImages.resize(images, {
+ projectName: 'test1',
+ resize: true,
+ webp: false,
+ maxWidth: 320,
+ maxHeight: 480,
+ devicePixelRatio: 1
+ });
+
+ var src = $('#resizeImages-resize-option-true img').attr('src');
+
+ equal(src, '//ir0.mobify.com/project-test1/320/480/http://www.mobify.com/i/phone-tablet.png', 'resize true img should resize');
+ });
+
test('resize images', function() {
var images = document.querySelectorAll('#resizeImages img');
@@ -383,7 +481,6 @@
equal(images[0].querySelectorAll("#no-width-and-no-src")[0].getAttribute("src"),
"//ir0.mobify.com/project-test1/1280/480/http://www.mobify.com/i/phone-tablet.png",
"source in picture has no width overide, and uses data-src in picture");
-
});
test('resize', function() {
View
61 tests/utils.html
@@ -11,21 +11,7 @@
<body>
<div id="qunit"></div>
-
-<div id="qunit-fixture">
-
-<div class="removeElementsFilter">
-
-<script id="scriptsrc" src="fake1.js"></script>
-<script id="scriptinline">
- console.log("fake2");
-</script>
-<img src="fake.png">
-
-</div>
-
-</div>
-
+<div id="qunit-fixture"></div>
<script>
QUnit.config.autostart = false;
@@ -37,8 +23,53 @@
});
require(["../src/utils.js"], function(Utils) {
QUnit.start();
+
+ var mockDocument = function(body) {
+ var doc = document.implementation.createHTMLDocument("");
+ doc.body.innerHTML = body;
+ return doc
+ };
+
+ var metaPropertiesEqual = function(body, expected, message) {
+ var doc = mockDocument(body);
+ var actual = Utils.getMetaViewportProperties(doc);
+ deepEqual(actual, expected, message);
+ }
+ test("getMetaViewportProperties - no viewport meta tag", function() {
+ metaPropertiesEqual('<html><head></head></html>', false,
+ "Should return false with no viewport tag");
+ });
+
+ test("getMetaViewportProperties - with a viewport meta tag", function() {
+ metaPropertiesEqual('<meta name="viewport" content="">', {},
+ "Should return an empty object");
+ });
+
+ test("getMetaViewportProperties - with improperly formatted content", function() {
+ var doc = mockDocument('<meta name="viewport" content="===, = ,,,=something=hey">');
+ var properties = Utils.getMetaViewportProperties(doc);
+ ok(properties, "Should not blow up");
+
+ metaPropertiesEqual('<meta name="viewport">', false,
+ "Should return false with no content attribute");
+ });
+
+ test("getMetaViewportProperties - with properly formatted content", function() {
+ metaPropertiesEqual(
+ '<meta name="viewport" content="width=device-width,initial-scale=1">',
+ {width: 'device-width', 'initial-scale': '1'},
+ "Should return an object representation of the content attribute");
+
+ metaPropertiesEqual(
+ '<meta name="viewport" content="width=device-width">',
+ {width: 'device-width'},
+ "Should return an object representation of the content attribute");
+ metaPropertiesEqual(
+ '<meta name="viewport" content="">', {},
+ "Should return an object representation of the content attribute")
+ });
});
</script>
</body>
View
2 www/docs/konf-reference.md
@@ -289,7 +289,7 @@ your site
kept
`mobileViewport`
-: Contents of the meta viewport tag to be sent
+: Contents of the viewport meta tag to be sent
`siteConfig`
: An object containing analytics configuration information
View
6 www/v2/docs/image-resizer.md
@@ -64,12 +64,16 @@ ir0.mobify.com will serve a 302 redirect back to the original image location.**
format, except non-animated gifs, which are converted to png.
- `quality`: An integer from 1-100 used as a quality parameter when encoding
jpg and webp images, can only be set along with the `format` parameter.
-- `maxWidth`: Maximum width of the image(s) being resized (in CSS pixes).
+- `maxWidth`: Maximum width of the image(s) being resized (in CSS pixels).
Defaults to automatically determine width of device.
- `maxHeight`: Maximum height of the image(s) being resized (in CSS pixels).
Only usable when maxWidth is specified.
- `devicePixelRatio`: Override the default devicePixelRatio. Defaults to
`window.devicePixelRatio.`
+- `resize`: A boolean that controls whether to scale the image(s). When
+ false, the image(s) are served through the image resizer backend but are not
+ resized. A value of null auto detects whether to resize images from the
+ document's viewport meta tag. The default is true.
**Example**
View
4 www/v2/docs/index.md
@@ -36,7 +36,7 @@ any element that loads external resources!**):
<script>!function(a,b,c,d,e){function g(a,c,d,e){var f=b.getElementsByTagName("script")[0];a.src=e,a.id=c,a.setAttribute("class",d),f.parentNode.insertBefore(a,f)}a.Mobify={points:[+new Date]};var f=/((; )|#|&|^)mobify=(\d)/.exec(location.hash+"; "+b.cookie);if(f&&f[3]){if(!+f[3])return}else if(!c())return;b.write('<plaintext style="display:none">'),setTimeout(function(){var c=a.Mobify=a.Mobify||{};c.capturing=!0;var f=b.createElement("script"),h="mobify",i=function(){var c=new Date;c.setTime(c.getTime()+3e5),b.cookie="mobify=0; expires="+c.toGMTString()+"; path=/",a.location=a.location.href};f.onload=function(){if(e)if("string"==typeof e){var c=b.createElement("script");c.onerror=i,g(c,"main-executable",h,mainUrl)}else a.Mobify.mainExecutable=e.toString(),e()},f.onerror=i,g(f,"mobify-js",h,d)})}(window,document,function(){a=/webkit|(firefox)[\/\s](\d+)|(opera)[\s\S]*version[\/\s](\d+)|(trident)[\/\s](\d+)|3ds/i.exec(navigator.userAgent);return!a||a[1]&&4>+a[2]||a[3]&&11>+a[4]||a[5]&&6>+a[6]?!1:!0},
// path to mobify.js
- "//cdn.mobify.com/mobifyjs/build/mobify-2.0.6.min.js",
+ "//cdn.mobify.com/mobifyjs/build/mobify-2.0.7.min.js",
// calls to APIs go here (or path to a main.js)
function() {
@@ -70,7 +70,7 @@ the DOM is ready.
Then, paste the following tag before <code>&lt;/head&gt;</code>, or top of
<code>&lt;body&gt;</code>:
- <script async src="//cdn.mobify.com/mobifyjs/build/mobify-2.0.6.min.js"></script>
+ <script async src="//cdn.mobify.com/mobifyjs/build/mobify-2.0.7.min.js"></script>
<script>
var intervalId = setInterval(function(){
if (window.Mobify) {

0 comments on commit 2e073bc

Please sign in to comment.
Something went wrong with that request. Please try again.