foundation.interchange.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. 'use strict';
  2. import $ from 'jquery';
  3. import { MediaQuery } from './foundation.util.mediaQuery';
  4. import { Plugin } from './foundation.core.plugin';
  5. import { GetYoDigits } from './foundation.core.utils';
  6. /**
  7. * Interchange module.
  8. * @module foundation.interchange
  9. * @requires foundation.util.mediaQuery
  10. */
  11. class Interchange extends Plugin {
  12. /**
  13. * Creates a new instance of Interchange.
  14. * @class
  15. * @name Interchange
  16. * @fires Interchange#init
  17. * @param {Object} element - jQuery object to add the trigger to.
  18. * @param {Object} options - Overrides to the default plugin settings.
  19. */
  20. _setup(element, options) {
  21. this.$element = element;
  22. this.options = $.extend({}, Interchange.defaults, options);
  23. this.rules = [];
  24. this.currentPath = '';
  25. this.className = 'Interchange'; // ie9 back compat
  26. this._init();
  27. this._events();
  28. }
  29. /**
  30. * Initializes the Interchange plugin and calls functions to get interchange functioning on load.
  31. * @function
  32. * @private
  33. */
  34. _init() {
  35. MediaQuery._init();
  36. var id = this.$element[0].id || GetYoDigits(6, 'interchange');
  37. this.$element.attr({
  38. 'data-resize': id,
  39. 'id': id
  40. });
  41. this._addBreakpoints();
  42. this._generateRules();
  43. this._reflow();
  44. }
  45. /**
  46. * Initializes events for Interchange.
  47. * @function
  48. * @private
  49. */
  50. _events() {
  51. this.$element.off('resizeme.zf.trigger').on('resizeme.zf.trigger', () => this._reflow());
  52. }
  53. /**
  54. * Calls necessary functions to update Interchange upon DOM change
  55. * @function
  56. * @private
  57. */
  58. _reflow() {
  59. var match;
  60. // Iterate through each rule, but only save the last match
  61. for (var i in this.rules) {
  62. if(this.rules.hasOwnProperty(i)) {
  63. var rule = this.rules[i];
  64. if (window.matchMedia(rule.query).matches) {
  65. match = rule;
  66. }
  67. }
  68. }
  69. if (match) {
  70. this.replace(match.path);
  71. }
  72. }
  73. /**
  74. * Gets the Foundation breakpoints and adds them to the Interchange.SPECIAL_QUERIES object.
  75. * @function
  76. * @private
  77. */
  78. _addBreakpoints() {
  79. for (var i in MediaQuery.queries) {
  80. if (MediaQuery.queries.hasOwnProperty(i)) {
  81. var query = MediaQuery.queries[i];
  82. Interchange.SPECIAL_QUERIES[query.name] = query.value;
  83. }
  84. }
  85. }
  86. /**
  87. * Checks the Interchange element for the provided media query + content pairings
  88. * @function
  89. * @private
  90. * @param {Object} element - jQuery object that is an Interchange instance
  91. * @returns {Array} scenarios - Array of objects that have 'mq' and 'path' keys with corresponding keys
  92. */
  93. _generateRules(element) {
  94. var rulesList = [];
  95. var rules;
  96. if (this.options.rules) {
  97. rules = this.options.rules;
  98. }
  99. else {
  100. rules = this.$element.data('interchange');
  101. }
  102. rules = typeof rules === 'string' ? rules.match(/\[.*?, .*?\]/g) : rules;
  103. for (var i in rules) {
  104. if(rules.hasOwnProperty(i)) {
  105. var rule = rules[i].slice(1, -1).split(', ');
  106. var path = rule.slice(0, -1).join('');
  107. var query = rule[rule.length - 1];
  108. if (Interchange.SPECIAL_QUERIES[query]) {
  109. query = Interchange.SPECIAL_QUERIES[query];
  110. }
  111. rulesList.push({
  112. path: path,
  113. query: query
  114. });
  115. }
  116. }
  117. this.rules = rulesList;
  118. }
  119. /**
  120. * Update the `src` property of an image, or change the HTML of a container, to the specified path.
  121. * @function
  122. * @param {String} path - Path to the image or HTML partial.
  123. * @fires Interchange#replaced
  124. */
  125. replace(path) {
  126. if (this.currentPath === path) return;
  127. var _this = this,
  128. trigger = 'replaced.zf.interchange';
  129. // Replacing images
  130. if (this.$element[0].nodeName === 'IMG') {
  131. this.$element.attr('src', path).on('load', function() {
  132. _this.currentPath = path;
  133. })
  134. .trigger(trigger);
  135. }
  136. // Replacing background images
  137. else if (path.match(/\.(gif|jpg|jpeg|png|svg|tiff)([?#].*)?/i)) {
  138. path = path.replace(/\(/g, '%28').replace(/\)/g, '%29');
  139. this.$element.css({ 'background-image': 'url('+path+')' })
  140. .trigger(trigger);
  141. }
  142. // Replacing HTML
  143. else {
  144. $.get(path, function(response) {
  145. _this.$element.html(response)
  146. .trigger(trigger);
  147. $(response).foundation();
  148. _this.currentPath = path;
  149. });
  150. }
  151. /**
  152. * Fires when content in an Interchange element is done being loaded.
  153. * @event Interchange#replaced
  154. */
  155. // this.$element.trigger('replaced.zf.interchange');
  156. }
  157. /**
  158. * Destroys an instance of interchange.
  159. * @function
  160. */
  161. _destroy() {
  162. this.$element.off('resizeme.zf.trigger')
  163. }
  164. }
  165. /**
  166. * Default settings for plugin
  167. */
  168. Interchange.defaults = {
  169. /**
  170. * Rules to be applied to Interchange elements. Set with the `data-interchange` array notation.
  171. * @option
  172. * @type {?array}
  173. * @default null
  174. */
  175. rules: null
  176. };
  177. Interchange.SPECIAL_QUERIES = {
  178. 'landscape': 'screen and (orientation: landscape)',
  179. 'portrait': 'screen and (orientation: portrait)',
  180. '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)'
  181. };
  182. export {Interchange};