有觉性 以安住且中立的心 照见身心的实相
MediaWiki:Common.js:修订间差异
来自Dhamma.cn
小无编辑摘要 |
小无编辑摘要 |
||
| (未显示同一用户的32个中间版本) | |||
| 第1行: | 第1行: | ||
/ | /* ========================================================= | ||
Dhamma.cn 划词复制开示及 UrlShortener 短网址落款(移动端遮挡修复版) | |||
适用于:MediaWiki:Common.js | |||
========================================================= */ | |||
(function () { | (function () { | ||
if (window.dhammaCopyLoaded) return; | |||
window.dhammaCopyLoaded = true; | |||
function initDhammaCopy() { | |||
var cachedShortUrl = ''; | |||
// 判断是否为移动端 / 触摸设备 | |||
function isMobileDevice() { | |||
return ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (window.innerWidth <= 768); | |||
} | } | ||
// 1. 统一域名规范化:剥离 www 及所有二级域名(如 reg.dhamma.cn),强转为 https://dhamma.cn | |||
function forceMainDomain(url) { | |||
if (!url) return 'https://dhamma.cn'; | |||
if (url.indexOf('http') !== 0) { | |||
return 'https://dhamma.cn' + (url.indexOf('/') === 0 ? '' : '/') + url; | |||
} | |||
return url.replace(/^https?:\/\/[^\/]+/, 'https://dhamma.cn'); | |||
' | |||
// | |||
} | } | ||
// 2. 异步获取真正的当前页面短网址 | |||
function getShortUrlAsync() { | |||
if (cachedShortUrl) return Promise.resolve(cachedShortUrl); | |||
// 仅在侧边栏/工具栏查找官方短网址,严禁扫描正文(#bodyContent)内的嵌入链接 | |||
var tShort = document.querySelector('#t-shorturl a, #p-tb a[href*="/s/"], .mw-portlet-tb a[href*="/s/"], li[id*="shorturl"] a'); | |||
if (tShort && tShort.href && tShort.href.indexOf('/s/') !== -1) { | |||
cachedShortUrl = forceMainDomain(tShort.href); | |||
return Promise.resolve(cachedShortUrl); | |||
} | |||
// 获取页面规范网址 | |||
var canonicalEl = document.querySelector('link[rel="canonical"]'); | |||
var targetUrl = canonicalEl ? canonicalEl.href : window.location.href; | |||
// 优先使用 MediaWiki 原生 Api 模块(带 CSRF Token) | |||
if (window.mw && mw.Api) { | |||
return new mw.Api().post({ | |||
action: 'shortenurl', | |||
url: targetUrl | |||
}).then(function (data) { | |||
if (data && data.shortenurl && data.shortenurl.shorturl) { | |||
cachedShortUrl = forceMainDomain(data.shortenurl.shorturl); | |||
} else { | |||
cachedShortUrl = forceMainDomain(targetUrl); | |||
} | |||
return cachedShortUrl; | |||
}).catch(function () { | |||
return fallbackFetchApi(targetUrl); | |||
}); | |||
} else { | |||
return fallbackFetchApi(targetUrl); | |||
} | |||
} | |||
} | } | ||
// 降级 Fetch 请求(带 CSRF Token) | |||
function fallbackFetchApi(targetUrl) { | |||
var scriptPath = (window.mw && mw.config && mw.config.get('wgScriptPath')) || ''; | |||
var apiUrl = scriptPath + '/api.php'; | |||
var token = (window.mw && mw.user && mw.user.tokens && mw.user.tokens.get('csrfToken')) || '+\\'; | |||
var params = new URLSearchParams(); | |||
params.append('action', 'shortenurl'); | |||
params.append('format', 'json'); | |||
params.append('url', targetUrl); | |||
params.append('token', token); | |||
return fetch(apiUrl, { | |||
method: 'POST', | |||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | |||
body: params.toString() | |||
}) | |||
.then(function (res) { return res.json(); }) | |||
.then(function (data) { | |||
if (data && data.shortenurl && data.shortenurl.shorturl) { | |||
cachedShortUrl = forceMainDomain(data.shortenurl.shorturl); | |||
} else { | |||
cachedShortUrl = forceMainDomain(targetUrl); | |||
} | } | ||
return cachedShortUrl; | |||
}) | |||
.catch(function () { | |||
cachedShortUrl = forceMainDomain(targetUrl); | |||
return cachedShortUrl; | |||
} | }); | ||
) | |||
} | } | ||
// 静默预取短网址 | |||
getShortUrlAsync(); | |||
var | // 3. 创建/获取浮窗节点 | ||
document.createElement('div'); | function getPopover() { | ||
var pop = document.getElementById('dhamma-copy-popover'); | |||
if (!pop) { | |||
pop = document.createElement('div'); | |||
pop.id = 'dhamma-copy-popover'; | |||
pop.style.cssText = 'display:none; position:fixed; z-index:2147483647; background:#ffffff; border:1px solid rgba(0,0,0,0.15); border-radius:30px; box-shadow:0 8px 24px rgba(0,0,0,0.22); padding:6px 8px; font-size:14px; white-space:nowrap; transition:bottom 0.2s ease, opacity 0.2s ease;'; | |||
var btn = document.createElement('button'); | |||
btn.id = 'dhamma-copy-btn'; | |||
btn.innerText = ' 复制该段开示(含出处)'; | |||
btn.style.cssText = 'background:#4d6b57; color:#ffffff; border:none; border-radius:20px; padding:8px 18px; font-size:14px; cursor:pointer; font-weight:600; font-family:sans-serif; -webkit-tap-highlight-color:transparent;'; | |||
btn.onmouseover = function () { if (this.innerText.indexOf('✅') === -1) this.style.background = '#3b5343'; }; | |||
btn.onmouseout = function () { if (this.innerText.indexOf('✅') === -1) this.style.background = '#4d6b57'; }; | |||
pop.appendChild(btn); | |||
document.body.appendChild(pop); | |||
} | } | ||
return pop; | |||
} | |||
var currentText = ''; | |||
// 4. 处理划词选择逻辑(响应式适配 PC / 移动端定位) | |||
function handleSelection() { | |||
var popover = getPopover(); | |||
var btn = document.getElementById('dhamma-copy-btn'); | |||
var sel = window.getSelection(); | |||
var text = sel ? sel.toString().trim() : ''; | |||
if (!text || text.length < 2) { | |||
popover.style.display = 'none'; | |||
return; | |||
} | } | ||
currentText = text; | |||
if (sel.rangeCount > 0) { | |||
var isMobile = isMobileDevice(); | |||
if (isMobile) { | |||
// 📱 移动端解决遮挡的核心方案:固定在屏幕底部中央,并兼容 iPhone 底部安全区 | |||
popover.style.top = 'auto'; | |||
popover.style.bottom = 'calc(25px + env(safe-area-inset-bottom, 0px))'; | |||
popover.style.left = '50%'; | |||
popover.style.transform = 'translateX(-50%)'; | |||
popover.style.display = 'block'; | |||
} else { | |||
// 💻 PC 端:跟随选中区域在上方居中弹出 | |||
var range = sel.getRangeAt(0); | |||
var rect = range.getBoundingClientRect(); | |||
if (rect.width === 0 || rect.height === 0) { | |||
popover.style.display = 'none'; | |||
return; | |||
} | } | ||
var popWidth = popover.offsetWidth || 200; | |||
var popHeight = popover.offsetHeight || 40; | |||
var top = rect.top - popHeight - 10; | |||
var left = rect.left + (rect.width / 2) - (popWidth / 2); | |||
if (left < 10) left = 10; | |||
if (top < 10) top = rect.bottom + 10; | |||
popover.style.bottom = 'auto'; | |||
popover.style.transform = 'none'; | |||
popover.style.top = top + 'px'; | |||
popover.style.left = left + 'px'; | |||
popover.style.display = 'block'; | |||
} | } | ||
btn.onclick = function (e) { | |||
e.stopPropagation(); | |||
e.preventDefault(); | |||
getShortUrlAsync().then(function (shortUrl) { | |||
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 output = | |||
'“' + currentText + '”\n' + | |||
'---------------------\n' + | |||
'来源:' + site + '\n' + | |||
'标题:' + title + '\n' + | |||
'地址:' + shortUrl + '\n\n' + | |||
'转载请保持原文,随喜分享,Sadhu!'; | |||
if (navigator.clipboard && navigator.clipboard.writeText) { | |||
navigator.clipboard.writeText(output).then(function () { | |||
showSuccess(btn, popover); | |||
}).catch(function () { | |||
fallbackCopy(output, btn, popover); | |||
}); | |||
} else { | |||
fallbackCopy(output, btn, popover); | |||
} | |||
}); | |||
}; | |||
} | |||
} | } | ||
// 5. 复制成功反馈与降级机制 | |||
/ | function showSuccess(btn, popover) { | ||
btn.innerText = '✅ 已复制开示及出处'; | |||
btn.style.background = '#2e7d32'; | |||
setTimeout(function () { | |||
btn.innerText = ' 复制该段开示(含出处)'; | |||
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); | |||
showSuccess(btn, popover); | |||
); | |||
} | } | ||
document.addEventListener('mouseup', function () { setTimeout(handleSelection, 30); }); | |||
document.addEventListener('touchend', function () { setTimeout(handleSelection, 50); }); | |||
document.addEventListener('mousedown', function (e) { | |||
var pop = document.getElementById('dhamma-copy-popover'); | |||
if (pop && !pop.contains(e.target)) { | |||
pop.style.display = 'none'; | |||
document | |||
} | } | ||
); | }); | ||
} | } | ||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', initDhammaCopy); | |||
} else { | |||
initDhammaCopy(); | |||
} | } | ||
})(); | |||
2026年9月20日 (日) 01:05的最新版本
/* =========================================================
Dhamma.cn 划词复制开示及 UrlShortener 短网址落款(移动端遮挡修复版)
适用于:MediaWiki:Common.js
========================================================= */
(function () {
if (window.dhammaCopyLoaded) return;
window.dhammaCopyLoaded = true;
function initDhammaCopy() {
var cachedShortUrl = '';
// 判断是否为移动端 / 触摸设备
function isMobileDevice() {
return ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (window.innerWidth <= 768);
}
// 1. 统一域名规范化:剥离 www 及所有二级域名(如 reg.dhamma.cn),强转为 https://dhamma.cn
function forceMainDomain(url) {
if (!url) return 'https://dhamma.cn';
if (url.indexOf('http') !== 0) {
return 'https://dhamma.cn' + (url.indexOf('/') === 0 ? '' : '/') + url;
}
return url.replace(/^https?:\/\/[^\/]+/, 'https://dhamma.cn');
}
// 2. 异步获取真正的当前页面短网址
function getShortUrlAsync() {
if (cachedShortUrl) return Promise.resolve(cachedShortUrl);
// 仅在侧边栏/工具栏查找官方短网址,严禁扫描正文(#bodyContent)内的嵌入链接
var tShort = document.querySelector('#t-shorturl a, #p-tb a[href*="/s/"], .mw-portlet-tb a[href*="/s/"], li[id*="shorturl"] a');
if (tShort && tShort.href && tShort.href.indexOf('/s/') !== -1) {
cachedShortUrl = forceMainDomain(tShort.href);
return Promise.resolve(cachedShortUrl);
}
// 获取页面规范网址
var canonicalEl = document.querySelector('link[rel="canonical"]');
var targetUrl = canonicalEl ? canonicalEl.href : window.location.href;
// 优先使用 MediaWiki 原生 Api 模块(带 CSRF Token)
if (window.mw && mw.Api) {
return new mw.Api().post({
action: 'shortenurl',
url: targetUrl
}).then(function (data) {
if (data && data.shortenurl && data.shortenurl.shorturl) {
cachedShortUrl = forceMainDomain(data.shortenurl.shorturl);
} else {
cachedShortUrl = forceMainDomain(targetUrl);
}
return cachedShortUrl;
}).catch(function () {
return fallbackFetchApi(targetUrl);
});
} else {
return fallbackFetchApi(targetUrl);
}
}
// 降级 Fetch 请求(带 CSRF Token)
function fallbackFetchApi(targetUrl) {
var scriptPath = (window.mw && mw.config && mw.config.get('wgScriptPath')) || '';
var apiUrl = scriptPath + '/api.php';
var token = (window.mw && mw.user && mw.user.tokens && mw.user.tokens.get('csrfToken')) || '+\\';
var params = new URLSearchParams();
params.append('action', 'shortenurl');
params.append('format', 'json');
params.append('url', targetUrl);
params.append('token', token);
return fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: params.toString()
})
.then(function (res) { return res.json(); })
.then(function (data) {
if (data && data.shortenurl && data.shortenurl.shorturl) {
cachedShortUrl = forceMainDomain(data.shortenurl.shorturl);
} else {
cachedShortUrl = forceMainDomain(targetUrl);
}
return cachedShortUrl;
})
.catch(function () {
cachedShortUrl = forceMainDomain(targetUrl);
return cachedShortUrl;
});
}
// 静默预取短网址
getShortUrlAsync();
// 3. 创建/获取浮窗节点
function getPopover() {
var pop = document.getElementById('dhamma-copy-popover');
if (!pop) {
pop = document.createElement('div');
pop.id = 'dhamma-copy-popover';
pop.style.cssText = 'display:none; position:fixed; z-index:2147483647; background:#ffffff; border:1px solid rgba(0,0,0,0.15); border-radius:30px; box-shadow:0 8px 24px rgba(0,0,0,0.22); padding:6px 8px; font-size:14px; white-space:nowrap; transition:bottom 0.2s ease, opacity 0.2s ease;';
var btn = document.createElement('button');
btn.id = 'dhamma-copy-btn';
btn.innerText = ' 复制该段开示(含出处)';
btn.style.cssText = 'background:#4d6b57; color:#ffffff; border:none; border-radius:20px; padding:8px 18px; font-size:14px; cursor:pointer; font-weight:600; font-family:sans-serif; -webkit-tap-highlight-color:transparent;';
btn.onmouseover = function () { if (this.innerText.indexOf('✅') === -1) this.style.background = '#3b5343'; };
btn.onmouseout = function () { if (this.innerText.indexOf('✅') === -1) this.style.background = '#4d6b57'; };
pop.appendChild(btn);
document.body.appendChild(pop);
}
return pop;
}
var currentText = '';
// 4. 处理划词选择逻辑(响应式适配 PC / 移动端定位)
function handleSelection() {
var popover = getPopover();
var btn = document.getElementById('dhamma-copy-btn');
var sel = window.getSelection();
var text = sel ? sel.toString().trim() : '';
if (!text || text.length < 2) {
popover.style.display = 'none';
return;
}
currentText = text;
if (sel.rangeCount > 0) {
var isMobile = isMobileDevice();
if (isMobile) {
// 📱 移动端解决遮挡的核心方案:固定在屏幕底部中央,并兼容 iPhone 底部安全区
popover.style.top = 'auto';
popover.style.bottom = 'calc(25px + env(safe-area-inset-bottom, 0px))';
popover.style.left = '50%';
popover.style.transform = 'translateX(-50%)';
popover.style.display = 'block';
} else {
// 💻 PC 端:跟随选中区域在上方居中弹出
var range = sel.getRangeAt(0);
var rect = range.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) {
popover.style.display = 'none';
return;
}
var popWidth = popover.offsetWidth || 200;
var popHeight = popover.offsetHeight || 40;
var top = rect.top - popHeight - 10;
var left = rect.left + (rect.width / 2) - (popWidth / 2);
if (left < 10) left = 10;
if (top < 10) top = rect.bottom + 10;
popover.style.bottom = 'auto';
popover.style.transform = 'none';
popover.style.top = top + 'px';
popover.style.left = left + 'px';
popover.style.display = 'block';
}
btn.onclick = function (e) {
e.stopPropagation();
e.preventDefault();
getShortUrlAsync().then(function (shortUrl) {
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 output =
'“' + currentText + '”\n' +
'---------------------\n' +
'来源:' + site + '\n' +
'标题:' + title + '\n' +
'地址:' + shortUrl + '\n\n' +
'转载请保持原文,随喜分享,Sadhu!';
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(output).then(function () {
showSuccess(btn, popover);
}).catch(function () {
fallbackCopy(output, btn, popover);
});
} else {
fallbackCopy(output, btn, popover);
}
});
};
}
}
// 5. 复制成功反馈与降级机制
function showSuccess(btn, popover) {
btn.innerText = '✅ 已复制开示及出处';
btn.style.background = '#2e7d32';
setTimeout(function () {
btn.innerText = ' 复制该段开示(含出处)';
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);
showSuccess(btn, popover);
}
document.addEventListener('mouseup', function () { setTimeout(handleSelection, 30); });
document.addEventListener('touchend', function () { setTimeout(handleSelection, 50); });
document.addEventListener('mousedown', function (e) {
var pop = document.getElementById('dhamma-copy-popover');
if (pop && !pop.contains(e.target)) {
pop.style.display = 'none';
}
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initDhammaCopy);
} else {
initDhammaCopy();
}
})();
