有觉性 以安住且中立的心 照见身心的实相
MediaWiki:Common.js:修订间差异
来自Dhamma.cn
小无编辑摘要 |
小无编辑摘要 |
||
| 第918行: | 第918行: | ||
} | } | ||
| 第923行: | 第926行: | ||
/* ========================================================= | /* ========================================================= | ||
Dhamma.cn | Dhamma.cn 划词复制开示 - 终极稳定版 | ||
========================================================= */ | ========================================================= */ | ||
(function () { | |||
console.log('[Dhamma-Copy] 划词复制脚本已成功启动!'); | |||
function createPopover() { | |||
var popover = document.getElementById('dhamma-copy-popover'); | |||
if (popover) return popover; | |||
popover = document.createElement('div'); | |||
popover.id = 'dhamma-copy-popover'; | |||
// z-index 设为最高,防止被任何皮肤组件遮挡 | |||
popover.style.cssText = 'display:none; position:absolute; z-index:2147483647; background:#ffffff; border:1px solid rgba(0,0,0,0.15); border-radius:8px; box-shadow:0 4px 18px rgba(0,0,0,0.2); padding:6px; font-size:13px; line-height:1.4; white-space:nowrap;'; | |||
var btn = document.createElement('button'); | |||
btn.id = 'dhamma-copy-btn'; | |||
btn.innerHTML = '📋 复制该段开示(带出处)'; | |||
btn.style.cssText = 'background:#4d6b57; color:#ffffff; border:none; border-radius:5px; padding:6px 14px; font-size:13px; cursor:pointer; font-weight:600; display:block;'; | |||
popover.appendChild(btn); | |||
document.body.appendChild(popover); | |||
return popover; | |||
} | } | ||
// 自动抓取 UrlShortener 生成的短网址 | |||
function getShortUrl() { | |||
var shortlink = document.querySelector('link[rel="shortlink"]'); | |||
// | if (shortlink && shortlink.getAttribute('href')) { | ||
function | var href = shortlink.getAttribute('href'); | ||
return href.indexOf('http') === 0 ? href : window.location.origin + href; | |||
var shortlink = | |||
return | |||
} | } | ||
if (window.mw && mw.config && mw.config.get('wgShortUrl')) { | |||
var sUrl = mw.config.get('wgShortUrl'); | |||
if (mw.config.get('wgShortUrl')) { | return sUrl.indexOf('http') === 0 ? sUrl : window.location.origin + sUrl; | ||
var | |||
return | |||
} | } | ||
return window.location.href.split('#')[0].split('?')[0]; | |||
} | |||
var currentText = ''; | |||
function checkAndShowPopover() { | |||
var popover = createPopover(); | |||
var btn = document.getElementById('dhamma-copy-btn'); | |||
var sel = window.getSelection(); | |||
var text = sel ? sel.toString().trim() : ''; | |||
// 未选中或选中文本小于 2 个字则隐藏 | |||
if (!text || text.length < 2) { | |||
popover.style.display = 'none'; | |||
return; | return; | ||
} | } | ||
currentText = text; | |||
var | |||
var | if (sel.rangeCount > 0) { | ||
var range = sel.getRangeAt(0); | |||
var rect = range.getBoundingClientRect(); | |||
if (rect.width === 0 && rect.height === 0) { | |||
if ( | popover.style.display = 'none'; | ||
return; | return; | ||
} | } | ||
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; | |||
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; | |||
var popWidth = popover.offsetWidth || 190; | |||
var popHeight = popover.offsetHeight || 38; | |||
var top = rect.top + scrollTop - popHeight - 10; | |||
var left = rect.left + scrollLeft + (rect.width / 2) - (popWidth / 2); | |||
if (left < 10) left = 10; | |||
if (top < scrollTop + 10) { | |||
top = rect.bottom + scrollTop + 10; | |||
} | } | ||
popover.style.top = top + 'px'; | |||
popover.style.left = left + 'px'; | |||
popover.style.display = 'block'; | |||
// 点击复制事件处理 | |||
btn.onclick = function (e) { | |||
e.stopPropagation(); | |||
e.preventDefault(); | |||
var title = (window.mw && mw.config && mw.config.get('wgTitle')) || document.title; | |||
var site = (window.mw && mw.config && mw.config.get('wgSiteName')) || 'Dhamma.cn'; | |||
var url = getShortUrl(); | |||
var output = | |||
'“' + currentText + '”\n\n' + | |||
'----------------------------------------\n' + | |||
'法谈摘自:' + site + ' 《' + title + '》\n' + | |||
'该篇网址:' + url + '\n' + | |||
'转载请保持原文,随喜分享,Sadhu!'; | |||
if (navigator.clipboard && navigator.clipboard.writeText) { | |||
navigator.clipboard.writeText(output).then(function () { | |||
showFeedback(btn, popover); | |||
}).catch(function () { | |||
fallbackCopy(output, btn, popover); | |||
}); | |||
} else { | |||
fallbackCopy(output, btn, popover); | |||
} | |||
}; | |||
} | } | ||
} | } | ||
function showFeedback(btn, popover) { | |||
function | btn.innerHTML = '✅ 已复制开示及出处'; | ||
btn.style.background = '#2e7d32'; | |||
setTimeout(function () { | setTimeout(function () { | ||
btn.innerHTML = '📋 复制该段开示(带出处)'; | |||
btn.style.background = '#4d6b57'; | |||
popover.style.display = 'none'; | |||
}, 1200); | }, 1200); | ||
} | } | ||
function fallbackCopy(text, btn, popover) { | |||
function fallbackCopy(text) { | var ta = document.createElement('textarea'); | ||
var | ta.value = text; | ||
ta.style.position = 'fixed'; | |||
ta.style.opacity = '0'; | |||
document.body.appendChild(ta); | |||
ta.select(); | |||
document.execCommand('copy'); | document.execCommand('copy'); | ||
document.body.removeChild(ta); | |||
showFeedback(btn, popover); | |||
} | } | ||
}); | |||
// 多重监听,兼容鼠标选词和手机触摸选词 | |||
document.addEventListener('mouseup', function () { setTimeout(checkAndShowPopover, 50); }); | |||
document.addEventListener('touchend', function () { setTimeout(checkAndShowPopover, 50); }); | |||
// 点击空白区域关闭浮窗 | |||
document.addEventListener('mousedown', function (e) { | |||
var popover = document.getElementById('dhamma-copy-popover'); | |||
if (popover && !popover.contains(e.target)) { | |||
popover.style.display = 'none'; | |||
} | |||
}); | |||
})(); | |||
2026年9月19日 (六) 22:07的版本
/**
* =========================================================
* Dhamma.cn 阅读显示设置
* MediaWiki 1.43
*
* 功能:
* - 背景主题
* - 字号
* - 行距
* - 阅读宽度
* - 字体
* - localStorage 保存
* =========================================================
*/
(function () {
'use strict';
/* =====================================================
1. 默认设置
===================================================== */
var defaults = {
theme: 'default',
fontSize: 18,
lineHeight: 1.9,
maxWidth: 900,
fontFamily: 'system'
};
/* =====================================================
2. 从 localStorage 读取
===================================================== */
var settings = {};
try {
var saved =
localStorage.getItem('dhammaReaderSettings');
if (saved) {
settings =
Object.assign(
{},
defaults,
JSON.parse(saved)
);
} else {
settings =
Object.assign({}, defaults);
}
} catch (e) {
settings =
Object.assign({}, defaults);
}
/* =====================================================
3. 保存设置
===================================================== */
function saveSettings() {
try {
localStorage.setItem(
'dhammaReaderSettings',
JSON.stringify(settings)
);
} catch (e) {
// 浏览器禁用 localStorage 时忽略
}
}
/* =====================================================
4. 字体
===================================================== */
var fonts = {
system:
'-apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans SC", "Microsoft YaHei", Arial, sans-serif',
serif:
'"Noto Serif SC", "Source Han Serif SC", "Songti SC", "SimSun", serif',
sans:
'"Noto Sans SC", "Source Han Sans SC", "Microsoft YaHei", Arial, sans-serif'
};
/* =====================================================
5. 应用设置
===================================================== */
function applySettings() {
var root =
document.documentElement;
var body =
document.body;
/* -----------------------------
背景主题
----------------------------- */
body.classList.remove(
'reader-theme-default',
'reader-theme-cream',
'reader-theme-zen',
'reader-theme-dark'
);
body.classList.add(
'reader-theme-' + settings.theme
);
/* -----------------------------
字号
----------------------------- */
root.style.setProperty(
'--reader-font-size',
settings.fontSize + 'px'
);
/* -----------------------------
行距
----------------------------- */
root.style.setProperty(
'--reader-line-height',
settings.lineHeight
);
/* -----------------------------
阅读宽度
----------------------------- */
root.style.setProperty(
'--reader-max-width',
settings.maxWidth + 'px'
);
/* -----------------------------
字体
----------------------------- */
root.style.setProperty(
'--reader-font-family',
fonts[settings.fontFamily]
);
}
/* =====================================================
6. 创建设置按钮
===================================================== */
function createSettingsButton() {
if (
document.getElementById(
'reader-settings-button'
)
) {
return;
}
var button =
document.createElement('button');
button.id =
'reader-settings-button';
button.type =
'button';
button.setAttribute(
'aria-label',
'阅读设置'
);
button.setAttribute(
'title',
'阅读设置'
);
button.innerHTML =
'⚙';
document.body.appendChild(button);
button.addEventListener(
'click',
function () {
var panel =
document.getElementById(
'reader-settings-panel'
);
if (!panel) {
return;
}
panel.classList.toggle(
'reader-settings-open'
);
}
);
}
/* =====================================================
7. 创建设置面板
===================================================== */
function createSettingsPanel() {
if (
document.getElementById(
'reader-settings-panel'
)
) {
return;
}
var panel =
document.createElement('div');
panel.id =
'reader-settings-panel';
panel.setAttribute(
'role',
'dialog'
);
panel.setAttribute(
'aria-label',
'阅读显示设置'
);
panel.innerHTML = `
<div class="reader-settings-title">
阅读显示设置
</div>
<!-- =========================
主题
========================= -->
<div class="reader-setting-group">
<span class="reader-setting-label">
背景
</span>
<div class="reader-theme-buttons">
<button
type="button"
class="reader-theme-button reader-theme-default-button"
data-theme="default">
默认
</button>
<button
type="button"
class="reader-theme-button reader-theme-cream-button"
data-theme="cream">
米白
</button>
<button
type="button"
class="reader-theme-button reader-theme-zen-button"
data-theme="zen">
禅意
</button>
<button
type="button"
class="reader-theme-button reader-theme-dark-button"
data-theme="dark">
夜间
</button>
</div>
</div>
<!-- =========================
字号
========================= -->
<div class="reader-setting-group">
<span class="reader-setting-label">
字号
</span>
<div class="reader-range-row">
<span>A−</span>
<input
id="reader-font-size"
class="reader-range"
type="range"
min="14"
max="26"
step="1">
<span>A+</span>
<span
id="reader-font-size-value"
class="reader-range-value">
</span>
</div>
</div>
<!-- =========================
行距
========================= -->
<div class="reader-setting-group">
<span class="reader-setting-label">
行距
</span>
<div class="reader-range-row">
<span>窄</span>
<input
id="reader-line-height"
class="reader-range"
type="range"
min="1.4"
max="2.4"
step="0.1">
<span>宽</span>
<span
id="reader-line-height-value"
class="reader-range-value">
</span>
</div>
</div>
<!-- =========================
阅读宽度
========================= -->
<div class="reader-setting-group">
<span class="reader-setting-label">
阅读宽度
</span>
<div class="reader-range-row">
<span>窄</span>
<input
id="reader-max-width"
class="reader-range"
type="range"
min="680"
max="1200"
step="20">
<span>宽</span>
<span
id="reader-max-width-value"
class="reader-range-value">
</span>
</div>
</div>
<!-- =========================
字体
========================= -->
<div class="reader-setting-group">
<span class="reader-setting-label">
字体
</span>
<div class="reader-font-buttons">
<button
type="button"
class="reader-font-button"
data-font="system">
系统字体
</button>
<button
type="button"
class="reader-font-button"
data-font="serif">
宋体
</button>
<button
type="button"
class="reader-font-button"
data-font="sans">
黑体
</button>
</div>
</div>
<!-- =========================
恢复默认
========================= -->
<button
id="reader-settings-reset"
type="button">
恢复默认设置
</button>
`;
document.body.appendChild(panel);
bindSettingsEvents();
updateSettingsUI();
}
/* =====================================================
8. 绑定事件
===================================================== */
function bindSettingsEvents() {
/* -----------------------------
主题
----------------------------- */
document
.querySelectorAll(
'.reader-theme-button'
)
.forEach(function (button) {
button.addEventListener(
'click',
function () {
settings.theme =
this.dataset.theme;
applySettings();
saveSettings();
updateSettingsUI();
}
);
});
/* -----------------------------
字号
----------------------------- */
var fontSize =
document.getElementById(
'reader-font-size'
);
fontSize.addEventListener(
'input',
function () {
settings.fontSize =
parseInt(
this.value,
10
);
applySettings();
saveSettings();
updateSettingsUI();
}
);
/* -----------------------------
行距
----------------------------- */
var lineHeight =
document.getElementById(
'reader-line-height'
);
lineHeight.addEventListener(
'input',
function () {
settings.lineHeight =
parseFloat(
this.value
);
applySettings();
saveSettings();
updateSettingsUI();
}
);
/* -----------------------------
阅读宽度
----------------------------- */
var maxWidth =
document.getElementById(
'reader-max-width'
);
maxWidth.addEventListener(
'input',
function () {
settings.maxWidth =
parseInt(
this.value,
10
);
applySettings();
saveSettings();
updateSettingsUI();
}
);
/* -----------------------------
字体
----------------------------- */
document
.querySelectorAll(
'.reader-font-button'
)
.forEach(function (button) {
button.addEventListener(
'click',
function () {
settings.fontFamily =
this.dataset.font;
applySettings();
saveSettings();
updateSettingsUI();
}
);
});
/* -----------------------------
恢复默认
----------------------------- */
document
.getElementById(
'reader-settings-reset'
)
.addEventListener(
'click',
function () {
settings =
Object.assign(
{},
defaults
);
applySettings();
saveSettings();
updateSettingsUI();
}
);
}
/* =====================================================
9. 更新界面
===================================================== */
function updateSettingsUI() {
/* -----------------------------
主题按钮
----------------------------- */
document
.querySelectorAll(
'.reader-theme-button'
)
.forEach(function (button) {
button.classList.toggle(
'active',
button.dataset.theme ===
settings.theme
);
});
/* -----------------------------
字号
----------------------------- */
var fontSize =
document.getElementById(
'reader-font-size'
);
var fontSizeValue =
document.getElementById(
'reader-font-size-value'
);
if (fontSize) {
fontSize.value =
settings.fontSize;
fontSizeValue.textContent =
settings.fontSize + 'px';
}
/* -----------------------------
行距
----------------------------- */
var lineHeight =
document.getElementById(
'reader-line-height'
);
var lineHeightValue =
document.getElementById(
'reader-line-height-value'
);
if (lineHeight) {
lineHeight.value =
settings.lineHeight;
lineHeightValue.textContent =
settings.lineHeight;
}
/* -----------------------------
阅读宽度
----------------------------- */
var maxWidth =
document.getElementById(
'reader-max-width'
);
var maxWidthValue =
document.getElementById(
'reader-max-width-value'
);
if (maxWidth) {
maxWidth.value =
settings.maxWidth;
maxWidthValue.textContent =
settings.maxWidth + 'px';
}
/* -----------------------------
字体
----------------------------- */
document
.querySelectorAll(
'.reader-font-button'
)
.forEach(function (button) {
button.classList.toggle(
'active',
button.dataset.font ===
settings.fontFamily
);
});
}
/* =====================================================
10. 点击页面其他地方关闭面板
===================================================== */
function bindOutsideClick() {
document.addEventListener(
'click',
function (event) {
var panel =
document.getElementById(
'reader-settings-panel'
);
var button =
document.getElementById(
'reader-settings-button'
);
if (!panel || !button) {
return;
}
if (
panel.contains(event.target) ||
button.contains(event.target)
) {
return;
}
panel.classList.remove(
'reader-settings-open'
);
}
);
}
/* =====================================================
11. 初始化
===================================================== */
function initReaderSettings() {
applySettings();
createSettingsButton();
createSettingsPanel();
bindOutsideClick();
}
/*
* MediaWiki 页面加载完成以后执行。
*/
/* =====================================================
MediaWiki 初始化
===================================================== */
function startReaderSettings() {
if (
document.getElementById(
'reader-settings-button'
)
) {
return;
}
initReaderSettings();
}
/*
* MediaWiki 页面加载完成后执行。
*
* 使用 mw.loader.using + jQuery ready,
* 避免 Common.js 加载时 DOMContentLoaded
* 已经执行完毕的问题。
*/
if (
typeof mw !== 'undefined' &&
mw.loader
) {
mw.loader.using([], function () {
$(startReaderSettings);
});
} else {
if (
document.readyState === 'loading'
) {
document.addEventListener(
'DOMContentLoaded',
startReaderSettings
);
} else {
startReaderSettings();
}
}
/* =========================================================
Dhamma.cn 划词复制开示 - 终极稳定版
========================================================= */
(function () {
console.log('[Dhamma-Copy] 划词复制脚本已成功启动!');
function createPopover() {
var popover = document.getElementById('dhamma-copy-popover');
if (popover) return popover;
popover = document.createElement('div');
popover.id = 'dhamma-copy-popover';
// z-index 设为最高,防止被任何皮肤组件遮挡
popover.style.cssText = 'display:none; position:absolute; z-index:2147483647; background:#ffffff; border:1px solid rgba(0,0,0,0.15); border-radius:8px; box-shadow:0 4px 18px rgba(0,0,0,0.2); padding:6px; font-size:13px; line-height:1.4; white-space:nowrap;';
var btn = document.createElement('button');
btn.id = 'dhamma-copy-btn';
btn.innerHTML = '📋 复制该段开示(带出处)';
btn.style.cssText = 'background:#4d6b57; color:#ffffff; border:none; border-radius:5px; padding:6px 14px; font-size:13px; cursor:pointer; font-weight:600; display:block;';
popover.appendChild(btn);
document.body.appendChild(popover);
return popover;
}
// 自动抓取 UrlShortener 生成的短网址
function getShortUrl() {
var shortlink = document.querySelector('link[rel="shortlink"]');
if (shortlink && shortlink.getAttribute('href')) {
var href = shortlink.getAttribute('href');
return href.indexOf('http') === 0 ? href : window.location.origin + href;
}
if (window.mw && mw.config && mw.config.get('wgShortUrl')) {
var sUrl = mw.config.get('wgShortUrl');
return sUrl.indexOf('http') === 0 ? sUrl : window.location.origin + sUrl;
}
return window.location.href.split('#')[0].split('?')[0];
}
var currentText = '';
function checkAndShowPopover() {
var popover = createPopover();
var btn = document.getElementById('dhamma-copy-btn');
var sel = window.getSelection();
var text = sel ? sel.toString().trim() : '';
// 未选中或选中文本小于 2 个字则隐藏
if (!text || text.length < 2) {
popover.style.display = 'none';
return;
}
currentText = text;
if (sel.rangeCount > 0) {
var range = sel.getRangeAt(0);
var rect = range.getBoundingClientRect();
if (rect.width === 0 && rect.height === 0) {
popover.style.display = 'none';
return;
}
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
var popWidth = popover.offsetWidth || 190;
var popHeight = popover.offsetHeight || 38;
var top = rect.top + scrollTop - popHeight - 10;
var left = rect.left + scrollLeft + (rect.width / 2) - (popWidth / 2);
if (left < 10) left = 10;
if (top < scrollTop + 10) {
top = rect.bottom + scrollTop + 10;
}
popover.style.top = top + 'px';
popover.style.left = left + 'px';
popover.style.display = 'block';
// 点击复制事件处理
btn.onclick = function (e) {
e.stopPropagation();
e.preventDefault();
var title = (window.mw && mw.config && mw.config.get('wgTitle')) || document.title;
var site = (window.mw && mw.config && mw.config.get('wgSiteName')) || 'Dhamma.cn';
var url = getShortUrl();
var output =
'“' + currentText + '”\n\n' +
'----------------------------------------\n' +
'法谈摘自:' + site + ' 《' + title + '》\n' +
'该篇网址:' + url + '\n' +
'转载请保持原文,随喜分享,Sadhu!';
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(output).then(function () {
showFeedback(btn, popover);
}).catch(function () {
fallbackCopy(output, btn, popover);
});
} else {
fallbackCopy(output, btn, popover);
}
};
}
}
function showFeedback(btn, popover) {
btn.innerHTML = '✅ 已复制开示及出处';
btn.style.background = '#2e7d32';
setTimeout(function () {
btn.innerHTML = '📋 复制该段开示(带出处)';
btn.style.background = '#4d6b57';
popover.style.display = 'none';
}, 1200);
}
function fallbackCopy(text, btn, popover) {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
showFeedback(btn, popover);
}
// 多重监听,兼容鼠标选词和手机触摸选词
document.addEventListener('mouseup', function () { setTimeout(checkAndShowPopover, 50); });
document.addEventListener('touchend', function () { setTimeout(checkAndShowPopover, 50); });
// 点击空白区域关闭浮窗
document.addEventListener('mousedown', function (e) {
var popover = document.getElementById('dhamma-copy-popover');
if (popover && !popover.contains(e.target)) {
popover.style.display = 'none';
}
});
})();
