msrp.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /**
  2. * Copyright © Magento, Inc. All rights reserved.
  3. * See COPYING.txt for license details.
  4. */
  5. define([
  6. 'jquery',
  7. 'Magento_Catalog/js/price-utils',
  8. 'underscore',
  9. 'jquery/ui',
  10. 'mage/dropdown',
  11. 'mage/template'
  12. ], function ($, priceUtils, _) {
  13. 'use strict';
  14. $.widget('mage.addToCart', {
  15. options: {
  16. showAddToCart: true,
  17. submitUrl: '',
  18. cartButtonId: '',
  19. singleOpenDropDown: true,
  20. dialog: {}, // Options for mage/dropdown
  21. dialogDelay: 500, // Delay in ms after resize dropdown shown again
  22. origin: '', //Required, type of popup: 'msrp', 'tier' or 'info' popup
  23. // Selectors
  24. cartForm: '.form.map.checkout',
  25. msrpLabelId: '#map-popup-msrp',
  26. msrpPriceElement: '#map-popup-msrp .price-wrapper',
  27. priceLabelId: '#map-popup-price',
  28. priceElement: '#map-popup-price .price',
  29. mapInfoLinks: '.map-show-info',
  30. displayPriceElement: '.old-price.map-old-price .price-wrapper',
  31. fallbackPriceElement: '.normal-price.map-fallback-price .price-wrapper',
  32. displayPriceContainer: '.old-price.map-old-price',
  33. fallbackPriceContainer: '.normal-price.map-fallback-price',
  34. popUpAttr: '[data-role=msrp-popup-template]',
  35. popupCartButtonId: '#map-popup-button',
  36. paypalCheckoutButons: '[data-action=checkout-form-submit]',
  37. popupId: '',
  38. realPrice: '',
  39. isSaleable: '',
  40. msrpPrice: '',
  41. helpLinkId: '',
  42. addToCartButton: '',
  43. // Text options
  44. productName: '',
  45. addToCartUrl: ''
  46. },
  47. openDropDown: null,
  48. triggerClass: 'dropdown-active',
  49. popUpOptions: {
  50. appendTo: 'body',
  51. dialogContentClass: 'active',
  52. closeOnMouseLeave: false,
  53. autoPosition: true,
  54. closeOnClickOutside: false,
  55. 'dialogClass': 'popup map-popup-wrapper',
  56. position: {
  57. my: 'left top',
  58. collision: 'fit none',
  59. at: 'left bottom',
  60. within: 'body'
  61. },
  62. shadowHinter: 'popup popup-pointer'
  63. },
  64. popupOpened: false,
  65. wasOpened: false,
  66. /**
  67. * Creates widget instance
  68. *
  69. * @private
  70. */
  71. _create: function () {
  72. if (this.options.origin === 'msrp') {
  73. this.initMsrpPopup();
  74. } else if (this.options.origin === 'info') {
  75. this.initInfoPopup();
  76. } else if (this.options.origin === 'tier') {
  77. this.initTierPopup();
  78. }
  79. $(this.options.cartButtonId).on('click', this._addToCartSubmit.bind(this));
  80. $(document).on('updateMsrpPriceBlock', this.onUpdateMsrpPrice.bind(this));
  81. $(this.options.cartForm).on('submit', this._onSubmitForm.bind(this));
  82. },
  83. /**
  84. * Init msrp popup
  85. *
  86. * @private
  87. */
  88. initMsrpPopup: function () {
  89. var popupDOM = $(this.options.popUpAttr)[0],
  90. $msrpPopup = $(popupDOM.innerHTML.trim());
  91. $msrpPopup.find(this.options.productIdInput).val(this.options.productId);
  92. $('body').append($msrpPopup);
  93. $msrpPopup.trigger('contentUpdated');
  94. $msrpPopup.find('button')
  95. .on('click',
  96. this.handleMsrpAddToCart.bind(this))
  97. .filter(this.options.popupCartButtonId)
  98. .text($(this.options.addToCartButton).text());
  99. $msrpPopup.find(this.options.paypalCheckoutButons).on('click',
  100. this.handleMsrpPaypalCheckout.bind(this));
  101. $(this.options.popupId).on('click',
  102. this.openPopup.bind(this));
  103. this.$popup = $msrpPopup;
  104. },
  105. /**
  106. * Init info popup
  107. *
  108. * @private
  109. */
  110. initInfoPopup: function () {
  111. var infoPopupDOM = $('[data-role=msrp-info-template]')[0],
  112. $infoPopup = $(infoPopupDOM.innerHTML.trim());
  113. $('body').append($infoPopup);
  114. $(this.options.helpLinkId).on('click', function (e) {
  115. this.popUpOptions.position.of = $(e.target);
  116. $infoPopup.dropdownDialog(this.popUpOptions).dropdownDialog('open');
  117. this._toggle($infoPopup);
  118. }.bind(this));
  119. this.$popup = $infoPopup;
  120. },
  121. /**
  122. * Init tier price popup
  123. * @private
  124. */
  125. initTierPopup: function () {
  126. var popupDOM = $(this.options.popUpAttr)[0],
  127. $tierPopup = $(popupDOM.innerHTML.trim());
  128. $('body').append($tierPopup);
  129. $tierPopup.find(this.options.productIdInput).val(this.options.productId);
  130. this.popUpOptions.position.of = $(this.options.helpLinkId);
  131. $tierPopup.find('button').on('click',
  132. this.handleTierAddToCart.bind(this))
  133. .filter(this.options.popupCartButtonId)
  134. .text($(this.options.addToCartButton).text());
  135. $tierPopup.find(this.options.paypalCheckoutButons).on('click',
  136. this.handleTierPaypalCheckout.bind(this));
  137. $(this.options.attr).on('click', function (e) {
  138. this.$popup = $tierPopup;
  139. this.tierOptions = $(e.target).data('tier-price');
  140. this.openPopup(e);
  141. }.bind(this));
  142. },
  143. /**
  144. * handle 'AddToCart' click on Msrp popup
  145. * @param {Object} ev
  146. *
  147. * @private
  148. */
  149. handleMsrpAddToCart: function (ev) {
  150. ev.preventDefault();
  151. if (this.options.addToCartButton) {
  152. $(this.options.addToCartButton).click();
  153. this.closePopup(this.$popup);
  154. }
  155. },
  156. /**
  157. * handle 'paypal checkout buttons' click on Msrp popup
  158. *
  159. * @private
  160. */
  161. handleMsrpPaypalCheckout: function () {
  162. this.closePopup(this.$popup);
  163. },
  164. /**
  165. * handle 'AddToCart' click on Tier popup
  166. *
  167. * @param {Object} ev
  168. * @private
  169. */
  170. handleTierAddToCart: function (ev) {
  171. ev.preventDefault();
  172. if (this.options.addToCartButton &&
  173. this.options.inputQty && !isNaN(this.tierOptions.qty)
  174. ) {
  175. $(this.options.inputQty).val(this.tierOptions.qty);
  176. $(this.options.addToCartButton).click();
  177. this.closePopup(this.$popup);
  178. }
  179. },
  180. /**
  181. * handle 'paypal checkout buttons' click on Tier popup
  182. *
  183. * @private
  184. */
  185. handleTierPaypalCheckout: function () {
  186. if (this.options.inputQty && !isNaN(this.tierOptions.qty)
  187. ) {
  188. $(this.options.inputQty).val(this.tierOptions.qty);
  189. this.closePopup(this.$popup);
  190. }
  191. },
  192. /**
  193. * Open and set up popup
  194. *
  195. * @param {Object} event
  196. */
  197. openPopup: function (event) {
  198. var options = this.tierOptions || this.options;
  199. this.popUpOptions.position.of = $(event.target);
  200. if (!this.wasOpened) {
  201. this.$popup.find(this.options.msrpLabelId).html(options.msrpPrice);
  202. this.$popup.find(this.options.priceLabelId).html(options.realPrice);
  203. this.wasOpened = true;
  204. }
  205. this.$popup.dropdownDialog(this.popUpOptions).dropdownDialog('open');
  206. this._toggle(this.$popup);
  207. if (!this.options.isSaleable) {
  208. this.$popup.find('form').hide();
  209. }
  210. },
  211. /**
  212. * Toggle MAP popup visibility
  213. *
  214. * @param {HTMLElement} $elem
  215. * @private
  216. */
  217. _toggle: function ($elem) {
  218. $(document).on('mouseup.msrp touchend.msrp', function (e) {
  219. if (!$elem.is(e.target) && $elem.has(e.target).length === 0) {
  220. this.closePopup($elem);
  221. }
  222. }.bind(this));
  223. $(window).on('resize', function () {
  224. this.closePopup($elem);
  225. }.bind(this));
  226. },
  227. /**
  228. * Close MAP information popup
  229. *
  230. * @param {HTMLElement} $elem
  231. */
  232. closePopup: function ($elem) {
  233. $elem.dropdownDialog('close');
  234. $(document).off('mouseup.msrp touchend.msrp');
  235. },
  236. /**
  237. * Handler for addToCart action
  238. *
  239. * @param {Object} e
  240. */
  241. _addToCartSubmit: function (e) {
  242. this.element.trigger('addToCart', this.element);
  243. if (this.element.data('stop-processing')) {
  244. return false;
  245. }
  246. if (this.options.addToCartButton) {
  247. $(this.options.addToCartButton).click();
  248. return false;
  249. }
  250. if (this.options.addToCartUrl) {
  251. $('.mage-dropdown-dialog > .ui-dialog-content').dropdownDialog('close');
  252. }
  253. e.preventDefault();
  254. $(this.options.cartForm).submit();
  255. },
  256. /**
  257. * Call on event updatePrice. Proxy to updateMsrpPrice method.
  258. *
  259. * @param {Event} event
  260. * @param {mixed} priceIndex
  261. * @param {Object} prices
  262. */
  263. onUpdateMsrpPrice: function onUpdateMsrpPrice(event, priceIndex, prices) {
  264. var defaultMsrp,
  265. defaultPrice,
  266. msrpPrice,
  267. finalPrice;
  268. defaultMsrp = _.chain(prices).map(function (price) {
  269. return price.msrpPrice.amount;
  270. }).reject(function (p) {
  271. return p === null;
  272. }).max().value();
  273. defaultPrice = _.chain(prices).map(function (p) {
  274. return p.finalPrice.amount;
  275. }).min().value();
  276. if (typeof priceIndex !== 'undefined') {
  277. msrpPrice = prices[priceIndex].msrpPrice.amount;
  278. finalPrice = prices[priceIndex].finalPrice.amount;
  279. if (msrpPrice === null || msrpPrice <= finalPrice) {
  280. this.updateNonMsrpPrice(priceUtils.formatPrice(finalPrice));
  281. } else {
  282. this.updateMsrpPrice(
  283. priceUtils.formatPrice(finalPrice),
  284. priceUtils.formatPrice(msrpPrice),
  285. false);
  286. }
  287. } else {
  288. this.updateMsrpPrice(
  289. priceUtils.formatPrice(defaultPrice),
  290. priceUtils.formatPrice(defaultMsrp),
  291. true);
  292. }
  293. },
  294. /**
  295. * Update prices for configurable product with MSRP enabled
  296. *
  297. * @param {String} finalPrice
  298. * @param {String} msrpPrice
  299. * @param {Boolean} useDefaultPrice
  300. */
  301. updateMsrpPrice: function (finalPrice, msrpPrice, useDefaultPrice) {
  302. var options = this.tierOptions || this.options;
  303. $(this.options.fallbackPriceContainer).hide();
  304. $(this.options.displayPriceContainer).show();
  305. $(this.options.mapInfoLinks).show();
  306. if (useDefaultPrice || !this.wasOpened) {
  307. this.$popup.find(this.options.msrpLabelId).html(options.msrpPrice);
  308. this.$popup.find(this.options.priceLabelId).html(options.realPrice);
  309. $(this.options.displayPriceElement).html(msrpPrice);
  310. this.wasOpened = true;
  311. }
  312. if (!useDefaultPrice) {
  313. this.$popup.find(this.options.msrpPriceElement).html(msrpPrice);
  314. this.$popup.find(this.options.priceElement).html(finalPrice);
  315. $(this.options.displayPriceElement).html(msrpPrice);
  316. }
  317. },
  318. /**
  319. * Display non MAP price for irrelevant products
  320. *
  321. * @param {String} price
  322. */
  323. updateNonMsrpPrice: function (price) {
  324. $(this.options.fallbackPriceElement).html(price);
  325. $(this.options.displayPriceContainer).hide();
  326. $(this.options.mapInfoLinks).hide();
  327. $(this.options.fallbackPriceContainer).show();
  328. },
  329. /**
  330. * Handler for submit form
  331. *
  332. * @private
  333. */
  334. _onSubmitForm: function () {
  335. if ($(this.options.cartForm).valid()) {
  336. $(this.options.cartButtonId).prop('disabled', true);
  337. }
  338. }
  339. });
  340. return $.mage.addToCart;
  341. });