Thành viên:Mifield/common.js

Bách khoa toàn thư mở Wikipedia

Chú ý: Sau khi lưu thay đổi trang, bạn phải xóa bộ nhớ đệm của trình duyệt để nhìn thấy các thay đổi. Google Chrome, Firefox, Internet ExplorerSafari: Giữ phím ⇧ Shift và nhấn nút Reload/Tải lại trên thanh công cụ của trình duyệt. Để biết chi tiết và hướng dẫn cho các trình duyệt khác, xem Trợ giúp:Xóa bộ nhớ đệm.

/* globals $, ace, mw, importScript */
"use strict";

$.when(
	mw.loader.using( [ "mediawiki.Title", "mediawiki.Uri" ] ),
	mw.loader.getScript( "/wiki/User:Mifield/x.js?action=raw&ctype=text/javascript" )
).done( function () {
	const x = mw.libs.x;

	// self-sufficient constants
	const _dump_    = 3;
	const _verbose_ = 2;
	const _normal_  = 1;

	const regexUnderscore   = /_/g;
	const regexSpace        = / /g;
	const charUnderscore    = "_";
	const charSpace         = " ";

	// locales
	const wgContentLanguage = mw.config.get( "wgContentLanguage" );
	const validateLocales   = function validateLocales( locales, defaultLocale ) {
		var defaultLocaleUsable;
		if ( defaultLocale !== undefined ) {
			defaultLocaleUsable = Boolean( validateLocales( defaultLocale ) );
			if ( !defaultLocaleUsable ) defaultLocale = undefined;
		}

		if ( Array.isArray( locales ) ) {
			if ( locales.length === 0 ) return defaultLocale;

			locales = arrayFlatten( locales );
			const filtered = locales.filter( function ( locale ) {
				return validateLocales( locale );
			} );

			if ( filtered.length < locales.length &&
				defaultLocaleUsable &&
				!( filtered.includes( defaultLocale ) )
			) filtered.push( defaultLocale );

			return filtered;
		}

		if ( locales === "" ||
			locales === undefined ||
			locales === null ||
			Number.isNaN( locales )
		) return defaultLocale;

		return locales;
	};

	// transformation between different forms of namespace names
	const regexMediaWikiCz  = /(?<![[:alnum:]])(MediaWiki)(?![[:alnum:]])/g;
	const regexMediaWikiLc  = /(?<![[:alnum:]])(mediawiki)(?![[:alnum:]])/g;
	const regexMediaWikiX   = /(?<![[:alnum:]])((?:mediaWiki|Mediawiki))(?![[:alnum:]])/g;
	const regexMediaWikiXCz = /(?<![[:alnum:]])((?:mediaWiki|Mediawiki|MediaWiki))(?![[:alnum:]])/g; 
	const regexMediaWikiXLc = /(?<![[:alnum:]])((?:mediaWiki|Mediawiki|mediawiki))(?![[:alnum:]])/g; 
	const strMediaWikiCz    = "MediaWiki";
	const strMediaWikiLc    = "mediawiki";

	// cz = capitalize(d), capitalization(s)
	const czNamespaceString = function czNamespaceString ( string, locales ) {
		string = String( string );

		if ( string.length === 0 ) return string;

		return x.string.to.spliced(
			string, 0, 1,
			string[ 0 ].toLocaleUpperCase(
				validateLocales( locales, wgContentLanguage )
			)
		).replace( regexMediaWikiXLc, strMediaWikiCz );
	};
	// lc = lowercase
	const lcNamespaceString = function lcNamespaceString ( string, locales ) {
		string = String( string );

		if ( string.length === 0 ) return string;

		return x.string.to.spliced(
			string, 0, 1,
			string[ 0 ].toLocaleLowerCase(
				validateLocales( locales, wgContentLanguage )
			)
		).replace( regexMediaWikiXCz, strMediaWikiLc );
	};

	// utilities that depend only on these constants
	const encodeName    = function encodeName ( name ) {
		if ( name === undefined ) return name;
		return encodeURI( String( nane ).replace( regexSpace, charUnderscore ) );
	};

	// namespace constants & utilities
	const wgNamespaceIds            = mw.config.get( "wgNamespaceIds" );
	const allNamespaceStringsLcUs   = Object.keys( wgNamespaceIds );
	const allNamespaceStringsLcSp   = allNamespaceStringsLcUs.map(
		function ( key ) {
			return key.replace( regexUnderscore, charSpace );
		}
	);
	const allNamespaceStringsCzUs   = allNamespaceStringsLcUs.map(
		function ( key ) { return czNamespaceString( key ); }
	);
	const allNamespaceStringsCzSp   = allNamespaceStringsLcSp.map(
		function ( key ) { return czNamespaceString( key ); }
	);
alert(0)
	const namespaceIDs              = x.array.sort.unique.numeric( Object.values( wgNamespaceIds ) );
	const wgFormattedNamespaces     = mw.config.get( "wgFormattedNamespaces" );
	const localizedNamespacesCzSp   = Object.values( wgFormattedNamespaces );

	const getNamespaceID            = function getNamespaceID ( key ) {
		if ( typeof key === "string" ) {
			return wgNamespaceIds[ key.toLowerCase().replaceAll( " ", "_" ) ];
		}

		return;
	};

	const localizeNamespace         = function localizeNamespace ( key, reencode ) {
		if ( key === undefined ) return key;

		key = String( key );
		decoded = decodeURIComponent( key );
		if ( reencode === undefined ) {
			if ( decoded === key )
				reencode = false;
			reencode = true;
		}

		var localized;

		const numberish = !( Number.isNaN( Number( key ) ) );
		if ( numberish )
			localized = wgFormattedNamespaces[ key ];
		else localized = wgFormattedNamespaces[
			String( getNamespaceID( key ) )
		];
		
		if ( reencode )
			return encodeName( localized );
		return localized;
	};
alert(1)

	const strNamespaceCz    = {
		mediawiki:    "MediaWiki",

		wikimedia:    "Wikimedia",
		meta:         "Meta",
		commons:      "Commons",
		wikidata:     "Wikidata",
		wikispecies:  "Wikispecies",
		incubator:    "Incubator",

		wikipedia:    "Wikipedia",
		wiktionary:   "Wiktionary",
		wikinews:     "Wikinews",
		wikivoyage:   "Wikivoyage",
		wikiquote:    "Wikiquote",
		wikiversity:  "Wikiversity",
		wikisource:   "Wikisource",
		wikibooks:    "Wikibooks",

		wikitech:     "Wikitech",
		phabricator:  "Phabricator",

		wikimania:    "Wikimania",

		wp:           "WP",
		t:            "T",
	};

	const localizedProjName = localizeNamespace( "Project", false );
	strNamespaceCz[ localizedProjName.toLocaleowerCase( wgContentLanguage ) ] = localizedProjName;
	alert( JSON.stringify( strNamespaceCz ) );
	alert( localizeNamespace( "Project", false ) );

	const allNamespaceStringPermutations = [
		allNamespaceStringsLcUs,
		allNamespaceStringsLcSp,
		allNamespaceStringsCzUs,
		allNamespaceStringsCzSp,
	];
	const allNamespaceStringPermutationsFlattened = x.array.sort.unique.lexical( allNamespaceStringPermutations.flat() );

//	alert(x.array.sort.unique(stringCompare__, ["Z", "1", "a", "A"]))

//	alert(allNamespaceStrings)
//	alert(localizedNamespacesCzSp)
//	alert(x.array.intersect(stringCompare__, allNamespaceStrings, localizedNamespacesCzSp, 1))

	// alert( JSON.stringify( mw.config.get( "wgNamespaceIds" ) ) );

	Object.assign( x, {
		debug: {
			levels: {
				dump:    _dump_,
				verbose: _verbose_,
				normal:  _normal_,
			},
			notify: {
				dump:    function dump    ( message ) { if (x.config.debug.level >= _dump_)    alert( message ) },
				verbose: function verbose ( message ) { if (x.config.debug.level >= _verbose_) alert( message ) },
				normal:  function normal  ( message ) { if (x.config.debug.level >= _normal_)  alert( message ) },
			},
			is: {
				expected: function ( representation, value, expected, compareFunction ) {
					if ( compareFunction === undefined )
						compareFunction = eqeqeq;
					return "" +
						/* "< " + */ representation /* + " > " */ + "\n\n" +
						"results in \n\n" +
						"\"" + value + "\", \n\n" + "which is " +
						( ( Array.isArray( expected ) ?
							expected.some(
								function ( _expected ) {
									return compareFunction( value, _expected );
								}
							) : compareFunction( value, expected )
						) ? "equal to " : "not " ) +
						"the expected value, \n\n" +
						"\"" + expected + "\".";
				},
			},
		},
		config: {
			debug: {
				level: _dump_,
			},
		},
		operator: {
			eqeqeq: eqeqeq,
		},
	} );

	x.debug.notify.dump( "common.js loaded" );

	const getPageName            = function getPageName ( encode ) {
		const pageName = mw.config.get( "wgPageName" );
		if ( encode )
			return encodeName( pageName );
		return pageName;
	};
	const _thisPageName          = getPageName();

	const wgArticlePath          = mw.config.get( "wgArticlePath" );
	const getPagePath            = function getPagePath ( pageName, encode ) {
		if ( pageName === undefined ) pageName = getPageName();
		const pagePath = mw.format( wgArticlePath, pageName );

		if ( encode )
			return encodeName( pagePath );
		return pagePath;
	};
	const _thisPagePath          = getPagePath();

	const siteOrigin             = window.location.origin;
	const getURLFromRootPath     = function getURLFromRootPath ( path ) {
		path = String ( path );
		if ( !( path.startsWith( "/" ) ) ) path = "/" + path;
		return new URL( siteOrigin + path );
	};
	const getPageURL             = function getPageURL ( pageName, encode ) {
		return getURLFromRootPath( getPagePath( pageName, encode ) );
	};
	/* class PageURL {} */
	const _thisPageURL           = getPageURL();
	const getAbsoluteURL         = function getAbsoluteURL ( path, base ) {
		if ( !( base instanceof URL ) ) {
			try {
				// if it's a valid full URL, this'll work
				base = new URL( base );
			} catch ( error ) {
				// if it's a valid page name, this'll work
				// or, if it's undefined, this'll make it relative to the current page
				base = getPageURL( base );
			}
		}
		return new URL( path, base );
	};

	const isPageName             = function isPageName ( pageName ) {
		if ( pageName === undefined ) return false;

		const segments = pageName.split( "/" );

		const first    = segments[ 0 ].split( ":" ).map( decodeURIComponent );
		if ( first[ 0 ] === "" ) return true; // presume to be article space

		alert(allNamespaceStringPermutationsFlattened)
		alert(allNamespaceStringPermutationsFlattened.includes( first[ 0 ] ))
		// if a valid namespace precedes the colon, presume pageName is valid
		if ( allNamespaceStringPermutationsFlattened.includes( first[ 0 ] ) ) return true;

		alert(mw.Title.exists( first.join( "" ) ))
		// last resort; treat it as an article
		return mw.Title.exists( first.join( "" ) );
	};
	const localizePageName       = function localizePageName ( pageName, reencode ) {
		if ( pageName === undefined ) return pageName;

		if ( reencode === undefined ) {
			const decoded  = decodeURIComponent( pageName );
			if ( decoded === String( pageName ) )
				reencode = false;
			reencode = true;
		}

		// decoding here again because of the possibility
		// that extra slashes exist after decoding
		const first     = pageName.split( "/" )[ 0 ].split( ":" ).map( decodeURIComponent );
		const segments  = pageName.split( "/" ).map( decodeURIComponent );
		const ns        = first[ 0 ];
		const nsLocal   = localizeNamespace( ns, reencode ); // reencoding done by localizeNamespace()

		if ( nsLocal === undefined ) return pageName; // l10n failed; content space? bad input?

		const mapFunction = reencode ? encodeName : ident;
		return segments.map( mapFunction ).toSpliced( 0, 1,
			first.map( mapFunction ).toSpliced( 0, 1, nsLocal ).join( ":" )
		).join( "/" );
	};
	const getLocalizedPagePath   = function getLocalizedPagePath ( pageName, reencode ) {
		return getPagePath( localizePageName( pageName, reencode ), reencode );
	};
	const getLocalizedPageURL    = function getLocalizedPageURL ( pageName, reencode ) {
		return getPageURL( localizePageName( pageName, reencode ), reencode );
	};

	const scriptQueryParams      = { action: "raw", ctype: "text/javascript" };
	const stylesheetQueryParams  = { action: "raw", ctype: "text/css" };

	const addParamsToURL         = function addParamsToURL ( url, params ) {
		const uri = new mw.Uri( String( url ) );
		uri.extend( params );
		return new URL( String( uri ) );
	};

	const _userCustomizationFilePathWorker = function ( path, base, queryParams ) {
		if ( base === undefined ) base = getLocalizedPageURL( undefined, true );

		var full;

		if ( path.startsWith( "//" ) ) // protocol-relative
			full = new URL( window.location.protocol + path );
		else if ( path.startsWith( "/" ) ) // origin-relative
			full = getURLFromRootPath( path );
		else if ( path.startsWith( "./" ) || path.startsWith( "../" ) ) // relative
			full = getAbsoluteURL( path, base );
		else if ( isPageName( path ) )
			full = getLocalizedPageURL( path, true );
		else full = getAbsoluteURL( "./" + path, base );

		return addParamsToURL( full, queryParams );
	};
	const scriptPath     = function scriptPath     ( path, base ) {
		return _userCustomizationFilePathWorker( path, base, scriptQueryParams );
	};
	const stylesheetPath = function stylesheetPath ( path, base ) {
		return _userCustomizationFilePathWorker( path, base, stylesheetQueryParams );
	};
	const c11nFilePath   = function c11nFilePath   ( path, base ) {
		if ( path === undefined ) return path;
		path = String( path );

		if ( path.endsWith( ".js"  ) ) return scriptPath( path, base );
		if ( path.endsWith( ".css" ) ) return stylesheetPath( path, base );

		// TODO: add logic to handle other cases
	};

	const tryPath = function ( path, expected ) {
		x.debug.notify.verbose( x.debug.is.expected (
			'c11nFilePath( "' + path + '" )',
			 c11nFilePath( path ),
			expected, stringEq
		) );
	};

	// x.debug.notify.verbose( "test verbose alert" );
/*	tryPath( "/wiki/User:Mifield/common/x-script-installer/loader.js", "https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:Mifield/common/x-script-installer/loader.js?action=raw&ctype=text%2Fjavascript" );
	tryPath( "User:Mifield/common/x-script-installer/loader.js", "https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:Mifield/common/x-script-installer/loader.js?action=raw&ctype=text%2Fjavascript" );
	tryPath( "./common/x-script-installer/loader.js", "https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:Mifield/common/x-script-installer/loader.js?action=raw&ctype=text%2Fjavascript" );
	tryPath( "common/x-script-installer/loader.js", "https://vi.wikipedia.org/wiki/Th%C3%A0nh_vi%C3%AAn:Mifield/common/x-script-installer/loader.js?action=raw&ctype=text%2Fjavascript" );
	tryPath( "Template:.polishcatsmybeloved/styles.css", "https://vi.wikipedia.org/wiki/B%E1%BA%A3n_m%E1%BA%ABu:.polishcatsmybeloved/styles.css?action=raw&ctype=text%2Fcss"); */
	tryPath( "MediaWiki:Common.js", "https://vi.wikipedia.org/wiki/MediaWiki:Common.js?action=raw&ctype=text%2Fjavascript" );
	tryPath( "MediaWiki:Common.css", "https://vi.wikipedia.org/wiki/MediaWiki:Common.css?action=raw&ctype=text%2Fcss" );

	// importScript( scriptPath( "common/x-script-installer/loader.js" ) );

} );

importScript( "User:Mifield/common/CodeEditor/main.js" );