1/*! 2 * Retina.js v1.1.0 3 * 4 * Copyright 2013 Imulus, LLC 5 * Released under the MIT license 6 * 7 * Retina.js is an open source script that makes it easy to serve 8 * high-resolution images to devices with retina displays. 9 */ 10(function() { 11 12 var root = (typeof exports == 'undefined' ? window : exports); 13 14 var config = { 15 // Ensure Content-Type is an image before trying to load @2x image 16 // https://github.com/imulus/retinajs/pull/45) 17 check_mime_type: true 18 }; 19 20 21 22 root.Retina = Retina; 23 24 function Retina() {} 25 26 Retina.configure = function(options) { 27 if (options == null) options = {}; 28 for (var prop in options) config[prop] = options[prop]; 29 }; 30 31 Retina.init = function(context) { 32 if (context == null) context = root; 33 34 var existing_onload = context.onload || new Function; 35 36 context.onload = function() { 37 var images = document.getElementsByTagName("img"), retinaImages = [], i, image; 38 for (i = 0; i < images.length; i++) { 39 image = images[i]; 40 retinaImages.push(new RetinaImage(image)); 41 } 42 existing_onload(); 43 } 44 }; 45 46 Retina.isRetina = function(){ 47 var mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\ 48 (min--moz-device-pixel-ratio: 1.5),\ 49 (-o-min-device-pixel-ratio: 3/2),\ 50 (min-resolution: 1.5dppx)"; 51 52 if (root.devicePixelRatio > 1) 53 return true; 54 55 if (root.matchMedia && root.matchMedia(mediaQuery).matches) 56 return true; 57 58 return false; 59 }; 60 61 62 root.RetinaImagePath = RetinaImagePath; 63 64 function RetinaImagePath(path, at_2x_path) { 65 this.path = path; 66 if (typeof at_2x_path !== "undefined" && at_2x_path !== null) { 67 this.at_2x_path = at_2x_path; 68 this.perform_check = false; 69 } else { 70 this.at_2x_path = path.replace(/\.\w+$/, function(match) { return "@2x" + match; }); 71 this.perform_check = true; 72 } 73 } 74 75 RetinaImagePath.confirmed_paths = []; 76 77 RetinaImagePath.prototype.is_external = function() { 78 return !!(this.path.match(/^https?\:/i) && !this.path.match('//' + document.domain) ) 79 } 80 81 RetinaImagePath.prototype.check_2x_variant = function(callback) { 82 var http, that = this; 83 if (this.is_external()) { 84 return callback(false); 85 } else if (!this.perform_check && typeof this.at_2x_path !== "undefined" && this.at_2x_path !== null) { 86 return callback(true); 87 } else if (this.at_2x_path in RetinaImagePath.confirmed_paths) { 88 return callback(true); 89 } else { 90 http = new XMLHttpRequest; 91 http.open('HEAD', this.at_2x_path); 92 http.onreadystatechange = function() { 93 if (http.readyState != 4) { 94 return callback(false); 95 } 96 97 if (http.status >= 200 && http.status <= 399) { 98 if (config.check_mime_type) { 99 var type = http.getResponseHeader('Content-Type'); 100 if (type == null || !type.match(/^image/i)) { 101 return callback(false); 102 } 103 } 104 105 RetinaImagePath.confirmed_paths.push(that.at_2x_path); 106 return callback(true); 107 } else { 108 return callback(false); 109 } 110 } 111 http.send(); 112 } 113 } 114 115 116 117 function RetinaImage(el) { 118 this.el = el; 119 this.path = new RetinaImagePath(this.el.getAttribute('src'), this.el.getAttribute('data-at2x')); 120 var that = this; 121 this.path.check_2x_variant(function(hasVariant) { 122 if (hasVariant) that.swap(); 123 }); 124 } 125 126 root.RetinaImage = RetinaImage; 127 128 RetinaImage.prototype.swap = function(path) { 129 if (typeof path == 'undefined') path = this.path.at_2x_path; 130 131 var that = this; 132 function load() { 133 if (! that.el.complete) { 134 setTimeout(load, 5); 135 } else { 136 that.el.setAttribute('width', that.el.offsetWidth); 137 that.el.setAttribute('height', that.el.offsetHeight); 138 that.el.setAttribute('src', path); 139 } 140 } 141 load(); 142 } 143 144 145 146 147 if (Retina.isRetina()) { 148 Retina.init(root); 149 } 150 151})(); 152 153