foundation.interchange.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. ;(function ($, window, document, undefined) {
  2. 'use strict';
  3. Foundation.libs.interchange = {
  4. name : 'interchange',
  5. version : '5.0.0',
  6. cache : {},
  7. images_loaded : false,
  8. nodes_loaded : false,
  9. settings : {
  10. load_attr : 'interchange',
  11. named_queries : {
  12. 'default' : Foundation.media_queries.small,
  13. small : Foundation.media_queries.small,
  14. medium : Foundation.media_queries.medium,
  15. large : Foundation.media_queries.large,
  16. xlarge : Foundation.media_queries.xlarge,
  17. xxlarge: Foundation.media_queries.xxlarge,
  18. landscape : 'only screen and (orientation: landscape)',
  19. portrait : 'only screen and (orientation: portrait)',
  20. retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
  21. 'only screen and (min--moz-device-pixel-ratio: 2),' +
  22. 'only screen and (-o-min-device-pixel-ratio: 2/1),' +
  23. 'only screen and (min-device-pixel-ratio: 2),' +
  24. 'only screen and (min-resolution: 192dpi),' +
  25. 'only screen and (min-resolution: 2dppx)'
  26. },
  27. directives : {
  28. replace: function (el, path, trigger) {
  29. // The trigger argument, if called within the directive, fires
  30. // an event named after the directive on the element, passing
  31. // any parameters along to the event that you pass to trigger.
  32. //
  33. // ex. trigger(), trigger([a, b, c]), or trigger(a, b, c)
  34. //
  35. // This allows you to bind a callback like so:
  36. // $('#interchangeContainer').on('replace', function (e, a, b, c) {
  37. // console.log($(this).html(), a, b, c);
  38. // });
  39. if (/IMG/.test(el[0].nodeName)) {
  40. var orig_path = el[0].src;
  41. if (new RegExp(path, 'i').test(orig_path)) return;
  42. el[0].src = path;
  43. return trigger(el[0].src);
  44. }
  45. var last_path = el.data('interchange-last-path');
  46. if (last_path == path) return;
  47. return $.get(path, function (response) {
  48. el.html(response);
  49. el.data('interchange-last-path', path);
  50. trigger();
  51. });
  52. }
  53. }
  54. },
  55. init : function (scope, method, options) {
  56. Foundation.inherit(this, 'throttle');
  57. this.data_attr = 'data-' + this.settings.load_attr;
  58. this.bindings(method, options);
  59. this.load('images');
  60. this.load('nodes');
  61. },
  62. events : function () {
  63. var self = this;
  64. $(window)
  65. .off('.interchange')
  66. .on('resize.fndtn.interchange', self.throttle(function () {
  67. self.resize.call(self);
  68. }, 50));
  69. return this;
  70. },
  71. resize : function () {
  72. var cache = this.cache;
  73. if(!this.images_loaded || !this.nodes_loaded) {
  74. setTimeout($.proxy(this.resize, this), 50);
  75. return;
  76. }
  77. for (var uuid in cache) {
  78. if (cache.hasOwnProperty(uuid)) {
  79. var passed = this.results(uuid, cache[uuid]);
  80. if (passed) {
  81. this.settings.directives[passed
  82. .scenario[1]](passed.el, passed.scenario[0], function () {
  83. if (arguments[0] instanceof Array) {
  84. var args = arguments[0];
  85. } else {
  86. var args = Array.prototype.slice.call(arguments, 0);
  87. }
  88. passed.el.trigger(passed.scenario[1], args);
  89. });
  90. }
  91. }
  92. }
  93. },
  94. results : function (uuid, scenarios) {
  95. var count = scenarios.length;
  96. if (count > 0) {
  97. var el = this.S('[data-uuid="' + uuid + '"]');
  98. for (var i = count - 1; i >= 0; i--) {
  99. var mq, rule = scenarios[i][2];
  100. if (this.settings.named_queries.hasOwnProperty(rule)) {
  101. mq = matchMedia(this.settings.named_queries[rule]);
  102. } else {
  103. mq = matchMedia(rule);
  104. }
  105. if (mq.matches) {
  106. return {el: el, scenario: scenarios[i]};
  107. }
  108. }
  109. }
  110. return false;
  111. },
  112. load : function (type, force_update) {
  113. if (typeof this['cached_' + type] === 'undefined' || force_update) {
  114. this['update_' + type]();
  115. }
  116. return this['cached_' + type];
  117. },
  118. update_images : function () {
  119. var images = this.S('img[' + this.data_attr + ']'),
  120. count = images.length,
  121. loaded_count = 0,
  122. data_attr = this.data_attr;
  123. this.cache = {};
  124. this.cached_images = [];
  125. this.images_loaded = (count === 0);
  126. for (var i = count - 1; i >= 0; i--) {
  127. loaded_count++;
  128. if (images[i]) {
  129. var str = images[i].getAttribute(data_attr) || '';
  130. if (str.length > 0) {
  131. this.cached_images.push(images[i]);
  132. }
  133. }
  134. if(loaded_count === count) {
  135. this.images_loaded = true;
  136. this.enhance('images');
  137. }
  138. }
  139. return this;
  140. },
  141. update_nodes : function () {
  142. var nodes = this.S('[' + this.data_attr + ']:not(img)'),
  143. count = nodes.length,
  144. loaded_count = 0,
  145. data_attr = this.data_attr;
  146. this.cached_nodes = [];
  147. // Set nodes_loaded to true if there are no nodes
  148. // this.nodes_loaded = false;
  149. this.nodes_loaded = (count === 0);
  150. for (var i = count - 1; i >= 0; i--) {
  151. loaded_count++;
  152. var str = nodes[i].getAttribute(data_attr) || '';
  153. if (str.length > 0) {
  154. this.cached_nodes.push(nodes[i]);
  155. }
  156. if(loaded_count === count) {
  157. this.nodes_loaded = true;
  158. this.enhance('nodes');
  159. }
  160. }
  161. return this;
  162. },
  163. enhance : function (type) {
  164. var count = this['cached_' + type].length;
  165. for (var i = count - 1; i >= 0; i--) {
  166. this.object($(this['cached_' + type][i]));
  167. }
  168. return $(window).trigger('resize');
  169. },
  170. parse_params : function (path, directive, mq) {
  171. return [this.trim(path), this.convert_directive(directive), this.trim(mq)];
  172. },
  173. convert_directive : function (directive) {
  174. var trimmed = this.trim(directive);
  175. if (trimmed.length > 0) {
  176. return trimmed;
  177. }
  178. return 'replace';
  179. },
  180. object : function(el) {
  181. var raw_arr = this.parse_data_attr(el),
  182. scenarios = [], count = raw_arr.length;
  183. if (count > 0) {
  184. for (var i = count - 1; i >= 0; i--) {
  185. var split = raw_arr[i].split(/\((.*?)(\))$/);
  186. if (split.length > 1) {
  187. var cached_split = split[0].split(','),
  188. params = this.parse_params(cached_split[0],
  189. cached_split[1], split[1]);
  190. scenarios.push(params);
  191. }
  192. }
  193. }
  194. return this.store(el, scenarios);
  195. },
  196. uuid : function (separator) {
  197. var delim = separator || "-";
  198. function S4() {
  199. return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  200. }
  201. return (S4() + S4() + delim + S4() + delim + S4()
  202. + delim + S4() + delim + S4() + S4() + S4());
  203. },
  204. store : function (el, scenarios) {
  205. var uuid = this.uuid(),
  206. current_uuid = el.data('uuid');
  207. if (current_uuid) return this.cache[current_uuid];
  208. el.attr('data-uuid', uuid);
  209. return this.cache[uuid] = scenarios;
  210. },
  211. trim : function(str) {
  212. if (typeof str === 'string') {
  213. return $.trim(str);
  214. }
  215. return str;
  216. },
  217. parse_data_attr : function (el) {
  218. var raw = el.data(this.settings.load_attr).split(/\[(.*?)\]/),
  219. count = raw.length, output = [];
  220. for (var i = count - 1; i >= 0; i--) {
  221. if (raw[i].replace(/[\W\d]+/, '').length > 4) {
  222. output.push(raw[i]);
  223. }
  224. }
  225. return output;
  226. },
  227. reflow : function () {
  228. this.load('images', true);
  229. this.load('nodes', true);
  230. }
  231. };
  232. }(jQuery, this, this.document));