; (function ($, window, document, undefined) { 'use strict'; Foundation.libs.interchange = { name: 'interchange', version: '5.5.0', cache: {}, images_loaded: false, nodes_loaded: false, settings: { load_attr: 'interchange', named_queries: { 'default': 'only screen', 'small': Foundation.media_queries['small'], 'small-only': Foundation.media_queries['small-only'], 'medium': Foundation.media_queries['medium'], 'medium-only': Foundation.media_queries['medium-only'], 'large': Foundation.media_queries['large'], 'large-only': Foundation.media_queries['large-only'], 'xlarge': Foundation.media_queries['xlarge'], 'xlarge-only': Foundation.media_queries['xlarge-only'], 'xxlarge': Foundation.media_queries['xxlarge'], 'landscape': 'only screen and (orientation: landscape)', 'portrait': 'only screen and (orientation: portrait)', 'retina': 'only screen and (-webkit-min-device-pixel-ratio: 2),' + 'only screen and (min--moz-device-pixel-ratio: 2),' + 'only screen and (-o-min-device-pixel-ratio: 2/1),' + 'only screen and (min-device-pixel-ratio: 2),' + 'only screen and (min-resolution: 192dpi),' + 'only screen and (min-resolution: 2dppx)' }, directives: { replace: function (el, path, trigger) { // The trigger argument, if called within the directive, fires // an event named after the directive on the element, passing // any parameters along to the event that you pass to trigger. // // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c) // // This allows you to bind a callback like so: // $('#interchangeContainer').on('replace', function (e, a, b, c) { // console.log($(this).html(), a, b, c); // }); if (/IMG/.test(el[0].nodeName)) { var orig_path = el[0].src; if (new RegExp(path, 'i').test(orig_path)) return; el[0].src = path; return trigger(el[0].src); } var last_path = el.data(this.data_attr + '-last-path'), self = this; if (last_path == path) return; if (/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(path)) { $(el).css('background-image', 'url(' + path + ')'); el.data('interchange-last-path', path); return trigger(path); } return $.get(path, function (response) { el.html(response); el.data(self.data_attr + '-last-path', path); trigger(); }); } } }, init: function (scope, method, options) { Foundation.inherit(this, 'throttle random_str'); this.data_attr = this.set_data_attr(); $.extend(true, this.settings, method, options); this.bindings(method, options); this.load('images'); this.load('nodes'); }, get_media_hash: function () { var mediaHash = ''; for (var queryName in this.settings.named_queries) { mediaHash += matchMedia(this.settings.named_queries[queryName]).matches.toString(); } return mediaHash; }, events: function () { var self = this, prevMediaHash; $(window) .off('.interchange') .on('resize.fndtn.interchange', self.throttle(function () { var currMediaHash = self.get_media_hash(); if (currMediaHash !== prevMediaHash) { self.resize(); } prevMediaHash = currMediaHash; }, 50)); return this; }, resize: function () { var cache = this.cache; if (!this.images_loaded || !this.nodes_loaded) { setTimeout($.proxy(this.resize, this), 50); return; } for (var uuid in cache) { if (cache.hasOwnProperty(uuid)) { var passed = this.results(uuid, cache[uuid]); if (passed) { this.settings.directives[passed .scenario[1]].call(this, passed.el, passed.scenario[0], function () { if (arguments[0] instanceof Array) { var args = arguments[0]; } else { var args = Array.prototype.slice.call(arguments, 0); } passed.el.trigger(passed.scenario[1], args); }); } } } }, results: function (uuid, scenarios) { var count = scenarios.length; if (count > 0) { var el = this.S('[' + this.add_namespace('data-uuid') + '="' + uuid + '"]'); while (count--) { var mq, rule = scenarios[count][2]; if (this.settings.named_queries.hasOwnProperty(rule)) { mq = matchMedia(this.settings.named_queries[rule]); } else { mq = matchMedia(rule); } if (mq.matches) { return {el: el, scenario: scenarios[count]}; } } } return false; }, load: function (type, force_update) { if (typeof this['cached_' + type] === 'undefined' || force_update) { this['update_' + type](); } return this['cached_' + type]; }, update_images: function () { var images = this.S('img[' + this.data_attr + ']'), count = images.length, i = count, loaded_count = 0, data_attr = this.data_attr; this.cache = {}; this.cached_images = []; this.images_loaded = (count === 0); while (i--) { loaded_count++; if (images[i]) { var str = images[i].getAttribute(data_attr) || ''; if (str.length > 0) { this.cached_images.push(images[i]); } } if (loaded_count === count) { this.images_loaded = true; this.enhance('images'); } } return this; }, update_nodes: function () { var nodes = this.S('[' + this.data_attr + ']').not('img'), count = nodes.length, i = count, loaded_count = 0, data_attr = this.data_attr; this.cached_nodes = []; this.nodes_loaded = (count === 0); while (i--) { loaded_count++; var str = nodes[i].getAttribute(data_attr) || ''; if (str.length > 0) { this.cached_nodes.push(nodes[i]); } if (loaded_count === count) { this.nodes_loaded = true; this.enhance('nodes'); } } return this; }, enhance: function (type) { var i = this['cached_' + type].length; while (i--) { this.object($(this['cached_' + type][i])); } return $(window).trigger('resize').trigger('resize.fndtn.interchange'); }, convert_directive: function (directive) { var trimmed = this.trim(directive); if (trimmed.length > 0) { return trimmed; } return 'replace'; }, parse_scenario: function (scenario) { // This logic had to be made more complex since some users were using commas in the url path // So we cannot simply just split on a comma var directive_match = scenario[0].match(/(.+),\s*(\w+)\s*$/), media_query = scenario[1]; if (directive_match) { var path = directive_match[1], directive = directive_match[2]; } else { var cached_split = scenario[0].split(/,\s*$/), path = cached_split[0], directive = ''; } return [this.trim(path), this.convert_directive(directive), this.trim(media_query)]; }, object: function (el) { var raw_arr = this.parse_data_attr(el), scenarios = [], i = raw_arr.length; if (i > 0) { while (i--) { var split = raw_arr[i].split(/\((.*?)(\))$/); if (split.length > 1) { var params = this.parse_scenario(split); scenarios.push(params); } } } return this.store(el, scenarios); }, store: function (el, scenarios) { var uuid = this.random_str(), current_uuid = el.data(this.add_namespace('uuid', true)); if (this.cache[current_uuid]) return this.cache[current_uuid]; el.attr(this.add_namespace('data-uuid'), uuid); return this.cache[uuid] = scenarios; }, trim: function (str) { if (typeof str === 'string') { return $.trim(str); } return str; }, set_data_attr: function (init) { if (init) { if (this.namespace.length > 0) { return this.namespace + '-' + this.settings.load_attr; } return this.settings.load_attr; } if (this.namespace.length > 0) { return 'data-' + this.namespace + '-' + this.settings.load_attr; } return 'data-' + this.settings.load_attr; }, parse_data_attr: function (el) { var raw = el.attr(this.attr_name()).split(/\[(.*?)\]/), i = raw.length, output = []; while (i--) { if (raw[i].replace(/[\W\d]+/, '').length > 4) { output.push(raw[i]); } } return output; }, reflow: function () { this.load('images', true); this.load('nodes', true); } }; }(jQuery, window, window.document));