利用者:MawaruNeko/ShowSource.js
表示
お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。
多くの Windows や Linux のブラウザ
- Ctrl を押しながら F5 を押す。
Mac における Safari
Mac における Chrome や Firefox
- ⌘ Cmd と ⇧ Shift を押しながら R を押す。
詳細についてはWikipedia:キャッシュを消すをご覧ください。
/*
* ソースを表示するカスタムJS
* Custom JS to show wiki source
*
* 説明:
* カスタムJSとして導入して下さい。
* ページのWikiのソース・各章のWikiのソースを表示するリンクを作成します。
* * ページ上部の「閲覧」・「編集」タブの間に
* * ページ先頭
* * 目次が表示されている場合は、各章の見出し
* ソースは、Wikiのソースと、テンプレート展開後のソースを表示することができます。
* ダイアログのSourceタブではテキストエリアにWikiソースを、
* Linksタブでは内部リンクとテンプレートをリンク型式で表示します。
* 内部リンクとテンプレートは、[[]]、{{}}で囲われたものをリンクと認識するため、
* <nowiki>タグ内などにあっても認識してしまいます。
* また、サブページのリンクには対応していません。
*
* Description:
* Use this file as custom JS.
* This script creates links to show wiki source.
* * between the tab of view and edit
* * on the top of the page
* * on each header if the table of contents exists
* Wiki source can be shown in original or expanded.
* Wiki source is shown in dialog;
* Source tab in the dialog shows Wiki source in textarea.
* Links tab shows Wiki source with links of templates.
* The recognition of links has some limitations.
*
* このファイルはパブリックドメインとします。
* This file is public domain.
*/
(function () {
'use strict';
var spaceRegexp = /\s/gm;
/* create link elements from wikiSource */
function getLinkElements(wikiSource, config) {
var ns_template = config.wgNamespaceIds.template;
var pageName = config.wgPageName;
function getLinkPageName(linkName) {
linkName = linkName.replace(spaceRegexp, ' ');
var firstChar = (linkName.slice(0, 1) === '/');
if (firstChar === '/') {
return pageName + linkName;
} else {
try {
return new mw.Title(linkName).getPrefixedText();
} catch (exception) {
return null;
}
}
}
function getTemplatePageName(templateName) {
templateName = templateName.replace(spaceRegexp, ' ');
var firstChar = (templateName.slice(0, 1) === '/');
if (firstChar === '/') {
return pageName + templateName;
} else {
try {
return new mw.Title(templateName, ns_template).getPrefixedText();
} catch (exception) {
return null;
}
}
}
var linkRegexp = /\[\[([^\{\}\[\]<>\#\|]+)(\]\]|\|)/mg;
var linkNameIndex = 1;
var linkNameIndexInRegexp = 2;
var templateRegexp = /\{\{([^\{\}\[\]<>\#\|]+)(\}\}|\|)/mg;
var templateNameIndex = 1;
var templateNameIndexInRegexp = 2;
function getPositions(regexp, nameIndex, nameIndexInRegexp, toPageName) {
var r = new RegExp(regexp);
var match;
var results = [];
while ((match = r.exec(wikiSource))) {
var name = match[nameIndex];
var pageName = toPageName(name);
if (pageName) {
results.push({
startPos: (match.index + nameIndexInRegexp),
name: name,
pageName: pageName,
url: mw.util.getUrl(pageName),
});
}
/* if toPageName cannot parse name, just skip it */
}
return results;
}
var positionResults = getPositions(linkRegexp, linkNameIndex, linkNameIndexInRegexp, getLinkPageName).
concat(getPositions(templateRegexp, templateNameIndex, templateNameIndexInRegexp, getTemplatePageName)).
sort(function (a, b) { return a.startPos - b.startPos; });
var elements = [];
var restStrPos = 0;
positionResults.forEach(function (position, index) {
var pre = wikiSource.slice(restStrPos, position.startPos);
elements.push(document.createTextNode(pre));
elements.push($('<a>').attr('target', '_blank').attr('href', position.url).attr('title', position.pageName).text(position.name));
restStrPos = position.startPos + position.name.length;
});
var restStr = wikiSource.slice(restStrPos);
elements.push(document.createTextNode(restStr));
return elements;
}
var sourceDialog = {
windowManager: null,
tabDialog: null,
sourceTextInput: null,
linksTabPanel: null,
linksPanel: null,
};
function createSourceDialog() {
/* MessageDialog with Tab IndexLayout */
/* config.tabPanels: tab panels */
function TabDialog(config) {
TabDialog.super.call(this, config);
this.tabPanels = config.tabPanels;
}
OO.inheritClass(TabDialog, OO.ui.MessageDialog);
TabDialog.static.name = 'tabDialog';
TabDialog.static.actions = [{ action: 'accept', label: 'Close' }];
TabDialog.prototype.initialize = function () {
TabDialog.super.prototype.initialize.apply(this, arguments);
var dialog = this;
this.indexLayout = new OO.ui.IndexLayout();
this.indexLayout.addTabPanels(this.tabPanels);
/*
this.indexLayout.on('set', function (tabPanel) {
dialog.updateSize();
});
*/
this.indexLayout.setTabPanel(this.tabPanels[0].name);
this.container.$element.append(this.indexLayout.$element);
this.bodyHeight = null;
};
TabDialog.prototype.getBodyHeight = function () {
/* plus 5 for workaround to avoid showing scroll */
this.bodyHeight = this.bodyHeight || TabDialog.super.prototype.getBodyHeight.call(this) +
this.indexLayout.getCurrentTabPanel().$element.outerHeight(true) + 5;
return this.bodyHeight;
};
TabDialog.prototype.getSetupProcess = function (data) {
this.indexLayout.setTabPanel(this.tabPanels[0].name);
return TabDialog.super.prototype.getSetupProcess.call(this, data);
};
sourceDialog.windowManager = new OO.ui.WindowManager();
$('body').append(sourceDialog.windowManager.$element);
var sourceTabPanel = new OO.ui.TabPanelLayout('source', { label: 'Source', padded: true, expanded: false });
sourceDialog.linksTabPanel = new OO.ui.TabPanelLayout('links', { label: 'Links', padded: true, expanded: true });
sourceDialog.sourceTextInput = new OO.ui.MultilineTextInputWidget({ readOnly: true, rows: 20 });
sourceTabPanel.$element.append(sourceDialog.sourceTextInput.$element);
sourceDialog.linksPanel = new OO.ui.PanelLayout({ padded: true, expanded: false, scrollable: true, classes: ['show-source-links-panel'] });
sourceDialog.linksTabPanel.$element.append(sourceDialog.linksPanel.$element);
sourceDialog.tabDialog = new TabDialog({ tabPanels: [ sourceTabPanel, sourceDialog.linksTabPanel ] });
sourceDialog.windowManager.addWindows([sourceDialog.tabDialog]);
}
function showSourceDialog(source, config) {
if (!sourceDialog.windowManager) {
createSourceDialog();
}
sourceDialog.sourceTextInput.setValue('');
sourceDialog.linksPanel.$element.empty();
var instance = sourceDialog.windowManager.openWindow(sourceDialog.tabDialog, { size: 'large' });
instance.opened.then(function () {
sourceDialog.sourceTextInput.setValue(source);
});
sourceDialog.linksTabPanel.once('active', function(){
var linksContent = getLinkElements(source, config);
sourceDialog.linksPanel.$element.empty().append(linksContent);
});
}
function setShowSourceInDialog(config) {
$(document).on('click', '.show-source-in-dialog', function (event) {
var url = $(this).attr('href');
$.get(url, function (source) {
showSourceDialog(source, config);
});
return false;
});
}
/* section: nullable */
/* needExpand: boolean */
function getWikiSourceUrl(title, curid, oldid, section, needExpand) {
var params = {
action: 'raw',
};
if (curid) {
params.curid = curid;
params.oldid = oldid;
} else {
params.title = title;
}
if (section || section === 0) {
params.section = section;
}
if (needExpand) {
params.templates = 'expand';
}
return mw.util.wikiScript() + '?' + $.param(params);
}
function main(config) {
$('span.mw-editsection a[href]').each(function () {
var $editLink = $(this);
var uri = new mw.Uri($(this).attr('href'));
if (uri.query.action === 'edit') {
var $headline = $editLink.closest('span.mw-editsection').prevAll('.mw-headline[id]');
$headline.
attr('data-section-number', uri.query.section.replace(/^T\-/, '')).
attr('data-title', uri.query.title);
}
});
$('#toc a .toctext').each(function (idx, toctextElem) {
var tocsectionClassNamePrefix = 'tocsection-';
var $toctextElem = $(toctextElem);
var href = $toctextElem.closest('a[href]').attr('href');
var tocsection = $toctextElem.closest('li').attr('class').split(' ').filter(function (className) {
return className.substr(0, tocsectionClassNamePrefix.length) === tocsectionClassNamePrefix;
}).map(function (className) {
return className.substr(tocsectionClassNamePrefix.length);
}) [0];
if (href.substr(0, 1) === '#' && tocsection) {
var anchor = href.substr(1);
if (anchor !== '') {
$(document.getElementById(anchor)).
attr('data-section-number', tocsection).
attr('data-curid', config.wgArticleId);
}
}
});
var topPlaceholder = $('<span>').attr('data-section-number', 0).attr('data-curid', config.wgArticleId);
if ($('#firstHeading .mw-editsection') [0]) {
$('#firstHeading .mw-editsection').before(topPlaceholder);
} else {
$('#firstHeading').append(topPlaceholder);
}
$('[data-section-number]').each(function (idx, elem) {
var $elem = $(elem);
var section = $elem.attr('data-section-number');
var title = $elem.attr('data-title');
var curid = $elem.attr('data-curid');
var $sourcesection = $('<span>').addClass('mw-editsection').insertAfter($elem);
$('<span>').addClass('mw-editsection-bracket').text('[').appendTo($sourcesection);
$('<a>').addClass('show-source-in-dialog').text('ソース').
attr('href', getWikiSourceUrl(title, curid, config.wgRevisionId, section)).appendTo($sourcesection);
$('<span>').addClass('mw-editsection-divider').css('margin-right', '0.25em').text('|').appendTo($sourcesection);
$('<a>').addClass('show-source-in-dialog').text('展開').
attr('href', getWikiSourceUrl(title, curid, config.wgRevisionId, section, true)).appendTo($sourcesection);
$('<span>').addClass('mw-editsection-bracket').text(']').appendTo($sourcesection);
});
/* show-source-in-dialog */
var $nextLiAfterCaView = $('#ca-view+*');
mw.util.addPortletLink ('p-views', getWikiSourceUrl(null, config.wgArticleId, config.wgRevisionId, null),
'ソース', 'ca-source-view', 'ソースを表示', null, $nextLiAfterCaView);
mw.util.addPortletLink ('p-views', getWikiSourceUrl(null, config.wgArticleId, config.wgRevisionId, null, true),
'展開', 'ca-source-expand', 'ソースを展開', null, $nextLiAfterCaView);
$('#ca-source-view a').addClass('show-source-in-dialog');
$('#ca-source-expand a').addClass('show-source-in-dialog');
setShowSourceInDialog(config);
mw.util.addCSS(
'.show-source-links-panel { white-space: pre-wrap; }\n' +
''
);
$('.mw-editsection-divider').show();
}
$(function () {
mw.loader.using(['mediawiki.util', 'mediawiki.Title', 'oojs-ui']).then(function () {
var config = mw.config.get(['wgAction', 'wgNamespaceNumber', 'wgArticleId', 'wgRevisionId', 'wgNamespaceIds', 'wgPageName']);
if ((config.wgAction === 'view') && (config.wgNamespaceNumber >= 0) && config.wgArticleId) {
main(config);
}
});
});
}) ();