You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

311 lines
9.2 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define([
  6. 'jquery',
  7. 'domReady',
  8. 'consoleLogger',
  9. 'Magento_PageCache/js/form-key-provider',
  10. 'jquery-ui-modules/widget',
  11. 'mage/cookies'
  12. ], function ($, domReady, consoleLogger, formKeyInit) {
  13. 'use strict';
  14. /**
  15. * Helper. Generate random string
  16. * TODO: Merge with mage/utils
  17. * @param {String} chars - list of symbols
  18. * @param {Number} length - length for need string
  19. * @returns {String}
  20. */
  21. function generateRandomString(chars, length) {
  22. var result = '';
  23. length = length > 0 ? length : 1;
  24. while (length--) {
  25. result += chars[Math.round(Math.random() * (chars.length - 1))];
  26. }
  27. return result;
  28. }
  29. /**
  30. * Nodes tree to flat list converter
  31. * @returns {Array}
  32. */
  33. $.fn.comments = function () {
  34. var elements = [],
  35. contents,
  36. elementContents;
  37. /**
  38. * @param {jQuery} element - Comment holder
  39. */
  40. (function lookup(element) {
  41. var iframeHostName;
  42. // prevent cross origin iframe content reading
  43. if ($(element).prop('tagName') === 'IFRAME') {
  44. iframeHostName = $('<a>').prop('href', $(element).prop('src'))
  45. .prop('hostname');
  46. if (window.location.hostname !== iframeHostName) {
  47. return [];
  48. }
  49. }
  50. /**
  51. * Rewrite jQuery contents().
  52. *
  53. * @param {jQuery} elem
  54. */
  55. contents = function (elem) {
  56. return $.map(elem, function (el) {
  57. try {
  58. return el.nodeName.toLowerCase() === 'iframe' ?
  59. el.contentDocument || (el.contentWindow ? el.contentWindow.document : []) :
  60. $.merge([], el.childNodes);
  61. } catch (e) {
  62. consoleLogger.error(e);
  63. return [];
  64. }
  65. });
  66. };
  67. elementContents = contents($(element));
  68. $.each(elementContents, function (index, el) {
  69. switch (el.nodeType) {
  70. case 1: // ELEMENT_NODE
  71. lookup(el);
  72. break;
  73. case 8: // COMMENT_NODE
  74. elements.push(el);
  75. break;
  76. case 9: // DOCUMENT_NODE
  77. lookup($(el).find('body'));
  78. break;
  79. }
  80. });
  81. })(this);
  82. return elements;
  83. };
  84. /**
  85. * FormKey Widget - this widget is generating from key, saves it to cookie and
  86. * @deprecated see Magento/PageCache/view/frontend/web/js/form-key-provider.js
  87. */
  88. $.widget('mage.formKey', {
  89. options: {
  90. inputSelector: 'input[name="form_key"]',
  91. allowedCharacters: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
  92. length: 16
  93. },
  94. /**
  95. * Creates widget 'mage.formKey'
  96. * @private
  97. */
  98. _create: function () {
  99. var formKey = $.mage.cookies.get('form_key'),
  100. options = {
  101. secure: window.cookiesConfig ? window.cookiesConfig.secure : false
  102. };
  103. if (!formKey) {
  104. formKey = generateRandomString(this.options.allowedCharacters, this.options.length);
  105. $.mage.cookies.set('form_key', formKey, options);
  106. }
  107. $(this.options.inputSelector).val(formKey);
  108. }
  109. });
  110. /**
  111. * PageCache Widget
  112. * Handles additional ajax request for rendering user private content.
  113. */
  114. $.widget('mage.pageCache', {
  115. options: {
  116. url: '/',
  117. patternPlaceholderOpen: /^ BLOCK (.+) $/,
  118. patternPlaceholderClose: /^ \/BLOCK (.+) $/,
  119. versionCookieName: 'private_content_version',
  120. handles: []
  121. },
  122. /**
  123. * Creates widget 'mage.pageCache'
  124. * @private
  125. */
  126. _create: function () {
  127. var placeholders,
  128. version = $.mage.cookies.get(this.options.versionCookieName);
  129. if (!version) {
  130. return;
  131. }
  132. placeholders = this._searchPlaceholders(this.element.comments());
  133. if (placeholders && placeholders.length) {
  134. this._ajax(placeholders, version);
  135. }
  136. },
  137. /**
  138. * Parse page for placeholders.
  139. * @param {Array} elements
  140. * @returns {Array}
  141. * @private
  142. */
  143. _searchPlaceholders: function (elements) {
  144. var placeholders = [],
  145. tmp = {},
  146. ii,
  147. len,
  148. el, matches, name;
  149. if (!(elements && elements.length)) {
  150. return placeholders;
  151. }
  152. for (ii = 0, len = elements.length; ii < len; ii++) {
  153. el = elements[ii];
  154. matches = this.options.patternPlaceholderOpen.exec(el.nodeValue);
  155. name = null;
  156. if (matches) {
  157. name = matches[1];
  158. tmp[name] = {
  159. name: name,
  160. openElement: el
  161. };
  162. } else {
  163. matches = this.options.patternPlaceholderClose.exec(el.nodeValue);
  164. if (matches) { //eslint-disable-line max-depth
  165. name = matches[1];
  166. if (tmp[name]) { //eslint-disable-line max-depth
  167. tmp[name].closeElement = el;
  168. placeholders.push(tmp[name]);
  169. delete tmp[name];
  170. }
  171. }
  172. }
  173. }
  174. return placeholders;
  175. },
  176. /**
  177. * Parse for page and replace placeholders
  178. * @param {Object} placeholder
  179. * @param {Object} html
  180. * @protected
  181. */
  182. _replacePlaceholder: function (placeholder, html) {
  183. var startReplacing = false,
  184. prevSibling = null,
  185. parent, contents, yy, len, element;
  186. if (!placeholder || !html) {
  187. return;
  188. }
  189. parent = $(placeholder.openElement).parent();
  190. contents = parent.contents();
  191. for (yy = 0, len = contents.length; yy < len; yy++) {
  192. element = contents[yy];
  193. if (element == placeholder.openElement) { //eslint-disable-line eqeqeq
  194. startReplacing = true;
  195. }
  196. if (startReplacing) {
  197. $(element).remove();
  198. } else if (element.nodeType != 8) { //eslint-disable-line eqeqeq
  199. //due to comment tag doesn't have siblings we try to find it manually
  200. prevSibling = element;
  201. }
  202. if (element == placeholder.closeElement) { //eslint-disable-line eqeqeq
  203. break;
  204. }
  205. }
  206. if (prevSibling) {
  207. $(prevSibling).after(html);
  208. } else {
  209. $(parent).prepend(html);
  210. }
  211. // trigger event to use mage-data-init attribute
  212. $(parent).trigger('contentUpdated');
  213. },
  214. /**
  215. * AJAX helper
  216. * @param {Object} placeholders
  217. * @param {String} version
  218. * @private
  219. */
  220. _ajax: function (placeholders, version) {
  221. var ii,
  222. data = {
  223. blocks: [],
  224. handles: this.options.handles,
  225. originalRequest: this.options.originalRequest,
  226. version: version
  227. };
  228. for (ii = 0; ii < placeholders.length; ii++) {
  229. data.blocks.push(placeholders[ii].name);
  230. }
  231. data.blocks = JSON.stringify(data.blocks.sort());
  232. data.handles = JSON.stringify(data.handles);
  233. data.originalRequest = JSON.stringify(data.originalRequest);
  234. $.ajax({
  235. url: this.options.url,
  236. data: data,
  237. type: 'GET',
  238. cache: true,
  239. dataType: 'json',
  240. context: this,
  241. /**
  242. * Response handler
  243. * @param {Object} response
  244. */
  245. success: function (response) {
  246. var placeholder, i;
  247. for (i = 0; i < placeholders.length; i++) {
  248. placeholder = placeholders[i];
  249. if (response.hasOwnProperty(placeholder.name)) {
  250. this._replacePlaceholder(placeholder, response[placeholder.name]);
  251. }
  252. }
  253. }
  254. });
  255. }
  256. });
  257. domReady(function () {
  258. formKeyInit();
  259. });
  260. return {
  261. 'pageCache': $.mage.pageCache,
  262. 'formKey': $.mage.formKey
  263. };
  264. });