コンテンツにスキップ

利用者:NA sounds/live installer/live installer lib.js

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

多くの WindowsLinux のブラウザ

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

Mac における Safari

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

Mac における ChromeFirefox

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

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

/*
Copyright (C) 2007 by N/A sounds <[email protected]>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

//<pre>
function WPToolInstaller(){
with(WPToolInstaller){

if( !na_lib.message ) na_lib();

var trans_db = new na_lib.TranslateDB(na_lib.MLString.prototype.translator);
function ml(data){ return trans_db.translate(data, "__", deep); }
trans_db.add( "__", "en", {
	"cookie error":"cookies error, count = %s. Don't worry, eat all bad cookies.\n"
} );
trans_db.add( "__", "ja", {
	"cookie error":"%s個のデータの読み込みに失敗。\n悪いcookieは全て食べてしまったので問題在りません。\n"
} );

function parse_path( path, current, func ){
	var re = /^(\/|)((?:\\\\|\\.|[^\\\/])*)\/?(.*)/;
	var m = path.match(re);
	if(!m) return undefined;

	if( m[1] == "/" ){
		m = path.match( new RegExp(current+"/(.*)") );
		if(!m) return undefined;
		m = m[1].match( re );
	}

	return func( m[2], m[3] );
}

//*************************************

function Config( name, parent ){
	this.parent = parent;
	this.name = name;
}

//短縮されたフォーマットから、Configの派生オブジェクトのリストを作る。
//{ type:"text", name:"", [desc:""], [def:undefined], [value:undefined], [level:3]  },
Config.createConfigsFromArray = function( parent, array, trans_db, lang ){
	var configs = [];
	for( var i=0; i<array.length; i++ ){
		var conf = array[i];

		eval( "var c = new Config_"+conf.type+"( conf.name, parent );" );
		c.init( conf, lang, trans_db );
		configs.push( c );
	}
	return configs;
}

//*************************************
//簡単な永続化機能を持ち、(設定用のHTML要素を作れる)設定クラス。
Config.prototype = {
	name: undefined,
	parent: undefined,

	description: "",
	level:3,		//0:hide, 1:専門的, 2:細かい, 3:普通, 4:簡潔

	value: undefined,	//解釈はtypeに因って異なる。
	def: undefined, 	//default。同上

	init: function( conf, lang, trans_db ){
		if( conf.level != undefined ) this.level = conf.level;
		if( conf.def != undefined ) this.def = conf.def;
		if( conf.value != undefined ) this.value = conf.value;
		this.resetValue( true );

		this.description = new na_lib.MLString(this.getPath(), "__", trans_db );
		if( conf.desc != undefined )
			this.description.ml_set( conf.desc, lang );
	},

	getPath: function( p ){
		if( !p ) return this.parent.getPath( this.name );
		return this.parent.getPath( this.name + "/" + p );			
	},

	loadConfig: function( cookie_box, path ){
		if( !path ) path = this.getPath();
		var v = cookie_box.get(path);
		if( v!=undefined ) return this.valueFromSource(v);
		else return false;
	},

	updateConfig: function( cookie_box, path ){
		if( !path ) path = this.getPath();
		return cookie_box.set(path, this.valueToSource());
	},

	getValue: function(){
		return this.value;
	},

	setValue: function(v){
		this.value = v;
		this.updateElement();
	},

	resetValue: function( no_overwrite ){
		if( ( !no_overwrite || this.value == undefined ) && this.def != undefined ){
			this.value = this.def;
			this.updateElement();
		}
	},

	isChanged: function(){
		return (this.value != this.def);
	},

	valueToSource: function(){},
	valueFromSource: function(){},
	updateElement: function(){},

	__extend: function(o){
		for( var k in o ) this[k] = o[k];
	}
}


function Config_string( name, parent ){
	Config.apply(this, [name, parent]);
}
Config_string.prototype = new Config();
Config_string.prototype.__extend({
    conv: false,
    valueToSource: function(){
	return "'" + this.value.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r") + "'";
    },
    valueFromSource: function(v){
	this.value = v.substring(1,v.length-1).replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\'/g,"'").replace(/\\\\/g,"\\");
	this.updateElement();
    }
});


function Config_number(name, parent){
	Config_string.apply(this, [name, parent]);
}
Config_number.prototype = new Config_string();
Config_number.prototype.__extend({
    conv: true,
    valueToSource: function(){
	return this.value.toString();
    },
    valueFromSource: function(v){
	this.value = Number(v);
	this.updateElement();
    }
});


function Config_function(name, parent){
	Config.apply(this, [name, parent]);
}
Config_function.prototype = new Config();
Config_function.prototype.__extend({
    valueToSource: function(){
	return "function(){" + this.value + "}";
    },
    valueFromSource: function(v){
	if( !v ) return;

	var v = v.replace( /\s*function\s*[a-zA-Z0-9_\-\$]*\(\)\s*\{/i, "" );
	if( v.length > 0 ) v = v.substring(0,v.length-1);
	this.value = v;
	this.updateElement();
    },
    getValue: function(){
	return new Function(this.value);
    },
    setValue: function(v){
	this.value = this.valueFromSource(v.toString());
	this.updateElement();
    }
});


//いらないような気もする...
function Config_static_function(name, parent){
	Config_function.apply(this, [name, parent]);
}
Config_static_function.prototype = new Config_function();
Config_static_function.prototype.__extend({
    valueToSource: function(){
	return "function(){" + this.def + "}";
    },
    loadConfig: function(cookie_box, path){ //umm.
	return true;
    },
    updateConfig: function(cookie_box, path){ //umm.
	return true;
    },
    valueFromSource: function(v){},
    resetValue: function( no_overwrite ){},
    getValue: function(){
	return new Function(this.def);
    },
    setValue: function(v){},
    isChanged: function(){
	return true;
    }
});

function Config_check(name, parent){
	Config.apply(this, [name, parent]);
}
Config_check.prototype = new Config();
Config_check.prototype.__extend({
    setValue: function(v){
	this.value = v;
	this.updateElement();
    },
    valueToSource: function(){
	return this.value?"true":"false";
    },
    valueFromSource: function(v){
	this.value = (v=="true");
	this.updateElement();
    }
});


function Config_radio(name, parent){
	Config.apply(this, [name, parent]);
}
Config_radio.prototype = new Config();
Config_radio.prototype.__extend({
    init: function( conf, lang, trans_db ){
	Config.prototype.init.apply(this, [conf, lang, trans_db]);
	if( conf.items != undefined ) this.items = conf.items; //radio only
    },
    getValue: function(){
	return this.items[this.value];
    },
    setValue: function(v){
	for( var k in this.items )
		if( this.items[k] == v )
			this.value = k;
	this.updateElement();
    },
    valueToSource: function(){
	var v = this.getValue().valueOf();
	if( (typeof v) == "number" || v instanceof Number ) return v.toString();
	if( (typeof v) == "boolean" || v instanceof Boolean ) return v.toString();
	if( (typeof v) == "undefined" ) return "undefined";
	else return "'" + v + "'";
    },
    valueFromSource: function(v){
	var m = v.match( /^(?:'(.*)')|(.*)$/ );
	if( m[1] ) this.setValue(m[1]);
	else if( m[2] ) this.setValue(m[2]);
    }
});



function Config_configs(name, parent){
	Config.apply(this, [name, parent]);
	this.config = [];
}
Config_configs.prototype = new Config();
Config_configs.prototype.__extend({
    config: undefined,		//Configオブジェクトの配列

    init: function( conf, lang, trans_db ){
	Config.prototype.init.apply(this, [conf, lang, trans_db]);
	this.config = Config.createConfigsFromArray( this, conf.config, trans_db, lang );
    },

    loadConfig: function( cookie_box, path ){
	if( !path ) path = this.getPath()
	if( !cookie_box.get(path) ) return false;
	this.value = (cookie_box.get(path + "/" + "__enable")=="true");
	for( var i=0; i<this.config.length; i++ ){
		this.config[i].loadConfig( cookie_box, path + "/" + this.config[i].name );
	}
	this.updateElement();
    },
    updateConfig: function( cookie_box, path ){
	if( !path ) path = this.getPath()
	if( !cookie_box.get(path) )
		cookie_box.set( path, {} ); //umm.
	cookie_box.set( path + "/" + "__enable", this.value.toString() );
	for( var i=0; i<this.config.length; i++ )
		this.config[i].updateConfig( cookie_box, path + "/" + this.config[i].name );
    },

    valueToSource: function( only_changed ){
	var s = "";
	if( only_changed && !this.value )
		return "{'__enable':'false'}";
	for( var i=0; i<this.config.length; i++ )
		if( ( !only_changed || this.config[i].isChanged() ))
			s += "'"+this.config[i].name +"':"+ this.config[i].valueToSource(only_changed) + ",";
	s += "'__enable':'"+this.value+"'";
	return "{"+s+"}";
    },

    //設定読み込みはloadConfig()の方を使うので、完全に読み込める必要はない。ので手抜き。
    valueFromSource: function(v){
	var m = v.match( /.*'__enable':'(.*)'\s*}\s*$/ );
	if( m )
		this.value = (m[1]=='true');
	this.updateElement();
    },

    isChanged: function(){ //umm.
	return true;
    },

    resetValue: function(no_overwrite){
	if( ( !no_overwrite || this.value == undefined ) && this.def != undefined ){
		this.value = this.def;
		this.updateElement();
	}
	for( var i=0; i<this.config.length; i++ )
		this.config[i].resetValue(no_overwrite);
    },

    getValue: function(){ //子のgetValueの配列を返す感じ?
	var array;
	if( this.value ){
		array = {};
		for( var i=0; i<this.config.length; i++ )
			array[this.config[i].name] = this.config[i].getValue();
	}
	return array;
    },

    setValue: function(v){
	if( !v ) this.value = false;
	else{
		this.value = true;
		for( var k in v )
			for( var i=0; i<this.config.length; i++ )
				if( this.config[i].name == k )
					this.config[i].setValue( v[k] );
	}
	this.updateElement();
    },

    getConfig: function(path){
	var config = this.config;
	return parse_path( path, this.getPath(),
	function(c,n){
		if( c == ".." ) return this.parent.getConfig(n);
		for( var i=0; i<config.length; i++ ){
			if( config[i].name == c ){
				if( !n )
					return config[i];
				else if( config[i] instanceof Config_configs )
					return config[i].getConfig(n);
			}
		}
	} );
    },

    keys: function( array, path ){
	if( !array ) array = [];
	if( !path ) path = "";
	for( var i=0; i<this.config.length; i++ ){
		if( this.config[i] instanceof Config_configs ){
			array.push( this.config[i].name + "/" );
			this.config[i].keys(array, this.config[i].name + "/");
		}
		else
			array.push( path + this.config[i].name );
	}
	return array;
    }
});


//*************************************
function wikiLinkStr( addr, title ){
	if( addr.substring(0,7) == "http://" )
		return "["+addr+" "+title+"]";
	else
		return "[["+decodeURIComponent(addr)+"|"+title+"]]";
}


//*************************************
function WPTool(name, tdb){
	this.translator = tdb;
	this.config = [];
	Config_configs.apply(this, [name, undefined]);
}
WPTool.prototype = new Config_configs();	//
WPTool.prototype.__extend( {
	name: undefined,		//ツールの名前
	page: undefined,		//includeするページ名。完全なURIか[[<page>]]でアクセスできる必要がある
	talk_page: "",			//解説ページ、あるいは公式ページがあるなら。
	description: "",		//簡単な解説
	help: "",			
	hidden: false,			//ライブラリタイプなら、true。選択画面に出ない。
	genre: "default",

	depends: [],			//依存関係。他のWPToolオブジェクトの配列。
	conflicts: [],			//面倒かなぁ...今のところダミー
	arrow_browser: [],		//今のところダミー
	reject_browser: [],		//今のところダミー

	config_object: undefined,	//設定用オブジェクトの名前。
					//var <config_object> = { <config[x].name>:<config[x].valueToSource()>, ... }
	run_only_in: undefined,		//dependsのからみが面倒か? 正規表現。
	onload_func: undefined,		//関数名。addOnloadHookに渡される。
	setup_func: undefined,

	translator: undefined,		//翻訳のDB。initより先に設定されている必要がある。

	include_code: function( maxage ){
		if( !this.page || !this.page.valueOf() ) return "";
		var s = "document.write('";
		s += '<script type="text/javascript" src="';
		if( this.page.substring(0,7) == "http://" ){
			s += this.page;
		}
		else{
			s += '/w/index.php?title=';
			s += this.page;
			s += '&action=raw&ctype=text/javascript&dontcountme=s';
			if( maxage ) s += '&smaxage=0&maxage=157680000';
		}
		s += '"></script>' + "');\n";
		return s;
	},

	config_code: function(){
		if( this.config_object == undefined )
			return this.config_code_flat();
		else
			return this.config_code_object(this.config_object.valueOf());
	},

	config_code_flat: function(){
		var s = "";
		for( var i=0; i<this.config.length; i++ )
			if( this.config[i].isChanged() )
				s += this.config[i].name + " = " + this.config[i].valueToSource(true) + ";\n";
		return s;
	},

	config_code_object: function(name){
		if( !name ) return "";
		var s = "";
		for( var i=0; i<this.config.length; i++ ){
			if( this.config[i].isChanged() ){
				if( s.length > 0 ) s += ",\n";
				s += this.config[i].name + ":" + this.config[i].valueToSource(true);
			}
		}
		return "var "+name+" = {\n" + s + "\n}\n";
	},

	hook_code: function(){
		if( !this.onload_func || !this.onload_func.valueOf() ) return "";
		if( (typeof this.onload_func) == "function" )
			return 'addOnloadHook('+this.onload_func.toString()+');\n';
		//return 'addOnloadHook(function(){eval("'+this.onload_func.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'");});\n';
		return 'addOnloadHook(function(){'+this.onload_func+'});\n';
	},

	init_code: function(){
		if( !this.init_func || !this.init_func.valueOf() ) return "";
		if( (typeof this.init_func) == "function" )
			return "("+this.init_func.toString()+")();\n";
		return this.init_func + ";\n";
	},

	description_line: function(){
		var s = this.name + " (";
		if( this.page && this.page.valueOf() )
			s += wikiLinkStr(this.page, "page");
		if( this.talk_page && this.talk_page.valueOf() )
			s += "/" + wikiLinkStr(this.talk_page, "talk");
		s += ") - ";
		if( this.description.valueOf() )
			s += this.description.valueOf();
		return s;
	},

    	valueToSource: function( disable_code, maxage ){
		var s = "";
		if( this.run_only_in ){
			s += "if( false";
			for( var i=0; i<this.run_only_in.length; i++ ){
				if( this.run_only_in[i] instanceof RegExp )
					s += " || " + this.run_only_in[i].toString() + ".test(wgPageName)";
				else
					s += " || (" + this.run_only_in[i].toString() + ")()";
			}
			s += " )";
		}
		s += "{\n"
		s += this.include_code(maxage);
		s += this.config_code();
		s += this.init_code();
		s += this.hook_code();
		if( disable_code )
			s += 'wgNoLiveInstall.push("'+encodeURIComponent(this.name)+'");\n';
		s += "}\n";
		return s;
	},
	valueFromSource: function(v){ return true; }, //無効。

    	loadConfig: function( cookie_box, path ){
		if( !path ) path = this.getPath()
		if( !cookie_box.get(path) ) return false;
		for( var i=0; i<this.config.length; i++ ){
			this.config[i].loadConfig( cookie_box, path + "/" + this.config[i].name );
		}
	},

  	updateConfig: function( cookie_box, path ){
		if( !path ) path = this.getPath()
		if( !cookie_box.get(path) )
			cookie_box.set( path, {} ); //umm.
		for( var i=0; i<this.config.length; i++ )
			this.config[i].updateConfig( cookie_box, path + "/" + this.config[i].name );
	},

	//辞書型データからのコンバート。
	init: function( dict, lang ){
		if( !lang ) lang = na_lib.MLString.prototype.lang[0];
		for( var k in dict ){
			if( (k != "name" && k != "genre" && k != "onload_func" && k != "init_func" && k != "page" ) && //umm.
			    ( (typeof dict[k]) == "string" ||
			      dict[k] instanceof String ||
			      dict[k] instanceof na_lib.MLString ) ){
				this[k] = new na_lib.MLString( dict[k], lang, this.translator );
			}
			else if( k == "config" )
				this.config = Config.createConfigsFromArray( this, dict[k], this.translator, lang );
			else
				this[k] = dict[k];
		}
	},

	getPath: function( path ){
		if( !path ) path = "";
		return "/" + this.name + "/" + path;
	}
} );


function WPCssFile(name, tdb){
	WPTool.apply(this, [name, tdb]);
}
WPCssFile.prototype = new WPTool();
WPCssFile.prototype.include_code = function(maxage){
	var s = "document.write('";
	s += '<link rel="stylesheet" type="text/css" href="';
	if( this.page.substring(0,7) == "http://" )
		s += this.page;
	else{
		s += '/w/index.php?title=';
		s += this.page;
		s += '&action=raw&ctype=text/css&dontcountme=s';
		if( maxage ) s += '&smaxage=0&maxage=157680000';
	}
	s += '"></link>' + "');\n";
	return s;
}
         
//*************************************
//WPToolを集めたもの。
function WPTools(){
	this.wptools = [];
}
WPTools.prototype = {
	wptools: undefined,

	add: function( wptool ){
		this.wptools.push( wptool );
	},

	get: function(path){
		var c = this.getConfig(path);
		if( c instanceof Config ) return c.getValue();
	},

	set: function(path, v){
		var c = this.getConfig(path);
		if( c instanceof Config ) return c.setValue(v);
	},

	reset: function( path ){
		var c = this.getConfig(path);
		if( c instanceof Config ) return c.resetValue();
	},

	getConfig: function( path ){
		var config = this.wptools;
		return parse_path( path, "",
		function(c,n){
			for( var i=0; i<config.length; i++ ){
				if( c == config[i].name ){
					if( !n )
						return config[i];
					else
						return config[i].getConfig(n);
				}
			}
		} );
	},

	checkEnable: function( name ){
		var wpt = this.getConfig(name);
		if( wpt && wpt.value ) return true;
		else return false;
	},

	loadConfig: function( cookie_box ){
		var error_keys = [];
		for( var i=0; i<this.wptools.length; i++ ){
			var t = this.wptools[i];
			t.path = "/" + t.name;
			try{
				t.loadConfig( cookie_box, t.path );
			}
	 		catch(e){
				error_keys.push( t.path );
				cookie_box.eat( t.path );
	 		}
		}

		if( error_keys.length > 0 ){
			cookie_box.update();
			addOnloadHook( function(){alert( ml({__:"cookie error"}).replace(/%s/,error_keys.length) + error_keys )} );
		}

		var code = cookie_box.get("/enable_tools")
		if( code ){
		    var enables = code.split(",");
		    for( var j=0; j<enables.length; j++ ){
		      enables[j] = decodeURIComponent(enables[j]);
		      for( var i=0; i<this.wptools.length; i++ )
			if( enables[j] == this.wptools[i].name )
			  this.wptools[i].value = true;
		    }
		}
	},

	updateConfig: function( cookie_box ){
		var enables = [];
		for( var i=0; i<this.wptools.length; i++ ){
			var t = this.wptools[i];
			if( !cookie_box.get("/" + t.name) )
				cookie_box.set( "/" + t.name, {} );

			t.updateConfig( cookie_box, "/" + t.name );
			if( t.value )
				enables.push( encodeURIComponent(t.name) );
		}
		cookie_box.set( "/enable_tools", enables.toString() );
		return true;
	},

	foreachTools: function( func ){
		var r, ret = {};
		for( var i=0; i<this.wptools.length; i++ )
			if( (r = func(this.wptools[i])) ) ret[this.wptools[i].name] = r;
		return ret;
	},

	foreachEnableTools: function( func ){
		var r, ret = {};
		var tmp = [];
		for( var i=0; i<this.wptools.length; i++ )
			if( this.wptools[i].value )
				tmp.push( this.wptools[i] );
		var tools = this.resolveDepends(tmp);
		for( var i=0; i<tools.length; i++ )
			if( (r = func(tools[i])) ) ret[tools[i].name] = r;
		return ret;
	},

	//*************************************
	//conflictsも考慮する必要が...
	resolveDepends: function(tmp){
		var tools = [];
		for( var i=0; i<tmp.length; i++ )
			add( tools, tmp[i] );

		return tools;

		function add( array, target, hist ){
			if( !hist ) var hist = [];
			var deps = target.depends;
			for( var j=0; j<deps.length; j++ ){
				if( array.indexOf(deps[j])<0 && hist.indexOf(deps[j])<0 ){ //ループ防止
					hist.push(target);
					add( array, deps[j], hist );
				}
				var i = array.indexOf(deps[j]);
				if( i >= 0 && array[i].run_only_in ){
					if( target.run_only_in )
						array[i].run_only_in = array[i].run_only_in.concat(target.run_only_in);
					else
						array[i].run_only_in = undefined;
				}
			}
			if( array.indexOf(target)<0 ){
				array.push(target);
				if( !target.run_only_in_orig && target.run_only_in )
					target.run_only_in_orig = target.run_only_in;
				else
					target.run_only_in = target.run_only_in_orig;
			}
		}
	},

	createCodes: function( description, live_install, maxage ){
		var s = "//support<pre>\n";
		var use_noliveinstall = false;
		if( !live_install && this.checkEnable("live installer") ){
			s += "var wgNoLiveInstall = [];\n";
			use_noliveinstall = true;
		}
		s += "//end</pre>\n";

		s += "//include start<hr>\n";
		this.foreachEnableTools( function(tool){
			if( live_install ){
				var n = false;
				for( var j=0; j<wgNoLiveInstall.length; j++ )
					if( tool.name == decodeURIComponent(wgNoLiveInstall[j]) ) n = true;
				if( n ) return;
			}
			s += "//" + (description?tool.description_line():"") + "<pre>\n";
			s += tool.valueToSource( use_noliveinstall, maxage );
			s += "//end</pre><hr>\n";
		} );
		return s;
	}

}

} //end of with(WPToolInstaller)

	WPToolInstaller.Config = Config;
	WPToolInstaller.Config_string = Config_string;
	WPToolInstaller.Config_number = Config_number;
	WPToolInstaller.Config_check = Config_check;
	WPToolInstaller.Config_radio = Config_radio;
	WPToolInstaller.Config_function = Config_function;
	WPToolInstaller.Config_static_function = Config_static_function;
	WPToolInstaller.Config_configs = Config_configs;

	WPToolInstaller.WPTool = WPTool;
	WPToolInstaller.WPCssFile = WPCssFile;
	WPToolInstaller.WPTools = WPTools;
}

WPToolInstaller();

wgWPTools = new WPToolInstaller.WPTools();

//*************************************
//end</pre>