エレメントが画面内に入ったときにテンプレートを実行させる
Navboxのようなページ下部の巨大テンプレートを遅延読み込みさせて「参照読み込みの展開後のサイズ(Post‐expand include size)」を削減させる狙い。
ページ保存時、以下のテンプレートを使用すると<div>...</div>のみが展開されて保存される。
テンプレート:LazyLoad
<includeonly><div class="lazyLoad" data-page="{{{page|}}}"></div></includeonly>
ユーザーがページを開いた時点では<div>のまま読み込まれる。
そしてガジェットに仕込んだJavaScriptがエレメントを監視し、画面内に入った瞬間にテンプレートを動的に展開する。
Gadget-lazyLoad.js
mw.loader.using( ['mediawiki.util', 'mediawiki.Title'], function(){
// IntersectionObserverを使用したエレメントの座標監視
const intersectionObserver = new IntersectionObserver( function( entries ) {
entries.forEach( function( entry ) {
// 画面内に入った
if ( entry.isIntersecting ){
// エレメントの要素から引数を取得
var page = entry.target.getAttribute( 'data-page' );
if( page ){
// Apiへのリクエスト情報
var requestData = {
action: 'parse',
prop: 'text|modules|jsconfigvars|templates',
title: mw.config.get( 'wgPageName' )
};
// 対象ページがテンプレートか記事か調べてWikitextを生成
var title = new mw.Title( page );
var template = title.getNamespaceId() == 10;
if ( template ) {
requestData.text = '{' + '{' + page + '}}';
} else {
requestData.text = '{' + '{:' + page + '}}';
}
// Wikitextを動的にパーサーさせる
new mw.Api().get( requestData ).done(function ( data ) {
// VisualEditorのプレビューと同じ処理
// * ve.init.mw.ArticleTarget.js
//
if ( data.parse.jsconfigvars ) {
// mw.loader呼び出しのための引数の割当
mw.config.set( data.parse.jsconfigvars );
}
if ( data.parse.modules ) {
// mw.loaderの呼び出し
mw.loader.load( data.parse.modules.concat(
data.parse.modulescripts,
data.parse.modulestyles
));
}
// できたHTMLの差し込み
var html = $( $(data.parse.text['*']).html() ).removeClass( 'noscript' );
$( entry.target ).append( html );
// 他のスクリプトへ読み込み完了通知
mw.hook( 'wikipage.content' ).fire( $(entry.target) );
});
}
// 監視対象から除外
intersectionObserver.unobserve( entry.target );
}
});
});
// エレメントの監視を開始
var observe_target = document.querySelectorAll( ".lazyLoad" );
observe_target.forEach( function( element ){
intersectionObserver.observe( element );
});
});