MediaWiki: Tweeki.js: Perbedaan antara revisi
Dari GBI Danau Bogor Raya
k Daftar isi: sinkron ScrollSpy dengan coba ulang (ScrollSpy Tweeki bisa dibuat belakangan) |
Tweeki.js: Masonry hanya untuk .grid yang berisi .grid-item (badan accordion Templat:BootstrapAccordion2Collapse ikut berkelas .grid dan jadi setinggi 0, isinya menimpa bagian bawah). |
||
| Baris 54: | Baris 54: | ||
// MASONRY: .grid > .grid-item. Library dimuat async dari CDN (hook BeforePageDisplay di | // MASONRY: .grid > .grid-item. Library dimuat async dari CDN (hook BeforePageDisplay di | ||
// LocalSettings), jadi bisa belum tersedia saat file ini jalan -> coba lagi saat window load. | // LocalSettings), jadi bisa belum tersedia saat file ini jalan -> coba lagi saat window load. | ||
var | // Hanya .grid yang benar-benar berisi .grid-item: badan accordion di Templat:BootstrapAccordion2Collapse | ||
// juga berkelas .grid tanpa item, dan Masonry membuatnya setinggi 0 sehingga isinya menimpa bagian bawahnya. | |||
var msnrys = []; | |||
function initMasonry() { | function initMasonry() { | ||
if (msnrys.length || typeof Masonry === 'undefined') { | |||
return; | return; | ||
} | } | ||
Array.prototype.forEach.call(document.querySelectorAll('.grid'), function (grid) { | |||
if (grid.querySelector(':scope > .grid-item')) { | |||
msnrys.push(new Masonry(grid, { | |||
itemSelector: '.grid-item', | |||
percentPosition: true | |||
})); | |||
} | |||
}); | }); | ||
} | } | ||
| Baris 146: | Baris 151: | ||
if (el) { | if (el) { | ||
el.addEventListener('shown.bs.collapse', function () { | el.addEventListener('shown.bs.collapse', function () { | ||
msnrys.forEach(function (m) { | |||
m.layout(); | |||
} | }); | ||
}); | }); | ||
} | } | ||
}); | }); | ||
Revisi per 30 Oktober 2026 21.39
/* Any JavaScript here will be loaded for users using the Tweeki skin */
/* Setiap blok dijaga: kalau elemen/library yang dicari tidak ada di halaman ini,
blok itu dilewati. Dulu satu error menghentikan seluruh file. */
// Bootstrap 5: Tweeki tidak membuka global `bootstrap`, pakai jembatan jQuery-nya.
// Plugin jQuery-nya bisa belum terdaftar (urutan muat), jadi dicek dulu.
$(function () {
if ($.fn.tooltip) {
$('[data-toggle="tooltip"]').tooltip();
}
if ($.fn.alert) {
$('.alert').alert();
}
if ($.fn.popover) {
$('[data-bs-toggle="popover"]').popover();
}
});
// Header tabel #table-1 menempel saat digulir (butuh #header-fixed di halaman)
(function () {
var $table = $('#table-1');
var $fixedHeader = $('#header-fixed');
if (!$table.length || !$fixedHeader.length) {
return;
}
var tableOffset = $table.offset().top;
$fixedHeader.append($table.children('thead').clone());
$(window).on('scroll', function () {
var offset = $(this).scrollTop();
if (offset >= tableOffset && $fixedHeader.is(':hidden')) {
$fixedHeader.show();
} else if (offset < tableOffset) {
$fixedHeader.hide();
}
});
}());
// Pindahkan kategori ke sidebar kanan
(function () {
var one = document.querySelector('#sidebar-right');
var catlinks = document.querySelector('.catlinks');
if (!one || !catlinks) {
return;
}
// salin ke array dulu: .children ikut berubah saat elemen dipindah (dulu yang terpindah hanya selang-seling)
Array.prototype.slice.call(catlinks.children).forEach(function (child) {
one.appendChild(child);
});
}());
// MASONRY: .grid > .grid-item. Library dimuat async dari CDN (hook BeforePageDisplay di
// LocalSettings), jadi bisa belum tersedia saat file ini jalan -> coba lagi saat window load.
// Hanya .grid yang benar-benar berisi .grid-item: badan accordion di Templat:BootstrapAccordion2Collapse
// juga berkelas .grid tanpa item, dan Masonry membuatnya setinggi 0 sehingga isinya menimpa bagian bawahnya.
var msnrys = [];
function initMasonry() {
if (msnrys.length || typeof Masonry === 'undefined') {
return;
}
Array.prototype.forEach.call(document.querySelectorAll('.grid'), function (grid) {
if (grid.querySelector(':scope > .grid-item')) {
msnrys.push(new Masonry(grid, {
itemSelector: '.grid-item',
percentPosition: true
}));
}
});
}
initMasonry();
window.addEventListener('load', initMasonry);
// Daftar isi (ScrollSpy): judul berawalan "#" (mis. "#1 Kanak-kanak") atau berisi "?" menghasilkan
// href seperti "##1_Kanak-kanak" yang bukan selector CSS sah -> ScrollSpy Bootstrap error dan
// berhenti, sehingga sub-daftar H3 tidak pernah terbuka. Escape href-nya, lalu tangani kliknya
// sendiri (href yang di-escape tidak lagi cocok dengan id heading).
// ScrollSpy menyimpan tautan dengan kunci href (yang sudah di-escape) tetapi mencarinya dengan
// '#' + id heading, jadi kunci versi id ditambahkan sebagai alias (ScrollSpy Bootstrap 5.3).
$(function () {
var $links;
var changed = false;
function getSpy() {
var SS = $.fn.scrollspy && $.fn.scrollspy.Constructor;
return SS && SS.getInstance ? SS.getInstance(document.body) : null;
}
function syncSpy() {
var spy = getSpy();
if (!spy) {
return false;
}
spy.refresh();
if (spy._targetLinks) {
$links.each(function () {
var id = $(this).data('tocId');
if (id) {
spy._targetLinks.set('#' + id, this);
}
});
}
return true;
}
if (!window.CSS || !CSS.escape) {
return;
}
$links = $('#toc ul a[href^="#"]');
$links.each(function () {
var id, safe;
try {
id = decodeURIComponent(this.hash.slice(1));
} catch (e) {
return;
}
safe = '#' + CSS.escape(id);
if (this.getAttribute('href') !== safe) {
$(this).attr('href', safe).data('tocId', id);
changed = true;
}
}).on('click', function (e) {
var id = $(this).data('tocId');
if (id && document.getElementById(id)) {
e.preventDefault();
// '#' tambahan wajib: setter location.hash membuang satu '#' di depan
location.hash = '#' + id;
}
});
// ScrollSpy dibuat oleh skin Tweeki, bisa sesudah blok ini jalan (event load pun sering sudah
// lewat), jadi coba ulang beberapa kali sampai ScrollSpy ada (maks. ±5 detik)
function trySync(tries) {
if (!syncSpy() && tries > 0) {
setTimeout(function () {
trySync(tries - 1);
}, 200);
}
}
if (changed) {
setTimeout(function () {
trySync(25);
}, 0);
}
});
// bootstrap 5.3 accordion/collapse: isi yang tadinya tersembunyi menumpuk -> susun ulang setelah terbuka
['myAccordion', 'collapseMasonry'].forEach(function (id) {
var el = document.getElementById(id);
if (el) {
el.addEventListener('shown.bs.collapse', function () {
msnrys.forEach(function (m) {
m.layout();
});
});
}
});