ウィキペディアで各利用者が設定できるカスタムJavaScriptカスタムJS)について解説します。「ユーザースクリプト」のウィキペディア版なので、そうとも呼ばれます。これは各利用者が記述できるJavaScriptコードで、登録利用者の利用者空間利用者ページ)のサブページに置く(公開する)などすることで、そのウィキ(ウィキペディア日本語版といった範囲)でのページの表示時などに実行されるものです。様々な機能を実現することができます。

既存のカスタムJSを利用する場合はカスタムJSの一覧をご覧ください。ガジェットは共有されたJavaScriptで個人設定からクリックで導入できます。

導入方法

編集

標準の方法

編集
  1. この場合、カスタムJSを使用するには、まずアカウントを取得してログインします。
  2. スキン共通の各利用者用のcommon.jsを開きます。あるいは、各スキンでだけ使うには、標準のベクター2022年版スキン用には各利用者のvector-2022.jsを、ベクタークラシックスキン用には各利用者のvector.jsを使います。異なるスキンを使っている場合、特別:個人設定の「表示」タブから、使用しているスキンの「カスタムJS」を開きます。これらの js のページは、本人だけが編集できます。
  3. 上記の通り開いた common.js などの js のページに、使いたいコードを記述し保存します。既存のカスタムJS一覧の中からウィキペディア日本語版の利用者:ウィキ助/hoge.js に置かれているコードを使用する場合、次のように書いて保存します。
    mw.loader.load('//ja.wikipedia.org/w/index.php?title=利用者:ウィキ助/hoge.js&action=raw&ctype=text/javascript');
    
    他言語版または他プロジェクトに置かれているコードを使用する、例えば英語版User:Example/bar.js (実際にはありません)に置かれているコードを使用する場合は、次のように記述します。
    mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Example/bar.js&action=raw&ctype=text/javascript');
    
  4. キャッシュを消します。これで、各ページにて保存したスクリプトが実行されるようになります。

見本

編集

どのように編集してよいかよく分からないときは、ウィキペディア内で検索することで、他の利用者のJSを閲覧できます。まずそれを参考に編集していくと良いでしょう。

ブックマークレットを使う方法

編集

ブックマークレットとしてスクリプトのアドレスをブックマークしておくことで、使いたい時だけクリックして使用できます。たとえば利用者:Hogehoge/hoge.js にあるスクリプトをブックマークする場合、以下のURLで登録します。

javascript:(function(){mw.loader.load('//ja.wikipedia.org/w/index.php?title=User:Hogehoge/hoge.js&action=raw&ctype=text/javascript');})()

Greasemonkeyを使う方法

編集

Firefoxを使用している場合、Greasemonkeyにスクリプトを登録しておくことで、適宜 有効・無効を切り替えてスクリプトを利用できます(Firefox Add-onsでの紹介ページ)。アドオンのインストール後、Firefoxのメニューから「ツール」->「Greasemonkey」->「新規ユーザスクリプト」を開き、各項目を埋めて登録します。登録の方法はGreasemonkey 作り方などで検索してください。

Chromeであれば、Tampermonkeyが互換性のある拡張機能として使用できます。

カスタムJS以外のJavascript

編集

MediaWikiにはカスタムJS以外にJSを置く場所があります。

独自の変数と関数

編集

MediaWiki上でJavaScriptを動かす場合、次のような変数と関数を利用できます。

読み込まれるファイルの一覧は「en:Wikipedia:Catalogue of CSS classes(英語)」に記載されています。mw:ResourceLoader/Modulesには、MediaWikiの関数やjQueryについて説明されています。

初期化

編集
  • $( /* 関数 */ ) - ページの読み込みが完了する前、DOMの構築が終わった後に関数を実行します。$( document ).ready( /* 関数 */ ) と同等です。DOMの構築完了時点ではなく、画像などがロード完了してから実行したい場合は、$(window).load( /* 関数 */ )などが使用できます。
$(function() {
  /* ここに初期化コードを書く */
});

ロード

編集

JavaScriptのロード

編集

他のページにあるJavaScriptのスクリプトをロードします。JavaScriptのロードは基本的に非同期に行われます。他のJavaScriptのスクリプトやモジュールに依存したコードを書きたい場合は、mw.loader.using( /* モジュール名 */ ).then( /* 関数 */ )$.getScript( /* URI */ ).then( /* 関数 */ )を使用します。

  • mw.loader.load( /* URI */ ) - 任意のサイトの任意のページにあるJavaScriptソースを読み込みます(非同期)。URIで指定します。
例:
mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Foo/bar.js&action=raw&ctype=text/javascript');
  • mw.loader.load( /* モジュール名 */ ) - mw:ResourceLoader/Core modulesに記載されているJavaScriptのモジュールを読み込みます(非同期)。配列にすることで複数同時に読み込めます。モジュールを読み込んでから、依存する処理を行いたい場合はmw.loader.using( /* モジュール名 */ ).then( /* 関数 */ )を使用して下さい。
  • mw.loader.using( /* モジュール名 */ ).then( /* 関数 */ ) - mw:ResourceLoader/Core modulesに記載されているJavaScriptのモジュールを読み込んでから処理を行います。配列にすることで複数同時に読み込めます。
例:
mw.loader.using( 'mediawiki.util' ).then( function() {
  alert(mw.util.wikiUrlencode("ほげ"));
} );
  • $.getScript( /* URI */ ).then( /* 関数 */ ) - 任意のサイトの任意のページにあるJavaScriptソースを読み込んでから処理を行います。URIで指定します。リクエストがキャッシュされないため、下記の$.ajaxを用いた方がよいでしょう。
  • $.ajax( { dataType: "script", cache: true, url: /* URI */ } ).then( /* 関数 */ ) - 任意のサイトの任意のページにあるJavaScriptソースを読み込んでから処理を行います。URIで指定します。キャッシュを有効にしています。
関数化すると使いやすくなるでしょう。:
jQuery.getScriptWithCache = function(url, options) {
  return $.ajax($.extend(options || {}, {
    dataType: "script",
    cache: true,
    url: url,
  }));
};
 
$.getScriptWithCache('//en.wikipedia.org/w/index.php?title=User:foo/bar.js&action=raw&ctype=text/javascript').done(function() {
  /* 処理 */
});
  • $.when($.ajax(...), $.ajax(...), ...).then(/* 処理 */) - 複数のファイルを読み込む場合、$.whenを使うことで、すべての読み込みが完了するまで処理待ちをすることができます。

CSSのロード

編集
  • mw.loader.load( /* URI */, 'text/css' ) - 任意のサイトの任意のページにあるCSSを読み込みます。URIで指定します。

ページ情報の取得

編集

mw.config.get の引数に以下の変数名を渡すことで、システムや記事に関する情報を得ることが出来ます。例えば、wgPageName の場合、mw.config.get( 'wgPageName' ) と記述します。 変数名と同名のグローバル変数が用意されていますが、これを直接呼び出すことは現在は非推奨となっています。 以下に主なものを示します。

変数 値の例 説明
システム全体
wgArticlePath '/wiki/$1' $1を記事名で置き換える (mw.config.get('wgArticlePath').replace('$1', '記事名')) ことで、パスを生成できます。より簡潔なmw.util.getUrl('記事名')が用意されています。
wgScript '/w/index.php' index.phpのパスを取得します。index.phpはソースの取得などに使用できます。mw:Manual:Parameters to index.php/jaを参照して下さい。
wgFormattedNamespaces
{
  '0': '',
  '1': 'ノート',
  '2': '利用者',
  ...
}
番号から名前空間の名称を得るためのマッピング。
wgNamespaceIds
{
  'メディア': - 2,
  '特別': - 1,
  '': 0,
  'ノート': 1,
  '利用者': 2,
  ...
}
名前空間の名称から番号を得るためのマッピング。
wgContentNamespaces [0] 記事の名前空間
wgContentLanguage 'ja' 言語設定
記事ごと
wgPageName 'Wikipedia:カスタムJS' この記事の名前空間を含めた名前(スペースはアンダースコアで置き換え)
wgTitle 'カスタムJS' この記事の名前空間を含まない記事名(スペースを含み、アンダースコアは含まない)
wgNamespaceNumber 4 この記事の名前空間の番号
wgCanonicalNamespace Project 正規化された名前空間名(例えば"Wikipedia"名前空間は"Project"、"利用者"名前空間は"User")
wgArticleId 2276878 記事ID(特別なページや存在しないページでは0になる)
wgRevisionId 66050435 現在見ているリビジョンのID
wgCurRevisionId 66050435 その記事の最新版のリビジョンのID
wgCategories ['ウィキペディア用ツール'] カテゴリ一覧(隠しカテゴリを区別しないので注意)
wgAction 'view' アクション(mw:Manual:Parameters to index.php/ja#Actionsを参照)
wgPageContentLanguage 'ja' 記事の言語
ユーザごと
wgUserId (ユーザのID) ユーザのID
wgUserEditCount (ユーザの編集回数) ユーザの編集回数
wgUserName (ユーザ名) ユーザ名
wgUserGroups (ユーザのグループ) ユーザのグループ
wgUserLanguage 'ja' ユーザの言語
skin 'vector' 現在使っているスキンの名前

ユーザ設定の取得

編集
  • mw.user.options.get(/* オプション名 */) - mw.config.getと同様に、ユーザ設定を取得します(user.optionsモジュールの読み込みが必要です)。

要素の取得

編集
  • document.editform.wpTextbox1 - 編集画面で、編集領域のテキストボックスを取得します。
  • mw.util.$content - 記事の領域のDivエレメントをjQueryオブジェクトで取得します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。

ユーティリティ

編集
  • mw.util.addCSS - CSSの定義を追加します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
  • mw.util.addPortletLink - 各種ツールバーにリンクを追加します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
詳細はw:Wikipedia:User_scripts/Guide#Portlets (add custom menus and tabs)(英語)を参照してください。
  • mw.util.getParamValue - ページのURLのパラメータを取得します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
  • mw.util.getUrl - 記事名に対して、そのURLを取得します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
例:
mw.util.getUrl('Wikipedia:カスタムJS/一覧'); // => "/wiki/Wikipedia:%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0JS/%E4%B8%80%E8%A6%A7"
  • mw.util.wikiScript - スクリプトのパスを取得します。引数に何も指定しない場合は、index.phpのパスを返します(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
例:
mw.util.wikiScript(); // => "/w/index.php"
mw.util.wikiScript('api'); // => "/w/api.php"
  • mw.util.wikiUrlencode - 文字列を、URLエンコードします(mediawiki.utilmw.loader.usingでロードして使用して下さい)。
例:
mw.util.wikiUrlencode('Wikipedia:カスタムJS/一覧'); // => "Wikipedia:%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0JS/%E4%B8%80%E8%A6%A7"

ローカルストレージ

編集
  • mw.storage - ブラウザのLocalStorageをget, set, remove で使用します(mediawiki.storageモジュールの読み込みが必要です)。mediawiki.storageを参照してください。既存のライブラリのLocalStorageの使用については、MediaWikiのJavaScriptのコーディング規約を確認して下さい。

コーディング規約

編集

カスタムJSには特にコーディング規約は定められていませんが、MediaWikiのJavaScriptのコーディング規約などを参考にすると、わかりやすいコードを書くことが出来ます。

グローバル変数によるカスタムJS外とのやりとり

編集

グローバル変数を使用することにより、カスタムJSに設定を渡したり、カスタムJSをロード後に、カスタムJSで定義した内容を使用したりすることが出来ます。 Place for Extensions Objects in JavaScriptによれば、第三者ライブラリはmw.libsを、拡張はmw.extを使用することが多いようです。

改良型編集ツールバーの拡張

編集

mw:Extension:WikiEditorで提供されている、改良型編集ツールバーは、カスタマイズが可能です。

カスタマイズをするにあたってのスニペット:

function CustomizeEditform() {
  $(document.editform.wpTextbox1).wikiEditor('addToToolbar', {
    // ... ここにObjectで設定を書く
  });
}

$(function () {
  if (document.editform) {
    mw.loader.using('user.options').then(function () {
      if (mw.user.options.get('usebetatoolbar') == 1) {
        mw.loader.using('ext.wikiEditor.toolbar').then(CustomizeEditform);
      }
    });
  }
});

構成

編集
  • 改良型編集ツールバーの上段の、ボタン (main) や「上級」(advanced) 「特殊文字」(characters) 「ヘルプ」(help) と並んでいる欄をsectionと呼びます。
  • 「上級」(advanced) をクリックしたときに表示される領域や、main sectionをtoolbarと呼びます。
    • toolbarの縦棒で区切られた領域 group でできています。
    • groupには、buttonまたはselect(プルダウン)が並んでいます。
  • 「特殊文字」(characters) や「ヘルプ」(help) をクリックしたときに表示される領域をbookletと呼びます。
    • bookletの左側はpagesからできており、各pageはbookletの右側のtable(「ヘルプ」(help) の場合など)またはcharacters(「特殊文字」(characters) の場合の各ボタン)からできています。
  • 各ボタン (button、charactersなど) の動作は、actionで記述できます。
    • actionのtypeで、動作種別をencapsulate, replace, callback, dialogから選択します。
    • actionのoptionsで、動作種別がencapsulate, replaceの場合の動作を記述します。
      • pre: カーソル位置またはテキスト選択の前に置かれます。
      • peri: テキストを選択していないときにカーソル位置に置かれます。
      • post: カーソル位置またはテキスト選択の後に置かれます。
      • regex: 置換の正規表現。
      • regexReplace: 置換後の置き換える文字列、$1などの置換パターンを使用できます。
    • actionのexecuteで、動作種別がcallbackの場合に、contextを引数に持つコールバック関数を記述します。戻り値は無視されます。編集内容を変更するには、直接wpTextbox1のvalueなどを変更する形で使います。
  • filtersオプションにCSSセレクターを記述することで、そのCSSセレクターを含むページでのみに表示を限定することができます。特に、bodyのクラスに対するセレクタbody.ns-talkbody:not(ns-talk)などが使用できます。
  • 既存のボタン・ツールバーの動作はjquery.wikiEditor.toolbar.configをご覧ください。

カスタマイズ

編集
  • sectionに新しくbookletを追加する場合:
    {
      sections: {
        '(新しいツールバー名)': {
          type: 'booklet',
          label: '(表示名)',
          pages: {
            '(ページ名)': {
              label: '(表示名)',
              layout: 'characters',
              characters: [
                '<br/>',
                {
                  label: '(表示名)',
                  action: {
                    type: 'encapsulate',
                    options: {
                      pre: '[[',
                      peri: '',
                      post: ']]'
                    }
                  },
                },
                // ...
              ]
            },
            // ...
          },
        }
      }
    }
    
例:
{
  sections: {
    'mytools': {
      type: 'booklet',
      label: 'ツール',
      pages: {
        'mysnippet': {
          label: 'スニペット',
          layout: 'characters',
          characters: [
            '<br/>',
            {
              label: '{{要出典範囲}}',
              action: {
                type: 'encapsulate',
                options: {
                  pre: '{{要出典|date=' + (new Date()).getUTCFullYear() + '年' + ((new Date()).getUTCMonth() + 1) + '月|',
                  peri: '',
                  post: '}}'
                }
              },
            },
          ],
        },
        'myedit': {
          label: '編集',
          layout: 'characters',
          characters: [
            {
              label: '改行削除',
              action: {
                type: 'replace',
                options: {
                  regex: /\r|\n/g,
                  regexReplace: '',
                }
              },
            },
          ],
        },
      },
    }
  }
}
  • 既存のsectionにgroupを追加:
    {
      section: 'advanced',
      groups: {
        '(グループ名)': {
          label: '(名前)',
        }
      }
    }
    
  • 既存のgroupにbuttonを追加:
    {
      section: 'advanced',
      group: 'heading',
      tools: {
        '(ボタン名)': {
          label: '(名前)',
          type: 'button',
          icon: '//upload.wikimedia.org/wikipedia/commons/thumb/3/36/Help-content.svg/22px-Help-content.svg.png',
          action: {
            type: 'encapsulate',
            options: {
              pre: '',
            }
          }
        },
        // ...
      }
    }
    

Mediawikiには各種のAPIが用意されています。APIを使用するメリットとして、各種の情報(投稿回数、カテゴリ一覧)を得られること、処理しやすい整形された情報が得られること、そして応答が早いこと、などが挙げられます。

APIへのアクセスはAjaxで行います。APIサンドボックスで、APIをテストすることが出来ます。他に、REST(Representational State Transfer)を使用するREST API(英語)も用意されています。

mediawiki.api モジュール

編集

JavaScriptでAPIを使用するときは、mediawiki.apiモジュールを使用すると便利です。

mw.loader.using('mediawiki.api').then(function () {
  var api = new mw.Api();
  api.get({
    action: 'query',
    prop: 'revisions',
    pageids: '2276878',
    rvprop: 'user|content'
  }).done(function (data) {
    console.log(data.query.pages);
  });
});

mediawiki.apiモジュールには各種プラグインがあり、例えばmediawiki.api.parseを使用すると、WikiテキストからHTMLへの変換を簡単に行うことができます。

mw.loader.using('mediawiki.api.parse').then(function () {
  var api = new mw.Api();
  api.parse('== chapter ==').done(function (html) {
    console.log(html);
  });
});

Query アクションとcontinue

編集

Query アクションは、Wikiの情報や一覧を取得するために使用するアクションです。 Query アクションの結果が、1回のAPIで取得できる件数の上限を超えた場合、APIの結果にcontinueが追加されます。 APIのリクエストのパラメータにcontinueの要素をマージすることで、APIの結果を継続して取得することができます。

以下のような関数を作成しておくとよいでしょう。

// overwrites obj1
// deepMerge({a: {b: [2], c: 3}, d: {e: {f: [4, 5]}}, g: 6}, {a: {b: [7], c: 8}, d: {e: {f: [9, 10]}}, h: 11})
//   => {a: {b: [2, 7], c: 8}, d: {e: {f: [4, 5, 9, 10]}}, g: 6, h: 11}
function deepMerge(obj1, obj2) {
  $.each(obj2, function (key, value2) {
    if (key in obj1) {
      var value1 = obj1[key];
      if (Array.isArray(value1)) {
        if (Array.isArray(value2)) {
          obj1[key] = value1.concat(value2);
        } else {
          value1.push(value);
        }
      } else if (typeof value1 === 'object') {
        if (typeof value2 === 'object') {
          deepMerge(value1, value2);
        } else {
          obj1[key] = value2;
        }
      } else {
        obj1[key] = value2;
      }
    } else {
      obj1[key] = value2;
    }
  });
  return obj1;
}

// iterate getting query api if request returned continue
// api: mw.Api
// options: Object, get options
// maxTry: integer, nullable (default 10), max of iterates count
// interval: integer, nullable (default 1000), milliseconds to sleep between each query
// deferred: jQuery.Deferred, nullable
// currentResult: Object, nullable, current query result
// returns deferred object
//   deferred return value: query result (data.query)
function iterateQuery(api, options, maxTry, interval, deferred, currentResult) {
  if (typeof (maxTry) !== 'number') {
    maxTry = 10;
  }
  interval = interval || 1000;
  deferred = deferred || $.Deferred();
  currentResult = currentResult || {
  };
  if (maxTry === 0) {
    deferred.reject('maxTry is 0');
    return deferred;
  }
  api.get($.extend({
    action: 'query',
  }, options)).done(function (data) {
    currentResult = deepMerge(currentResult, data.query);
    if (data.continue ) {
      setTimeout(function () {
        iterateQuery(api, $.extend(options, data.continue ), maxTry - 1, interval, deferred, currentResult);
      }, interval);
    } else {
      deferred.resolve(currentResult);
    }
  });
  return deferred.promise();
}

例: 管理者一覧を取得

iterateQuery(new mw.Api(), {
  list: 'allusers',
  augroup: 'sysop',
  aulimit: '20',
}).then(function(query){
  console.log(query.allusers);
});

別ドメインへのアクセス

編集

JavaScriptでMediaWikiAPIを使用する際のひとつの制約として、JavaScriptが持つ同一生成元ポリシー(別ドメインの情報に直接アクセスできない)により、そのままでは多言語版やウィキデータなどの他プロジェクトへのアクセスは出来ません。多言語版や他プロジェクトにアクセスするには、en:Cross-Origin Resource Sharing (CORS) を使います。mediawiki.ForeignApiモジュールを使用することで、CORSを簡単に実現できます。

mw.loader.using('mediawiki.ForeignApi').then(function () {
  var api = new mw.ForeignApi('https://en.wikipedia.org/w/api.php');
  api.get({
    action: 'query',
    list: 'recentchanges',
  }).done(function (data) {
    console.log(data);
  });
});

デバッグ

編集

最も原始的なデバッグの方法はアラートコメントアウトを使う方法です。

アラートとコメントアウト

編集

アラート

編集

アラートを使う方法は問題が起きていそうな場所に次のようなコードを入れて実行することです。

alert(変数名);

これにより変数がどういう値を取っているか、またif文などの分岐を含む文であればその場所が実行されているかが、ポップアップの有無とその内容により分かります。

コメントアウト

編集

コメントアウトを使う方法も単純です。問題が起きていそうな場所で、行の先頭にスラッシュ二つを入れるか、または/* */で囲みます。

//abc = hoge.IndexOf('foo');

/*
abc = hoge.IndexOf('foo');
x = abc;
*/

こうした一部分のコメントアウトで今まで動かなかったコードが動き出したら、問題はコメントアウトした部分の周辺にあることが分かります。

ブラウザ別のデバッグ機能

編集

現在は多くのパソコン向けブラウザで、ファンクションキーF12 を押すとデバッグ機能が表示されます。

Firefox

編集
  • Ctrl Shift を押しながら K を押します。
    • あるいは、ウィンドウ右上の「三」のようにみえるマーク(いわゆるハンバーガーメニュー)を押す。メニューから「開発ツール」->「WEBコンソール」をクリックします。

アドオン(ブラウザ拡張機能)のJavaScript Debuggerもあります。追加してからFirefoxを再起動し、メニューから「ツール」->「JavaScript Debugger」をクリックすると、デバッガが立ち上がります。ブレークポイントの指定、変数のウォッチなどが可能です。

Chrome

編集

パソコン版の場合)

  • CTRL Shift を押しながら I (アイ)を押します。
    • あるいはウィンドウ右上の「三」のようにみえるマークを押す ->「その他のツール」->「デベロッパーツール」をクリック。

表示されたペインの「Console」にエラーなどが表示されます。

画面上で右クリック->「要素を調べる」をクリック。表示されたペインで「Console」という所をクリックすると、デバッガが表示されます。

Microsoft Edge / Internet Explorer

編集

F12 を押すとウィンドウが表示されます。または、メニューから「ツール」->「F12 開発者ツール」でも同様です。ここで「スクリプト」という所をクリックすると、デバッガが表示されます。

関連項目

編集
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy