// $Id: extwiki-debug.js 81 2010-12-10 05:42:20Z mashiki $
Ext.onReady(function(){
	/**
	 * @class XC
	 * {@link Ext.util.Cookies} へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XD
	 * {@link Ext.DomHelper} へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XF
	 * Ext.form  へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XG
	 * Ext.grid  へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XJ
	 * {@link Ext.util.JSON} へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XM
	 * {@link Ext.MessageBox} へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class XT
	 * Ext.tree  へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	/**
	 * @class WL
	 * window.location へのショートカット<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 */
	var XC=Ext.util.Cookies, XD=Ext.DomHelper, XF=Ext.form, XG=Ext.grid, XJ=Ext.util.JSON,
		XM=Ext.Msg, XT=Ext.tree, WL=window.location;

	/**
	 * @class P
	 * phpより渡されたパラメータ等を格納<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 * @singleton
	 */
	/**
	 * ExtWikiモード優先
	 * @property AutoMode
	 * @type {Boolean}
	 */
	/**
	 * コンフィグファイルのページ名<br />
	 * 通常 ":ExtConfig"
	 * @property ConfigPage
	 * @type {String}
	 */
	/**
	 * 管理者が追加した、cssファイル、複数ある場合はカンマ区切り
	 * @property CustomStyle
	 * @type {String}
	 */
	/**
	 * ページ名未指定で表示されるデフォルトページ
	 * @property DefaultPage
	 * @type {String}
	 */
	/**
	 * 一番最初に表示されるページ<br />
	 * 明示的に指定されなかった場合、DefaultPageになる
	 * @property FirstPage
	 * @type {String}
	 */
	/**
	 * タブパネルで管理されるパネルの最大数
	 * @property MaxTabs
	 * @type {Number}
	 */
	/**
	 * サブリージョンの位置<br />
	 * 'top','botom','right','left'のいずれか
	 * @property MenuPosition
	 * @type {String}
	 */
	/**
	 * ページ編集時に時間を変更しないことを許すか
	 * @property NoTimeUpdate
	 * @type {Number}
	 */
	/**
	 * Pukiwikiエンジンのバージョン
	 * @property PukiwikiVer
	 * @type {String}
	 */
	/**
	 * サイトのタイトル<br />
	 * 左上ロゴに使用
	 * @property SightName
	 * @type {String}
	 */
	/**
	 * タブの表示位置<br />
	 * 'top','botom'のいずれか
	 * @property TabPosition
	 * @type {String}
	 */
	/**
	 * サイトの配色等のテーマ<br />
	 * 'access'、'blue'、'gray'等が指定可能
	 * @property Theme
	 * @type {String}
	 */
	/**
	 * Ajax応答待ち時間<br />
	 * 秒単位で指定する
	 * @property Timeout
	 * @type {Number}
	 */
	/**
	 * ExtJSライブラリのURL<br />
	 * CacheFlyを使うときなど変更
	 * @property UrlExtJS
	 * @type {String}
	 */
	/**
	 * extwikiフォルダのURL
	 * @property UrlExtWiki
	 * @type {String}
	 */
	/**
	 * 通常モードのpukiwikiのURL
	 * @property UrlWiki
	 * @type {String}
	 */
	/**
	 * 起動時のURL(searchとhashを除く)
	 * @property UrlWiki0
	 * @type {String}
	 */
	/**
	 * 最初にExtWikiを立ち上げた時についていたアンカー(#xxxx)
	 * @property anchor0
	 * @type {String}
	 */
	var P = Ext.apply(ExtWikiConf, XJ.decode(XC.get('custom_conf')||'{}'));
	P.UrlWiki0= WL.protocol+'//'+WL.host+WL.pathname;
	if (WL.hash!='___'&&WL.hash!='_..') P.anchor0 = WL.hash;

	// その他の初期化
	Ext.BLANK_IMAGE_URL = P.UrlExtJS+'/resources/images/default/s.gif';
	Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
	Ext.QuickTips.init();

	// 戻るボタンによる誤操作抑止
	XD.append(
		'hidden_div', {
			tag:  'form',
			children: [{tag:'input',id:'x-history-field'},{tag:'iframe',id:'x-history-frame'}]
		}
	);
	Ext.History.init(function(){
		if (Ext.isIE) this.add('_..');
		this.on('change', function(id) {
			if ((!id||id=='_..')&&!confirm('「戻る」の操作でExtWikiを抜けます')) this.forward();
		});
		this.add('___');
	});

	// テーマ設定
	var stl = Ext.getDom('theme');
	stl.href = stl.href.replace(/xtheme-[^\/]+[.]css$/,'xtheme-'+P.Theme+'.css');

	/**
	 * @class Xji
	 * Extwiki Javascript API (Xji) オブジェクトの定義<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 * @singleton
	 */
	var Xji = {
		/**
		 * メインリージョンのタブパネルの参照
		 * @property
		 * @type {Ext.TabPanel}
		 */
		main: new Ext.TabPanel({
			region:'center',
			tabPosition:P.TabPosition,
			enableTabScroll: true,
			deferredRender:false,
			plain:true,
			tbar:[],
			listeners:{
				tabchange: function(tp, pnl) {Xji.onPageActive(pnl)}
			}
		}) // Xji.main
		,
		/**
		 * サブリージョンのメニューパネル参照
		 * @property menu
		 * @type {Ext.Panel}
		 */
		/**
		 * サブリージョンのパネル(Cardレイアウト)への参照
		 * @property
		 * @type {Ext.Panel}
		 */
		sub:new Ext.Panel({ // 左側メニュー
			region:{top:'north',bottom:'south',left:'west',right:'east'}[P.MenuPosition],
			split:true,
			width: 200,
			minSize: 100,
			collapsible: true,
			collapseMode:'mini',
			title: 'Menu',
			margins:0,
			layout:'card',
			activeItem: 0, // make sure the active item is set on the container config!
			items: [{ // 左側メニュー
				id: 'menu',
				margins:0,
				layout:'accordion',
				layoutConfig:{
				    animate:true
				}
			}],
			tools: [{
				id:'refresh', qtip : 'Menu リロード',
				handler: function(e,el,p,c){Xji.loadMenuBar()}
			}],
			listeners:{
				resize: function(t, aW, aH, rW, rH ) {
					if (t.items.getCount()==1) {
						if (t.region=='west'||t.region=='east') {
							t.menuWidth = rW;
						} else {
							t.menuHeight = rH;
						}
					}
				}
			}
		})
		,
		/**
		 * 指定されたパネルのタブをアクティブにする
		 * ・アンカーが指定されていればアンカーに移動する
		 * @param {Xji.Panel} pnl パネルへの参照
		 * @param {String} anchor アンカー
		 */
		activate: function(pnl, anchor) {
			if (pnl.getPI('sub')) {
				this.sub.setTitle('Sub Region Contents');
				this.sub.getLayout().setActiveItem(1);
			} else {
				this.main.activate(pnl);
			}
			if (anchor)pnl.goAnchor(anchor);
		}
		,
		/**
		 * パネル追加
		 * ・リージョン指定がない場合、メインリージョンに追加する
		 * ・パネルへ参照がない場合、読み込み中と表示された新規のパネルを作成する
		 * @param {Object} pi ページ情報
		 * @param {String} reg リージョン
		 * @param {Xji.Panel} pnl パネル
		 * @return {Xji.Panel} パネル
		 */
		add: function(pi, reg, pnl) {
			pi.lastdisp = new Date;
			if (!pnl) {
				var cfg = {
					title: 'loading ...',
					iconCls: 'ewi_loading',
					closable: true,
					autoScroll: true,
					bodyStyle: 'padding: 5',
					pageinfo: pi,
					items:{html:'loading ...'}
				};
				if (reg=='sub') cfg.tools = [{
					id:'close', qtip : '閉じる',
					handler: function(e,el,p,c){Xji.clearSub(true)}
				}];
				pnl = new Xji.Panel(cfg);
			}
			pnl.doLayout(false,true);
			if (reg!='sub') {
				this.main.add(pnl);
				// パネルが最大数を超えたなら一番古いパネルを消す
				var p = this.sub.items.itemAt(1);
				if (this.main.items.getCount()+(p && !p.getPI('temp')?1:0) >P.MaxTabs) {
					var oldest;
					this.main.items.each(function(pn) {
						if (oldest) {
							if (pn.getPI('lastdisp')<oldest.getPI('lastdisp')) oldest=pn;
						} else {
							oldest = pn;
						}
					});
					this.main.remove(oldest);
				}
			} else { // サブリージョン
				var sub=this.sub;
				// 既にあればクリアする
				this.clearSub();
				pi.sub = true;
				pi.temp = true;
				sub.add(pnl);
				this.setSubRegionSize('half');
			}
			return pnl;
		} // add
		,
		/**
		 * サブリージョンを整理する
		 * @param {Boolean} dispMenu 整理後、メニューを表示する場合、trueにする
		 */
		clearSub: function(dispMenu) {
			var pnl, sub=this.sub;
			var cmp=sub.items.itemAt(1);
			if (!cmp) return;
			if (!cmp.getPI('temp')) {
				pnl = cmp.items.itemAt(0);
				delete pnl.pageinfo.sub;
				this.main.add(pnl);
			}
			sub.remove(cmp, true);
			if (dispMenu) {
				this.setSubRegionSize('menu');
				sub.getLayout().setActiveItem(0);
				sub.setTitle('Menu');
			}
			return pnl;
		}
		,
		/**
		 * 結果を表示し確認を求める
		 * @param {String} title ダイアログに表示するタイトル
		 * @param {String} message 表示するメッセージ
		 * @param {Object} res ajaxでの通信結果
		 * @param {Object/Array} btns 下部に表示するボタン
		 */
		confirmWithResult: function (title, message, res, btns) {
			if (!btns) btns = [{
				text:'Ok',
				handler:function(b,e){b.ownerCt.ownerCt.ownerCt.close();}
			}];
			// window表示。サイズ(512,384)変更可能。closable。自動スクロールバー
			(new Ext.Window({
				title: title,
				width : 512,
				height: 384,
				resizable : true,
				closable: true,
				modal: true,
				layout: 'border',
				items: [{
					region: 'north',
					xtype: 'panel',
					height: 80,
					html:message,
					buttonAlign:'center',
					buttons: btns,
					autoScroll: true,
					split:true
				},{
					region: 'center',
					xtype: 'tabpanel',
					activeTab: 0,
					items: [{
						title: 'image',
						contentEl: Xji.makeDiv(res.responseText),
						autoScroll:true
					},{
						title: 'source',
						html: res.responseText.replace(/&/g,'&amp;').replace(/</g,'&lt;'),
						autoScroll:true
					}]
				}]
			})).show();
		} //confirmWithResult
		,
		/**
		 * リンクのクリック処理を実行する
		 * @param {String} url リンクのURL
		 * @param {Xji.Panel} pnl クリックされたリンクを持っているパネル
		 */
		doLinkAction: function(url, pnl) {  // リンクの実行
			var purl = url.match(/^([^?#]*)([^#]*)(.*)$/);
			if ((purl[1]!=P.UrlWiki && purl[1]!=P.UrlWiki0) ) { // 外部サイトへのリンク
				window.open(purl[0]);
				return;
			}
			var p = Xji.query2obj(purl[2]);
			p.cmd = p.cmd || p.plugin || 'read';
			if (p.cmd=='read' && !p.page) {
				p.page = P.DefaultPage;
			}
			if (pnl && ( // ページ内のアンカー と 自ページへのリンク(read)
				p.cmd=='extwiki' && p.mode=='extwiki'
				|| p.page==pnl.getPI('page') && p.cmd=='read' && pnl.getPI('action') == 'read'
			)) {
				pnl.goAnchor(purl[3]);
			} else if (p.openfile || (p.cmd=='attach' && p.pcmd=='open')) {
				// 別windowで開くコマンド
				window.open(purl[0]);
			} else { // サイト内のページ(plugin)を開く
				if (purl[3]!='') p._anchor = purl[3];
				Xji.loadPluginPage(p);
			}
		} // doLinkAction
		,
		/**
		 * ページ検索(リージョン,ページ情報)<br />
		 * ・ページ情報からタブを検索する(リージョン指定「sub」の場合、省略可)
		 * @param {String} reg 検索を実行するリージョン指定、main/sub/both のいずれか
		 * @param {Object} pi 検索条件を格納するページ情報
		 * @return {Array} パネルへの参照の配列、ない場合は空の配列
		 */
		find: function (reg, pi) {
			var ret = [];
			if (reg!='sub') {
				this.main.items.each(function(pnl) {
					if (cmp(pi, pnl.getPI())) ret.push(pnl);
				})
			}
			if (reg!='main') {
				var scp = this.sub.items.get(1);
				if (scp && (!pi || cmp(pi, scp.getPI()))) ret.push(scp);
			}
			return ret;
			// ページ情報比較
			function cmp(p1,p2) {
				for (key in p1) if(p1[key]!=p2[key]){
					return false;
				}
				return true;
			}
		}
		,
		/**
		 * アクティブパネルの取得
		 * @return {Xji.Panel} 取得したパネル
		 */
		getActivePanel: function() { // アクティブパネルの取得()
			return this.main.getActiveTab();
		}
		,
		itemHandler: function(item,e) {
			e.stopEvent();
			var p = {}; //オブジェクトをコピーして渡す
			var conf = item.attributes||item.initialConfig; // XT.TreeNode||Ext.menu.Item
			for (var k in conf.params) p[k] = conf.params[k];
			if (item=='-' || p.acttype=='menu') { // do nothing
			} else if (p.acttype=='link') {
				Xji.doLinkAction(p.url, Xji.getActivePanel());
			} else {
				if (p.page=='.') {
					p.page = Xji.getActivePanel().getPI('page');
				}
				if (p.refer=='.') {
					p.refer = Xji.getActivePanel().getPI('page');
				}
				if (p.acttype=='xjf') {
					Xji.require(p.xjf, function(opt) {
						X[p.xjf](opt);
					}, p);
				//else means (p.acttype=='plugin')
				} else if (p._external) {
					window.open(P.UrlWiki+'?'+Xji.obj2query(p));
				} else {
					Xji.loadPluginPage(p); 
				}
			}
		} // itemHandler
		,
		/**
		 * メニューバーの読込み
		 */
		loadMenuBar: function() {
			Xji.request({
				url: P.UrlWiki+'?cmd=extwiki&mode=getTreeList&page=:ExtMenuBar',
				x_action: 'read',
				x_page: ':ExtMenuBar',
				x_pnl: this.menu,
				failure: Xji.onRequestFail,
				success: function(data){
					Xji.menu.removeAll();
					for (var i=0,top; top=data[i]; ++i) {
						// ツリーパネル作成
						var root = new XT.TreeNode({text:top.text});
						//addNodes
						(function(parent, childs) {
							for (var i=0,cld; cld=childs[i]; ++i) {
								//childs[i]よりnodeを作成
								var p = cld.params;
								var node = new XT.TreeNode({
									iconCls:'ewi_'+cld.iconCls,
									text:cld.text,
									href:p?p.url||(p.page?P.UrlWiki+'?'+p.page:''):'',
									params:cld.params,
									qtip:cld.tooltip,
									leaf:!cld.menu
								});
								// node をparentに追加
								parent.appendChild(node);

								// click した時の動作をセット
								node.on(
									'click',
									Xji.itemHandler,
									null,
									{stopEvent:true}
								);

								// もしnodeに子ノードがあれば追加する
								if (cld.menu && cld.menu.items.length>0) {
									arguments.callee(node, cld.menu.items);
								}
							}
						})(root, top.menu?top.menu.items:[{"acttype":"menu","text":"NoMenu"}]); // 自己再帰呼出
						var tp = new XT.TreePanel({
							title:top.text,
							iconCls:'ewi_'+top.iconCls,
							rootVisible: false,
							autoScroll: true,
							root: root
						});
						// ノードをツリーに追加
						Xji.menu.add(tp);
					}
					Xji.menu.doLayout();
				} //success
			});
		} // loadMenuBar
		,
		/**
		 * read を含めたプラグインのページの処理<br />
		 * ・ページ情報からタブを検索する(リージョン指定「sub」の場合、省略可)
		 * @param {String} reg 実行するリージョン、main/sub/both のいずれか
		 * @param {Object} pi 取得するプラグインのページ情報
		 */
		loadPluginPage: function(p, reg) {
			// actionを決定する
			p.x_cmd = p.plugin || p.cmd || 'read';
			reg = reg || 'main';
			// pageを確定させる
			if (!p.page) {
				p.page = (p.x_cmd=='read')?P.DefaultPage:'';
			}
			// 再利用可能かどうか確認する
			var pi = {page:p.page,action:p.x_cmd},
				pnl = Xji.find('both',pi)[0];
				if (pnl && pnl.getPI('sub')) pnl=Xji.clearSub(true);
			// パネルがありリロードでない場合、アクティブにする
			if (pnl && !p.reload) {
				Xji.activate(pnl, p._anchor);
				return;
			}
			// パネルがない場合作成する
			if (!pnl) pnl = Xji.add(pi, reg);
			// パラメータセット
			if (p.mode) p.x_mode = p.mode;
			p.mode = 'getPage';
			p.cmd  = 'extwiki';
			delete p.plugin;
			// 新ページの読み込み
			Xji.request({
				url: P.UrlWiki+'?'+Xji.obj2query(p),
				x_action: p.x_cmd,
				x_anchor: p._anchor,
				x_page  : p.page,
				x_pnl   : pnl,
				x_refer : Xji.getActivePanel(),
				success : Xji.onPageLoad,
				failure : Xji.onRequestFail
			});
		}  // loadPluginPage
		,
		/**
		 * ツールバーの読込み
		 */
		loadToolBar: function() {
			Xji.request({
				url: P.UrlWiki+'?cmd=extwiki&mode=getTreeList&page=:ExtToolBar',
				x_action: 'read',
				x_page: ':ExtToolBar',
				failure: Xji.onRequestFail,
				success: function(res){
					// クリックイベントとアイコンの設定
					var tb = Xji.main.getTopToolbar();
					tb.removeAll(true);
					for (var ii=0; ii<res.length; ++ii) {
						// recurciveSet
						(function(item) {
							if (item.iconCls) item.iconCls = 'ewi_'+item.iconCls;
							item.handler = Xji.itemHandler;
							if (item.menu && item.menu.items) {
								for (var ii=0; ii<item.menu.items.length; ++ii) {
									arguments.callee(item.menu.items[ii]);
								}
							}
						})(res[ii]);
						tb.add(res[ii]);
					}
					tb.doLayout();
				}
			});
		} // loadToolBar
		,
		/**
		 * hidden領域にdivを作成する
		 * @param {String} html Divに作成するhtml
		 * @param {Object} pi ページ情報
		 * @return {Xji.Panel} パネルへの参照
		 */
		makeDiv: function(html, pnl) {
			var el = XD.append('hidden_div', {tag:'div', html:html}, true);
			// hrefがあるaタグについて、clickイベント処理変更
			el.select('a').each(function(e){
				var url = e.dom.href;
				if (url) e.on(
					'click',
					(function(u,pn){
						return function() {Xji.doLinkAction(u,pn);}
					})(url,pnl),
					null,
					{stopEvent:true}
				);
			});
			// フォームのsubmitイベントの処理変更
			el.select('form').each(function(e) {
				e.on(
					'submit',
					(function(pnl){
						return function(ev,form,c) {Xji.postForm(pnl,form);}
					})(pnl),
					null, {stopEvent:true}
				);
			});
			// サブミットボタンのclickイベント処理変更
			el.select('input').each(function(e) {
				if (e.dom.type=='submit') e.on(
					'click', 
					function(a,submit,c){Ext.get(submit.form)._submit=submit;},
					null,
					{stopEvent:false}
				);
			});
			return el;
		} // makeDiv
		,
		/**
		 * 指定されたパネルをサブリージョンに移動する
		 * @param {Xji.Panel} pnl 移動するパネル
		 */
		move2sub: function(pnl) {
			var sub=this.sub;
			this.clearSub();
			pnl.pageinfo.sub = true;
			sub.add(new Ext.Panel({
				items:pnl,
				title:pnl.getPI('title'),
				iconCls:pnl.getPI('iconCls'),
				layout:'fit',
				getPI:function(p){return pnl.getPI(p)},
				tools: [{
					id:'unpin', qtip : 'タブへ',
					handler: function(e,el,p,c){
						Xji.clearSub(true);
						if (Xji.main.items.getCount()==1) Xji.main.activate(0);
					}
				}]
			}));
			sub.doLayout();
			this.activate(pnl);
			this.setSubRegionSize('half');
		}
		,
		/**
		 * オブジェクトをurlクエリーに変換する
		 * @param {Object} o パラメータを格納したオブジェクト
		 * @return {String} クエリー文字列
		 */
		obj2query:function(o) {
			var q ='';
			for (var k in o) {
				if (k[0]=='_') continue;
				if (k!='page'&&k!='refer') o[k] = encodeURIComponent(o[k]);
				q += '&'+k+'='+o[k];
			}
			return q.substr(1);
		}
		,
		/**
		 * パネルがアクティブになった時の処理<br />
		 *  最終参照日時の更新、ヘッダ部表示、編集可/不可によるToolBarの制御 等を行う
		 * @param {Xji.Panel} pnl アクティブになったパネル
		 */
		onPageActive: function(pnl) {
			var pi = pnl?pnl.getPI():{};
			// 最終参照日時の更新
			pi.lastdisp = new Date;

			// ヘッダ部表示
			document.title = (pi.title||'') + '  --  ' + P.SightName;
			Ext.getDom('top_title').innerHTML = pi.title||'';
			Ext.getDom('top_count').innerHTML = pnl?pi.cntTotal:'0';
			Ext.getDom('top_today').innerHTML = pnl?pi.cntToday:'0';
			Ext.getDom('top_yesterday').innerHTML = pnl?pi.cntYesterday:'0';
			Ext.getDom('top_url').innerHTML = P.UrlWiki +'?'+ (pi.page||'');
			Ext.getDom('top_url').href = P.UrlWiki +'?'+ (pi.page||'');
			
			Ext.getDom('top_update').innerHTML = Xji.shortDate(pi.update);

			// 編集可/不可によるToolBarの制御
			(function setDisable(items) {
				items.each(function(item) {
					if (item.ctledit) {
						if ( item.ctledit==(pi.writable?'enable':'disable') ) {
						 	item.enable();
						} else if ( item.ctledit==(pi.writable?'disable':'enable') ) {
						 	item.disable();
						}
					}
					if (item.menu) {
						setDisable(item.menu.items);
					}
				});
			})(this.main.getTopToolbar().items);
		} // onPageActive
		,
		/**
		 * ページが読み込まれた時の処理
		 * @param {Object} res 処理結果
		 * @param {Object} opt リクエスト時に指定したパラメータ
		 */
		onPageLoad: function(res, opt){
			if (res.body=='') {
				XM.confirm(
					'アクション「'+opt.x_action+'」の結果',
					res.title+'<br />ページの再表示をしますか',
					function(btn) {
						if (btn=='yes') {
							Xji.loadPluginPage({page:res.page,reload:true});
						}
					}
				);
				return;
			}

			// ページ内容セットとパネルへの書き込み
			opt.x_pnl.setPI({
				page: res.page,
				action: opt.x_action,
				title: res.title,
				iconClass: '',
				writable: res.writable,
				update: (res.update&&res.update!='-')?new Date(res.update):'-',
				cntTotal: res.cntTotal,
				cntToday: res.cntToday,
				cntYesterday: res.cntYesterday
			});
			var cmpt = new Ext.Component(Xji.makeDiv(res.body, opt.x_pnl));
			opt.x_pnl.write(cmpt, opt.x_anchor);
		} // OnPageLoad
		,
		/**
		 * ページ読み込みが失敗した時の処理
		 * @param {Object} res 処理結果
		 * @param {Object} opt リクエスト時に指定したパラメータ
		 */
		onRequestFail: function(res, opt) {
			var pnl = opt.x_pnl;
			if (res.err_type=='request') {
				XM.alert(
					'通信エラー',
					'「'+opt.url+'」への通信でエラーが発生しました<br />'+XJ.encode(res)
				);
			} else if (res.err_type=='app') {
				if (res.decode.reason=='PageNotFound' && (opt.x_action=='read' || opt.x_action=='edit')) {
					Xji.confirmWithResult(
						'ページ読み込み',
						res.decode.message+'<br />新規ページとして作成しますか？',
						res,
						[{
							text:'yes',
							handler:function(b,e){
								Xji.require('edit', function(opt){
									X.edit(opt);
								}, {page:opt.x_page,refer:opt.x_refer,force:true});
								Xji.remove(pnl);
								b.ownerCt.ownerCt.ownerCt.close();
							}
						},'-',{
							text:'no',
							handler:function(b,e){
								Xji.remove(pnl);
								b.ownerCt.ownerCt.ownerCt.close();
							}
						}]
					);
				} else {
					Xji.confirmWithResult(
						'ページ読み込み',
						'ページの読み込みに失敗しました'+ (res.decode.message?'<br />'+ res.decode.message:''),
						res
					);
				}
			} else if (res.responseText=="\n") {
				XM.alert(
					'編集保存エラー',
					'ページ「'+opt.x_page+'」の保存で空の改行が戻りました<br />'
					+'スパムと見なされてエラーとなった可能性があります'
				);
			} else if (opt.params && opt.params.x_cmd=='edit' && opt.params.write ) {
				var pg = pnl.getPI('page');
				Xji.loadPluginPage({page:pg, reload:true});
				Xji.confirmWithResult(
					'編集結果',
					'ページ'+(opt.x_page?'「'+opt.x_page+'」':'')+'の編集はおそらく成功しました。<br />'
						+'古い編集ページを閉じますか？',
					res,
					[{
						text:'yes',
						handler:function(b,e){
							var cont = Ext.getCmp('edit_continue').getValue();
							Xji.remove(pnl);
							if (cont) {
								Xji.require('edit', function(opt){
									X.edit(opt);
								}, {page:pg,edit_continue:cont});
							}
							b.ownerCt.ownerCt.ownerCt.close();
						}
					},{
						xtype:'checkbox',
						id:'edit_continue',
						checked: pnl.getPI('edit_continue'),
						boxLabel:'閉じて開く'
					},'->',{
						text:'no',
						handler:function(b,e){
							b.ownerCt.ownerCt.ownerCt.close();
						}
					}]
				);
			} else if (opt.params && opt.params.x_cmd=='edit' && opt.params.cancel) {
				Xji.remove(pnl);
			} else if (opt.params && (opt.params.x_cmd=='tracker'||opt.params.x_cmd=='pcomment')) {
				 Xji.confirmWithResult(
					'編集結果('+opt.params.x_cmd+')',
					'ページ'+(opt.x_page?'「'+opt.x_page+'」':'')+'の編集はおそらく成功しました。<br />'
						+'ページをリロードしますか？',
					res,
					[{
						text:'yes',
						handler:function(b,e){
							Xji.loadPluginPage({page:pnl.getPI('page'),reload:true});
							b.ownerCt.ownerCt.ownerCt.close();
						}
					},'-',{
						text:'no',
						handler:function(b,e){
							b.ownerCt.ownerCt.ownerCt.close();
						}
					}]
				);
			} else if (opt.params && opt.params.x_cmd=='rename' && opt.form && opt.form.pass) {
				var refer = opt.form.refer.value;
				Xji.confirmWithResult(
					'名前変更結果',
					'名前変更の結果<br />変更前のパネル「'+ refer +'」を閉じて、新しい名前「'+ opt.x_page +'」を開きますか',
					res,
					[{
						text:'yes',
						handler:function(b,e){
							Xji.remove(pnl);
							// 変更前のパネルを削除
							var pnls = Xji.find('both',{page:refer});
							for (var i=0,p; p=pnls[i]; ++i) {
								Xji.remove(p);
							}
							// 新しい名前のページを開く
							Xji.loadPluginPage({page:opt.x_page,reload:true});
							b.ownerCt.ownerCt.ownerCt.close();
						}
					},'-',{
						text:'no',
						handler:function(b,e){
							b.ownerCt.ownerCt.ownerCt.close();
						}
					}]
				);
			} else {
	 			Xji.confirmWithResult(
					'想定外の結果',
					'サーバーから想定外の結果が返されました',
					res
				);
			}
		} // onRequestFail
		,
		/**
		 * formの内容をPOSTする
		 * @param {Xji.Panel} pnl フォームのあったパネル
		 * @param {HtmlElement} form POSTするフォーム
		 */
		postForm: function(pnl, form) {
			var el, name, action, page, submit;
			// クエリーパラメータの分解
			var params = Ext.urlDecode(form.action.replace(/^.*[?]/,''), true);
			if (params.mode) params.x_mode = params.mode;
			// サブミットボタンをパラメータにセット
			if((submit=Ext.get(form)._submit)) params[submit.name] = submit.value;
			// actionの決定とエレメント名の一時的変更
			var action = params.plugin || params.cmd;
			for (var i=0; el=form.elements[i]; ++i) {
				name = el.name;
				if (!el.disabled && name) {
					if (name=='plugin' || name=='cmd') {
						el.name = 'xx_' + name;
						action  = el.value;
					} else if (name=='mode') {
						el.name = 'x_mode';
					} else if (name=='page') {
						page = el.value.replace(/^\[\[(.*)\]\]$/, '$1');
					}
					if (el.type=='submit') el.name='xx_' + name;
				}
			}
			params.x_cmd  = action;
			// 不要パラメータの削除
			delete params.cmd;
			delete params.plugin;
			delete params.mode;
			// リクエスト発行
			Xji.request({
				method: 'POST',
				url: P.UrlWiki+'?cmd=extwiki&mode=postForm',
				params: params,
				form:form,
				x_page: page,
				x_action: action,
				x_anchor: '',
				x_pnl: pnl,
				success: Xji.onPageLoad,
				failure: Xji.onRequestFail
			});
			// 一時的に変更した、エレメント名を元に戻す
			for (var i=0; el=form.elements[i]; ++i) el.name = el.name.replace(/^xx_/,'');
		}  // postForm
		,
		/**
		 * urlクエリーをオブジェクトに格納する
		 * @param {String} q クエリー
		 * @return {Object} 格納されたオブジェクト
		 */
		query2obj: function(q) {
			var aq = q.replace(/^\?/,'').split('&');
			for (var i=0,p={},s; s=aq[i]; ++i){
				var v = s.split('=');
				if (v.length<2) {
					p.page = s;
				} else {
					p[v[0]] = (v[0]=='page'||v[0]=='refer')?v[1]:decodeURIComponent(v[1]);
				}
			}
			return p;
		}
		,
		/**
		 * アクティブパネルをリロードする
		 */
		reload: function() {
			var pagename = Xji.getActivePanel().getPI('page');
			Xji.loadPluginPage({page:pagename,reload:true});
		}
		,
		/**
		 * 指定されたパネルを削除する
		 * @param {Xji.panel} pnl パネルへの参照またはID
		 */
		remove: function(pnl) {
			// mainかsubかを判定
			this.main.remove(pnl, true);
		}
		,
		/**
		 * Ajaxのリクエストを実行する
		 * @param {Object} opt success,failureの処理以外はほぼExt.Ajax.requestと同じ
		 */
		request: function(obj) {
			if (obj.x_pnl && obj.x_pnl.el) obj.x_pnl.el.mask('loading ...', 'x-mask-loading');
			obj.timeout = P.Timeout*1000;
			obj.failureX = obj.failure;
			obj.successX = obj.success;
			delete obj.failure;
			delete obj.success;
			obj.callback = function(opt, success, res) {
				if (opt.x_pnl && opt.x_pnl.el) opt.x_pnl.el.unmask();
				if (!success) {
					res.err_type = 'request';
				} else {
					if (res.responseText.match(/^<pre>(.*)<\/pre>$/)) // patch Ext3.0 bug
						res.responseText = res.responseText.replace(/^<pre>|<\/pre>$/g, '');
					try {
						res.decode = XJ.decode(res.responseText);
					} catch(e) {
						res.err_type = 'json';
					}
					res.err_type = !res.decode?'json'
								:(!res.decode.success?'app':false);
				}
				res.err_type? opt.failureX(res, opt)
						: opt.successX(res.decode.data, opt);
			} // obj.success 定義
			Ext.Ajax.request(obj);
		} //request
		,
		/**
		 * Javascript プラグインを準備し、指定された処理を実行する
		 * @param {String} target 必要とするJavascriptプラグインの名前。<br />
		 * まだロードされていない場合、xjpディレクトリにある拡張子「.js」ファイルを読み込む
		 * @param {Function} callback プラグインが読み込まれたときに実行される処理。<br />
		 * 既にロードされていればただちに実行される
		 * @param {Object} opt callbackが受け取る引数
		 */
		require: function(target, callback, opt) {
			if (typeof(target)=='string') target=target.split(/[ ,]+/);
			opt = opt||{};
			var t = target.shift();
			if (!t) {
				callback(opt);
			} else if (X[t]) {
				Xji.require(target, callback, opt);
			} else if (X._queue[t]) {
				X._queue[t].push({target:target,callback:callback, opt:opt});
			} else {
				X._queue[t] =[{target:target,callback:callback, opt:opt}];
				Ext.Ajax.request({
					url: P.UrlExtWiki+'/xjp/'+t+'.js',
					disableCaching: !!(X._list[t]),
					success: function(res, opts) {
						var cnt =  X._list[t]?X._list[t].count+1:1,
							scr = '/*'+t+': '+cnt+'*/\nX[t]='+ res.responseText;
						if (!X._lineEval) X._lineEval = (new Error()).lineNumber+2||-1;
						try {
							eval(scr);
						} catch(e) {
							dispError('の評価時にエラー発生('+(e.lineNumber?'line:'+(e.lineNumber-X._lineEval)+' ':'')+e.message+')');
							return;
						}
						X._list[t] = {
							url: opts.url,
							status: ''+res.status+' '+res.statusText,
							size: res.getResponseHeader('Content-Length'),
							date: res.getResponseHeader('Date'),
							modified: res.getResponseHeader('Last-Modified'),
							count: cnt,
							removed: false
						};
						for (var i=0,o; o=X._queue[t][i]; ++i) {
							Xji.require(o.target, o.callback, o.opt);
						}
						delete X._queue[t];
					},
					failure: function(res, opts) { //通信エラー処理
						if (res.status==404) {
							dispError('が存在しない、もしくは未実装です');
						} else {
							dispError('の読み込み中にエラー発生');
						}
					}
				});
			}
			function dispError(msg) {
				XM.alert('xjp 読込みエラー', 'Javascriptファイル「xjp/'+t+'.js」'+msg);
				delete X._queue[t];
			}
		} // require
		,
		/**
		 * サブリージョンのサイズを変更する
		 * @param {String} mode 'half' or 'menu' メニューの場合記憶したサイズ、half(デフォルト)の場合、画面の半分の大きさ
		 */
		setSubRegionSize: function(mode) {
			var sub=this.sub;
			if (mode=='menu') {
				if (sub.region=='west'||sub.region=='east') {
					sub.setWidth(sub.menuWidth);
				} else {
					sub.setHeight(sub.menuHeight);
				}
				sub.getTool('refresh').show();
			} else {
				if (sub.region=='west'||sub.region=='east') {
					sub.setWidth((sub.getWidth()+this.main.getWidth())/2-10);
				} else {
					sub.setHeight((sub.getHeight()+this.main.getHeight())/2-25);
				}
				sub.getTool('refresh').hide();
			}
			sub.on({
				collapse:function(){sub.expand(true)},
				single: true,
				delay: 100
			});
			sub.collapse(true);
		}
		,
		/**
		 * 短い形式で日時または日付を表示する<br />
		 * 10日以内であれば年を省略し分まで表示する<br />
		 * それ以上であれば、年月日を表示。日付でない場合、「-」を表示する
		 * @param {Date} dt 日時
		 * @return {String} 日付を表す文字列
		 */
		shortDate: function(dt) {
			return (dt instanceof Date)
				?dt.format((dt>(new Date)-10*24*60*60*1000)?'m/d H:i':'Y/m/d')
				:'-'
		}
		,
		/**
		 * バージョン情報取得
		 * @return {String} バージョンを表す文字列
		 */
		version: function(){return '1.4  $Rev: 81 $'.replace(/ \$/g,'')}
		,
		/**
		 * @class Xji.Panel  Extwiki Panelクラス定義
		 * @namespace Xji
		 * @extends Ext.Panel
		 * @constructor
		 * @param {Object} config The configuration options
		 * 
		 * @cfg {Object} pageinfo The information of this panel
		 */
		Panel: Ext.extend(Ext.Panel, {
			constructor: function(config) {
				this.pageinfo = config.pageinfo;
				Xji.Panel.superclass.constructor.apply(this, arguments);
			},
			/**
			 * ページ情報取得
			 * @param {String} key ページ情報のkey
			 * @return mixed keyが指定された場合、その値。なかった場合、ページ情報のオブジェクトを返す
			 */
			getPI: function(key) {
				return !key?this.pageinfo:(this.pageinfo[key]||'');
			},
			/**
			 * ページ情報設定
			 * @param {Object} pageinfo ページ情報を設定する
			 */
			setPI: function(obj) {
				if ('title' in obj) this.setTitle(obj.title);
				if ('iconClass' in obj) this.setIconClass(obj.iconClass);
				Ext.apply(this.pageinfo,obj);
			},
			/**
			 * ページ内容書込み
			 * 初めてページを読込んだ時に、お待ちくださいの画面をコンテンツに変更する
			 * @param {...Object/Array} cpmt 書き込むコンポーネント
			 * @param {String} anchor ページ内のアンカー
			 */
			write: function(cmpt, anchor) {
				this.removeAll(true); // 既存ページ削除
				this.add(cmpt); // コンテンツ表示
				this.doLayout(false,true);
				if (Xji.getActivePanel()==this){
					Xji.onPageActive(this);
				} else {
					Xji.activate(this, anchor);
				}
			},
			/**
			 * アンカーへ移動
			 * 初めてページを読込んだ時に、お待ちくださいの画面をコンテンツに変更する
			 * @param {String} anchor アンカー
			 */
			goAnchor: function(anchor) {
				if (anchor) {
					this.body.select(anchor).each(function(el){
						this.body.scrollTo('top', el.getTop(false)-this.body.getTop(false),true);
					},this);
				}
			} // goAnchor
		})
	}

	/**
	 * @class X
	 * 動的に読み込んだ、Javascript プラグインを格納する<br />
	 * 実際にはグローバルでなく、Ext.onReadyで呼ばれる関数の中でのみ参照可能です
	 * @singleton
	 */
	var X = {
		_queue: {},
		_list: {},
		_lineEval: null
	} // X

	// ページ全体のレイアウト
	var viewport = new Ext.Viewport({
		layout:'border',
		items:[
			{	// 上部ヘッダエリア
				contentEl:'north',
				region:'north',
				height:53
			},{
				region:'center',
				layout:'border',
				items:[Xji.sub, Xji.main]
			}
		],
		listeners: {
			render: function(p) {
				// 初期ページの追加とメニューパネルセット
				Xji.loadToolBar();
				// メニューパネルセット
				Xji.menu = Ext.getCmp('menu');
				Xji.loadMenuBar(false);
				Xji.loadPluginPage({page:P.FirstPage,_anchor:P.anchor0});
				// ロゴ作成
				XD.append(
					'top_logo', 
					{tag:'a', id:'logo_url', html:P.SightName, title:'トップページへ', href:P.UrlWiki},
					true
				).on('click', function(){Xji.loadPluginPage({})}, null, {stopEvent:true});
				Ext.get('top_url').on('click', function(){}, null, {stopEvent:true});
				//f5キーを押したときの制御
				Ext.getDoc().on('keydown', function(e) {
					if (e.keyCode==116 && !e.ctrlKey) {
						if (Ext.isIE) e.browserEvent.keyCode = 0;
						e.stopEvent();
						Xji.reload();
					}
				});
			},
			single: true  // Remove the listener after first invocation
		}
	}); // viewport
});
