コンテンツにスキップ

利用者:MawaruNeko/CustomWikiEditor.js

お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。

多くの WindowsLinux のブラウザ

  • Ctrl を押しながら F5 を押す。

Mac における Safari

  • Shift を押しながら、更新ボタン をクリックする。

Mac における ChromeFirefox

  • Cmd Shift を押しながら R を押す。

詳細についてはWikipedia:キャッシュを消すをご覧ください。

/*
 * 改良型編集ツールバーに各種ボタンを追加するカスタムJS
 * Custom JS to add custom tools to WikiEditor
 * 
 * 説明:
 *   改良型編集ツールバーにコメントテンプレートなどを追加します。
 *   カスタムJSとして導入するか、コピーして使用してください。
 *   カスタマイズする場合は、[[Wikipedia:カスタムJS#改良型編集ツールバーの拡張]]を参照してください。
 * 
 * このファイルはパブリックドメインとします。
 * 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,
    panelDialog: null,
  };
  function createSourceDialog() {
    function PanelDialog(config) {
      PanelDialog.super.call(this, config);
    }
    OO.inheritClass(PanelDialog, OO.ui.MessageDialog);

    PanelDialog.static.name = 'panelDialog';
    PanelDialog.static.actions = [{ action: 'accept', label: 'Close' }];

    PanelDialog.prototype.initialize = function () {
      PanelDialog.super.prototype.initialize.apply(this, arguments);
      var dialog = this;

      this.sourcePanel = new OO.ui.PanelLayout({ padded: true, expanded: false, scrollable: true, classes: ['show-source-links-panel'] });
      this.container.$element.append(this.sourcePanel.$element);
    };

    PanelDialog.prototype.getBodyHeight = function () {
      return PanelDialog.super.prototype.getBodyHeight.call(this) +
        this.sourcePanel.$element.outerHeight(true);
    };

    sourceDialog.windowManager = new OO.ui.WindowManager();
    $('body').append(sourceDialog.windowManager.$element);

    sourceDialog.panelDialog = new PanelDialog();
    sourceDialog.windowManager.addWindows([sourceDialog.panelDialog]);
  }

  function showSourceDialog(source, config) {
    if (!sourceDialog.windowManager) {
      createSourceDialog();
    }
    sourceDialog.panelDialog.sourcePanel.$element.empty();

    var instance = sourceDialog.windowManager.openWindow(sourceDialog.panelDialog, { size: 'large' });

    instance.opened.then(function () {
      var linksContent = getLinkElements(source, config);
      sourceDialog.panelDialog.sourcePanel.$element.empty().append(linksContent);
    });
  }

  function encapsulateSetting(pre, post, label, peri) {
    pre = pre || '';
    post = post || '';
    peri = peri || '';
    label = label || (pre + peri + post);
    return {
      label: label,
      action: {
        type: 'encapsulate',
        options: {
          pre: pre,
          peri: peri,
          post: post,
        }
      },
    };
  }

  function getSettings(config) {
    var dateNow = new Date();
    var isoDateMonth = dateNow.getUTCFullYear() + '-' + (dateNow.getUTCMonth() + 1);
    var isoDateMonthDay = dateNow.getUTCFullYear() + '-' + (dateNow.getUTCMonth() + 1) + '-' + dateNow.getUTCDate();
    var jaDateMonth = dateNow.getUTCFullYear() + '年' + (dateNow.getUTCMonth() + 1) + '月';

    var settings = {
      sections: {}
    };


    settings.sections['editBooklet'] = {
      type: 'booklet',
      label: '編集',
      pages: {},
    };

    settings.sections['editBooklet'].pages['editPage'] = {
      label: '編集',
      layout: 'characters',
      characters: [
        {
          label: '改行削除',
          action: {
            type: 'encapsulate',
            options: {
              regex: /\r|\n/g,
              regexReplace: '',
            }
          },
        },
        {
          label: 'リンクを表示',
          action: {
            type: 'callback',
            execute: function(context) {
              showSourceDialog(context.$textarea.val(), config);
            }
          },
        },
      ],
    };

    settings.sections['editBooklet'].pages['replaceTags'] = {
      label: 'タグ置換',
      layout: 'characters',
      characters: [
        {
          label: '改行 -> <br/>',
          action: {
            type: 'encapsulate',
            options: {
              regex: /\r|\n/g,
              regexReplace: '<br/>',
            }
          },
        },
        {
          label: '<font color=""> -> {{font color|$1|',
          action: {
            type: 'encapsulate',
            options: {
              regex: /<font\ *color\ *\=\ *(\"|\')?(\#[0-9a-fA-F]+|\w+)(\"|\')?\ *>/g,
              regexReplace: '{{font color|$2|',
            }
          },
        },
        {
          label: '</font\ *> -> }}',
          action: {
            type: 'encapsulate',
            options: {
              regex: /<\/font>/g,
              regexReplace: '}}',
            }
          },
        },
      ],
    };


    settings.sections['commentBooklet'] = {
      type: 'booklet',
      label: 'コメント',
      pages: {},
    };

    if (config.wgNamespaceNumber === 4 && config.wgPageName.includes('削除依頼')) {
      settings.sections['commentBooklet'].pages['AFDcomments'] = {
        label: '削除依頼',
        layout: 'characters',
        characters: [
          '{{AFD|削除}}',
          '{{AFD|全削除}}',
          '{{AFD|即時削除}}',
          '{{AFD|一部}}',
          '{{AFD|一部削除}}',
          '{{AFD|一部存続}}',
          '{{AFD|特定版}}',
          '{{AFD|特定版削除}}',
          '{{AFD|版指定}}',
          '{{AFD|版指定削除}}',
          '{{AFD|即時版指定}}',
          '{{AFD|即時版指定削除}}',
          '{{AFD|緊急削除}}',
          '{{AFD|緊急}}',
          '{{AFD|緊急特定版削除}}',
          '{{AFD|緊急版指定}}',
          '{{AFD|緊急版指定削除}}',
          '{{AFD|緊急即時削除}}',
          '{{AFD|緊急即時}}',
          '{{AFD|存続}}',
          '{{AFD|全存続}}',
          '{{AFD|即時存続}}',
          '{{AFD|移動}}',
          '{{AFD|他プロジェクトへ移動}}',
          '{{AFD|取り下げ}}',
          '{{AFD|終了}}',
          '{{AFD|保留}}',
          '{{AFD|コメント}}',
          '{{AFD|コ}}',
        ],
      };
    }

    if (config.wgNamespaceNumber === 4 && config.wgPageName.includes('保護') && config.wgPageName.includes('依頼')) {
      settings.sections['commentBooklet'].pages['RFPcomments'] = {
        label: '保護依頼',
        layout: 'characters',
        characters: [
          '{{RFP|保護}} ',
          '{{RFP|半保護}} ',
          '{{RFP|移動}} ',
          '{{RFP|白紙}} ',
          '{{RFP|半白紙}} ',
          '{{RFP|継続}} ',
          '{{RFP|解除}}',
          '{{RFP|解除2}} ',
          '{{RFP|反対}} ',
          '{{RFP|終了}} ',
          '{{RFP|保留}} ',
          '{{RFP|コメント}} ',
        ],
      };
    }

    if (config.wgNamespaceNumber === 4 && config.wgPageName.includes('ブロック依頼')) {
      settings.sections['commentBooklet'].pages['BLcomments'] = {
        label: 'ブロック依頼',
        layout: 'characters',
        characters: [
          '{{BL|賛成}}',
          '{{BL|賛成|対話の結果次第|3ヶ月}}',
          '{{BL|反対}}',
          '{{BL|反対|対話の結果次第}}',
          '{{BL|即時終了}}',
          '{{BL|中立}}',
          '{{BL|棄権}}',
          '{{BL|保留}}',
          '{{BL|コメント}}',
          '{{BL|延長}}',
          '{{BL|延長|対話の結果次第|1年}}',
          '{{BL|維持}}',
          '{{BL|維持|対話の結果次第}}',
          '{{BL|解除}}',
          '{{BL|解除|対話の結果次第}}',
          '{{BL|短縮}}',
          '{{BL|短縮|対話の結果次第}}',
          '{{BL|継続}}',
          '{{BL|継続|対話の結果次第}}',
          '{{BL|追認}}',
          '{{BL|追認|対話の結果次第|3ヶ月}}',
          '{{BL|質問}}',
          '{{BL|情報}}',
          '{{BL|報告}}',
          '{{BL|取り下げ}}',
          '{{BL|終了提案}}',
        ],
      };
    }

    settings.sections['commentBooklet'].pages['discussion'] = {
      label: '議論',
      layout: 'characters',
      characters: [
        '{{賛成}}',
        '{{条件付賛成}}',
        '{{賛成r}}',
        '{{反対}}',
        '{{条件付反対}}',
        '{{反対r}}',
        '{{保留}}',
        '{{ニュートラル}}',
        '{{棄権}}',
        '{{コメント}}',
        '{{コ|(コメント)}}',
        '{{返信}}',
        '{{返|(宛先)}}',
        '{{提案}}',
        '{{理由}}',
        '{{問}}',
        '{{情報}}',
        '{{報告}}',
        '{{撤回}}',
      ],
    };

    settings.sections['commentBooklet'].pages['discussion2'] = {
      label: '議論2',
      layout: 'characters',
      characters: [
        '{{支持}}',
        '{{コメント2|横から失礼}}',
        '{{無関係}}',
        '{{Attention}}',
        '{{Attention2}}',
        '{{Warnsign}}',
        '{{おそらく}}',
        '{{ありそうにない}}',
        '{{移譲}}',
        '{{メモ}}',
        '{{終了依頼}}',
        '{{補助メモ}}',
        '{{補助要求}}',
        '{{追加情報}}',
        '{{非決定的}}',
        '{{追記}}',
        '{{除外}}',
        '{{不必要}}',
        '{{不要}}',
        '{{除去}}',
        '{{維持}}',
        '{{コメント2|維持r}}',
        '{{現状維持}}',
        '{{現状維持|r}}',
        '{{存続}}',
        '{{存続|存続r}}',
        '{{存続|全}}',
        '{{存続|全存続}}',
        '{{存続|全r}}',
        '{{存続|全存続r}}',
        '{{存続|即時}}',
        '{{存続|即時存続}}',
        '{{存続|即時r}}',
        '{{存続|即時存続r}}',
        '{{存続|一部}}',
        '{{存続|一部存続}}',
        '{{存続|一部r}}',
        '{{存続|一部存続r}}',
      ],
    };

    settings.sections['commentBooklet'].pages['discussionEnd'] = {
      label: '終了',
      layout: 'characters',
      characters: [
        '{{レ}}',
        '{{済}}',
        '{{完了}}',
        '{{対処}}',
        '{{確認}}',
        '{{可能}}',
        '{{追加済}}',
        '{{×}}',
        '{{中止}}',
        '{{却下}}',
        '{{自動失効}}',
        '{{依頼無効}}',
        '{{取り下げ}}',
        '{{受付除外}}',
        '{{未了}}',
        '{{未了2}}',
        '{{謝絶}}',
        '{{時間切れ}}',
        '{{終了}}',
        '{{Close}}',
        '{{再受付}}',
        '{{作業中}}',
      ],
    };

    settings.sections['commentBooklet'].pages['discussionThanks'] = {
      label: '感謝',
      layout: 'characters',
      characters: [
        '{{感謝}}',
        '{{感謝2}}',
        '{{笑顔}}',
        '{{花}}',
      ],
    };

    settings.sections['commentBooklet'].pages['discussionState'] = {
      label: '話題の状態',
      layout: 'characters',
      characters: [
        '{{済み}}',
        '{{失効}}',
        '{{スタック}}',
        '{{解決済み}}',
        '{{未解決}}',
      ],
    };


    settings.sections['layoutBooklet'] = {
      type: 'booklet',
      label: 'レイアウト',
      pages: {},
    };

    settings.sections['layoutBooklet'].pages['sfnPage'] = {
      label: 'Sfn',
      layout: 'characters',
      characters: [
      	'{{Sfn|author|YYYY|p=}}',
      	'{{Harv|author|YYYY|p=}}',
      	'{{Harvnb|author|YYYY|p=}}',
      	'{{SfnRef|author|YYYY}}',
      ],
    };

    settings.sections['layoutBooklet'].pages['notePage'] = {
      label: '脚注',
      layout: 'characters',
      characters: [
      	encapsulateSetting('{{efn2|', '}}'),
      	'{{notelist2}}',
      ],
    };

    settings.sections['layoutBooklet'].pages['formatPage'] = {
      label: '書式',
      layout: 'characters',
      characters: [
        encapsulateSetting('{{Color|red|', '}}'),
        encapsulateSetting('{{Color|#00F000|', '}}'),
        encapsulateSetting('{{fontsize|12px|', '}}'),
        encapsulateSetting('{{Center|', '}}'),
        encapsulateSetting('{{Del|', '}}'),
        encapsulateSetting('<s>', '</s>'),
        encapsulateSetting('<code>', '</code>'),
        encapsulateSetting('<source lang="javascript">', '</source>'),
        encapsulateSetting('<kbd>', '</kbd>'),
        encapsulateSetting('<var>', '</var>'),
        encapsulateSetting('<samp>', '</samp>'),
      ],
    };


    settings.sections['cleanupBooklet'] = {
      type: 'booklet',
      label: '問題',
      pages: {},
    };

    settings.sections['cleanupBooklet'].pages['cleanupHeadPage'] = {
      label: '見出し',
      layout: 'characters',
      characters: [
        '{{特筆性|date=' + jaDateMonth + '}}',
        '{{観点|date=' + jaDateMonth + '}}',
        '{{国際化|date=' + jaDateMonth + '}}',
        '{{宣伝|date=' + jaDateMonth + '}}',
        '{{存命人物の出典明記|date=' + jaDateMonth + '}}',
        '{{BLP unsourced|date=' + jaDateMonth + '}}',
        '{{スポーツ選手の出典明記|section=1|date=' + jaDateMonth + '}}',
        '{{出典の明記|date=' + jaDateMonth + '}}',
        '{{単一の出典|date=' + jaDateMonth + '}}',
        '{{単一の出典|section=1|date=' + jaDateMonth + '}}',
        '{{一次資料|date=' + jaDateMonth + '}}',
        '{{一次資料|section=1|date=' + jaDateMonth + '}}',
        '{{精度|date=' + jaDateMonth + '}}',
        '{{精度|date=' + jaDateMonth + '|section=1}}',
        '{{未検証|date=' + jaDateMonth + '}}',
        '{{未検証|date=' + jaDateMonth + '|talk=ノート:XXXXXXXX|section=1}}',
        '{{ページ番号|date=' + jaDateMonth + '}}',
        '{{参照方法|date=' + jaDateMonth + '}}',
        '{{参照方法|date=' + jaDateMonth + '|section=1}}',
        '{{No footnotes|date=' + jaDateMonth + '}}',
        '{{No footnotes|date=' + jaDateMonth + '|section=1}}',
        '{{No footnotes|date=' + jaDateMonth + '|BLP=yes}}',
        '{{脚注の不足|date=' + jaDateMonth + '}}',
        '{{脚注の不足|date=' + jaDateMonth + '|section=1}}',
        '{{脚注の不足|date=' + jaDateMonth + '|BLP=yes}}',
        '{{Ibid|date=' + jaDateMonth + '}}',
        '{{TVWATCH}}',
        '{{RADIOLISTEN}}',
        '{{医学の情報源|date=' + jaDateMonth + '}}',
        '{{医学の情報源|section|date=' + jaDateMonth + '}}',
        '{{独自研究|date=' + jaDateMonth + '}}',
        '{{独自研究|section=1|date=' + jaDateMonth + '}}',
        '{{Cleanup|date=' + jaDateMonth + '}}',
        '{{Cleanup|section=1|date=' + jaDateMonth + '}}',
        '{{Wikify|date=' + jaDateMonth + '}}',
        '{{リンクのみの節}}',
        '{{年譜のみの経歴|date=' + jaDateMonth + '}}',
        '{{色の過剰使用}}',
        '{{一部ブラウザで表示できない}}',
        '{{一部ブラウザで表示できない|問題のブラウザ}}',
        '{{導入部がない|date=' + jaDateMonth + '}}',
        '{{導入部が短い|date=' + jaDateMonth + '}}',
        '{{導入部が長い|date=' + jaDateMonth + '}}',
        '{{導入部がおかしい|date=' + jaDateMonth + '}}',
        '{{概要節がおかしい|date=' + jaDateMonth + '}}',
        '{{雑多な内容の箇条書き|date=' + jaDateMonth + '}}',
        '{{雑多な内容の箇条書き|section=1|date=' + jaDateMonth + '}}',
        '{{内容過剰|date=' + jaDateMonth + '|該当ポータル・プロジェクトの運用基準が記されているページ名}}',
        '{{画像過剰|date=' + jaDateMonth + '}}',
        '{{リンク過剰||date=' + jaDateMonth + '}}',
        '{{関連項目過剰|date=' + jaDateMonth + '}}',
        '{{百科事典的でない|date=' + jaDateMonth + '|t=Wikipedia‐ノート:ウィキペディアは何ではないか}}',
        '{{百科事典的でない|date=' + jaDateMonth + '|section=1}}',
        '{{字引|date=' + jaDateMonth + '}}',
        '{{百科事典的でない|date=' + jaDateMonth + '|t=Wikipedia‐ノート:ウィキペディアは何ではないか}}',
        '{{百科事典的でない|date=' + jaDateMonth + '|section=1}}',
        '{{正確性|date=' + jaDateMonth + '}}',
        '{{正確性|date=' + jaDateMonth + '|疑問点の要約}}',
        '{{正確性|date=' + jaDateMonth + '|section=1}}',
        '{{大言壮語|date=' + jaDateMonth + '}}',
        '{{大言壮語|date=' + jaDateMonth + '|section=1}}',
        '{{言葉を濁さない|date=' + jaDateMonth + '}}',
        '{{不十分なあらすじ|date=' + jaDateMonth + '}}',
        '{{要あらすじ}}',
        '{{物語世界内の観点|date=' + jaDateMonth + '}}',
        '{{物語内容のみ|date=' + jaDateMonth + '}}',
        '{{外部リンクの注意}}',
        '{{外部リンクの注意|section=1}}',
        '{{Rough translation|言語名}}',
        '{{要改訳}}',
      ],
    };

    settings.sections['cleanupBooklet'].pages['cleanupNotePage'] = {
      label: '注釈',
      layout: 'characters',
      characters: [
        '{{要検証|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{要検証範囲|date=' + jaDateMonth + '|', '}}'),
        '{{信頼性要検証|date=' + isoDateMonth + '}}',
        '{{要出典|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{要出典範囲|date=' + jaDateMonth + '|', '}}'),
        '{{要ページ番号|date=' + jaDateMonth + '}}',
        '{{Full citation needed|date=' + jaDateMonth + '}}',
        '{{出典無効|date=' + isoDateMonthDay + '}}',
        '{{リンク切れ|date=' + jaDateMonth + '}}',
        '{{要出典医学|date=' + jaDateMonth + '}}',
        '{{信頼性の低い医学の情報源|date=' + jaDateMonth + '}}',
        '{{誰|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{誰範囲|date=' + jaDateMonth + '|', '}}'),
        '{{誰2|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{誰範囲2|date=' + jaDateMonth + '|', '}}'),
        '{{いつ|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{いつ範囲|date=' + jaDateMonth + '|', '}}'),
        '{{どこ|date=' + jaDateMonth + '}}',
        '{{どれ|date=' + jaDateMonth + '}}',
        '{{How|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{独自研究範囲|date=' + jaDateMonth + '|', '}}'),
        '{{Synthesis-inline}}',
        '{{疑問点|date=' + jaDateMonth + '|title=|talksection=}}',
        encapsulateSetting('{{疑問点範囲|date=' + jaDateMonth + '|', '}}'),
        '{{読み疑問点|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{要追加記述範囲|date=' + jaDateMonth + '|', '}}'),
        '{{要曖昧さ回避|date=' + jaDateMonth + '}}',
        '{{要説明|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{要説明範囲|date=' + jaDateMonth + '|', '}}'),
        '{{訳語疑問点|date=' + jaDateMonth + '}}',
        encapsulateSetting('{{訳語疑問点範囲|date=' + jaDateMonth + '|', '}}'),
      ],
    };

    return settings;
  }

  function customizeEditform(config) {
    mw.util.addCSS(
      '.show-source-links-panel { white-space: pre-wrap; height: 40em; }\n' +
      ''
    );

    $(document.editform.wpTextbox1).wikiEditor('addToToolbar', getSettings(config));
  }

  $(function () {
    mw.loader.using(['mediawiki.util', 'user.options', 'mediawiki.Title', 'oojs-ui']).then(function () {
      if (document.editform) {
        var config = mw.config.get(['wgAction', 'wgNamespaceNumber', 'wgNamespaceIds', 'wgPageName']);
        if (mw.user.options.get('usebetatoolbar') == 1) {
          mw.loader.using('ext.wikiEditor').then(function () {
            customizeEditform(config);
          });
        }
      }
    });
  });
}) ();