{"version":3,"file":"front.min.js","names":["$$","selector","element","document","querySelector","$","querySelectorAll","addClass","className","classList","add","removeClass","remove","hasClass","contains","isInstanceOf","elem","constructor","isArray","value","Array","toArray","NodeList","ForEach","array","callback","forEach","getAttr","attributeName","getAttribute","setAttr","attributeObjects","attrs","Object","entries","name","setAttribute","removeAttr","attributeNames","removeAttribute","createElement","tag","attributes","content","innerHTML","addEvent","elements","eventNames","capture","eventName","addEventListener","singleRemoveEvent","removeEventListener","dispatchChangeEvent","event","eventsubmit","Event","dispatchEvent","observeElements","options","observer","IntersectionObserver","entry","observe","countUpNumbers","isIntersecting","target","targetAttr","JSON","parse","targetNum","parseInt","startTime","prefix","suffix","window","requestAnimationFrame","stepAnim","timestamp","progress","Math","min","currentNum","floor","textContent","toLocaleString","undefined","maximumFractionDigits","unobserve","pageAddLoading","enableReSubmit","SetTimeout","pageRemoveLoading","spinner","removeElement","btnSubmit","fieldset","addItem","contenteditable","postData","async","url","data","fetchOption","method","mode","cache","credentials","redirect","referrerPolicy","body","response","fetch","ok","json","success","error","scrollIntoViewOffset","offset","scrollPosition","scrollY","pageYOffset","scrollTo","behavior","top","getBoundingClientRect","appendChild","parent","child","getCurrentTarget","currentTarget","message","elemDisplay","style","display","insertBeforeElement","newElement","referenceElement","insertBefore","closestParent","closest","dragSrcEl","enterCounter","WeakMap","touchStartX","touchStartY","currentHoveredElement","getClosestDraggable","handleTouchStart","e","touches","clientX","clientY","handleTouchMove","shouldPreventDefault","preventDefault","elementFromPoint","closestTarget","set","has","get","touch","handleTouchEnd","changedTouches","dropTarget","draggableItems","from","indexOf","parentNode","nextSibling","item","handleDragStart","this","dataTransfer","effectAllowed","setData","handleDragOver","dropEffect","handleDragEnter","handleDragLeave","handleDrop","stopPropagation","handleDragEnd","addDraggable","uploadFile","xhr","XMLHttpRequest","submitBtn","disabled","parentElement","previousElementSibling","progressText","label","nextElementSibling","createProgressText","upload","onprogress","handleUploadProgress","onload","readyState","DONE","status","location","href","handleFileError","onerror","onabort","formData","createFormData","open","send","uploadImage","uploadFolder","host","startsWith","isMultiple","hasAttribute","container","progressBar","createProgressBar","handleUploadLoad","handleUploadError","handleRequestError","class","lengthComputable","progressVal","loaded","total","round","handleMultipleUploadSuccess","handleSingleUploadSuccess","length","images","src","values","imgContainer","draggable","imgDiv","imgTag","imgBtnDelete","type","imgBtnMove","imgInput","inputName","append","FormData","files","imgSizes","importType","file","createModalElements","sectionElem","elemConfig","attr","createModalContent","htmlConfig","fragment","createDocumentFragment","section","createModal","config","modal","tabindex","modalSize","modalDialog","modalContent","modalInnerContent","fetchUrl","postBody","formdata","NONCE","HASH","htmlContent","bootstrap","Modal","show","delay","setTimeout","handleError","formElem","submitButton","alertmsg","noScroll","renameCloneVariant","variant","cloneIndex","group","for","replace","id","deleteBtnVariant","Index","btnDelete","itemID","onSubmit","token","rootMarginPX","rootMargin","hash","targetElement","triggerbeforeunload","history","back","referrer","tooltipTriggerList","tooltipList","map","tooltipTriggerEl","Tooltip","str","toLowerCase","dataFetch","then","embed_product_id","iframe","allow","dataModal","img_counter","innerText","to","input_value","max_amount","isNaN","total_value","tooltipInstance","getInstance","hide","subTotal","input","parseFloat","Intl","NumberFormat","format","inputElem","amount","formSections","formNav","newIndex","storedIndex","formBtn","pgNumber","editor","elemID","quill","Quill","modules","toolbar","formats","on","delta","oldDelta","source","root","form","alertmsgOrginalText","checkValidity","firstChild","fileInput","action","removeSubmit","resubmit","download","checkout","Razorpay","inputInvalid","select","submit","click","thisElem","email","limit","checked","elemValue","donateAmount","focus","donateBtn","donateBtnOther","orgText","imgToRemove","acceptType","getConfirm","imgPic","imgToDelete","cloneditem","cloneNode","tagName","selected","datachartjs","Chart","register","ChartDataLabels","ChartDeferred","configchartjs","callbackLabelFunc","plugins","tooltip","callbacks","eval","dataLabelsFormatter","datalabels","formatter","maxDataValue","max","datasets","buffer","scales","y","suggestedMax","ticks","deferred","yOffset","myChart","videoElem","resultElem","import","module","qrScanner","QrScanner","default","result","stop","highlightScanRegion","highlightCodeOutline","start","catch","deferredPrompt","prompt","userChoice","choiceResult","outcome","availLang","google","currentlang","documentElement","lang","translate","TranslateElement","includedLanguages","checkCount","checkInterval","setInterval","combo","clearInterval"],"sources":["front.js"],"sourcesContent":["\r\n\r\n\r\n\r\n/*\tSELECTORS ==========================================================================\t*/\r\n\r\n\tconst $$ = (selector, element = document) => {\r\n\r\n\t\treturn element.querySelector(selector);\r\n\r\n\t};\r\n\r\n\tconst $ = (selector, element = document) => {\r\n\r\n\t\treturn element.querySelectorAll(selector);\r\n\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tADD REMOVE CLASS ==========================================================================\t*/\r\n\r\n\tconst addClass = (element, className) => {\r\n\t\tif (element && className) {\r\n\t\t\telement.classList.add(className);\r\n\t\t}\r\n\t};\r\n\r\n\tconst removeClass = (element, className) => {\r\n\t\tif (element && className) {\r\n\t\t\telement.classList.remove(className);\r\n\t\t}\r\n\t};\r\n\r\n\tconst hasClass = (element, className) => {\r\n\t\tif (!element || !className) return false;\r\n\t\treturn element.classList.contains(className);\r\n\t};\r\n\r\n\r\n\r\n/*\tARRAY ========================================================================== */\r\n\r\n\tconst isInstanceOf = (elem, constructor) => elem instanceof constructor;\r\n\r\n\tconst isArray = (value) => Array.isArray(value);\r\n\tconst toArray = elem => isArray(elem) || isInstanceOf(elem, NodeList) ? elem : [elem];\r\n\t\r\n\tconst ForEach = (array, callback) => array && toArray(array).forEach(callback);\r\n\r\n\r\n\r\n\r\n/*\tATTRIBUTES ========================================================================== */\r\n\r\n\tconst getAttr = (elem, attributeName) => elem?.getAttribute(attributeName);\r\n\r\n\r\n\tconst setAttr = (elem, attributeObjects) => {\r\n\t\telem && ForEach(attributeObjects,\r\n\t\t\tattrs => ForEach(Object.entries(attrs), ([name, value]) => elem?.setAttribute(name, value)))\r\n\t};\r\n\r\n\r\n\tconst removeAttr = (elem, attributeNames) => {\r\n\t\telem && ForEach(attributeNames, name => elem?.removeAttribute(name));\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tCREATE ELEMENT ==========================================================================\t*/\r\n\r\n\tconst createElement = (tag, attributes, content) => {\r\n\r\n\t\tconst element = document.createElement(tag);\r\n\t\tsetAttr(element, attributes);\r\n\r\n\t\tif (content) {\r\n\t\t\telement.innerHTML = content;\r\n\t\t}\r\n\r\n\t\treturn element;\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tEVENT LISTENER ========================================================================== */\r\n\r\n\tconst addEvent = (elements, eventNames, callback, capture = false) => {\r\n\r\n\r\n\t\tForEach(eventNames, eventName => {\r\n\t\t\tForEach(elements, element => {\r\n\t\t\t\tif (element) {\r\n\t\t\t\t\telement.addEventListener(eventName, callback, capture);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t});\r\n\r\n\t};\r\n\r\n\r\n\tconst singleRemoveEvent = (elem, eventName, callback, capture = false) => {\r\n\t\t$(elem)?.removeEventListener(eventName, callback, capture);\r\n\t}\r\n\r\n\tconst dispatchChangeEvent = (elem, event) => {\r\n\t\tconst eventsubmit = new Event(event);\r\n\t\telem.dispatchEvent(eventsubmit);\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tINTERSECTION OBSERVER ========================================================================== */\r\n\r\n\tconst observeElements = (selector, callback, options) => {\r\n\r\n\t\tconst observer = new IntersectionObserver((entries, observer) => {\r\n\t\t//\tconsole.log( 'new entry!', entries[0].target );\r\n\t\t\tForEach(entries, entry => callback(entry, observer));\r\n\t\t}, options);\r\n\r\n\t\tForEach(selector, element => observer.observe(element));\r\n\t};\r\n\r\n\r\n\r\n\r\n\r\n/*\tCOUNTUP NUMBERS ========================================================================== */\r\n\r\n\tconst countUpNumbers = (entry, observer) => {\r\n\t\tif (!entry.isIntersecting) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconst element = entry.target;\r\n\t\tconst targetAttr = JSON.parse(getAttr(element, 'data-anim-num'));\r\n\t\tconst targetNum = parseInt(targetAttr['val']);\r\n\t\tconst duration = 2000;\r\n\r\n\t\tlet startNum = 0;\r\n\t\tlet startTime = null;\r\n\t\tconst prefix = targetAttr['prefix'] ?? '';\r\n\t\tconst suffix = targetAttr['suffix'] ?? '';\r\n\r\n\t\tfunction stepAnim(timestamp) {\r\n\t\t\tif (!startTime) startTime = timestamp;\r\n\t\t\tconst progress = Math.min((timestamp - startTime) / duration, 1);\r\n\t\t\tconst currentNum = Math.floor(progress * (targetNum - startNum) + startNum);\r\n\t\t\telement.textContent = prefix + currentNum.toLocaleString(undefined, { maximumFractionDigits: 2 }) + suffix;\r\n\t\t\tif (progress < 1) {\r\n\t\t\t\twindow.requestAnimationFrame(stepAnim);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\twindow.requestAnimationFrame(stepAnim);\r\n\r\n\t\tobserver.unobserve(element);\r\n\t}\r\n\r\n\r\n\r\n\r\n/*\tCLASS BODY LOADING ========================================================================== */\r\n\r\n\tconst pageAddLoading = (enableReSubmit = 0) => {\r\n\t\tconsole.log('pageAddLoading')\r\n\t\taddClass($$('body'), 'loading');\r\n\t\t\r\n\t\tSetTimeout(() => {\r\n\t\t\tpageRemoveLoading(enableReSubmit);\r\n\t\t}, 10000);\r\n\t\t\r\n\t};\r\n\r\n\tconst pageRemoveLoading = (enableReSubmit = 1) => {\r\n\r\n\t\tremoveClass($$('body'), 'loading');\r\n\r\n\t\tconst spinner = $$('.spinner-border');\r\n\r\n\t\tif (spinner) {\r\n\t\t\tremoveElement(spinner);\r\n\t\t}\r\n\r\n\t\tif (enableReSubmit) {\r\n\r\n\t\t\tForEach($('[type=\"submit\"]'), btnSubmit => {\r\n\t\t\t\tremoveClass(btnSubmit, 'disabled');\r\n\t\t\t});\r\n\r\n\r\n\t\t\tForEach($('fieldset.form'),\tfieldset => {\r\n\t\t\t\tremoveAttr(fieldset, 'disabled');\r\n\t\t\t});\r\n\r\n\t\t\tForEach($('.add-item'),\taddItem => {\r\n\t\t\t\tremoveAttr(addItem, 'disabled');\r\n\t\t\t});\r\n\r\n\t\t\tForEach($('[contenteditable]'),\tcontenteditable => {\r\n\t\t\t\tsetAttr(contenteditable, {contenteditable:true});\r\n\t\t\t});\r\n\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tFETCH ========================================================================== */\r\n\r\n\tconst postData = async (url = \"\", data = null) => {\r\n\r\n\t\tconst fetchOption = {\r\n\t\t\t\tmethod: \"POST\",\r\n\t\t\t\tmode: \"same-origin\",\r\n\t\t\t\tcache: \"no-cache\",\r\n\t\t\t\tcredentials: \"same-origin\",\r\n\t\t\t\tredirect: \"follow\",\r\n\t\t\t\treferrerPolicy: \"strict-origin-when-cross-origin\",\r\n\t\t\t\tbody: data,\r\n\t\t\t};\r\n\r\n\t\ttry {\r\n\r\n\t\t\tconst options = (data) ? fetchOption : {}\r\n\t\t\tconst response = await fetch(url, options);\r\n\r\n\t\t\tif (response.ok) {\r\n\t\t\t\treturn response.json();\r\n\t\t\t} else {\r\n\t\t\t\treturn { success: 0, error: 1 };\r\n\t\t\t}\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error('There was a problem with the fetch operation:', error.message);\r\n\t\t\treturn { success: 0, error: 1 };\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tUTILITIES ========================================================================== */\r\n\r\n\r\n\tconst scrollIntoViewOffset = (selector, offset = 110) => {\r\n\r\n\t\tconst scrollPosition = window.scrollY || window.pageYOffset;\r\n\r\n\t\tif (selector && scrollPosition !== undefined) {\r\n\t\t\twindow.scrollTo({\r\n\t\t\t\tbehavior: 'smooth',\r\n\t\t\t\ttop: selector.getBoundingClientRect().top - document.body.getBoundingClientRect().top - offset,\r\n\t\t\t})\r\n\r\n\t\t}\r\n\t}\r\n\r\n\tconst appendChild = (parent, child) => {\r\n\t\tparent.appendChild(child);\r\n\t};\r\n\r\n\tconst removeElement = (element) => {\r\n\t\telement?.remove();\r\n\t};\r\n\r\n\tconst getCurrentTarget = (event) => {\r\n\t\treturn event.currentTarget;\r\n\t};\r\n\r\n\tconst innerHTML = (element, message) => {\r\n\t\telement.innerHTML = message;\r\n\t};\r\n\r\n\tconst elemDisplay = (element, value) => {\r\n\t\telement.style.display = value;\r\n\t};\r\n\r\n\tconst insertBeforeElement = (parent, newElement, referenceElement) => {\r\n\t\tparent.insertBefore(newElement, referenceElement);\r\n\t};\r\n\r\n\r\n\tconst closestParent = (child, parent) => {\r\n\t\treturn child.closest(parent);\r\n\t};\r\n\r\n\r\n\r\n/*\tDRAGGABLE ========================================================================== */\r\n\r\n\r\n\tlet dragSrcEl = null;\r\n\tlet enterCounter = new WeakMap();\r\n\tlet touchStartX, touchStartY;\r\n\tlet currentHoveredElement = null; // Track the currently hovered element\r\n\r\n\r\n\tconst getClosestDraggable = function (element) {\r\n\t\tif (element) {\r\n\t\t\treturn element.closest('[draggable=\"true\"]');\r\n\t\t}\r\n\t\treturn null;\r\n\t};\r\n\r\n\r\n\tconst handleTouchStart = function (e) {\r\n\t\tdragSrcEl = getClosestDraggable(e.target);\r\n\t\tif (dragSrcEl) {\r\n\t\t\ttouchStartX = e.touches[0].clientX;\r\n\t\t\ttouchStartY = e.touches[0].clientY;\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleTouchMove = function (e) {\r\n\t\tif (!dragSrcEl) return;\r\n\r\n\r\n\t\tif (shouldPreventDefault(e)) {\r\n\t\t\te.preventDefault();\r\n\t\t}\r\n\r\n\t\tconst target = document.elementFromPoint(e.touches[0].clientX, e.touches[0].clientY);\r\n\t\tconst closestTarget = getClosestDraggable(target);\r\n\r\n\r\n\t\tif (currentHoveredElement && currentHoveredElement !== closestTarget) {\r\n\t\t\tcurrentHoveredElement.classList.remove('over');\r\n\t\t\tenterCounter.set(currentHoveredElement, 0);\r\n\t\t}\r\n\r\n\r\n\t\tif (closestTarget && closestTarget !== dragSrcEl) {\r\n\t\t\tif (!enterCounter.has(closestTarget)) {\r\n\t\t\t\tenterCounter.set(closestTarget, 0);\r\n\t\t\t}\r\n\t\t\tenterCounter.set(closestTarget, enterCounter.get(closestTarget) + 1);\r\n\t\t\tclosestTarget.classList.add('over');\r\n\t\t\tcurrentHoveredElement = closestTarget; // Update the currently hovered element\r\n\t\t}\r\n\t};\r\n\r\n\r\n\tconst shouldPreventDefault = function (e) {\r\n\t\tconst touch = e.touches[0];\r\n\t\tconst element = document.elementFromPoint(touch.clientX, touch.clientY);\r\n\t\treturn element && element.classList.contains('icon-arrows-up-down-left-right');\r\n\t};\r\n\r\n\tconst handleTouchEnd = function (e) {\r\n\t\tif (!dragSrcEl) return;\r\n\r\n\t\tconst target = document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY);\r\n\t\tconst dropTarget = getClosestDraggable(target);\r\n\r\n\t\tif (dragSrcEl !== dropTarget && dropTarget) {\r\n\t\t\tconst draggableItems = Array.from(document.querySelectorAll('[draggable=\"true\"]'));\r\n\t\t\tconst dragIndex = draggableItems.indexOf(dragSrcEl);\r\n\t\t\tconst dropIndex = draggableItems.indexOf(dropTarget);\r\n\r\n\t\t\tif (dragIndex < dropIndex) {\r\n\t\t\t\tdropTarget.parentNode.insertBefore(dragSrcEl, dropTarget.nextSibling);\r\n\t\t\t} else {\r\n\t\t\t\tdropTarget.parentNode.insertBefore(dragSrcEl, dropTarget);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdraggableItems.forEach(item => {\r\n\t\t\titem.classList.remove('over');\r\n\t\t\tenterCounter.set(item, 0);\r\n\t\t});\r\n\r\n\t\tdragSrcEl = null; // Reset the dragged element\r\n\t\tcurrentHoveredElement = null; // Reset the currently hovered element\r\n\t};\r\n\r\n\r\n\tconst handleDragStart = function (e) {\r\n\t\tdragSrcEl = this;\r\n\t\te.dataTransfer.effectAllowed = 'move';\r\n\t\te.dataTransfer.setData('text/plain', '');\r\n\t};\r\n\r\n\tconst handleDragOver = function (e) {\r\n\t\tif (e.preventDefault) {\r\n\t\t\te.preventDefault();\r\n\t\t}\r\n\t\te.dataTransfer.dropEffect = 'move';\r\n\t\treturn false;\r\n\t};\r\n\r\n\tconst handleDragEnter = function (e) {\r\n\t\tlet target = getClosestDraggable(e.target);\r\n\t\tif (target && target !== dragSrcEl) {\r\n\t\t\tif (!enterCounter.has(target)) {\r\n\t\t\t\tenterCounter.set(target, 0);\r\n\t\t\t}\r\n\t\t\tenterCounter.set(target, enterCounter.get(target) + 1);\r\n\t\t\ttarget.classList.add('over');\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleDragLeave = function (e) {\r\n\t\tlet target = getClosestDraggable(e.target);\r\n\t\tif (target && target !== dragSrcEl) {\r\n\t\t\tenterCounter.set(target, enterCounter.get(target) - 1);\r\n\t\t\tif (enterCounter.get(target) === 0) {\r\n\t\t\t\ttarget.classList.remove('over');\r\n\t\t\t}\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleDrop = function (e) {\r\n\t\tif (e.stopPropagation) {\r\n\t\t\te.stopPropagation();\r\n\t\t}\r\n\r\n\t\tlet target = getClosestDraggable(e.target);\r\n\t\tif (dragSrcEl !== target && target) {\r\n\t\t\tconst draggableItems = Array.from(document.querySelectorAll('[draggable=\"true\"]'));\r\n\t\t\tconst dragIndex = draggableItems.indexOf(dragSrcEl);\r\n\t\t\tconst dropIndex = draggableItems.indexOf(target);\r\n\r\n\t\t\tif (dragIndex < dropIndex) {\r\n\t\t\t\ttarget.parentNode.insertBefore(dragSrcEl, target.nextSibling);\r\n\t\t\t} else {\r\n\t\t\t\ttarget.parentNode.insertBefore(dragSrcEl, target);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t};\r\n\r\n\tconst handleDragEnd = (e) => {\r\n\t\tForEach(draggableItems, item => {\r\n\t\t\titem.classList.remove('over');\r\n\t\t\tenterCounter.set(item, 0);\r\n\t\t});\r\n\t\tdragSrcEl = null; // Reset the dragged element\r\n\t\tcurrentHoveredElement = null; // Reset the currently hovered element\r\n\t};\r\n\r\n\tconst addDraggable = (element) => {\r\n\r\n\t addEvent(element, 'dragstart', handleDragStart);\r\n\t addEvent(element, 'dragenter', handleDragEnter);\r\n\t addEvent(element, 'dragover', handleDragOver);\r\n\t addEvent(element, 'dragleave', handleDragLeave);\r\n\t addEvent(element, 'drop', handleDrop);\r\n\t addEvent(element, 'dragend', handleDragEnd);\r\n\t addEvent(element, 'touchstart', handleTouchStart);\r\n\t addEvent(element, 'touchmove', handleTouchMove);\r\n\t addEvent(element, 'touchend', handleTouchEnd);\r\n\r\n\t}\r\n\r\n\tlet draggableItems = $('[draggable=\"true\"]');\r\n\taddDraggable(draggableItems);\r\n\r\n\r\n\r\n\r\n\r\n/*\tUPLOAD FILE ========================================================================== */\r\n\r\n\r\n\tconst uploadFile = (elem) => {\r\n\r\n\r\n\r\n\t\tconst xhr = new XMLHttpRequest();\r\n\r\n\t\tconst submitBtn = $$('[type=\"submit\"]');\r\n\t\tif (submitBtn) {\r\n\t\t\tsubmitBtn.disabled = true;\r\n\t\t}\r\n\t\t\r\n\r\n\t\tconst container = elem.parentElement.previousElementSibling;\r\n\t\tlet progressBar, progressText;\r\n\t\tconst label = elem.nextElementSibling;\r\n\r\n\t\t$$('span',label)?.remove();\r\n\t\tprogressText = createProgressText();\r\n\t\tlabel.appendChild(progressText);\r\n\r\n\t\taddClass(label, 'disabled');\r\n\r\n\t\txhr.upload.onprogress = (e) => handleUploadProgress(e, progressText, elem);\r\n\t\txhr.onload = () => {\r\n\t\t\tif (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {\r\n\t\t\t\tconst data = JSON.parse(xhr.response);\r\n\r\n\t\t\t\tif (data.success) {\r\n\r\n\t\t\t\t\tif (data.redirect) {\r\n\t\t\t\t\t\r\n\t\t\t\t\t\twindow.location.href = data.redirect;\r\n\r\n\t\t\t\t\t} else {\r\n\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\t handleFileError(elem, label, progressText, submitBtn);\r\n\t\t\t\t}\r\n\t\t\t\tconsole.log(data)\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\txhr.upload.onerror = () => handleFileError(elem, label, progressText, submitBtn);\r\n\t\txhr.upload.onabort = () => handleFileError(elem, label, progressText, submitBtn);\r\n\t\txhr.onerror = () => handleFileError(elem, label, progressText, submitBtn);\r\n\r\n\t\tconst formData = createFormData(elem);\r\n\t\txhr.open('POST', '/forms-user/import', true);\r\n\t\txhr.send(formData);\r\n\r\n\t};\r\n\r\n\tconst handleFileError = (elem, label, progressText, submitBtn) => {\r\n\t\tprogressText.textContent = getAttr(elem, 'data-error');\r\n\t\tremoveClass(label, 'disabled');\r\n\t\telem.value = '';\r\n\t\tif (submitBtn) {\r\n\t\t\tsubmitBtn.disabled = false;\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tUPLOAD IMAGE ========================================================================== */\r\n\r\n\r\n\tconst uploadImage = (elem) => {\r\n\r\n\t\tconst xhr = new XMLHttpRequest();\r\n\t\tconst uploadFolder = location.host.startsWith(\"sandbox\") ? '/uploads-sandbox/' : '/uploads/';\r\n\t\tconst isMultiple = elem.hasAttribute('multiple');\r\n\r\n\t\tconst submitBtn = $$('[type=\"submit\"]');\r\n\t\tsubmitBtn.disabled = true;\r\n\r\n\t\tconst container = elem.parentElement.previousElementSibling;\r\n\t\tlet progressBar, progressText;\r\n\t\tconst label = elem.nextElementSibling;\r\n\r\n\t\tif (isMultiple) {\r\n\r\n\r\n\t\t\t$$('span',label)?.remove();\r\n\t\t\tprogressText = createProgressText();\r\n\t\t\tlabel.appendChild(progressText);\r\n\r\n\t\t} else {\r\n\r\n\t\t\t[progressBar, progressText] = createProgressBar();\r\n\t\t\t$$('.progress-text',container)?.remove();\r\n\t\t\tcontainer.appendChild(progressBar);\r\n\t\t}\r\n\r\n\t\taddClass(label, 'disabled');\r\n\r\n\t\txhr.upload.onprogress = (e) => handleUploadProgress(e, progressText, elem);\r\n\t\txhr.onload = () => handleUploadLoad(xhr, elem, container, label, progressBar, progressText, submitBtn, isMultiple, uploadFolder);\r\n\t\txhr.upload.onerror = () => handleUploadError(elem, label, progressText, submitBtn);\r\n\t\txhr.upload.onabort = () => handleUploadError(elem, label, progressText, submitBtn);\r\n\t\txhr.onerror = () => handleRequestError(elem, label, progressText, submitBtn);\r\n\r\n\t\tconst formData = createFormData(elem);\r\n\t\txhr.open('POST', '/forms-user/upload', true);\r\n\t\txhr.send(formData);\r\n\r\n\t};\r\n\r\n\r\n\r\n\r\n/*\tUPLOAD FILES UTILITIES ========================================================================== */\r\n\r\n\r\n\tconst createProgressText = () => {\r\n\t\tconst progressText = createElement('span', {class: 'badge bg-secondary white-space-normal ms-1 p-2'});\r\n\t\treturn progressText;\r\n\t};\r\n\r\n\tconst createProgressBar = () => {\r\n\t\tconst progressBar = createElement('div', {class: 'progress-text bg-light bg-opacity-50'});\r\n\r\n\t\tconst progressText = createElement('div', {class: 'badge bg-secondary white-space-normal p-2'});\r\n\t\tprogressBar.appendChild(progressText);\r\n\r\n\t\treturn [progressBar, progressText];\r\n\t};\r\n\r\n\tconst handleUploadProgress = (e, progressText, elem) => {\r\n\t\tif (e.lengthComputable) {\r\n\t\t\tconst progressVal = (e.loaded / e.total) * 100;\r\n\t\t\tprogressText.textContent = (progressVal > 99) ? getAttr(elem, 'data-progress') : `${Math.round(progressVal)}%`;\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleUploadLoad = (xhr, elem, container, label, progressBar, progressText, submitBtn, isMultiple, uploadFolder) => {\r\n\t\tif (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {\r\n\t\t\tconst data = JSON.parse(xhr.response);\r\n\t\t\tconsole.log(data);\r\n\t\t\tif (data.success) {\r\n\t\t\t\tif (isMultiple) {\r\n\t\t\t\t\thandleMultipleUploadSuccess(data, container, elem, label, progressText, uploadFolder);\r\n\t\t\t\t} else {\r\n\t\t\t\t\thandleSingleUploadSuccess(data, container, elem, label, progressBar, uploadFolder);\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\thandleUploadError(elem, label, progressText, submitBtn);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!$('label.disabled').length) {\r\n\t\t\tsubmitBtn.disabled = false;\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleMultipleUploadSuccess = (data, container, elem, label, progressText, uploadFolder) => {\r\n\r\n\t\tlet images = data.src;\r\n\t\tif (typeof images === 'object' && images !== null) {\r\n\t\t\timages = Object.values(images);\r\n\t\t}\r\n\t\timages.forEach(src => {\r\n\t\t\tconst imgContainer = createElement('div', {draggable: 'true'});\r\n\r\n\t\t\tconst imgDiv = createElement('div', {class: 'img-multiple'});\r\n\r\n\t\t\tconst imgTag = createElement('img', {class: 'img-fluid img-thumbnail', src:`${uploadFolder}${src}.jpg` });\r\n\r\n\t\t\tconst imgBtnDelete = createElement('button', {type: 'button', class: 'delete-img btn btn-danger top-0 start-0 position-absolute z-1 icon-trash'});\r\n\r\n\t\t\tconst imgBtnMove = createElement('button', {type: 'button', class: 'btn btn-light text-secondary bottom-0 end-0 position-absolute z-1 icon-arrows-up-down-left-right'});\r\n\r\n\t\t\tconst imgInput = createElement('input', {type: 'hidden', name: `${data.inputName}[]`, value: src});\r\n\r\n\t\t\timgDiv.append(imgTag, imgBtnDelete, imgBtnMove, imgInput);\r\n\t\t\timgContainer.appendChild(imgDiv)\r\n\t\t\tcontainer.appendChild(imgContainer);\r\n\t\t\tlet draggableItems = $('[draggable=\"true\"]');\r\n\t\t\taddDraggable(imgContainer);\r\n\r\n\t\t});\r\n\t\tprogressText.remove();\r\n\t\tremoveClass(label, 'disabled');\r\n\t\telem.value = '';\r\n\t};\r\n\r\n\tconst handleSingleUploadSuccess = (data, container, elem, label, progressBar, uploadFolder) => {\r\n\t\t$$('img', container).src = `${uploadFolder}${data.src[0]}.jpg`;\r\n\t\t$$('input', container).value = data.src[0];\r\n\t\tprogressBar.remove();\r\n\t\tremoveClass(label, 'disabled');\r\n\t\telem.value = '';\r\n\t};\r\n\r\n\tconst handleUploadError = (elem, label, progressText, submitBtn) => {\r\n\t\tprogressText.textContent = getAttr(elem, 'data-error');\r\n\t\tremoveClass(label, 'disabled');\r\n\t\telem.value = '';\r\n\t\tif (!$('label.disabled').length) {\r\n\t\t\tsubmitBtn.disabled = false;\r\n\t\t}\r\n\t};\r\n\r\n\tconst handleRequestError = (elem, label, progressText, submitBtn) => {\r\n\t\tconsole.error('Request error');\r\n\t\thandleUploadError(elem, label, progressText, submitBtn);\r\n\t};\r\n\r\n\tconst createFormData = (elem) => {\r\n\t\tconst formData = new FormData();\r\n\t\tconst files = elem.files;\r\n\t\tconst imgSizes = getAttr(elem,'data-img-size');\r\n\t\tconst importType = getAttr(elem,'data-import');\r\n\r\n\t\tArray.from(files).forEach(file => {\r\n\t\t\tformData.append(`${elem.name}[]`, file);\r\n\t\t\tformData.append('inputName[]', elem.name);\r\n\t\t});\r\n\r\n\r\n\t\tformData.append('NONCE', $$('#NONCE').value);\r\n\t\tformData.append('HASH', $$('#HASH').value);\r\n\t\tformData.append('URL', $$('#URL').value);\r\n\t\tif (imgSizes) {\r\n\t\t\tformData.append('sizes', imgSizes);\r\n\t\t}\r\n\t\tif (importType) {\r\n\t\t\tformData.append('import-type', importType);\r\n\t\t}\r\n\t\treturn formData;\r\n\t};\r\n\r\n\r\n\r\n/*\tMODAL ========================================================================== */\r\n\r\n\r\n\r\n\tconst createModalElements = (sectionElem, elemConfig) => {\r\n\r\n\r\n\t\tForEach(elemConfig, item => {\r\n\t\t\tfor (const tag in item) {\r\n\t\t\t\tconst { attr, content } = item[tag];\r\n\t\t\t\tappendChild(sectionElem, createElement(tag, attr, content));\r\n\t\t\t}\r\n\t\t});\r\n\t};\r\n\r\n\tconst createModalContent = (htmlConfig) => {\r\n\t\tconst fragment = document.createDocumentFragment();\r\n\t\tfor (const section in htmlConfig) {\r\n\t\t\tconst sectionElem = createElement('div', { class: section });\r\n\t\t\tcreateModalElements(sectionElem, htmlConfig[section]);\r\n\t\t\tappendChild(fragment, sectionElem);\r\n\t\t}\r\n\t\treturn fragment;\r\n\t};\r\n\r\n\tconst createModal = async (config) => {\r\n\t\tconst modal = createElement('div', { class: 'modal fade', tabindex: '-1' });\r\n\t\tconst modalSize = config.modalSize ?? '';\r\n\t\tconst modalDialog = createElement('div', { class: 'modal-dialog modal-dialog-centered modal-dialog-scrollable '+modalSize });\r\n\t\tconst modalContent = createElement('div', { class: 'modal-content' });\r\n\t\tlet modalInnerContent;\r\n\r\n\t\tif (config.fetchUrl) {\r\n\r\n\t\t\tpageAddLoading();\r\n\r\n\t\t\ttry {\r\n\r\n\t\t\t\tlet postBody = {};\r\n\r\n\t\t\t\tif (config.formdata) {\r\n\t\t\t\t\tconst formData = new FormData();\r\n\t\t\t\t\tformData.append('NONCE', config.formdata.NONCE);\r\n\t\t\t\t\tformData.append('HASH', config.formdata.HASH);\r\n\t\t\t\t\tformData.append('URL', config.fetchUrl);\r\n\t\t\t\t\tpostBody = formData\r\n\t\t\t\t}\r\n\r\n\t\t\tconst data = await postData(config.fetchUrl, postBody);\r\n\r\n\t\t\tif (data.success) {\r\n\r\n\t\t\t\tmodalInnerContent = data.modal.content;\r\n\t\t\t\tif (data.modal.modalSize) {\r\n\t\t\t\t\taddClass(modalDialog, data.modal.modalSize);\r\n\t\t\t\t}\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (data.error) {\r\n\t\t\t\t\tmodalInnerContent = data.error;\r\n\t\t\t\t}\r\n\t\t\t\tif (data.message) {\r\n\t\t\t\t\tmodalInnerContent = data.message;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconsole.log(data);\r\n\t\t\t} catch (error) {\r\n\t\t\t\tmodalInnerContent = data.error;\r\n\t\t\t\tconsole.log('catch error');\r\n\t\t\t}\r\n\r\n\t\t\tpageRemoveLoading();\r\n\r\n\t\t} else {\r\n\r\n\t\t\tmodalInnerContent = config.modal;\r\n\r\n\t\t}\r\n\r\n\r\n\t\tconst htmlContent = createModalContent(modalInnerContent);\r\n\r\n\t\tappendChild(modalContent, htmlContent);\r\n\t\tappendChild(modalDialog, modalContent);\r\n\t\tappendChild(modal, modalDialog);\r\n\r\n\t\tappendChild(document.body, modal);\r\n\r\n\r\n\t\tconst bootstrapModal = new bootstrap.Modal(modal);\r\n\r\n\t\tbootstrapModal .show();\r\n\t\taddEvent(modal, ['hidden.bs.modal'], () => {\r\n\t\t\tremoveElement(modal);\r\n\t\t});\r\n\r\n\t};\r\n\r\n\r\n\r\n/*\tTIMEOUT, PREVENT DEFAULT ========================================================================== */\r\n\r\n\r\n\tconst SetTimeout = (callback, delay) => setTimeout(callback, delay);\r\n\r\n\tconst preventDefault = event => event.preventDefault();\r\n\r\n\r\n\r\n/*\tFORM HANDLE ERROR ========================================================================== */\r\n\r\n\tconst handleError = (formElem, submitButton, alertmsg, data, spinner) => {\r\n\r\n\t\taddClass(formElem, 'was-error');\r\n\t\tpageRemoveLoading();\r\n\r\n\t\tif (data.message && alertmsg) {\r\n\t\t\tremoveClass(alertmsg, 'alert-success');\r\n\t\t\taddClass(alertmsg, 'alert-danger');\r\n\t\t\tinnerHTML(alertmsg, data.message)\r\n\t\t\telemDisplay(alertmsg,'block')\r\n\r\n\t\t\tif (typeof data.noScroll === 'undefined') {\r\n\t\t\t\tscrollIntoViewOffset(alertmsg);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\r\n\t\t/*\r\n\t\tif ($('#delete_post')) {\r\n\t\t\tenableFormInputs();\r\n\t\t\t$('#delete_post').remove();\r\n\t\t}\r\n\t\t*/\r\n\t};\r\n\r\n\r\n\r\n/*\tRENAME CLONE VARIANT ========================================================================== */\r\n\r\n\tconst renameCloneVariant = () => {\r\n\r\n\t\tconst variant = $('.product-variant');\r\n\t\tlet cloneIndex = 0;\r\n\r\n\t\tForEach(variant, group => {\r\n\r\n\r\n\t\t\tForEach($('input, select, textarea, label',group), elem => {\r\n\r\n\t\t\t\tconst label = elem.getAttribute('for');\r\n\r\n\t\t\t\tif (label) {\r\n\t\t\t\t\tsetAttr(elem, {for: label.replace(/\\[\\d+\\]/, `[${cloneIndex}]`)} );\r\n\t\t\t\t}\r\n\t\t\t\tif (elem.name) {\r\n\t\t\t\t\telem.name = elem.name.replace(/\\[\\d+\\]/, `[${cloneIndex}]`);\r\n\t\t\t\t}\r\n\t\t\t\tif (elem.id) {\r\n\t\t\t\t\telem.id = elem.id.replace(/\\[\\d+\\]/, `[${cloneIndex}]`);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\tcloneIndex++;\r\n\r\n\t\t});\r\n\r\n\t\tdeleteBtnVariant();\r\n\t}\r\n\r\n\r\n\r\n\r\n/*\tSHOW DELETE BTN VARIANT ========================================================================== */\r\n\r\n\tconst deleteBtnVariant = () => {\r\n\r\n\t\tconst variant = $('.product-variant');\r\n\t\tlet Index = 0;\r\n\r\n\t\tForEach(variant, group => {\r\n\r\n\t\t\tconst btnDelete = $$('.delete-item', group);\r\n\t\t\tconst itemID = $$('input', group);\r\n\r\n\t\t\tif (Index > 0) {\r\n\t\t\t\tif (hasClass(btnDelete,'enable-delete')) {\r\n\r\n\t\t\t\t\tremoveAttr(btnDelete, 'style');\r\n\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (!itemID.value) {\r\n\t\t\t\t\t\tremoveAttr(btnDelete, 'style');\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\r\n\t\t\t} else {\r\n\t\t\t\telemDisplay(btnDelete, 'none');\r\n\t\t\t}\r\n\r\n\t\t\tIndex++;\r\n\r\n\t\t});\r\n\r\n\t}\r\n\r\n\r\n\r\n/*\tGOOGLE CAPTCHA ========================================================================== */\r\n\r\n\tfunction onSubmit(token) {\r\n\t\tdispatchChangeEvent($$('form'), 'submit');\r\n\t}\r\n\r\n\r\n\r\n\r\n/*\tEVENTS DOM LOADED ====================================================================== */\r\n\r\n\tconst rootMarginPX = '0px 0px -10% 0px'\r\n\r\n\taddEvent(document, [\"DOMContentLoaded\"], event => {\r\n\r\n\r\n\r\n\r\n/*\tTRANSITION ========================================================================== */\r\n\r\n\tForEach(['.fadeIn','.fadeInUp','.fadeInLeft','.fadeInRight'], elem => observeElements($(elem), (entry, observer) => {\r\n\r\n\t\tif (entry.isIntersecting) {\r\n\t\t\tconst element = entry.target;\r\n\t\t\taddClass(element, 'active');\r\n\t\t\tobserver.unobserve(element);\r\n\t\t}\r\n\r\n\t\t},\r\n\r\n\t\t{ rootMargin: rootMarginPX } \r\n\r\n\t));\r\n\r\n\tobserveElements($('[data-anim-num]'), countUpNumbers, { rootMargin: rootMarginPX });\r\n\r\n\r\n\tconst fragment = window.location.hash;\r\n\tif (fragment && $$(fragment)) {\r\n\r\n\t\tconst targetElement = $$(fragment);\r\n\r\n\t\tif (targetElement) {\r\n\t\t\twindow.location.hash = '';\r\n\t\t\tscrollIntoViewOffset(targetElement);\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n/*\tBODY LOADING ========================================================================== */\r\n\r\n\tpageRemoveLoading();\r\n\r\n\tlet triggerbeforeunload = true;\r\n\r\n\taddEvent($('a'), 'click', event => {\r\n\r\n\t\tconst elem = getCurrentTarget(event);\r\n\t\tconst href = getAttr(elem,'href');\r\n\r\n\t\tif (href) {\r\n\r\n\t\t\tif (href == '#') {\r\n\r\n\t\t\t\tpreventDefault(event);\r\n\r\n\t\t\t\tif (hasClass(elem,'history-back')) {\r\n\t\t\t\t\thistory.back();\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\r\n\t\t\t} else {\r\n\r\n\t\t\t\tif (!getAttr(elem,'target')) {\r\n\t\t\t\t\tpageAddLoading();\r\n\r\n\t\t\t\t} else {\r\n\r\n\t\t\t\t\ttriggerbeforeunload = false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t});\r\n\r\n\t/*\r\n\t\taddEvent($('.history-back'), ['click'], event => {\r\n\t\t\tpageAddLoading();\r\n\t\t\thistory.back();\r\n\t\t});\r\n\t*/\r\n\r\n\taddEvent(window, ['beforeunload'], event => {\r\n\t\tif (triggerbeforeunload) {\r\n\t\t\tpageAddLoading();\r\n\t\t}\r\n\t\t\r\n\t});\r\n\r\n\r\n\tif (document.referrer.indexOf(window.location.host) === -1 || document.referrer == '') {\r\n\t\tForEach($('.history-back'), elem => setAttr(elem, {disabled:true}))\r\n\t}\r\n\r\n\r\n\r\n\r\n/*\tTOOLTIP ========================================================================== */\r\n\r\n\tconst tooltipTriggerList = $('[data-bs-toggle=\"tooltip\"]')\r\n\tconst tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))\r\n\r\n\r\n\r\n\r\n/*\tLOWERCASE ========================================================================== */\r\n\taddEvent($('.js-lowercase'), 'change', event => {\r\n\r\n\t\tconst elem = event.currentTarget;\r\n\t\tconst str = elem.value;\r\n\t\telem.value = str.toLowerCase();\r\n\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tREMOVE SPACE ========================================================================== */\r\n\taddEvent($('.js-nospace'), 'change', event => {\r\n\t\t\r\n\t\tconst elem = event.currentTarget;\r\n\t\tconst str = elem.value;\r\n\t\telem.value = str.replace(/\\s+/g, '');\r\n\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tTIKTOK EMBED ========================================================================== */\r\n\r\n\tconst dataFetch = 'data-fetch';\r\n\tForEach($('['+dataFetch+']'), elem => {\r\n\r\n\t\tif (elem) {\r\n\r\n\t\t\tconst config = JSON.parse(getAttr(elem, dataFetch));\r\n\r\n\t\t\ttry {\r\n\t\t\t\tpostData('https://www.tiktok.com/oembed?url=https://vt.tiktok.com/' + config.url).then((data) => {\r\n\r\n\t\t\t\t\t// TIKTOK\r\n\t\t\t\t\tif (config.type == 'tiktok') {\r\n\t\t\t\t\t\tif (data.embed_product_id) {\r\n\r\n\t\t\t\t\t\t\tconst iframe = createElement('iframe', {src: 'https://www.tiktok.com/player/v1/'+data.embed_product_id, allow: 'fullscreen'});\r\n\t\t\t\t\t\t\telem.appendChild(iframe);\r\n\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\telem.remove();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\r\n\t\t\t\t//\tconsole.log(data);\r\n\t\t\t\t});\r\n\r\n\t\t\t} catch (error) {\r\n\t\t\t\tconsole.log(error)\r\n\r\n\t\t\t}\r\n\t\t\t\r\n\r\n\t\t}\r\n\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tMODAL ========================================================================== */\r\n\r\n\tconst dataModal = 'data-modal-config';\r\n\taddEvent($('['+dataModal+']'), ['click'], event => {\r\n\t\tconst elem = event.currentTarget;\r\n\r\n\t\tconst config = JSON.parse(getAttr(elem, dataModal));\r\n\r\n\t\tcreateModal(config);\r\n\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tSLIDESHOW ========================================================================== */\r\n\r\n\taddEvent($$('#carousel'), ['slide.bs.carousel'], event => {\r\n\r\n\t\tconst img_counter = $$('#img-counter');\r\n\t\tif (img_counter) {\r\n\t\t\timg_counter.innerText = event.to + 1;\r\n\t\t}\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tSHOPPING CART ========================================================================== */\r\n\r\n\r\n\r\n\taddEvent($('.input-qty'), ['change'], event => {\r\n\r\n\t\tconst elem = event.currentTarget;\r\n\t\tlet input_value = parseInt(elem.value);\r\n\t\tlet max_amount = parseInt(getAttr(elem,'data-max'));\r\n\r\n\t\tif (max_amount < 1) {\r\n\t\t\tmax_amount = 0;\r\n\t\t}\r\n\r\n\t\tif (isNaN(input_value)) {\r\n\t\t\tinput_value = 0;\r\n\t\t}\r\n\r\n\t\tlet total_value = input_value;\r\n\r\n\t\tif (total_value < 1) {\r\n\t\t\telem.value = '';\r\n\t\t}\r\n\r\n\t\tif (total_value > max_amount) {\r\n\t\t\telem.value = max_amount;\r\n\t\t\tif (max_amount == 0) {\r\n\t\t\t\telem.value = '';\r\n\t\t\t}\r\n\r\n\t\t\tconst tooltipInstance = bootstrap.Tooltip.getInstance(elem.nextElementSibling);\r\n\t\t\ttooltipInstance.show();\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\ttooltipInstance.hide();\r\n\t\t\t}, 800);\r\n\t\t}\r\n\r\n\r\n\t\t// CALCULATE\r\n\r\n\t\tlet subTotal = 0;\r\n\t\tForEach($('.input-qty'), input => {\r\n\t\t\tsubTotal += input.value * parseFloat(getAttr(input,'data-price'));\r\n\t\t});\r\n\r\n\t\t$$('#total-amount').innerText = new Intl.NumberFormat().format(subTotal);\r\n\r\n\t});\r\n\r\n\r\n\taddEvent($('.add-qty'), ['click'], event => {\r\n\r\n\t\tconst elem = event.currentTarget;\r\n\r\n\t\tconst inputElem = $$('input', elem.parentNode);\r\n\t\tlet input_value = parseInt(inputElem.value);\r\n\r\n\t\tlet amount = 1;\r\n\r\n\t\tif (isNaN(input_value)) {\r\n\t\t\tinput_value = 0;\r\n\t\t}\r\n\r\n\t\tif (hasClass(elem, 'cart-minus')) {\r\n\t\t\tamount = -1;\r\n\t\t}\r\n\r\n\t\tinputElem.value = input_value + amount;\r\n\t\tdispatchChangeEvent(inputElem, 'change');\r\n\r\n\r\n\t});\r\n\r\n\r\n\r\n\r\n/*\tFORM NEXT SECTION BUTTON ========================================================================== */\r\n\r\n\tconst formSections = $('section');\r\n\r\n\tconst formNav = $('.form-page-nav');\r\n\r\n\tlet newIndex = 0;\r\n\tlet storedIndex = 0;\r\n\r\n\tif (formNav.length) {\r\n\r\n\t\tForEach(formNav, formBtn => {\r\n\r\n\t\t\taddEvent(formBtn, 'click', event => {\r\n\r\n\t\t\t\tconst pgNumber = (formBtn.id == 'next-form') ? 1 : -1;\r\n\t\t\t\tnewIndex = storedIndex + pgNumber;\r\n\r\n\t\t\t\tif (formSections[newIndex]) {\r\n\t\t\t\t\tstoredIndex = newIndex;\r\n\t\t\t\t\tscrollIntoViewOffset(formSections[newIndex], 60);\r\n\t\t\t\t}\r\n\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n\r\n\r\n\r\n\r\n/*\tHTML EDITOR ========================================================================== */\r\n\r\n\t/*\r\n\tconst toolbarOptions = [\r\n\t\t['bold', 'italic', 'underline', 'strike'], // toggled buttons\r\n\t\t['blockquote', 'code-block'],\r\n\t\t['link', 'image', 'video', 'formula'],\r\n\r\n\t\t[{ 'header': 1 }, { 'header': 2 }], // custom button values\r\n\t\t[{ 'list': 'ordered'}, { 'list': 'bullet' }, { 'list': 'check' }],\r\n\t\t[{ 'script': 'sub'}, { 'script': 'super' }], // superscript/subscript\r\n\t\t[{ 'indent': '-1'}, { 'indent': '+1' }], // outdent/indent\r\n\t\t[{ 'direction': 'rtl' }], // text direction\r\n\r\n\t\t[{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown\r\n\t\t[{ 'header': [1, 2, 3, 4, 5, 6, false] }],\r\n\r\n\t\t[{ 'color': [] }, { 'background': [] }], // dropdown with defaults from theme\r\n\t\t[{ 'font': [] }],\r\n\t\t[{ 'align': [] }],\r\n\r\n\t\t['clean'] // remove formatting button\r\n\t];\r\n\t*/\r\n\r\n\r\n\tForEach($('.js-htmleditor'), editor => {\r\n\r\n\t\tconst elemID = '#'+ getAttr(editor, 'data-id');\r\n\r\n\t\tconst quill = new Quill(editor, {\r\n\t\t\tmodules: {\r\n\t\t\t\ttoolbar: elemID + '-htmltoolbar',\r\n\t\t\t},\r\n\t\t\tformats: ['header', 'bold', 'italic', 'underline', 'list', 'link'],\r\n\t\t});\r\n\r\n\t\tquill.on('text-change', (delta, oldDelta, source) => {\r\n\r\n\t\t\tlet content = quill.root.innerHTML.replace('