PageSourceSearch

https://www.perfectdraft.com/static/version0.0.0.1228/frontend/BeerHawk/perfectdraft/en_BE/Anowave_Ec/js/ec.js

js perfectdraft.com collected 2026-10-09 22:39:32 UTC 35,440 bytes, 1,773 lines download raw bytes

1/**
2 * Anowave Magento 2 Google Tag Manager Enhanced Ecommerce (UA) Tracking
3 *
4 * NOTICE OF LICENSE
5 *
6 * This source file is subject to the Anowave license that is
7 * available through the world-wide-web at this URL:
8 * http://www.anowave.com/license-agreement/
9 *
10 * DISCLAIMER
11 *
12 * Do not edit or add to this file if you wish to upgrade this extension to newer
13 * version in the future.
14 *
15 * @category 	Anowave
16 * @package 	Anowave_Ec
17 * @copyright 	Copyright (c) 2020 Anowave (http://www.anowave.com/)
18 * @license  	http://www.anowave.com/license-agreement/
19 */
20
21if ('undefined' === typeof log)
22{
23	var log = function (message)
24	{
25		window.console && console.log ? console.log(message) : null;
26	};
27}
28
29var AEC = (function()
30{
31	return {
32		debug: false,
33		eventCallback: true,
34		/**
35		 * Track "Add to cart" from detail page
36		 *
37		 * @param (domelement) context
38		 * @param (object) dataLayer
39		 * @return boolean
40		 */
41		ajax:function(context,dataLayer)
42		{
43			var element = jQuery(context), qty = jQuery(':radio[name=qty]:checked, [name=qty]').eq(0).val(), variant = [], variant_attribute_option = [], products = [];
44
45			/**
46			 * Cast quantity to integer
47			 */
48			qty = Math.abs(qty);
49
50			if (isNaN(qty))
51			{
52				qty = 1;
53			}
54
55			/**
56			 * Validate "Add to cart" before firing an event
57			 */
58			var form = jQuery(context).closest('form');
59
60			if (form.length)
61			{
62				if (!form.valid())
63				{
64					return true;
65				}
66			}
67
68			if (!AEC.gtm())
69			{
70				/**
71				 * Invoke original click event(s)
72				 */
73				if (element.data('click'))
74				{
75					/**
76					 * Track time
77					 */
78					AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
79
80					eval(element.data('click'));
81				}
82
83				return true;
84			}
85
86			if(element.data('configurable'))
87			{
88				var attributes = jQuery('[name^="super_attribute"]'), variants = [];
89
90				jQuery.each(attributes, function(index, attribute)
91				{
92					if (jQuery(attribute).is('select'))
93					{
94						var name = jQuery(attribute).attr('name'), id = name.substring(name.indexOf('[') + 1, name.lastIndexOf(']'));
95
96						var option = jQuery(attribute).find('option:selected');
97
98						if (0 < parseInt(option.val()))
99						{
100							variants.push(
101								{
102									id: 	id,
103									option: option.val(),
104									text: 	option.text()
105								});
106						}
107					}
108				});
109
110				/**
111				 * Colour Swatch support
112				 */
113				if (!variants.length)
114				{
115					jQuery.each(AEC.SUPER, function(index, attribute)
116					{
117						var swatch = jQuery('div[attribute-code="' + attribute.code + '"]');
118
119						if (swatch.length)
120						{
121							var variant =
122								{
123									id: 	attribute.id,
124									text:	'',
125									option: null,
126								};
127
128							var select = swatch.find('select');
129
130							if (select.length)
131							{
132								var option = swatch.find('select').find(':selected');
133
134								if (option.length)
135								{
136									variant.text 	= option.text();
137									variant.option 	= option.val();
138								}
139							}
140							else
141							{
142								var span = swatch.find('span.swatch-attribute-selected-option');
143
144								if (span.length)
145								{
146									variant.text 	= span.text();
147									variant.option 	= span.parent().attr('option-selected');
148								}
149							}
150
151							variants.push(variant);
152						}
153					});
154				}
155
156				var SUPER_SELECTED = [];
157
158
159				if (true)
160				{
161					for (i = 0, l = variants.length; i < l; i++)
162					{
163						for (a = 0, b = AEC.SUPER.length; a < b; a++)
164						{
165							if (AEC.SUPER[a].id == variants[i].id)
166							{
167								var text = variants[i].text;
168
169								if (AEC.useDefaultValues)
170								{
171									jQuery.each(AEC.SUPER[a].options, function(index, option)
172									{
173										if (parseInt(option.value_index) == parseInt(variants[i].option))
174										{
175											text = option.admin_label;
176										}
177									});
178								}
179
180								variant.push([AEC.SUPER[a].label,text].join(AEC.Const.VARIANT_DELIMITER_ATT));
181
182								/**
183								 * Push selected options
184								 */
185								variant_attribute_option.push(
186									{
187										attribute: 	variants[i].id,
188										option: 	variants[i].option
189									})
190							}
191						}
192					}
193				}
194
195				if (!variant.length)
196				{
197					/**
198					 * Invoke original click event(s)
199					 */
200					if (element.data('click'))
201					{
202						/**
203						 * Track time
204						 */
205						AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
206
207						eval(element.data('click'));
208					}
209
210					return true;
211				}
212			}
213
214			if (element.data('grouped'))
215			{
216				for (u = 0, y = window.G.length; u < y; u++)
217				{
218					var qty = Math.abs(jQuery('[name="super_group[' + window.G[u].id + ']"]').val());
219
220					if (qty)
221					{
222						products.push(
223							{
224								'name': 		window.G[u].name,
225								'id': 		    window.G[u].sku,
226								'price': 		window.G[u].price,
227								'category': 	window.G[u].category,
228								'brand':		window.G[u].brand,
229								'quantity': 	qty
230							});
231					}
232				}
233			}
234			else
235			{
236				qty = element.data('quantity') ? element.data('quantity') : qty;
237				products.push(
238					{
239						'name': 		element.data('name'),
240						'id': 		    element.data('id'),
241						'price': 		element.data('price'),
242						'category': 	element.data('category'),
243						'brand':		element.data('brand'),
244						'variant':		variant.join(AEC.Const.VARIANT_DELIMITER),
245						'quantity': 	qty
246					});
247			}
248
249			/**
250			 * Affiliation attributes
251			 */
252			for (i = 0, l = products.length; i < l; i++)
253			{
254				(function(product)
255				{
256					jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value)
257					{
258						product[key] = value;
259					});
260				})(products[i]);
261
262			}
263
264			var data =
265				{
266					'event': 'addToCart',
267					'eventLabel': element.data('name'),
268					'ecommerce':
269						{
270							'currencyCode': AEC.currencyCode,
271							'add':
272								{
273									'actionField':
274										{
275											'list': element.data('list')
276										},
277									'products': products
278								},
279							'options': variant_attribute_option
280						},
281					'eventCallback': function()
282					{
283						if (AEC.eventCallback)
284						{
285							if (element.data('event'))
286							{
287								element.trigger(element.data('event'));
288							}
289
290							if (element.data('click'))
291							{
292								eval(element.data('click'));
293							}
294						}
295					},
296					'currentStore': element.data('currentstore')
297				};
298
299			if (AEC.useDefaultValues)
300			{
301				data['currentstore'] = AEC.storeName;
302			}
303
304			/**
305			 * Track event
306			 */
307			AEC.Cookie.add(data).push(dataLayer);
308
309			/**
310			 * Save backreference
311			 */
312			if (AEC.localStorage)
313			{
314				(function(products)
315				{
316					for (var i = 0, l = products.length; i < l; i++)
317					{
318						AEC.Storage.reference().set(
319							{
320								id: products[i].id,
321								category: products[i].category
322							});
323					}
324				})(products);
325			}
326
327			/**
328			 * Track time
329			 */
330			AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
331
332			if (AEC.facebook)
333			{
334				if ("undefined" !== typeof fbq)
335				{
336					(function(product, products, fbq)
337					{
338						var content_ids = [], price = 0;
339
340						for (i = 0, l = products.length; i < l; i++)
341						{
342							content_ids.push(products[i].id);
343
344							price += parseFloat(products[i].price);
345						}
346
347						(function(callback)
348						{
349							if (AEC.Const.COOKIE_DIRECTIVE)
350							{
351								AEC.CookieConsent.queue(callback).process();
352							}
353							else
354							{
355								callback.apply(window,[]);
356							}
357						})
358						(
359							(function(product, content_ids, price)
360							{
361								return function()
362								{
363									fbq('track', 'AddToCart',
364										{
365											content_name: 	product,
366											content_ids: 	content_ids,
367											content_type: 	'product',
368											value: 			price,
369											currency: 		AEC.currencyCode
370										});
371								}
372							})(product, content_ids, price)
373						);
374
375					})(element.data('name'), products, fbq);
376				}
377			}
378
379			/**
380			 * Invoke original click event(s)
381			 */
382			if (element.data('click'))
383			{
384				eval(element.data('click'));
385			}
386
387			return true;
388		},
389		/**
390		 * Track "Add to cart" from listings page
391		 *
392		 * @param (domelement) context
393		 * @param (object) dataLayer
394		 * @return boolean
395		 */
396		ajaxSwatch: function(context,dataLayer)
397		{
398			(function($, element)
399			{
400				$(document).on('ajax:addToCart', function()
401				{
402					var attributes = [];
403
404					jQuery.each(AEC.parseJSON(element.data('swatch')), function(key, value)
405					{
406						attributes.push(value)
407					});
408
409					var variant =
410						[
411							[
412								attributes[0].attribute_label,
413								$('.swatch-option.selected').attr('option-label')
414							].join(AEC.Const.VARIANT_DELIMITER_ATT)
415						].join(AEC.Const.VARIANT_DELIMITER)
416
417					var products =
418						[
419							{
420								'name': 		element.data('name'),
421								'id': 		    element.data('id'),
422								'price': 		element.data('price'),
423								'category': 	element.data('category'),
424								'brand':		element.data('brand'),
425								'variant':		variant,
426								'quantity': 	1
427							}
428						];
429					var data =
430						{
431							'event': 'addToCart',
432							'eventLabel': element.data('name'),
433							'ecommerce':
434								{
435									'currencyCode': AEC.currencyCode,
436									'add':
437										{
438											'actionField':
439												{
440													'list': element.data('list')
441												},
442											'products': products
443										}
444								},
445							'currentStore': element.data('currentstore')
446						}
447
448					/**
449					 * Track event
450					 */
451					AEC.Cookie.add(data).push(dataLayer);
452
453					/**
454					 * Track time
455					 */
456					AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
457				});
458			})(jQuery, jQuery(context));
459
460			return true;
461		},
462		/**
463		 * Track "Add to cart" from listings page
464		 *
465		 * @param (domelement) context
466		 * @param (object) dataLayer
467		 * @return boolean
468		 */
469		ajaxList:function(context,dataLayer)
470		{
471			var element = jQuery(context),
472				products = [],
473				qty = parseInt(jQuery(context).parent().find('[name=qty]').val());;
474
475			if (!AEC.gtm())
476			{
477				/**
478				 * Invoke original click event(s)
479				 */
480				if (element.data('click'))
481				{
482					/**
483					 * Track time
484					 */
485					AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
486
487					eval(element.data('click'));
488				}
489
490				return true;
491			}
492
493			products.push(
494				{
495					'name': 		element.data('name'),
496					'id': 		    element.data('id'),
497					'price': 		element.data('price'),
498					'category': 	element.data('category'),
499					'brand':		element.data('brand'),
500					'position':		element.data('position'),
501					'quantity': 	qty
502				});
503
504			/**
505			 * Affiliation attributes
506			 */
507			for (i = 0, l = products.length; i < l; i++)
508			{
509				(function(product)
510				{
511					jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value)
512					{
513						product[key] = value;
514					});
515				})(products[i]);
516			}
517
518			var data =
519				{
520					'event': 'addToCart',
521					'eventLabel': element.data('name'),
522					'ecommerce':
523						{
524							'currencyCode': AEC.currencyCode,
525							'add':
526								{
527									'actionField':
528										{
529											'list': element.data('list')
530										},
531									'products': products
532								}
533						},
534					'eventCallback': function()
535					{
536						if (AEC.eventCallback)
537						{
538							if (element.data('event'))
539							{
540								element.trigger(element.data('event'));
541							}
542
543							if (element.data('click'))
544							{
545								eval(element.data('click'));
546							}
547						}
548					},
549					'currentStore': element.data('store')
550				};
551
552			/**
553			 * Track event
554			 */
555			AEC.Cookie.add(data).push(dataLayer);
556
557			/**
558			 * Save backreference
559			 */
560			if (AEC.localStorage)
561			{
562				(function(products)
563				{
564					for (var i = 0, l = products.length; i < l; i++)
565					{
566						AEC.Storage.reference().set(
567							{
568								id: products[i].id,
569								category: products[i].category
570							});
571					}
572				})(products);
573			}
574
575			/**
576			 * Track time
577			 */
578			AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_ADD_TO_CART, element.data('name'), element.data('category'));
579
580			if (AEC.facebook)
581			{
582				if ("undefined" !== typeof fbq)
583				{
584					(function(product, products, fbq)
585					{
586						var content_ids = [], price = 0;
587
588						for (i = 0, l = products.length; i < l; i++)
589						{
590							content_ids.push(products[i].id);
591
592							price += parseFloat(products[i].price);
593						}
594
595						(function(callback)
596						{
597							if (AEC.Const.COOKIE_DIRECTIVE)
598							{
599								AEC.CookieConsent.queue(callback).process();
600							}
601							else
602							{
603								callback.apply(window,[]);
604							}
605						})
606						(
607							(function(product, content_ids, price)
608							{
609								return function()
610								{
611									fbq('track', 'AddToCart',
612										{
613											content_name: 	product,
614											content_ids: 	content_ids,
615											content_type: 	'product',
616											value: 			price,
617											currency: 		AEC.currencyCode
618										});
619								}
620							})(product, content_ids, price)
621						);
622
623					})(element.data('name'), products, fbq);
624				}
625			}
626
627			/**
628			 * Invoke original click event(s)
629			 */
630			if (element.data('click'))
631			{
632				eval(element.data('click'));
633			}
634
635			return true;
636		},
637		/**
638		 * Track "Product click" event
639		 *
640		 * @param (domelement) context
641		 * @param (object) dataLayer
642		 * @return boolean
643		 */
644		click: function(context,dataLayer)
645		{
646			var element = jQuery(context);
647
648			if (!AEC.gtm())
649			{
650				/**
651				 * Track time
652				 */
653				AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.data('name'), element.data('category'));
654
655				return true;
656			}
657
658			var item =
659				{
660					'name': 		element.data('name'),
661					'id': 			element.data('id'),
662					'price': 		element.data('price'),
663					'category': 	element.data('category'),
664					'brand':		element.data('brand'),
665					'quantity': 	element.data('quantity'),
666					'position':		element.data('position')
667				};
668
669			jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value)
670			{
671				item[key] = value;
672			});
673
674			var data =
675				{
676					'event': 'productClick',
677					'eventLabel': element.data('name'),
678					'ecommerce':
679						{
680							'click':
681								{
682									'actionField':
683										{
684											'list': element.data('list')
685										},
686									'products':
687										[
688											item
689										]
690								}
691						},
692					'eventCallback': function()
693					{
694						if (AEC.eventCallback)
695						{
696							if (element.data('event'))
697							{
698								element.trigger(element.data('event'));
699							}
700
701							if (element.data('click'))
702							{
703								eval(element.data('click'));
704							}
705							else if (element.is('a'))
706							{
707								document.location = element.attr('href');
708							}
709							else if (element.is('img') && element.parent().is('a'))
710							{
711								document.location = element.parent().attr('href');
712							}
713							else
714							{
715								return true;
716							}
717						}
718					},
719					'eventTarget': (function(element)
720					{
721						/**
722						 * Default target
723						 */
724						var target = 'Default';
725
726						/**
727						 * Check if element is anchor
728						 */
729						if (element.is('a'))
730						{
731							target = 'Link';
732
733							if (element.find('img').length > 0)
734							{
735								target = 'Image';
736							}
737						}
738
739						if (element.is('button'))
740						{
741							target = 'Button';
742						}
743
744						return target;
745
746					})(element),
747					'currentStore': element.data('store')
748				};
749
750			/**
751			 * Push data
752			 */
753			AEC.Cookie.click(data).push(dataLayer);
754
755			/**
756			 * Track time
757			 */
758			AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_CLICK, element.data('name'), element.data('category'));
759
760			if (element.data('click'))
761			{
762				eval(element.data('click'));
763			}
764
765			if (AEC.eventCallback)
766			{
767				return false;
768			}
769
770			return true;
771		},
772		/**
773		 * Track "Remove From Cart" event
774		 *
775		 * @param (domelement) context
776		 * @param (object) dataLayer
777		 * @return boolean
778		 */
779		remove: function(context, dataLayer)
780		{
781			var element = jQuery(context);
782
783			if (!AEC.gtm())
784			{
785				/**
786				 * Track time
787				 */
788				AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name'), element.data('category'));
789
790				return true;
791			}
792
793			var item =
794				{
795					'name': 		element.data('name'),
796					'id': 			element.data('id'),
797					'price': 		element.data('price'),
798					'category': 	element.data('category'),
799					'brand':		element.data('brand'),
800					'quantity': 	element.data('quantity')
801				};
802
803
804			jQuery.each(AEC.parseJSON(element.data('attributes')), function(key, value)
805			{
806				item[key] = value;
807			});
808
809			var data =
810				{
811					'event': 'removeFromCart',
812					'eventLabel': element.data('name'),
813					'ecommerce':
814						{
815							'remove':
816								{
817									'actionField':
818										{
819											'list': element.data('list')
820										},
821									'products':
822										[
823											item
824										]
825								}
826						}
827				};
828
829			if (AEC.Message.confirm)
830			{
831				(function($)
832				{
833					require(['Magento_Ui/js/modal/confirm'], function(confirmation)
834					{
835						confirmation(
836							{
837								title: AEC.Message.confirmRemoveTitle,
838								content: AEC.Message.confirmRemove,
839								actions:
840									{
841										confirm: function()
842										{
843											/**
844											 * Track event
845											 */
846											AEC.Cookie.remove(data).push(dataLayer);
847
848											/**
849											 * Track time
850											 */
851											AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name'));
852
853											/**
854											 * Execute standard data-post
855											 */
856											var params = $(element).data('post-action');
857
858											$(document).dataPost('postData', params);
859										},
860										cancel: function()
861										{
862											return false;
863										},
864										always: function()
865										{
866											return false;
867										}
868									}
869							});
870					});
871
872				})(jQuery);
873			}
874			else
875			{
876				/**
877				 * Track event
878				 */
879				AEC.Cookie.remove(data).push(dataLayer);
880
881				/**
882				 * Track time
883				 */
884				AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_REMOVE_FROM_CART, element.data('name'));
885			}
886
887			return false;
888		},
889		wishlist: function(context, dataLayer)
890		{
891			var element = jQuery(context);
892
893			if (!AEC.gtm())
894			{
895				/**
896				 * Track time
897				 */
898				AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_WISHLIST, element.data('name'),'Wishlist');
899
900				return true;
901			}
902
903			/**
904			 * Push data
905			 */
906			dataLayer.push(
907				{
908					'event': 		element.data('event'),
909					'eventLabel':	element.data('event-label')
910				});
911
912			return true;
913		},
914		compare: function(context, dataLayer)
915		{
916			var element = jQuery(context);
917
918			if (!AEC.gtm())
919			{
920				/**
921				 * Track time
922				 */
923				AEC.Time.track(dataLayer, AEC.Const.TIMING_CATEGORY_PRODUCT_COMPARE, element.data('name'),'Compare');
924
925				return true;
926			}
927
928			/**
929			 * Push data
930			 */
931			dataLayer.push(
932				{
933					'event': 		element.data('event'),
934					'eventLabel':	element.data('event-label')
935				});
936
937			return true;
938		},
939		Bind: (function()
940		{
941			return {
942				apply: function(parameters)
943				{
944					/**
945					 * Merge persistent storage
946					 */
947					AEC.Persist.merge();
948
949					/**
950					 * Push private data
951					 */
952					AEC.Cookie.pushPrivate();
953
954					/**
955					 * Add listeners
956					 */
957					require(['jquery'], function($)
958					{
959						$('body').on(
960							{
961								catalogCategoryAddToCartRedirect: function()
962								{
963									dataLayer.push(
964										{
965											event: AEC.Const.CATALOG_CATEGORY_ADD_TO_CART_REDIRECT_EVENT
966										});
967								}
968							});
969
970						if (parameters)
971						{
972							if (parameters.performance)
973							{
974								if (window.performance)
975								{
976									window.onload = function()
977									{
978										setTimeout(function()
979										{
980											var time = performance.timing.loadEventEnd - performance.timing.responseEnd;
981
982											var timePayload =
983												{
984													'event':'performance',
985													'performance':
986														{
987															'timingCategory':	'Load times',
988															'timingVar':		'load',
989															'timingValue': 		(time % 60000)
990														}
991												};
992
993											switch(window.google_tag_params.ecomm_pagetype)
994											{
995												case 'home':
996
997													timePayload.performance.timingLabel = 'Home';
998
999													dataLayer.push(timePayload);
1000
1001													break;
1002												case 'product':
1003
1004													timePayload.performance.timingLabel = 'Product';
1005
1006													dataLayer.push(timePayload);
1007
1008													break;
1009
1010												case 'category':
1011
1012													timePayload.performance.timingLabel = 'Category';
1013
1014													dataLayer.push(timePayload);
1015
1016													break;
1017											}
1018
1019										}, 0);
1020									}
1021								}
1022							}
1023						}
1024					});
1025
1026					return this;
1027				}
1028			}
1029		})(),
1030		Time: (function()
1031		{
1032			var T =
1033				{
1034					event: 			'trackTime',
1035					timingCategory:	'',
1036					timingVar:		'',
1037					timingValue:	-1,
1038					timingLabel:	''
1039				};
1040
1041			var time = new Date().getTime();
1042
1043			return {
1044				track: function(dataLayer, category, variable, label)
1045				{
1046					T.timingValue = (new Date().getTime()) - time;
1047
1048					if (category)
1049					{
1050						T.timingCategory = category;
1051					}
1052
1053					if (variable)
1054					{
1055						T.timingVar = variable;
1056					}
1057
1058					if (label)
1059					{
1060						T.timingLabel = label;
1061					}
1062
1063					(function(callback)
1064					{
1065						if (AEC.Const.COOKIE_DIRECTIVE)
1066						{
1067							AEC.CookieConsent.queue(callback).process();
1068						}
1069						else
1070						{
1071							callback.apply(window,[]);
1072						}
1073					})
1074					(
1075						(function(dataLayer, T)
1076						{
1077							return function()
1078							{
1079								dataLayer.push(T);
1080							}
1081						})(dataLayer, T)
1082					);
1083				},
1084				trackContinue: function(dataLayer, category, variable, label)
1085				{
1086					this.track(dataLayer, category, variable, label);
1087
1088					/**
1089					 * Reset time
1090					 */
1091					time = new Date().getTime();
1092				}
1093			}
1094		})(),
1095		Persist:(function()
1096		{
1097			var DATA_KEY = 'persist';
1098
1099			var proto = 'undefined' != typeof Storage ?
1100				{
1101					push: function(key, entity)
1102					{
1103						/**
1104						 * Get data
1105						 */
1106						var data = this.data();
1107
1108						/**
1109						 * Push data
1110						 */
1111						data[key] = entity;
1112
1113						/**
1114						 * Save to local storage
1115						 */
1116						localStorage.setItem(DATA_KEY, JSON.stringify(data));
1117
1118						return this;
1119					},
1120					data: function()
1121					{
1122						var data = localStorage.getItem(DATA_KEY);
1123
1124						if (null !== data)
1125						{
1126							return JSON.parse(data);
1127						}
1128
1129						return {};
1130					},
1131					merge: function()
1132					{
1133						var data = this.data();
1134						var push =
1135							{
1136								persist: {}
1137							}
1138
1139						for (var i in data)
1140						{
1141							push.persist[i] = data[i];
1142						}
1143
1144						dataLayer.push(push);
1145
1146						return this;
1147					},
1148					clear: function()
1149					{
1150						/**
1151						 * Reset private local storage
1152						 */
1153						localStorage.setItem(DATA_KEY,JSON.stringify({}));
1154
1155						return this;
1156					}
1157				} : {
1158					push: 	function(){},
1159					merge: 	function(){},
1160					clear: 	function(){}
1161				}
1162
1163			/**
1164			 * Constants
1165			 */
1166			proto.CONST_KEY_PROMOTION = 'persist_promotion';
1167
1168			return proto;
1169
1170		})(),
1171		Checkout: (function()
1172		{
1173			return {
1174				data: {},
1175				tracked: {},
1176				step: function(previous, current, currentCode)
1177				{
1178					if (this.data && this.data.hasOwnProperty('ecommerce'))
1179					{
1180						this.data.ecommerce.checkout.actionField.step = ++current;
1181
1182						if (AEC.Const.COOKIE_DIRECTIVE)
1183						{
1184							if (AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED)
1185							{
1186								dataLayer.push(this.data);
1187							}
1188						}
1189						else
1190						{
1191							dataLayer.push(this.data);
1192						}
1193					}
1194
1195					return this;
1196				},
1197				stepOption: function(step, option)
1198				{
1199					if (!option)
1200					{
1201						return this;
1202					}
1203
1204					if (!option.toString().length)
1205					{
1206						return this;
1207					}
1208
1209					var data =
1210						{
1211							'event': 'checkoutOption',
1212							'ecommerce':
1213								{
1214									'checkout_option':
1215										{
1216											'actionField':
1217												{
1218													'step': step,
1219													'option': option
1220												}
1221										}
1222								}
1223						};
1224
1225					if (AEC.Const.COOKIE_DIRECTIVE)
1226					{
1227						if (AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED)
1228						{
1229							dataLayer.push(data);
1230						}
1231					}
1232					else
1233					{
1234						dataLayer.push(data);
1235					}
1236
1237					return this;
1238				}
1239			}
1240		})(),
1241		Cookie: (function() //This is an experimental feature to overcome FPC (Full Page Cache) related issues (beta)
1242		{
1243			return {
1244				data: null,
1245				privateData: null,
1246				push: function(dataLayer, consent)
1247				{
1248					consent = typeof consent !== 'undefined' ? consent : true;
1249
1250					if (this.data)
1251					{
1252						if (consent)
1253						{
1254							if (AEC.Const.COOKIE_DIRECTIVE)
1255							{
1256								if (AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED)
1257								{
1258									dataLayer.push(this.data);
1259								}
1260							}
1261							else
1262							{
1263								dataLayer.push(this.data);
1264							}
1265						}
1266						else
1267						{
1268							dataLayer.push(this.data);
1269						}
1270
1271						/**
1272						 * Reset data to prevent further push
1273						 */
1274						this.data = null;
1275					}
1276
1277					return this;
1278				},
1279				pushPrivate: function()
1280				{
1281					var data = this.getPrivateData();
1282
1283					if (data)
1284					{
1285						dataLayer.push(
1286							{
1287								privateData: data
1288							});
1289					}
1290
1291					return this;
1292				},
1293				/**
1294				 * Augment products array [] and map category with localStorage reference
1295				 */
1296				augment: function(products)
1297				{
1298					/**
1299					 * Parse data & apply local reference
1300					 */
1301					var reference = AEC.Storage.reference().get();
1302
1303					if (reference)
1304					{
1305						for (var i = 0, l = products.length; i < l; i++)
1306						{
1307							for (var a = 0, b = reference.length; a < b; a++)
1308							{
1309								if (products[i].id.toString().toLowerCase() === reference[a].id.toString().toLowerCase())
1310								{
1311									products[i].category = reference[a].category;
1312								}
1313							}
1314						}
1315					}
1316
1317					return products;
1318				},
1319				click: function(data)
1320				{
1321					this.data = data;
1322
1323					return this;
1324				},
1325				add: function(data)
1326				{
1327					this.data = data;
1328
1329					return this;
1330				},
1331				remove: function(data)
1332				{
1333					this.data = data;
1334
1335					if (AEC.localStorage)
1336					{
1337						this.data.ecommerce.remove.products = this.augment(this.data.ecommerce.remove.products);
1338					}
1339
1340					return this;
1341				},
1342				visitor: function(data)
1343				{
1344					this.data = (function(data, privateData)
1345					{
1346						if (privateData)
1347						{
1348							if (privateData.hasOwnProperty('visitor'))
1349							{
1350								data.visitorId 		   = privateData.visitor.visitorId;
1351								data.visitorLoginState = privateData.visitor.visitorLoginState;
1352							}
1353						}
1354
1355						return data;
1356
1357					})(data, AEC.Cookie.getPrivateData());
1358
1359					return this;
1360				},
1361				detail: function(data)
1362				{
1363					this.data = data;
1364
1365					return this;
1366				},
1367				purchase: function(data)
1368				{
1369					this.data = data;
1370
1371					if (AEC.localStorage)
1372					{
1373						this.data.ecommerce.purchase.products = this.augment(this.data.ecommerce.purchase.products);
1374					}
1375
1376					return this;
1377				},
1378				impressions: function(data)
1379				{
1380					this.data = data;
1381
1382					return this;
1383				},
1384				checkout: function(data)
1385				{
1386					this.data = data;
1387
1388					if (AEC.localStorage)
1389					{
1390						this.data.ecommerce.checkout.products = this.augment(this.data.ecommerce.checkout.products);
1391					}
1392
1393					return this;
1394				},
1395				checkoutOption: function(data)
1396				{
1397					this.data = data;
1398
1399					return this;
1400				},
1401				promotion: function(data)
1402				{
1403					this.data = data;
1404
1405					return this;
1406				},
1407				promotionClick: function(data)
1408				{
1409					this.data = data;
1410
1411					return this;
1412				},
1413				remarketing: function(data)
1414				{
1415					this.data = data;
1416
1417					return this;
1418				},
1419				getPrivateData: function()
1420				{
1421					if (!this.privateData)
1422					{
1423						var cookie = this.get('privateData');
1424
1425						if (cookie)
1426						{
1427							this.privateData = this.parse(cookie);
1428						}
1429					}
1430
1431					return this.privateData;
1432				},
1433				get: function(name)
1434				{
1435					var start = document.cookie.indexOf(name + "="), len = start + name.length + 1;
1436
1437					if ((!start) && (name != document.cookie.substring(0, name.length)))
1438					{
1439						return null;
1440					}
1441
1442					if (start == -1)
1443					{
1444						return null;
1445					}
1446
1447					var end = document.cookie.indexOf(String.fromCharCode(59), len);
1448
1449					if (end == -1)
1450					{
1451						end = document.cookie.length;
1452					}
1453
1454					return decodeURIComponent(document.cookie.substring(len, end));
1455				},
1456				unset: function(name)
1457				{
1458					document.cookie = name + "=" + "; path=/; expires=" + (new Date(0)).toUTCString();
1459
1460					return this;
1461				},
1462				parse: function(json)
1463				{
1464					var json = decodeURIComponent(json.replace(/\+/g, ' '));
1465
1466					return JSON.parse(json);
1467				}
1468			}
1469		})(),
1470		CookieConsent: (function()
1471		{
1472			return {
1473				chain: {},
1474				queue: function(callback, event)
1475				{
1476					event = typeof event !== 'undefined' ? event : AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT;
1477
1478					if (!this.chain.hasOwnProperty(event))
1479					{
1480						this.chain[event] = [];
1481					}
1482
1483					this.chain[event].push(callback);
1484
1485					return this;
1486				},
1487				dispatch: function(consent)
1488				{
1489					/**
1490					 * Essential cookies
1491					 */
1492					AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED = true;
1493
1494					/**
1495					 * Push consent to dataLayer
1496					 */
1497					dataLayer.push(consent);
1498
1499					return this.process(consent.event);
1500				},
1501				process: function(event)
1502				{
1503					event = typeof event !== 'undefined' ? event : AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT;
1504
1505					if (this.chain.hasOwnProperty(event) && 1 == AEC.Cookie.get(event))
1506					{
1507						for (a = 0, b = this.chain[event].length; a < b; a++)
1508						{
1509							this.chain[event][a].apply(this,[]);
1510						}
1511
1512						this.chain[event] = [];
1513					}
1514
1515					return this;
1516				},
1517				acceptConsent: function(event)
1518				{
1519					return this.dispatch({ event:event });
1520				},
1521				declineConsent: function(event)
1522				{
1523					return this.dispatch({ event:event });
1524				},
1525				getConsentDialog: function(dataLayer, endpoints)
1526				{
1527					require(['jquery'],function($)
1528					{
1529						if (1 == AEC.Cookie.get(AEC.Const.COOKIE_DIRECTIVE_CONSENT_DECLINE_EVENT))
1530						{
1531							return true;
1532						}
1533
1534						if (1 != AEC.Cookie.get(AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT))
1535						{
1536							$.get(endpoints.cookieContent,function(response)
1537							{
1538								var directive = $('body').append(response.cookieContent).end().find('.ec-gtm-cookie-directive');
1539
1540								directive.find('a.ec-gtm-cookie-directive-note-toggle').off('click.ec').on('click.ec', function()
1541								{
1542									$(this).next().slideToggle();
1543								});
1544
1545								/**
1546								 * Accept cookies
1547								 */
1548								directive.find('a.accept').off('click.ec').on('click.ec', function()
1549								{
1550									var message = $(this).attr('data-confirm');
1551
1552									$(this).text(message);
1553
1554									var grant = $('.ec-gtm-cookie-directive [name="cookie[]"]:checked').map(function(){return this.value}).get();
1555
1556									$.post(endpoints.cookie,{ cookie: grant }, function(response)
1557									{
1558										$.each(response, function(event, value)
1559										{
1560											AEC.CookieConsent.acceptConsent(event);
1561										});
1562
1563										directive.remove();
1564
1565									}, endpoints.type);
1566								});
1567
1568								/**
1569								 * Decline cookies
1570								 */
1571								directive.find('a.decline').off('click.ec').on('click.ec', function()
1572								{
1573									$.post(endpoints.cookie,{ decline: true }, function(response)
1574									{
1575										$.each(response, function(event, value)
1576										{
1577											AEC.CookieConsent.declineConsent(event);
1578										});
1579
1580										directive.remove();
1581
1582									}, endpoints.type);
1583								});
1584
1585							}, endpoints.type);
1586						}
1587						else
1588						{
1589							if (AEC.Const.COOKIE_DIRECTIVE_SEGMENT_MODE)
1590							{
1591								(function(segments)
1592								{
1593									for (i = 0, l = segments.length; i < l;i++)
1594									{
1595										if (1 == AEC.Cookie.get(segments[i]))
1596										{
1597											AEC.CookieConsent.acceptConsent(segments[i]);
1598										}
1599									}
1600
1601								})(AEC.Const.COOKIE_DIRECTIVE_SEGMENT_MODE_EVENTS);
1602							}
1603							else
1604							{
1605								AEC.CookieConsent.acceptConsent(AEC.Const.COOKIE_DIRECTIVE_CONSENT_GRANTED_EVENT);
1606							}
1607						}
1608					});
1609				}
1610			}
1611		})(),
1612		/**
1613		 * localStorage cache
1614		 */
1615		Storage: (function(api)
1616		{
1617			return {
1618				set: function(property, value)
1619				{
1620					if ('undefined' !== typeof(Storage))
1621					{
1622						localStorage.setItem(property, JSON.stringify(value));
1623					}
1624
1625					return this;
1626
1627				},
1628				get: function(property)
1629				{
1630					if ('undefined' !== typeof(Storage))
1631					{
1632						return JSON.parse(localStorage.getItem(property));
1633					}
1634
1635					return null;
1636				},
1637				reference: function()
1638				{
1639					return (function(storage)
1640					{
1641						return {
1642							set: function(reference)
1643							{
1644								var current = storage.get('category.add') || [];
1645
1646								var exists = (function(current, reference)
1647								{
1648									for (i = 0, l = current.length; i < l; i++)
1649									{
1650										if (current[i].id.toString().toLowerCase() === reference.id.toString().toLowerCase())
1651										{
1652											/**
1653											 * Update category
1654											 */
1655											current[i].category = reference.category;
1656
1657											return true;
1658										}
1659									}
1660
1661									return false;
1662
1663								})(current, reference);
1664
1665								if (!exists)
1666								{
1667									current.push(reference);
1668								}
1669
1670								storage.set('category.add', current);
1671
1672								return this;
1673							},
1674							get: function()
1675							{
1676								return storage.get('category.add');
1677							}
1678						}
1679					})(this);
1680				}
1681			}
1682		})(),
1683		/**
1684		 * Check if GTM snippet is available on page.
1685		 *
1686		 * @param void
1687		 * @return boolean
1688		 */
1689		gtm: function()
1690		{
1691			if ("undefined" === typeof google_tag_manager)
1692			{
1693				/**
1694				 * Log error to console
1695				 */
1696				log('Unable to detect Google Tag Manager. Please verify if GTM install snippet is available.');
1697
1698				return false;
1699			}
1700
1701			return true;
1702		},
1703		parseJSON: function(content)
1704		{
1705			if ('object' === typeof content)
1706			{
1707				return content;
1708			}
1709
1710			if ('string' === typeof content)
1711			{
1712				try
1713				{
1714					return JSON.parse(content);
1715				}
1716				catch (e){}
1717			}
1718
1719			return {};
1720		},
1721		getPayloadSize: function(object)
1722		{
1723			var objects = [object];
1724			var size = 0;
1725
1726			for (var index = 0; index < objects.length; index++)
1727			{
1728				switch (typeof objects[index])
1729				{
1730					case 'boolean':
1731						size += 4;
1732						break;
1733					case 'number':
1734						size += 8;
1735						break;
1736					case 'string':
1737						size += 2 * objects[index].length;
1738						break;
1739					case 'object':
1740						if (Object.prototype.toString.call(objects[index]) != '[object Array]')
1741						{
1742							for (var key in objects[index]) size += 2 * key.length;
1743						}
1744						for (var key in objects[index])
1745						{
1746							var processed = false;
1747
1748							for (var search = 0; search < objects.length; search++)
1749							{
1750								if (objects[search] === objects[index][key]) {
1751									processed = true;
1752									break;
1753								}
1754							}
1755							if (!processed) objects.push(objects[index][key]);
1756						}
1757				}
1758			}
1759			return size;
1760		},
1761		getPayloadChunks: function(arr, len)
1762		{
1763			var chunks = [],i = 0, n = arr.length;
1764
1765			while (i < n)
1766			{
1767				chunks.push(arr.slice(i, i += len));
1768			}
1769
1770			return chunks;
1771		}
1772	}
1773})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.