利用者:NA sounds/live installer/live installer lib.js
表示
お知らせ: 保存した後、ブラウザのキャッシュをクリアしてページを再読み込みする必要があります。
多くの Windows や Linux のブラウザ
- Ctrl を押しながら F5 を押す。
Mac における Safari
Mac における Chrome や Firefox
- ⌘ 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>