利用者:Sigsign/vector.js

出典: 謎の百科事典もどき『エンペディア(Enpedia)』
ナビゲーションに移動 検索に移動

注意: 保存後、変更を確認するにはブラウザーのキャッシュを消去する必要がある場合があります。

  • Firefox / Safari: Shift を押しながら 再読み込み をクリックするか、Ctrl-F5 または Ctrl-R を押してください (Mac では ⌘-R)
  • Google Chrome: Ctrl-Shift-R を押してください (Mac では ⌘-Shift-R)
  • Internet Explorer / Microsoft Edge: Ctrl を押しながら 最新の情報に更新 をクリックするか、Ctrl-F5 を押してください
  • Opera: Ctrl-F5を押してください
/**
* Pathnav.js
*
* Author: [[User:Sigsign]]
* License: CC0
*/

mw.loader.using( [ 'jquery', 'mediawiki.api', 'mediawiki.storage' ], function () {
	'use strict';

	function makeTree( array, title, requestCache ) {
		var promise;

		array = array.concat();

		if ( array.indexOf( title ) !== -1 ) {
			array.push( '…' );
			addPathnav( array );
			return;
		}

		array.push( title );
		promise = getParentCategories( title, requestCache );
		promise.then( function ( parents ) {
			if ( parents.length === 0 ) {
				addPathnav( array );
				return;
			}
			parents.forEach( function ( t ) {
				return makeTree( array, t, requestCache );
			} );
		} );
	}

	function addPathnav( array ) {
		var container = document.getElementById( 'pathnavContainer' );
		container.innerHTML += array.reverse().join( ' > ' ) + '<br>';
	}

	function fetchParentCategories( title ) {
		var promise;

		promise = new mw.Api().get( {
			action: 'categorytree',
			category: title,
			options: '{ "mode": 100, "hideprefix": 20, "showcount": false, "namespaces": false }',
			uselang: mw.config.get( 'wgUserLanguage' ),
			formatversion: 2
		} );
		promise = promise.then( parseCategories );
		return promise;
	}

	function getParentCategories( title, reqCache ) {
		var cache, key, promise;

		// Request cache (session only)
		promise = reqCache.get( title );
		if ( promise ) {
			return promise;
		}

		// LocalStorage cache (persistent, site-wide)
		key = 'pathnav_cache_' + title;
		cache = mw.storage.getObject( key );

		// Cache exists and not expired
		if ( cache && cache.expire > Date.now() ) {
			return wrappedPromise( cache.categories );
		}

		// Cache not exists or expired
		promise = fetchParentCategories( title );
		promise = promise.then( function ( categories ) {
			mw.storage.setObject( key, {
				categories: categories,
				expire: Date.now() + ( 3600 * 1000 ) // expire: after 3600 sec
			} );
			return categories;
		} );
		reqCache.set( title, promise );

		return promise;
	}

	// CategoryTree return not json, actualy html (T177474)
	function parseCategories( object ) {
		var doc, html = object.categorytree.html;

		// ParentCategories are not exist (root category)
		if ( html === '' ) {
			return [];
		}
		// ParentCategories are exist
		doc = new DOMParser().parseFromString( html, 'text/html' );
		return [].map.call( doc.querySelectorAll( '.CategoryTreeItem a' ), function ( e ) {
			return e.textContent;
		} );
	}

	function requestCacheStore() {
		var req = {};

		function getter( title ) {
			return req[ title ];
		}
		function setter( title, promise ) {
			req[ title ] = promise;
		}

		return { get: getter, set: setter };
	}

	function wrappedPromise( categories ) {
		return $.Deferred().resolve( categories ).promise();
	}

	if ( mw.config.get( 'wgAction' ) === 'view' && mw.config.get( 'wgNamespaceNumber' ) === 14 ) {
		mw.hook( 'wikipage.content' ).add( function () {
			var reqCache = requestCacheStore();

			$( '<div>' ).attr( {
				id: 'pathnavContainer'
			} ).css( {
				backgroundColor: '#eef',
				border: '1px outset #eef',
				clear: 'both',
				fontSize: '80%',
				margin: '0 0 0.5em 0',
				padding: '0.3em 0.6em'
			} ).prependTo( '#mw-content-text' );
			makeTree( [], mw.config.get( 'wgTitle' ), reqCache );
		} );
	}

} );