Copy files from jekyll-asciidoc-quickstart
[web.git] / js / foundation / foundation.interchange.js
1 ;
2 (function ($, window, document, undefined) {
3 'use strict';
4
5 Foundation.libs.interchange = {
6 name: 'interchange',
7
8 version: '5.5.0',
9
10 cache: {},
11
12 images_loaded: false,
13 nodes_loaded: false,
14
15 settings: {
16 load_attr: 'interchange',
17
18 named_queries: {
19 'default': 'only screen',
20 'small': Foundation.media_queries['small'],
21 'small-only': Foundation.media_queries['small-only'],
22 'medium': Foundation.media_queries['medium'],
23 'medium-only': Foundation.media_queries['medium-only'],
24 'large': Foundation.media_queries['large'],
25 'large-only': Foundation.media_queries['large-only'],
26 'xlarge': Foundation.media_queries['xlarge'],
27 'xlarge-only': Foundation.media_queries['xlarge-only'],
28 'xxlarge': Foundation.media_queries['xxlarge'],
29 'landscape': 'only screen and (orientation: landscape)',
30 'portrait': 'only screen and (orientation: portrait)',
31 'retina': 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
32 'only screen and (min--moz-device-pixel-ratio: 2),' +
33 'only screen and (-o-min-device-pixel-ratio: 2/1),' +
34 'only screen and (min-device-pixel-ratio: 2),' +
35 'only screen and (min-resolution: 192dpi),' +
36 'only screen and (min-resolution: 2dppx)'
37 },
38
39 directives: {
40 replace: function (el, path, trigger) {
41 // The trigger argument, if called within the directive, fires
42 // an event named after the directive on the element, passing
43 // any parameters along to the event that you pass to trigger.
44 //
45 // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
46 //
47 // This allows you to bind a callback like so:
48 // $('#interchangeContainer').on('replace', function (e, a, b, c) {
49 // console.log($(this).html(), a, b, c);
50 // });
51
52 if (/IMG/.test(el[0].nodeName)) {
53 var orig_path = el[0].src;
54
55 if (new RegExp(path, 'i').test(orig_path)) return;
56
57 el[0].src = path;
58
59 return trigger(el[0].src);
60 }
61 var last_path = el.data(this.data_attr + '-last-path'),
62 self = this;
63
64 if (last_path == path) return;
65
66 if (/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(path)) {
67 $(el).css('background-image', 'url(' + path + ')');
68 el.data('interchange-last-path', path);
69 return trigger(path);
70 }
71
72 return $.get(path, function (response) {
73 el.html(response);
74 el.data(self.data_attr + '-last-path', path);
75 trigger();
76 });
77
78 }
79 }
80 },
81
82 init: function (scope, method, options) {
83 Foundation.inherit(this, 'throttle random_str');
84
85 this.data_attr = this.set_data_attr();
86 $.extend(true, this.settings, method, options);
87 this.bindings(method, options);
88 this.load('images');
89 this.load('nodes');
90 },
91
92 get_media_hash: function () {
93 var mediaHash = '';
94 for (var queryName in this.settings.named_queries) {
95 mediaHash += matchMedia(this.settings.named_queries[queryName]).matches.toString();
96 }
97 return mediaHash;
98 },
99
100 events: function () {
101 var self = this, prevMediaHash;
102
103 $(window)
104 .off('.interchange')
105 .on('resize.fndtn.interchange', self.throttle(function () {
106 var currMediaHash = self.get_media_hash();
107 if (currMediaHash !== prevMediaHash) {
108 self.resize();
109 }
110 prevMediaHash = currMediaHash;
111 }, 50));
112
113 return this;
114 },
115
116 resize: function () {
117 var cache = this.cache;
118
119 if (!this.images_loaded || !this.nodes_loaded) {
120 setTimeout($.proxy(this.resize, this), 50);
121 return;
122 }
123
124 for (var uuid in cache) {
125 if (cache.hasOwnProperty(uuid)) {
126 var passed = this.results(uuid, cache[uuid]);
127
128 if (passed) {
129 this.settings.directives[passed
130 .scenario[1]].call(this, passed.el, passed.scenario[0], function () {
131 if (arguments[0] instanceof Array) {
132 var args = arguments[0];
133 } else {
134 var args = Array.prototype.slice.call(arguments, 0);
135 }
136
137 passed.el.trigger(passed.scenario[1], args);
138 });
139 }
140 }
141 }
142
143 },
144
145 results: function (uuid, scenarios) {
146 var count = scenarios.length;
147
148 if (count > 0) {
149 var el = this.S('[' + this.add_namespace('data-uuid') + '="' + uuid + '"]');
150
151 while (count--) {
152 var mq, rule = scenarios[count][2];
153 if (this.settings.named_queries.hasOwnProperty(rule)) {
154 mq = matchMedia(this.settings.named_queries[rule]);
155 } else {
156 mq = matchMedia(rule);
157 }
158 if (mq.matches) {
159 return {el: el, scenario: scenarios[count]};
160 }
161 }
162 }
163
164 return false;
165 },
166
167 load: function (type, force_update) {
168 if (typeof this['cached_' + type] === 'undefined' || force_update) {
169 this['update_' + type]();
170 }
171
172 return this['cached_' + type];
173 },
174
175 update_images: function () {
176 var images = this.S('img[' + this.data_attr + ']'),
177 count = images.length,
178 i = count,
179 loaded_count = 0,
180 data_attr = this.data_attr;
181
182 this.cache = {};
183 this.cached_images = [];
184 this.images_loaded = (count === 0);
185
186 while (i--) {
187 loaded_count++;
188 if (images[i]) {
189 var str = images[i].getAttribute(data_attr) || '';
190
191 if (str.length > 0) {
192 this.cached_images.push(images[i]);
193 }
194 }
195
196 if (loaded_count === count) {
197 this.images_loaded = true;
198 this.enhance('images');
199 }
200 }
201
202 return this;
203 },
204
205 update_nodes: function () {
206 var nodes = this.S('[' + this.data_attr + ']').not('img'),
207 count = nodes.length,
208 i = count,
209 loaded_count = 0,
210 data_attr = this.data_attr;
211
212 this.cached_nodes = [];
213 this.nodes_loaded = (count === 0);
214
215
216 while (i--) {
217 loaded_count++;
218 var str = nodes[i].getAttribute(data_attr) || '';
219
220 if (str.length > 0) {
221 this.cached_nodes.push(nodes[i]);
222 }
223
224 if (loaded_count === count) {
225 this.nodes_loaded = true;
226 this.enhance('nodes');
227 }
228 }
229
230 return this;
231 },
232
233 enhance: function (type) {
234 var i = this['cached_' + type].length;
235
236 while (i--) {
237 this.object($(this['cached_' + type][i]));
238 }
239
240 return $(window).trigger('resize').trigger('resize.fndtn.interchange');
241 },
242
243 convert_directive: function (directive) {
244
245 var trimmed = this.trim(directive);
246
247 if (trimmed.length > 0) {
248 return trimmed;
249 }
250
251 return 'replace';
252 },
253
254 parse_scenario: function (scenario) {
255 // This logic had to be made more complex since some users were using commas in the url path
256 // So we cannot simply just split on a comma
257 var directive_match = scenario[0].match(/(.+),\s*(\w+)\s*$/),
258 media_query = scenario[1];
259
260 if (directive_match) {
261 var path = directive_match[1],
262 directive = directive_match[2];
263 }
264 else {
265 var cached_split = scenario[0].split(/,\s*$/),
266 path = cached_split[0],
267 directive = '';
268 }
269
270 return [this.trim(path), this.convert_directive(directive), this.trim(media_query)];
271 },
272
273 object: function (el) {
274 var raw_arr = this.parse_data_attr(el),
275 scenarios = [],
276 i = raw_arr.length;
277
278 if (i > 0) {
279 while (i--) {
280 var split = raw_arr[i].split(/\((.*?)(\))$/);
281
282 if (split.length > 1) {
283 var params = this.parse_scenario(split);
284 scenarios.push(params);
285 }
286 }
287 }
288
289 return this.store(el, scenarios);
290 },
291
292 store: function (el, scenarios) {
293 var uuid = this.random_str(),
294 current_uuid = el.data(this.add_namespace('uuid', true));
295
296 if (this.cache[current_uuid]) return this.cache[current_uuid];
297
298 el.attr(this.add_namespace('data-uuid'), uuid);
299
300 return this.cache[uuid] = scenarios;
301 },
302
303 trim: function (str) {
304
305 if (typeof str === 'string') {
306 return $.trim(str);
307 }
308
309 return str;
310 },
311
312 set_data_attr: function (init) {
313 if (init) {
314 if (this.namespace.length > 0) {
315 return this.namespace + '-' + this.settings.load_attr;
316 }
317
318 return this.settings.load_attr;
319 }
320
321 if (this.namespace.length > 0) {
322 return 'data-' + this.namespace + '-' + this.settings.load_attr;
323 }
324
325 return 'data-' + this.settings.load_attr;
326 },
327
328 parse_data_attr: function (el) {
329 var raw = el.attr(this.attr_name()).split(/\[(.*?)\]/),
330 i = raw.length,
331 output = [];
332
333 while (i--) {
334 if (raw[i].replace(/[\W\d]+/, '').length > 4) {
335 output.push(raw[i]);
336 }
337 }
338
339 return output;
340 },
341
342 reflow: function () {
343 this.load('images', true);
344 this.load('nodes', true);
345 }
346
347 };
348
349 }(jQuery, window, window.document));