diff --git a/_assets/javascripts/global/echo.js b/_assets/javascripts/global/echo.js new file mode 100644 index 0000000..0d94724 --- /dev/null +++ b/_assets/javascripts/global/echo.js @@ -0,0 +1,134 @@ +(function (global, factory) { + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = factory(global.document); + } + else if (typeof define === "function" && define.amd) { + define([global.document], factory); + } else { + global = global || self; + global.echo = factory(global.document); + } +})(this, function (root) { + + "use strict"; + + var echo = {}; + + var callback = function () {}; + + var offset, poll, delay, useDebounce, unload; + + var isHidden = function (element) { + return (element.offsetParent === null); + }; + + var inView = function (element, view) { + if (isHidden(element)) { + return false; + } + + var box = element.getBoundingClientRect(); + return (box.right >= view.l && box.bottom >= view.t && box.left <= view.r && box.top <= view.b); + }; + + var debounceOrThrottle = function () { + if(!useDebounce && !!poll) { + return; + } + clearTimeout(poll); + poll = setTimeout(function(){ + echo.render(); + poll = null; + }, delay); + }; + + echo.init = function (opts) { + opts = opts || {}; + var offsetAll = opts.offset || 0; + var offsetVertical = opts.offsetVertical || offsetAll; + var offsetHorizontal = opts.offsetHorizontal || offsetAll; + var optionToInt = function (opt, fallback) { + return parseInt(opt || fallback, 10); + }; + offset = { + t: optionToInt(opts.offsetTop, offsetVertical), + b: optionToInt(opts.offsetBottom, offsetVertical), + l: optionToInt(opts.offsetLeft, offsetHorizontal), + r: optionToInt(opts.offsetRight, offsetHorizontal) + }; + delay = optionToInt(opts.throttle, 250); + useDebounce = opts.debounce !== false; + unload = !!opts.unload; + callback = opts.callback || callback; + echo.render(); + if (document.addEventListener) { + root.addEventListener("scroll", debounceOrThrottle, false); + root.addEventListener("load", debounceOrThrottle, false); + } else { + root.attachEvent("onscroll", debounceOrThrottle); + root.attachEvent("onload", debounceOrThrottle); + } + }; + + echo.render = function () { + var nodes = document.querySelectorAll("img[data-echo], [data-echo-background]"); + var length = nodes.length; + var src, elem; + var view = { + l: 0 - offset.l, + t: 0 - offset.t, + b: (root.innerHeight || document.documentElement.clientHeight) + offset.b, + r: (root.innerWidth || document.documentElement.clientWidth) + offset.r + }; + for (var i = 0; i < length; i++) { + elem = nodes[i]; + if (inView(elem, view)) { + + if (unload) { + elem.setAttribute("data-echo-placeholder", elem.src); + } + + if (elem.getAttribute("data-echo-background") !== null) { + elem.style.backgroundImage = "url(" + elem.getAttribute("data-echo-background") + ")"; + } + else { + elem.src = elem.getAttribute("data-echo"); + } + + if (!unload) { + elem.removeAttribute("data-echo"); + elem.removeAttribute("data-echo-background"); + } + + callback(elem, "load"); + } + else if (unload && !!(src = elem.getAttribute("data-echo-placeholder"))) { + + if (elem.getAttribute("data-echo-background") !== null) { + elem.style.backgroundImage = "url(" + src + ")"; + } + else { + elem.src = src; + } + + elem.removeAttribute("data-echo-placeholder"); + callback(elem, "unload"); + } + } + if (!length) { + echo.detach(); + } + }; + + echo.detach = function () { + if (document.removeEventListener) { + root.removeEventListener("scroll", debounceOrThrottle); + } else { + root.detachEvent("onscroll", debounceOrThrottle); + } + clearTimeout(poll); + }; + + return echo; + +});