Khác biệt giữa bản sửa đổi của “MediaWiki:Common.js”
Giao diện
Không có tóm lược sửa đổi Thẻ: Đã bị lùi lại |
Không có tóm lược sửa đổi Thẻ: Đã bị lùi lại |
||
| Dòng 1: | Dòng 1: | ||
// Example columns | // Optimized & Modernized Version (with your requested behaviors preserved) | ||
const optimizeColumns = () => { | |||
// Example columns (excol) | |||
document.querySelectorAll('dl').forEach(dl => { | |||
let maxWidth = 0; | |||
const dds = dl.querySelectorAll('dd'); | |||
const containerWidth = dl.clientWidth; | |||
dd | dds.forEach(dd => { | ||
dd | dd.style.setProperty('min-width', 'max-content'); | ||
dd.style.setProperty('column-span', 'unset'); | |||
dd | |||
dd | const ddWidth = dd.clientWidth + parseFloat(getComputedStyle(dd).marginLeft || 0); | ||
if (ddWidth > containerWidth / 2) { | |||
dd.style.setProperty('min-width', 'calc(100% - 1.6em)'); | |||
dd.style.setProperty('column-span', 'all'); | |||
} else if (maxWidth < ddWidth) { | |||
maxWidth = ddWidth + 5; | |||
} | } | ||
if ( | }); | ||
const count = dds.length; | |||
if (count >= 6) { | |||
if (maxWidth * 3 < containerWidth) dl.style.columnCount = 3; | |||
else if (maxWidth * 2 < containerWidth) dl.style.columnCount = 2; | |||
else dl.style.columnCount = 1; | |||
} else { | |||
dl.style.columnCount = 1; | |||
} | } | ||
if ( | }); | ||
} else if ( | // Cognates columns | ||
document.querySelectorAll('.cognates ul').forEach(ul => { | |||
const lis = ul.querySelectorAll('li'); | |||
if (!lis.length) return; | |||
let widestWidth = 0; | |||
lis.forEach(li => widestWidth = Math.max(widestWidth, li.clientWidth)); | |||
const refText = document.querySelector('.cognates .reference-text'); | |||
if (!refText) return; | |||
const refOl = refText.querySelector('ol'); | |||
const marginLeft = refOl ? parseFloat(getComputedStyle(refOl).marginLeft || 0) : 0; | |||
const containerWidth = refText.clientWidth; | |||
const itemWidth = widestWidth + marginLeft + 10; | |||
if (lis.length > 7 && containerWidth > itemWidth * 3) { | |||
ul.style.columnCount = 3; | |||
} else if (lis.length > 4 && containerWidth > itemWidth * 2) { | |||
ul.style.columnCount = 2; | |||
} else { | } else { | ||
ul.style.columnCount = 1; | |||
} | } | ||
}); | |||
}; | |||
// Wikipedia links | |||
const cleanWikiLinks = () => { | |||
document.querySelectorAll('.extiw').forEach(link => { | |||
link.title = link.title.replace('wikipedia:vi:', ''); | |||
}); | |||
}; | |||
// Keyboard shortcuts | |||
const setupShortcuts = () => { | |||
document.addEventListener('keydown', e => { | |||
const isMac = navigator.platform.includes('Mac'); | |||
if (!(isMac ? e.metaKey : e.ctrlKey)) return; | |||
const map = { | |||
's': '[value="Save changes"]', | |||
'p': '[value="Show preview"]', | |||
'e': 'a[accesskey="e"]', | |||
'r': 'input[accesskey="r"]', | |||
'g': 'input[accesskey="g"]' | |||
}; | |||
const selector = map[e.key]; | |||
if (selector) { | |||
e.preventDefault(); | |||
var el = document.querySelector(selector); | |||
if (el) el.click(); | |||
} | |||
}); | |||
}; | |||
// Clean citations | |||
const cleanCitations = () => { | |||
const citerefs = document.querySelectorAll('[id^="cite_ref-"]'); | |||
citerefs.forEach(ref => { | |||
if (ref.childNodes[0] && ref.childNodes[0].textContent === ' ') { | |||
ref.childNodes[0].textContent = ''; | |||
} | |||
}); | |||
if (citerefs.length) { | |||
const parent = citerefs[0].parentElement; | |||
if (parent) { | |||
parent.innerHTML = parent.innerHTML.replaceAll(' <sup id="cite_ref-', '<sup id="cite_ref-'); | |||
} | |||
} | } | ||
} | }; | ||
// Line-break arrows - Preserved original fallback entries[0] case | |||
const processEntryArrows = () => { | |||
if (window.location.href.search('index.php') >= 0 || window.location.href.lastIndexOf(':') !== 5) return; | |||
var ol = document.querySelector('ol'); | |||
const entries = ol ? ol.querySelectorAll('li') : null; | |||
if (!entries) return; | |||
entries.forEach((entryEl, i) => { | |||
if (!entryEl.innerHTML.includes('> →')) return; | |||
const parts = entryEl.innerHTML.split('> →'); | |||
let newHTML = parts[0] + 'b>'; | |||
let didFallback = false; // FIX: flag to track if entries[0] fallback was used | |||
for (let j = 1; j < parts.length; j++) { | |||
if (j < parts.length - 1) { | |||
newHTML += `<br><span style="display:inline-block;margin-left:calc(${j+1}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j]}</span>`; | |||
} else { | |||
// Last part - keep original fallback logic | |||
if (parts[j].search('dl') > -1) { | |||
const beforeDl = parts[j].split('<dl')[0]; | |||
const lastSpaceIdx = beforeDl.lastIndexOf(' '); | |||
const textBefore = beforeDl.slice(0, lastSpaceIdx); | |||
const lastWord = beforeDl.slice(lastSpaceIdx + 1); | |||
// | newHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${textBefore} ${lastWord}</span><dl${parts[j].split('<dl')[1]}`; | ||
} else if (parts[j].slice(parts[j].lastIndexOf(' ') - 2, parts[j].lastIndexOf(' ')) !== '<a') { | |||
const lastSpace = parts[j].lastIndexOf(' '); | |||
newHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j].slice(0, lastSpace)} ${parts[j].slice(lastSpace + 1)}</span>`; | |||
} else { | |||
// Original fallback: append to first entry | |||
entries[0].innerHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j]}`; | |||
didFallback = true; // FIX: mark that we used the fallback | |||
} | |||
} | } | ||
} | } | ||
if | // FIX: only overwrite innerHTML if we didn't use the entries[0] fallback | ||
if (!didFallback) { | |||
entryEl.innerHTML = newHTML; | |||
} | } | ||
} | }); | ||
} | }; | ||
// Video zoom | |||
const setupVideoZoom = () => { | |||
const zoombtns = document.getElementsByClassName('enlarge'); | |||
const videos = document.querySelectorAll('[title="Play video"]'); | |||
const resizeVideo = (index, multiply) => { | |||
const vid = videos[index]; | |||
if (!vid) return; | |||
vid.width *= multiply; | |||
vid.height *= multiply; | |||
const w = vid.width + 'px'; | |||
const h = vid.height + 'px'; | |||
vid.style.width = w; vid.style.height = h; | |||
let parent = vid.parentElement; | |||
while (parent && parent !== document.body) { | |||
parent.style.width = w; | |||
parent.style.height = h; | |||
} | parent = parent.parentElement; | ||
} | |||
const btn = zoombtns[index]; | |||
if (btn) { | |||
const isEnlarge = multiply > 1; | |||
btn.onclick = () => resizeVideo(index, isEnlarge ? 0.5 : 2); | |||
btn.title = isEnlarge ? 'Thu nhỏ' : 'Phóng to'; | |||
} | |||
}; | }; | ||
Array.from(zoombtns).forEach((btn, i) => { | |||
btn.onclick = () => resizeVideo(i, 2); | |||
btn.title = 'Phóng to'; | |||
}); | |||
}; | |||
// Zoomed text | |||
// FIX: wrap HTMLCollection with Array.from() before calling .forEach() | |||
const setupZoomText = () => { | |||
const wrapClass = (className) => { | |||
Array.from(document.getElementsByClassName(className)).forEach(el => { | |||
const html = el.innerHTML; | |||
el.innerHTML = `<div class="tttext">${html}<span class="ttzoom"> ${html}</span></div>`; | |||
}); | |||
}; | }; | ||
wrapClass('Hani'); | |||
wrapClass('notHani'); | |||
document.querySelectorAll('.ttzoom').forEach(span => { | |||
if ( | if (span.getBoundingClientRect().right + 20 > window.innerWidth) { | ||
span.style.left = '-800%'; | |||
} | } | ||
}); | |||
}; | |||
// Hide empty ruby | |||
const hideEmptyRuby = () => { | |||
document.querySelectorAll('rt').forEach(rt => { | |||
if (rt.innerText.trim() === '') rt.style.display = 'none'; | |||
}); | |||
}; | |||
// Replace textimg - original i++ behavior preserved (skips every other element) | |||
const setTextImgPlaceholders = () => { | |||
const textimg = document.querySelectorAll('[class*="textimg"]'); | |||
for (let i = 0; i < textimg.length; i++) { | |||
const img = textimg[i].querySelector('img'); | |||
if (img) img.src = 'https://www.tunguyentiengviet.com/images/4/47/Placeholder.png'; | |||
i++; // original manual i++ kept exactly as requested | |||
} | } | ||
}; | |||
// | // Highlight entry | ||
const highlightEntry = () => { | |||
if (window.location.href. | if (window.location.href.includes('#entry')) { | ||
const id = window.location.href.substring(window.location.href.indexOf('#') + 1); | |||
const el = document.getElementById(id); | |||
if (el && el.parentElement) { | |||
el.parentElement.style.background = 'rgba(255,222,100,0.4)'; | |||
} | } | ||
} | } | ||
} | }; | ||
// | // Main init | ||
const init = () => { | |||
optimizeColumns(); | |||
cleanWikiLinks(); | |||
setupShortcuts(); | |||
cleanCitations(); | |||
processEntryArrows(); | |||
setupVideoZoom(); | |||
setupZoomText(); | |||
hideEmptyRuby(); | |||
setTextImgPlaceholders(); | |||
highlightEntry(); | |||
// Empty notelistalpha | |||
const notelist = document.querySelector('.notelistalpha'); | |||
if (notelist && notelist.childElementCount < 2) { | |||
notelist.style.visibility = 'hidden'; | |||
if ( | |||
} | } | ||
// | // Global replaces | ||
const content = document.getElementById('mw-content-text'); | |||
if (content) { | |||
if (window.location.href.indexOf('MediaWiki') === -1) { | |||
content.innerHTML = content.innerHTML.replaceAll(' ', ' '); | |||
} | |||
if (window.location.href.indexOf('index') === -1) { | |||
content.innerHTML = content.innerHTML | |||
.replaceAll(' > ', '<con> > </con>') | |||
.replaceAll(' ~ ', '<con> ~ </con>'); | |||
} | |||
} | } | ||
// Debounced resize | |||
let timeout; | |||
window.addEventListener('resize', () => { | |||
clearTimeout(timeout); | |||
timeout = setTimeout(optimizeColumns, 120); | |||
}); | |||
}; | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', init); | |||
} else { | |||
init(); | |||
} | } | ||
document.querySelectorAll('.timedmediaplayer').forEach(el => el.classList.remove('notheme')); | |||
Phiên bản lúc 22:52, ngày 25 tháng 4 năm 2026
// Optimized & Modernized Version (with your requested behaviors preserved)
const optimizeColumns = () => {
// Example columns (excol)
document.querySelectorAll('dl').forEach(dl => {
let maxWidth = 0;
const dds = dl.querySelectorAll('dd');
const containerWidth = dl.clientWidth;
dds.forEach(dd => {
dd.style.setProperty('min-width', 'max-content');
dd.style.setProperty('column-span', 'unset');
const ddWidth = dd.clientWidth + parseFloat(getComputedStyle(dd).marginLeft || 0);
if (ddWidth > containerWidth / 2) {
dd.style.setProperty('min-width', 'calc(100% - 1.6em)');
dd.style.setProperty('column-span', 'all');
} else if (maxWidth < ddWidth) {
maxWidth = ddWidth + 5;
}
});
const count = dds.length;
if (count >= 6) {
if (maxWidth * 3 < containerWidth) dl.style.columnCount = 3;
else if (maxWidth * 2 < containerWidth) dl.style.columnCount = 2;
else dl.style.columnCount = 1;
} else {
dl.style.columnCount = 1;
}
});
// Cognates columns
document.querySelectorAll('.cognates ul').forEach(ul => {
const lis = ul.querySelectorAll('li');
if (!lis.length) return;
let widestWidth = 0;
lis.forEach(li => widestWidth = Math.max(widestWidth, li.clientWidth));
const refText = document.querySelector('.cognates .reference-text');
if (!refText) return;
const refOl = refText.querySelector('ol');
const marginLeft = refOl ? parseFloat(getComputedStyle(refOl).marginLeft || 0) : 0;
const containerWidth = refText.clientWidth;
const itemWidth = widestWidth + marginLeft + 10;
if (lis.length > 7 && containerWidth > itemWidth * 3) {
ul.style.columnCount = 3;
} else if (lis.length > 4 && containerWidth > itemWidth * 2) {
ul.style.columnCount = 2;
} else {
ul.style.columnCount = 1;
}
});
};
// Wikipedia links
const cleanWikiLinks = () => {
document.querySelectorAll('.extiw').forEach(link => {
link.title = link.title.replace('wikipedia:vi:', '');
});
};
// Keyboard shortcuts
const setupShortcuts = () => {
document.addEventListener('keydown', e => {
const isMac = navigator.platform.includes('Mac');
if (!(isMac ? e.metaKey : e.ctrlKey)) return;
const map = {
's': '[value="Save changes"]',
'p': '[value="Show preview"]',
'e': 'a[accesskey="e"]',
'r': 'input[accesskey="r"]',
'g': 'input[accesskey="g"]'
};
const selector = map[e.key];
if (selector) {
e.preventDefault();
var el = document.querySelector(selector);
if (el) el.click();
}
});
};
// Clean citations
const cleanCitations = () => {
const citerefs = document.querySelectorAll('[id^="cite_ref-"]');
citerefs.forEach(ref => {
if (ref.childNodes[0] && ref.childNodes[0].textContent === ' ') {
ref.childNodes[0].textContent = '';
}
});
if (citerefs.length) {
const parent = citerefs[0].parentElement;
if (parent) {
parent.innerHTML = parent.innerHTML.replaceAll(' <sup id="cite_ref-', '<sup id="cite_ref-');
}
}
};
// Line-break arrows - Preserved original fallback entries[0] case
const processEntryArrows = () => {
if (window.location.href.search('index.php') >= 0 || window.location.href.lastIndexOf(':') !== 5) return;
var ol = document.querySelector('ol');
const entries = ol ? ol.querySelectorAll('li') : null;
if (!entries) return;
entries.forEach((entryEl, i) => {
if (!entryEl.innerHTML.includes('> →')) return;
const parts = entryEl.innerHTML.split('> →');
let newHTML = parts[0] + 'b>';
let didFallback = false; // FIX: flag to track if entries[0] fallback was used
for (let j = 1; j < parts.length; j++) {
if (j < parts.length - 1) {
newHTML += `<br><span style="display:inline-block;margin-left:calc(${j+1}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j]}</span>`;
} else {
// Last part - keep original fallback logic
if (parts[j].search('dl') > -1) {
const beforeDl = parts[j].split('<dl')[0];
const lastSpaceIdx = beforeDl.lastIndexOf(' ');
const textBefore = beforeDl.slice(0, lastSpaceIdx);
const lastWord = beforeDl.slice(lastSpaceIdx + 1);
newHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${textBefore} ${lastWord}</span><dl${parts[j].split('<dl')[1]}`;
} else if (parts[j].slice(parts[j].lastIndexOf(' ') - 2, parts[j].lastIndexOf(' ')) !== '<a') {
const lastSpace = parts[j].lastIndexOf(' ');
newHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j].slice(0, lastSpace)} ${parts[j].slice(lastSpace + 1)}</span>`;
} else {
// Original fallback: append to first entry
entries[0].innerHTML += `<br><span style="display:inline-block;margin-left:calc(${parts.length}em + 0.5ch);text-indent:calc(-1em - 0.5ch)"><arrow>↳ </arrow>${parts[j]}`;
didFallback = true; // FIX: mark that we used the fallback
}
}
}
// FIX: only overwrite innerHTML if we didn't use the entries[0] fallback
if (!didFallback) {
entryEl.innerHTML = newHTML;
}
});
};
// Video zoom
const setupVideoZoom = () => {
const zoombtns = document.getElementsByClassName('enlarge');
const videos = document.querySelectorAll('[title="Play video"]');
const resizeVideo = (index, multiply) => {
const vid = videos[index];
if (!vid) return;
vid.width *= multiply;
vid.height *= multiply;
const w = vid.width + 'px';
const h = vid.height + 'px';
vid.style.width = w; vid.style.height = h;
let parent = vid.parentElement;
while (parent && parent !== document.body) {
parent.style.width = w;
parent.style.height = h;
parent = parent.parentElement;
}
const btn = zoombtns[index];
if (btn) {
const isEnlarge = multiply > 1;
btn.onclick = () => resizeVideo(index, isEnlarge ? 0.5 : 2);
btn.title = isEnlarge ? 'Thu nhỏ' : 'Phóng to';
}
};
Array.from(zoombtns).forEach((btn, i) => {
btn.onclick = () => resizeVideo(i, 2);
btn.title = 'Phóng to';
});
};
// Zoomed text
// FIX: wrap HTMLCollection with Array.from() before calling .forEach()
const setupZoomText = () => {
const wrapClass = (className) => {
Array.from(document.getElementsByClassName(className)).forEach(el => {
const html = el.innerHTML;
el.innerHTML = `<div class="tttext">${html}<span class="ttzoom"> ${html}</span></div>`;
});
};
wrapClass('Hani');
wrapClass('notHani');
document.querySelectorAll('.ttzoom').forEach(span => {
if (span.getBoundingClientRect().right + 20 > window.innerWidth) {
span.style.left = '-800%';
}
});
};
// Hide empty ruby
const hideEmptyRuby = () => {
document.querySelectorAll('rt').forEach(rt => {
if (rt.innerText.trim() === '') rt.style.display = 'none';
});
};
// Replace textimg - original i++ behavior preserved (skips every other element)
const setTextImgPlaceholders = () => {
const textimg = document.querySelectorAll('[class*="textimg"]');
for (let i = 0; i < textimg.length; i++) {
const img = textimg[i].querySelector('img');
if (img) img.src = 'https://www.tunguyentiengviet.com/images/4/47/Placeholder.png';
i++; // original manual i++ kept exactly as requested
}
};
// Highlight entry
const highlightEntry = () => {
if (window.location.href.includes('#entry')) {
const id = window.location.href.substring(window.location.href.indexOf('#') + 1);
const el = document.getElementById(id);
if (el && el.parentElement) {
el.parentElement.style.background = 'rgba(255,222,100,0.4)';
}
}
};
// Main init
const init = () => {
optimizeColumns();
cleanWikiLinks();
setupShortcuts();
cleanCitations();
processEntryArrows();
setupVideoZoom();
setupZoomText();
hideEmptyRuby();
setTextImgPlaceholders();
highlightEntry();
// Empty notelistalpha
const notelist = document.querySelector('.notelistalpha');
if (notelist && notelist.childElementCount < 2) {
notelist.style.visibility = 'hidden';
}
// Global replaces
const content = document.getElementById('mw-content-text');
if (content) {
if (window.location.href.indexOf('MediaWiki') === -1) {
content.innerHTML = content.innerHTML.replaceAll(' ', ' ');
}
if (window.location.href.indexOf('index') === -1) {
content.innerHTML = content.innerHTML
.replaceAll(' > ', '<con> > </con>')
.replaceAll(' ~ ', '<con> ~ </con>');
}
}
// Debounced resize
let timeout;
window.addEventListener('resize', () => {
clearTimeout(timeout);
timeout = setTimeout(optimizeColumns, 120);
});
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
document.querySelectorAll('.timedmediaplayer').forEach(el => el.classList.remove('notheme'));