Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

424 строки
13 KiB

  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. /**
  6. * @api
  7. */
  8. define([
  9. 'jquery',
  10. 'underscore',
  11. 'ko',
  12. 'Magento_Customer/js/section-config',
  13. 'mage/url',
  14. 'mage/storage',
  15. 'jquery/jquery-storageapi'
  16. ], function ($, _, ko, sectionConfig, url) {
  17. 'use strict';
  18. var options = {},
  19. storage,
  20. storageInvalidation,
  21. invalidateCacheBySessionTimeOut,
  22. invalidateCacheByCloseCookieSession,
  23. dataProvider,
  24. buffer,
  25. customerData,
  26. deferred = $.Deferred();
  27. url.setBaseUrl(window.BASE_URL);
  28. options.sectionLoadUrl = url.build('customer/section/load');
  29. /**
  30. * @param {Object} invalidateOptions
  31. */
  32. invalidateCacheBySessionTimeOut = function (invalidateOptions) {
  33. var date;
  34. if (new Date($.localStorage.get('mage-cache-timeout')) < new Date()) {
  35. storage.removeAll();
  36. }
  37. date = new Date(Date.now() + parseInt(invalidateOptions.cookieLifeTime, 10) * 1000);
  38. $.localStorage.set('mage-cache-timeout', date);
  39. };
  40. /**
  41. * Invalidate Cache By Close Cookie Session
  42. */
  43. invalidateCacheByCloseCookieSession = function () {
  44. if (!$.cookieStorage.isSet('mage-cache-sessid')) {
  45. storage.removeAll();
  46. }
  47. $.cookieStorage.set('mage-cache-sessid', true);
  48. };
  49. dataProvider = {
  50. /**
  51. * @param {Object} sectionNames
  52. * @return {Object}
  53. */
  54. getFromStorage: function (sectionNames) {
  55. var result = {};
  56. _.each(sectionNames, function (sectionName) {
  57. result[sectionName] = storage.get(sectionName);
  58. });
  59. return result;
  60. },
  61. /**
  62. * @param {Object} sectionNames
  63. * @param {Boolean} forceNewSectionTimestamp
  64. * @return {*}
  65. */
  66. getFromServer: function (sectionNames, forceNewSectionTimestamp) {
  67. var parameters;
  68. sectionNames = sectionConfig.filterClientSideSections(sectionNames);
  69. parameters = _.isArray(sectionNames) && sectionNames.indexOf('*') < 0 ? {
  70. sections: sectionNames.join(',')
  71. } : [];
  72. parameters['force_new_section_timestamp'] = forceNewSectionTimestamp;
  73. return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) {
  74. throw new Error(jqXHR);
  75. });
  76. }
  77. };
  78. /**
  79. * @param {Function} target
  80. * @param {String} sectionName
  81. * @return {*}
  82. */
  83. ko.extenders.disposableCustomerData = function (target, sectionName) {
  84. var sectionDataIds, newSectionDataIds = {};
  85. target.subscribe(function () {
  86. setTimeout(function () {
  87. storage.remove(sectionName);
  88. sectionDataIds = $.cookieStorage.get('section_data_ids') || {};
  89. _.each(sectionDataIds, function (data, name) {
  90. if (name !== sectionName) {
  91. newSectionDataIds[name] = data;
  92. }
  93. });
  94. $.cookieStorage.set('section_data_ids', newSectionDataIds);
  95. }, 3000);
  96. });
  97. return target;
  98. };
  99. buffer = {
  100. data: {},
  101. /**
  102. * @param {String} sectionName
  103. */
  104. bind: function (sectionName) {
  105. this.data[sectionName] = ko.observable({});
  106. },
  107. /**
  108. * @param {String} sectionName
  109. * @return {Object}
  110. */
  111. get: function (sectionName) {
  112. if (!this.data[sectionName]) {
  113. this.bind(sectionName);
  114. }
  115. return this.data[sectionName];
  116. },
  117. /**
  118. * @return {Array}
  119. */
  120. keys: function () {
  121. return _.keys(this.data);
  122. },
  123. /**
  124. * @param {String} sectionName
  125. * @param {Object} sectionData
  126. */
  127. notify: function (sectionName, sectionData) {
  128. if (!this.data[sectionName]) {
  129. this.bind(sectionName);
  130. }
  131. this.data[sectionName](sectionData);
  132. },
  133. /**
  134. * @param {Object} sections
  135. */
  136. update: function (sections) {
  137. var sectionId = 0,
  138. sectionDataIds = $.cookieStorage.get('section_data_ids') || {};
  139. _.each(sections, function (sectionData, sectionName) {
  140. sectionId = sectionData['data_id'];
  141. sectionDataIds[sectionName] = sectionId;
  142. storage.set(sectionName, sectionData);
  143. storageInvalidation.remove(sectionName);
  144. buffer.notify(sectionName, sectionData);
  145. });
  146. $.cookieStorage.set('section_data_ids', sectionDataIds);
  147. },
  148. /**
  149. * @param {Object} sections
  150. */
  151. remove: function (sections) {
  152. _.each(sections, function (sectionName) {
  153. storage.remove(sectionName);
  154. if (!sectionConfig.isClientSideSection(sectionName)) {
  155. storageInvalidation.set(sectionName, true);
  156. }
  157. });
  158. }
  159. };
  160. customerData = {
  161. /**
  162. * Customer data initialization
  163. */
  164. init: function () {
  165. var expiredSectionNames = this.getExpiredSectionNames();
  166. if (expiredSectionNames.length > 0) {
  167. _.each(dataProvider.getFromStorage(storage.keys()), function (sectionData, sectionName) {
  168. buffer.notify(sectionName, sectionData);
  169. });
  170. this.reload(expiredSectionNames, false);
  171. } else {
  172. _.each(dataProvider.getFromStorage(storage.keys()), function (sectionData, sectionName) {
  173. buffer.notify(sectionName, sectionData);
  174. });
  175. if (!_.isEmpty(storageInvalidation.keys())) {
  176. this.reload(storageInvalidation.keys(), false);
  177. }
  178. }
  179. if (!_.isEmpty($.cookieStorage.get('section_data_clean'))) {
  180. this.reload(sectionConfig.getSectionNames(), true);
  181. $.cookieStorage.set('section_data_clean', '');
  182. }
  183. },
  184. /**
  185. * Storage init
  186. */
  187. initStorage: function () {
  188. $.cookieStorage.setConf({
  189. path: '/',
  190. expires: new Date(Date.now() + parseInt(options.cookieLifeTime, 10) * 1000)
  191. });
  192. storage = $.initNamespaceStorage('mage-cache-storage').localStorage;
  193. storageInvalidation = $.initNamespaceStorage('mage-cache-storage-section-invalidation').localStorage;
  194. },
  195. /**
  196. * Retrieve the list of sections that has expired since last page reload.
  197. *
  198. * Sections can expire due to lifetime constraints or due to inconsistent storage information
  199. * (validated by cookie data).
  200. *
  201. * @return {Array}
  202. */
  203. getExpiredSectionNames: function () {
  204. var expiredSectionNames = [],
  205. cookieSectionTimestamps = $.cookieStorage.get('section_data_ids') || {},
  206. sectionLifetime = options.expirableSectionLifetime * 60,
  207. currentTimestamp = Math.floor(Date.now() / 1000),
  208. sectionData;
  209. // process sections that can expire due to lifetime constraints
  210. _.each(options.expirableSectionNames, function (sectionName) {
  211. sectionData = storage.get(sectionName);
  212. if (typeof sectionData === 'object' && sectionData['data_id'] + sectionLifetime <= currentTimestamp) {
  213. expiredSectionNames.push(sectionName);
  214. }
  215. });
  216. // process sections that can expire due to storage information inconsistency
  217. _.each(cookieSectionTimestamps, function (cookieSectionTimestamp, sectionName) {
  218. sectionData = storage.get(sectionName);
  219. if (typeof sectionData === 'undefined' ||
  220. typeof sectionData === 'object' &&
  221. cookieSectionTimestamp !== sectionData['data_id']
  222. ) {
  223. expiredSectionNames.push(sectionName);
  224. }
  225. });
  226. //remove expired section names of previously installed/enable modules
  227. expiredSectionNames = _.intersection(expiredSectionNames, sectionConfig.getSectionNames());
  228. return _.uniq(expiredSectionNames);
  229. },
  230. /**
  231. * Check if some sections have to be reloaded.
  232. *
  233. * @deprecated Use getExpiredSectionNames instead.
  234. *
  235. * @return {Boolean}
  236. */
  237. needReload: function () {
  238. var expiredSectionNames = this.getExpiredSectionNames();
  239. return expiredSectionNames.length > 0;
  240. },
  241. /**
  242. * Retrieve the list of expired keys.
  243. *
  244. * @deprecated Use getExpiredSectionNames instead.
  245. *
  246. * @return {Array}
  247. */
  248. getExpiredKeys: function () {
  249. return this.getExpiredSectionNames();
  250. },
  251. /**
  252. * @param {String} sectionName
  253. * @return {*}
  254. */
  255. get: function (sectionName) {
  256. return buffer.get(sectionName);
  257. },
  258. /**
  259. * @param {String} sectionName
  260. * @param {Object} sectionData
  261. */
  262. set: function (sectionName, sectionData) {
  263. var data = {};
  264. data[sectionName] = sectionData;
  265. buffer.update(data);
  266. },
  267. /**
  268. * Avoid using this function directly 'cause of possible performance drawbacks.
  269. * Each customer section reload brings new non-cached ajax request.
  270. *
  271. * @param {Array} sectionNames
  272. * @param {Boolean} forceNewSectionTimestamp
  273. * @return {*}
  274. */
  275. reload: function (sectionNames, forceNewSectionTimestamp) {
  276. return dataProvider.getFromServer(sectionNames, forceNewSectionTimestamp).done(function (sections) {
  277. $(document).trigger('customer-data-reload', [sectionNames]);
  278. buffer.update(sections);
  279. });
  280. },
  281. /**
  282. * @param {Array} sectionNames
  283. */
  284. invalidate: function (sectionNames) {
  285. var sectionDataIds,
  286. sectionsNamesForInvalidation;
  287. sectionsNamesForInvalidation = _.contains(sectionNames, '*') ? sectionConfig.getSectionNames() :
  288. sectionNames;
  289. $(document).trigger('customer-data-invalidate', [sectionsNamesForInvalidation]);
  290. buffer.remove(sectionsNamesForInvalidation);
  291. sectionDataIds = $.cookieStorage.get('section_data_ids') || {};
  292. // Invalidate section in cookie (increase version of section with 1000)
  293. _.each(sectionsNamesForInvalidation, function (sectionName) {
  294. if (!sectionConfig.isClientSideSection(sectionName)) {
  295. sectionDataIds[sectionName] += 1000;
  296. }
  297. });
  298. $.cookieStorage.set('section_data_ids', sectionDataIds);
  299. },
  300. /**
  301. * Checks if customer data is initialized.
  302. *
  303. * @returns {jQuery.Deferred}
  304. */
  305. getInitCustomerData: function () {
  306. return deferred.promise();
  307. },
  308. /**
  309. * Reload sections on ajax complete
  310. *
  311. * @param {Object} jsonResponse
  312. * @param {Object} settings
  313. */
  314. onAjaxComplete: function (jsonResponse, settings) {
  315. var sections,
  316. redirects;
  317. if (settings.type.match(/post|put|delete/i)) {
  318. sections = sectionConfig.getAffectedSections(settings.url);
  319. if (sections && sections.length) {
  320. this.invalidate(sections);
  321. redirects = ['redirect', 'backUrl'];
  322. if (_.isObject(jsonResponse) && !_.isEmpty(_.pick(jsonResponse, redirects))) { //eslint-disable-line
  323. return;
  324. }
  325. this.reload(sections, true);
  326. }
  327. }
  328. },
  329. /**
  330. * @param {Object} settings
  331. * @constructor
  332. */
  333. 'Magento_Customer/js/customer-data': function (settings) {
  334. options = settings;
  335. customerData.initStorage();
  336. invalidateCacheBySessionTimeOut(settings);
  337. invalidateCacheByCloseCookieSession();
  338. customerData.init();
  339. deferred.resolve();
  340. }
  341. };
  342. /**
  343. * Events listener
  344. */
  345. $(document).on('ajaxComplete', function (event, xhr, settings) {
  346. customerData.onAjaxComplete(xhr.responseJSON, settings);
  347. });
  348. /**
  349. * Events listener
  350. */
  351. $(document).on('submit', function (event) {
  352. var sections;
  353. if (event.target.method.match(/post|put|delete/i)) {
  354. sections = sectionConfig.getAffectedSections(event.target.action);
  355. if (sections) {
  356. customerData.invalidate(sections);
  357. }
  358. }
  359. });
  360. return customerData;
  361. });