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.