luv-assets 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/js/js.js ADDED
@@ -0,0 +1,552 @@
1
+ function isStrictMode() {
2
+ return (function () { return !this; })();
3
+ }
4
+ // console.log(isStrictMode()); // if true, strict mode is on
5
+ function isSurportedLoading() {
6
+ return 'loading' in HTMLImageElement.prototype;
7
+ }
8
+ // console.log(isSurportedLoading()); // if true, loading attribute is supported
9
+
10
+ function webLoadScript(url, callback) {
11
+ var script = document.createElement("script");
12
+ script.type = "text/javascript";
13
+ if (typeof (callback) != "undefined") {
14
+ if (script.readyState) {
15
+ script.onreadystatechange = function () {
16
+ if (script.readyState == "loaded" || script.readyState == "complete") {
17
+ script.onreadystatechange = null;
18
+ callback();
19
+ }
20
+ };
21
+ } else {
22
+ script.onload = function () {
23
+ callback();
24
+ };
25
+ }
26
+ }
27
+ script.src = url;
28
+ document.body.appendChild(script);
29
+ }
30
+ function check_email(email) {
31
+
32
+ if (!email || email == "") {
33
+ return false;
34
+ }
35
+
36
+ const myreg = /^([a-zA-Z0-9]+[_|\_|\.|-|\-]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.|-|\-]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
37
+ if (!myreg.test(email)) {
38
+ return false;
39
+ }
40
+
41
+ return true;
42
+ }
43
+ function check_pass(str) {
44
+ const re = /^\w{6,30}$/;
45
+ if (re.test(str)) {
46
+ return true;
47
+ } else {
48
+ return false;
49
+ }
50
+ }
51
+
52
+ //set cookie
53
+ function setCookie(name, value) {
54
+ const Days = 30;
55
+ const exp = new Date();
56
+ exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000);
57
+ document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString();
58
+ }
59
+
60
+ //get cookies
61
+ function getCookie(name) {
62
+ const arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
63
+ if (arr) {
64
+ return unescape(arr[2]);
65
+ } else {
66
+ return null;
67
+ }
68
+ }
69
+
70
+ $(document).ready(function () {
71
+
72
+ const currentBaseUrl = $("#currentBaseUrl").val();
73
+ if (currentBaseUrl) {
74
+ const loginInfoUrl = currentBaseUrl + "/member/ajax";
75
+ const product_id = $("#cart_product_spu").val();
76
+ product_id = product_id ? product_id : null;
77
+ if (product_id) {
78
+ const ajax_params = {
79
+ 'product_id': product_id
80
+ };
81
+ } else {
82
+ const ajax_params = {};
83
+ }
84
+ $.ajax({
85
+ async: true,
86
+ timeout: 6000,
87
+ dataType: 'json',
88
+ type: 'get',
89
+ data: ajax_params,
90
+ url: loginInfoUrl,
91
+ success: function (data, textStatus) {
92
+
93
+ if (data.loginStatus) {
94
+ $(".header_welcome").show();
95
+ $(".header_account").hide();
96
+ }
97
+
98
+ if (data.favorite) {
99
+ $('.product-favorite').addClass("icon-like");
100
+ $('.product-favorite').addClass("wish-pink");
101
+
102
+ }
103
+
104
+ if (data.favorite_product_count) {
105
+ // $(".header-right-user-wishlist-num-js").html(data.favorite_product_count);
106
+ }
107
+
108
+ if (data.affiliate) {
109
+ $(".affiliate_link-js").show();
110
+ }
111
+
112
+ if (data.cart_qty) {
113
+ $(".bag-count").text(data.cart_qty);
114
+ $(".num-tag").text(data.cart_qty);
115
+ }
116
+ },
117
+ error: function (XMLHttpRequest, textStatus, errorThrown) { }
118
+ });
119
+ }
120
+ $(".app-header-left .showMenu").click(function () {
121
+ $(".js-side-nav.side-nav").addClass("side-nav--visible");
122
+ $(".js-side-nav-container").css({ left: "-8rem" });
123
+ $(".js-side-nav-container").animate({ left: "0" }, 400);
124
+ });
125
+
126
+ $(".js-side-nav.side-nav").click(function () {
127
+ $(".js-side-nav.side-nav").removeClass("side-nav--visible");
128
+
129
+ });
130
+ $(".js-side-nav-container").click(function (e) {
131
+ e.stopPropagation();
132
+ });
133
+
134
+ $("body").on("click", ".span_click", function () {
135
+ url = $(this).attr('rel');
136
+ window.location.href = url;
137
+ });
138
+
139
+ // $(".span_click").click(function () {
140
+ // url = $(this).attr('rel');
141
+ // window.location.href = url;
142
+ // });
143
+ //ajax subscribe
144
+ $("#subscribe_btn").click(function () {
145
+ //disable button
146
+ $(this).prop('disabled', true);
147
+
148
+ email = $("#subscribe_email").val();
149
+ if (!check_email(email)) {
150
+ alert('Enter your email address');
151
+ //enable button
152
+ $('#subscribe_btn').prop('disabled', false);
153
+ return false;
154
+ }
155
+ $.ajax({
156
+ dataType: 'json',
157
+ type: 'post',
158
+ data: { 'email': email },
159
+ url: currentBaseUrl + "/member/account/subscribe",
160
+ success: function (data, textStatus) {
161
+ //enable button
162
+ $('#subscribe_btn').prop('disabled', false);
163
+ if (data.success) {
164
+ alert(data.message);
165
+ $("#subscribe_email").val("");
166
+ } else {
167
+ alert(data.message);
168
+ }
169
+ },
170
+ error: function (error) {
171
+
172
+ alert('Oops! Something went wrong. Please try again later.');
173
+ //enable button
174
+ $('#subscribe_btn').prop('disabled', false);
175
+ }
176
+ })
177
+ });
178
+ });
179
+
180
+
181
+ ///////////////////////////////
182
+
183
+ function isValidSearchKeyword(keyword, maxLength = 100) {
184
+ //
185
+ keyword = keyword.trim();
186
+ if (keyword === '') {
187
+ return false;
188
+ }
189
+ //
190
+ if (keyword.length > maxLength) {
191
+ return false;
192
+ }
193
+ // Unicode
194
+ // const safePattern = /^[\p{L}\p{N}\s.,;:'"!?-]+$/u;
195
+ const safePattern = /^[\p{L}\p{N}\s.;:'"!?-]+$/u;
196
+ if (!safePattern.test(keyword)) {
197
+ return false;
198
+ }
199
+ //
200
+ const escapedKeyword = keyword.replace(/&/g, "&")
201
+ .replace(/</g, "&lt;")
202
+ .replace(/>/g, "&gt;")
203
+ .replace(/"/g, "&quot;")
204
+ .replace(/'/g, "&#039;");
205
+ //
206
+ return true;
207
+ }
208
+
209
+ const historyKey = 'search_history';
210
+ function pullSearchHistory(Url) {
211
+ // let localHistory = getSearchHistoryFromLocalStorage();
212
+ let localHistory = getCompatibleSearchHistoryFromLocalStorage();
213
+ if (!isSyncNeeded(localHistory)) {
214
+ return;
215
+ }
216
+ $.ajax({
217
+ async: true,
218
+ timeout: 6000,
219
+ dataType: 'json',
220
+ type: 'get',
221
+ url: Url,
222
+ success: function (data, textStatus) {
223
+ if (data.data.length > 0) {
224
+ // console.log(data.data);
225
+ mergeLocalSearchHistory(data.data);
226
+ }
227
+ },
228
+ error: function (XMLHttpRequest, textStatus, errorThrown) {
229
+
230
+ }
231
+ });
232
+ }
233
+ /**
234
+ * save search history to server
235
+ * @param {string} keyword
236
+ * @param {string} Url
237
+ */
238
+ function saveOneSearchHistory(keyword, Url) {
239
+ $.ajax({
240
+ async: true,
241
+ timeout: 6000,
242
+ dataType: 'json',
243
+ type: 'post',
244
+ url: Url,
245
+ data: {
246
+ keyword: keyword
247
+ },
248
+ success: function (data, textStatus) {
249
+
250
+ },
251
+ error: function (XMLHttpRequest, textStatus, errorThrown) {
252
+
253
+ }
254
+ });
255
+ }
256
+ /**
257
+ * save search history to local storage
258
+ * @param {string} keyword
259
+ */
260
+ function saveSearchToLocalStorage(keyword) {
261
+ // let searchHistory = JSON.parse(localStorage.getItem(historyKey)) || [];
262
+ let searchHistory = getCompatibleSearchHistoryFromLocalStorage();
263
+
264
+ // data
265
+ // data keyword exits
266
+ const index = searchHistory.data.indexOf(keyword);
267
+ if (index > -1) {
268
+ searchHistory.data.splice(index, 1);
269
+ }
270
+ searchHistory.data.unshift(keyword);
271
+ // data keywords max length
272
+ if (searchHistory.data.length > maxSearchHistoryLength) {
273
+ searchHistory.data = searchHistory.data.slice(0, maxSearchHistoryLength); // move
274
+ }
275
+
276
+ //update_time
277
+ searchHistory.update_time = new Date().toISOString();
278
+
279
+ // save local
280
+ localStorage.setItem(historyKey, JSON.stringify(searchHistory));
281
+ }
282
+
283
+ function removeSearchFromLocalStorage(keyword) {
284
+ // get local search history
285
+ let searchHistory = JSON.parse(localStorage.getItem(historyKey));
286
+ // search history exists
287
+ if (searchHistory && Array.isArray(searchHistory.data)) {
288
+ if (keyword) {
289
+ // if keyword exists in search history, remove it
290
+ searchHistory.data = searchHistory.data.filter(item => item !== keyword);
291
+ } else {
292
+ // // set search history to empty
293
+ // searchHistory.data = [];
294
+ // remove search history from local storage
295
+ localStorage.removeItem(historyKey);
296
+ return;
297
+ }
298
+ //update_time
299
+ searchHistory.update_time = new Date().toISOString();
300
+ // update local storage
301
+ localStorage.setItem(historyKey, JSON.stringify(searchHistory));
302
+ return;
303
+ } else {
304
+ // remove search history from local storage
305
+ localStorage.removeItem(historyKey);
306
+ return;
307
+ }
308
+
309
+ }
310
+
311
+ function getSearchHistoryFromLocalStorage() {
312
+ let searchHistory = JSON.parse(localStorage.getItem(historyKey)) || {
313
+ update_time: null,
314
+ last_sync_time: null,
315
+ data: []
316
+ };
317
+ return searchHistory;
318
+ }
319
+ function getCompatibleSearchHistoryFromLocalStorage() {
320
+ const rawHistory = localStorage.getItem(historyKey);
321
+ if (!rawHistory) {
322
+ // if no history, return default new structure
323
+ return {
324
+ update_time: null,
325
+ last_sync_time: null,
326
+ data: []
327
+ };
328
+ }
329
+
330
+ let history;
331
+ try {
332
+ history = JSON.parse(rawHistory);
333
+ } catch (e) {
334
+ console.error('Failed to parse history:', e);
335
+ return {
336
+ update_time: null,
337
+ last_sync_time: null,
338
+ data: []
339
+ };
340
+ }
341
+ // check if it's old array structure
342
+ if (Array.isArray(history)) {
343
+ // convert to new object structure
344
+ history = {
345
+ update_time: null, // assume old data has no update time
346
+ last_sync_time: null, // assume old data has no sync time
347
+ data: history
348
+ };
349
+ // update to localStorage, ensure subsequent use of new structure
350
+ localStorage.setItem(historyKey, JSON.stringify(history));
351
+ }
352
+
353
+ return history;
354
+ }
355
+ function isSyncNeeded(history) {
356
+ if (!history || !history.last_sync_time) return true;
357
+
358
+ const lastSyncTime = new Date(history.last_sync_time);
359
+ const currentTime = new Date();
360
+ const diffInMinutes = (currentTime - lastSyncTime) / (1000 * 60);
361
+
362
+ return diffInMinutes > 15;
363
+ }
364
+ function mergeLocalSearchHistory(serverHistory) {
365
+ // let localHistory = getSearchHistoryFromLocalStorage();
366
+ let localHistory = getCompatibleSearchHistoryFromLocalStorage();
367
+ //last_sync_time
368
+ localHistory.last_sync_time = new Date().toISOString();
369
+
370
+ // merge
371
+ let mergedData = Array.from(new Set([...localHistory.data, ...serverHistory]));
372
+ localHistory.data = mergedData;
373
+ // save
374
+ localStorage.setItem(historyKey, JSON.stringify(localHistory));
375
+ }
376
+
377
+
378
+ function getUrlParams() {
379
+ // get current page URL
380
+ const url = new URL(window.location.href);
381
+ // create URLSearchParams
382
+ const searchParams = new URLSearchParams(url.search);
383
+
384
+ // loop all params
385
+ // for (const [key, value] of searchParams.entries()) {
386
+ // // console.log(`Key: ${key}, Value: ${value}`);
387
+ // }
388
+
389
+ // return searchParams object;
390
+ return searchParams;
391
+ }
392
+
393
+
394
+ ///////////////////////
395
+
396
+ /////////////////////// start product
397
+ const product_history_key = 'viewed_products';
398
+ function saveProductToLocalStorage(product_id, maxHistoryLength = 30) {
399
+ let productHistory = JSON.parse(localStorage.getItem(product_history_key)) || [];
400
+ // product_id exits
401
+ const index = productHistory.indexOf(product_id);
402
+ if (index > -1) {
403
+ productHistory.splice(index, 1);
404
+ }
405
+ productHistory.unshift(product_id);
406
+ // max length
407
+ if (productHistory.length > maxHistoryLength) {
408
+ productHistory = productHistory.slice(0, maxHistoryLength); // move
409
+ }
410
+ // save local
411
+ localStorage.setItem(product_history_key, JSON.stringify(productHistory));
412
+ }
413
+ function fetchAndDisplayViewedProducts(history_url) {
414
+ let productHistory = JSON.parse(localStorage.getItem(product_history_key) || '[]');
415
+ if (productHistory.length === 0) {
416
+ return;
417
+ }
418
+ const viewedProductsElement = $('#viewed-products');
419
+ viewedProductsElement.empty();
420
+ // get products
421
+ $.ajax({
422
+ url: history_url,
423
+ method: 'POST',
424
+ data: { productIds: productHistory },
425
+ success: function (response) {
426
+ viewedProductsElement.html(response.html);
427
+ lazyLoadInstance.update(); // lazy load
428
+ },
429
+ error: function () {
430
+ viewedProductsElement.html('<p>Failed to load viewed products.</p>');
431
+ }
432
+ });
433
+
434
+ }
435
+ /////////////////////// end product
436
+
437
+ /**
438
+ * Checks if the provided URL is valid
439
+ *
440
+ * @param string url
441
+ *
442
+ * @return bool
443
+ *
444
+ */
445
+ function is_valid_url(url) {
446
+
447
+ var regex = new RegExp(/^(https?|s):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i);
448
+
449
+ return regex.test(url);
450
+
451
+ }
452
+ /**
453
+ * Checks if the two provided URLs are from the same domain
454
+ *
455
+ * @param string base_url
456
+ * @param string custom_url
457
+ *
458
+ * @return bool
459
+ *
460
+ */
461
+ function is_same_domain(base_url, custom_url) {
462
+
463
+ base_url = base_url.replace('http://', '').replace('https://', '').replace('www.', '').replace('m.', '').split(/[/?#]/)[0];
464
+ custom_url = custom_url.replace('http://', '').replace('https://', '').replace('www.', '').replace('m.', '').split(/[/?#]/)[0];
465
+
466
+ return (base_url == custom_url || base_url.indexOf(custom_url) != -1 || custom_url.indexOf(base_url) != -1);
467
+
468
+ }
469
+ /**
470
+ * Adds the the friendly affiliate parameters to the url
471
+ *
472
+ */
473
+ function process_friendly_url(param, value, url) {
474
+
475
+ // Save the hash, if it's present.
476
+ var hash = url.split('#')[1];
477
+
478
+ url = url.split('#')[0];
479
+
480
+ // Check if this is already an affiliate friendly url
481
+ var re = new RegExp("([\/]" + param + "[\/][^?]*)"),
482
+ match = re.exec(url);
483
+
484
+ // Check if we have any parameters in the url
485
+ var re2 = new RegExp("([?].*)"),
486
+ match2 = re2.exec(url);
487
+
488
+ // Remove the affiliate friendly endpoint
489
+ if (match && match[0])
490
+ url = url.replace(match[0], '');
491
+
492
+ // Remove the url parameters
493
+ if (match2 && match2[0])
494
+ url = url.replace(match2[0], '');
495
+
496
+ // Check if we have the affiliate parameter without affiliate id in the url
497
+ var re3 = new RegExp("([\/]" + param + "$)"),
498
+ match3 = re3.exec(url);
499
+
500
+ // Remove the affiliate parameter
501
+ if (match3 && match3[0])
502
+ url = url.replace(match3[0], '');
503
+
504
+ // Remove the trailing slash
505
+ url = url.replace(/\/+$/, '');
506
+
507
+ // Add the affiliate friendly endpoint
508
+ url = url + '/' + param + '/' + value + '/';
509
+
510
+ // Add back the parameters to the url
511
+ if (match2 && match2[0])
512
+ url = url + match2[0];
513
+
514
+ // Add back the hash if it exists.
515
+ if (hash)
516
+ url += '#' + hash;
517
+
518
+ return url;
519
+
520
+ }
521
+ /**
522
+ * Adds an argument name, value pair to a given URL string
523
+ *
524
+ */
525
+ function add_query_arg(param, value, url) {
526
+
527
+ var re = new RegExp("[\\?&]" + param + "=([^&#]*)"),
528
+ match = re.exec(url),
529
+ delimiter, newString;
530
+ var hash = url.split('#')[1];
531
+
532
+ url = url.split('#')[0];
533
+
534
+ if (match === null) {
535
+
536
+ var hasQuestionMark = /\?/.test(url);
537
+ delimiter = hasQuestionMark ? "&" : "?";
538
+ newString = url + delimiter + param + "=" + value;
539
+
540
+ } else {
541
+
542
+ delimiter = match[0].charAt(0);
543
+ newString = url.replace(re, delimiter + param + "=" + value);
544
+
545
+ }
546
+
547
+ if (hash) {
548
+ newString += '#' + hash;
549
+ }
550
+
551
+ return newString;
552
+ }