Skip to content

Instantly share code, notes, and snippets.

@hankbao
Forked from Sai/image_replacer.js
Created March 17, 2012 16:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hankbao/2062078 to your computer and use it in GitHub Desktop.
Save hankbao/2062078 to your computer and use it in GitHub Desktop.
Web@2x
if (typeof (AC) === "undefined") {
AC = {}
}
AC.ImageReplacer = Class.create({
_defaultOptions: {
listenToSwapView: true,
filenameRegex: /(.*)(\.[a-z]{3}($|#.*|\?.*))/i,
filenameInsert: "_☃x",
ignoreCheck: /(^http:\/\/movies\.apple\.com\/|\/105\/|\/global\/elements\/quicktime\/|_(([2-9]|[1-9][0-9]+)x|nohires)(\.[a-z]{3})($|#.*|\?.*))/i,
attribute: "data-hires",
recursive: true,
preload: false,
checkExists: true,
queueSize: 8,
debug: false
},
_lowestPriority: 2,
__replacedAttribute: "data-hires-status",
initialize: function (c) {
if (typeof c !== "object") {
c = {}
}
this.options = Object.extend(Object.clone(this._defaultOptions), c);
this.options.lowestPriority = this._lowestPriority;
this.options.replacedAttribute = this.__replacedAttribute;
if ((this.options.debug !== true) && ((typeof AC.Detector !== "undefined" && AC.Detector.isMobile()) || (AC.ImageReplacer.devicePixelRatio() <= 1))) {
return
}
if (this.options.debug === true) {
AC.ImageReplacer._devicePixelRatio = 2
}
Object.synthesize(this);
if (windowHasLoaded) {
this.__setup()
} else {
var d = this.__setup.bind(this);
Event.observe(window, "load", d)
}
},
log: function () {
if (this.__canLog !== false && this.options.debug === true) {
var d = $A(arguments);
if (d.length < 2) {
d = d[0]
}
try {
console.log(d)
} catch (c) {
this.__canLog = false
}
}
},
isReplaceable: function (f) {
if ((f.getAttribute(this.options.attribute) === "false") || (f.up("[" + this.options.attribute + '="false"]') && this.options.recursive === true)) {
return false
}
var e = (typeof f.responsiveImageObject === "undefined");
if (f.tagName.toLowerCase() === "img") {
return e
} else {
if (f.hasClassName("imageLink") && f.tagName.toLowerCase() === "a") {
return true
} else {
var d = AC.ImageReplacer.Image.removeCSSURLSyntax(f.getStyle("background-image"));
return (((d.match(AC.ImageReplacer.normalImageTypeRegex) !== null) && e))
}
}
},
potentialElements: function (j, k) {
if (typeof j === "undefined") {
j = document.body
}
var h = $(j).getElementsBySelector("[" + this.options.attribute + "]");
var i;
var n = function (a) {
if (typeof k === "undefined") {
return typeof j.up("[" + a + "]") !== "undefined"
} else {
return k.getAttribute(a) !== null || typeof k.up("[" + a + "]") !== "undefined"
}
};
if (this.options.recursive === true) {
if (j !== document.body && n(this.options.attribute)) {
h = h.concat(j)
}
i = [];
var l = this.isReplaceable.bind(this);
var m = function (a) {
if (l(a)) {
i.push(a)
}
i = i.concat(this.replaceableElementsWithinElement(a))
}.bind(this);
$A(h).each(m)
} else {
i = h
}
return i
},
prioritize: function (f) {
var h = [];
var g = function (a) {
if (typeof a.responsiveImageObject !== "undefined") {
return
}
var b = new AC.ImageReplacer.Image(a, this.options);
if (b.hiResSrc() !== null && !b.isHiRes()) {
if (typeof h[b.priority()] === "undefined") {
h[b.priority()] = []
}
h[b.priority()].push(b)
} else {
if (b.hiResSrc() && b.isHiRes()) {
b.setStatus("already-hires")
} else {
b.setStatus("not-replaceable")
}
}
}.bind(this);
$A(f).each(g);
var e;
for (e = this._lowestPriority;
e >= 0; e--) {
if (typeof h[e] === "undefined") {
h[e] = []
}
}
return h.flatten()
},
replaceableElementsWithinElement: function (g) {
g = $(g);
var f = this;
var e = g.descendants();
var h = this.isReplaceable.bind(this);
return e.findAll(h)
},
addToQueue: function (b) {
if (typeof this.__queues === "undefined") {
this.__queues = $A()
}
if (this.__queues.length === 0) {
this.__queues.push($A())
}
this.__queues[this.__queues.length - 1].push(b)
},
replace: function () {
if (typeof this.__queues === "undefined") {
this.__queues = $A()
}
if (this.__queues.length > 0 && this.__queues[0].length > 0) {
this.__queues.push($A());
var b = this.replace.bind(this);
this.__replaceNextQueue(b)
} else {
this.log("There are no queues to replace")
}
},
__replaceNextQueue: function (g) {
var f = this.__queues[0].reverse();
var e = this.log.bind(this);
this.__queues.splice(0, 1);
var h = function () {
e("Found " + f.length + " elements to replace.");
var a = function () {
var b = f.pop();
if (!b) {
e("No more images to start replacing.");
if (typeof g === "function") {
g()
}
g = Prototype.emptyFunction;
return
}
b.replace(function (c) {
e("Replaced image.", b.hiResSrc(), "status: " + b.status());
a()
})
};
$R(0, this.options.queueSize - 1).each(a)
}.bind(this);
window.setTimeout(h, 10)
},
__respondToSwapView: function (h) {
var e = h.event_data.data.incomingView.content;
var f = h.event_data.data.sender.view.view();
var g = this.addToQueue.bind(this);
this.prioritize(this.potentialElements(e, f)).each(g);
this.replace()
},
__setup: function () {
if (this.options.listenToSwapView === true && "Listener" in Event && typeof AC.ViewMaster !== "undefined") {
this.respondToSwapView = this.__respondToSwapView.bindAsEventListener(this);
Event.Listener.listenForEvent(AC.ViewMaster, "ViewMasterDidShowNotification", false, this.respondToSwapView)
}
var b = this.addToQueue.bind(this);
this.prioritize(this.potentialElements()).each(b);
this.replace()
}
});
AC.ImageReplacer.normalImageTypeRegex = /(\.jpg($|#.*|\?.*)|\.png($|#.*|\?.*)|\.gif($|#.*|\?.*))/;
AC.ImageReplacer.devicePixelRatio = function () {
if (typeof AC.ImageReplacer._devicePixelRatio !== "undefined") {
return AC.ImageReplacer._devicePixelRatio
}
if ("devicePixelRatio" in window && window.devicePixelRatio > 1) {
return AC.ImageReplacer._devicePixelRatio = 2
} else {
return AC.ImageReplacer._devicePixelRatio = 1
}
};
AC.ImageReplacer.Image = Class.create(Object.clone(AC.Synthesize), {
initialize: function (c, d) {
if (Object.isElement(c)) {
this._el = c;
this._tagName = this._el.tagName.toLowerCase();
this.options = Object.extend(Object.clone(d), AC.ImageReplacer.Image.convertParametersToOptions(this.src()));
this.setStatus("considered");
this.synthesize()
}
},
__synthesizeSetter: Prototype.emptyFunction,
preload: function (c) {
if (this._isPreloaded) {
return true
}
this.setStatus("loading");
var d = new Element("img");
d.observe("load", function () {
this._isPreloaded = true;
this.width = d.width;
this.height = d.height;
this.setStatus("replaced");
if (typeof c === "function") {
c()
}
}.bind(this));
d.observe("error", function () {
this.setStatus("404");
this._exists = false;
if (typeof c === "function") {
c()
}
}.bind(this));
d.src = this.hiResSrc()
},
replace: function (c) {
var d = this.replace.bind(this, c);
if (this._exists === false) {
this.setStatus("404");
if (typeof c === "function") {
c(false)
}
return
}
if (this.options.checkExists === true && typeof this._exists === "undefined") {
return this.requestHeaders(d)
}
if (this.isImageLink()) {
this._el.setAttribute("href", this.hiResSrc());
this.setStatus("replaced");
if (typeof c === "function") {
c(true)
}
} else {
if ((this.options.preload === true || this._tagName !== "img") && this._isPreloaded !== true) {
return this.preload(d)
}
if (this._tagName === "img") {
this._el.setAttribute("src", this.hiResSrc());
if ((this.options.preload !== true)) {
this.setStatus("loading");
this._el.observe("load", function (a) {
this.setStatus("replaced");
if (typeof c === "function") {
c(true)
}
}.bindAsEventListener(this));
this._el.observe("error", function (a) {
this.setStatus("404");
this._el.setAttribute("src", this.src());
if (typeof c === "function") {
c(false)
}
}.bindAsEventListener(this))
}
} else {
this._el.setStyle("background-image:url(" + this.hiResSrc() + ");");
this._el.setStyle("background-size:" + (this.width / AC.ImageReplacer.devicePixelRatio()) + "px " + (this.height / AC.ImageReplacer.devicePixelRatio()) + "px;");
if (typeof c === "function") {
c(true)
}
}
}
this._el.responsiveImageObject = this;
this.synthesize()
},
requestHeaders: function (f) {
var e = this;
if (typeof e._headers === "undefined") {
var d = new XMLHttpRequest();
var e = this;
src = this.hiResSrc().replace(/^http:\/\/.*\.apple\.com\//, "/");
d.open("HEAD", src, true);
d.onreadystatechange = function () {
if (d.readyState == 4) {
if (d.status === 200) {
e._exists = true;
var a = d.getAllResponseHeaders();
e._headers = {
src: src
};
var c, b;
a = a.split("\r");
for (c = 0;
c < a.length; c++) {
b = a[c].split(": ");
if (b.length > 1) {
e._headers[b[0].replace("\n", "")] = b[1]
}
}
} else {
e._exists = false;
e._headers = null
}
if (typeof f === "function") {
f(e._headers, e)
}
}
};
d.send(null)
} else {
f(e._headers, e)
}
},
requestFileSize: function (f) {
var d = this;
if (typeof d._fileSize === "undefined") {
var e = function (a) {
d._fileSize = parseFloat(a["Content-Length"]) / 1000;
if (typeof f === "function") {
f(d._fileSize, d)
}
};
this.requestHeaders(e)
} else {
f(d._fileSize, d)
}
},
src: function () {
if (typeof this._src !== "undefined") {
return this._src
}
if (this.isImageLink()) {
this._src = this._el.getAttribute("href")
} else {
if (this._tagName === "img") {
this._src = this._el.getAttribute("src")
} else {
this._src = AC.ImageReplacer.Image.removeCSSURLSyntax(this._el.getStyle("background-image"));
if (this._src === "none") {
return this._src = ""
}
}
}
return this._src
},
hiResSrc: function () {
if (typeof this._hiResSrc !== "undefined") {
return this._hiResSrc
}
var b;
if (typeof this.options.hiresFormat === "string") {
b = this.src().match(/^(.*)((\.[a-z]{3})($|#.*|\?.*))/i);
if (b !== null && b.length > 1) {
return this._hiResSrc = b[1] + "." + this.options.hiresFormat + (b[4] || "")
}
}
b = this.src().match(this.options.filenameRegex);
if (b === null) {
return this._hiResSrc = null
} else {
return this._hiResSrc = b[1] + this.options.filenameInsert.replace("☃", AC.ImageReplacer.devicePixelRatio()) + b[2]
}
},
isHiRes: function () {
if (this._isHiRes === true) {
return this._isHiRes
}
if (this.status() === "replaced") {
return this._isHiRes = true
}
var b = this.src();
if (b.match(AC.ImageReplacer.normalImageTypeRegex) === null) {
return this._isHiRes = true
}
if (b.match(this.options.ignoreCheck) !== null) {
return this._isHiRes = true
}
this._isHiRes = false
},
isImageLink: function () {
if (typeof this._isImageLink !== "undefined") {
return this._isImageLink
}
return this._isImageLink = (this._el.hasClassName("imageLink") && this._tagName === "a")
},
priority: function () {
if (typeof this._priority !== "undefined") {
return this._priority
}
if (this.options.recursive && this._el.hasAttribute(this.options.attribute) === false) {
var b = this._el.up("[" + this.options.attribute + "]");
if ( !! b) {
this._priority = parseInt(b.getAttribute(this.options.attribute))
} else {
this._priority = this.options.lowestPriority
}
} else {
this._priority = parseInt(this._el.getAttribute(this.options.attribute))
}
if (isNaN(this._priority) || this._priority > this.options.lowestPriority) {
this._priority = this.options.lowestPriority
} else {
if (this._priority < 0) {
this._priority = 0
}
}
return this._priority
},
setStatus: function (b) {
if (typeof b === "string") {
this._status = b;
this._el.setAttribute(this.options.replacedAttribute, b)
}
},
status: function () {
return this._el.getAttribute(this.options.replacedAttribute)
}
});
AC.ImageReplacer.Image.removeCSSURLSyntax = function (b) {
if (typeof b === "string" && typeof b.replace === "function") {
return b.replace(/^url\(/, "").replace(/\)$/, "")
}
return ""
};
AC.ImageReplacer.Image.convertParametersToOptions = function (d) {
if (typeof d === "string" && typeof d.toQueryParams === "function") {
var e = d.toQueryParams(),
f;
for (f in e) {
if (e.hasOwnProperty(f)) {
e[f.camelize()] = e[f]
}
}
return e
}
return {}
};
AC.ImageReplacer.autoInstance = new AC.ImageReplacer();
var windowHasLoaded = false;
Event.observe(window, "load", function () {
windowHasLoaded = true
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment