1var defArFontSize = 30; 2var maxArFontSize = 98; 3var minArFontSize = 18; 4 5if (localStorage.getItem("arFontSize") === null) { 6 localStorage.setItem('arFontSize', defArFontSize); 7} 8 9if (localStorage.getItem("autoAudioPlay") === null) { 10 localStorage.setItem('autoAudioPlay', 'no'); 11} 12 13function setArFontSize(){ 14 var getArFontSize = localStorage.getItem("arFontSize"); 15 var arFsize = document.querySelectorAll(".ar-fsize"); 16 17 for (var i = 0; i < arFsize.length; i++) { 18 if (arFsize[i].closest && arFsize[i].closest('#tepsirModal, #captureData, #qkTepsirCaptureHost, #qkTepsirExportPreview, #qkTepsirBrandStage')) { 19 continue; 20 } 21 arFsize[i].style.fontSize = getArFontSize+'px'; 22 } 23} 24 25function qkModalShow(sel) { 26 var id = (typeof sel === 'string' && sel.charAt(0) !== '#') ? ('#' + sel) : sel; 27 if (typeof window.qkOpenModal === 'function') { 28 window.qkOpenModal(sel); 29 } else if (window.jQuery) { 30 window.jQuery(id).modal('show'); 31 } 32} 33 34var arFontSizeIncrease = document.querySelector(".ar_increase"); 35if (arFontSizeIncrease) { 36 arFontSizeIncrease.addEventListener("click", function(){ 37 var getArFontSize = Number(localStorage.getItem("arFontSize")); 38 if (getArFontSize <= maxArFontSize) { 39 localStorage.setItem('arFontSize', getArFontSize+2); 40 setArFontSize(); 41 } 42 }); 43} 44 45var arFontSizeDecrease = document.querySelector(".ar_decrease"); 46if (arFontSizeDecrease) { 47 arFontSizeDecrease.addEventListener("click", function(){ 48 var getArFontSize = Number(localStorage.getItem("arFontSize")); 49 if (getArFontSize >= minArFontSize) { 50 localStorage.setItem('arFontSize', getArFontSize-2); 51 setArFontSize(); 52 } 53 }); 54} 55 56 57//Text Size 58var defTxFontSize = 22; 59var maxTxFontSize = 48; 60var minTxFontSize = 14; 61 62if (localStorage.getItem("txFontSize") === null) { 63 localStorage.setItem('txFontSize', defTxFontSize); 64} 65 66function setTxFontSize(){ 67 var getTxFontSize = localStorage.getItem("txFontSize"); 68 var txFsize = document.querySelectorAll(".tx-fsize"); 69 70 for (var i = 0; i < txFsize.length; i++) { 71 txFsize[i].style.fontSize = getTxFontSize+'px'; 72 } 73} 74 75var txFontSizeIncrease = document.querySelector(".tx_increase"); 76if (txFontSizeIncrease) { 77 txFontSizeIncrease.addEventListener("click", function(){ 78 var getTxFontSize = Number(localStorage.getItem("txFontSize")); 79 if (getTxFontSize <= maxTxFontSize) { 80 localStorage.setItem('txFontSize', getTxFontSize+2); 81 setTxFontSize(); 82 } 83 }); 84} 85 86var txFontSizeDecrease = document.querySelector(".tx_decrease"); 87if (txFontSizeDecrease) { 88 txFontSizeDecrease.addEventListener("click", function(){ 89 var getTxFontSize = Number(localStorage.getItem("txFontSize")); 90 if (getTxFontSize >= minTxFontSize) { 91 localStorage.setItem('txFontSize', getTxFontSize-2); 92 setTxFontSize(); 93 } 94 }); 95} 96 97 98 99if (localStorage.getItem("theme") === null) { 100 localStorage.setItem("theme", "light"); 101} 102document.documentElement.className = localStorage.getItem("theme"); 103 104function toggleTheme() { 105 if (localStorage.getItem('theme') == 'light') { 106 localStorage.setItem("theme", "dark"); 107 document.documentElement.className = 'dark'; 108 }else if (localStorage.getItem('theme') == 'dark') { 109 localStorage.setItem("theme", "light"); 110 document.documentElement.className = 'light'; 111 } 112} 113 114 115function selectTerjime(str, strDir) { 116 $.ajax({ 117 url:"/terjimeselect", 118 type:"POST", 119 data:{ 120 data0: 'terjime', 121 data1: str, 122 data2: strDir 123 }, 124 success:function() { 125 location.reload(); 126 } 127 }); 128} 129 130function selectQuran(str) { 131 $.ajax({ 132 url:"/terjimeselect", 133 type:"POST", 134 data:{ 135 data0: 'quran', 136 data1: str 137 }, 138 success:function() { 139 location.reload(); 140 } 141 }); 142} 143 144function reciterSelector(str) { 145 $.ajax({ 146 url:"/terjimeselect", 147 type:"POST", 148 data:{ 149 data0: 'reciter', 150 data1: str 151 }, 152 success:function() { 153 location.reload(); 154 } 155 }); 156} 157 158function tilSelector(str) { 159 $.ajax({ 160 url:"/terjimeselect", 161 type:"POST", 162 data:{ 163 data0: 'lang', 164 data1: str 165 }, 166 success:function() { 167 localStorage.setItem('langSelect', 'yes'); 168 location.reload(); 169 } 170 }); 171} 172 173function showToast(text){ 174 Message.add(text, { 175 type:'success', 176 timeIn: 400, 177 timeOut: 1000, 178 close: false, 179 vertical:'center', 180 horizontal:'center' 181 }); 182} 183 184var sureIndexShow = false;
185 186function qkIsRtlWebdir() { 187 var dir = ($('html').attr('dir') || document.documentElement.getAttribute('dir') || '').toLowerCase(); 188 if (dir === 'rtl') { 189 return true; 190 } 191 if (dir === 'ltr') { 192 return false; 193 } 194 return ($('body').css('direction') || '').toLowerCase() === 'rtl'; 195} 196 197function qkGetSureIndexEl() { 198 return $('#qkSureIndex, .sure-index').first(); 199} 200 201function qkIsSureIndexOpen() { 202 var $idx = qkGetSureIndexEl(); 203 if (!$idx.length) { 204 return false; 205 } 206 if ($idx.hasClass('qk-index-open')) { 207 return true; 208 } 209 if (sureIndexShow) { 210 return true; 211 } 212 var side = qkIsRtlWebdir() ? 'right' : 'left'; 213 return $idx.css(side) === '0px'; 214} 215 216function qkSyncSureIndexBackdrop(show) { 217 var $bd = $('#qkSureIndexBackdrop'); 218 if (!$bd.length) { 219 return; 220 } 221 if (show) { 222 $bd.addClass('is-visible').removeAttr('hidden').attr('aria-hidden', 'false'); 223 } else { 224 $bd.removeClass('is-visible').attr('hidden', 'hidden').attr('aria-hidden', 'true'); 225 } 226} 227 228function qkOpenSureIndex(panel) { 229 panel = panel || 'sure'; 230 var $idx = qkGetSureIndexEl(); 231 if (!$idx.length) { 232 return; 233 } 234 $idx.attr('data-active-panel', panel).addClass('qk-index-open'); 235 sureIndexShow = true; 236 if (qkIsRtlWebdir()) { 237 $idx.css({ right: '0px', left: '' }); 238 } else { 239 $idx.css({ left: '0px', right: '' }); 240 } 241 qkSyncSureIndexBackdrop(true); 242} 243 244function qkCloseSureIndex() { 245 var $idx = qkGetSureIndexEl(); 246 if (!$idx.length) { 247 return; 248 } 249 $idx.removeClass('qk-index-open'); 250 sureIndexShow = false; 251 if (qkIsRtlWebdir()) { 252 $idx.css({ right: '-300px' }); 253 } else { 254 $idx.css({ left: '-300px' }); 255 } 256 qkSyncSureIndexBackdrop(false); 257} 258 259function qkCloseFlyoutPanels() { 260 qkCloseSureIndex(); 261 $('.qk-dt-dropdown.is-open').removeClass('is-open'); 262 $('.qk-dt-dropdown [aria-expanded="true"]').attr('aria-expanded', 'false'); 263 if (window.qkDiyanetMushaf && typeof window.qkDiyanetMushaf.setMushafSettingsDrawerOpen === 'function') { 264 var $drawer = $('#qkMushafSettingsDrawer'); 265 if ($drawer.length && $drawer.hasClass('is-open')) { 266 window.qkDiyanetMushaf.setMushafSettingsDrawerOpen(false); 267 } 268 } 269} 270 271window.qkOpenSureIndex = qkOpenSureIndex; 272window.qkCloseSureIndex = qkCloseSureIndex; 273window.qkIsSureIndexOpen = qkIsSureIndexOpen; 274window.qkCloseFlyoutPanels = qkCloseFlyoutPanels; 275 276var selectedSureNo = 0; 277var selectedAyetNo = 0; 278var shareUrl = ''; 279var qkCaptureKind = 'ayah'; 280 281var qkTepsirIzahatXhr = null; 282var qkTepsirIzahatOpenKey = ''; 283 284function qkGetSelectedTepsirId() { 285 var $sel = $('#tepsirSelector'); 286 if ($sel.length) { 287 var storedTbl = localStorage.getItem('selectedTepsirTbl'); 288 if (storedTbl) { 289 if ($sel.find('option[value="' + storedTbl.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"]').length) { 290 $sel.val(storedTbl); 291 } else { 292 localStorage.removeItem('selectedTepsirTbl'); 293 localStorage.removeItem('selectedTepsir'); 294 } 295 } 296 var $opt = $sel.find('option:selected'); 297 if (!$opt.length) { 298 $opt = $sel.find('option:first'); 299 } 300 var id = $opt.attr('data-tepsir'); 301 if (!id) { 302 id = $opt.data('tepsir'); 303 } 304 if (id) { 305 return String(id); 306 } 307 } 308 var stored = localStorage.getItem('selectedTepsir'); 309 return stored ? String(stored) : '1'; 310} 311 312function qkGetSelectedTepsirTbl() { 313 var $sel = $('#tepsirSelector'); 314 if ($sel.length) { 315 var val = $sel.val(); 316 if (val) { 317 return val; 318 } 319 } 320 var $host = $('.qk-tefsir-commentary[data-tepsir-tbl]').first(); 321 if ($host.length) { 322 return String($host.attr('data-tepsir-tbl') || ''); 323 } 324 var $fn = $('a.qk-fn-link[data-tbl], a[id^="ftnt_ref"][data-tbl]').first(); 325 if ($fn.length) { 326 return String($fn.attr('data-tbl') || ''); 327 } 328 var stored = localStorage.getItem('selectedTepsirTbl'); 329 return stored ? String(stored) : ''; 330} 331 332function qkLoadTrtKuranYoluAudio() { 333 /* TRT Dinle oynatıcı Åimdilik kapalı */ 334} 335 336function qkToggleTrtDinleBox() { 337 $('#qkTrtDinleBox').hide(); 338} 339 340function qkTepsirLoadUrl(tepsirId, sureNo, ayetNo) { 341 return '/tepsir/' + tepsirId + '/' + sureNo + '-' + ayetNo + '?v=' + Date.now(); 342} 343 344function qkTepsirModalVisible() { 345 var el = document.getElementById('tepsirModal'); 346 return !!(el && el.classList.contains('show')); 347} 348 349function qkCoordsFromPlaylistItem(item) { 350 if (!item) { 351 return null; 352 } 353 if (item.sureNo != null && item.ayetNo != null) { 354 return { sure: parseInt(item.sureNo, 10), ayet: parseInt(item.ayetNo, 10) }; 355 } 356 if (item.sure != null && item.ayet != null) { 357 return { sure: parseInt(item.sure, 10), ayet: parseInt(item.ayet, 10) }; 358 } 359 var mp3 = item.mp3 || ''; 360 var m = mp3.match(/(\d{3})(\d{3})\.mp3/i); 361 if (m) { 362 return { sure: parseInt(m[1], 10), ayet: parseInt(m[2], 10) }; 363 } 364 return null; 365} 366 367function qkFindPlaylistIndex(sureNo, ayetNo) { 368 var pl = window.myPlaylist; 369 if (!pl || !pl.playlist || !pl.playlist.length) { 370 return -1; 371 } 372 sureNo = parseInt(sureNo, 10); 373 ayetNo = parseInt(ayetNo, 10); 374 for (var i = 0; i < pl.playlist.length; i++) { 375 var c = qkCoordsFromPlaylistItem(pl.playlist[i]); 376 if (c && c.sure === sureNo && c.ayet === ayetNo) { 377 return i; 378 } 379 } 380 return -1; 381} 382 383function qkTepsirSyncEnabled() { 384 var $cb = $('#qkTepsirSyncAudio'); 385 if ($cb.length) { 386 return $cb.is(':checked'); 387 } 388 return localStorage.getItem('qkTepsirSyncAudio') !== 'no'; 389} 390 391function qkTepsirUpdateNavPos(sureNo, ayetNo) { 392 var $pos = $('#qkTepsirPos'); 393 if (!$pos.length) { 394 return; 395 } 396 sureNo = parseInt(sureNo, 10); 397 ayetNo = parseInt(ayetNo, 10); 398 if (!sureNo || !ayetNo) { 399 $pos.text('â'); 400 return; 401 } 402 $pos.text(sureNo + ' · ' + ayetNo); 403 var $bar = $('#qkTepsirShareBar'); 404 if ($bar.length) { 405 $bar.attr('data-sure', sureNo).attr('data-ayet', ayetNo).attr('data-link', 'terjime/' + sureNo + '-' + ayetNo); 406 } 407 if (typeof window.qkTepsirSyncAboutLink === 'function') { 408 window.qkTepsirSyncAboutLink(); 409 } 410 var $from = $('#qkTepsirAyahFrom'); 411 var $to = $('#qkTepsirAyahTo'); 412 if ($from.length && $to.length) { 413 var f = parseInt($from.val(), 10); 414 var t = parseInt($to.val(), 10); 415 if (!f || !t || f === t) { 416 qkFillAyahRange('qkTepsirAyahFrom', 'qkTepsirAyahTo', sureNo, ayetNo); 417 } 418 } 419} 420 421function qkTepsirProgressHtml() { 422 return '<div class="progress"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width:100%">...</div></div>'; 423} 424 425function qkTepsirReloadContent(sureNo, ayetNo) { 426 sureNo = parseInt(sureNo, 10); 427 ayetNo = parseInt(ayetNo, 10); 428 if (!sureNo || !ayetNo || !qkTepsirModalVisible()) { 429 return Promise.resolve(); 430 }
431 selectedSureNo = String(sureNo); 432 selectedAyetNo = String(ayetNo); 433 qkTepsirUpdateNavPos(sureNo, ayetNo); 434 var tepsirId = qkGetSelectedTepsirId(); 435 $('#tepsirModal .izahat-box').hide(); 436 qkTepsirIzahatOpenKey = ''; 437 return qkTepsirLoadInto('#tepsirData', tepsirId, sureNo, ayetNo); 438} 439 440function qkTepsirLoadInto($target, tepsirId, sureNo, ayetNo) { 441 var $el = ($target && $target.jquery) ? $target : $($target); 442 if (!$el.length) { 443 return Promise.resolve(); 444 } 445 $el.html(qkTepsirProgressHtml()); 446 return new Promise(function (resolve) { 447 $el.load(qkTepsirLoadUrl(tepsirId, sureNo, ayetNo), function(response, status) { 448 if (status === 'error' || status === 'timeout') { 449 $el.html('<p class="tepsir-izahat text-danger uyghur">تÛÙ¾Ø³ÙØ± ÙÛÙÙÛÙÙ ÙØ¯Ù. (HTTP ' + status + ')</p>'); 450 resolve(); 451 return; 452 } 453 $el.find('.ar-fsize').each(function () { 454 this.style.fontSize = ''; 455 }); 456 if (typeof window.qkApplyTepsirSizePreview === 'function') { 457 window.qkApplyTepsirSizePreview(); 458 } 459 resolve(); 460 }); 461 }); 462} 463 464function qkTepsirSyncPlaylistQuiet(idx) { 465 idx = parseInt(idx, 10); 466 var pl = window.myPlaylist; 467 if (!pl || !pl.playlist || !pl.playlist[idx]) { 468 return false; 469 } 470 window._qkTefsirAwaitingPlayClick = true; 471 window._qkPlaylistAutoAdvance = false; 472 try { 473 localStorage.removeItem('jumpAutoPlayPending'); 474 localStorage.removeItem('_qkResumePlaylistAid'); 475 localStorage.removeItem('_qkResumePlaylistIdx'); 476 } catch (e) {} 477 if (typeof window.qkClearJumpAutoPlayFlags === 'function') { 478 window.qkClearJumpAutoPlayFlags(); 479 } 480 pl.current = idx; 481 try { 482 var jp = $('#audioPlayer').data('jPlayer'); 483 if (jp && jp.status && !jp.status.paused) { 484 $('#audioPlayer').jPlayer('pause'); 485 } 486 $('#audioPlayer').jPlayer('setMedia', pl.playlist[idx]); 487 } catch (e) {} 488 if (typeof checkPlayer === 'function') { 489 checkPlayer(); 490 } 491 return true; 492} 493 494function qkTepsirStep(delta) { 495 delta = parseInt(delta, 10); 496 if (!delta) { 497 return; 498 } 499 var sure = parseInt(selectedSureNo, 10); 500 var ayet = parseInt(selectedAyetNo, 10); 501 if (!sure || !ayet) { 502 return; 503 } 504 var idx = qkFindPlaylistIndex(sure, ayet); 505 var pl = window.myPlaylist; 506 if (idx >= 0 && pl && pl.playlist && pl.playlist.length) { 507 var nextIdx = idx + delta; 508 if (nextIdx >= 0 && nextIdx < pl.playlist.length) { 509 window._qkTepsirNavigating = true; 510 var c = qkCoordsFromPlaylistItem(pl.playlist[nextIdx]); 511 if (c) { 512 var mushafTefsirMode = $('body').hasClass('qk-diyanet-mushaf-active') 513 && typeof window.qkGetContentMode === 'function' 514 && window.qkGetContentMode() === 'tefsir'; 515 if (qkTepsirModalVisible()) { 516 qkTepsirReloadContent(c.sure, c.ayet); 517 } 518 if (mushafTefsirMode && typeof window.qkMushafOpenTefsirForAyet === 'function') { 519 window.qkMushafOpenTefsirForAyet(c.sure, c.ayet); 520 } else if (!qkTepsirModalVisible()) { 521 qkTepsirReloadContent(c.sure, c.ayet); 522 } 523 if (typeof window.qkSelectPlaylistIndexQuiet === 'function') { 524 window.qkSelectPlaylistIndexQuiet(nextIdx); 525 } else { 526 qkTepsirSyncPlaylistQuiet(nextIdx); 527 } 528 } 529 window._qkTepsirNavigating = false; 530 return; 531 } 532 } 533 var nextAyet = ayet + delta; 534 if (nextAyet < 1) { 535 return; 536 } 537 window._qkTepsirNavigating = true; 538 qkTepsirReloadContent(sure, nextAyet); 539 window._qkTepsirNavigating = false; 540} 541 542function qkTepsirSyncFromPlaylistIndex(idx) { 543 if (window._qkTepsirNavigating || !qkTepsirSyncEnabled() || !qkTepsirModalVisible()) { 544 return; 545 } 546 var pl = window.myPlaylist; 547 if (!pl || !pl.playlist || !pl.playlist[idx]) { 548 return; 549 } 550 var c = qkCoordsFromPlaylistItem(pl.playlist[idx]); 551 if (!c) { 552 return; 553 } 554 if (String(c.sure) === String(selectedSureNo) && String(c.ayet) === String(selectedAyetNo)) { 555 return; 556 } 557 qkTepsirReloadContent(c.sure, c.ayet); 558} 559 560function qkOpenTepsirModal(sureNo, ayetNo) { 561 if (!sureNo || !ayetNo) { 562 return; 563 } 564 selectedSureNo = sureNo; 565 selectedAyetNo = ayetNo; 566 qkTepsirUpdateNavPos(sureNo, ayetNo); 567 var tepsirId = qkGetSelectedTepsirId(); 568 qkTepsirLoadInto('#tepsirData', tepsirId, sureNo, ayetNo); 569 qkModalShow('tepsirModal'); 570 qkToggleTrtDinleBox(); 571 $('#tepsirModal .izahat-box').hide(); 572 qkTepsirIzahatOpenKey = ''; 573 var syncOn = localStorage.getItem('qkTepsirSyncAudio') !== 'no'; 574 $('#qkTepsirSyncAudio').prop('checked', syncOn); 575} 576 577window.qkGetSelectedTepsirId = qkGetSelectedTepsirId; 578window.qkOpenTepsirModal = qkOpenTepsirModal; 579window.qkTepsirReloadContent = qkTepsirReloadContent; 580window.qkOnPlaylistTrackChange = function (idx) { 581 qkTepsirSyncFromPlaylistIndex(idx); 582}; 583 584$(document).ready(function(){ 585 586 $(document).on('click', '#qkSureIndexBackdrop', function(e) { 587 e.preventDefault(); 588 qkCloseFlyoutPanels(); 589 }); 590
591 $(document).on('click.qkFlyoutDismiss', function(e) { 592 var $drawer = $('#qkMushafSettingsDrawer'); 593 var drawerOpen = $drawer.length && $drawer.hasClass('is-open'); 594 if (!qkIsSureIndexOpen() && !$('.qk-dt-dropdown.is-open').length && !drawerOpen) { 595 return; 596 } 597 var $t = $(e.target); 598 if ($t.closest([ 599 '#qkSureIndex', 600 '.sure-index', 601 '.nav-sure-selector', 602 '#qkSureIndexBackdrop', 603 '.qk-dt-dropdown', 604 '.qk-dt-dropdown-menu', 605 '.qk-dt-nav-btn', 606 '#qkMshSettingsToggle', 607 '#qkMshSettingsBody', 608 '.qk-mushaf-settings-drawer' 609 ].join(', ')).length) { 610 return; 611 } 612 qkCloseFlyoutPanels(); 613 }); 614 615 $(".nav-sure-selector").on('click', function(e) { 616 e.preventDefault(); 617 e.stopPropagation(); 618 if (qkIsSureIndexOpen()) { 619 qkCloseSureIndex(); 620 } else { 621 qkOpenSureIndex('sure'); 622 } 623 }); 624 625 $(".lang-list-item").click(function(){ 626 var mylang = $(this).attr("data-lang"); 627 tilSelector(mylang); 628 }); 629 630 $(document).on('click', '.tepsir-button', function(e){ 631 e.preventDefault(); 632 e.stopPropagation(); 633 var sureNo = $(this).attr('data-sure'); 634 var ayetNo = $(this).attr('data-ayet'); 635 if ($('body').hasClass('qk-diyanet-mushaf-active') && typeof window.qkMushafOpenTefsirForAyet === 'function') { 636 window.qkMushafOpenTefsirForAyet(sureNo, ayetNo); 637 return; 638 } 639 qkOpenTepsirModal(sureNo, ayetNo); 640 }); 641 642 $('#qkTepsirPrev').on('click', function(e) { 643 e.preventDefault(); 644 qkTepsirStep(-1); 645 }); 646 $('#qkTepsirNext').on('click', function(e) { 647 e.preventDefault(); 648 qkTepsirStep(1); 649 }); 650 $('#qkTepsirSyncAudio').on('change', function() { 651 localStorage.setItem('qkTepsirSyncAudio', $(this).is(':checked') ? 'yes' : 'no'); 652 }); 653 654 $(".setting-icon, .nav-item-icon:has(.setting-icon)").on('click touchend', function(e){ 655 e.preventDefault(); 656 e.stopPropagation(); 657 if ($('body').hasClass('qk-diyanet-mushaf-active') && $('#qkMushafSettingsDrawer').length) { 658 if (window.qkDiyanetMushaf && typeof window.qkDiyanetMushaf.setMushafSettingsDrawerOpen === 'function') { 659 window.qkDiyanetMushaf.setMushafSettingsDrawerOpen(true); 660 return false; 661 } 662 } 663 qkModalShow('settingModal'); 664 }); 665 666 $(".bi-search").click(function(){ 667 qkModalShow('searchModal'); 668 }); 669 670 function qkGetSavedFrameId() { 671 var fid = parseInt(localStorage.getItem('qkPrintFrameId') || '0', 10); 672 return isNaN(fid) ? 0 : fid; 673 } 674 675 function qkMarkActiveFrame(frameId) { 676 var $picker = $('#qkFramePicker'); 677 if (!$picker.length) return; 678 $picker.find('.qk-frame-opt').removeClass('active'); 679 var $match = $picker.find('.qk-frame-opt[data-frame-id="' + frameId + '"]'); 680 if ($match.length) { 681 $match.addClass('active'); 682 } else { 683 $picker.find('.qk-frame-opt').first().addClass('active'); 684 } 685 } 686 687 function qkIsDuaCapture() { 688 return qkCaptureKind === 'dua' || $('#captureData .dprint').length > 0; 689 } 690 691 function qkCaptureSetDuaUi(isDua) { 692 qkCaptureKind = isDua ? 'dua' : 'ayah'; 693 $('#qkCaptureAyahRange').toggle(!isDua); 694 $('#qkCaptureShareBar').toggle(!isDua); 695 $('#captureBtnVideo').toggle(!isDua); 696 $('#qkCaptureTefsirRow').toggle(!isDua); 697 $('#qkCaptureSourcePick').toggle(!isDua); 698 } 699 700 function qkFrameOptMeta(frameId) { 701 var $opt = (frameId > 0) 702 ? $('#qkFramePicker .qk-frame-opt[data-frame-id="' + frameId + '"]') 703 : $('#qkFramePicker .qk-frame-opt.active'); 704 if (!$opt.length) { 705 $opt = $('#qkFramePicker .qk-frame-opt').first(); 706 } 707 if (!$opt.length) { 708 return null; 709 } 710 return { 711 id: parseInt($opt.attr('data-frame-id'), 10) || 0, 712 css: $opt.attr('data-css-key') || 'qk-frame-classic', 713 bg: $opt.attr('data-bg') || '#ffffff', 714 tip: $opt.attr('data-tip') || 'css', 715 overlay: $opt.attr('data-overlay') || '', 716 pad: parseInt($opt.attr('data-pad'), 10) || 28 717 }; 718 } 719 720 function qkApplyDuaFrame(frameId) { 721 var $frame = $('#captureData .dprint').first(); 722 if (!$frame.length) { 723 return; 724 } 725 var fid = (typeof frameId === 'number' && frameId > 0) ? frameId : qkGetSavedFrameId(); 726 var meta = qkFrameOptMeta(fid); 727 if (!meta) { 728 return; 729 } 730 if (!$frame.find('.qk-print-inner').length) { 731 $frame.children().wrapAll('<div class="qk-print-inner"></div>'); 732 } 733 $frame.addClass('qk-print-frame dprint'); 734 $frame.removeClass('qk-frame-classic qk-frame-gold qk-frame-parchment qk-frame-emerald qk-frame-midnight qk-frame-img qk-frame-double qk-frame-ornate qk-frame-navy qk-frame-burgundy qk-frame-plain qk-frame-teal');
735 $frame.find('.qk-frame-overlay').remove(); 736 if (meta.tip === 'image' && meta.overlay) { 737 $frame.addClass('qk-frame-img'); 738 $frame.attr('style', '--qk-frame-pad:' + meta.pad + 'px;background:' + meta.bg + ';'); 739 $frame.prepend($('<img class="qk-frame-overlay" alt="">').attr({ src: meta.overlay, crossorigin: 'anonymous' })); 740 $frame.find('.qk-print-inner').first().attr('style', 'background:' + meta.bg + ';'); 741 } else { 742 $frame.addClass(meta.css); 743 $frame.attr('style', '--qk-frame-pad:' + meta.pad + 'px;background:' + meta.bg + ';padding:' + meta.pad + 'px;'); 744 $frame.find('.qk-print-inner').first().attr('style', ''); 745 } 746 $frame.attr('data-frame-id', meta.id); 747 qkMarkActiveFrame(meta.id); 748 qkApplyCaptureSizePreview(); 749 } 750 751 function qkOpenDuaCapture(duaTxt, terjimeTxt) { 752 selectedSureNo = 0; 753 selectedAyetNo = 0; 754 qkCaptureSetDuaUi(true); 755 var $inner = $('<div class="qk-print-inner"></div>'); 756 $inner.append($('<div class="dprint-ar ar-fsize"></div>').text(duaTxt || '')); 757 $inner.append($('<div class="dprint-txt tx-fsize"></div>').text(terjimeTxt || '')); 758 $inner.append($('<div class="web-p"></div>').text('www.qurankerim.com')); 759 var $frame = $('<div class="print-border dprint qk-print-frame"></div>').append($inner); 760 $('#captureData').empty().append($frame); 761 qkModalShow('captureModal'); 762 qkApplyDuaFrame(qkGetSavedFrameId()); 763 } 764 window.qkOpenDuaCapture = qkOpenDuaCapture; 765 766 function qkEnsurePrintFooterBrand($root) { 767 var $foot = $root.find('.print-social-footer').first(); 768 if (!$foot.length) { 769 return; 770 } 771 if (!$foot.find('img').length) { 772 var src = $('.qk-header-logo-img, .qk-tepsir-modal-logo, .qk-tepsir-modal-brandbar-logo').first().attr('src') || ''; 773 if (src) { 774 $foot.prepend($('<img class="qk-print-footer-logo" alt="Qurankerim">').attr({ src: src, crossorigin: 'anonymous' })); 775 } 776 } 777 } 778 779 function qkCaptureAyahUrl(sure, ayet, fid) { 780 var _terjimeCsv = localStorage.getItem('terjimearr') || ''; 781 if (!_terjimeCsv) { 782 _terjimeCsv = 'terjime_msalih'; 783 } 784 var url = '/resim/' + sure + '-' + ayet + '?terjime=' + encodeURIComponent(_terjimeCsv); 785 if (fid > 0) { 786 url += '&cerceve=' + fid; 787 } 788 return url; 789 } 790 791 function qkCaptureFetchHtml(url) { 792 return new Promise(function (resolve, reject) { 793 $.ajax({ url: url, dataType: 'html' }).done(function (html) { 794 resolve(html || ''); 795 }).fail(function () { 796 reject(new Error('preview')); 797 }); 798 }); 799 } 800 801 function qkCaptureBuildRangeCard(htmls, from, to) { 802 var $box = $('<div></div>').append($.parseHTML(htmls[0] || '', document, false)); 803 var $frame = $box.find('.print-border, .qk-print-frame').first(); 804 if (!$frame.length) { 805 return $box.contents(); 806 } 807 if (!htmls || htmls.length < 2) { 808 return $frame; 809 } 810 var $inner = $frame.find('.qk-print-inner').first(); 811 if (!$inner.length) { 812 return $frame; 813 } 814 var $foot = $inner.find('.print-social-footer').first(); 815 var $sure = $inner.find('.surename-p').first(); 816 var sureRaw = ($sure.text() || '').replace(/\s+/g, ' ').trim(); 817 var $stack = $('<div class="qk-capture-ayah-stack"></div>');
818 htmls.forEach(function (html, i) { 819 var $tmp = $('<div></div>').append($.parseHTML(html || '', document, false)); 820 var $src = $tmp.find('.qk-print-inner').first(); 821 var $piece = $('<div class="qk-capture-ayah-piece"></div>').attr('data-ayah', from + i); 822 $src.children().not('.surename-p, .print-social-footer, .web-p, .qk-frame-overlay').each(function () { 823 $piece.append($(this).clone()); 824 }); 825 if ($piece.children().length) { 826 $piece.attr('data-ayah-ar', qkExtractAyahArabic($piece)); 827 $stack.append($piece); 828 } 829 }); 830 $inner.children().not($foot).remove(); 831 $inner.prepend($stack); 832 if (sureRaw) { 833 var m = sureRaw.match(/^(.*?)(\d+)(.*)$/); 834 var label = m ? (m[1] + from + '-' + to + m[3]) : (from + '-' + to); 835 var $sn = $('<div class="surename-p"></div>').text(label); 836 if ($foot.length) { 837 $foot.before($sn); 838 } else { 839 $inner.append($sn); 840 } 841 } 842 if ($foot.length) { 843 $inner.append($foot); 844 } 845 return $frame; 846 } 847 848 var qkCapturePreviewGen = 0; 849 850 function qkFinishCapturePreview(done) { 851 var go = function () { 852 qkApplyCaptureSizePreview(); 853 if (typeof done === 'function') { 854 done(); 855 } 856 }; 857 if (typeof qkAttachCaptureTefsir === 'function' && !qkIsDuaCapture()) { 858 qkAttachCaptureTefsir().then(go, go); 859 return; 860 } 861 go(); 862 } 863 864 function qkLoadCapturePreview(sure, ayet, frameId, done) { 865 var fid = (typeof frameId === 'number' && frameId > 0) ? frameId : qkGetSavedFrameId(); 866 var range = qkReadAyahRange('qkCaptureAyahFrom', 'qkCaptureAyahTo', sure, ayet); 867 var gen = ++qkCapturePreviewGen; 868 var ayahs = []; 869 var a; 870 for (a = range.from; a <= range.to; a++) { 871 ayahs.push(a); 872 } 873 $('#captureData').html('<div class="text-center p-4"><div class="spinner-border text-primary"></div></div>'); 874 if (ayahs.length === 1) { 875 $('#captureData').load(qkCaptureAyahUrl(sure, ayahs[0], fid), function () { 876 if (gen !== qkCapturePreviewGen) { 877 return; 878 } 879 qkEnsurePrintFooterBrand($('#captureData')); 880 qkMarkActiveFrame(fid); 881 qkFinishCapturePreview(done); 882 }); 883 return; 884 } 885 Promise.all(ayahs.map(function (n) { 886 return qkCaptureFetchHtml(qkCaptureAyahUrl(sure, n, fid)).catch(function () { 887 return ''; 888 }); 889 })).then(function (htmls) { 890 if (gen !== qkCapturePreviewGen) { 891 return; 892 } 893 htmls = (htmls || []).filter(function (html) { 894 return html && String(html).replace(/\s+/g, ''); 895 }); 896 if (!htmls.length) { 897 throw new Error('preview'); 898 } 899 var $card = qkCaptureBuildRangeCard(htmls, range.from, range.to); 900 $('#captureData').empty().append($card); 901 qkEnsurePrintFooterBrand($('#captureData')); 902 qkMarkActiveFrame(fid); 903 qkFinishCapturePreview(done); 904 }).catch(function () { 905 if (gen !== qkCapturePreviewGen) { 906 return; 907 } 908 $('#captureData').load(qkCaptureAyahUrl(sure, range.from, fid), function () { 909 qkEnsurePrintFooterBrand($('#captureData')); 910 qkMarkActiveFrame(fid); 911 qkFinishCapturePreview(done); 912 }); 913 }); 914 } 915 window.qkLoadCapturePreview = qkLoadCapturePreview; 916 window.qkGetSavedFrameId = qkGetSavedFrameId; 917 918 $(document).on('click', '.ayet-print, button:has(.ayet-print)', function(e){ 919 e.preventDefault(); 920 e.stopPropagation(); 921 var $el = $(e.target).closest('.ayet-print'); 922 if (!$el.length) { 923 $el = $(this).find('.ayet-print').first(); 924 } 925 if (!$el.length && $(this).hasClass('ayet-print')) { 926 $el = $(this); 927 } 928 selectedSureNo = $el.attr('data-sure'); 929 selectedAyetNo = $el.attr('data-ayet'); 930 if (!selectedSureNo || !selectedAyetNo) { 931 return; 932 } 933 qkCaptureSetDuaUi(false); 934 qkModalShow('captureModal'); 935 qkFillAyahRange('qkCaptureAyahFrom', 'qkCaptureAyahTo', selectedSureNo, selectedAyetNo); 936 qkSyncCaptureShareBar(selectedSureNo, selectedAyetNo); 937 qkApplyCaptureSizePreview(); 938 qkLoadCapturePreview(selectedSureNo, selectedAyetNo); 939 }); 940 941 $(document).on('change', '#qkCaptureAyahFrom, #qkCaptureAyahTo', function () { 942 if (qkIsDuaCapture()) { 943 return; 944 } 945 var sure = parseInt(selectedSureNo, 10) || 0; 946 var range = qkReadAyahRange('qkCaptureAyahFrom', 'qkCaptureAyahTo', sure, selectedAyetNo); 947 if (sure && range.from) { 948 qkSyncCaptureShareBar(sure, range.from); 949 qkLoadCapturePreview(sure, range.from); 950 } 951 }); 952 953 $(document).on('change', 'input[name="qkCaptureSize"], input[name="qkCaptureAyahFont"], input[name="qkCaptureBodyFont"], #qkCaptureAyahColor, #qkCaptureBodyColor', function () { 954 qkApplyCaptureSizePreview(); 955 }); 956 957 $(document).on('change', 'input[name="qkTepsirSize"], input[name="qkTepsirFrame"], input[name="qkTepsirAyahFont"], input[name="qkTepsirBodyFont"], #qkTepsirAyahColor, #qkTepsirBodyColor', function () { 958 qkApplyTepsirSizePreview(); 959 if (typeof window.qkTepsirRefreshExportPreview === 'function' && $('#qkTepsirExportPreview .qk-tepsir-capture-card').length) { 960 qkApplyExportStyle($('#qkTepsirExportPreview .qk-tepsir-capture-card'), 'tepsir'); 961 } 962 }); 963 964 $(document).on('change', '#qkTepsirAyahFrom, #qkTepsirAyahTo', function () { 965 if (typeof window.qkTepsirRefreshExportPreview === 'function') { 966 window.qkTepsirRefreshExportPreview(); 967 } 968 }); 969 970 $(document).on('click', '#qkFramePicker .qk-frame-opt, #qkTepsirFramePicker .qk-frame-opt', function(e) { 971 e.preventDefault(); 972 var fid = parseInt($(this).attr('data-frame-id'), 10); 973 if (isNaN(fid) || fid < 1) return; 974 localStorage.setItem('qkPrintFrameId', String(fid)); 975 $('.qk-frame-opt').removeClass('active'); 976 $('.qk-frame-opt[data-frame-id="' + fid + '"]').addClass('active'); 977 if (typeof qkRememberExportLock === 'function') { 978 qkRememberExportLock(); 979 } 980 if ($(this).closest('#qkTepsirFramePicker').length) { 981 qkApplyTepsirSizePreview(); 982 return; 983 } 984 if (qkIsDuaCapture()) { 985 qkApplyDuaFrame(fid); 986 return; 987 } 988 if (selectedSureNo) { 989 qkLoadCapturePreview(selectedSureNo, selectedAyetNo, fid); 990 } 991 }); 992 993 $(document).on('click', '.dua-print', function (e) { 994 e.preventDefault(); 995 e.stopPropagation(); 996 qkOpenDuaCapture($(this).attr('data-dua'), $(this).attr('data-terjime')); 997 }); 998 999 function qkTepsirSyncAboutLink() { 1000 var $wrap = $('#qkTepsirAboutWrap'); 1001 var $link = $('#qkTepsirAboutLink'); 1002 if (!$wrap.length) { 1003 return; 1004 } 1005 $wrap.attr('hidden', 'hidden'); 1006 if ($link.length) { 1007 $link.attr('href', '#').text(''); 1008 } 1009 } 1010 window.qkTepsirSyncAboutLink = qkTepsirSyncAboutLink; 1011 1012 var storedTepsir = localStorage.getItem('selectedTepsirTbl'); 1013 if (storedTepsir) { 1014 if ($('#tepsirSelector option[value="' + storedTepsir.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"]').length) { 1015 $('#tepsirSelector').val(storedTepsir); 1016 } else { 1017 localStorage.removeItem('selectedTepsirTbl'); 1018 localStorage.removeItem('selectedTepsir'); 1019 } 1020 } 1021 if (!$('#tepsirSelector').val() || $('#tepsirSelector').val() === 'tepsir_tehfizulquran') { 1022 var $tf = $('#tepsirSelector option[value="tepsir_tefhim"]'); 1023 if ($tf.length) { 1024 $('#tepsirSelector').val('tepsir_tefhim'); 1025 localStorage.setItem('selectedTepsirTbl', 'tepsir_tefhim');
1026 localStorage.setItem('selectedTepsir', String($tf.attr('data-tepsir') || $tf.data('tepsir') || '')); 1027 } 1028 } 1029 qkToggleTrtDinleBox(); 1030 qkTepsirSyncAboutLink(); 1031 1032 function qkSyncTepsirPicker() { 1033 var v = $('#tepsirSelector').val(); 1034 var $rows = $('#qkTepsirPicker .qk-tepsir-pick'); 1035 $rows.each(function () { 1036 var on = $(this).attr('data-value') === v; 1037 $(this).toggleClass('is-selected', on).attr('aria-selected', on ? 'true' : 'false'); 1038 }); 1039 var $on = $rows.filter('.is-selected').first(); 1040 if ($on.length && $on[0].scrollIntoView) { 1041 $on[0].scrollIntoView({ block: 'nearest' }); 1042 } 1043 } 1044 1045 function qkMountTepsirPicker() { 1046 var $sel = $('#tepsirSelector'); 1047 if (!$sel.length) { 1048 return; 1049 } 1050 if ($('#qkTepsirPicker').length) { 1051 qkSyncTepsirPicker(); 1052 return; 1053 } 1054 var $list = $('<div id="qkTepsirPicker" class="qk-tepsir-picker" role="listbox"></div>'); 1055 $sel.find('option').each(function (i) { 1056 var $o = $(this); 1057 var $b = $('<button type="button" class="qk-tepsir-pick" role="option"></button>'); 1058 $b.attr('data-value', $o.val()); 1059 $b.attr('data-tone', String(i % 6)); 1060 $b.attr('dir', 'auto'); 1061 $b.text($o.text()); 1062 $list.append($b); 1063 }); 1064 $sel.addClass('qk-tepsir-select-native').after($list); 1065 qkSyncTepsirPicker(); 1066 } 1067 1068 qkMountTepsirPicker(); 1069 $(document).on('click', '.qk-tepsir-pick', function (e) { 1070 e.preventDefault(); 1071 var v = $(this).attr('data-value'); 1072 if ($('#tepsirSelector').val() === v) { 1073 return; 1074 } 1075 $('#tepsirSelector').val(v).trigger('change'); 1076 }); 1077 1078 $("#tepsirSelector").change(function(){ 1079 var $opt = $('option:selected', this); 1080 var tepsir = $opt.attr('data-tepsir') || $opt.data('tepsir'); 1081 var tepsirTbl = $opt.val(); 1082 localStorage.setItem('selectedTepsir', tepsir); 1083 localStorage.setItem('selectedTepsirTbl', tepsirTbl); 1084 qkToggleTrtDinleBox(); 1085 qkTepsirSyncAboutLink(); 1086 qkSyncTepsirPicker(); 1087 1088 if (selectedSureNo && selectedAyetNo) { 1089 setTimeout(function() { 1090 qkTepsirLoadInto('#tepsirData', tepsir, selectedSureNo, selectedAyetNo).then(function () { 1091 if (typeof window.qkTepsirRefreshExportPreview === 'function') { 1092 window.qkTepsirRefreshExportPreview(); 1093 } 1094 }); 1095 }, 300); 1096 } 1097 }); 1098 1099 function qkTepsirCircledDigit(n) { 1100 n = parseInt(n, 10); 1101 return n > 0 ? String(n) : ''; 1102 } 1103 1104 function qkTepsirDisplayNoteId(id) { 1105 var n = parseInt(id, 10); 1106 if (!n || isNaN(n)) { 1107 return '?'; 1108 } 1109 if (n >= 1000) { 1110 var local = n % 1000; 1111 if (local > 0) { 1112 return qkTepsirCircledDigit(local); 1113 } 1114 } 1115 return qkTepsirCircledDigit(n); 1116 } 1117 1118 function qkTepsirNoteIdFromEl($el) { 1119 var base = String($el.attr('data-fn-base') || '').trim(); 1120 if (/^\d+$/.test(base)) { 1121 return base; 1122 } 1123 var ids = String($el.attr('data-fn-ids') || '').trim(); 1124 if (ids) { 1125 var first = ids.split(',')[0].trim(); 1126 if (/^\d+$/.test(first)) { 1127 return first; 1128 } 1129 } 1130 var rawId = String($el.attr('id') || '').trim(); 1131 if (!rawId) { 1132 return ''; 1133 } 1134 var izahatId = rawId.replace(/^ftnt_ref/i, ''); 1135 if (/^\d+$/.test(izahatId)) { 1136 return izahatId; 1137 } 1138 var partMatch = izahatId.match(/^(\d+)_([ab])$/i); 1139 return partMatch ? partMatch[1] : ''; 1140 } 1141 1142 function qkTepsirPartFromEl($el) { 1143 var part = String($el.attr('data-fn-part') || '').trim().toLowerCase(); 1144 if (part === 'a' || part === 'b') { 1145 return part; 1146 } 1147 var rawId = String($el.attr('id') || '').trim().replace(/^ftnt_ref/i, ''); 1148 var m = rawId.match(/^\d+_([ab])$/i); 1149 return m ? m[1].toLowerCase() : ''; 1150 } 1151 1152 function qkUnicodeCircledToPlain(label) { 1153 return String(label || '').replace(/[\u2460-\u2473]/g, function (ch) { 1154 return String(ch.charCodeAt(0) - 0x245f); 1155 }).replace(/\u24ea/g, '0'); 1156 } 1157 1158 function qkReadingLocaleDefaults() { 1159 return window.qkReadingLocale || { 1160 dir: 'rtl', 1161 lang: 'ug', 1162 class: 'qk-reading-locale tepsir-izahat uyghur' 1163 }; 1164 } 1165 1166 function qkReadingLocaleFromEl($el) { 1167 var loc = qkReadingLocaleDefaults(); 1168 var $host = $el.closest('[lang][dir]').first(); 1169 if ($host.length) { 1170 var cls = String($host.attr('class') || '').trim(); 1171 if (cls.indexOf('qk-reading-locale') === -1) { 1172 cls = (loc.class + ' ' + cls).trim(); 1173 } 1174 return { 1175 dir: $host.attr('dir') || loc.dir, 1176 lang: $host.attr('lang') || loc.lang, 1177 class: cls || loc.class 1178 }; 1179 } 1180 return loc; 1181 } 1182 1183 function qkBuildFnBadgeHtml(label) { 1184 label = qkNormalizeFnBadgeLabel(label || ''); 1185 if (!label) { 1186 return ''; 1187 } 1188 return '<span class="qk-izahat-fn-badge" aria-hidden="true"><span class="qk-fn-circled-inner">' 1189 + $('<div>').text(label).html() + '</span></span>'; 1190 } 1191 1192 function qkNormalizeFnBadgeLabel(label) { 1193 label = String(label || '').trim(); 1194 if (!label) { 1195 return ''; 1196 } 1197 if (/^[\u2460-\u2473\u24ea]/.test(label)) { 1198 return qkUnicodeCircledToPlain(label); 1199 } 1200 var range = label.match(/^\[(\d+)\s*[â\-]\s*(\d+)\]$/); 1201 if (range) { 1202 return qkTepsirCircledDigit(range[1]) + '\u2013' + qkTepsirCircledDigit(range[2]); 1203 } 1204 var single = label.match(/^\[(\d+)\]$/); 1205 if (single) { 1206 return qkTepsirCircledDigit(single[1]); 1207 } 1208 if (/^\d+$/.test(label) && label.length <= 3) { 1209 return qkTepsirCircledDigit(label); 1210 } 1211 var brace = label.match(/^\{(\d+)\}$/); 1212 if (brace) { 1213 return qkTepsirCircledDigit(brace[1]); 1214 } 1215 return label; 1216 } 1217 1218 function qkResolveIzahatNoteLabel(noteLabel, izahatId) { 1219 noteLabel = qkNormalizeFnBadgeLabel(noteLabel || ''); 1220 if (noteLabel) { 1221 return noteLabel; 1222 } 1223 if (izahatId) { 1224 return qkTepsirDisplayNoteId(izahatId); 1225 } 1226 return ''; 1227 } 1228 1229 function qkApplyIzahatBadgeLayout(html, noteLabel, locale) { 1230 html = String(html || '').trim(); 1231 locale = locale || qkReadingLocaleDefaults(); 1232 noteLabel = qkNormalizeFnBadgeLabel(noteLabel || ''); 1233 if (!html || qkIzahatHtmlIsEmpty(html)) { 1234 return html; 1235 } 1236 var $root = $('<div>').html(html); 1237 $root.find('script').remove();
1238 var $line = $root.find('.izahat-fn-line').first(); 1239 var $badge = $root.find('.qk-izahat-fn-badge').first(); 1240 if (!$line.length) { 1241 var inner = qkStripIzahatInnerHtml(html); 1242 if (!noteLabel) { 1243 return html; 1244 } 1245 var bodyClass = 'izahat-fn-body ' + (locale.class || 'qk-reading-locale tepsir-izahat uyghur'); 1246 return '<div class="' + bodyClass + '" lang="' + (locale.lang || 'ug') + '" dir="' + (locale.dir || 'rtl') + '">' + 1247 '<p class="izahat-fn-line">' + 1248 qkBuildFnBadgeHtml(noteLabel) + 1249 '<span class="izahat-fn-text">' + inner + '</span>' + 1250 '</p></div>'; 1251 } 1252 if ($badge.length && noteLabel) { 1253 $badge.html('<span class="qk-fn-circled-inner">' + $('<div>').text(noteLabel).html() + '</span>'); 1254 } else if (!$badge.length && noteLabel) { 1255 $line.prepend($(qkBuildFnBadgeHtml(noteLabel))); 1256 } 1257 return $root.html(); 1258 } 1259 1260 function qkStripIzahatInnerHtml(html) { 1261 html = String(html || '').trim(); 1262 if (!html) { 1263 return ''; 1264 } 1265 var $root = $('<div>').html(html); 1266 $root.find('script').remove(); 1267 var $ug = $root.find('.tepsir-izahat, .qk-reading-locale').first(); 1268 if ($ug.length) { 1269 $root = $('<div>').html($ug.html()); 1270 } 1271 var $p = $root.find('p').first(); 1272 if ($p.length) { 1273 return $p.html(); 1274 } 1275 return $root.html(); 1276 } 1277 1278 function qkFootnoteClickLabel($el, izahatId) { 1279 var $anchor = $el.is('a') ? $el : $el.closest('a.qk-fn-link, a[id^="ftnt_ref"]'); 1280 if ($anchor.length) { 1281 $el = $anchor; 1282 } 1283 var dataLabel = String($el.attr('data-fn-label') || '').trim(); 1284 if (dataLabel) { 1285 return qkNormalizeFnBadgeLabel(dataLabel); 1286 } 1287 var $inner = $el.find('.qk-fn-circled-inner').first(); 1288 var text = ($inner.length ? $inner.text() : $el.text()) || ''; 1289 text = String(text).replace(/\s+/g, '').trim(); 1290 if (/^[\u2460-\u2473\u24ea]([\u2013-][\u2460-\u2473\u24ea])?$/.test(text)) { 1291 return qkUnicodeCircledToPlain(text); 1292 } 1293 if (/^\[\d+([â\-]\d+)?\]$/.test(text)) { 1294 var m = text.match(/\[(\d+)/); 1295 if (m) { 1296 return qkTepsirCircledDigit(m[1]); 1297 } 1298 return text; 1299 } 1300 if (/^\d+$/.test(text) && text.length <= 3) { 1301 return qkTepsirCircledDigit(text); 1302 } 1303 return qkTepsirDisplayNoteId(izahatId); 1304 } 1305 1306 function qkUseMushafIzahatPanel() { 1307 return $('body').hasClass('qk-diyanet-mushaf-active') && $('#qkMushafIzahatBox').length > 0; 1308 } 1309 1310 function qkParseIzahatPageHtml(html) { 1311 var $wrap = $('<div>').html(String(html || '')); 1312 var $inner = $wrap.find('.ayet-list-holder').first(); 1313 if ($inner.length) { 1314 return $inner.html(); 1315 } 1316 return String(html || ''); 1317 } 1318 1319 function qkIzahatHtmlIsEmpty(html) { 1320 if (/class="text-muted"/.test(html)) { 1321 return true; 1322 } 1323 var plain = String(html || '').replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); 1324 return plain === '' || plain === 'â' || plain === '-'; 1325 } 1326 1327 function qkLoadTepsirIzahatHtml(html, noteLabel, locale, izahatId) { 1328 html = String(html || '').replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, ''); 1329 var isEmpty = qkIzahatHtmlIsEmpty(html); 1330 locale = locale || qkReadingLocaleDefaults(); 1331 noteLabel = qkResolveIzahatNoteLabel(noteLabel, izahatId); 1332 if (!isEmpty) { 1333 html = qkApplyIzahatBadgeLayout(html, noteLabel, locale); 1334 } 1335 if (qkUseMushafIzahatPanel()) { 1336 var $box = $('#qkMushafIzahatBox .qk-mushaf-izahat-content'); 1337 $box.attr('dir', locale.dir || 'rtl').attr('lang', locale.lang || 'ug'); 1338 $box.html(html); 1339 $('#qkMushafIzahatBox').stop(true, true).slideDown(180); 1340 return; 1341 } 1342 var $panel = $('#tepsirModal .izahat-box'); 1343 $('#tepsirModal .izahat-box-content').html(html); 1344 if ($panel.is(':visible')) { 1345 $panel.show(); 1346 } else { 1347 $panel.stop(true, true).slideDown(200); 1348 } 1349 } 1350 1351 function qkTepsirIzahatUsesFileScope(tbl) { 1352 return tbl === 'tepsir_tefhim' || tbl === 'tepsir_jewherliri'; 1353 } 1354 1355 function qkBuildTepsirIzahatUrl(izahatTbl, fileId, izahatId, fnPart) { 1356 if (fileId && qkTepsirIzahatUsesFileScope(izahatTbl)) { 1357 var scopedUrl = '/tpizahat/jewher/' + encodeURIComponent(fileId) + '/' + encodeURIComponent(izahatId); 1358 var qs = []; 1359 if (izahatTbl === 'tepsir_tefhim') { 1360 qs.push('tbl=tepsir_tefhim'); 1361 } 1362 if (fnPart) { 1363 qs.push('part=' + encodeURIComponent(fnPart)); 1364 } 1365 if (qs.length) { 1366 scopedUrl += '?' + qs.join('&'); 1367 } 1368 return scopedUrl; 1369 } 1370 if (izahatTbl) { 1371 return '/tpizahat/' + encodeURIComponent(izahatTbl) + '/' + encodeURIComponent(izahatId); 1372 } 1373 return ''; 1374 } 1375 1376 function qkLoadTepsirIzahat($el) { 1377 var $target = $el;
1378 if (!$target.is('a.qk-fn-link, a[id^="ftnt_ref"], a[data-fn-part], span[id]')) { 1379 $target = $el.closest('a.qk-fn-link, a[id^="ftnt_ref"], a[data-fn-part], span[id]'); 1380 } 1381 if (!$target.length) { 1382 return; 1383 } 1384 var izahatId = qkTepsirNoteIdFromEl($target); 1385 if (!izahatId) { 1386 return; 1387 } 1388 var fnPart = qkTepsirPartFromEl($target); 1389 var noteLabel = qkFootnoteClickLabel($target, izahatId); 1390 var $scope = $target.closest('.myusuf'); 1391 var izahatTbl = $target.attr('data-tbl') || $scope.attr('data-tepsir-tbl') || ''; 1392 var fileId = $scope.attr('data-file-id') || $target.attr('data-file-id') || ''; 1393 if (!izahatTbl) { 1394 izahatTbl = qkGetSelectedTepsirTbl(); 1395 } 1396 if (!izahatTbl) { 1397 return; 1398 } 1399 var openKey = izahatTbl + ':' + (fileId || '') + ':' + izahatId + ':' + (fnPart || ''); 1400 if (openKey === qkTepsirIzahatOpenKey && $('#tepsirModal .izahat-box').is(':visible')) { 1401 return; 1402 } 1403 qkTepsirIzahatOpenKey = openKey; 1404 var url = qkBuildTepsirIzahatUrl(izahatTbl, fileId, izahatId, fnPart); 1405 if (!url) { 1406 return; 1407 } 1408 var locale = qkReadingLocaleFromEl($target); 1409 if (qkTepsirIzahatXhr && qkTepsirIzahatXhr.abort) { 1410 qkTepsirIzahatXhr.abort(); 1411 } 1412 qkTepsirIzahatXhr = $.get(url).done(function(html) { 1413 qkLoadTepsirIzahatHtml(html, noteLabel, locale, izahatId); 1414 }).fail(function() { 1415 qkLoadTepsirIzahatHtml('<p class="text-muted">â</p>', '', locale, ''); 1416 }).always(function() { 1417 qkTepsirIzahatXhr = null; 1418 }); 1419 } 1420 1421 $(document).on('click', '#tepsirData .tepsir-izahat span[id], #tepsirData .tepsir-izahat a[id^="ftnt_ref"], #tepsirData .tepsir-izahat a.qk-fn-link, #tepsirData .tepsir-izahat a[data-fn-part], #tepsirData .tepsir-izahat .qk-fn-circled-inner, #tepsirData .tepsiri span[id], #tepsirData .tepsiri a[id^="ftnt_ref"], #tepsirData .tepsiri a.qk-fn-link, #tepsirData .tepsiri a[data-fn-part], #tepsirData .tepsiri .qk-fn-circled-inner, #tepsirData .terjimisi span[id], #tepsirData .terjimisi a[id^="ftnt_ref"], #tepsirData .terjimisi a.qk-fn-link, #tepsirData .terjimisi a[data-fn-part], #tepsirData .terjimisi .qk-fn-circled-inner, #tepsirModal .izahat-box-content a.qk-fn-link, #tepsirModal .izahat-box-content a[id^="ftnt_ref"], #tepsirModal .izahat-box-content a[data-fn-part], #tepsirModal .izahat-box-content .qk-fn-circled-inner, .qk-tefsir-commentary a.qk-fn-link, .qk-tefsir-commentary a[id^="ftnt_ref"], .qk-tefsir-commentary a[data-fn-part], .qk-tefsir-commentary .qk-fn-circled-inner, .qk-tefsir-document a.qk-fn-link, .qk-tefsir-document a[id^="ftnt_ref"], .qk-tefsir-document a[data-fn-part], .qk-tefsir-document .qk-fn-circled-inner', function(e) { 1422 e.preventDefault(); 1423 e.stopPropagation(); 1424 qkLoadTepsirIzahat($(this)); 1425 }); 1426 1427 $(document).on('click', '.qk-tefsir-meal-box a.qk-meal-fn-link, .qk-tefsir-document a.qk-meal-fn-link', function(e) { 1428 e.preventDefault(); 1429 var url = $(this).attr('href'); 1430 if (!url) { 1431 return; 1432 } 1433 var $link = $(this); 1434 var noteLabel = $link.text(); 1435 var fidMatch = String(url || '').match(/[?&]fid=(\d+)/i); 1436 var fid = fidMatch ? fidMatch[1] : ''; 1437 if (!noteLabel && fid) { 1438 noteLabel = fid; 1439 } 1440 var locale = qkReadingLocaleFromEl($link); 1441 $.get(url).done(function(resp) { 1442 qkLoadTepsirIzahatHtml(qkParseIzahatPageHtml(resp), noteLabel, locale, fid); 1443 }).fail(function() { 1444 qkLoadTepsirIzahatHtml('<p class="text-muted">â</p>', '', locale, ''); 1445 }); 1446 }); 1447 1448 $(document).on('click', '.close-izahat, .qk-mushaf-izahat-close', function(e) { 1449 e.preventDefault(); 1450 e.stopPropagation(); 1451 qkTepsirIzahatOpenKey = ''; 1452 if ($('#qkMushafIzahatBox').is(':visible')) { 1453 $('#qkMushafIzahatBox').slideUp(180); 1454 } 1455 $('#tepsirModal .izahat-box').stop(true, true).slideUp(180); 1456 }); 1457 1458 $("#tepsirModal").on("hidden.bs.modal", function () { 1459 var trtAudio = document.getElementById('qkTrtDinleAudio'); 1460 if (trtAudio) { 1461 try { trtAudio.pause(); } catch (e) {} 1462 } 1463 $("#tepsirData").empty(); 1464 $('#tepsirModal .izahat-box').hide(); 1465 qkTepsirIzahatOpenKey = ''; 1466 }); 1467 1468 qkInitTepsirFloatingModal(); 1469}); 1470 1471function qkInitTepsirFloatingModal() { 1472 var $modal = $('#tepsirModal'); 1473 if (!$modal.length) { 1474 return; 1475 }
1476 var $dialog = $modal.find('.modal-dialog').first(); 1477 var geomKey = 'qkTepsirModalGeom'; 1478 var defaults = { w: 850, h: Math.min(Math.round(window.innerHeight * 0.82), 720) }; 1479 1480 function clamp(n, min, max) { 1481 return Math.max(min, Math.min(max, n)); 1482 } 1483 1484 function readGeom() { 1485 try { 1486 var raw = localStorage.getItem(geomKey); 1487 if (!raw) { 1488 return null; 1489 } 1490 var g = JSON.parse(raw); 1491 if (!g || typeof g.w !== 'number' || typeof g.h !== 'number') { 1492 return null; 1493 } 1494 return g; 1495 } catch (e) { 1496 return null; 1497 } 1498 } 1499 1500 function saveGeom(g) { 1501 try { 1502 localStorage.setItem(geomKey, JSON.stringify(g)); 1503 } catch (e) {} 1504 } 1505 1506 function centerDialog(w, h) { 1507 var left = Math.max(8, Math.round((window.innerWidth - w) / 2)); 1508 var top = Math.max(8, Math.round((window.innerHeight - h) / 2)); 1509 return { left: left, top: top, w: w, h: h }; 1510 } 1511 1512 function applyGeom(g) { 1513 var w = clamp(g.w, 360, window.innerWidth - 16); 1514 var h = clamp(g.h, 280, window.innerHeight - 16); 1515 var left = clamp(g.left, 8, window.innerWidth - w - 8); 1516 var top = clamp(g.top, 8, window.innerHeight - h - 8); 1517 $dialog.css({ 1518 left: left + 'px', 1519 top: top + 'px', 1520 width: w + 'px', 1521 height: h + 'px', 1522 '--qk-tepsir-w': w + 'px', 1523 '--qk-tepsir-h': h + 'px' 1524 }); 1525 return { left: left, top: top, w: w, h: h }; 1526 } 1527 1528 function currentGeom() { 1529 var rect = $dialog[0].getBoundingClientRect(); 1530 return { 1531 left: Math.round(rect.left), 1532 top: Math.round(rect.top), 1533 w: Math.round(rect.width), 1534 h: Math.round(rect.height) 1535 }; 1536 } 1537 1538 function resetSize() { 1539 var g = centerDialog(defaults.w, defaults.h); 1540 applyGeom(g); 1541 saveGeom(g); 1542 } 1543 1544 function zoomBy(delta) { 1545 var g = currentGeom(); 1546 g.w = clamp(g.w + delta * 48, 360, window.innerWidth - 16); 1547 g.h = clamp(g.h + delta * 36, 280, window.innerHeight - 16); 1548 g = applyGeom(g); 1549 saveGeom(g); 1550 } 1551 1552 $modal.on('shown.bs.modal', function () { 1553 $modal.addClass('qk-tepsir-modal-float'); 1554 var stored = readGeom(); 1555 if (stored && typeof stored.left === 'number' && typeof stored.top === 'number') { 1556 applyGeom(stored); 1557 } else { 1558 var g = centerDialog(defaults.w, defaults.h); 1559 applyGeom(g); 1560 saveGeom(g); 1561 } 1562 }); 1563 1564 $modal.find('.qk-tepsir-zoom-in').on('click', function (e) { 1565 e.preventDefault(); 1566 e.stopPropagation(); 1567 zoomBy(1); 1568 }); 1569 $modal.find('.qk-tepsir-zoom-out').on('click', function (e) { 1570 e.preventDefault(); 1571 e.stopPropagation(); 1572 zoomBy(-1); 1573 }); 1574 $modal.find('.qk-tepsir-reset-size').on('click', function (e) { 1575 e.preventDefault(); 1576 e.stopPropagation(); 1577 resetSize(); 1578 }); 1579 $modal.find('#qkTepsirSaveImg').on('click', function (e) { 1580 e.preventDefault(); 1581 e.stopPropagation(); 1582 var $panel = $('#qkTepsirExportPanel'); 1583 if ($panel.attr('hidden') != null) { 1584 $panel.removeAttr('hidden'); 1585 qkFillAyahRange('qkTepsirAyahFrom', 'qkTepsirAyahTo', selectedSureNo, selectedAyetNo); 1586 if (typeof window.qkTepsirRefreshExportPreview === 'function') { 1587 window.qkTepsirRefreshExportPreview(); 1588 } 1589 } else { 1590 $panel.attr('hidden', 'hidden'); 1591 if (typeof window.qkTepsirHideExportPreview === 'function') { 1592 window.qkTepsirHideExportPreview(); 1593 } 1594 } 1595 qkApplyTepsirSizePreview(); 1596 }); 1597 $modal.find('#qkTepsirPlayAyah').on('click', function (e) { 1598 e.preventDefault(); 1599 e.stopPropagation(); 1600 qkTepsirPlayCurrentAyah(); 1601 }); 1602 $modal.find('#qkTepsirExportJpg').on('click', function (e) { 1603 e.preventDefault(); 1604 e.stopPropagation(); 1605 qkTepsirSaveAsImage(document.getElementById('qkTepsirSaveImg'), { video: false }); 1606 }); 1607 $modal.find('#qkTepsirExportMp4').on('click', function (e) { 1608 e.preventDefault(); 1609 e.stopPropagation(); 1610 qkTepsirSaveAsImage(document.getElementById('qkTepsirSaveImg'), { video: true }); 1611 }); 1612 1613 var drag = { active: false, startX: 0, startY: 0, startLeft: 0, startTop: 0 }; 1614 var resize = { active: false, startX: 0, startY: 0, startW: 0, startH: 0, startLeft: 0, startTop: 0 }; 1615 1616 function isDragExcluded(target) { 1617 return $(target).closest('button, select, input, textarea, a, label, .qk-tepsir-modal-tools, .btn-close, .qk-tepsir-export-panel, .qk-tepsir-share-bar').length > 0; 1618 } 1619 1620 $modal.on('mousedown touchstart', '.qk-tepsir-modal-header', function (e) { 1621 if (isDragExcluded(e.target)) { 1622 return; 1623 } 1624 var ev = e.type === 'touchstart' ? (e.originalEvent.touches[0] || e) : e; 1625 drag.active = true; 1626 $modal.addClass('qk-tepsir-modal-dragging'); 1627 var g = currentGeom(); 1628 drag.startX = ev.clientX; 1629 drag.startY = ev.clientY; 1630 drag.startLeft = g.left; 1631 drag.startTop = g.top; 1632 e.preventDefault(); 1633 }); 1634 1635 $modal.on('mousedown touchstart', '.qk-tepsir-resize-handle', function (e) { 1636 var ev = e.type === 'touchstart' ? (e.originalEvent.touches[0] || e) : e; 1637 resize.active = true; 1638 $modal.addClass('qk-tepsir-modal-resizing'); 1639 var g = currentGeom(); 1640 resize.startX = ev.clientX; 1641 resize.startY = ev.clientY; 1642 resize.startW = g.w; 1643 resize.startH = g.h; 1644 resize.startLeft = g.left; 1645 resize.startTop = g.top; 1646 e.preventDefault(); 1647 e.stopPropagation(); 1648 }); 1649 1650 function onPointerMove(clientX, clientY) { 1651 if (drag.active) {
1652 var left = drag.startLeft + (clientX - drag.startX); 1653 var top = drag.startTop + (clientY - drag.startY); 1654 applyGeom({ left: left, top: top, w: currentGeom().w, h: currentGeom().h }); 1655 } else if (resize.active) { 1656 var dx = resize.startX - clientX; 1657 var dy = clientY - resize.startY; 1658 var w = clamp(resize.startW + dx, 360, window.innerWidth - 16); 1659 var h = clamp(resize.startH + dy, 280, window.innerHeight - 16); 1660 var left = resize.startLeft - (w - resize.startW); 1661 applyGeom({ left: left, top: resize.startTop, w: w, h: h }); 1662 } 1663 } 1664 1665 function endPointer() { 1666 if (drag.active || resize.active) { 1667 saveGeom(currentGeom()); 1668 } 1669 drag.active = false; 1670 resize.active = false; 1671 $modal.removeClass('qk-tepsir-modal-dragging qk-tepsir-modal-resizing'); 1672 } 1673 1674 $(document).on('mousemove.qkTepsirFloat touchmove.qkTepsirFloat', function (e) { 1675 if (!drag.active && !resize.active) { 1676 return; 1677 } 1678 var ev = e.type === 'touchmove' ? (e.originalEvent.touches[0] || e) : e; 1679 onPointerMove(ev.clientX, ev.clientY); 1680 e.preventDefault(); 1681 }); 1682 1683 $(document).on('mouseup.qkTepsirFloat touchend.qkTepsirFloat touchcancel.qkTepsirFloat', endPointer); 1684 1685 $(window).on('resize.qkTepsirFloat', function () { 1686 if (!$modal.hasClass('show')) { 1687 return; 1688 } 1689 var g = applyGeom(currentGeom()); 1690 saveGeom(g); 1691 }); 1692} 1693
1694function qkTepsirSureName(sureNo) { 1695 sureNo = String(parseInt(sureNo, 10) || 0); 1696 if (!sureNo) { 1697 return ''; 1698 } 1699 if (window.qkSureNames && window.qkSureNames[sureNo]) { 1700 return String(window.qkSureNames[sureNo]); 1701 } 1702 var found = ''; 1703 $('#qkSureIndex .sure-index-holder li a').each(function () { 1704 var n = $(this).find('span').first().text().trim(); 1705 if (n === sureNo) { 1706 found = $(this).clone().children().remove().end().text().trim(); 1707 return false; 1708 } 1709 }); 1710 return found; 1711} 1712 1713function qkTepsirPlayCurrentAyah() { 1714 var sure = parseInt(selectedSureNo, 10) || 0; 1715 var ayet = parseInt(selectedAyetNo, 10) || 0; 1716 var idx = qkFindPlaylistIndex(sure, ayet); 1717 if (idx < 0) { 1718 return false; 1719 } 1720 if (typeof window.qkPlayByIndex === 'function') { 1721 return window.qkPlayByIndex(idx); 1722 } 1723 return false; 1724} 1725 1726var QK_AYAH_COUNTS = [0, 7, 286, 200, 176, 120, 165, 206, 75, 129, 109, 123, 111, 43, 52, 99, 128, 111, 110, 98, 135, 112, 78, 118, 64, 77, 227, 93, 88, 69, 60, 34, 30, 73, 54, 45, 83, 182, 88, 75, 85, 54, 53, 89, 59, 37, 35, 38, 29, 18, 45, 60, 49, 62, 55, 78, 96, 29, 22, 24, 13, 14, 11, 11, 18, 12, 12, 30, 52, 52, 44, 28, 28, 20, 56, 40, 31, 50, 40, 46, 42, 29, 19, 36, 25, 22, 17, 19, 26, 30, 20, 15, 21, 11, 8, 8, 19, 5, 8, 8, 11, 11, 8, 3, 9, 5, 4, 7, 3, 6, 3, 5, 4, 5, 6]; 1727var QK_VIDEO_AYAH_MAX = 20; 1728 1729function qkSureAyahCount(sure) { 1730 sure = parseInt(sure, 10) || 0; 1731 return QK_AYAH_COUNTS[sure] || 286; 1732} 1733 1734function qkPad3(n) { 1735 return ('000' + (parseInt(n, 10) || 0)).slice(-3); 1736} 1737 1738function qkFillAyahRange(fromId, toId, sure, ayet) { 1739 var max = qkSureAyahCount(sure); 1740 ayet = parseInt(ayet, 10) || 1; 1741 if (ayet < 1) { 1742 ayet = 1; 1743 } 1744 if (ayet > max) { 1745 ayet = max; 1746 } 1747 $('#' + fromId + ', #' + toId).attr('max', max).attr('min', 1); 1748 $('#' + fromId).val(ayet); 1749 $('#' + toId).val(ayet); 1750} 1751 1752function qkReadAyahRange(fromId, toId, sure, fallback) { 1753 var max = qkSureAyahCount(sure); 1754 fallback = parseInt(fallback, 10) || 1; 1755 var from = parseInt($('#' + fromId).val(), 10) || fallback; 1756 var to = parseInt($('#' + toId).val(), 10) || fallback; 1757 if (from > to) { 1758 var tmp = from; 1759 from = to; 1760 to = tmp; 1761 } 1762 if (from < 1) { 1763 from = 1; 1764 } 1765 if (to > max) { 1766 to = max; 1767 } 1768 if (to - from + 1 > QK_VIDEO_AYAH_MAX) { 1769 to = from + QK_VIDEO_AYAH_MAX - 1; 1770 if (to > max) { 1771 to = max; 1772 from = Math.max(1, to - QK_VIDEO_AYAH_MAX + 1); 1773 } 1774 } 1775 return { from: from, to: to, max: max }; 1776} 1777 1778function qkAyahAudioUrl(sure, ayet) { 1779 sure = parseInt(sure, 10) || 0; 1780 ayet = parseInt(ayet, 10) || 0; 1781 var idx = qkFindPlaylistIndex(sure, ayet); 1782 if (idx >= 0 && window.myPlaylist && window.myPlaylist.playlist && window.myPlaylist.playlist[idx]) { 1783 var hit = window.myPlaylist.playlist[idx].mp3 || window.myPlaylist.playlist[idx].m4a || ''; 1784 if (hit) { 1785 return hit; 1786 } 1787 } 1788 var sample = ''; 1789 if (window.myPlaylist && window.myPlaylist.playlist) { 1790 for (var i = 0; i < window.myPlaylist.playlist.length; i++) { 1791 sample = window.myPlaylist.playlist[i].mp3 || window.myPlaylist.playlist[i].m4a || ''; 1792 if (sample) { 1793 break; 1794 } 1795 } 1796 } 1797 var file = qkPad3(sure) + qkPad3(ayet) + '.mp3'; 1798 if (sample) { 1799 return sample.replace(/\d{6}\.mp3(\?.*)?$/i, file); 1800 } 1801 var rec = ($('#reciterSelector').val() || $('#qkMpReciterSelect').val() || '').replace(/[^a-z0-9_-]/gi, ''); 1802 if (rec) { 1803 return qkBuildReciterAyahUrl(rec, sure, ayet); 1804 } 1805 return ''; 1806} 1807 1808function qkBuildReciterAyahUrl(rec, sure, ayet) { 1809 var file = qkPad3(sure) + qkPad3(ayet) + '.mp3'; 1810 var map = window.qkReciterAudio || {}; 1811 var cfg = map[rec]; 1812 if (!cfg) { 1813 return 'https://audio.qurancdn.com/' + rec + '/mp3/' + file; 1814 } 1815 var base = (cfg.base || '').replace(/\/$/, ''); 1816 if (cfg.type === 'qurancdn') { 1817 return base + '/' + cfg.folder + '/mp3/' + file; 1818 } 1819 if (cfg.type === 'everyayah') { 1820 return base + '/' + cfg.folder + '/' + file; 1821 } 1822 if (cfg.type === 'custom') { 1823 return base + '/' + file; 1824 } 1825 return ''; 1826} 1827 1828function qkCaptureSetStatus(text) { 1829 var $s = $('#qkCaptureStatus, #qkTepsirExportStatus'); 1830 if (!text) { 1831 $s.attr('hidden', 'hidden').text(''); 1832 return; 1833 } 1834 $s.removeAttr('hidden').text(text); 1835} 1836 1837function qkExportSizeFrom(name) { 1838 var v = ($('input[name="' + name + '"]:checked').val() || 'ig'); 1839 if (v === 'fb') { 1840 return { w: 1080, h: 1350, key: 'fb' }; 1841 } 1842 if (v === 'igstory') { 1843 return { w: 1080, h: 1920, key: 'igstory' }; 1844 } 1845 if (v === 'reels') { 1846 return { w: 1080, h: 1920, key: 'reels' }; 1847 } 1848 if (v === 'shorts') { 1849 return { w: 1080, h: 1920, key: 'shorts' }; 1850 } 1851 return { w: 1080, h: 1080, key: 'ig' }; 1852} 1853 1854function qkSyncCaptureShareBar(sure, ayet) { 1855 sure = parseInt(sure, 10) || 0; 1856 ayet = parseInt(ayet, 10) || 0; 1857 var $bar = $('#qkCaptureShareBar'); 1858 if (!$bar.length || !sure || !ayet) { 1859 return; 1860 } 1861 $bar.attr('data-sure', sure).attr('data-ayet', ayet).attr('data-link', 'terjime/' + sure + '-' + ayet); 1862} 1863 1864function qkResetExportFit($stage) { 1865 var $fit = $stage.children('.qk-export-fit'); 1866 if ($fit.length) { 1867 $fit.css({ position: '', left: '', top: '', transform: '', width: '', height: '' }); 1868 $fit.contents().unwrap(); 1869 } 1870} 1871 1872function qkFitExportStage($stage, cardSel) { 1873 if (!$stage || !$stage.length) { 1874 return; 1875 } 1876 var $fit = $stage.children('.qk-export-fit'); 1877 if (!$fit.length) { 1878 var $card = cardSel ? $stage.find(cardSel).first() : $(); 1879 if ($card.length) { 1880 $card.wrap('<div class="qk-export-fit"></div>'); 1881 } else { 1882 return; 1883 } 1884 $fit = $stage.children('.qk-export-fit'); 1885 } 1886 var layoutW = 520; 1887 $fit.css({ 1888 transform: 'none', 1889 position: 'relative', 1890 left: 'auto', 1891 top: 'auto', 1892 width: layoutW + 'px', 1893 maxWidth: 'none', 1894 minWidth: layoutW + 'px' 1895 });
1896 var sw = $stage.innerWidth(); 1897 var sh = $stage.innerHeight(); 1898 var cw = $fit.outerWidth(); 1899 var ch = $fit.outerHeight(); 1900 if (sw < 20 || sh < 20 || cw < 40 || ch < 8) { 1901 return; 1902 } 1903 var pad = Math.min(sw, sh) * 0.05; 1904 var scale = Math.min((sw - pad * 2) / cw, (sh - pad * 2) / ch); 1905 if (!isFinite(scale) || scale <= 0) { 1906 scale = 1; 1907 } 1908 $fit.css({ 1909 position: 'absolute', 1910 left: '50%', 1911 top: '50%', 1912 width: layoutW + 'px', 1913 minWidth: layoutW + 'px', 1914 transform: 'translate(-50%, -50%) scale(' + scale + ')', 1915 transformOrigin: 'center center' 1916 }); 1917} 1918 1919function qkApplyCaptureSizePreview() { 1920 var v = ($('input[name="qkCaptureSize"]:checked').val() || 'ig'); 1921 var $stage = $('#captureData'); 1922 if (!$stage.length) { 1923 return; 1924 } 1925 qkResetExportFit($stage); 1926 $stage.addClass('qk-export-stage').removeClass('qk-size-ig qk-size-igstory qk-size-fb qk-size-reels qk-size-shorts').addClass('qk-size-' + v); 1927 qkApplyExportStyle($stage, 'capture'); 1928 if (typeof qkAfterExportPreview === 'function') { 1929 qkAfterExportPreview('capture'); 1930 } 1931} 1932 1933function qkApplyTepsirSizePreview() { 1934 var $data = $('#tepsirData'); 1935 if ($data.length) { 1936 qkResetExportFit($data); 1937 $data.removeClass('qk-export-stage qk-size-ig qk-size-igstory qk-size-fb qk-size-reels qk-size-shorts qk-frame-teal qk-frame-thin qk-frame-dark qk-frame-gold'); 1938 } 1939 var size = ($('input[name="qkTepsirSize"]:checked').val() || 'ig'); 1940 var frame = ($('input[name="qkTepsirFrame"]:checked').val() || 'teal'); 1941 $('#qkTepsirSizeThumb').attr('data-size', size).attr('data-frame', frame); 1942 $('#qkTepsirBrandStage').removeClass('qk-size-ig qk-size-igstory qk-size-fb qk-size-reels qk-size-shorts').addClass('qk-export-stage qk-size-' + size); 1943 qkApplyExportStyle($('#qkTepsirExportPreview .qk-tepsir-capture-card'), 'tepsir'); 1944 if (typeof qkAfterExportPreview === 'function') { 1945 qkAfterExportPreview('tepsir'); 1946 } 1947} 1948 1949function qkExportFontKey(name) { 1950 var v = ($('input[name="' + (name || 'qkTepsirAyahFont') + '"]:checked').val() || 'm'); 1951 if (v !== 's' && v !== 'l' && v !== 'xl') { 1952 v = 'm'; 1953 } 1954 return v; 1955} 1956 1957function qkExportColorVal(id, fallback) { 1958 var v = ($('#' + id).val() || '').trim(); 1959 return /^#[0-9a-fA-F]{6}$/.test(v) ? v : (fallback || '#1c2a2e'); 1960} 1961 1962function qkApplyExportStyle($root, kind) { 1963 if (!$root || !$root.length) { 1964 return; 1965 } 1966 var tepsir = kind !== 'capture'; 1967 $root.attr('data-export-ayah-font', qkExportFontKey(tepsir ? 'qkTepsirAyahFont' : 'qkCaptureAyahFont')); 1968 $root.attr('data-export-body-font', qkExportFontKey(tepsir ? 'qkTepsirBodyFont' : 'qkCaptureBodyFont')); 1969 $root.css('--qk-export-ayah-color', qkExportColorVal(tepsir ? 'qkTepsirAyahColor' : 'qkCaptureAyahColor', '#1c2a2e')); 1970 $root.css('--qk-export-body-color', qkExportColorVal(tepsir ? 'qkTepsirBodyColor' : 'qkCaptureBodyColor', '#1c2a2e')); 1971} 1972 1973function qkApplyExportFont($root, name) { 1974 qkApplyExportStyle($root, (name || '').indexOf('Capture') >= 0 ? 'capture' : 'tepsir'); 1975} 1976 1977window.qkApplyCaptureSizePreview = qkApplyCaptureSizePreview; 1978window.qkApplyTepsirSizePreview = qkApplyTepsirSizePreview; 1979 1980function qkTepsirCurrentAudioUrl() { 1981 return qkAyahAudioUrl(selectedSureNo, selectedAyetNo); 1982} 1983 1984function qkTepsirExportSize() { 1985 return qkExportSizeFrom('qkTepsirSize'); 1986} 1987 1988function qkTepsirExportFrame() { 1989 return ($('input[name="qkTepsirFrame"]:checked').val() || 'teal'); 1990} 1991 1992function qkTepsirFramePalette(style) { 1993 var palettes = { 1994 teal: { a: '#1FA4BE', b: '#0d7377', c: '#0D4A52' }, 1995 thin: { a: '#1FA4BE', b: '#1FA4BE', c: '#0d7377' }, 1996 dark: { a: '#0D4A52', b: '#0d7377', c: '#1FA4BE' }, 1997 gold: { a: '#c9a227', b: '#0d7377', c: '#0D4A52' }, 1998 'qk-frame-classic': { a: '#1FA4BE', b: '#ffffff', c: '#1FA4BE' }, 1999 'qk-frame-gold': { a: '#c9a227', b: '#fff8ec', c: '#e8d5a3' }, 2000 'qk-frame-parchment': { a: '#8b7355', b: '#faf6ee', c: '#c4b49a' }, 2001 'qk-frame-emerald': { a: '#1a8a6a', b: '#e8f7f2', c: '#1a8a6a' }, 2002 'qk-frame-midnight': { a: '#c9a227', b: '#2a3f4a', c: '#1e2d36' } 2003 }; 2004 return palettes[style] || palettes.teal; 2005} 2006 2007function qkTepsirFrameMetrics(style, w, h) { 2008 var min = Math.min(w, h); 2009 var band = style === 'thin' ? Math.max(10, Math.round(min * 0.012)) : Math.max(22, Math.round(min * 0.026)); 2010 var a = style === 'thin' ? Math.max(4, Math.round(band * 0.34)) : Math.max(8, Math.round(band * 0.38)); 2011 var b = style === 'thin' ? Math.max(3, Math.round(band * 0.33)) : Math.max(7, Math.round(band * 0.34)); 2012 var c = Math.max(3, band - a - b); 2013 var inset = a + b + c; 2014 return { 2015 a: a, 2016 b: b, 2017 c: c, 2018 inset: inset, 2019 inner: { x: inset, y: inset, w: w - inset * 2, h: h - inset * 2 } 2020 }; 2021} 2022 2023function qkTepsirDrawEdgeBand(ctx, w, h, inset, thickness, color) { 2024 if (thickness < 1) { 2025 return; 2026 } 2027 ctx.fillStyle = color; 2028 ctx.fillRect(inset, inset, w - inset * 2, thickness); 2029 ctx.fillRect(inset, h - inset - thickness, w - inset * 2, thickness); 2030 ctx.fillRect(inset, inset, thickness, h - inset * 2); 2031 ctx.fillRect(w - inset - thickness, inset, thickness, h - inset * 2); 2032} 2033 2034function qkTepsirDrawEdgeFrame(ctx, w, h, style) { 2035 if (!style || style === 'qk-frame-img') { 2036 return; 2037 }
2038 var pal = qkTepsirFramePalette(style); 2039 var m = qkTepsirFrameMetrics(style, w, h); 2040 qkTepsirDrawEdgeBand(ctx, w, h, 0, m.a, pal.a); 2041 qkTepsirDrawEdgeBand(ctx, w, h, m.a, m.b, pal.b); 2042 qkTepsirDrawEdgeBand(ctx, w, h, m.a + m.b, m.c, pal.c); 2043} 2044 2045function qkTepsirPaintCaptureFrame(srcCanvas, style) { 2046 style = style || 'teal'; 2047 var m = qkTepsirFrameMetrics(style, srcCanvas.width + 80, srcCanvas.height + 80); 2048 var out = document.createElement('canvas'); 2049 out.width = srcCanvas.width + m.inset * 2; 2050 out.height = srcCanvas.height + m.inset * 2; 2051 var ctx = out.getContext('2d'); 2052 ctx.fillStyle = '#fffefb'; 2053 ctx.fillRect(0, 0, out.width, out.height); 2054 ctx.drawImage(srcCanvas, m.inset, m.inset); 2055 qkTepsirDrawEdgeFrame(ctx, out.width, out.height, style); 2056 return out; 2057} 2058 2059function qkTepsirComposeExportCanvas(src, size, style, bg, footer, grow) { 2060 var tw = size.w; 2061 var th = size.h; 2062 var m = qkTepsirFrameMetrics(style, tw, th); 2063 function sidePad(metrics) { 2064 return Math.max(8, Math.round(Math.min(metrics.inner.w, metrics.inner.h) * 0.012)); 2065 } 2066 var pad = sidePad(m); 2067 var maxW = m.inner.w - pad * 2; 2068 function footHFor(innerH) { 2069 if (!footer || !footer.width || !footer.height) { 2070 return 0; 2071 } 2072 return Math.min(Math.round(footer.height * (maxW / footer.width)), Math.round(Math.max(innerH, 200) * 0.14)); 2073 } 2074 var footH = footHFor(m.inner.h); 2075 var scale = maxW / Math.max(1, src.width); 2076 var dw = Math.max(1, Math.round(src.width * scale)); 2077 var dh = Math.max(1, Math.round(src.height * scale)); 2078 var gap = footH ? Math.round(pad * 0.35) : 0; 2079 var needH = pad + dh + (footH ? gap + footH : 0) + pad + m.inset * 2; 2080 if (needH > th) { 2081 th = needH; 2082 m = qkTepsirFrameMetrics(style, tw, th); 2083 pad = sidePad(m); 2084 maxW = m.inner.w - pad * 2; 2085 scale = maxW / Math.max(1, src.width); 2086 dw = Math.max(1, Math.round(src.width * scale)); 2087 dh = Math.max(1, Math.round(src.height * scale)); 2088 footH = footHFor(m.inner.h); 2089 gap = footH ? Math.round(pad * 0.35) : 0; 2090 } 2091 var out = document.createElement('canvas'); 2092 out.width = tw; 2093 out.height = th; 2094 var ctx = out.getContext('2d'); 2095 ctx.fillStyle = bg || '#fffefb'; 2096 ctx.fillRect(0, 0, tw, th); 2097 var inner = m.inner; 2098 var x = inner.x + pad; 2099 var y = inner.y + pad; 2100 var availH = inner.h - pad * 2 - (footH ? gap + footH : 0); 2101 if (!grow && dh < availH - 2) { 2102 y = inner.y + pad + Math.round((availH - dh) / 2); 2103 } 2104 ctx.drawImage(src, x, y, dw, dh); 2105 if (footer && footH) { 2106 ctx.drawImage(footer, x, inner.y + inner.h - pad - footH, maxW, footH); 2107 } 2108 qkTepsirDrawEdgeFrame(ctx, tw, th, style); 2109 return out; 2110} 2111 2112function qkCanvasFromEl($el, bg, minW) { 2113 var node = $el && $el[0] ? $el[0] : $el; 2114 if (!node) { 2115 return Promise.reject(new Error('empty')); 2116 } 2117 var w = Math.max(node.scrollWidth || 0, node.offsetWidth || 0, minW || 1); 2118 var h = Math.max(node.scrollHeight || 0, node.offsetHeight || 0, 1); 2119 return window.html2canvas(node, { 2120 backgroundColor: bg || '#fffefb', 2121 scale: Math.min(window.devicePixelRatio || 1, 2), 2122 useCORS: true, 2123 allowTaint: true, 2124 logging: false, 2125 width: w, 2126 height: h 2127 }); 2128} 2129 2130function qkExportBrandNode(bg, dark) { 2131 var logoSrc = $('.qk-header-logo-img, .qk-tepsir-modal-logo, .qk-tepsir-modal-brandbar-logo').first().attr('src') || ''; 2132 var $brand = $('<div class="qk-tepsir-capture-brand"></div>').css({ 2133 width: '720px', 2134 boxSizing: 'border-box', 2135 padding: '12px 16px 10px', 2136 background: bg || '#fffefb', 2137 borderTop: dark ? '1px solid rgba(255,255,255,0.2)' : '1px solid rgba(19, 165, 174, 0.3)' 2138 }); 2139 if (logoSrc) { 2140 $brand.append($('<img alt="Qurankerim">').attr({ src: logoSrc, crossorigin: 'anonymous' })); 2141 } 2142 var $url = $('<div class="qk-tepsir-capture-url"></div>').text('www.qurankerim.com'); 2143 if (dark) { 2144 $url.css('color', '#7fd4e8'); 2145 } 2146 $brand.append($url); 2147 return $brand; 2148} 2149 2150function qkCaptureBrandFooter(bg, dark) { 2151 var $host = $('#qkTepsirCaptureHost'); 2152 if (!$host.length) { 2153 $host = $('<div id="qkTepsirCaptureHost"></div>').appendTo(document.body); 2154 } 2155 var $brand = qkExportBrandNode(bg, dark); 2156 $host.append($brand); 2157 return qkTepsirWaitCaptureAssets($brand).then(function () { 2158 return qkCanvasFromEl($brand, bg, 720); 2159 }).then(function (canvas) { 2160 $brand.remove(); 2161 return canvas; 2162 }); 2163} 2164 2165function qkTepsirFitCanvas(src, tw, th, bg) { 2166 var out = document.createElement('canvas'); 2167 out.width = tw; 2168 out.height = th; 2169 var ctx = out.getContext('2d'); 2170 ctx.fillStyle = bg || '#fffefb'; 2171 ctx.fillRect(0, 0, tw, th); 2172 var pad = Math.round(Math.min(tw, th) * 0.04); 2173 var maxW = tw - pad * 2; 2174 var maxH = th - pad * 2; 2175 var scale = Math.min(maxW / src.width, maxH / src.height); 2176 var dw = Math.max(1, Math.round(src.width * scale)); 2177 var dh = Math.max(1, Math.round(src.height * scale)); 2178 ctx.drawImage(src, Math.round((tw - dw) / 2), Math.round((th - dh) / 2), dw, dh); 2179 return out; 2180} 2181 2182function qkUnlockAudioForRecord() { 2183 var AudioCtx = window.AudioContext || window.webkitAudioContext; 2184 if (!AudioCtx) { 2185 return null; 2186 } 2187 if (!window._qkRecordAudioCtx || window._qkRecordAudioCtx.state === 'closed') { 2188 try { 2189 window._qkRecordAudioCtx = new AudioCtx({ sampleRate: 48000, latencyHint: 'interactive' }); 2190 } catch (eNew) { 2191 window._qkRecordAudioCtx = new AudioCtx(); 2192 } 2193 } 2194 var ac = window._qkRecordAudioCtx; 2195 if (ac.resume) { 2196 ac.resume(); 2197 } 2198 try { 2199 var buf = ac.createBuffer(1, Math.max(1, Math.round((ac.sampleRate || 48000) * 0.03)), ac.sampleRate || 48000); 2200 var src = ac.createBufferSource(); 2201 src.buffer = buf; 2202 var g = ac.createGain(); 2203 g.gain.value = 0.0001; 2204 src.connect(g); 2205 g.connect(ac.destination); 2206 src.start(0); 2207 } catch (e) {} 2208 return ac; 2209} 2210 2211function qkDecodeAudioBuffer(ac, url) { 2212 return fetch(url, { mode: 'cors', credentials: 'omit', cache: 'force-cache' }).then(function (res) { 2213 if (!res.ok) { 2214 throw new Error('audio-http'); 2215 } 2216 return res.arrayBuffer(); 2217 }).then(function (ab) { 2218 var copy = ab.slice(0); 2219 return new Promise(function (resolve, reject) { 2220 var done = false;
2221 function ok(buf) { 2222 if (done) { 2223 return; 2224 } 2225 done = true; 2226 resolve(buf); 2227 } 2228 function fail(err) { 2229 if (done) { 2230 return; 2231 } 2232 done = true; 2233 reject(err || new Error('decode')); 2234 } 2235 try { 2236 var p = ac.decodeAudioData(copy, ok, fail); 2237 if (p && typeof p.then === 'function') { 2238 p.then(ok, fail); 2239 } 2240 } catch (eDec) { 2241 fail(eDec); 2242 } 2243 }); 2244 }); 2245} 2246 2247function qkStackClipCanvases(clips, bg) { 2248 var srcs = (clips || []).filter(function (c) { 2249 return c && c.canvas && c.canvas.width; 2250 }); 2251 if (!srcs.length) { 2252 return null; 2253 } 2254 var w = srcs[0].canvas.width; 2255 var gap = Math.max(28, Math.round(w * 0.055)); 2256 var parts = []; 2257 var totalH = 0; 2258 srcs.forEach(function (c) { 2259 var h = Math.max(1, Math.round(c.canvas.height * (w / Math.max(1, c.canvas.width)))); 2260 parts.push({ canvas: c.canvas, h: h }); 2261 totalH += h + gap; 2262 }); 2263 totalH -= gap; 2264 var out = document.createElement('canvas'); 2265 out.width = w; 2266 out.height = Math.max(1, totalH); 2267 var ctx = out.getContext('2d'); 2268 ctx.fillStyle = bg || '#fffefb'; 2269 ctx.fillRect(0, 0, w, out.height); 2270 var y = 0; 2271 parts.forEach(function (p) { 2272 ctx.drawImage(p.canvas, 0, y, w, p.h); 2273 y += p.h + gap; 2274 }); 2275 return out; 2276} 2277 2278function qkMp4MuxerUrl() { 2279 var el = document.querySelector('script[src*="app.js"]'); 2280 if (el && el.src) { 2281 return el.src.replace(/js\/app\.js(\?.*)?$/i, 'js/mp4-muxer.mjs'); 2282 } 2283 return '/v5_assets/js/mp4-muxer.mjs'; 2284} 2285 2286function qkLoadMp4Muxer() { 2287 if (window._qkMp4Muxer) { 2288 return Promise.resolve(window._qkMp4Muxer); 2289 } 2290 return import(qkMp4MuxerUrl()).then(function (mod) { 2291 window._qkMp4Muxer = mod; 2292 return mod; 2293 }); 2294} 2295 2296function qkCanEncodeMp4WebCodecs() { 2297 return typeof VideoEncoder === 'function' && typeof AudioEncoder === 'function' && typeof VideoFrame === 'function' && typeof AudioData === 'function'; 2298} 2299 2300function qkWaitEncoderDrain(encoder) { 2301 if (!encoder || encoder.encodeQueueSize < 8) { 2302 return Promise.resolve(); 2303 } 2304 return new Promise(function (resolve) { 2305 function check() { 2306 if (!encoder || encoder.encodeQueueSize < 3) { 2307 resolve(); 2308 return; 2309 } 2310 setTimeout(check, 8); 2311 } 2312 check(); 2313 }); 2314} 2315 2316function qkPickAvcConfig(w, h) { 2317 var codecs = ['avc1.42001E', 'avc1.42001f', 'avc1.4d001f', 'avc1.4d0028']; 2318 var i = 0; 2319 function next() { 2320 if (i >= codecs.length) { 2321 return Promise.reject(new Error('avc')); 2322 } 2323 var cfg = { 2324 codec: codecs[i], 2325 width: w, 2326 height: h, 2327 bitrate: 4500000, 2328 framerate: 30, 2329 avc: { format: 'avc' } 2330 }; 2331 i += 1; 2332 if (typeof VideoEncoder.isConfigSupported !== 'function') { 2333 return Promise.resolve(cfg); 2334 } 2335 return VideoEncoder.isConfigSupported(cfg).then(function (r) { 2336 if (r && r.supported) { 2337 return r.config || cfg; 2338 } 2339 return next(); 2340 }).catch(next); 2341 } 2342 return next(); 2343} 2344 2345function qkPickAacConfig(sampleRate, channels) { 2346 var rates = [sampleRate, 48000, 44100]; 2347 var seen = {}; 2348 var list = [];
2349 rates.forEach(function (r) { 2350 r = parseInt(r, 10) || 0; 2351 if (r && !seen[r]) { 2352 seen[r] = 1; 2353 list.push(r); 2354 } 2355 }); 2356 var i = 0; 2357 function next() { 2358 if (i >= list.length) { 2359 return Promise.reject(new Error('aac')); 2360 } 2361 var cfg = { 2362 codec: 'mp4a.40.2', 2363 sampleRate: list[i], 2364 numberOfChannels: channels, 2365 bitrate: 128000 2366 }; 2367 i += 1; 2368 if (typeof AudioEncoder.isConfigSupported !== 'function') { 2369 return Promise.resolve(cfg); 2370 } 2371 return AudioEncoder.isConfigSupported(cfg).then(function (r) { 2372 if (r && r.supported) { 2373 return r.config || cfg; 2374 } 2375 return next(); 2376 }).catch(next); 2377 } 2378 return next(); 2379} 2380 2381function qkMergeClipAudioStereo(ac, clips) { 2382 var parts = []; 2383 (clips || []).forEach(function (c) { 2384 if (c && c.buffer && c.buffer.length) { 2385 parts.push(c.buffer); 2386 } 2387 }); 2388 if (!parts.length) { 2389 return null; 2390 } 2391 var rate = parts[0].sampleRate; 2392 var total = 0; 2393 parts.forEach(function (p) { 2394 total += p.length; 2395 }); 2396 var out = ac.createBuffer(2, total, rate); 2397 var off = 0; 2398 parts.forEach(function (p) { 2399 var left = p.getChannelData(0); 2400 var right = p.numberOfChannels > 1 ? p.getChannelData(1) : left; 2401 out.getChannelData(0).set(left, off); 2402 out.getChannelData(1).set(right, off); 2403 off += p.length; 2404 }); 2405 return out; 2406} 2407 2408function qkEncodeAyahVideoMp4(opts) { 2409 opts = opts || {}; 2410 if (!qkCanEncodeMp4WebCodecs()) { 2411 return Promise.reject(new Error('webcodecs')); 2412 } 2413 var recCanvas = opts.canvas; 2414 var paintAtProgress = opts.paintAtProgress; 2415 var clips = opts.clips || []; 2416 var ac = opts.ac; 2417 var w = opts.w - (opts.w % 2); 2418 var h = opts.h - (opts.h % 2); 2419 var fps = opts.fps || 30; 2420 var totalDur = opts.totalDur || 1; 2421 if (totalDur < 0.25) { 2422 totalDur = 0.25; 2423 } 2424 var numFrames = Math.max(8, Math.round(totalDur * fps)); 2425 var mixed = qkMergeClipAudioStereo(ac, clips); 2426 if (!mixed) { 2427 return Promise.reject(new Error('audio')); 2428 } 2429 return qkLoadMp4Muxer().then(function (mod) { 2430 return qkPickAvcConfig(w, h).then(function (vCfg) { 2431 return qkPickAacConfig(mixed.sampleRate, 2).then(function (aCfg) { 2432 return { mod: mod, vCfg: vCfg, aCfg: aCfg }; 2433 }); 2434 }); 2435 }).then(function (pack) { 2436 var Muxer = pack.mod.Muxer; 2437 var ArrayBufferTarget = pack.mod.ArrayBufferTarget; 2438 var target = new ArrayBufferTarget(); 2439 var muxer = new Muxer({ 2440 target: target, 2441 fastStart: 'in-memory', 2442 firstTimestampBehavior: 'offset', 2443 video: { 2444 codec: 'avc', 2445 width: w, 2446 height: h, 2447 frameRate: fps 2448 }, 2449 audio: { 2450 codec: 'aac', 2451 numberOfChannels: 2, 2452 sampleRate: pack.aCfg.sampleRate 2453 } 2454 }); 2455 var vErr = null; 2456 var aErr = null; 2457 var videoEncoder = new VideoEncoder({ 2458 output: function (chunk, meta) { 2459 muxer.addVideoChunk(chunk, meta); 2460 }, 2461 error: function (e) { 2462 vErr = e; 2463 } 2464 }); 2465 var audioEncoder = new AudioEncoder({ 2466 output: function (chunk, meta) { 2467 muxer.addAudioChunk(chunk, meta); 2468 }, 2469 error: function (e) { 2470 aErr = e; 2471 } 2472 }); 2473 videoEncoder.configure(pack.vCfg); 2474 audioEncoder.configure(pack.aCfg); 2475 if (pack.aCfg.sampleRate !== mixed.sampleRate) { 2476 throw new Error('rate'); 2477 } 2478 var frameDur = Math.round(1e6 / fps); 2479 var seq = Promise.resolve(); 2480 var n; 2481 for (n = 0; n < numFrames; n++) { 2482 seq = seq.then((function (idx) { 2483 return function () { 2484 if (vErr) { 2485 throw vErr; 2486 } 2487 qkCaptureSetStatus((idx + 1) + ' / ' + numFrames); 2488 paintAtProgress(idx / Math.max(numFrames - 1, 1)); 2489 var vf = new VideoFrame(recCanvas, { 2490 timestamp: idx * frameDur, 2491 duration: frameDur 2492 }); 2493 videoEncoder.encode(vf, { keyFrame: idx % (fps * 2) === 0 }); 2494 vf.close(); 2495 return qkWaitEncoderDrain(videoEncoder); 2496 }; 2497 })(n)); 2498 } 2499 return seq.then(function () { 2500 if (aErr) { 2501 throw aErr; 2502 } 2503 var sampleRate = mixed.sampleRate; 2504 var frameCount = 1024; 2505 var ts = 0; 2506 var i; 2507 for (i = 0; i < mixed.length; i += frameCount) { 2508 var count = Math.min(frameCount, mixed.length - i); 2509 var plane0 = mixed.getChannelData(0).subarray(i, i + count); 2510 var plane1 = mixed.getChannelData(1).subarray(i, i + count); 2511 var copy0 = new Float32Array(count); 2512 var copy1 = new Float32Array(count); 2513 copy0.set(plane0); 2514 copy1.set(plane1); 2515 var data = new Float32Array(count * 2); 2516 data.set(copy0, 0); 2517 data.set(copy1, count); 2518 var ad = new AudioData({ 2519 format: 'f32-planar', 2520 sampleRate: sampleRate, 2521 numberOfFrames: count, 2522 numberOfChannels: 2, 2523 timestamp: ts, 2524 data: data 2525 }); 2526 audioEncoder.encode(ad); 2527 ad.close(); 2528 ts += Math.round((count / sampleRate) * 1e6); 2529 } 2530 return qkWaitEncoderDrain(audioEncoder); 2531 }).then(function () { 2532 return Promise.all([ 2533 videoEncoder.state === 'configured' ? videoEncoder.flush() : Promise.resolve(), 2534 audioEncoder.state === 'configured' ? audioEncoder.flush() : Promise.resolve() 2535 ]); 2536 }).then(function () { 2537 if (vErr) { 2538 throw vErr; 2539 }
2540 if (aErr) { 2541 throw aErr; 2542 } 2543 try { 2544 videoEncoder.close(); 2545 } catch (eV) {} 2546 try { 2547 audioEncoder.close(); 2548 } catch (eA) {} 2549 muxer.finalize(); 2550 return { 2551 blob: new Blob([target.buffer], { type: 'video/mp4' }), 2552 ext: 'mp4', 2553 duration: totalDur 2554 }; 2555 }); 2556 }); 2557} 2558 2559function qkExtractAyahArabic($root) { 2560 if (!$root || !$root.length) { 2561 return ''; 2562 } 2563 var $el = $root.find('.qk-tepsir-capture-ayah-box, .qk-jumle-arabic-box, .qk-ehsen-arabic-box, .ayet.ar-fsize, .qk-modal-ayet, .ayet').first(); 2564 if (!$el.length && $root.is('.ayet, .qk-modal-ayet, .qk-tepsir-capture-ayah-box')) { 2565 $el = $root; 2566 } 2567 var text = ($el.text() || '').replace(/\s+/g, ' ').trim(); 2568 return text; 2569} 2570 2571function qkAyahArabicText(sure, ayet) { 2572 sure = parseInt(sure, 10) || 0; 2573 ayet = parseInt(ayet, 10) || 0; 2574 var t = ''; 2575 var $tp = $('#qkTepsirExportPreview .qk-tepsir-export-ayah-piece'); 2576 if ($tp.length && ayet) { 2577 var $hit = $tp.filter('[data-ayah="' + ayet + '"]').first(); 2578 if (!$hit.length) { 2579 var range = qkReadAyahRange('qkTepsirAyahFrom', 'qkTepsirAyahTo', sure, ayet); 2580 $hit = $tp.eq(ayet - range.from); 2581 } 2582 t = ($hit.attr('data-ayah-ar') || '').trim() || qkExtractAyahArabic($hit); 2583 } 2584 if (!t) { 2585 var $cp = $('#captureData .qk-capture-ayah-piece'); 2586 if ($cp.length && ayet) { 2587 var $ch = $cp.filter('[data-ayah="' + ayet + '"]').first(); 2588 if (!$ch.length) { 2589 var cr = qkReadAyahRange('qkCaptureAyahFrom', 'qkCaptureAyahTo', sure, ayet); 2590 $ch = $cp.eq(ayet - cr.from); 2591 } 2592 t = ($ch.attr('data-ayah-ar') || '').trim() || qkExtractAyahArabic($ch); 2593 } 2594 } 2595 if (!t) { 2596 t = qkExtractAyahArabic($('#captureData')); 2597 } 2598 if (!t) { 2599 var $page = $('[data-sure="' + sure + '"][data-ayet="' + ayet + '"]').first(); 2600 if ($page.length) { 2601 t = qkExtractAyahArabic($page.closest('.ayet-item, .verse, li, .row, article, div')); 2602 if (!t) { 2603 t = qkExtractAyahArabic($page); 2604 } 2605 } 2606 } 2607 if (!t) { 2608 t = qkExtractAyahArabic($('#tepsirData')); 2609 } 2610 return t; 2611} 2612 2613function qkCanvasWrapLines(ctx, text, maxW) { 2614 var words = String(text || '').split(/\s+/).filter(Boolean); 2615 var lines = []; 2616 var line = ''; 2617 var i; 2618 for (i = 0; i < words.length; i++) { 2619 var test = line ? (line + ' ' + words[i]) : words[i]; 2620 if (line && ctx.measureText(test).width > maxW) { 2621 lines.push(line); 2622 line = words[i]; 2623 } else { 2624 line = test; 2625 } 2626 } 2627 if (line) { 2628 lines.push(line); 2629 } 2630 return lines.slice(0, 5); 2631} 2632 2633function qkMeasureAyahBoxes($root) { 2634 if (!$root || !$root[0]) { 2635 return []; 2636 } 2637 var root = $root[0]; 2638 var origin = root.getBoundingClientRect(); 2639 var boxes = []; 2640 var $hits = $root.find('.qk-capture-ayah-piece, .qk-tepsir-export-ayah-piece').filter(function () { 2641 var r = this.getBoundingClientRect(); 2642 return r.width > 24 && r.height > 16; 2643 }); 2644 if (!$hits.length) { 2645 $hits = $root.find('.qk-tepsir-capture-ayah-box, .qk-jumle-arabic-box, .qk-ehsen-arabic-box, .qk-tefsir-ayah-box, .ar-fsize').filter(function () { 2646 var r = this.getBoundingClientRect(); 2647 return r.width > 24 && r.height > 16; 2648 }); 2649 } 2650 if (!$hits.length) { 2651 $hits = $root.find('.ayet').filter(function () { 2652 var r = this.getBoundingClientRect(); 2653 return r.width > 24 && r.height > 16; 2654 }); 2655 } 2656 $hits.each(function () { 2657 var r = this.getBoundingClientRect(); 2658 var box = { 2659 x: r.left - origin.left + (root.scrollLeft || 0), 2660 y: r.top - origin.top + (root.scrollTop || 0), 2661 w: r.width, 2662 h: r.height 2663 }; 2664 var ar = null; 2665 if (this.querySelector) { 2666 ar = this.querySelector('.qk-jumle-arabic-box, .qk-ehsen-arabic-box, .ayet.ar-fsize, .qk-modal-ayet'); 2667 if (!ar) { 2668 ar = this.querySelector('.ayet'); 2669 } 2670 } 2671 if (ar) { 2672 var arR = ar.getBoundingClientRect(); 2673 if (arR.width > 24 && arR.height > 12) { 2674 box.pulse = { 2675 x: arR.left - origin.left + (root.scrollLeft || 0), 2676 y: arR.top - origin.top + (root.scrollTop || 0), 2677 w: arR.width, 2678 h: arR.height 2679 }; 2680 } 2681 } 2682 boxes.push(box); 2683 }); 2684 return boxes; 2685} 2686 2687function qkShrinkWrapExportNode($el) { 2688 var node = $el && $el[0]; 2689 if (!node) { 2690 return; 2691 } 2692 $el.css({ 2693 height: 'auto', 2694 minHeight: '0', 2695 maxHeight: 'none', 2696 flex: 'none' 2697 }); 2698 var h = 0; 2699 var kids = node.children; 2700 var i; 2701 for (i = 0; i < kids.length; i++) { 2702 h = Math.max(h, kids[i].offsetTop + kids[i].offsetHeight); 2703 }
2704 h = Math.max(h, node.scrollHeight || 0); 2705 if (h > 1) { 2706 $el.css('height', Math.ceil(h) + 'px'); 2707 } 2708} 2709 2710function qkCropCanvasToInk(canvas, ayahBoxes) { 2711 if (!canvas || !canvas.getContext) { 2712 return canvas; 2713 } 2714 var ctx; 2715 var img; 2716 try { 2717 ctx = canvas.getContext('2d'); 2718 img = ctx.getImageData(0, 0, canvas.width, canvas.height); 2719 } catch (eInk) { 2720 return canvas; 2721 } 2722 var d = img.data; 2723 var w = canvas.width; 2724 var h = canvas.height; 2725 var step = w > 1400 ? 3 : 2; 2726 function rowHasInk(y) { 2727 var row = y * w * 4; 2728 var x; 2729 for (x = 0; x < w; x += step) { 2730 var i = row + x * 4; 2731 if (d[i + 3] < 18) { 2732 continue; 2733 } 2734 if (d[i] < 248 || d[i + 1] < 247 || d[i + 2] < 244) { 2735 return true; 2736 } 2737 } 2738 return false; 2739 } 2740 var top = 0; 2741 var bot = h - 1; 2742 var y; 2743 var found = false; 2744 for (y = 0; y < h; y += 1) { 2745 if (rowHasInk(y)) { 2746 top = y; 2747 found = true; 2748 break; 2749 } 2750 } 2751 if (!found) { 2752 return canvas; 2753 } 2754 for (y = h - 1; y >= top; y -= 1) { 2755 if (rowHasInk(y)) { 2756 bot = y; 2757 break; 2758 } 2759 } 2760 var pad = Math.max(10, Math.round(w * 0.012)); 2761 top = Math.max(0, top - pad); 2762 bot = Math.min(h - 1, bot + pad); 2763 if (top <= 1 && bot >= h - 2) { 2764 return canvas; 2765 } 2766 var out = document.createElement('canvas'); 2767 out.width = w; 2768 out.height = bot - top + 1; 2769 out.getContext('2d').drawImage(canvas, 0, top, w, out.height, 0, 0, w, out.height); 2770 var boxes = ayahBoxes || canvas._ayahBoxes || []; 2771 out._ayahBoxes = boxes.map(function (b) { 2772 return { x: b.x, y: b.y - top, w: b.w, h: b.h }; 2773 }); 2774 return out; 2775} 2776 2777function qkAyahBoxesToCanvas(boxes, elW, canvas) { 2778 var sx = (canvas && canvas.width ? canvas.width : 1) / Math.max(1, elW); 2779 return (boxes || []).map(function (b) { 2780 var o = { x: b.x * sx, y: b.y * sx, w: b.w * sx, h: b.h * sx }; 2781 if (b.pulse) { 2782 o.pulse = { x: b.pulse.x * sx, y: b.pulse.y * sx, w: b.pulse.w * sx, h: b.pulse.h * sx }; 2783 } 2784 return o; 2785 }); 2786} 2787 2788function qkPulseSrcBox(srcBox) { 2789 return (srcBox && srcBox.pulse) ? srcBox.pulse : srcBox; 2790} 2791 2792function qkMapStillRect(srcBox, still, dx, dy, dw, dh) { 2793 if (!srcBox || !still) { 2794 return null; 2795 } 2796 var sx = dw / Math.max(1, still.width); 2797 var sy = dh / Math.max(1, still.height); 2798 return { 2799 x: dx + srcBox.x * sx, 2800 y: dy + srcBox.y * sy, 2801 w: srcBox.w * sx, 2802 h: srcBox.h * sy 2803 }; 2804} 2805 2806function qkPulseAyahRegion(ctx, rect, tSec) { 2807 if (!rect || rect.w < 8 || rect.h < 8) { 2808 return; 2809 } 2810 var pulse = 0.5 - 0.5 * Math.cos((Math.max(0, tSec) / 2.2) * Math.PI * 2); 2811 ctx.save(); 2812 ctx.lineWidth = Math.max(2, Math.round(Math.min(rect.w, rect.h) * 0.018)); 2813 ctx.strokeStyle = 'rgba(31, 164, 190,' + (0.28 + 0.72 * pulse).toFixed(3) + ')'; 2814 ctx.fillStyle = 'rgba(31, 164, 190,' + (0.03 + 0.11 * pulse).toFixed(3) + ')'; 2815 if (typeof ctx.roundRect === 'function') { 2816 ctx.beginPath(); 2817 ctx.roundRect(rect.x, rect.y, rect.w, rect.h, Math.min(12, Math.round(rect.h * 0.12))); 2818 ctx.fill(); 2819 ctx.stroke(); 2820 } else { 2821 ctx.fillRect(rect.x, rect.y, rect.w, rect.h); 2822 ctx.strokeRect(rect.x, rect.y, rect.w, rect.h); 2823 } 2824 ctx.restore(); 2825} 2826 2827function qkClipIndexAtTime(clips, tSec) { 2828 var acc = 0; 2829 var i; 2830 for (i = 0; i < clips.length; i++) { 2831 var d = clips[i] && clips[i].buffer && clips[i].buffer.duration ? clips[i].buffer.duration : 0; 2832 if (tSec < acc + d + 0.02) { 2833 return i; 2834 } 2835 acc += d; 2836 } 2837 return Math.max(0, clips.length - 1); 2838} 2839 2840function qkClipAyahBoxes(clips) { 2841 var i; 2842 for (i = 0; i < clips.length; i++) { 2843 if (clips[i] && clips[i].ayahBoxes && clips[i].ayahBoxes.length) { 2844 return clips[i].ayahBoxes; 2845 } 2846 } 2847 return []; 2848} 2849 2850function qkTepsirRecordAyahVideo(stillCanvas, audioUrl, extra) { 2851 extra = extra || {}; 2852 var canvas = (stillCanvas && stillCanvas.canvas) ? stillCanvas.canvas : stillCanvas; 2853 var footer = extra.footer || (stillCanvas && stillCanvas.footer) || null; 2854 return qkRecordAyahVideoClips([{ 2855 canvas: canvas, 2856 audioUrl: audioUrl, 2857 footer: footer, 2858 ayahText: extra.ayahText || qkAyahArabicText(selectedSureNo, selectedAyetNo), 2859 ayahBoxes: extra.ayahBoxes || (canvas && canvas._ayahBoxes) || (stillCanvas && stillCanvas.ayahBoxes) || [] 2860 }], { 2861 scroll: true, 2862 edgeFrame: qkTepsirExportFrame(), 2863 size: qkTepsirExportSize(), 2864 footer: footer, 2865 bg: extra.bg || '#fffefb' 2866 }); 2867} 2868 2869function qkRecordAyahVideoClips(clips, opts) { 2870 return new Promise(function (resolve, reject) { 2871 opts = opts || {}; 2872 clips = (clips || []).filter(function (c) { 2873 return c && c.canvas && c.audioUrl; 2874 }); 2875 if (!clips.length || typeof window.MediaRecorder !== 'function' || !HTMLCanvasElement.prototype.captureStream) { 2876 reject(new Error('video')); 2877 return; 2878 } 2879 var size = opts.size || { w: clips[0].canvas.width, h: clips[0].canvas.height }; 2880 var w = size.w - (size.w % 2);
2881 var h = size.h - (size.h % 2); 2882 var scroll = opts.scroll !== false; 2883 var centerBlocks = opts.centerBlocks === true; 2884 var edgeFrame = opts.edgeFrame || ''; 2885 var fillBg = opts.bg || '#fffefb'; 2886 var overlayImg = opts.overlay || null; 2887 var frameM = edgeFrame ? qkTepsirFrameMetrics(edgeFrame, w, h) : { 2888 inner: { 2889 x: Math.round(Math.min(w, h) * 0.026), 2890 y: Math.round(Math.min(w, h) * 0.026), 2891 w: w - Math.round(Math.min(w, h) * 0.052), 2892 h: h - Math.round(Math.min(w, h) * 0.052) 2893 } 2894 }; 2895 if (typeof qkInsetFrameMetrics === 'function') { 2896 frameM = qkInsetFrameMetrics(frameM, (size && size.key) || '', w, h); 2897 } 2898 var recCanvas = document.createElement('canvas'); 2899 recCanvas.width = w; 2900 recCanvas.height = h; 2901 recCanvas.setAttribute('aria-hidden', 'true'); 2902 recCanvas.style.cssText = 'position:fixed;left:-10000px;top:0;width:' + w + 'px;height:' + h + 'px;opacity:1;pointer-events:none;'; 2903 document.body.appendChild(recCanvas); 2904 var rctx = recCanvas.getContext('2d', { alpha: false }); 2905 var still = clips[0].canvas; 2906 var currentFooter = clips[0].footer || opts.footer || null; 2907 var clipStart = 0; 2908 var clipDur = 1; 2909 var videoStart = 0; 2910 var totalDur = 0; 2911 var vTrack = null; 2912 function ease(t) { 2913 if (t <= 0) { 2914 return 0; 2915 } 2916 if (t >= 1) { 2917 return 1; 2918 } 2919 return 0.5 - 0.5 * Math.cos(Math.PI * t); 2920 } 2921 function paintAtProgress(t01) { 2922 if (t01 > 1) { 2923 t01 = 1; 2924 } 2925 if (t01 < 0) { 2926 t01 = 0; 2927 } 2928 if (opts.pageReady && still) { 2929 var pageIdx = qkClipIndexAtTime(clips, t01 * (totalDur || 1)); 2930 var page = (clips[pageIdx] && clips[pageIdx].canvas) || still; 2931 rctx.drawImage(page, 0, 0, w, h); 2932 if (vTrack && typeof vTrack.requestFrame === 'function') { 2933 try { 2934 vTrack.requestFrame(); 2935 } catch (eRfReady) {} 2936 } 2937 return; 2938 } 2939 rctx.fillStyle = fillBg; 2940 rctx.fillRect(0, 0, w, h); 2941 if (typeof qkPaintExportBackdrop === 'function') { 2942 qkPaintExportBackdrop(rctx, w, h); 2943 } 2944 if (!still) { 2945 if (edgeFrame) { 2946 qkTepsirDrawEdgeFrame(rctx, w, h, edgeFrame); 2947 } 2948 if (overlayImg && overlayImg.naturalWidth) { 2949 rctx.drawImage(overlayImg, 0, 0, w, h); 2950 } 2951 if (typeof qkDrawExportBrand === 'function') { 2952 qkDrawExportBrand(rctx); 2953 } 2954 return; 2955 } 2956 var ts = ease(t01 < 0.92 ? (t01 / 0.92) : 1); 2957 var tSec = t01 * totalDur; 2958 var clipIdx = qkClipIndexAtTime(clips, tSec); 2959 var ayahBoxes = (still && still._ayahBoxes) || qkClipAyahBoxes(clips); 2960 var srcBox = ayahBoxes[clipIdx] || ayahBoxes[0] || null; 2961 if (scroll) { 2962 var inner = frameM.inner; 2963 var pad = Math.max(8, Math.round(Math.min(inner.w, inner.h) * 0.012)); 2964 var box = { x: inner.x + pad, y: inner.y + pad, w: inner.w - pad * 2, h: inner.h - pad * 2 }; 2965 var foot = currentFooter || opts.footer || null; 2966 var footH = 0; 2967 var footDrawH = 0; 2968 if (typeof qkDrawExportBrand === 'function') { 2969 foot = null; 2970 } 2971 if (foot && foot.width && foot.height) { 2972 footDrawH = Math.round(foot.height * (box.w / foot.width)); 2973 footDrawH = Math.min(footDrawH, Math.round(box.h * 0.2)); 2974 footH = footDrawH + Math.round(pad * 0.45); 2975 } 2976 var contentY = box.y; 2977 var viewH = Math.max(8, box.h - footH); 2978 var scale = box.w / still.width; 2979 var ch = still.height * scale; 2980 var fits = ch <= viewH + 2; 2981 var y; 2982 var sy = ch / Math.max(1, still.height); 2983 var minY = contentY + viewH - ch; 2984 var maxY = contentY; 2985 if (fits) { 2986 y = contentY + Math.round((viewH - ch) / 2); 2987 } else if (srcBox) { 2988 var pieceY = srcBox.y * sy; 2989 var pieceH = Math.max(srcBox.h * sy, 24); 2990 if (centerBlocks) { 2991 y = contentY + Math.round(viewH / 2 - (pieceY + pieceH / 2)); 2992 } else { 2993 y = contentY - Math.round(pieceY); 2994 if (pieceH > viewH + 2) { 2995 y -= Math.round((pieceH - viewH) * ts); 2996 } 2997 } 2998 y = Math.max(minY, Math.min(maxY, y)); 2999 } else { 3000 y = contentY - (ch - viewH) * ts; 3001 } 3002 rctx.save(); 3003 rctx.beginPath(); 3004 rctx.rect(box.x, contentY, box.w, viewH); 3005 rctx.clip(); 3006 rctx.drawImage(still, box.x, y, box.w, ch);
3007 rctx.restore(); 3008 qkPulseAyahRegion(rctx, qkMapStillRect(qkPulseSrcBox(srcBox), still, box.x, y, box.w, ch), tSec); 3009 if (foot && footDrawH) { 3010 rctx.drawImage(foot, box.x, box.y + box.h - footDrawH, box.w, footDrawH); 3011 } 3012 } else if (still.width === w && still.height === h) { 3013 rctx.drawImage(still, 0, 0); 3014 qkPulseAyahRegion(rctx, qkMapStillRect(qkPulseSrcBox(srcBox), still, 0, 0, w, h), tSec); 3015 } else { 3016 var sc = Math.min(w / still.width, h / still.height); 3017 var dw = Math.max(1, Math.round(still.width * sc)); 3018 var dh = Math.max(1, Math.round(still.height * sc)); 3019 var dx = Math.round((w - dw) / 2); 3020 var dy = Math.round((h - dh) / 2); 3021 rctx.drawImage(still, dx, dy, dw, dh); 3022 qkPulseAyahRegion(rctx, qkMapStillRect(qkPulseSrcBox(srcBox), still, dx, dy, dw, dh), tSec); 3023 } 3024 if (edgeFrame) { 3025 qkTepsirDrawEdgeFrame(rctx, w, h, edgeFrame); 3026 } 3027 if (overlayImg && overlayImg.naturalWidth) { 3028 rctx.drawImage(overlayImg, 0, 0, w, h); 3029 } 3030 if (typeof qkDrawExportBrand === 'function') { 3031 qkDrawExportBrand(rctx); 3032 } 3033 if (vTrack && typeof vTrack.requestFrame === 'function') { 3034 try { 3035 vTrack.requestFrame(); 3036 } catch (eRf) {} 3037 } 3038 } 3039 function paintFrame() { 3040 var t01 = 0; 3041 if (videoStart && totalDur > 0.05) { 3042 t01 = (performance.now() - videoStart) / (totalDur * 1000); 3043 } else if (clipDur > 0.05 && clipStart) { 3044 t01 = (performance.now() - clipStart) / (clipDur * 1000); 3045 } 3046 paintAtProgress(t01); 3047 } 3048 paintFrame(); 3049 var fps = 30; 3050 var vStream = recCanvas.captureStream(fps); 3051 try { 3052 vTrack = vStream.getVideoTracks()[0] || null; 3053 if (vTrack) { 3054 vTrack.contentHint = 'detail'; 3055 vTrack.enabled = true; 3056 } 3057 } catch (eHint) {} 3058 var ac = qkUnlockAudioForRecord() || window._qkRecordAudioCtx; 3059 if (ac && ac.state === 'suspended' && ac.resume) { 3060 ac.resume(); 3061 } 3062 var dest = ac ? ac.createMediaStreamDestination() : null; 3063 var gain = ac ? ac.createGain() : null; 3064 if (gain) { 3065 gain.gain.value = 0.9; 3066 gain.connect(dest); 3067 gain.connect(ac.destination); 3068 } 3069 var tracks = vStream.getVideoTracks(); 3070 if (dest) { 3071 tracks = tracks.concat(dest.stream.getAudioTracks()); 3072 } 3073 tracks.forEach(function (t) { 3074 try { 3075 t.enabled = true; 3076 } catch (eEn) {} 3077 }); 3078 var mixed = new MediaStream(tracks); 3079 var mime = ''; 3080 var types = [ 3081 'video/mp4;codecs=avc1.42E01E,mp4a.40.2', 3082 'video/mp4;codecs=avc1.4d002a,mp4a.40.2', 3083 'video/mp4;codecs=avc1.42001f,mp4a.40.2', 3084 'video/mp4', 3085 'video/webm;codecs=vp8,opus', 3086 'video/webm' 3087 ]; 3088 for (var i = 0; i < types.length; i++) { 3089 if (MediaRecorder.isTypeSupported(types[i])) { 3090 mime = types[i]; 3091 break; 3092 } 3093 } 3094 var recOpts = { audioBitsPerSecond: 192000, videoBitsPerSecond: 6000000 }; 3095 if (mime) { 3096 recOpts.mimeType = mime; 3097 } 3098 var rec; 3099 try { 3100 rec = new MediaRecorder(mixed, recOpts); 3101 } catch (err) { 3102 try { 3103 rec = mime ? new MediaRecorder(mixed, { mimeType: mime }) : new MediaRecorder(mixed); 3104 } catch (err2) { 3105 reject(err2); 3106 return; 3107 } 3108 } 3109 var chunks = []; 3110 rec.ondataavailable = function (ev) { 3111 if (ev.data && ev.data.size) { 3112 chunks.push(ev.data); 3113 } 3114 }; 3115 var raf = 0; 3116 var clipTimer = null; 3117 var finished = false; 3118 var settled = false; 3119 var recStarted = false; 3120 var totalMs = 0; 3121 var currentSrc = null; 3122 function stopAnim() { 3123 if (raf) { 3124 cancelAnimationFrame(raf); 3125 raf = 0; 3126 } 3127 } 3128 function dropRecCanvas() { 3129 if (recCanvas && recCanvas.parentNode) { 3130 recCanvas.parentNode.removeChild(recCanvas); 3131 } 3132 } 3133 function tick() { 3134 if (finished) { 3135 return; 3136 } 3137 paintFrame(); 3138 raf = requestAnimationFrame(tick); 3139 } 3140 function finish() { 3141 if (finished) { 3142 return; 3143 } 3144 finished = true; 3145 stopAnim(); 3146 if (clipTimer) { 3147 clearTimeout(clipTimer); 3148 } 3149 try { 3150 if (currentSrc) { 3151 currentSrc.stop(0); 3152 } 3153 } catch (e3) {} 3154 if (recStarted && rec.state !== 'inactive') { 3155 try { 3156 rec.stop(); 3157 } catch (e2) {} 3158 return; 3159 } 3160 dropRecCanvas(); 3161 if (!settled) { 3162 settled = true; 3163 reject(new Error('empty')); 3164 } 3165 } 3166 rec.onstop = function () { 3167 stopAnim(); 3168 dropRecCanvas(); 3169 if (settled) { 3170 return; 3171 } 3172 settled = true; 3173 var type = rec.mimeType || mime || 'video/webm'; 3174 var isMp4 = /mp4/i.test(type); 3175 resolve({ blob: new Blob(chunks, { type: isMp4 ? 'video/mp4' : type }), ext: isMp4 ? 'mp4' : 'webm', duration: totalMs / 1000 }); 3176 }; 3177 function startRec() { 3178 if (recStarted || rec.state !== 'inactive') { 3179 return; 3180 } 3181 try { 3182 rec.start(1000); 3183 recStarted = true; 3184 } catch (eStart) { 3185 try { 3186 rec.start(); 3187 recStarted = true; 3188 } catch (eStart2) { 3189 settled = true; 3190 reject(new Error('start')); 3191 } 3192 }
3193 if (ac && ac.state === 'suspended' && ac.resume) { 3194 ac.resume(); 3195 } 3196 } 3197 function playClip(index) { 3198 if (finished) { 3199 return; 3200 } 3201 if (index >= clips.length) { 3202 finish(); 3203 return; 3204 } 3205 var clip = clips[index]; 3206 currentFooter = clip.footer || opts.footer || currentFooter || null; 3207 qkCaptureSetStatus((index + 1) + ' / ' + clips.length); 3208 var buf = clip.buffer; 3209 var dur = buf && buf.duration ? buf.duration : 0; 3210 if (!buf || !isFinite(dur) || dur < 0.2) { 3211 playClip(index + 1); 3212 return; 3213 } 3214 totalMs += dur * 1000; 3215 clipDur = dur; 3216 clipStart = performance.now(); 3217 if (!videoStart) { 3218 videoStart = clipStart; 3219 } 3220 paintFrame(); 3221 startRec(); 3222 try { 3223 if (currentSrc) { 3224 currentSrc.stop(0); 3225 } 3226 } catch (eStop) {} 3227 var src = ac.createBufferSource(); 3228 src.buffer = buf; 3229 src.connect(gain); 3230 currentSrc = src; 3231 src.onended = function () { 3232 if (finished) { 3233 return; 3234 } 3235 clipTimer = setTimeout(function () { 3236 playClip(index + 1); 3237 }, 80); 3238 }; 3239 try { 3240 src.start(0); 3241 } catch (ePlay) { 3242 playClip(index + 1); 3243 } 3244 } 3245 try { 3246 $('#audioPlayer').jPlayer('pause'); 3247 } catch (ePause) {} 3248 if (!ac || !dest || !gain) { 3249 reject(new Error('audio')); 3250 return; 3251 } 3252 var decodeSeq = Promise.resolve(); 3253 clips.forEach(function (clip) { 3254 decodeSeq = decodeSeq.then(function () { 3255 qkCaptureSetStatus('â¦'); 3256 return qkDecodeAudioBuffer(ac, clip.audioUrl).then(function (buf) { 3257 clip.buffer = buf; 3258 }); 3259 }); 3260 }); 3261 decodeSeq.then(function () { 3262 if (!opts.pageReady) { 3263 var stacked = opts.stackCanvas || qkStackClipCanvases(clips, fillBg); 3264 if (stacked) { 3265 still = stacked; 3266 } 3267 } 3268 if (still && !still._ayahBoxes) { 3269 still._ayahBoxes = qkClipAyahBoxes(clips); 3270 } 3271 totalDur = 0; 3272 clips.forEach(function (c) { 3273 if (c.buffer && c.buffer.duration && isFinite(c.buffer.duration)) { 3274 totalDur += c.buffer.duration; 3275 } 3276 }); 3277 if (totalDur < 0.2) { 3278 totalDur = clipDur || 1; 3279 } 3280 qkEncodeAyahVideoMp4({ 3281 canvas: recCanvas, 3282 paintAtProgress: paintAtProgress, 3283 clips: clips, 3284 ac: ac, 3285 w: w, 3286 h: h, 3287 fps: fps, 3288 totalDur: totalDur 3289 }).then(function (out) { 3290 finished = true; 3291 stopAnim(); 3292 dropRecCanvas(); 3293 if (!settled) { 3294 settled = true; 3295 resolve(out); 3296 } 3297 }).catch(function () { 3298 raf = requestAnimationFrame(tick); 3299 playClip(0); 3300 }); 3301 }).catch(function () { 3302 stopAnim(); 3303 dropRecCanvas(); 3304 reject(new Error('audio')); 3305 }); 3306 }); 3307} 3308 3309function qkSaveComposedCanvas(canvas, filename) { 3310 if (!canvas) { 3311 return; 3312 } 3313 var pages = (canvas._qkPages && canvas._qkPages.length) ? canvas._qkPages : [canvas]; 3314 if (pages.length > 1) { 3315 qkCaptureSetStatus(String(pages.length)); 3316 } 3317 pages.forEach(function (page, i) { 3318 var name = filename; 3319 if (pages.length > 1) { 3320 name = String(filename).replace(/\.jpg$/i, '-' + (i + 1) + '.jpg'); 3321 } 3322 setTimeout(function () { 3323 qkTepsirDownloadDataUrl(page.toDataURL('image/jpeg', 0.92), name); 3324 }, i * 400); 3325 }); 3326} 3327 3328function qkTepsirDownloadDataUrl(dataUrl, filename) { 3329 if (typeof window.simulateDownloadImageClick === 'function') { 3330 window.simulateDownloadImageClick(dataUrl, filename); 3331 return; 3332 } 3333 var a = document.createElement('a'); 3334 a.href = dataUrl; 3335 a.download = filename; 3336 document.body.appendChild(a); 3337 a.click(); 3338 document.body.removeChild(a); 3339} 3340 3341function qkTepsirWaitPaint() { 3342 return new Promise(function (resolve) { 3343 if (window.requestAnimationFrame) { 3344 window.requestAnimationFrame(function () { 3345 window.requestAnimationFrame(function () { 3346 resolve(); 3347 }); 3348 }); 3349 } else { 3350 setTimeout(resolve, 80); 3351 } 3352 }); 3353} 3354 3355function qkTepsirWaitCaptureAssets($root) { 3356 var loads = []; 3357 if (document.fonts && document.fonts.load) { 3358 loads.push(Promise.all([ 3359 document.fonts.load('1em UKIJEkran'), 3360 document.fonts.load('1em UKIJTuzBB'), 3361 document.fonts.load('1em hafs'), 3362 document.fonts.load('400 1em "Scheherazade New"'), 3363 document.fonts.load('400 1em Amiri') 3364 ]).then(function () { 3365 return document.fonts.ready; 3366 }).catch(function () { 3367 return document.fonts && document.fonts.ready ? document.fonts.ready : Promise.resolve(); 3368 })); 3369 } else if (document.fonts && document.fonts.ready) { 3370 loads.push(document.fonts.ready); 3371 } 3372 $root.find('img').each(function () { 3373 var img = this; 3374 if (img.complete) { 3375 return; 3376 } 3377 loads.push(new Promise(function (resolve) { 3378 img.onload = img.onerror = function () { 3379 resolve(); 3380 }; 3381 })); 3382 }); 3383 return Promise.all(loads).then(qkTepsirWaitPaint); 3384} 3385 3386function qkTepsirSanitizeExportClone($root, ayetNo, tafsirH) { 3387 if (!$root || !$root.length) { 3388 return $root; 3389 }
3390 $root.find('.qk-tepsir-about-wrap, .qk-tepsir-about-link, script, style, .progress, .izahat-box, .small-box, .accordion-button, .accordion-header').remove(); 3391 $root.find('a.qk-fn-link, a[id^="ftnt_ref"]').each(function () { 3392 $(this).replaceWith(document.createTextNode($(this).text())); 3393 }); 3394 var ugHeadFrom = 'ئاÙÛØªÙÛØ±ÙÙÚ Ø¨Ø§ØºÙÙÙÙØ´Ù'; 3395 var ugHeadTo = 'ئاÙÛØªÙÛØ±Ø¯Ù٠ئÛÙÙÙØºØ§Ù Ø¨ÛØ²Ù Ù¾Ø§ÙØ¯ÙÙØ§Ø±:'; 3396 $root.find('.qk-muhtasar-h, h4, p, strong').each(function () { 3397 var $el = $(this); 3398 if ($el.children().length > 1) { 3399 return; 3400 } 3401 var raw = ($el.text() || '').replace(/\s+/g, ' ').trim(); 3402 var stripped = raw.replace(/[:ï¼]\s*$/, ''); 3403 if (stripped === ugHeadFrom || raw.indexOf(ugHeadFrom) !== -1 && stripped.length <= ugHeadFrom.length + 2) { 3404 $el.text(ugHeadTo).addClass('qk-muhtasar-h'); 3405 } 3406 }); 3407 $root.find('.qk-jumle-ayetler-wrap, .qk-ehsen-ayetler-wrap, .qk-jumle-arabic-box, .qk-ehsen-arabic-box').addClass('qk-tepsir-capture-ayah-box'); 3408 tafsirH = ((tafsirH || $('#qkTepsirSaveImg').attr('data-tefsir-h') || 'تÛÙ¾Ø³ÙØ±Ù:').replace(/[\s:ï¼]+$/, '')) + ':'; 3409 if (!$root.find('.qk-tepsir-capture-tefsir-h').length) { 3410 var $arBox = $root.find('.qk-tepsir-capture-ayah-box, .qk-jumle-arabic-box, .qk-ehsen-arabic-box').first(); 3411 var $tefsirH = $('<div class="qk-tepsir-capture-tefsir-h"></div>').text(tafsirH); 3412 if ($arBox.length) { 3413 $arBox.after($tefsirH); 3414 } else { 3415 $root.prepend($tefsirH); 3416 } 3417 } 3418 if (ayetNo) { 3419 var $mez = $root.find('.tepsir-izahat, .qk-tepsir-mezmun').first(); 3420 if ($mez.length && !$mez.find('.qk-tepsir-mezmun-no').length) { 3421 var lead = ($mez.text() || '').replace(/^\s+/, ''); 3422 if (!/^\d{1,3}\s*[_\-â.]/.test(lead)) { 3423 var $mark = $('<span class="qk-tepsir-mezmun-no"></span>').text(ayetNo + ' _ '); 3424 var $p = $mez.find('p').first(); 3425 if ($p.length) { 3426 $p.prepend($mark); 3427 } else { 3428 $mez.prepend($mark); 3429 } 3430 } 3431 } 3432 } 3433 return $root; 3434} 3435 3436function qkTepsirSnapshotFitted(btn, sureNo, ayetNo, onScreen, shotOpts) { 3437 shotOpts = shotOpts || {}; 3438 var $btn = $(btn); 3439 var $src = $('#tepsirData .qk-tepsir-sheet, #tepsirData .tepsir').first(); 3440 if (!$src.length) { 3441 $src = $('#tepsirData'); 3442 } 3443 if (!$src.length || !$src.text().replace(/\s+/g, '')) { 3444 return Promise.reject(new Error('empty')); 3445 } 3446 var $host = $('#qkTepsirCaptureHost'); 3447 if (!$host.length) { 3448 $host = $('<div id="qkTepsirCaptureHost"></div>').appendTo(document.body); 3449 } 3450 var $clone = $src.clone(false, false); 3451 qkTepsirSanitizeExportClone($clone, ayetNo, $btn.attr('data-tefsir-h'));
3452 var sureName = qkTepsirSureName(sureNo); 3453 var tafsirName = qkTepsirDisplayName(); 3454 var tafsirTbl = ($('#tepsirSelector').val() || '').replace(/\s+/g, ''); 3455 var ayahLbl = $btn.attr('data-ayah') || ''; 3456 var metaBits = []; 3457 if (sureName) { 3458 metaBits.push(sureName); 3459 } 3460 if (ayetNo) { 3461 metaBits.push(ayetNo + (ayahLbl ? '-' + ayahLbl : '')); 3462 } 3463 var $card = $('<div class="qk-tepsir-capture-card"></div>'); 3464 if (tafsirTbl) { 3465 $card.attr('data-tepsir-tbl', tafsirTbl); 3466 } 3467 qkApplyExportStyle($card, 'tepsir'); 3468 if (!shotOpts.skipTitle) { 3469 $card.append($('<div class="qk-tepsir-capture-title"></div>').text(tafsirName)); 3470 } 3471 if (shotOpts.rangeText) { 3472 $card.append($('<div class="qk-tepsir-capture-range"></div>').text(shotOpts.rangeText)); 3473 } 3474 var $inner = $('<div class="qk-tepsir-capture-inner"></div>'); 3475 $inner.append($('<div class="qk-tepsir-capture-body"></div>').append($clone)); 3476 if (metaBits.length && !shotOpts.skipMeta) { 3477 $inner.append($('<div class="qk-tepsir-capture-meta"></div>').text(metaBits.join(' · '))); 3478 } 3479 var $brand = qkExportBrandNode('#fffefb', false); 3480 $card.append($inner); 3481 $host.empty().append($card).removeAttr('hidden'); 3482 if (onScreen) { 3483 $host.addClass('is-capturing'); 3484 } 3485 if (typeof qkPrepareExportClone === 'function') { 3486 qkPrepareExportClone($card, 720, 'qkTepsirSize'); 3487 } 3488 var bodyCanvas = null; 3489 return qkTepsirWaitCaptureAssets($card).then(function () { 3490 var w = Math.max($card[0].scrollWidth, $card.outerWidth() || 0, 720);
3491 var h = Math.max($card[0].scrollHeight, $card.outerHeight() || 0, 1); 3492 var boxes = qkMeasureAyahBoxes($card); 3493 return window.html2canvas($card[0], { 3494 backgroundColor: '#fffefb', 3495 scale: Math.min(window.devicePixelRatio || 1, 2), 3496 useCORS: true, 3497 allowTaint: true, 3498 logging: false, 3499 width: w, 3500 height: h 3501 }).then(function (canvas) { 3502 canvas._ayahBoxes = qkAyahBoxesToCanvas(boxes, w, canvas); 3503 return canvas; 3504 }); 3505 }).then(function (canvas) { 3506 bodyCanvas = canvas; 3507 $host.empty().append($brand).removeAttr('hidden'); 3508 return qkTepsirWaitCaptureAssets($brand).then(function () { 3509 return qkCanvasFromEl($brand, '#fffefb', 720); 3510 }); 3511 }).then(function (footer) { 3512 $host.empty().removeClass('is-capturing').attr('hidden', 'hidden'); 3513 return { canvas: bodyCanvas, footer: footer, bg: '#fffefb', ayahBoxes: bodyCanvas._ayahBoxes || [] }; 3514 }); 3515} 3516 3517function qkTepsirDisplayName() { 3518 var $opt = $('#tepsirSelector option:selected'); 3519 var name = ($opt.text() || '').replace(/\s+/g, ' ').trim(); 3520 if (name) { 3521 return name; 3522 } 3523 var tbl = ($('#tepsirSelector').val() || '').replace(/^tepsir_/, '').replace(/_/g, ' '); 3524 return tbl || 'تÛÙ¾Ø³ÙØ±'; 3525} 3526 3527function qkTepsirAyahRangeText(from, to, ayahWord) { 3528 from = parseInt(from, 10) || 1; 3529 to = parseInt(to, 10) || from; 3530 ayahWord = (ayahWord || '').replace(/^\s+|\s+$/g, ''); 3531 if (to > from) { 3532 return from + '-' + to + (ayahWord ? '-' + ayahWord : ''); 3533 } 3534 return from + (ayahWord ? '-' + ayahWord : ''); 3535} 3536 3537function qkTepsirCaptureHeadCanvas(btn, sureNo, from, to) { 3538 var tafsirName = qkTepsirDisplayName(); 3539 var tafsirTbl = ($('#tepsirSelector').val() || '').replace(/\s+/g, '');
3540 var sureName = qkTepsirSureName(sureNo); 3541 var ayahWord = (($(btn).attr('data-ayah') || $('#qkTepsirSaveImg').attr('data-ayah') || '') + '').trim(); 3542 var $card = $('<div class="qk-tepsir-capture-card"></div>').css({ 3543 width: '720px', 3544 minHeight: '120px', 3545 background: '#fffefb' 3546 }); 3547 if (tafsirTbl) { 3548 $card.attr('data-tepsir-tbl', tafsirTbl); 3549 } 3550 $card.append($('<div class="qk-tepsir-capture-title"></div>').text(tafsirName)); 3551 var bits = []; 3552 if (sureName) { 3553 bits.push(sureName); 3554 } 3555 bits.push(qkTepsirAyahRangeText(from, to, ayahWord)); 3556 $card.append($('<div class="qk-tepsir-capture-range"></div>').text(bits.join(' ⢠'))); 3557 var $host = $('#qkTepsirCaptureHost'); 3558 if (!$host.length) { 3559 $host = $('<div id="qkTepsirCaptureHost"></div>').appendTo(document.body); 3560 } 3561 $host.empty().append($card).removeAttr('hidden').addClass('is-capturing'); 3562 return qkTepsirWaitCaptureAssets($card).then(function () { 3563 return window.html2canvas($card[0], { 3564 backgroundColor: '#0d7377', 3565 scale: Math.min(window.devicePixelRatio || 1, 2), 3566 useCORS: true, 3567 allowTaint: true, 3568 logging: false, 3569 width: 720, 3570 height: Math.max($card[0].scrollHeight, $card.outerHeight() || 0, 120) 3571 }); 3572 }).then(function (canvas) { 3573 $host.empty().removeClass('is-capturing').attr('hidden', 'hidden'); 3574 return canvas; 3575 }); 3576} 3577 3578var qkTepsirPreviewGen = 0; 3579 3580function qkTepsirExportPanelOpen() { 3581 return $('#qkTepsirExportPanel').length && $('#qkTepsirExportPanel').attr('hidden') == null; 3582} 3583 3584function qkTepsirHideExportPreview() { 3585 qkTepsirPreviewGen += 1; 3586 $('#qkTepsirExportPreview').empty().attr('hidden', 'hidden'); 3587 $('#tepsirData').removeAttr('hidden'); 3588} 3589 3590function qkTepsirFetchHtml(sure, ayet) { 3591 return new Promise(function (resolve) { 3592 $.ajax({ 3593 url: qkTepsirLoadUrl(qkGetSelectedTepsirId(), sure, ayet), 3594 dataType: 'html' 3595 }).done(function (html) { 3596 resolve(html || ''); 3597 }).fail(function () { 3598 resolve(''); 3599 }); 3600 }); 3601} 3602 3603function qkTepsirBuildRangePreviewCard(items, sureNo, from, to) { 3604 var $card = $('<div class="qk-tepsir-capture-card"></div>'); 3605 var tbl = ($('#tepsirSelector').val() || '').replace(/\s+/g, ''); 3606 if (tbl) { 3607 $card.attr('data-tepsir-tbl', tbl); 3608 } 3609 qkApplyExportStyle($card, 'tepsir'); 3610 $card.append($('<div class="qk-tepsir-capture-title"></div>').text(qkTepsirDisplayName())); 3611 var bits = [];
3612 var sureName = qkTepsirSureName(sureNo); 3613 if (sureName) { 3614 bits.push(sureName); 3615 } 3616 bits.push(qkTepsirAyahRangeText(from, to, ($('#qkTepsirSaveImg').attr('data-ayah') || '') + '')); 3617 $card.append($('<div class="qk-tepsir-capture-range"></div>').text(bits.join(' ⢠'))); 3618 var $body = $('<div class="qk-tepsir-capture-body"></div>'); 3619 var seenHtml = {}; 3620 items.forEach(function (item) { 3621 var fp = String(item.html || '').replace(/\s+/g, ' ').trim(); 3622 if (fp && seenHtml[fp]) { 3623 return; 3624 } 3625 if (fp) { 3626 seenHtml[fp] = 1; 3627 } 3628 var $piece = $('<div class="qk-tepsir-export-ayah-piece"></div>').html(item.html); 3629 qkTepsirSanitizeExportClone($piece, item.ayet); 3630 $piece.attr('data-ayah', item.ayet).attr('data-ayah-ar', qkExtractAyahArabic($piece)); 3631 $body.append($piece); 3632 }); 3633 $card.append($('<div class="qk-tepsir-capture-inner"></div>').append($body)); 3634 var $brand = qkExportBrandNode('#fffefb', false); 3635 $brand.css({ width: '100%', maxWidth: '100%' }); 3636 $card.append($brand); 3637 return $card; 3638} 3639 3640function qkTepsirRefreshExportPreview() { 3641 var $preview = $('#qkTepsirExportPreview'); 3642 if (!$preview.length) { 3643 return Promise.resolve(); 3644 } 3645 if (!qkTepsirExportPanelOpen()) { 3646 qkTepsirHideExportPreview(); 3647 return Promise.resolve(); 3648 } 3649 var sureNo = parseInt(selectedSureNo, 10) || 0; 3650 var ayetNo = parseInt(selectedAyetNo, 10) || 0; 3651 var range = qkReadAyahRange('qkTepsirAyahFrom', 'qkTepsirAyahTo', sureNo, ayetNo); 3652 if (!sureNo || range.to <= range.from) { 3653 qkTepsirHideExportPreview(); 3654 return Promise.resolve(); 3655 } 3656 var gen = ++qkTepsirPreviewGen; 3657 var ayahs = []; 3658 var a; 3659 for (a = range.from; a <= range.to; a++) { 3660 ayahs.push(a); 3661 } 3662 $('#tepsirData').attr('hidden', 'hidden'); 3663 $preview.removeAttr('hidden').html('<div class="text-center p-4"><div class="spinner-border text-primary"></div></div>'); 3664 return Promise.all(ayahs.map(function (n) { 3665 return qkTepsirFetchHtml(sureNo, n).then(function (html) { 3666 return { ayet: n, html: html }; 3667 }); 3668 })).then(function (items) { 3669 if (gen !== qkTepsirPreviewGen) { 3670 return; 3671 } 3672 items = (items || []).filter(function (item) { 3673 return item && item.html && String(item.html).replace(/\s+/g, ''); 3674 }); 3675 if (!items.length) { 3676 qkTepsirHideExportPreview(); 3677 return; 3678 } 3679 $preview.empty().append(qkTepsirBuildRangePreviewCard(items, sureNo, range.from, range.to)); 3680 }); 3681} 3682 3683function qkTepsirSnapshotExportPreview() { 3684 var $src = $('#qkTepsirExportPreview .qk-tepsir-capture-card').first(); 3685 if (!$src.length) { 3686 return Promise.reject(new Error('empty')); 3687 } 3688 var $host = $('#qkTepsirCaptureHost'); 3689 if (!$host.length) { 3690 $host = $('<div id="qkTepsirCaptureHost"></div>').appendTo(document.body); 3691 } 3692 var $card = $src.clone(false, false); 3693 $card.find('.qk-tepsir-capture-brand').remove(); 3694 $card.css({ 3695 width: '720px', 3696 maxWidth: '720px', 3697 height: 'auto', 3698 overflow: 'visible' 3699 }); 3700 $host.empty().append($card).removeAttr('hidden').addClass('is-capturing'); 3701 if (typeof qkPrepareExportClone === 'function') { 3702 qkPrepareExportClone($card, 720, 'qkTepsirSize'); 3703 } 3704 var bodyCanvas = null; 3705 return qkTepsirWaitCaptureAssets($card).then(function () { 3706 var w = Math.max($card[0].scrollWidth, $card.outerWidth() || 0, 720);
3707 var h = Math.max($card[0].scrollHeight, $card.outerHeight() || 0, 1); 3708 var boxes = qkMeasureAyahBoxes($card); 3709 return window.html2canvas($card[0], { 3710 backgroundColor: '#fffefb', 3711 scale: Math.min(window.devicePixelRatio || 1, 2), 3712 useCORS: true, 3713 allowTaint: true, 3714 logging: false, 3715 width: w, 3716 height: h 3717 }).then(function (canvas) { 3718 canvas._ayahBoxes = qkAyahBoxesToCanvas(boxes, w, canvas); 3719 return canvas; 3720 }); 3721 }).then(function (canvas) { 3722 bodyCanvas = canvas; 3723 var $brand = qkExportBrandNode('#fffefb', false); 3724 $host.empty().append($brand).removeAttr('hidden'); 3725 return qkTepsirWaitCaptureAssets($brand).then(function () { 3726 return qkCanvasFromEl($brand, '#fffefb', 720); 3727 }); 3728 }).then(function (footer) { 3729 $host.empty().removeClass('is-capturing').attr('hidden', 'hidden'); 3730 return { canvas: bodyCanvas, footer: footer, bg: '#fffefb', ayahBoxes: bodyCanvas._ayahBoxes || [] }; 3731 }); 3732} 3733 3734window.qkTepsirRefreshExportPreview = qkTepsirRefreshExportPreview; 3735window.qkTepsirHideExportPreview = qkTepsirHideExportPreview; 3736 3737function qkTepsirStackRangeClips(clips, btn, sureNo, from, to, bg) { 3738 return Promise.resolve(qkStackClipCanvases(clips || [], bg || '#fffefb')); 3739} 3740 3741function qkTepsirCollectRangeClips(btn, sureNo, from, to, collectOpts) { 3742 collectOpts = collectOpts || {}; 3743 var originSure = selectedSureNo; 3744 var originAyet = selectedAyetNo; 3745 var clips = []; 3746 var seq = Promise.resolve(); 3747 var a; 3748 for (a = from; a <= to; a++) { 3749 seq = seq.then((function (ayet) { 3750 return function () { 3751 qkCaptureSetStatus(ayet + ' / ' + to); 3752 return qkTepsirReloadContent(sureNo, ayet).then(function () { 3753 return qkTepsirWaitCaptureAssets($('#tepsirData')); 3754 }).then(function () { 3755 var rangeText = ''; 3756 if (ayet === from && to > from) { 3757 var bits = [];
3758 var sureName = qkTepsirSureName(sureNo); 3759 if (sureName) { 3760 bits.push(sureName); 3761 } 3762 bits.push(qkTepsirAyahRangeText(from, to, ($(btn).attr('data-ayah') || $('#qkTepsirSaveImg').attr('data-ayah') || '') + '')); 3763 rangeText = bits.join(' ⢠'); 3764 } 3765 return qkTepsirSnapshotFitted(btn, sureNo, ayet, ayet === from, { 3766 skipTitle: ayet !== from, 3767 skipMeta: true, 3768 rangeText: rangeText 3769 }); 3770 }).then(function (shot) { 3771 var url = qkAyahAudioUrl(sureNo, ayet); 3772 if (collectOpts.requireAudio !== false && !url) { 3773 return; 3774 } 3775 clips.push({ 3776 canvas: shot.canvas || shot, 3777 audioUrl: url || '', 3778 footer: shot.footer || null, 3779 ayahText: qkAyahArabicText(sureNo, ayet) 3780 }); 3781 }); 3782 }; 3783 })(a)); 3784 } 3785 return seq.then(function () { 3786 return qkTepsirReloadContent(originSure, originAyet).then(function () { 3787 return clips; 3788 }); 3789 }); 3790} 3791 3792function qkDownloadVideoOut(out, filename) { 3793 var url = URL.createObjectURL(out.blob); 3794 qkTepsirDownloadDataUrl(url, filename); 3795 setTimeout(function () { 3796 URL.revokeObjectURL(url); 3797 }, 8000); 3798} 3799 3800function qkTepsirSaveAsImage(btn, opts) { 3801 opts = opts || {}; 3802 var $btn = $(btn); 3803 if ($btn.data('busy')) { 3804 return; 3805 } 3806 if (typeof window.html2canvas !== 'function') { 3807 showToast($btn.attr('data-fail') || 'Save failed'); 3808 return; 3809 } 3810 var sureNo = parseInt(selectedSureNo, 10) || 0; 3811 var ayetNo = parseInt(selectedAyetNo, 10) || 0; 3812 var range = qkReadAyahRange('qkTepsirAyahFrom', 'qkTepsirAyahTo', sureNo, ayetNo); 3813 var tafsirTbl = ($('#tepsirSelector').val() || '').replace(/\s+/g, ''); 3814 var slug = (tafsirTbl || 'tepsir').replace(/^tepsir_/, ''); 3815 var base = slug + '-' + (sureNo || 's') + '-' + range.from + (range.to > range.from ? '-' + range.to : ''); 3816 $btn.data('busy', 1).prop('disabled', true); 3817 qkCaptureSetStatus(''); 3818 if (opts.video) { 3819 qkUnlockAudioForRecord(); 3820 } 3821 var work; 3822 if (opts.video && typeof window.qkExportReadyPages === 'function') { 3823 var prepTv = (range.to > range.from) ? qkTepsirRefreshExportPreview() : Promise.resolve(); 3824 work = Promise.resolve(prepTv).then(function () { 3825 return window.qkExportReadyPages('tepsir'); 3826 }).then(function (pages) { 3827 if (!pages || !pages.length) { 3828 throw new Error('empty'); 3829 } 3830 var clips = []; 3831 var a; 3832 var span = range.to - range.from + 1; 3833 for (a = range.from; a <= range.to; a++) { 3834 var url = qkAyahAudioUrl(sureNo, a); 3835 if (url) { 3836 clips.push({ 3837 canvas: pages.length === span ? pages[a - range.from] : pages[0], 3838 audioUrl: url, 3839 ayahText: qkAyahArabicText(sureNo, a) 3840 }); 3841 } 3842 } 3843 if (!clips.length) { 3844 throw new Error('clips'); 3845 } 3846 return qkRecordAyahVideoClips(clips, { 3847 scroll: false, 3848 pageReady: true, 3849 size: qkTepsirExportSize(), 3850 bg: '#fffefb' 3851 }).then(function (out) { 3852 qkDownloadVideoOut(out, base + '.' + out.ext); 3853 }); 3854 }); 3855 } else if (!opts.video && typeof window.qkExportReadyPages === 'function') { 3856 var prepT = (range.to > range.from) ? qkTepsirRefreshExportPreview() : Promise.resolve(); 3857 work = Promise.resolve(prepT).then(function () { 3858 return window.qkExportReadyPages('tepsir'); 3859 }).then(function (pages) { 3860 if (!pages || !pages.length) { 3861 throw new Error('empty'); 3862 } 3863 pages[0]._qkPages = pages; 3864 qkSaveComposedCanvas(pages[0], base + '.jpg'); 3865 }); 3866 } else if (range.to > range.from) { 3867 work = qkTepsirRefreshExportPreview().then(function () { 3868 if (!$('#qkTepsirExportPreview .qk-tepsir-capture-card').length) { 3869 throw new Error('empty'); 3870 } 3871 qkCaptureSetStatus(''); 3872 return qkTepsirSnapshotExportPreview(); 3873 }).then(function (shot) { 3874 if (opts.video) { 3875 var clips = []; 3876 var a; 3877 for (a = range.from; a <= range.to; a++) { 3878 var url = qkAyahAudioUrl(sureNo, a); 3879 if (url) { 3880 clips.push({ 3881 canvas: shot.canvas, 3882 audioUrl: url, 3883 footer: shot.footer, 3884 ayahText: qkAyahArabicText(sureNo, a), 3885 ayahBoxes: shot.ayahBoxes || (shot.canvas && shot.canvas._ayahBoxes) || [] 3886 }); 3887 } 3888 } 3889 if (!clips.length) { 3890 throw new Error('clips'); 3891 } 3892 return qkRecordAyahVideoClips(clips, { 3893 scroll: true, 3894 edgeFrame: qkTepsirExportFrame(), 3895 size: qkTepsirExportSize(), 3896 footer: shot.footer, 3897 bg: '#fffefb', 3898 stackCanvas: shot.canvas 3899 }).then(function (out) { 3900 qkDownloadVideoOut(out, base + '.' + out.ext); 3901 }); 3902 } 3903 var fitted = qkTepsirComposeExportCanvas(shot.canvas, qkTepsirExportSize(), qkTepsirExportFrame(), '#fffefb', shot.footer, true); 3904 qkSaveComposedCanvas(fitted, base + '.jpg'); 3905 }); 3906 } else { 3907 work = qkTepsirSnapshotFitted(btn, sureNo, ayetNo, true).then(function (shot) { 3908 var content = shot.canvas || shot; 3909 var footer = shot.footer || null; 3910 if (opts.video) { 3911 var audioUrl = qkAyahAudioUrl(sureNo, ayetNo); 3912 if (!audioUrl) { 3913 throw new Error('audio'); 3914 } 3915 return qkTepsirRecordAyahVideo(content, audioUrl, { footer: footer, bg: shot.bg || '#fffefb', ayahBoxes: shot.ayahBoxes || (content && content._ayahBoxes) || [] }).then(function (out) { 3916 qkDownloadVideoOut(out, base + '.' + out.ext); 3917 }); 3918 } 3919 var fitted = qkTepsirComposeExportCanvas(content, qkTepsirExportSize(), qkTepsirExportFrame(), shot.bg || '#fffefb', footer); 3920 qkSaveComposedCanvas(fitted, base + '.jpg'); 3921 }); 3922 }
3923 work.catch(function () { 3924 showToast($btn.attr('data-fail') || 'Save failed'); 3925 }).then(function () { 3926 qkCaptureSetStatus(''); 3927 var $host = $('#qkTepsirCaptureHost'); 3928 $host.empty().removeClass('is-capturing').attr('hidden', 'hidden'); 3929 $btn.data('busy', 0).prop('disabled', false); 3930 }); 3931} 3932 3933function qkCaptureLoadPreviewPromise(sure, ayet) { 3934 return new Promise(function (resolve) { 3935 if (typeof window.qkLoadCapturePreview !== 'function') { 3936 resolve(); 3937 return; 3938 } 3939 window.qkLoadCapturePreview(sure, ayet, 0, resolve); 3940 }); 3941} 3942 3943function qkCaptureFrameKey($frame) { 3944 if (!$frame || !$frame.length) { 3945 return 'qk-frame-classic'; 3946 } 3947 var m = ($frame.attr('class') || '').match(/qk-frame-(classic|gold|parchment|emerald|midnight|img|double|ornate|navy|burgundy|plain|teal)/); 3948 return m ? ('qk-frame-' + m[1]) : 'qk-frame-classic'; 3949} 3950 3951function qkCaptureInnerSnapshot() { 3952 var $stage = $('#captureData'); 3953 var $frame = $stage.find('.print-border, .qk-print-frame').first(); 3954 var $inner = $frame.find('.qk-print-inner').first(); 3955 if (!$inner.length) { 3956 $inner = $frame; 3957 } 3958 if (!$inner.length) { 3959 return Promise.reject(new Error('frame')); 3960 } 3961 var bg = $frame.css('background-color') || '#ffffff'; 3962 if (!bg || bg === 'rgba(0, 0, 0, 0)' || bg === 'transparent') { 3963 bg = '#ffffff'; 3964 } 3965 var overlay = $frame.find('.qk-frame-overlay').get(0) || null; 3966 var $host = $('#qkTepsirCaptureHost'); 3967 if (!$host.length) { 3968 $host = $('<div id="qkTepsirCaptureHost"></div>').appendTo(document.body); 3969 } 3970 var $clone = $inner.clone(false, false); 3971 $clone.find('script, .qk-frame-overlay, .print-social-footer, .web-p').remove(); 3972 qkApplyExportStyle($clone, 'capture'); 3973 var layoutW = 720; 3974 $clone.css({ 3975 width: layoutW + 'px', 3976 maxWidth: layoutW + 'px', 3977 height: 'auto', 3978 overflow: 'visible', 3979 position: 'relative', 3980 background: bg, 3981 display: 'block', 3982 flex: 'none', 3983 minHeight: '0' 3984 }); 3985 $clone.find('.qk-capture-ayah-stack').css({ 3986 overflow: 'visible', 3987 height: 'auto', 3988 maxHeight: 'none', 3989 flex: 'none', 3990 minHeight: '0' 3991 }); 3992 $clone.css({ 3993 paddingTop: '0', 3994 paddingBottom: '0', 3995 justifyContent: 'flex-start' 3996 }); 3997 $host.empty().append($clone).removeAttr('hidden'); 3998 if (typeof qkPrepareExportClone === 'function') { 3999 qkPrepareExportClone($clone, layoutW, 'qkCaptureSize'); 4000 } 4001 var bodyCanvas = null; 4002 var frameKey = qkCaptureFrameKey($frame); 4003 var dark = frameKey === 'qk-frame-midnight'; 4004 return qkTepsirWaitCaptureAssets($clone).then(function () { 4005 qkShrinkWrapExportNode($clone); 4006 var w = Math.max($clone[0].scrollWidth, layoutW); 4007 var h = Math.max($clone[0].scrollHeight, 1); 4008 var boxes = qkMeasureAyahBoxes($clone); 4009 return window.html2canvas($clone[0], { 4010 backgroundColor: bg, 4011 scale: Math.min(window.devicePixelRatio || 1, 2), 4012 useCORS: true, 4013 allowTaint: true, 4014 logging: false, 4015 width: w, 4016 height: h 4017 }).then(function (canvas) { 4018 canvas._ayahBoxes = qkAyahBoxesToCanvas(boxes, w, canvas); 4019 return qkCropCanvasToInk(canvas, canvas._ayahBoxes); 4020 }); 4021 }).then(function (canvas) { 4022 bodyCanvas = canvas; 4023 $host.empty(); 4024 return qkCaptureBrandFooter(bg, dark); 4025 }).then(function (footer) { 4026 $host.empty().removeClass('is-capturing').attr('hidden', 'hidden'); 4027 return { 4028 canvas: bodyCanvas, 4029 footer: footer, 4030 bg: bg, 4031 frameKey: frameKey, 4032 overlay: overlay, 4033 ayahBoxes: bodyCanvas._ayahBoxes || [] 4034 }; 4035 }); 4036} 4037 4038function qkCapturePrintCanvas(sure, ayet, size) { 4039 return qkCaptureLoadPreviewPromise(sure, ayet).then(function () { 4040 qkApplyCaptureSizePreview(); 4041 return qkCaptureInnerSnapshot(); 4042 }).then(function (info) { 4043 var out = qkTepsirComposeExportCanvas(info.canvas, size, info.frameKey, info.bg, info.footer); 4044 return out; 4045 }); 4046} 4047 4048function qkCaptureExport(opts) { 4049 opts = opts || {}; 4050 var $btn = $(opts.video ? '#captureBtnVideo' : '#captureBtn'); 4051 if ($btn.data('busy')) { 4052 return; 4053 } 4054 if (typeof window.html2canvas !== 'function') { 4055 showToast($('#qkTepsirSaveImg').attr('data-fail') || 'Save failed'); 4056 return; 4057 } 4058 var isDua = $('#captureData .dprint').length > 0; 4059 if (isDua && opts.video) { 4060 showToast($('#qkTepsirSaveImg').attr('data-fail') || 'Save failed'); 4061 return; 4062 } 4063 var sureNo = parseInt(selectedSureNo, 10) || 0; 4064 var ayetNo = parseInt(selectedAyetNo, 10) || 0; 4065 var range = qkReadAyahRange('qkCaptureAyahFrom', 'qkCaptureAyahTo', sureNo, ayetNo); 4066 var size = qkExportSizeFrom('qkCaptureSize'); 4067 var base = isDua ? 'dua' : ((sureNo || 's') + '-' + range.from + (range.to > range.from ? '-' + range.to : '')); 4068 $btn.data('busy', 1).prop('disabled', true); 4069 $('#captureBtn, #captureBtnVideo').prop('disabled', true); 4070 qkCaptureSetStatus(''); 4071 if (opts.video) { 4072 qkUnlockAudioForRecord(); 4073 } 4074 var work; 4075 if (!opts.video && typeof window.qkExportReadyPages === 'function') { 4076 var prepCap = isDua ? Promise.resolve() : qkCaptureLoadPreviewPromise(sureNo, range.from); 4077 work = prepCap.then(function () { 4078 return window.qkExportReadyPages('capture'); 4079 }).then(function (pages) { 4080 if (!pages || !pages.length) { 4081 throw new Error('empty'); 4082 } 4083 pages[0]._qkPages = pages; 4084 qkSaveComposedCanvas(pages[0], base + '.jpg'); 4085 }); 4086 } else if (isDua) { 4087 work = Promise.resolve().then(function () { 4088 qkApplyCaptureSizePreview(); 4089 return qkCaptureInnerSnapshot(); 4090 }).then(function (info) { 4091 var out = qkTepsirComposeExportCanvas(info.canvas, size, info.frameKey, info.bg, info.footer, false); 4092 qkSaveComposedCanvas(out, base + '.jpg'); 4093 }); 4094 } else if (opts.video) { 4095 work = qkCaptureLoadPreviewPromise(sureNo, range.from).then(function () { 4096 return window.qkExportReadyPages('capture'); 4097 }).then(function (pages) { 4098 if (!pages || !pages.length) { 4099 throw new Error('empty'); 4100 } 4101 var clips = []; 4102 var a; 4103 var span = range.to - range.from + 1; 4104 for (a = range.from; a <= range.to; a++) { 4105 var url = qkAyahAudioUrl(sureNo, a); 4106 if (url) { 4107 var page = pages.length === span ? pages[a - range.from] : pages[0]; 4108 clips.push({ 4109 canvas: page, 4110 audioUrl: url, 4111 ayahText: qkAyahArabicText(sureNo, a) 4112 }); 4113 } 4114 } 4115 if (!clips.length) { 4116 throw new Error('clips'); 4117 } 4118 return qkRecordAyahVideoClips(clips, { 4119 scroll: false, 4120 pageReady: true, 4121 size: size, 4122 bg: '#fffefb' 4123 }).then(function (out) { 4124 qkDownloadVideoOut(out, base + '.' + out.ext); 4125 }); 4126 }); 4127 } else { 4128 work = qkCaptureLoadPreviewPromise(sureNo, range.from).then(function () { 4129 qkApplyCaptureSizePreview(); 4130 return qkCaptureInnerSnapshot(); 4131 }).then(function (info) { 4132 var out = qkTepsirComposeExportCanvas(info.canvas, size, info.frameKey, info.bg, info.footer, range.to > range.from); 4133 qkSaveComposedCanvas(out, base + '.jpg'); 4134 }); 4135 }
4136 work.catch(function () { 4137 showToast($('#qkTepsirSaveImg').attr('data-fail') || 'Save failed'); 4138 }).then(function () { 4139 qkCaptureSetStatus(''); 4140 $btn.data('busy', 0); 4141 $('#captureBtn, #captureBtnVideo').prop('disabled', false); 4142 }); 4143} 4144 4145window.qkCaptureExport = qkCaptureExport; 4146 4147(function () { 4148 document.addEventListener('copy', function (e) { 4149 try { 4150 if (!e.clipboardData || !window.getSelection) { 4151 return; 4152 } 4153 var text = String(window.getSelection()); 4154 if (text.length < 320) { 4155 return; 4156 } 4157 if (/qurankerim\.com/i.test(text)) { 4158 return; 4159 } 4160 e.clipboardData.setData('text/plain', text.replace(/\s+$/, '') + '\n\nâ https://www.qurankerim.com'); 4161 e.preventDefault(); 4162 } catch (err) {} 4163 }); 4164})(); 4165 4166 4167
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.