1function toast(message, code = 200) { 2 3 classToast = "toast-success"; 4 if (code != 200) classToast = "toast-error"; 5 6 7 const toastInstance = Toastify({ 8 text: message, 9 duration: 5000, 10 close: false, 11 gravity: "top", // `top` or `bottom` 12 position: "left", // `left`, `center` or `right` 13 stopOnFocus: true, // Prevents dismissing of toast on hover 14 className: classToast, 15 onClick: function () { toastInstance.hideToast() } // Callback after click 16 }); 17 18 toastInstance.showToast(); 19} 20//SPINWHEELS 21 22function toastAction(message, code = 200, buttonText = null, buttonId = null) { 23 24 if (!document.getElementById("toast-action-btn-style")) { 25 const style = document.createElement("style"); 26 style.id = "toast-action-btn-style"; 27 style.innerHTML = ` 28 .toast-action-btn { 29 position: relative; 30 display: inline-flex; 31 align-items: center; 32 justify-content: center; 33 margin-top: 10px; 34 margin-left: 12px; 35 padding: 7px 16px; 36 border-radius: 999px; 37 font-weight: 800; 38 font-size: 12px; 39 letter-spacing: .5px; 40 border: none; 41 cursor: pointer; 42 color: #151515 !important; 43 background: linear-gradient(135deg, #ffd400 0%, #ffb800 35%, #ffdf66 50%, #ffb800 65%, #ffd400 100%); 44 background-size: 220% 220%; 45 box-shadow: 46 0 0 0 1px rgba(255,255,255,.12) inset, 47 0 4px 14px rgba(255, 193, 7, .45), 48 0 0 18px rgba(255, 215, 0, .28); 49 overflow: hidden; 50 animation: toastCasinoGlow 1.8s ease-in-out infinite, toastCasinoShine 2.4s linear infinite; 51 transition: transform .18s ease, box-shadow .18s ease; 52 white-space: nowrap; 53 vertical-align: middle; 54 } 55 56 .toast-action-btn:hover { 57 transform: translateY(-1px) scale(1.03); 58 box-shadow: 59 0 0 0 1px rgba(255,255,255,.16) inset, 60 0 8px 18px rgba(255, 193, 7, .55), 61 0 0 22px rgba(255, 215, 0, .34); 62 } 63 64 .toast-action-btn::before { 65 content: ""; 66 position: absolute; 67 top: -30%; 68 left: -35%; 69 width: 30%; 70 height: 160%; 71 background: linear-gradient( 72 90deg, 73 rgba(255,255,255,0) 0%, 74 rgba(255,255,255,.18) 35%, 75 rgba(255,255,255,.7) 50%, 76 rgba(255,255,255,.18) 65%, 77 rgba(255,255,255,0) 100% 78 ); 79 transform: rotate(20deg); 80 animation: toastCasinoSweep 1.9s linear infinite; 81 pointer-events: none; 82 } 83 84 @keyframes toastCasinoGlow { 85 0%, 100% { 86 box-shadow: 87 0 0 0 1px rgba(255,255,255,.12) inset, 88 0 4px 14px rgba(255, 193, 7, .42), 89 0 0 14px rgba(255, 215, 0, .22); 90 } 91 50% { 92 box-shadow: 93 0 0 0 1px rgba(255,255,255,.18) inset, 94 0 6px 18px rgba(255, 193, 7, .62), 95 0 0 24px rgba(255, 215, 0, .38); 96 } 97 } 98 99 @keyframes toastCasinoShine { 100 0% { background-position: 0% 50%; } 101 50% { background-position: 100% 50%; } 102 100% { background-position: 0% 50%; } 103 } 104 105 @keyframes toastCasinoSweep { 106 0% { left: -35%; opacity: .2; } 107 30% { opacity: .85; } 108 100% { left: 120%; opacity: 0; } 109 } 110 111 @media (max-width: 768px) { 112 .toast-action-btn { 113 margin-left: 0; 114 margin-top: 8px; 115 width: 100%; 116 min-height: 42px; 117 font-size: 13px; 118 padding: 10px 14px; 119 } 120 } 121 `; 122 document.head.appendChild(style); 123 } 124
125 let classToast = code === 200 ? "toast-success" : "toast-error"; 126 127 let html = `<span style="font-weight:600;">${message}</span>`; 128 129 if (buttonText && buttonId) { 130 html += `<br><button id="${buttonId}" class="toast-action-btn">ð¡ ${buttonText}</button>`; 131 } 132 133 const toastInstance = Toastify({ 134 text: html, 135 duration: 10000, 136 close: false, 137 gravity: "top", 138 position: "left", 139 stopOnFocus: true, 140 className: classToast, 141 escapeMarkup: false 142 }); 143 144 toastInstance.showToast(); 145 146 // attach event AFTER render 147 if (buttonId) { 148 setTimeout(() => { 149 const btn = document.getElementById(buttonId); 150 if (btn) { 151 btn.addEventListener("click", function () { 152 153 // â CLOSE TOAST 154 toastInstance.hideToast(); 155 156 // lanjut logic lu 157 $(".enterSpinBtn").trigger("click"); 158 }); 159 } 160 }, 100); 161 } 162} 163//SPINWHEELS 164 165function reinitMasonry() { 166 const masonryContainer = document.querySelector('[data-masonry]'); 167 if (masonryContainer && typeof Masonry !== 'undefined') { 168 new Masonry(masonryContainer, { 169 itemSelector: '[data-masonry] > div', 170 percentPosition: true 171 }); 172 } 173} 174 175function deleteMetaTags() { 176 177 const head = document.head; 178 const nodes = Array.from(head.childNodes); 179 let inside = false;
180 181 // Remove existing meta tags between comments 182 for (let i = nodes.length - 1; i >= 0; i--) { 183 const node = nodes[i]; 184 if (node.nodeType === Node.COMMENT_NODE) { 185 if (node.data.trim() === 'Meta-End') { 186 inside = true; 187 continue; 188 } 189 if (node.data.trim() === 'Meta-Start') { 190 inside = false; 191 continue; 192 } 193 } 194 195 if (inside 196 && node.nodeType === Node.ELEMENT_NODE 197 // && node.tagName === 'META' 198 ) { 199 head.removeChild(node); 200 } 201 } 202 203 // Check if Meta-Start comment exists 204 const metaStartComment = Array.from(head.childNodes).find(node => 205 node.nodeType === Node.COMMENT_NODE && node.data.trim() === 'Meta-Start' 206 ); 207 208 return !!metaStartComment; 209} 210 211function updateMetaTags2(decodedHtml) { 212 213 // Create temporary div to parse escaped HTML 214 const tempDiv = document.createElement('div'); 215 tempDiv.innerHTML = decodedHtml; 216 217 // Extract meta tags from parsed HTML 218 const newMetaTags = Array.from(tempDiv.children); 219 220 // Delete existing meta tags 221 const metaStartExists = deleteMetaTags(); 222 223 if (decodedHtml != "") { 224 if (!metaStartExists) { 225 console.error('Meta-Start comment not found'); 226 tempDiv.remove(); 227 return; 228 } 229 230 // Find Meta-Start comment to insert after 231 const head = document.head; 232 const metaStartComment = Array.from(head.childNodes).find(node => 233 node.nodeType === Node.COMMENT_NODE && node.data.trim() === 'Meta-Start' 234 ); 235 236 // Insert new meta tags 237 newMetaTags.slice().reverse().forEach(meta => { 238 if (meta.tagName.toLowerCase() === "script") { 239 // re-create script so it executes 240 const script = document.createElement("script"); 241 if (meta.src) { 242 script.src = meta.src; 243 } else { 244 script.textContent = meta.textContent; 245 } 246 metaStartComment.after(script); 247 } else { 248 // for <meta> or others, clone normally 249 metaStartComment.after(meta.cloneNode(true)); 250 } 251 }); 252 253 } 254 255 256 // Clean up 257 tempDiv.remove(); 258} 259 260 261function updateMetaTags(base64Encoded) { 262 263 var decodedHtml = atob(base64Encoded); 264 265 // Create temporary div to parse escaped HTML 266 const tempDiv = document.createElement('div'); 267 tempDiv.innerHTML = decodedHtml; 268 269 // Extract meta tags from parsed HTML 270 const newMetaTags = Array.from(tempDiv.children); 271 272 // Delete existing meta tags 273 const metaStartExists = deleteMetaTags(); 274 275 if (!metaStartExists) { 276 console.error('Meta-Start comment not found'); 277 tempDiv.remove(); 278 return; 279 } 280 281 // Find Meta-Start comment to insert after 282 const head = document.head; 283 const metaStartComment = Array.from(head.childNodes).find(node => 284 node.nodeType === Node.COMMENT_NODE && node.data.trim() === 'Meta-Start' 285 ); 286 287 // Insert new meta tags 288 newMetaTags.slice().reverse().forEach(meta => { 289 if (meta.tagName.toLowerCase() === "script") { 290 // re-create script so it executes 291 const script = document.createElement("script"); 292 if (meta.src) { 293 script.src = meta.src; 294 } else { 295 script.textContent = meta.textContent; 296 } 297 metaStartComment.after(script); 298 } else { 299 // for <meta> or others, clone normally 300 metaStartComment.after(meta.cloneNode(true)); 301 } 302 }); 303 304 // Clean up 305 tempDiv.remove(); 306} 307 308function isOtpMobileApp() { 309 return navigator.userAgent.includes("OTP"); 310} 311 312// Core content loader 313function content(uri, target = 'content', callback = null) { 314 loading(target); 315 closeAllSlidePages(); 316 317 // if (target == 'content') { 318 // window.history.pushState({}, '', uri); 319 // console.log(window.location.href); 320 // getMeta(window.location.href); 321 // } 322 if(!navigator.userAgent.includes('OTP')) { 323 window.history.pushState({}, '', uri); 324 } 325 // console.log(window.location.href); 326 getMeta(window.location.href); 327 328 window.api.get(uri, {}, { 329 onSuccess: (response) => { 330 $(`#${target}`).html(response); 331 332 if (typeof callback === "function") { 333 callback(); // call after success 334 } 335 }, 336 onError: (response) => { 337 if (typeof callback === "function") { 338 callback(); // also call after error if needed 339 } 340 } 341 }); 342} 343 344 345function getMeta(url) { 346 347 var form = new FormData(); 348 form.append("url", url); 349 350 var settings = { 351 "url": "/api/meta", 352 "method": "POST", 353 "timeout": 0, 354 "processData": false, 355 "mimeType": "multipart/form-data", 356 "contentType": false, 357 "data": form 358 }; 359 360 $.ajax(settings).done(function (response) { 361 response = JSON.parse(response); 362 363 if (response['error']['code'] == 200) { 364 365 meta = response['data']['meta']; 366 367 title = response['data']['title']; 368 369 370 document.title = title; 371 updateMetaTags2(meta); 372 } 373 }); 374 375} 376 377 378function loading(content = 'content') { 379 $(`#${content}`).html( 380 '<div class="h-100 w-100 d-flex justify-content-center align-items-center py-5"><div class="spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div></div>' 381 ); 382} 383 384// Close all slide pages and re-enable scroll 385function closeAllSlidePages() { 386 $('.slide-page').removeClass('show'); 387 $('body').css('overflow', ''); 388} 389 390 391function salin(text) { 392 navigator.clipboard.writeText(text).then(function () { 393 toast(`${text} berhasil di salin`, 200); 394 }, function (err) { 395 toast(`${text} gagal di salin`, 400); 396 }); 397} 398 399 400 401// // Example usage: 402// const metaTags = getMetaBetweenComments();
403// metaTags.forEach(tag => console.log(tag.outerHTML))
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.