PageSourceSearch

https://haroct.com.my/themes/store/default/assets/js/custom.js

js haroct.com.my collected 2026-09-24 14:04:15 UTC 18,400 bytes, 521 lines download raw bytes

1var App = {
2    datePicker: function () {
3        if (jQuery('.datepicker').length) {
4            jQuery('.datepicker').each(function () {
5                var $this = jQuery(this);
6                var option = {
7                    dateFormat: 'dd-mm-yy'
8                };
9                if ($this.data('changemonth')) {
10                    option.changeMonth = true;
11                }
12                if ($this.data('changeyear')) {
13                    option.changeYear = true;
14                }
15                if ($this.data('yearrange')) {
16                    option.yearRange = $this.data('yearrange');
17                }
18                $this.datepicker(option);
19            });
20        }
21    },
22    initCss: function () {
23        if (jQuery('.selectpicker').length) {
24            jQuery('.selectpicker').each(function () {
25                var $this = jQuery(this);
26                var option = {
27                    'noneSelectedText': 'Vui lòng chọn'
28                };
29                $this.selectpicker(option);
30            });
31        }
32    },
33    initEvent: function () {
34        if (jQuery('[data-trigger]').length) {
35            jQuery('[data-trigger]').each(function () {
36                var $trigger = jQuery(this).data('trigger');
37                jQuery(this).trigger($trigger);
38
39            });
40            if (jQuery('.selectpicker').length) {
41                jQuery('.selectpicker').selectpicker('refresh');
42            }
43        }
44        if (jQuery('.alert-msg').length && jQuery('.alert-msg .alert').length) {
45            jQuery('.alert-msg').modal('show');
46        }
47        if (location.hash) {
48            var $hash = location.hash;
49            var $class = $hash.replace("#", ".");
50            if (jQuery($hash).length) {
51                jQuery('body,html').animate({scrollTop: jQuery($hash).offset().top}, 1000);
52            } else if (jQuery($class).length) {
53                jQuery('body,html').animate({scrollTop: jQuery($class).offset().top}, 1000);
54            }
55        }
56        if (jQuery('.scrollto').length) {
57            jQuery('.scrollto').each(function () {
58                var $this = jQuery(this);
59                $this.click(function () {
60                    var $target = jQuery(jQuery(this).data('target'));
61                    if ($target.length) {
62                        jQuery('body,html').animate({scrollTop: $target.offset().top}, 1000);
63                    }
64                })
65
66
67
68            });
69        }
70        if (jQuery('.custom-file-input').length) {
71           var $default = jQuery('.custom-file-label').text();
72            jQuery('.custom-file-input').change(function () {
73                var parent = jQuery(this).parent();
74                var files = jQuery(this)[0].files;
75                if (files.length) {
76                    for (var $i = 0; $i < files.length; $i++) {
77                        var filetype = files[$i].type;
78                        if (files[$i].size > 10 * 1024 * 1024) {
79                            jQuery(this).val('');
80                            parent.find('.custom-file-label').addClass('error');
81                            return false;
82                        }
83
84                    }
85                    parent.find('.custom-file-label').removeClass('error');
86                    if (files.length == 1) {
87                        parent.find('.custom-file-label').text(files[0].name);
88                    }
89                }
90            });
91        }
92        if (jQuery('.footer-page .nav-link').length) {
93            jQuery('.footer-page .nav-link').each(function () {
94                var $this = jQuery(this);
95                $this.click(function () {
96//                    location.href=$this.attr('href');
97                    var hashValue = $this.attr('href').split('#');
98                    if (hashValue.length == 2) {
99                        var $hash = '#'+hashValue[1];
100                        var $class = '.'+hashValue[1];
101                        if (jQuery($hash).length) {
102                            jQuery('body,html').animate({scrollTop: jQuery($hash).offset().top}, 1000);
103                        } else if (jQuery($class).length) {
104                            jQuery('body,html').animate({scrollTop: jQuery($class).offset().top}, 1000);
105                        }
106                    }
107
108//                    window.location.reload();
109                })
110            });
111        }
112        if (jQuery('.selectpicker').length) {
113            jQuery('.selectpicker').selectpicker('refresh');
114        }
115
116        if (jQuery('input[name="paymentMethod"]').length) {
117            jQuery('input[name="paymentMethod"]').change(function () {
118                if (jQuery('input[name="paymentMethod"]:checked').val() == 2) {
119                    jQuery('.bankaccountinfo').removeClass('d-none');
120                } else {
121                    jQuery('.bankaccountinfo').addClass('d-none');
122                    if (jQuery('input[name="bankaccount"]').length && !jQuery('input[name="bankaccount"]:checked').length) {
123                        jQuery(jQuery('input[name="bankaccount"]')[0]).prop({'checked': true});
124                    }
125                }
126            });
127            jQuery('input[name="paymentMethod"]').trigger('change');
128        }
129        if (jQuery('input[name="username"]').length) {
130            jQuery('input[name="username"]').keyup(function () {
131                var $this = jQuery(this);
132                $this.val($this.val().replace(/[^a-zA-Z0-9]/g, '').toLowerCase());
133            });
134        }
135
136    },
137    initSlide: function () {
138        if (jQuery('.swiper-container').length) {
139            jQuery('.swiper-container').each(function () {
140                var $this = jQuery(this);
141                var $option = {
142
143                    // Optional parameters
144                    loop: true,
145                    speed: 1200,
146                    parallax: true,
147                    // If we need pagination
148                    pagination: {
149                        el: $this.find('.swiper-pagination'),
150                        clickable: true
151                    },
152
153                    // Navigation arrows
154                    navigation: {
155                        nextEl: $this.find('.swiper-button-next'),
156                        prevEl: $this.find('.swiper-button-prev')
157                    },
158
159                    // And if we need scrollbar
160                    scrollbar: {
161                        el: $this.find('.swiper-scrollbar')
162                    }
163                };
164                if ($this.data('loop')) {
165                    $option.loop = $this.data('loop');
166                }
167                if ($this.data('space-between')) {
168                    $option.spaceBetween = $this.data('space-between');
169                }
170                if ($this.data('slides-per-view')) {
171                    $option.slidesPerView = $this.data('slides-per-view');
172                }
173                if ($this.data('next-el')) {
174                    $option.navigation.nextEl = $this.parent().find($this.data('next-el'));
175                }
176                if ($this.data('prev-el')) {
177                    $option.navigation.prevEl = $this.parent().find($this.data('prev-el'));
178                }
179                if ($this.data('breakpoints')) {
180
181                    $option.breakpoints = $this.data('breakpoints');
182                }
183                new Swiper($this, $option);
184            });
185        }
186
187    }
188};
189
190jQuery(document).ready(function (e) {
191    App.datePicker();
192    App.initCss();
193    App.initEvent();
194    App.initSlide();
195});
196
197/*
198function t(type, text, autohide) {
199	autohide = autohide ? false : true;
200	if(type == "e"){
201		icon = "fa fa-exclamation";
202		title = 'Error!';
203		className = 'error';
204	}else if(type == "w"){
205		icon = "fa fa-warning";
206		title = 'Warning!';
207		className = 'warning';
208	}else if(type == "s"){
209		icon = "fa fa-check";
210		title = 'Success!';
211		className = 'success';
212	}else if(type == "i"){
213		icon = "fa fa-question";
214		title = 'Information';
215		className = 'info';
216	}else{
217		icon = "fa fa-circle-o";
218		title = 'Information';
219		className = 'cool';
220	}
221	
222    $.notify({
223        title: title,
224        text: text,
225        image: "<i class='"+icon+"'></i>"
226    }, {
227        style: 'metro',
228        className: className,
229        globalPosition: 'top right',
230        showAnimation: 'slideDown',
231		hideAnimation: 'slideUp',
232		showDuration: 200,
233        hideDuration: 200,
234        autoHide: autohide,
235        clickToHide: true
236    });
237}
238*/
239
240let modalCount = 0;
241t = function(type, text, data = {}) {
242    let icon, title, className;
243    let autohide = data.autohide ?? false;
244    let url = data.url ?? false;
245
246    if (type === "e") {
247        icon = "fa fa-circle-xmark";
248        title = "Error!";
249        className = "text-danger";
250    } else if (type === "w") {
251        icon = "fa fa-exclamation-triangle";
252        title = "Warning!";
253        className = "text-warning";
254    } else if (type === "s") {
255        icon = "fa fa-check-circle";
256        title = "Success!";
257        className = "text-success";
258    } else if (type === "i") {
259        icon = "fa fa-info-circle";
260        title = "Information";
261        className = "text-info";
262    } else {
263        icon = "fa fa-circle-o";
264        title = "Information";
265        className = "text-secondary";
266    }
267
268    modalCount++;
269    let modalId = `dynamicModal${modalCount}`;
270
271    let modalHTML = `
272        <div class="modal fade" id="${modalId}" tabindex="-1" aria-labelledby="${modalId}Label" aria-hidden="true">
273            <div class="modal-dialog modal-dialog-centered">
274                <div class="modal-content">
275                    ${autohide ? `
276                    <div class="progress" style="height: 4px;">
277                        <div class="progress-bar bg-secondary" id="progressBar${modalId}" role="progressbar" style="width: 100%;"></div>
278                    </div>` : ''}
279                    <div class="modal-header border-0 pb-0">
280                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
281                    </div>
282                    <div class="modal-body text-center">
283                        <div class="mb-3">
284                            <i class="${icon} ${className}" style="font-size:60px;"></i>
285                        </div>
286                        <div>
287                            <div>${text}</div>
288                        </div>
289                    </div>
290                    <div class="modal-footer border-0">
291                        <button type="button" class="btn btn-haroct btn-block" data-bs-dismiss="modal">Okay</button>
292                    </div>
293                </div>
294            </div>
295        </div>`;
296
297    $('body').append(modalHTML);
298
299    let myModal = new bootstrap.Modal(document.getElementById(modalId));
300    myModal.show();
301
302    if (autohide) {
303        let duration = 3000;
304        let progressBar = $(`#progressBar${modalId}`);
305
306        progressBar.animate({ width: '0%' }, duration, function() {
307            myModal.hide();
308            $(`#${modalId}`).on('hidden.bs.modal', function () {
309                $(this).remove();
310            });
311
312            if(url){
313                location.href = url;
314            }
315        });
316    }
317
318    return modalId;
319}
320
321ajax_error = function(error){
322	if(error.status == 0){
323		// t('e', 'You network currently are offline!!');
324	}else if(error.status == 404){
325		t('e', 'Requested URL not found.');
326	}else if(error.status == 500){
327		t('e', 'Internel Server Error.');
328	}else if(error == 'parsererror'){
329		t('e', 'Parsing JSON Request failed.');
330	}else if(error == 'timeout'){
331		t('e', 'Request Time out.');
332	}else {
333		t('e', 'Unknow Error : '+ error.responseText);
334	}
335}
336
337ajax_form = function(data, url){
338    if (typeof data === 'string') {
339        data += '&version=11111';
340    } else if (Array.isArray(data)) {
341        data.push({
342            name: 'version',
343            value: 11111
344        });
345    } else if (typeof data === 'object') {
346        data.version = 11111;
347    }
348
349    return $.ajax({
350        type: 'POST',
351        url: url,
352        dataType: 'json',
353        data: data,
354        headers: {
355            'Api-Secret': 'wbhZDkHjLxp9DzJPwgSwd2ch6rKM9sAS',
356            'Api-Key': 'gMpsvU5rB35DGvFS',
357            'Authorization': 'dev'
358        }
359    });      
360}
361
362let processLock = Promise.resolve();
363async function processRequest(requests) {
364    processLock = processLock.then(async () => {
365        for (const request of requests) {
366            try {
367                const response = await ajax_form(request.data, request.url);
368                request.handler(response);
369            } catch (error) {
370                ajax_error(error);
371            }
372        }
373    });
374
375    return processLock;
376}
377
378// Shared "enter your passcode to confirm" modal, used across Store dashboard pages
379// (Place Order, Withdraw, Subscribe, etc.) to verify an existing passcode against
380// u/verify-passcode before a sensitive action. The #pinModal markup itself is
381// generated by ensurePinModal() below — pages only call showPinModal(...).
382function initPinInputs() {
383    document.querySelectorAll('.pin').forEach(function(input, index, arr) {
384        if (input.dataset.pinBound) return; // idempotent — safe to call every time the modal opens
385        input.dataset.pinBound = '1';
386        input.setAttribute('inputmode', 'numeric');
387        input.setAttribute('pattern', '[0-9]*');
388
389        input.addEventListener('input', function() {
390            this.value = this.value.replace(/\D/g, '').slice(0, 1);
391            if (this.value.length === 1 && index < arr.length - 1) {
392                arr[index + 1].focus();
393            }
394            checkPinComplete();
395        });
396        input.addEventListener('keydown', function(e) {
397            if (e.key === 'Backspace' && !this.value && index > 0) {
398                arr[index - 1].focus();
399            }
400        });
401    });
402}
403
404function checkPinComplete() {
405    const pinInputs = document.querySelectorAll('.pin');
406    const confirmBtn = document.getElementById('confirmPin');
407    const isComplete = Array.from(pinInputs).every(input => input.value);
408    if (confirmBtn) confirmBtn.disabled = !isComplete;
409}
410
411function getPinValue() {
412    const pinInputs = document.querySelectorAll('.pin');
413    let pinValue = '';
414
415    pinInputs.forEach(input => {
416        pinValue += input.value || '0';
417    });
418
419    return pinValue.padStart(6, '0');
420}
421
422function clearPinInputs() {
423    const pinInputs = document.querySelectorAll('.pin');
424    pinInputs.forEach(input => input.value = '');
425
426    if (pinInputs.length > 0) {
427        pinInputs[0].focus();
428    }
429
430    const confirmBtn = document.getElementById('confirmPin');
431    if (confirmBtn) confirmBtn.disabled = true;
432}
433
434function ensurePinModal(title, confirmText) {
435    if (document.getElementById('pinModal')) return;
436
437    const modal = document.createElement('div');
438    modal.className = 'modal fade';
439    modal.id = 'pinModal';
440    modal.setAttribute('tabindex', '-1');
441    modal.setAttribute('aria-labelledby', 'pinModalLabel');
442    modal.setAttribute('aria-hidden', 'true');
443    modal.setAttribute('data-bs-backdrop', 'static');
444    modal.setAttribute('data-bs-keyboard', 'false');
445
446    modal.innerHTML = `
447        <div class="modal-dialog modal-dialog-centered">
448            <div class="modal-content">
449                <div class="modal-header border-0">
450                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
451                </div>
452                <div class="modal-body text-center pb-0">
453                    <h5 class="modal-title mb-2"></h5>
454                    <div class="pin-inputs mb-4">
455                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
456                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
457                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
458                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
459                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
460                        <input type="password" pattern="[0-9]*" inputmode="numeric" maxlength="1" autocomplete="off" class="pin" />
461                    </div>
462                </div>
463                <div class="modal-footer border-0 justify-content-center">
464                    <button type="button" class="btn btn-haroct w-100" id="confirmPin" disabled></button>
465                </div>
466            </div>
467        </div>
468    `;
469    modal.querySelector('.modal-title').textContent = title;
470    modal.querySelector('#confirmPin').textContent = confirmText;
471
472    document.body.appendChild(modal);
473}
474
475function showPinModal(apiUrl, accessToken, title, confirmText, onSuccess, onFail) {
476    ensurePinModal(title, confirmText);
477    initPinInputs();
478    clearPinInputs();
479    $('#pinModal').modal('show');
480
481    $('#confirmPin').off('click').on('click', function() {
482        processRequest([{
483            url: apiUrl + 'u/verify-passcode',
484            data: {
485                accessToken: accessToken,
486                passcode: getPinValue()
487            },
488            handler: function(response) {
489                $('#pinModal').modal('hide');
490                if (response.code == 200) {
491                    onSuccess(response);
492                } else {
493                    t('e', response.msg);
494                    clearPinInputs();
495                    if (typeof onFail === 'function') onFail(response);
496                }
497            }
498        }]);
499    });
500}
501
502priceFormat = function(val) {
503    return parseFloat(val).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
504}
505
506numberFormat = function(val) {
507    return parseFloat(val).toLocaleString('en-US', { minimumFractionDigits: 0, maximumFractionDigits: 2 });
508}
509
510$(function(){
511    if( $('.select2').length ){ 
512        $('.select2').each(function () {
513            const $this = $(this);
514            $this.select2({
515                theme: 'bootstrap-5',
516                placeholder: "- Select -",
517                minimumResultsForSearch: $this.data('search') ? 0 : Infinity
518            });
519        });
520    }
521});

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.