sidebar.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define([
  6. 'jquery',
  7. 'Magento_Customer/js/model/authentication-popup',
  8. 'Magento_Customer/js/customer-data',
  9. 'Magento_Ui/js/modal/alert',
  10. 'Magento_Ui/js/modal/confirm',
  11. 'underscore',
  12. 'jquery/ui',
  13. 'mage/decorate',
  14. 'mage/collapsible',
  15. 'mage/cookies'
  16. ], function ($, authenticationPopup, customerData, alert, confirm, _) {
  17. 'use strict';
  18. $.widget('mage.sidebar', {
  19. options: {
  20. isRecursive: true,
  21. minicart: {
  22. maxItemsVisible: 3
  23. }
  24. },
  25. scrollHeight: 0,
  26. shoppingCartUrl: window.checkout.shoppingCartUrl,
  27. /**
  28. * Create sidebar.
  29. * @private
  30. */
  31. _create: function () {
  32. this._initContent();
  33. },
  34. /**
  35. * Update sidebar block.
  36. */
  37. update: function () {
  38. $(this.options.targetElement).trigger('contentUpdated');
  39. this._calcHeight();
  40. this._isOverflowed();
  41. },
  42. /**
  43. * @private
  44. */
  45. _initContent: function () {
  46. var self = this,
  47. events = {};
  48. this.element.decorate('list', this.options.isRecursive);
  49. /**
  50. * @param {jQuery.Event} event
  51. */
  52. events['click ' + this.options.button.close] = function (event) {
  53. event.stopPropagation();
  54. $(self.options.targetElement).dropdownDialog('close');
  55. };
  56. events['click ' + this.options.button.checkout] = $.proxy(function () {
  57. var cart = customerData.get('cart'),
  58. customer = customerData.get('customer'),
  59. element = $(this.options.button.checkout);
  60. if (!customer().firstname && cart().isGuestCheckoutAllowed === false) {
  61. // set URL for redirect on successful login/registration. It's postprocessed on backend.
  62. $.cookie('login_redirect', this.options.url.checkout);
  63. if (this.options.url.isRedirectRequired) {
  64. element.prop('disabled', true);
  65. location.href = this.options.url.loginUrl;
  66. } else {
  67. authenticationPopup.showModal();
  68. }
  69. return false;
  70. }
  71. element.prop('disabled', true);
  72. location.href = this.options.url.checkout;
  73. }, this);
  74. /**
  75. * @param {jQuery.Event} event
  76. */
  77. events['click ' + this.options.button.remove] = function (event) {
  78. event.stopPropagation();
  79. confirm({
  80. content: self.options.confirmMessage,
  81. actions: {
  82. /** @inheritdoc */
  83. confirm: function () {
  84. self._removeItem($(event.currentTarget));
  85. },
  86. /** @inheritdoc */
  87. always: function (e) {
  88. e.stopImmediatePropagation();
  89. }
  90. }
  91. });
  92. };
  93. /**
  94. * @param {jQuery.Event} event
  95. */
  96. events['keyup ' + this.options.item.qty] = function (event) {
  97. self._showItemButton($(event.target));
  98. };
  99. /**
  100. * @param {jQuery.Event} event
  101. */
  102. events['change ' + this.options.item.qty] = function (event) {
  103. self._showItemButton($(event.target));
  104. };
  105. /**
  106. * @param {jQuery.Event} event
  107. */
  108. events['click ' + this.options.item.button] = function (event) {
  109. event.stopPropagation();
  110. self._updateItemQty($(event.currentTarget));
  111. };
  112. /**
  113. * @param {jQuery.Event} event
  114. */
  115. events['focusout ' + this.options.item.qty] = function (event) {
  116. self._validateQty($(event.currentTarget));
  117. };
  118. this._on(this.element, events);
  119. this._calcHeight();
  120. this._isOverflowed();
  121. },
  122. /**
  123. * Add 'overflowed' class to minicart items wrapper element
  124. *
  125. * @private
  126. */
  127. _isOverflowed: function () {
  128. var list = $(this.options.minicart.list),
  129. cssOverflowClass = 'overflowed';
  130. if (this.scrollHeight > list.innerHeight()) {
  131. list.parent().addClass(cssOverflowClass);
  132. } else {
  133. list.parent().removeClass(cssOverflowClass);
  134. }
  135. },
  136. /**
  137. * @param {HTMLElement} elem
  138. * @private
  139. */
  140. _showItemButton: function (elem) {
  141. var itemId = elem.data('cart-item'),
  142. itemQty = elem.data('item-qty');
  143. if (this._isValidQty(itemQty, elem.val())) {
  144. $('#update-cart-item-' + itemId).show('fade', 300);
  145. } else if (elem.val() == 0) { //eslint-disable-line eqeqeq
  146. this._hideItemButton(elem);
  147. } else {
  148. this._hideItemButton(elem);
  149. }
  150. },
  151. /**
  152. * @param {*} origin - origin qty. 'data-item-qty' attribute.
  153. * @param {*} changed - new qty.
  154. * @returns {Boolean}
  155. * @private
  156. */
  157. _isValidQty: function (origin, changed) {
  158. return origin != changed && //eslint-disable-line eqeqeq
  159. changed.length > 0 &&
  160. changed - 0 == changed && //eslint-disable-line eqeqeq
  161. changed - 0 > 0;
  162. },
  163. /**
  164. * @param {Object} elem
  165. * @private
  166. */
  167. _validateQty: function (elem) {
  168. var itemQty = elem.data('item-qty');
  169. if (!this._isValidQty(itemQty, elem.val())) {
  170. elem.val(itemQty);
  171. }
  172. },
  173. /**
  174. * @param {HTMLElement} elem
  175. * @private
  176. */
  177. _hideItemButton: function (elem) {
  178. var itemId = elem.data('cart-item');
  179. $('#update-cart-item-' + itemId).hide('fade', 300);
  180. },
  181. /**
  182. * @param {HTMLElement} elem
  183. * @private
  184. */
  185. _updateItemQty: function (elem) {
  186. var itemId = elem.data('cart-item');
  187. this._ajax(this.options.url.update, {
  188. 'item_id': itemId,
  189. 'item_qty': $('#cart-item-' + itemId + '-qty').val()
  190. }, elem, this._updateItemQtyAfter);
  191. },
  192. /**
  193. * Update content after update qty
  194. *
  195. * @param {HTMLElement} elem
  196. */
  197. _updateItemQtyAfter: function (elem) {
  198. var productData = this._getProductById(Number(elem.data('cart-item')));
  199. if (!_.isUndefined(productData)) {
  200. $(document).trigger('ajax:updateCartItemQty');
  201. if (window.location.href === this.shoppingCartUrl) {
  202. window.location.reload(false);
  203. }
  204. }
  205. this._hideItemButton(elem);
  206. },
  207. /**
  208. * @param {HTMLElement} elem
  209. * @private
  210. */
  211. _removeItem: function (elem) {
  212. var itemId = elem.data('cart-item');
  213. this._ajax(this.options.url.remove, {
  214. 'item_id': itemId
  215. }, elem, this._removeItemAfter);
  216. },
  217. /**
  218. * Update content after item remove
  219. *
  220. * @param {Object} elem
  221. * @private
  222. */
  223. _removeItemAfter: function (elem) {
  224. var productData = this._getProductById(Number(elem.data('cart-item')));
  225. if (!_.isUndefined(productData)) {
  226. $(document).trigger('ajax:removeFromCart', {
  227. productIds: [productData['product_id']]
  228. });
  229. }
  230. },
  231. /**
  232. * Retrieves product data by Id.
  233. *
  234. * @param {Number} productId - product Id
  235. * @returns {Object|undefined}
  236. * @private
  237. */
  238. _getProductById: function (productId) {
  239. return _.find(customerData.get('cart')().items, function (item) {
  240. return productId === Number(item['item_id']);
  241. });
  242. },
  243. /**
  244. * @param {String} url - ajax url
  245. * @param {Object} data - post data for ajax call
  246. * @param {Object} elem - element that initiated the event
  247. * @param {Function} callback - callback method to execute after AJAX success
  248. */
  249. _ajax: function (url, data, elem, callback) {
  250. $.extend(data, {
  251. 'form_key': $.mage.cookies.get('form_key')
  252. });
  253. $.ajax({
  254. url: url,
  255. data: data,
  256. type: 'post',
  257. dataType: 'json',
  258. context: this,
  259. /** @inheritdoc */
  260. beforeSend: function () {
  261. elem.attr('disabled', 'disabled');
  262. },
  263. /** @inheritdoc */
  264. complete: function () {
  265. elem.attr('disabled', null);
  266. }
  267. })
  268. .done(function (response) {
  269. var msg;
  270. if (response.success) {
  271. callback.call(this, elem, response);
  272. } else {
  273. msg = response['error_message'];
  274. if (msg) {
  275. alert({
  276. content: msg
  277. });
  278. }
  279. }
  280. })
  281. .fail(function (error) {
  282. console.log(JSON.stringify(error));
  283. });
  284. },
  285. /**
  286. * Calculate height of minicart list
  287. *
  288. * @private
  289. */
  290. _calcHeight: function () {
  291. var self = this,
  292. height = 0,
  293. counter = this.options.minicart.maxItemsVisible,
  294. target = $(this.options.minicart.list),
  295. outerHeight;
  296. self.scrollHeight = 0;
  297. target.children().each(function () {
  298. if ($(this).find('.options').length > 0) {
  299. $(this).collapsible();
  300. }
  301. outerHeight = $(this).outerHeight();
  302. if (counter-- > 0) {
  303. height += outerHeight;
  304. }
  305. self.scrollHeight += outerHeight;
  306. });
  307. target.parent().height(height);
  308. }
  309. });
  310. return $.mage.sidebar;
  311. });