From 95420164ae796977e93715665ccf075aee4cd3c2 Mon Sep 17 00:00:00 2001 From: Kazuhiko Shiozaki <kazuhiko@nexedi.com> Date: Fri, 21 Oct 2011 11:49:29 +0200 Subject: [PATCH] replace some css and javascript with compressed ones. --- .../erp5_xinha_editor/xinha/Xinha.css.xml | 480 +- .../erp5_xinha_editor/xinha/XinhaCore.js.xml | 8304 +---------------- bt5/erp5_xinha_editor/bt/revision | 2 +- 3 files changed, 9 insertions(+), 8777 deletions(-) diff --git a/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/Xinha.css.xml b/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/Xinha.css.xml index 3b384071f6..aaad548707 100644 --- a/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/Xinha.css.xml +++ b/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/Xinha.css.xml @@ -28,484 +28,8 @@ </item> <item> <key> <string>raw</string> </key> - <value> <string>.htmlarea { background: #fff; }\n -.htmlarea td { margin:0;padding:0; }\n -\n -.htmlarea .toolbarRow {\n - width:1px;\n -}\n -\n -.htmlarea .toolbar {\n - cursor: default;\n - background: ButtonFace;\n - padding: 3px;\n - border: 1px solid;\n - border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;\n -}\n -.htmlarea .toolbar table { margin: 0; font-family: Tahoma, Verdana,sans-serif; font-size: 11px; }\n -.htmlarea .toolbar img { border: none; vertical-align: top; }\n -.htmlarea .toolbar .label { padding: 0 3px; }\n -\n -.htmlarea .toolbar .button {\n - background: ButtonFace;\n - color: ButtonText;\n - border: 1px solid ButtonFace;\n - padding: 1px;\n - margin: 0;\n - width: 18px;\n - height: 18px;\n -}\n -.htmlarea .toolbar a.button:hover {\n - border: 1px solid;\n - border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;\n -}\n -.htmlarea .toolbar a.buttonDisabled:hover {\n - border-color: ButtonFace;\n -}\n -.htmlarea .toolbar .buttonActive,\n -.htmlarea .toolbar .buttonPressed\n -{\n - padding: 2px 0 0 2px;\n - border: 1px solid;\n - border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;\n -}\n -.htmlarea .toolbar .buttonPressed {\n - background: ButtonHighlight;\n -}\n -.htmlarea .toolbar .indicator {\n - padding: 0 3px;\n - overflow: hidden;\n - width: 20px;\n - text-align: center;\n - cursor: default;\n - border: 1px solid ButtonShadow;\n -}\n -\n -.htmlarea .toolbar .buttonDisabled img {\n - filter: gray() alpha(opacity = 25);\n - -moz-opacity: 0.25;\n - opacity: 0.25;\n -}\n -\n -.htmlarea .toolbar .separator {\n - /*position: relative;*/\n - margin:0 3px;\n - border-left: 1px solid ButtonShadow;\n - border-right: 1px solid ButtonHighlight;\n - width: 0;\n - height: 18px;\n - padding: 0;\n -}\n -\n -.htmlarea .toolbar .space { width: 5px; }\n -\n -.htmlarea .toolbar select, .htmlarea .toolbar option { font: 11px Tahoma,Verdana,sans-serif;}\n -\n -.htmlarea .toolbar select,\n -.htmlarea .toolbar select:hover,\n -.htmlarea .toolbar select:active { \n - position:relative;\n - top:-2px;\n - margin-bottom:-2px;\n - color: ButtonText;\n -}\n -\n -.htmlarea iframe.xinha_iframe, .htmlarea textarea.xinha_textarea\n -{\n - border: none; /*1px solid;*/\n -}\n -\n -.htmlarea .statusBar {\n - border: 1px solid;\n - border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;\n - padding: 2px 4px;\n - background-color: ButtonFace;\n - color: ButtonText;\n - font: 11px Tahoma,Verdana,sans-serif;\n - height:16px;\n - overflow: hidden;\n -}\n -\n -.htmlarea .statusBar .statusBarTree a {\n - padding: 2px 5px;\n - color: #00f;\n -}\n -\n -.htmlarea .statusBar .statusBarTree a:visited { color: #00f; }\n -.htmlarea .statusBar .statusBarTree a:hover {\n - background-color: Highlight;\n - color: HighlightText;\n - padding: 1px 4px;\n - border: 1px solid HighlightText;\n -}\n -\n -.statusBarWidgetContainer {\n - background-color: ButtonFace;\n -}\n -\n -/* popup dialogs */\n -\n -.dialog {\n - color: ButtonText;\n - background: ButtonFace; \n - border: 1px outset; \n - border-color: WindowFrame;\n -}\n -div.dialog {\n - padding-bottom:10px;\n - border-radius: 8px 8px 0 0;\n - -moz-border-radius: 8px 8px 0 0;\n - -webkit-border-top-left-radius: 8px;\n - -webkit-border-top-right-radius: 8px;\n - \n - box-shadow: 9px 9px 10px #444;\n - -moz-box-shadow: 9px 9px 10px #444;\n - -webkit-box-shadow: 9px 9px 10px #444;\n -}\n -div.dialog.modeless {\n - box-shadow: 4px 4px 5px #888;\n - -moz-box-shadow: 4px 4px 5px #888;\n - -webkit-box-shadow: 4px 4px 5px #888;\n -}\n -div.dialog.chrome {\n - -webkit-box-shadow: none !IMPORTANT;\n -}\n -.panels div.dialog.panel {\n - border-radius:0;\n - -moz-border-radius: 0;\n - -webkit-border-radius:0;\n - \n - box-shadow: none;\n - -moz-box-shadow: none;\n - -webkit-box-shadow: none;\n -}\n -.xinha_dialog_background {\n - filter: alpha(opacity=0);\n - -moz-opacity: 0;\n - opacity: 0;\n - border:none;\n -}\n -.xinha_dialog_background_modal_greyout {\n - background-color:#666;\n - filter: alpha(opacity=70) !IMPORTANT;\n - -moz-opacity: 0.7;\n - opacity: 0.7;\n -}\n -.xinha_dialog_background_modal {\n - filter: alpha(opacity=0) !IMPORTANT;\n - -moz-opacity: 0;\n - opacity: 0;\n - border:none;\n -}\n -body.xinha_dialog_background_modal_greyout {\n - filter: alpha(opacity=100) !IMPORTANT;\n -}\n -body.xinha_dialog_background_modal {\n - filter: alpha(opacity=0);\n -}\n -.dialog .content { padding: 2px; }\n -\n -.dialog, .dialog button, .dialog input, .dialog select, .dialog textarea, .dialog table {\n - font: 11px Tahoma,Verdana,sans-serif;\n -}\n -\n -.dialog table { border-collapse: collapse; }\n -\n -.dialog .title, .dialog h1\n -{\n - background: ActiveCaption;\n - color: CaptionText;\n - border-bottom: 1px solid #000;\n - padding: 1px 0 2px 5px;\n - font-size: 12px;\n - font-weight: bold;\n - cursor: default;\n - letter-spacing: 0.01em;\n -}\n -.dialog h1 { \n - padding-left:22px;\n - margin:0;\n - border-radius: 8px 8px 0 0;\n - -moz-border-radius: 8px 8px 0 0;\n - -webkit-border-top-left-radius: 8px;\n - -webkit-border-top-right-radius: 8px;\n -}\n -.panels .dialog.panel h1 { \n - -moz-border-radius: 0;\n - -webkit-border-radius:0;\n -}\n -\n -.dialog .title .button {\n - float: right;\n - border: 1px solid #66a;\n - padding: 0 1px 0 2px;\n - margin-right: 1px;\n - color: #fff;\n - text-align: center;\n -}\n -\n -.dialog .title .button-hilite { border-color: #88f; background: #44c; }\n -\n -.dialog button {\n - width: 5.5em;\n - padding: 0;\n -}\n -.dialog .closeButton {\n - padding: 0;\n - cursor: default;\n - border: 1px solid;\n - border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;\n - height : 11px;\n - width : 11px;\n - vertical-align : top;\n - position : absolute;\n - top : 3px;\n - right : 2px;\n - background-color: ButtonFace;\n - color: ButtonText;\n - font-size: 13px;\n - font-family: Tahoma,Verdana,sans-serif;\n - text-align:center;\n - letter-spacing:0;\n - overflow:hidden;\n -}\n -.dialog .buttonColor {\n - width :1em;\n - padding: 1px;\n - cursor: default;\n - border: 1px solid;\n - border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;\n -}\n -\n -.dialog .buttonColor .chooser, .dialog .buttonColor .nocolor {\n - height: 0.6em;\n - border: 1px solid;\n - padding: 0 1em;\n - border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;\n -}\n -\n -.dialog .buttonClick {\n - border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;\n -}\n -.dialog .buttonColor-hilite {\n - border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;\n -}\n -\n -.dialog .buttonColor .nocolor { padding: 0; }\n -.dialog .buttonColor .nocolor-hilite { background-color: #fff; color: #f00; }\n -\n -.dialog .label { text-align: right; width: 6em; }\n -.dialog .value input { width: 100%; }\n -\n -.dialog legend { font-weight: bold; }\n -.dialog fieldset table { margin: 2px 0; }\n - \n -.dialog .buttons {\n -\n - padding: 1em; \n - text-align: center;\n -}\n -.dialog .resizeHandle {\n - -moz-appearance : resizer;\n - width: 12px;\n - height: 12px;\n - border-bottom: 2px solid #000;\n - border-right: 2px solid #000;\n - cursor : se-resize;\n -}\n -.popupwin {\n - padding: 0;\n - margin: 0;\n -}\n -\n -.popupwin .title {\n - background: #fff;\n - color: #000;\n - font-weight: bold;\n - font-size: 120%;\n - padding: 3px 10px;\n - margin-bottom: 10px;\n - border-bottom: 1px solid black;\n - letter-spacing: 2px;\n -}\n -\n -form { margin: 0; border: none; }\n -\n -\n -/** Panels **/\n -.htmlarea .panels_top\n -{\n - border-bottom : 1px solid;\n - border-color: ButtonShadow;\n -}\n -\n -.htmlarea .panels_right\n -{\n - border-left : 1px solid;\n - border-color: ButtonShadow;\n -}\n -\n -.htmlarea .panels_left\n -{\n - border-right : 1px solid;\n - border-color: ButtonShadow;\n -}\n -\n -.htmlarea .panels_bottom\n -{\n - border-top : 1px solid;\n - border-color: ButtonShadow;\n -}\n -\n -.htmlarea .panel h1 {\n - clear:left;\n - font-size:0.9em;\n -}\n -\n -.htmlarea .panel { \n - overflow:hidden; \n - background-color:white;\n - padding-bottom:0 !IMPORTANT;\n - border: none !IMPORTANT;\n -}\n -.htmlarea .panels_left .panel { border-right:none; border-left:none; }\n -.htmlarea .panels_left h1 { border-right:none; }\n -.htmlarea .panels_right .panel { border-right:none; border-left:none; }\n -.htmlarea .panels_left h1 { border-left:none; }\n -.htmlarea { border: 1px solid black; }\n -\n -.loading\n -{\n - font-family:sans-serif;\n - position:absolute;\n - z-index:998;\n - text-align:center;\n - width:212px;\n - padding: 55px 0 5px 0;\n - border:2px solid #ccc;\n - /* border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;*/\n - background: url(images/xinha_logo.gif) no-repeat #fff center 5px;\n -}\n -.loading_main\n -{\n - font-size:11px;\n - color:#000;\n - \n -}\n -.loading_sub\n -{\n - font-size:9px;\n - color:#666;\n - text-align:center;\n -}\n -/* Classes for filemanager styles in a dialog. */\n -.dialog a img\n -{\n -border: 0 none transparent;\n -}\n -\n -.dialog fieldset.collapsed {\n -border: 0 none transparent;\n -}\n -\n -.dialog fieldset.collapsed form {\n -display: none;\n -}\n -\n -.hidden\n -{\n -display: none;\n -}\n -\n -.placesmanager\n -{\n - width: 95%;\n - overflow: auto;\n -}\n -\n -.filemanager\n -{\n - width: 95%;\n - height: 200px;\n - overflow: auto;\n - background-color: #fff;\n -}\n -.filemanager div.file\n -{\n - min-width: 80px;\n - height: 100px;\n - position: relative;\n - float: left;\n - border: 1px outset #666;\n - margin: 4px;\n -}\n -.placesmanager div.file\n -{\n - min-width: 60px;\n - height: 70px;\n - position: relative;\n - float: left;\n - border: 1px outset #666;\n - margin: 4px;\n -}\n -.filemanager div.file:hover,\n -.placesmanager div.file:hover\n -{\n - border: 1px solid #333;\n - background: #fffff3;\n -}\n -\n -.filemanager div.selected,\n -.filemanager div.selected:hover,\n -.placesmanager div.selected,\n -.placesmanager div.selected:hover\n -{\n - background: #ffffda;\n - border: 1px solid #000;\n -}\n -.filemanager .filename {\n -\tmargin: 0.5em;\n -\tcolor: #222;\n -}\n -.filemanager div.selected .filename {\n - color: #000;\n -}\n -.filemanager img.thumb\n -{\n - width: 50px;\n - height: 50px;\n - position: absolute;\n - top: 50%;\n - left: 50%;\n - margin: -25px 0 0 -25px;\n - border: 1px solid black;\n -}\n -.filemanager img.icon\n -{\n - width: 32px;\n - height: 32px;\n - position: absolute;\n - top: 50%;\n - left: 50%;\n - margin: -16px 0 0 -16px;\n -}\n -.filemanager img.action\n -{\n - width: 15px;\n - height: 15px;\n - position: absolute;\n -}\n -.filemanager img.delete\n -{\n - bottom: 3px;\n - left: 20px;\n -}\n -.filemanager img.copy\n -{\n - bottom: 3px;\n - left: 3px;\n -}\n -</string> </value> + <value> <string>/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */\n +.htmlarea{background:#fff;}.htmlarea td{margin:0;padding:0;}.htmlarea .toolbarRow{width:1px;}.htmlarea .toolbar{cursor:default;background:ButtonFace;padding:3px;border:1px solid;border-color:ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;}.htmlarea .toolbar table{margin:0;font-family:Tahoma,Verdana,sans-serif;font-size:11px;}.htmlarea .toolbar img{border:none;vertical-align:top;}.htmlarea .toolbar .label{padding:0 3px;}.htmlarea .toolbar .button{background:ButtonFace;color:ButtonText;border:1px solid ButtonFace;padding:1px;margin:0;width:18px;height:18px;}.htmlarea .toolbar a.button:hover{border:1px solid;border-color:ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;}.htmlarea .toolbar a.buttonDisabled:hover{border-color:ButtonFace;}.htmlarea .toolbar .buttonActive,.htmlarea .toolbar .buttonPressed{padding:2px 0 0 2px;border:1px solid;border-color:ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;}.htmlarea .toolbar .buttonPressed{background:ButtonHighlight;}.htmlarea .toolbar .indicator{padding:0 3px;overflow:hidden;width:20px;text-align:center;cursor:default;border:1px solid ButtonShadow;}.htmlarea .toolbar .buttonDisabled img{filter:gray() alpha(opacity = 25);-moz-opacity:.25;opacity:.25;}.htmlarea .toolbar .separator{margin:0 3px;border-left:1px solid ButtonShadow;border-right:1px solid ButtonHighlight;width:0;height:18px;padding:0;}.htmlarea .toolbar .space{width:5px;}.htmlarea .toolbar select,.htmlarea .toolbar option{font:11px Tahoma,Verdana,sans-serif;}.htmlarea .toolbar select,.htmlarea .toolbar select:hover,.htmlarea .toolbar select:active{position:relative;top:-2px;margin-bottom:-2px;color:ButtonText;}.htmlarea iframe.xinha_iframe,.htmlarea textarea.xinha_textarea{border:none;}.htmlarea .statusBar{border:1px solid;border-color:ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;padding:2px 4px;background-color:ButtonFace;color:ButtonText;font:11px Tahoma,Verdana,sans-serif;height:16px;overflow:hidden;}.htmlarea .statusBar .statusBarTree a{padding:2px 5px;color:#00f;}.htmlarea .statusBar .statusBarTree a:visited{color:#00f;}.htmlarea .statusBar .statusBarTree a:hover{background-color:Highlight;color:HighlightText;padding:1px 4px;border:1px solid HighlightText;}.statusBarWidgetContainer{background-color:ButtonFace;}.dialog{color:ButtonText;background:ButtonFace;border:1px outset;border-color:WindowFrame;}div.dialog{padding-bottom:10px;border-radius:8px 8px 0 0;-moz-border-radius:8px 8px 0 0;-webkit-border-top-left-radius:8px;-webkit-border-top-right-radius:8px;box-shadow:9px 9px 10px #444;-moz-box-shadow:9px 9px 10px #444;-webkit-box-shadow:9px 9px 10px #444;}div.dialog.modeless{box-shadow:4px 4px 5px #888;-moz-box-shadow:4px 4px 5px #888;-webkit-box-shadow:4px 4px 5px #888;}div.dialog.chrome{-webkit-box-shadow:none!IMPORTANT;}.panels div.dialog.panel{border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;box-shadow:none;-moz-box-shadow:none;-webkit-box-shadow:none;}.xinha_dialog_background{filter:alpha(opacity=0);-moz-opacity:0;opacity:0;border:none;}.xinha_dialog_background_modal_greyout{background-color:#666;filter:alpha(opacity=70)!IMPORTANT;-moz-opacity:.7;opacity:.7;}.xinha_dialog_background_modal{filter:alpha(opacity=0)!IMPORTANT;-moz-opacity:0;opacity:0;border:none;}body.xinha_dialog_background_modal_greyout{filter:alpha(opacity=100)!IMPORTANT;}body.xinha_dialog_background_modal{filter:alpha(opacity=0);}.dialog .content{padding:2px;}.dialog,.dialog button,.dialog input,.dialog select,.dialog textarea,.dialog table{font:11px Tahoma,Verdana,sans-serif;}.dialog table{border-collapse:collapse;}.dialog .title,.dialog h1{background:ActiveCaption;color:CaptionText;border-bottom:1px solid #000;padding:1px 0 2px 5px;font-size:12px;font-weight:bold;cursor:default;letter-spacing:.01em;}.dialog h1{padding-left:22px;margin:0;border-radius:8px 8px 0 0;-moz-border-radius:8px 8px 0 0;-webkit-border-top-left-radius:8px;-webkit-border-top-right-radius:8px;}.panels .dialog.panel h1{-moz-border-radius:0;-webkit-border-radius:0;}.dialog .title .button{float:right;border:1px solid #66a;padding:0 1px 0 2px;margin-right:1px;color:#fff;text-align:center;}.dialog .title .button-hilite{border-color:#88f;background:#44c;}.dialog button{width:5.5em;padding:0;}.dialog .closeButton{padding:0;cursor:default;border:1px solid;border-color:ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;height:11px;width:11px;vertical-align:top;position:absolute;top:3px;right:2px;background-color:ButtonFace;color:ButtonText;font-size:13px;font-family:Tahoma,Verdana,sans-serif;text-align:center;letter-spacing:0;overflow:hidden;}.dialog .buttonColor{width:1em;padding:1px;cursor:default;border:1px solid;border-color:ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;}.dialog .buttonColor .chooser,.dialog .buttonColor .nocolor{height:.6em;border:1px solid;padding:0 1em;border-color:ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;}.dialog .buttonClick{border-color:ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;}.dialog .buttonColor-hilite{border-color:ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;}.dialog .buttonColor .nocolor{padding:0;}.dialog .buttonColor .nocolor-hilite{background-color:#fff;color:#f00;}.dialog .label{text-align:right;width:6em;}.dialog .value input{width:100%;}.dialog legend{font-weight:bold;}.dialog fieldset table{margin:2px 0;}.dialog .buttons{padding:1em;text-align:center;}.dialog .resizeHandle{-moz-appearance:resizer;width:12px;height:12px;border-bottom:2px solid #000;border-right:2px solid #000;cursor:se-resize;}.popupwin{padding:0;margin:0;}.popupwin .title{background:#fff;color:#000;font-weight:bold;font-size:120%;padding:3px 10px;margin-bottom:10px;border-bottom:1px solid black;letter-spacing:2px;}form{margin:0;border:none;}.htmlarea .panels_top{border-bottom:1px solid;border-color:ButtonShadow;}.htmlarea .panels_right{border-left:1px solid;border-color:ButtonShadow;}.htmlarea .panels_left{border-right:1px solid;border-color:ButtonShadow;}.htmlarea .panels_bottom{border-top:1px solid;border-color:ButtonShadow;}.htmlarea .panel h1{clear:left;font-size:.9em;}.htmlarea .panel{overflow:hidden;background-color:white;padding-bottom:0!IMPORTANT;border:none!IMPORTANT;}.htmlarea .panels_left .panel{border-right:none;border-left:none;}.htmlarea .panels_left h1{border-right:none;}.htmlarea .panels_right .panel{border-right:none;border-left:none;}.htmlarea .panels_left h1{border-left:none;}.htmlarea{border:1px solid black;}.loading{font-family:sans-serif;position:absolute;z-index:998;text-align:center;width:212px;padding:55px 0 5px 0;border:2px solid #ccc;background:url(images/xinha_logo.gif) no-repeat #fff center 5px;}.loading_main{font-size:11px;color:#000;}.loading_sub{font-size:9px;color:#666;text-align:center;}.dialog a img{border:0 none transparent;}.dialog fieldset.collapsed{border:0 none transparent;}.dialog fieldset.collapsed form{display:none;}.hidden{display:none;}.placesmanager{width:95%;overflow:auto;}.filemanager{width:95%;height:200px;overflow:auto;background-color:#fff;}.filemanager div.file{min-width:80px;height:100px;position:relative;float:left;border:1px outset #666;margin:4px;}.placesmanager div.file{min-width:60px;height:70px;position:relative;float:left;border:1px outset #666;margin:4px;}.filemanager div.file:hover,.placesmanager div.file:hover{border:1px solid #333;background:#fffff3;}.filemanager div.selected,.filemanager div.selected:hover,.placesmanager div.selected,.placesmanager div.selected:hover{background:#ffffda;border:1px solid #000;}.filemanager .filename{margin:.5em;color:#222;}.filemanager div.selected .filename{color:#000;}.filemanager img.thumb{width:50px;height:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;border:1px solid black;}.filemanager img.icon{width:32px;height:32px;position:absolute;top:50%;left:50%;margin:-16px 0 0 -16px;}.filemanager img.action{width:15px;height:15px;position:absolute;}.filemanager img.delete{bottom:3px;left:20px;}.filemanager img.copy{bottom:3px;left:3px;}</string> </value> </item> <item> <key> <string>title</string> </key> diff --git a/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/XinhaCore.js.xml b/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/XinhaCore.js.xml index b5a057c25d..d949da1a0a 100644 --- a/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/XinhaCore.js.xml +++ b/bt5/erp5_xinha_editor/SkinTemplateItem/portal_skins/erp5_xinha_editor/xinha/XinhaCore.js.xml @@ -30,8315 +30,23 @@ <key> <string>raw</string> </key> <value> <string encoding="cdata"><![CDATA[ - \n - /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:--\n +/* This compressed file is part of Xinha. For uncompressed sources, forum, and bug reports, go to xinha.org */\n +/* The URL of the most recent uncompressed version of this file is http://svn.xinha.org/trunk/XinhaCore.js */\n + /*--------------------------------------------------------------------------\n -- Xinha (is not htmlArea) - http://xinha.org\n --\n -- Use of Xinha is granted by the terms of the htmlArea License (based on\n -- BSD license) please read license.txt in this package for details.\n --\n - -- Copyright (c) 2005-2008 Xinha Developer Team and contributors\n + -- Copyright (c) 2005-2010 Xinha Developer Team and contributors\n -- \n -- Xinha was originally based on work by Mihai Bazon which is:\n -- Copyright (c) 2003-2004 dynarch.com.\n -- Copyright (c) 2002-2003 interactivetools.com, inc.\n -- This copyright notice MUST stay intact for use.\n - --\n - -- Developers - Coding Style: \n - -- Before you are going to work on Xinha code, please see http://trac.xinha.org/wiki/Documentation/StyleGuide\n - --\n - -- $HeadURL: http://svn.xinha.org/trunk/XinhaCore.js $\n - -- $LastChangedDate: 2010-05-12 09:40:06 +1200 (Wed, 12 May 2010) $\n - -- $LastChangedRevision: 1263 $\n - -- $LastChangedBy: gogo $\n - --------------------------------------------------------------------------*/\n -/*jslint regexp: false, rhino: false, browser: true, bitwise: false, forin: true, adsafe: false, evil: true, nomen: false, \n -glovar: false, debug: false, eqeqeq: false, passfail: false, sidebar: false, laxbreak: false, on: false, cap: true, \n -white: false, widget: false, undef: true, plusplus: false*/\n -/*global Dialog , _editor_css , _editor_icons, _editor_lang , _editor_skin , _editor_url, dumpValues, ActiveXObject, HTMLArea, _editor_lcbackend*/\n -\n -/** Information about the Xinha version \n - * @type Object\n - */\n -Xinha.version =\n -{\n - \'Release\' : \'Trunk\',\n - \'Head\' : \'$HeadURL: http://svn.xinha.org/trunk/XinhaCore.js $\'.replace(/^[^:]*:\\s*(.*)\\s*\\$$/, \'$1\'),\n - \'Date\' : \'$LastChangedDate: 2010-05-12 09:40:06 +1200 (Wed, 12 May 2010) $\'.replace(/^[^:]*:\\s*([0-9\\-]*) ([0-9:]*) ([+0-9]*) \\((.*)\\)\\s*\\$/, \'$4 $2 $3\'),\n - \'Revision\' : \'$LastChangedRevision: 1263 $\'.replace(/^[^:]*:\\s*(.*)\\s*\\$$/, \'$1\'),\n - \'RevisionBy\': \'$LastChangedBy: gogo $\'.replace(/^[^:]*:\\s*(.*)\\s*\\$$/, \'$1\')\n -};\n -\n -//must be here. it is called while converting _editor_url to absolute\n -Xinha._resolveRelativeUrl = function( base, url )\n -{\n - if(url.match(/^([^:]+\\:)?\\/\\//))\n - {\n - return url;\n - }\n - else\n - {\n - var b = base.split("/");\n - if(b[b.length - 1] === "")\n - {\n - b.pop();\n - }\n - var p = url.split("/");\n - if(p[0] == ".")\n - {\n - p.shift();\n - }\n - while(p[0] == "..")\n - {\n - b.pop();\n - p.shift();\n - }\n - return b.join("/") + "/" + p.join("/");\n - }\n -};\n -\n -if ( typeof _editor_url == "string" )\n -{\n - // Leave exactly one backslash at the end of _editor_url\n - _editor_url = _editor_url.replace(/\\x2f*$/, \'/\');\n - \n - // convert _editor_url to absolute\n - if(!_editor_url.match(/^([^:]+\\:)?\\//))\n - {\n - (function()\n - {\n - var tmpPath = window.location.toString().replace(/\\?.*$/,\'\').split("/");\n - tmpPath.pop();\n - _editor_url = Xinha._resolveRelativeUrl(tmpPath.join("/"), _editor_url);\n - })();\n - }\n -}\n -else\n -{\n - alert("WARNING: _editor_url is not set! You should set this variable to the editor files path; it should preferably be an absolute path, like in \'/xinha/\', but it can be relative if you prefer. Further we will try to load the editor files correctly but we\'ll probably fail.");\n - _editor_url = \'\';\n -}\n -\n -// make sure we have a language\n -if ( typeof _editor_lang == "string" )\n -{\n - _editor_lang = _editor_lang.toLowerCase();\n -}\n -else\n -{\n - _editor_lang = "en";\n -}\n -\n -// skin stylesheet to load\n -if ( typeof _editor_skin !== "string" )\n -{\n - _editor_skin = "";\n -}\n -\n -if ( typeof _editor_icons !== "string" )\n -{\n - _editor_icons = "";\n -}\n -/**\n -* The list of Xinha editors on the page. May be multiple editors.\n -* You can access each editor object through this global variable.\n -*\n -* Example:<br />\n -* <code>\n -*\tvar html = __xinhas[0].getEditorContent(); // gives you the HTML of the first editor in the page\n -* </code>\n -*/\n -var __xinhas = [];\n -\n -// browser identification\n -/** Cache the user agent for the following checks\n - * @type String\n - * @private\n - */\n -Xinha.agt = navigator.userAgent.toLowerCase();\n -/** Browser is Microsoft Internet Explorer\n - * @type Boolean \n - */\n -Xinha.is_ie = ((Xinha.agt.indexOf("msie") != -1) && (Xinha.agt.indexOf("opera") == -1));\n -/** Version Number, if browser is Microsoft Internet Explorer\n - * @type Float \n - */\n -Xinha.ie_version= parseFloat(Xinha.agt.substring(Xinha.agt.indexOf("msie")+5));\n -/** Browser is Opera\n - * @type Boolean \n - */\n -Xinha.is_opera = (Xinha.agt.indexOf("opera") != -1);\n -/** Version Number, if browser is Opera \n - * @type Float \n - */\n -if(Xinha.is_opera && Xinha.agt.match(/opera[\\/ ]([0-9.]+)/))\n -{\n - Xinha.opera_version = parseFloat(RegExp.$1);\n -}\n -else\n -{\n - Xinha.opera_version = 0;\n -}\n -/** Browserengine is KHTML (Konqueror, Safari)\n - * @type Boolean \n - */\n -Xinha.is_khtml = (Xinha.agt.indexOf("khtml") != -1);\n -/** Browser is WebKit\n - * @type Boolean \n - */\n -Xinha.is_webkit = (Xinha.agt.indexOf("applewebkit") != -1);\n -/** Webkit build number\n - * @type Integer\n - */\n -Xinha.webkit_version = parseInt(navigator.appVersion.replace(/.*?AppleWebKit\\/([\\d]).*?/,\'$1\'), 10);\n -\n -/** Browser is Safari\n - * @type Boolean \n - */\n -Xinha.is_safari = (Xinha.agt.indexOf("safari") != -1);\n -\n -/** Browser is Google Chrome\n - * @type Boolean \n - */\n -Xinha.is_chrome = (Xinha.agt.indexOf("chrome") != -1);\n -\n -/** OS is MacOS\n - * @type Boolean \n - */\n -Xinha.is_mac\t = (Xinha.agt.indexOf("mac") != -1);\n -/** Browser is Microsoft Internet Explorer Mac\n - * @type Boolean \n - */\n -Xinha.is_mac_ie = (Xinha.is_ie && Xinha.is_mac);\n -/** Browser is Microsoft Internet Explorer Windows\n - * @type Boolean \n - */\n -Xinha.is_win_ie = (Xinha.is_ie && !Xinha.is_mac);\n -/** Browser engine is Gecko (Mozilla), applies also to Safari and Opera which work\n - * largely similar.\n - *@type Boolean \n - */\n -Xinha.is_gecko = (navigator.product == "Gecko") || Xinha.is_opera;\n -/** Browser engine is really Gecko, i.e. Browser is Firefox (or Netscape, SeaMonkey, Flock, Songbird, Beonex, K-Meleon, Camino, Galeon, Kazehakase, Skipstone, or whatever derivate might exist out there...)\n - * @type Boolean \n - */\n -Xinha.is_real_gecko = (navigator.product == "Gecko" && !Xinha.is_webkit);\n -\n -/** Gecko version lower than 1.9\n - * @type Boolean \n - */\n -Xinha.is_ff2 = Xinha.is_real_gecko && parseInt(navigator.productSub.substr(0,10), 10) < 20071210;\n -\n -/** File is opened locally opened ("file://" protocol)\n - * @type Boolean\n - * @private\n - */\n -Xinha.isRunLocally = document.URL.toLowerCase().search(/^file:/) != -1;\n -/** Editing is enabled by document.designMode (Gecko, Opera), as opposed to contenteditable (IE)\n - * @type Boolean\n - * @private\n - */\n -Xinha.is_designMode = (typeof document.designMode != \'undefined\' && !Xinha.is_ie); // IE has designMode, but we\'re not using it\n -\n -/** Check if Xinha can run in the used browser, otherwise the textarea will be remain unchanged\n - * @type Boolean\n - * @private\n - */\n -Xinha.checkSupportedBrowser = function()\n -{\n - return Xinha.is_real_gecko || (Xinha.is_opera && Xinha.opera_version >= 9.2) || Xinha.ie_version >= 5.5 || Xinha.webkit_version >= 522;\n -};\n -/** Cache result of checking for browser support\n - * @type Boolean\n - * @private\n - */\n -Xinha.isSupportedBrowser = Xinha.checkSupportedBrowser();\n -\n -if ( Xinha.isRunLocally && Xinha.isSupportedBrowser)\n -{\n - alert(\'Xinha *must* be installed on a web server. Locally opened files (those that use the "file://" protocol) cannot properly function. Xinha will try to initialize but may not be correctly loaded.\');\n -}\n -\n -/** Creates a new Xinha object\n - * @version $Rev: 1263 $ $LastChangedDate: 2010-05-12 09:40:06 +1200 (Wed, 12 May 2010) $\n - * @constructor\n - * @param {String|DomNode} textarea the textarea to replace; can be either only the id or the DOM object as returned by document.getElementById()\n - * @param {Xinha.Config} config optional if no Xinha.Config object is passed, the default config is used\n - */\n -function Xinha(textarea, config)\n -{ \n - if ( !Xinha.isSupportedBrowser )\n - {\n - return;\n - }\n - \n - if ( !textarea )\n - {\n - throw new Error ("Tried to create Xinha without textarea specified.");\n - }\n -\n - if ( typeof config == "undefined" )\n - {\n -\t\t/** The configuration used in the editor\n -\t\t * @type Xinha.Config\n -\t\t */\n - this.config = new Xinha.Config();\n - }\n - else\n - {\n - this.config = config;\n - }\n -\n - if ( typeof textarea != \'object\' )\n - {\n - textarea = Xinha.getElementById(\'textarea\', textarea);\n - }\n - /** This property references the original textarea, which is at the same time the editor in text mode\n - * @type DomNode textarea\n - */\n - this._textArea = textarea;\n - this._textArea.spellcheck = false;\n - Xinha.freeLater(this, \'_textArea\');\n - \n - // \n - /** Before we modify anything, get the initial textarea size\n - * @private\n - * @type Object w,h \n - */\n - this._initial_ta_size =\n - {\n - w: textarea.style.width ? textarea.style.width : ( textarea.offsetWidth ? ( textarea.offsetWidth + \'px\' ) : ( textarea.cols + \'em\') ),\n - h: textarea.style.height ? textarea.style.height : ( textarea.offsetHeight ? ( textarea.offsetHeight + \'px\' ) : ( textarea.rows + \'em\') )\n - };\n -\n - if ( document.getElementById("loading_" + textarea.id) || this.config.showLoading )\n - {\n - if (!document.getElementById("loading_" + textarea.id))\n - {\n - Xinha.createLoadingMessage(textarea);\n - }\n - this.setLoadingMessage(Xinha._lc("Constructing object"));\n - }\n -\n - /** the current editing mode\n - * @private \n - * @type string "wysiwyg"|"text"\n - */\n - this._editMode = "wysiwyg";\n - /** this object holds the plugins used in the editor\n - * @private \n - * @type Object\n - */\n - this.plugins = {};\n - /** periodically updates the toolbar\n - * @private \n - * @type timeout\n - */\n - this._timerToolbar = null;\n - /** periodically takes a snapshot of the current editor content\n - * @private \n - * @type timeout\n - */\n - this._timerUndo = null;\n - /** holds the undo snapshots\n - * @private \n - * @type Array\n - */\n - this._undoQueue = [this.config.undoSteps];\n - /** the current position in the undo queue \n - * @private \n - * @type integer\n - */\n - this._undoPos = -1;\n - /** use our own undo implementation (true) or the browser\'s (false) \n - * @private \n - * @type Boolean\n - */\n - this._customUndo = true;\n - /** the document object of the page Xinha is embedded in\n - * @private \n - * @type document\n - */\n - this._mdoc = document; // cache the document, we need it in plugins\n - /** doctype of the edited document (fullpage mode)\n - * @private \n - * @type string\n - */\n - this.doctype = \'\';\n - /** running number that identifies the current editor\n - * @public \n - * @type integer\n - */\n - this.__htmlarea_id_num = __xinhas.length;\n - __xinhas[this.__htmlarea_id_num] = this;\n -\t\n - /** holds the events for use with the notifyOn/notifyOf system\n - * @private \n - * @type Object\n - */\n - this._notifyListeners = {};\n -\n - // Panels\n - var panels = \n - {\n - right:\n - {\n - on: true,\n - container: document.createElement(\'td\'),\n - panels: []\n - },\n - left:\n - {\n - on: true,\n - container: document.createElement(\'td\'),\n - panels: []\n - },\n - top:\n - {\n - on: true,\n - container: document.createElement(\'td\'),\n - panels: []\n - },\n - bottom:\n - {\n - on: true,\n - container: document.createElement(\'td\'),\n - panels: []\n - }\n - };\n -\n - for ( var i in panels )\n - {\n - if(!panels[i].container) { continue; } // prevent iterating over wrong type\n - panels[i].div = panels[i].container; // legacy\n - panels[i].container.className = \'panels panels_\' + i;\n - Xinha.freeLater(panels[i], \'container\');\n - Xinha.freeLater(panels[i], \'div\');\n - }\n - /** holds the panels\n - * @private \n - * @type Array\n - */\n - // finally store the variable\n - this._panels = panels;\n -\t\n - // Init some properties that are defined later\n - /** The statusbar container\n - * @type DomNode statusbar div\n - */\n - this._statusBar = null;\n - /** The DOM path that is shown in the statusbar in wysiwyg mode\n - * @private\n - * @type DomNode\n - */\n - this._statusBarTree = null;\n - /** The message that is shown in the statusbar in text mode\n - * @private\n - * @type DomNode\n - */\n - this._statusBarTextMode = null;\n - /** Holds the items of the DOM path that is shown in the statusbar in wysiwyg mode\n - * @private\n - * @type Array tag names\n - */\n - this._statusBarItems = [];\n - /** Holds the parts (table cells) of the UI (toolbar, panels, statusbar)\n -\n - * @type Object framework parts\n - */\n - this._framework = {};\n - /** Them whole thing (table)\n - * @private\n - * @type DomNode\n - */\n - this._htmlArea = null;\n - /** This is the actual editable area.<br />\n - * Technically it\'s an iframe that\'s made editable using window.designMode = \'on\', respectively document.body.contentEditable = true (IE).<br />\n - * Use this property to get a grip on the iframe\'s window features<br />\n - *\n - * @type window\n - */\n - this._iframe = null;\n - /** The document object of the iframe.<br />\n - * Use this property to perform DOM operations on the edited document\n - * @type document\n - */\n - this._doc = null;\n - /** The toolbar\n - * @private\n - * @type DomNode \n - */\n - this._toolBar = this._toolbar = null; //._toolbar is for legacy, ._toolBar is better thanks.\n - /** Holds the botton objects\n - * @private\n - * @type Object\n - */\n - this._toolbarObjects = {};\n - \n - //hook in config.Events as as a "plugin"\n - this.plugins.Events = \n - {\n - name: \'Events\',\n - developer : \'The Xinha Core Developer Team\',\n - instance: config.Events\n - };\n -};\n -// ray: What is this for? Do we need it?\n -Xinha.onload = function() { };\n -Xinha.init = function() { Xinha.onload(); };\n -\n -// cache some regexps\n -/** Identifies HTML tag names\n -* @type RegExp\n -*/\n -Xinha.RE_tagName = /(<\\/|<)\\s*([^ \\t\\n>]+)/ig;\n -/** Exracts DOCTYPE string from HTML\n -* @type RegExp\n -*/\n -Xinha.RE_doctype = /(<!doctype((.|\\n)*?)>)\\n?/i;\n -/** Finds head section in HTML\n -* @type RegExp\n -*/\n -Xinha.RE_head = /<head>((.|\\n)*?)<\\/head>/i;\n -/** Finds body section in HTML\n -* @type RegExp\n -*/\n -Xinha.RE_body = /<body[^>]*>((.|\\n|\\r|\\t)*?)<\\/body>/i;\n -/** Special characters that need to be escaped when dynamically creating a RegExp from an arbtrary string\n -* @private\n -* @type RegExp\n -*/\n -Xinha.RE_Specials = /([\\/\\^$*+?.()|{}\\[\\]])/g;\n -/** When dynamically creating a RegExp from an arbtrary string, some charactes that have special meanings in regular expressions have to be escaped.\n -* Run any string through this function to escape reserved characters.\n -* @param {string} string the string to be escaped\n -* @returns string\n -*/\n -Xinha.escapeStringForRegExp = function (string)\n -{\n - return string.replace(Xinha.RE_Specials, \'\\\\$1\');\n -};\n -/** Identifies email addresses\n -* @type RegExp\n -*/\n -Xinha.RE_email = /^[_a-z\\d\\-\\.]{3,}@[_a-z\\d\\-]{2,}(\\.[_a-z\\d\\-]{2,})+$/i;\n -/** Identifies URLs\n -* @type RegExp\n -*/\n -Xinha.RE_url = /(https?:\\/\\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_\\-]{2,}(\\.[a-z0-9_\\-]{2,}){2,}(:[0-9]+)?(\\/\\S+)*)/i;\n -\n -\n -\n -/**\n - * This class creates an object that can be passed to the Xinha constructor as a parameter.\n - * Set the object\'s properties as you need to configure the editor (toolbar etc.)\n - * @version $Rev: 1263 $ $LastChangedDate: 2010-05-12 09:40:06 +1200 (Wed, 12 May 2010) $\n - * @constructor\n - */\n -Xinha.Config = function()\n -{\n - /** The svn revision number \n - * @type Number\n - */\n - this.version = Xinha.version.Revision;\n - \n - /** This property controls the width of the editor.<br />\n - * Allowed values are \'auto\', \'toolbar\' or a numeric value followed by "px".<br />\n - * <code>auto</code>: let Xinha choose the width to use.<br />\n - * <code>toolbar</code>: compute the width size from the toolbar width.<br />\n - * <code>numeric value</code>: forced width in pixels (\'600px\').<br />\n - * \n - * Default: <code>"auto"</code>\n - * @type String\n - */\n - this.width = "auto";\n - /** This property controls the height of the editor.<br />\n - * Allowed values are \'auto\' or a numeric value followed by px.<br />\n - * <code>"auto"</code>: let Xinha choose the height to use.<br />\n - * <code>numeric value</code>: forced height in pixels (\'200px\').<br />\n - * Default: <code>"auto"</code> \n - * @type String\n - */\n - this.height = "auto";\n -\n - /** Specifies whether the toolbar should be included\n - * in the size, or are extra to it. If false then it\'s recommended\n - * to have the size set as explicit pixel sizes (either in Xinha.Config or on your textarea)<br />\n - *\n - * Default: <code>true</code>\n - *\n - * @type Boolean\n - */\n - this.sizeIncludesBars = true;\n - /**\n - * Specifies whether the panels should be included\n - * in the size, or are extra to it. If false then it\'s recommended\n - * to have the size set as explicit pixel sizes (either in Xinha.Config or on your textarea)<br />\n - * \n - * Default: <code>true</code>\n - *\n - * @type Boolean\n - */\n - this.sizeIncludesPanels = true;\n -\n - /**\n - * each of the panels has a dimension, for the left/right it\'s the width\n - * for the top/bottom it\'s the height.\n - *\n - * WARNING: PANEL DIMENSIONS MUST BE SPECIFIED AS PIXEL WIDTHS<br />\n - *Default values: \n - *<pre>\n - *\t xinha_config.panel_dimensions =\n - * {\n - *\t left: \'200px\', // Width\n - *\t right: \'200px\',\n - *\t top: \'100px\', // Height\n - *\t bottom: \'100px\'\n - *\t }\n - *</pre>\n - * @type Object\n - */\n - this.panel_dimensions =\n - {\n - left: \'200px\', // Width\n - right: \'200px\',\n - top: \'100px\', // Height\n - bottom: \'100px\'\n - };\n -\n - /** To make the iframe width narrower than the toolbar width, e.g. to maintain\n - * the layout when editing a narrow column of text, set the next parameter (in pixels).<br />\n - *\n - * Default: <code>true</code>\n - *\n - * @type Integer|null\n - */\n - this.iframeWidth = null;\n - \n - /** Enable creation of the status bar?<br />\n - *\n - * Default: <code>true</code>\n - *\n - * @type Boolean \n - */\n - this.statusBar = true;\n -\n - /** Intercept ^V and use the Xinha paste command\n - * If false, then passes ^V through to browser editor widget, which is the only way it works without problems in Mozilla<br />\n - *\n - * Default: <code>false</code>\n - *\n - * @type Boolean\n - */\n - this.htmlareaPaste = false;\n - \n - /** <strong>Gecko only:</strong> Let the built-in routine for handling the <em>return</em> key decide if to enter <em>br</em> or <em>p</em> tags,\n - * or use a custom implementation.<br />\n - * For information about the rules applied by Gecko, <a href="http://www.mozilla.org/editor/rules.html">see Mozilla website</a> <br />\n - * Possible values are <em>built-in</em> or <em>best</em><br />\n - *\n - * Default: <code>"best"</code>\n - *\n - * @type String\n - */\n - this.mozParaHandler = \'best\'; \n - \n - /** This determines the method how the HTML output is generated.\n - * There are two choices:\n - * \n - *<table border="1">\n - * <tr>\n - * <td><em>DOMwalk</em></td>\n - * <td>This is the classic and proven method. It recusively traverses the DOM tree \n - * and builds the HTML string "from scratch". Tends to be a bit slow, especially in IE.</td>\n - * </tr>\n - * <tr>\n - * <td><em>TransformInnerHTML</em></td>\n - * <td>This method uses the JavaScript innerHTML property and relies on Regular Expressions to produce\n - * clean XHTML output. This method is much faster than the other one.</td>\n - * </tr>\n - * </table>\n - *\n - * Default: <code>"DOMwalk"</code>\n - *\n - * @type String\n - */\n - this.getHtmlMethod = \'DOMwalk\';\n - \n - /** Maximum size of the undo queue<br />\n - * Default: <code>20</code>\n - * @type Integer\n - */\n - this.undoSteps = 20;\n -\n - /** The time interval at which undo samples are taken<br />\n - * Default: <code>500</code> (1/2 sec)\n - * @type Integer milliseconds\n - */\n - this.undoTimeout = 500;\n -\n - /** Set this to true if you want to explicitly right-justify when setting the text direction to right-to-left<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.changeJustifyWithDirection = false;\n -\n - /** If true then Xinha will retrieve the full HTML, starting with the <HTML> tag.<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.fullPage = false;\n -\n - /** Raw style definitions included in the edited document<br />\n - * When a lot of inline style is used, perhaps it is wiser to use one or more external stylesheets.<br />\n - * To set tags P in red, H1 in blue andn A not underlined, we may do the following\n - *<pre>\n - * xinha_config.pageStyle =\n - * \'p { color:red; }\\n\' +\n - * \'h1 { color:bleu; }\\n\' +\n - * \'a {text-decoration:none; }\';\n - *</pre>\n - * Default: <code>""</code> (empty)\n - * @type String\n - */\n - this.pageStyle = "";\n -\n - /** Array of external stylesheets to load. (Reference these absolutely)<br />\n - * Example<br />\n - * <pre>xinha_config.pageStyleSheets = ["/css/myPagesStyleSheet.css","/css/anotherOne.css"];</pre>\n - * Default: <code>[]</code> (empty)\n - * @type Array\n - */\n - this.pageStyleSheets = [];\n -\n - // specify a base href for relative links\n - /** Specify a base href for relative links<br />\n - * ATTENTION: this does not work as expected and needs t be changed, see Ticket #961 <br />\n - * Default: <code>null</code>\n - * @type String|null\n - */\n - this.baseHref = null;\n -\n - /** If true, relative URLs (../) will be made absolute. \n - * When the editor is in different directory depth \n - * as the edited page relative image sources will break the display of your images.\n - * this fixes an issue where Mozilla converts the urls of images and links that are on the same server \n - * to relative ones (../) when dragging them around in the editor (Ticket #448)<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.expandRelativeUrl = true;\n - \n - /** We can strip the server part out of URL to make/leave them semi-absolute, reason for this\n - * is that the browsers will prefix the server to any relative links to make them absolute, \n - * which isn\'t what you want most the time.<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.stripBaseHref = true;\n -\n - /** We can strip the url of the editor page from named links (eg <a href="#top">...</a>) and links \n - * that consist only of URL parameters (eg <a href="?parameter=value">...</a>)\n - * reason for this is that browsers tend to prefixe location.href to any href that\n - * that don\'t have a full url<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.stripSelfNamedAnchors = true;\n -\n - /** In URLs all characters above ASCII value 127 have to be encoded using % codes<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.only7BitPrintablesInURLs = true;\n -\n - \n - /** If you are putting the HTML written in Xinha into an email you might want it to be 7-bit\n - * characters only. This config option will convert all characters consuming\n - * more than 7bits into UNICODE decimal entity references (actually it will convert anything\n - * below <space> (chr 20) except cr, lf and tab and above <tilde> (~, chr 7E))<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.sevenBitClean = false;\n -\n -\n - /** Sometimes we want to be able to replace some string in the html coming in and going out\n - * so that in the editor we use the "internal" string, and outside and in the source view\n - * we use the "external" string this is useful for say making special codes for\n - * your absolute links, your external string might be some special code, say "{server_url}"\n - * an you say that the internal represenattion of that should be http://your.server/<br />\n - * Example: <code>{ \'html_string\' : \'wysiwyg_string\' }</code><br />\n - * Default: <code>{}</code> (empty)\n - * @type Object\n - */\n - this.specialReplacements = {}; //{ \'html_string\' : \'wysiwyg_string\' }\n - \n - /** A filter function for the HTML used inside the editor<br />\n - * Default: function (html) { return html }\n - * \n - * @param {String} html The whole document\'s HTML content\n - * @return {String} The processed HTML \n - */\n - this.inwardHtml = function (html) { return html; };\n - \n - /** A filter function for the generated HTML<br />\n - * Default: function (html) { return html }\n - * \n - * @param {String} html The whole document\'s HTML content\n - * @return {String} The processed HTML \n - */\n - this.outwardHtml = function (html) { return html; };\n - \n - /** This setting determines whether or not the editor will be automatically activated and focused when the page loads. \n - * If the page contains only a single editor, autofocus can be set to true to focus it. \n - * Alternatively, if the page contains multiple editors, autofocus may be set to the ID of the text area of the editor to be focused. \n - * For example, the following setting would focus the editor attached to the text area whose ID is "myTextArea": \n - * <code>xinha_config.autofocus = "myTextArea";</code>\n - * Default: <code>false</code>\n - * @type Boolean|String\n - */\n - this.autofocus = false;\n - \n - /** Set to true if you want Word code to be cleaned upon Paste. This only works if \n - * you use the toolbr button to paste, not ^V. This means that due to the restrictions\n - * regarding pasting, this actually has no real effect in Mozilla <br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.killWordOnPaste = true;\n -\n - /** Enable the \'Target\' field in the Make Link dialog. Note that the target attribute is invalid in (X)HTML strict<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.makeLinkShowsTarget = true;\n -\n - /** CharSet of the iframe, default is the charset of the document\n - * @type String\n - */\n - this.charSet = (typeof document.characterSet != \'undefined\') ? document.characterSet : document.charset;\n -\n - /** Whether the edited document should be rendered in Quirksmode or Standard Compliant (Strict) Mode.<br />\n - * This is commonly known as the "doctype switch"<br />\n - * for details read here http://www.quirksmode.org/css/quirksmode.html\n - *\n - * Possible values:<br />\n - * true : Quirksmode is used<br />\n - * false : Strict mode is used<br />\n - * null (default): the mode of the document Xinha is in is used\n - * @type Boolean|null\n - */\n - this.browserQuirksMode = null;\n -\n - // URL-s\n - this.imgURL = "images/";\n - this.popupURL = "popups/";\n -\n - /** RegExp allowing to remove certain HTML tags when rendering the HTML.<br />\n - * Example: remove span and font tags\n - * <code>\n - * xinha_config.htmlRemoveTags = /span|font/;\n - * </code>\n - * Default: <code>null</code>\n - * @type RegExp|null\n - */\n - this.htmlRemoveTags = null;\n -\n - /** Turning this on will turn all "linebreak" and "separator" items in your toolbar into soft-breaks,\n - * this means that if the items between that item and the next linebreak/separator can\n - * fit on the same line as that which came before then they will, otherwise they will\n - * float down to the next line.\n -\n - * If you put a linebreak and separator next to each other, only the separator will\n - * take effect, this allows you to have one toolbar that works for both flowToolbars = true and false\n - * infact the toolbar below has been designed in this way, if flowToolbars is false then it will\n - * create explictly two lines (plus any others made by plugins) breaking at justifyleft, however if\n - * flowToolbars is false and your window is narrow enough then it will create more than one line\n - * even neater, if you resize the window the toolbars will reflow. <br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.flowToolbars = true;\n - \n - /** Set to center or right to change button alignment in toolbar\n - * @type String\n - */\n - this.toolbarAlign = "left";\n - \n - /** Set to true to display the font names in the toolbar font select list in their actual font.\n - * Note that this doesn\'t work in IE, but doesn\'t hurt anything either.\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.showFontStylesInToolbar = false;\n - \n - /** Set to true if you want the loading panel to show at startup<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.showLoading = false;\n - \n - /** Set to false if you want to allow JavaScript in the content, otherwise <script> tags are stripped out.<br />\n - * This currently only affects the "DOMwalk" getHtmlMethod.<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.stripScripts = true;\n -\n - /** See if the text just typed looks like a URL, or email address\n - * and link it appropriatly\n - * Note: Setting this option to false only affects Mozilla based browsers.\n - * In InternetExplorer this is native behaviour and cannot be turned off.<br />\n - * Default: <code>true</code>\n - * @type Boolean\n - */\n - this.convertUrlsToLinks = true;\n -\n -\n - /** Size of color picker cells<br />\n - * Use number + "px"<br />\n - * Default: <code>"6px"</code>\n - * @type String\n - */\n - this.colorPickerCellSize = \'6px\';\n - /** Granularity of color picker cells (number per column/row)<br />\n - * Default: <code>18</code>\n - * @type Integer\n - */\n - this.colorPickerGranularity = 18;\n - /** Position of color picker from toolbar button<br />\n - * Default: <code>"bottom,right"</code>\n - * @type String\n - */\n - this.colorPickerPosition = \'bottom,right\';\n - /** Set to true to show only websafe checkbox in picker<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.colorPickerWebSafe = false;\n - /** Number of recent colors to remember<br />\n - * Default: <code>20</code>\n - * @type Integer\n - */\n - this.colorPickerSaveColors = 20;\n -\n - /** Start up the editor in fullscreen mode<br />\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.fullScreen = false;\n - \n - /** You can tell the fullscreen mode to leave certain margins on each side.<br />\n - * The value is an array with the values for <code>[top,right,bottom,left]</code> in that order<br />\n - * Default: <code>[0,0,0,0]</code>\n - * @type Array\n - */\n - this.fullScreenMargins = [0,0,0,0];\n - \n - \n - /** Specify the method that is being used to calculate the editor\'s size<br/>\n - * when we return from fullscreen mode.\n - * There are two choices:\n - * \n - * <table border="1">\n - * <tr>\n - * <td><em>initSize</em></td>\n - * <td>Use the internal Xinha.initSize() method to calculate the editor\'s \n - * dimensions. This is suitable for most usecases.</td>\n - * </tr>\n - * <tr>\n - * <td><em>restore</em></td>\n - * <td>The editor\'s dimensions will be stored before going into fullscreen\n - * mode and restored when we return to normal mode, taking a possible\n - * window resize during fullscreen in account.</td>\n - * </tr>\n - * </table>\n - *\n - * Default: <code>"initSize"</code>\n - * @type String\n - */\n - this.fullScreenSizeDownMethod = \'initSize\';\n - \n - /** This array orders all buttons except plugin buttons in the toolbar. Plugin buttons typically look for one \n - * a certain button in the toolbar and place themselves next to it.\n - * Default value:\n - *<pre>\n - *xinha_config.toolbar =\n - * [\n - * ["popupeditor"],\n - * ["separator","formatblock","fontname","fontsize","bold","italic","underline","strikethrough"],\n - * ["separator","forecolor","hilitecolor","textindicator"],\n - * ["separator","subscript","superscript"],\n - * ["linebreak","separator","justifyleft","justifycenter","justifyright","justifyfull"],\n - * ["separator","insertorderedlist","insertunorderedlist","outdent","indent"],\n - * ["separator","inserthorizontalrule","createlink","insertimage","inserttable"],\n - * ["linebreak","separator","undo","redo","selectall","print"], (Xinha.is_gecko ? [] : ["cut","copy","paste","overwrite","saveas"]),\n - * ["separator","killword","clearfonts","removeformat","toggleborders","splitblock","lefttoright", "righttoleft"],\n - * ["separator","htmlmode","showhelp","about"]\n - * ];\n - *</pre>\n - * @type Array\n - */ \n - this.toolbar =\n - [\n - ["popupeditor"],\n - ["separator","formatblock","fontname","fontsize","bold","italic","underline","strikethrough"],\n - ["separator","forecolor","hilitecolor","textindicator"],\n - ["separator","subscript","superscript"],\n - ["linebreak","separator","justifyleft","justifycenter","justifyright","justifyfull"],\n - ["separator","insertorderedlist","insertunorderedlist","outdent","indent"],\n - ["separator","inserthorizontalrule","createlink","insertimage","inserttable"],\n - ["linebreak","separator","undo","redo","selectall","print"], (Xinha.is_gecko ? [] : ["cut","copy","paste","overwrite","saveas"]),\n - ["separator","killword","clearfonts","removeformat","toggleborders","splitblock","lefttoright", "righttoleft"],\n - ["separator","htmlmode","showhelp","about"]\n -];\n -\n - /** The fontnames listed in the fontname dropdown\n - * Default value:\n - *<pre>\n - *xinha_config.fontname =\n - *{\n - * "— font —" : \'\',\n - * "Arial" : \'arial,helvetica,sans-serif\',\n - * "Courier New" : \'courier new,courier,monospace\',\n - * "Georgia" : \'georgia,times new roman,times,serif\',\n - * "Tahoma" : \'tahoma,arial,helvetica,sans-serif\',\n - * "Times New Roman" : \'times new roman,times,serif\',\n - * "Verdana" : \'verdana,arial,helvetica,sans-serif\',\n - * "impact" : \'impact\',\n - * "WingDings" : \'wingdings\'\n - *};\n - *</pre>\n - * @type Object\n - */\n - this.fontname =\n - {\n - "— font —": "", // — is mdash\n - "Arial" :\t\'arial,helvetica,sans-serif\',\n - "Courier New" :\t\'courier new,courier,monospace\',\n - "Georgia" :\t\'georgia,times new roman,times,serif\',\n - "Tahoma" :\t\'tahoma,arial,helvetica,sans-serif\',\n - "Times New Roman" : \'times new roman,times,serif\',\n - "Verdana" :\t\'verdana,arial,helvetica,sans-serif\',\n - "impact" :\t\'impact\',\n - "WingDings" : \'wingdings\' \n - };\n -\n - /** The fontsizes listed in the fontsize dropdown\n - * Default value:\n - *<pre>\n - *xinha_config.fontsize =\n - *{\n - * "— size —": "",\n - * "1 (8 pt)" : "1",\n - * "2 (10 pt)": "2",\n - * "3 (12 pt)": "3",\n - * "4 (14 pt)": "4",\n - * "5 (18 pt)": "5",\n - * "6 (24 pt)": "6",\n - * "7 (36 pt)": "7"\n - *};\n - *</pre>\n - * @type Object\n - */\n - this.fontsize =\n - {\n - "— size —": "", // — is mdash\n - "1 (8 pt)" : "1",\n - "2 (10 pt)": "2",\n - "3 (12 pt)": "3",\n - "4 (14 pt)": "4",\n - "5 (18 pt)": "5",\n - "6 (24 pt)": "6",\n - "7 (36 pt)": "7"\n - };\n - /** The tags listed in the formatblock dropdown\n - * Default value:\n - *<pre>\n - *xinha_config.formatblock =\n - *{\n - * "— size —": "",\n - * "1 (8 pt)" : "1",\n - * "2 (10 pt)": "2",\n - * "3 (12 pt)": "3",\n - * "4 (14 pt)": "4",\n - * "5 (18 pt)": "5",\n - * "6 (24 pt)": "6",\n - * "7 (36 pt)": "7"\n - *};\n - *</pre>\n - * @type Object\n - */\n - this.formatblock =\n - {\n - "— format —": "", // — is mdash\n - "Heading 1": "h1",\n - "Heading 2": "h2",\n - "Heading 3": "h3",\n - "Heading 4": "h4",\n - "Heading 5": "h5",\n - "Heading 6": "h6",\n - "Normal" : "p",\n - "Address" : "address",\n - "Formatted": "pre"\n - };\n - \n - this.dialogOptions =\n - { \n - \'centered\' : true, //true: dialog is shown in the center the screen, false dialog is shown near the clicked toolbar button\n - \'greyout\':true, //true: when showing modal dialogs, the page behind the dialoge is greyed-out\n - \'closeOnEscape\':true\n - };\n - /** You can add functions to this object to be executed on specific events\n - * Example:\n - * <pre>\n - * xinha_config.Events.onKeyPress = function (event)\n - * {\n - * //do something \n - * return false;\n - * }\n - * </pre>\n - * Note that <em>this</em> inside the function refers to the respective Xinha object\n - * The possible function names are documented at <a href="http://trac.xinha.org/wiki/Documentation/EventHooks">http://trac.xinha.org/wiki/Documentation/EventHooks</a>\n - */\n - this.Events = {};\n - \n - /** ??\n - * Default: <code>{}</code>\n - * @type Object\n - */\n - this.customSelects = {};\n -\n - /** Switches on some debugging (only in execCommand() as far as I see at the moment)<br />\n - *\n - * Default: <code>false</code>\n - * @type Boolean\n - */\n - this.debug = false;\n -\n - this.URIs =\n - {\n - "blank": _editor_url + "popups/blank.html",\n - "link": _editor_url + "modules/CreateLink/link.html",\n - "insert_image": _editor_url + "modules/InsertImage/insert_image.html",\n - "insert_table": _editor_url + "modules/InsertTable/insert_table.html",\n - "select_color": _editor_url + "popups/select_color.html",\n - "help": _editor_url + "popups/editor_help.html"\n - };\n -\n - /** The button list conains the definitions of the toolbar button. Normally, there\'s nothing to change here :) \n - * <div style="white-space:pre">ADDING CUSTOM BUTTONS: please read below!\n - * format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]"\n - * - ID: unique ID for the button. If the button calls document.execCommand\n - *\t it\'s wise to give it the same name as the called command.\n - * - ACTION: function that gets called when the button is clicked.\n - * it has the following prototype:\n - * function(editor, buttonName)\n - * - editor is the Xinha object that triggered the call\n - * - buttonName is the ID of the clicked button\n - * These 2 parameters makes it possible for you to use the same\n - * handler for more Xinha objects or for more different buttons.\n - * - ToolTip: tooltip, will be translated below\n - * - Icon: path to an icon image file for the button\n - * OR; you can use an 18x18 block of a larger image by supllying an array\n - * that has three elemtents, the first is the larger image, the second is the column\n - * the third is the row. The ros and columns numbering starts at 0 but there is\n - * a header row and header column which have numbering to make life easier.\n - * See images/buttons_main.gif to see how it\'s done.\n - * - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time.</div>\n - * @type Object\n - */\n - this.btnList =\n - {\n - bold: [ "Bold", Xinha._lc({key: \'button_bold\', string: ["ed_buttons_main.png",3,2]}, \'Xinha\'), false, function(e) { e.execCommand("bold"); } ],\n - italic: [ "Italic", Xinha._lc({key: \'button_italic\', string: ["ed_buttons_main.png",2,2]}, \'Xinha\'), false, function(e) { e.execCommand("italic"); } ],\n - underline: [ "Underline", Xinha._lc({key: \'button_underline\', string: ["ed_buttons_main.png",2,0]}, \'Xinha\'), false, function(e) { e.execCommand("underline"); } ],\n - strikethrough: [ "Strikethrough", Xinha._lc({key: \'button_strikethrough\', string: ["ed_buttons_main.png",3,0]}, \'Xinha\'), false, function(e) { e.execCommand("strikethrough"); } ],\n - subscript: [ "Subscript", Xinha._lc({key: \'button_subscript\', string: ["ed_buttons_main.png",3,1]}, \'Xinha\'), false, function(e) { e.execCommand("subscript"); } ],\n - superscript: [ "Superscript", Xinha._lc({key: \'button_superscript\', string: ["ed_buttons_main.png",2,1]}, \'Xinha\'), false, function(e) { e.execCommand("superscript"); } ],\n -\n - justifyleft: [ "Justify Left", ["ed_buttons_main.png",0,0], false, function(e) { e.execCommand("justifyleft"); } ],\n - justifycenter: [ "Justify Center", ["ed_buttons_main.png",1,1], false, function(e){ e.execCommand("justifycenter"); } ],\n - justifyright: [ "Justify Right", ["ed_buttons_main.png",1,0], false, function(e) { e.execCommand("justifyright"); } ],\n - justifyfull: [ "Justify Full", ["ed_buttons_main.png",0,1], false, function(e) { e.execCommand("justifyfull"); } ],\n -\n - orderedlist: [ "Ordered List", ["ed_buttons_main.png",0,3], false, function(e) { e.execCommand("insertorderedlist"); } ],\n - unorderedlist: [ "Bulleted List", ["ed_buttons_main.png",1,3], false, function(e) { e.execCommand("insertunorderedlist"); } ],\n - insertorderedlist: [ "Ordered List", ["ed_buttons_main.png",0,3], false, function(e) { e.execCommand("insertorderedlist"); } ],\n - insertunorderedlist: [ "Bulleted List", ["ed_buttons_main.png",1,3], false, function(e) { e.execCommand("insertunorderedlist"); } ],\n -\n - outdent: [ "Decrease Indent", ["ed_buttons_main.png",1,2], false, function(e) { e.execCommand("outdent"); } ],\n - indent: [ "Increase Indent",["ed_buttons_main.png",0,2], false, function(e) { e.execCommand("indent"); } ],\n - forecolor: [ "Font Color", ["ed_buttons_main.png",3,3], false, function(e) { e.execCommand("forecolor"); } ],\n - hilitecolor: [ "Background Color", ["ed_buttons_main.png",2,3], false, function(e) { e.execCommand("hilitecolor"); } ],\n -\n - undo: [ "Undoes your last action", ["ed_buttons_main.png",4,2], false, function(e) { e.execCommand("undo"); } ],\n - redo: [ "Redoes your last action", ["ed_buttons_main.png",5,2], false, function(e) { e.execCommand("redo"); } ],\n - cut: [ "Cut selection", ["ed_buttons_main.png",5,0], false, function (e, cmd) { e.execCommand(cmd); } ],\n - copy: [ "Copy selection", ["ed_buttons_main.png",4,0], false, function (e, cmd) { e.execCommand(cmd); } ],\n - paste: [ "Paste from clipboard", ["ed_buttons_main.png",4,1], false, function (e, cmd) { e.execCommand(cmd); } ],\n - selectall: [ "Select all", ["ed_buttons_main.png",3,5], false, function(e) {e.execCommand("selectall");} ],\n -\n - inserthorizontalrule: [ "Horizontal Rule", ["ed_buttons_main.png",6,0], false, function(e) { e.execCommand("inserthorizontalrule"); } ],\n - createlink: [ "Insert Web Link", ["ed_buttons_main.png",6,1], false, function(e) { e._createLink(); } ],\n - insertimage: [ "Insert/Modify Image", ["ed_buttons_main.png",6,3], false, function(e) { e.execCommand("insertimage"); } ],\n - inserttable: [ "Insert Table", ["ed_buttons_main.png",6,2], false, function(e) { e.execCommand("inserttable"); } ],\n -\n - htmlmode: [ "Toggle HTML Source", ["ed_buttons_main.png",7,0], true, function(e) { e.execCommand("htmlmode"); } ],\n - toggleborders: [ "Toggle Borders", ["ed_buttons_main.png",7,2], false, function(e) { e._toggleBorders(); } ],\n - print: [ "Print document", ["ed_buttons_main.png",8,1], false, function(e) { if(Xinha.is_gecko) {e._iframe.contentWindow.print(); } else { e.focusEditor(); print(); } } ],\n - saveas: [ "Save as", ["ed_buttons_main.png",9,1], false, function(e) { e.execCommand("saveas",false,"noname.htm"); } ],\n - about: [ "About this editor", ["ed_buttons_main.png",8,2], true, function(e) { e.getPluginInstance("AboutBox").show(); } ],\n - showhelp: [ "Help using editor", ["ed_buttons_main.png",9,2], true, function(e) { e.execCommand("showhelp"); } ],\n -\n - splitblock: [ "Split Block", "ed_splitblock.gif", false, function(e) { e._splitBlock(); } ],\n - lefttoright: [ "Direction left to right", ["ed_buttons_main.png",0,2], false, function(e) { e.execCommand("lefttoright"); } ],\n - righttoleft: [ "Direction right to left", ["ed_buttons_main.png",1,2], false, function(e) { e.execCommand("righttoleft"); } ],\n - overwrite: [ "Insert/Overwrite", "ed_overwrite.gif", false, function(e) { e.execCommand("overwrite"); } ],\n -\n - wordclean: [ "MS Word Cleaner", ["ed_buttons_main.png",5,3], false, function(e) { e._wordClean(); } ],\n - clearfonts: [ "Clear Inline Font Specifications", ["ed_buttons_main.png",5,4], true, function(e) { e._clearFonts(); } ],\n - removeformat: [ "Remove formatting", ["ed_buttons_main.png",4,4], false, function(e) { e.execCommand("removeformat"); } ],\n - killword: [ "Clear MSOffice tags", ["ed_buttons_main.png",4,3], false, function(e) { e.execCommand("killword"); } ]\n - };\n - \n - /** A hash of double click handlers for the given elements, each element may have one or more double click handlers\n - * called in sequence. The element may contain a class selector ( a.somethingSpecial )\n - * \n - */\n - \n - this.dblclickList = \n - {\n - "a": [function(e, target) {e._createLink(target);}],\n - "img": [function(e, target) {e._insertImage(target);}]\n - };\n - \n - /** A container for additional icons that may be swapped within one button (like fullscreen)\n - * @private\n - */\n - this.iconList = \n - {\n - dialogCaption : _editor_url + \'images/xinha-small-icon.gif\',\n - wysiwygmode : [_editor_url + \'images/ed_buttons_main.png\',7,1]\n - };\n - // initialize tooltips from the I18N module and generate correct image path\n - for ( var i in this.btnList )\n - {\n - var btn = this.btnList[i];\n - // prevent iterating over wrong type\n - if ( typeof btn != \'object\' )\n - {\n - continue;\n - } \n - if ( typeof btn[1] != \'string\' )\n - {\n - btn[1][0] = _editor_url + this.imgURL + btn[1][0];\n - }\n - else\n - {\n - btn[1] = _editor_url + this.imgURL + btn[1];\n - }\n - btn[0] = Xinha._lc(btn[0]); //initialize tooltip\n - }\n -};\n -/** A plugin may require more than one icon for one button, this has to be registered in order to work with the iconsets (see FullScreen)\n - * \n - * @param {String} id\n - * @param {String|Array} icon definition like in registerButton\n - */\n -Xinha.Config.prototype.registerIcon = function (id, icon)\n -{\n - this.iconList[id] = icon;\n -};\n -/** ADDING CUSTOM BUTTONS\n -* ---------------------\n -*\n -*\n -* Example on how to add a custom button when you construct the Xinha:\n -*\n -* var editor = new Xinha("your_text_area_id");\n -* var cfg = editor.config; // this is the default configuration\n -* cfg.btnList["my-hilite"] =\n -*\t[ "Highlight selection", // tooltip\n -*\t "my_hilite.gif", // image\n -*\t false // disabled in text mode\n -*\t function(editor) { editor.surroundHTML(\'<span style="background:yellow">\', \'</span>\'); }, // action\n -*\t];\n -* cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar\n -*\n -* An alternate (also more convenient and recommended) way to\n -* accomplish this is to use the registerButton function below.\n -*/\n -/** Helper function: register a new button with the configuration. It can be\n - * called with all 5 arguments, or with only one (first one). When called with\n - * only one argument it must be an object with the following properties: id,\n - * tooltip, image, textMode, action.<br /> \n - * \n - * Examples:<br />\n - *<pre>\n - * config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...});\n - * config.registerButton({\n - * id : "my-hilite", // the ID of your button\n - * tooltip : "Hilite text", // the tooltip\n - * image : "my-hilite.gif", // image to be displayed in the toolbar\n - * textMode : false, // disabled in text mode\n - * action : function(editor) { // called when the button is clicked\n - * editor.surroundHTML(\'<span class="hilite">\', \'</span>\');\n - * },\n - * context : "p" // will be disabled if outside a <p> element\n - * });</pre>\n - */\n -Xinha.Config.prototype.registerButton = function(id, tooltip, image, textMode, action, context)\n -{\n - if ( typeof id == "string" )\n - {\n - this.btnList[id] = [ tooltip, image, textMode, action, context ];\n - }\n - else if ( typeof id == "object" )\n - {\n - this.btnList[id.id] = [ id.tooltip, id.image, id.textMode, id.action, id.context ];\n - }\n - else\n - {\n - alert("ERROR [Xinha.Config::registerButton]:\\ninvalid arguments");\n - return false;\n - }\n -};\n -\n -Xinha.prototype.registerPanel = function(side, object)\n -{\n - if ( !side )\n - {\n - side = \'right\';\n - }\n - this.setLoadingMessage(\'Register \' + side + \' panel \');\n - var panel = this.addPanel(side);\n - if ( object )\n - {\n - object.drawPanelIn(panel);\n - }\n -};\n -\n -/** The following helper function registers a dropdown box with the editor\n - * configuration. You still have to add it to the toolbar, same as with the\n - * buttons. Call it like this:\n - *\n - * FIXME: add example\n - */\n -Xinha.Config.prototype.registerDropdown = function(object)\n -{\n - // check for existing id\n -// if ( typeof this.customSelects[object.id] != "undefined" )\n -// {\n - // alert("WARNING [Xinha.Config::registerDropdown]:\\nA dropdown with the same ID already exists.");\n -// }\n -// if ( typeof this.btnList[object.id] != "undefined" )\n -// {\n - // alert("WARNING [Xinha.Config::registerDropdown]:\\nA button with the same ID already exists.");\n -// }\n - this.customSelects[object.id] = object;\n -};\n -\n -/** Call this function to remove some buttons/drop-down boxes from the toolbar.\n - * Pass as the only parameter a string containing button/drop-down names\n - * delimited by spaces. Note that the string should also begin with a space\n - * and end with a space. Example:\n - *\n - * config.hideSomeButtons(" fontname fontsize textindicator ");\n - *\n - * It\'s useful because it\'s easier to remove stuff from the defaul toolbar than\n - * create a brand new toolbar ;-)\n - */\n -Xinha.Config.prototype.hideSomeButtons = function(remove)\n -{\n - var toolbar = this.toolbar;\n - for ( var i = toolbar.length; --i >= 0; )\n - {\n - var line = toolbar[i];\n - for ( var j = line.length; --j >= 0; )\n - {\n - if ( remove.indexOf(" " + line[j] + " ") >= 0 )\n - {\n - var len = 1;\n - if ( /separator|space/.test(line[j + 1]) )\n - {\n - len = 2;\n - }\n - line.splice(j, len);\n - }\n - }\n - }\n -};\n -\n -/** Helper Function: add buttons/drop-downs boxes with title or separator to the toolbar\n - * if the buttons/drop-downs boxes doesn\'t allready exists.\n - * id: button or selectbox (as array with separator or title)\n - * where: button or selectbox (as array if the first is not found take the second and so on)\n - * position:\n - * -1 = insert button (id) one position before the button (where)\n - * 0 = replace button (where) by button (id)\n - * +1 = insert button (id) one position after button (where)\n - *\n - * cfg.addToolbarElement(["T[title]", "button_id", "separator"] , ["first_id","second_id"], -1);\n -*/\n -\n -Xinha.Config.prototype.addToolbarElement = function(id, where, position)\n -{\n - var toolbar = this.toolbar;\n - var a, i, j, o, sid;\n - var idIsArray = false;\n - var whereIsArray = false;\n - var whereLength = 0;\n - var whereJ = 0;\n - var whereI = 0;\n - var exists = false;\n - var found = false;\n - // check if id and where are arrys\n - if ( ( id && typeof id == "object" ) && ( id.constructor == Array ) )\n - {\n - idIsArray = true;\n - }\n - if ( ( where && typeof where == "object" ) && ( where.constructor == Array ) )\n - {\n - whereIsArray = true;\n - whereLength = where.length;\n -\t}\n -\n - if ( idIsArray ) //find the button/select box in input array\n - {\n - for ( i = 0; i < id.length; ++i )\n - {\n - if ( ( id[i] != "separator" ) && ( id[i].indexOf("T[") !== 0) )\n - {\n - sid = id[i];\n - }\n - }\n - }\n - else\n - {\n - sid = id;\n - }\n - \n - for ( i = 0; i < toolbar.length; ++i ) {\n - a = toolbar[i];\n - for ( j = 0; j < a.length; ++j ) {\n - // check if button/select box exists\n - if ( a[j] == sid ) {\n - return; // cancel to add elements if same button already exists\n - }\n - }\n - }\n - \n -\n - for ( i = 0; !found && i < toolbar.length; ++i )\n - {\n - a = toolbar[i];\n - for ( j = 0; !found && j < a.length; ++j )\n - {\n - if ( whereIsArray )\n - {\n - for ( o = 0; o < whereLength; ++o )\n - {\n - if ( a[j] == where[o] )\n - {\n - if ( o === 0 )\n - {\n - found = true;\n - j--;\n - break;\n - }\n - else\n - {\n - whereI = i;\n - whereJ = j;\n - whereLength = o;\n - }\n - }\n - }\n - }\n - else\n - {\n - // find the position to insert\n - if ( a[j] == where )\n - { \n - found = true;\n - break;\n - }\n - }\n - }\n - }\n -\n - //if check found any other as the first button\n - if ( !found && whereIsArray )\n - { \n - if ( where.length != whereLength )\n - {\n - j = whereJ;\n - a = toolbar[whereI];\n - found = true;\n - }\n - }\n - if ( found )\n - {\n - // replace the found button\n - if ( position === 0 )\n - {\n - if ( idIsArray)\n - {\n - a[j] = id[id.length-1];\n - for ( i = id.length-1; --i >= 0; )\n - {\n - a.splice(j, 0, id[i]);\n - }\n - }\n - else\n - {\n - a[j] = id;\n - }\n - }\n - else\n - { \n - // insert before/after the found button\n - if ( position < 0 )\n - {\n - j = j + position + 1; //correct position before\n - }\n - else if ( position > 0 )\n - {\n - j = j + position; //correct posion after\n - }\n - if ( idIsArray )\n - {\n - for ( i = id.length; --i >= 0; )\n - {\n - a.splice(j, 0, id[i]);\n - }\n - }\n - else\n - {\n - a.splice(j, 0, id);\n - }\n - }\n - }\n - else\n - {\n - // no button found\n - toolbar[0].splice(0, 0, "separator");\n - if ( idIsArray)\n - {\n - for ( i = id.length; --i >= 0; )\n - {\n - toolbar[0].splice(0, 0, id[i]);\n - }\n - }\n - else\n - {\n - toolbar[0].splice(0, 0, id);\n - }\n - }\n -};\n -/** Alias of Xinha.Config.prototype.hideSomeButtons()\n -* @type Function\n -*/\n -Xinha.Config.prototype.removeToolbarElement = Xinha.Config.prototype.hideSomeButtons;\n -\n -/** Helper function: replace all TEXTAREA-s in the document with Xinha-s. \n -* @param {Xinha.Config} optional config \n -*/\n -Xinha.replaceAll = function(config)\n -{\n - var tas = document.getElementsByTagName("textarea");\n - // @todo: weird syntax, doesnt help to read the code, doesnt obfuscate it and doesnt make it quicker, better rewrite this part\n - for ( var i = tas.length; i > 0; new Xinha(tas[--i], config).generate() )\n - {\n - // NOP\n - }\n -};\n -\n -/** Helper function: replaces the TEXTAREA with the given ID with Xinha. \n -* @param {string} id id of the textarea to replace \n -* @param {Xinha.Config} optional config \n -*/\n -Xinha.replace = function(id, config)\n -{\n - var ta = Xinha.getElementById("textarea", id);\n - return ta ? new Xinha(ta, config).generate() : null;\n -};\n - \n -/** Creates the toolbar and appends it to the _htmlarea\n -* @private\n -* @returns {DomNode} toolbar\n -*/\n -Xinha.prototype._createToolbar = function ()\n -{\n - this.setLoadingMessage(Xinha._lc(\'Create Toolbar\'));\n - var editor = this;\t// to access this in nested functions\n -\n - var toolbar = document.createElement("div");\n - // ._toolbar is for legacy, ._toolBar is better thanks.\n - this._toolBar = this._toolbar = toolbar;\n - toolbar.className = "toolbar"; \n - toolbar.align = this.config.toolbarAlign;\n - \n - Xinha.freeLater(this, \'_toolBar\');\n - Xinha.freeLater(this, \'_toolbar\');\n - \n - var tb_row = null;\n - var tb_objects = {};\n - this._toolbarObjects = tb_objects;\n -\n -\tthis._createToolbar1(editor, toolbar, tb_objects);\n -\t\n -\t// IE8 is totally retarded, if you click on a toolbar element (eg button)\n -\t// and it doesn\'t have unselectable="on", then it defocuses the editor losing the selection\n -\t// so nothing works. Particularly prevalent with TableOperations\n -\tfunction noselect(e)\n -\t{\n - if(e.tagName) e.unselectable = "on"; \n - if(e.childNodes)\n - {\n - for(var i = 0; i < e.childNodes.length; i++) if(e.tagName) noselect(e.childNodes(i));\n - }\n -\t}\n -\tif(Xinha.is_ie) noselect(toolbar);\n -\t\n -\t\n -\tthis._htmlArea.appendChild(toolbar); \n - \n - return toolbar;\n -};\n -\n -/** FIXME : function never used, can probably be removed from source\n -* @private\n -* @deprecated\n -*/\n -Xinha.prototype._setConfig = function(config)\n -{\n -\tthis.config = config;\n -};\n -/** FIXME: How can this be used??\n -* @private\n -*/\n -Xinha.prototype._rebuildToolbar = function()\n -{\n -\tthis._createToolbar1(this, this._toolbar, this._toolbarObjects);\n -\n - // We only want ONE editor at a time to be active\n - if ( Xinha._currentlyActiveEditor )\n - {\n - if ( Xinha._currentlyActiveEditor == this )\n - {\n - this.activateEditor();\n - }\n - }\n - else\n - {\n - this.disableToolbar();\n - }\n -};\n -\n -/**\n - * Create a break element to add in the toolbar\n - *\n - * @return {DomNode} HTML element to add\n - * @private\n - */\n -Xinha._createToolbarBreakingElement = function()\n -{\n - var brk = document.createElement(\'div\');\n - brk.style.height = \'1px\';\n - brk.style.width = \'1px\';\n - brk.style.lineHeight = \'1px\';\n - brk.style.fontSize = \'1px\';\n - brk.style.clear = \'both\';\n - return brk;\n -};\n -\n -\n -/** separate from previous createToolBar to allow dynamic change of toolbar\n - * @private\n - * @return {DomNode} toolbar\n - */\n -Xinha.prototype._createToolbar1 = function (editor, toolbar, tb_objects)\n -{\n - // We will clean out any existing toolbar elements.\n - while (toolbar.lastChild)\n - {\n - toolbar.removeChild(toolbar.lastChild);\n - }\n -\n - var tb_row;\n - // This shouldn\'t be necessary, but IE seems to float outside of the container\n - // when we float toolbar sections, so we have to clear:both here as well\n - // as at the end (which we do have to do).\n - if ( editor.config.flowToolbars )\n - {\n - toolbar.appendChild(Xinha._createToolbarBreakingElement());\n - }\n -\n - // creates a new line in the toolbar\n - function newLine()\n - {\n - if ( typeof tb_row != \'undefined\' && tb_row.childNodes.length === 0)\n - {\n - return;\n - }\n -\n - var table = document.createElement("table");\n - table.border = "0px";\n - table.cellSpacing = "0px";\n - table.cellPadding = "0px";\n - if ( editor.config.flowToolbars )\n - {\n - if ( Xinha.is_ie )\n - {\n - table.style.styleFloat = "left";\n - }\n - else\n - {\n - table.style.cssFloat = "left";\n - }\n - }\n -\n - toolbar.appendChild(table);\n - // TBODY is required for IE, otherwise you don\'t see anything\n - // in the TABLE.\n - var tb_body = document.createElement("tbody");\n - table.appendChild(tb_body);\n - tb_row = document.createElement("tr");\n - tb_body.appendChild(tb_row);\n -\n - table.className = \'toolbarRow\'; // meh, kinda.\n - } // END of function: newLine\n -\n - // init first line\n - newLine();\n -\n - // updates the state of a toolbar element. This function is member of\n - // a toolbar element object (unnamed objects created by createButton or\n - // createSelect functions below).\n - function setButtonStatus(id, newval)\n - {\n - var oldval = this[id];\n - var el = this.element;\n - if ( oldval != newval )\n - {\n - switch (id)\n - {\n - case "enabled":\n - if ( newval )\n - {\n - Xinha._removeClass(el, "buttonDisabled");\n - el.disabled = false;\n - }\n - else\n - {\n - Xinha._addClass(el, "buttonDisabled");\n - el.disabled = true;\n - }\n - break;\n - case "active":\n - if ( newval )\n - {\n - Xinha._addClass(el, "buttonPressed");\n - }\n - else\n - {\n - Xinha._removeClass(el, "buttonPressed");\n - }\n - break;\n - }\n - this[id] = newval;\n - }\n - } // END of function: setButtonStatus\n -\n - // this function will handle creation of combo boxes. Receives as\n - // parameter the name of a button as defined in the toolBar config.\n - // This function is called from createButton, above, if the given "txt"\n - // doesn\'t match a button.\n - function createSelect(txt)\n - {\n - var options = null;\n - var el = null;\n - var cmd = null;\n - var customSelects = editor.config.customSelects;\n - var context = null;\n - var tooltip = "";\n - switch (txt)\n - {\n - case "fontsize":\n - case "fontname":\n - case "formatblock":\n - // the following line retrieves the correct\n - // configuration option because the variable name\n - // inside the Config object is named the same as the\n - // button/select in the toolbar. For instance, if txt\n - // == "formatblock" we retrieve config.formatblock (or\n - // a different way to write it in JS is\n - // config["formatblock"].\n - options = editor.config[txt];\n - cmd = txt;\n - break;\n - default:\n - // try to fetch it from the list of registered selects\n - cmd = txt;\n - var dropdown = customSelects[cmd];\n - if ( typeof dropdown != "undefined" )\n - {\n - options = dropdown.options;\n - context = dropdown.context;\n - if ( typeof dropdown.tooltip != "undefined" )\n - {\n - tooltip = dropdown.tooltip;\n - }\n - }\n - else\n - {\n - alert("ERROR [createSelect]:\\nCan\'t find the requested dropdown definition");\n - }\n - break;\n - }\n - if ( options )\n - {\n - el = document.createElement("select");\n - el.title = tooltip;\n - el.style.width = \'auto\';\n - el.name = txt;\n - var obj =\n - {\n - name\t: txt, // field name\n - element : el,\t// the UI element (SELECT)\n - enabled : true, // is it enabled?\n - text\t: false, // enabled in text mode?\n - cmd\t: cmd, // command ID\n - state\t: setButtonStatus, // for changing state\n - context : context\n - };\n - \n - Xinha.freeLater(obj);\n - \n - tb_objects[txt] = obj;\n - \n - for ( var i in options )\n - {\n - // prevent iterating over wrong type\n - if ( typeof options[i] != \'string\' )\n - {\n - continue;\n - }\n - var op = document.createElement("option");\n - op.innerHTML = Xinha._lc(i);\n - op.value = options[i];\n - if (txt ==\'fontname\' && editor.config.showFontStylesInToolbar)\n - {\n - op.style.fontFamily = options[i];\n - }\n - el.appendChild(op);\n - }\n - Xinha._addEvent(el, "change", function () { editor._comboSelected(el, txt); } );\n - }\n - return el;\n - } // END of function: createSelect\n -\n - // appends a new button to toolbar\n - function createButton(txt)\n - {\n - // the element that will be created\n - var el, btn, obj = null;\n - switch (txt)\n - {\n - case "separator":\n - if ( editor.config.flowToolbars )\n - {\n - newLine();\n - }\n - el = document.createElement("div");\n - el.className = "separator";\n - break;\n - case "space":\n - el = document.createElement("div");\n - el.className = "space";\n - break;\n - case "linebreak":\n - newLine();\n - return false;\n - case "textindicator":\n - el = document.createElement("div");\n - el.appendChild(document.createTextNode("A"));\n - el.className = "indicator";\n - el.title = Xinha._lc("Current style");\n - obj =\n - {\n - name\t: txt, // the button name (i.e. \'bold\')\n - element : el, // the UI element (DIV)\n - enabled : true, // is it enabled?\n - active\t: false, // is it pressed?\n - text\t: false, // enabled in text mode?\n - cmd\t: "textindicator", // the command ID\n - state\t: setButtonStatus // for changing state\n - };\n - \n - Xinha.freeLater(obj);\n - \n - tb_objects[txt] = obj;\n - break;\n - default:\n - btn = editor.config.btnList[txt];\n - }\n - if ( !el && btn )\n - {\n - el = document.createElement("a");\n - el.style.display = \'block\';\n - el.href = \'javascript:void(0)\';\n - el.style.textDecoration = \'none\';\n - el.title = btn[0];\n - el.className = "button";\n - el.style.direction = "ltr";\n - // let\'s just pretend we have a button object, and\n - // assign all the needed information to it.\n - obj =\n - {\n - name : txt, // the button name (i.e. \'bold\')\n - element : el, // the UI element (DIV)\n - enabled : true, // is it enabled?\n - active : false, // is it pressed?\n - text : btn[2], // enabled in text mode?\n - cmd\t: btn[3], // the command ID\n - state\t: setButtonStatus, // for changing state\n - context : btn[4] || null // enabled in a certain context?\n - };\n - Xinha.freeLater(el);\n - Xinha.freeLater(obj);\n -\n - tb_objects[txt] = obj;\n -\n - // prevent drag&drop of the icon to content area\n - el.ondrag = function() { return false; };\n -\n - // handlers to emulate nice flat toolbar buttons\n - Xinha._addEvent(\n - el,\n - "mouseout",\n - function(ev)\n - {\n - if ( obj.enabled )\n - {\n - //Xinha._removeClass(el, "buttonHover");\n - Xinha._removeClass(el, "buttonActive");\n - if ( obj.active )\n - {\n - Xinha._addClass(el, "buttonPressed");\n - }\n - }\n - }\n - );\n -\n - Xinha._addEvent(\n - el,\n - "mousedown",\n - function(ev)\n - {\n - if ( obj.enabled )\n - {\n - Xinha._addClass(el, "buttonActive");\n - Xinha._removeClass(el, "buttonPressed");\n - Xinha._stopEvent(Xinha.is_ie ? window.event : ev);\n - }\n - }\n - );\n -\n - // when clicked, do the following:\n - Xinha._addEvent(\n - el,\n - "click",\n - function(ev)\n - {\n - ev = ev || window.event;\n - editor.btnClickEvent = {clientX : ev.clientX, clientY : ev.clientY};\n - if ( obj.enabled )\n - {\n - Xinha._removeClass(el, "buttonActive");\n - //Xinha._removeClass(el, "buttonHover");\n - if ( Xinha.is_gecko )\n - {\n - editor.activateEditor();\n - }\n - // We pass the event to the action so they can can use it to\n - // enhance the UI (e.g. respond to shift or ctrl-click)\n - obj.cmd(editor, obj.name, obj, ev);\n - Xinha._stopEvent(ev);\n - }\n - }\n - );\n -\n - var i_contain = Xinha.makeBtnImg(btn[1]);\n - var img = i_contain.firstChild;\n - Xinha.freeLater(i_contain);\n - Xinha.freeLater(img);\n - \n - el.appendChild(i_contain);\n -\n - obj.imgel = img; \n - obj.swapImage = function(newimg)\n - {\n - if ( typeof newimg != \'string\' )\n - {\n - img.src = newimg[0];\n - img.style.position = \'relative\';\n - img.style.top = newimg[2] ? (\'-\' + (18 * (newimg[2] + 1)) + \'px\') : \'-18px\';\n - img.style.left = newimg[1] ? (\'-\' + (18 * (newimg[1] + 1)) + \'px\') : \'-18px\';\n - }\n - else\n - {\n - obj.imgel.src = newimg;\n - img.style.top = \'0px\';\n - img.style.left = \'0px\';\n - }\n - };\n - \n - }\n - else if( !el )\n - {\n - el = createSelect(txt);\n - }\n -\n - return el;\n - }\n -\n - var first = true;\n - for ( var i = 0; i < this.config.toolbar.length; ++i )\n - {\n - if ( !first )\n - {\n - // createButton("linebreak");\n - }\n - else\n - {\n - first = false;\n - }\n - if ( this.config.toolbar[i] === null )\n - {\n - this.config.toolbar[i] = [\'separator\'];\n - }\n - var group = this.config.toolbar[i];\n -\n - for ( var j = 0; j < group.length; ++j )\n - {\n - var code = group[j];\n - var tb_cell;\n - if ( /^([IT])\\[(.*?)\\]/.test(code) )\n - {\n - // special case, create text label\n - var l7ed = RegExp.$1 == "I"; // localized?\n - var label = RegExp.$2;\n - if ( l7ed )\n - {\n - label = Xinha._lc(label);\n - }\n - tb_cell = document.createElement("td");\n - tb_row.appendChild(tb_cell);\n - tb_cell.className = "label";\n - tb_cell.innerHTML = label;\n - }\n - else if ( typeof code != \'function\' )\n - {\n - var tb_element = createButton(code);\n - if ( tb_element )\n - {\n - tb_cell = document.createElement("td");\n - tb_cell.className = \'toolbarElement\';\n - tb_row.appendChild(tb_cell);\n - tb_cell.appendChild(tb_element);\n - }\n - else if ( tb_element === null )\n - {\n - alert("FIXME: Unknown toolbar item: " + code);\n - }\n - }\n - }\n - }\n -\n - if ( editor.config.flowToolbars )\n - {\n - toolbar.appendChild(Xinha._createToolbarBreakingElement());\n - }\n -\n - return toolbar;\n -};\n -\n -/** creates a button (i.e. container element + image)\n - * @private\n - * @return {DomNode} conteainer element\n - */\n -Xinha.makeBtnImg = function(imgDef, doc)\n -{\n - if ( !doc )\n - {\n - doc = document;\n - }\n -\n - if ( !doc._xinhaImgCache )\n - {\n - doc._xinhaImgCache = {};\n - Xinha.freeLater(doc._xinhaImgCache);\n - }\n -\n - var i_contain = null;\n - if ( Xinha.is_ie && ( ( !doc.compatMode ) || ( doc.compatMode && doc.compatMode == "BackCompat" ) ) )\n - {\n - i_contain = doc.createElement(\'span\');\n - }\n - else\n - {\n - i_contain = doc.createElement(\'div\');\n - i_contain.style.position = \'relative\';\n - }\n -\n - i_contain.style.overflow = \'hidden\';\n - i_contain.style.width = "18px";\n - i_contain.style.height = "18px";\n - i_contain.className = \'buttonImageContainer\';\n -\n - var img = null;\n - if ( typeof imgDef == \'string\' )\n - {\n - if ( doc._xinhaImgCache[imgDef] )\n - {\n - img = doc._xinhaImgCache[imgDef].cloneNode();\n - }\n - else\n - {\n - if (Xinha.ie_version < 7 && /\\.png$/.test(imgDef[0]))\n - {\n - img = doc.createElement("span");\n - \n - img.style.display = \'block\';\n - img.style.width = \'18px\';\n - img.style.height = \'18px\';\n - img.style.filter = \'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="\'+imgDef+\'")\';\n -\t\timg.unselectable = \'on\';\n - }\n - else\n - {\n - img = doc.createElement("img");\n - img.src = imgDef;\n - }\n - }\n - }\n - else\n - {\n - if ( doc._xinhaImgCache[imgDef[0]] )\n - {\n - img = doc._xinhaImgCache[imgDef[0]].cloneNode();\n - }\n - else\n - {\n - if (Xinha.ie_version < 7 && /\\.png$/.test(imgDef[0]))\n - {\n - img = doc.createElement("span");\n - img.style.display = \'block\';\n - img.style.width = \'18px\';\n - img.style.height = \'18px\';\n - img.style.filter = \'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="\'+imgDef[0]+\'")\';\n -\t\timg.unselectable = \'on\';\n - }\n - else\n - {\n - img = doc.createElement("img");\n - img.src = imgDef[0];\n - }\n - img.style.position = \'relative\';\n - }\n - // @todo: Using 18 dont let us use a theme with its own icon toolbar height\n - // and width. Probably better to calculate this value 18\n - // var sizeIcon = img.width / nb_elements_per_image;\n - img.style.top = imgDef[2] ? (\'-\' + (18 * (imgDef[2] + 1)) + \'px\') : \'-18px\';\n - img.style.left = imgDef[1] ? (\'-\' + (18 * (imgDef[1] + 1)) + \'px\') : \'-18px\';\n - }\n - i_contain.appendChild(img);\n - return i_contain;\n -};\n -/** creates the status bar \n - * @private\n - * @return {DomNode} status bar\n - */\n -Xinha.prototype._createStatusBar = function()\n -{\n - // TODO: Move styling into separate stylesheet\n - this.setLoadingMessage(Xinha._lc(\'Create Statusbar\'));\n - var statusBar = document.createElement("div");\n - statusBar.style.position = "relative";\n - statusBar.className = "statusBar";\n - statusBar.style.width = "100%";\n - Xinha.freeLater(this, \'_statusBar\');\n -\n - var widgetContainer = document.createElement("div");\n - widgetContainer.className = "statusBarWidgetContainer";\n - widgetContainer.style.position = "absolute";\n - widgetContainer.style.right = "0";\n - widgetContainer.style.top = "0";\n - widgetContainer.style.padding = "3px 3px 3px 10px";\n - statusBar.appendChild(widgetContainer);\n -\n - // statusbar.appendChild(document.createTextNode(Xinha._lc("Path") + ": "));\n - // creates a holder for the path view\n - var statusBarTree = document.createElement("span");\n - statusBarTree.className = "statusBarTree";\n - statusBarTree.innerHTML = Xinha._lc("Path") + ": ";\n -\n - this._statusBarTree = statusBarTree;\n - Xinha.freeLater(this, \'_statusBarTree\');\n - statusBar.appendChild(statusBarTree);\n - var statusBarTextMode = document.createElement("span");\n - statusBarTextMode.innerHTML = Xinha.htmlEncode(Xinha._lc("You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG."));\n - statusBarTextMode.style.display = "none";\n -\n - this._statusBarTextMode = statusBarTextMode;\n - Xinha.freeLater(this, \'_statusBarTextMode\');\n - statusBar.appendChild(statusBarTextMode);\n -\n - statusBar.style.whiteSpace = "nowrap";\n -\n - var self = this;\n - this.notifyOn("before_resize", function(evt, size) {\n - self._statusBar.style.width = null;\n - });\n - this.notifyOn("resize", function(evt, size) {\n - // HACK! IE6 doesn\'t update the width properly when resizing if it\'s \n - // given in pixels, but does hide the overflow content correctly when \n - // using 100% as the width. (FF, Safari and IE7 all require fixed\n - // pixel widths to do the overflow hiding correctly.)\n - if (Xinha.is_ie && Xinha.ie_version == 6)\n - {\n - self._statusBar.style.width = "100%";\n - } \n - else\n - {\n - var width = size[\'width\'];\n - self._statusBar.style.width = width + "px";\n - }\n - });\n -\n - this.notifyOn("modechange", function(evt, mode) {\n - // Loop through all registered status bar items\n - // and show them only if they\'re turned on for\n - // the new mode.\n - for (var i in self._statusWidgets)\n - {\n - var widget = self._statusWidgets[i];\n - for (var index=0; index<widget.modes.length; index++)\n - {\n - if (widget.modes[index] == mode.mode)\n - {\n - var found = true;\n - }\n - }\n - if (typeof found == \'undefined\')\n - {\n - widget.block.style.display = "none"; \n - }\n - else\n - {\n - widget.block.style.display = "";\n - }\n - }\n - });\n -\n - if ( !this.config.statusBar )\n - {\n - // disable it...\n - statusBar.style.display = "none";\n - }\n - return statusBar;\n -};\n -\n -/** Registers and inserts a new block for a widget in the status bar\n - @param id unique string identifer for this block\n - @param modes list of modes this block should be shown in\n -\n - @returns reference to HTML element inserted into the status bar\n - */\n -Xinha.prototype.registerStatusWidget = function(id, modes)\n -{\n - modes = modes || [\'wysiwyg\'];\n - if (!this._statusWidgets)\n - {\n - this._statusWidgets = {};\n - }\n -\n - var block = document.createElement("div");\n - block.className = "statusBarWidget";\n - block = this._statusBar.firstChild.appendChild(block);\n -\n - var showWidget = false;\n - for (var i=0; i<modes.length; i++)\n - {\n - if (modes[i] == this._editMode)\n - {\n - showWidget = true;\n - }\n - }\n - block.style.display = showWidget == true ? "" : "none";\n -\n - this._statusWidgets[id] = {block: block, modes: modes};\n - return block;\n -};\n -\n -/** Creates the Xinha object and replaces the textarea with it. Loads required files.\n - * @returns {Boolean}\n - */\n -Xinha.prototype.generate = function ()\n -{\n - if ( !Xinha.isSupportedBrowser )\n - {\n - return;\n - }\n - \n - var i;\n - var editor = this; // we\'ll need "this" in some nested functions\n - var url;\n - var found = false;\n - var links = document.getElementsByTagName("link");\n -\n - if (!document.getElementById("XinhaCoreDesign"))\n - {\n - _editor_css = (typeof _editor_css == "string") ? _editor_css : "Xinha.css";\n - for(i = 0; i<links.length; i++)\n - {\n - if ( ( links[i].rel == "stylesheet" ) && ( links[i].href == _editor_url + _editor_css ) )\n - {\n - found = true;\n - }\n - }\n - if ( !found )\n - {\n - Xinha.loadStyle(_editor_css,null,"XinhaCoreDesign",true);\n - }\n - }\n - \n - if ( _editor_skin !== "" && !document.getElementById("XinhaSkin"))\n - {\n - found = false;\n - for(i = 0; i<links.length; i++)\n - {\n - if ( ( links[i].rel == "stylesheet" ) && ( links[i].href == _editor_url + \'skins/\' + _editor_skin + \'/skin.css\' ) )\n - {\n - found = true;\n - }\n - }\n - if ( !found )\n - {\n - Xinha.loadStyle(\'skins/\' + _editor_skin + \'/skin.css\',null,"XinhaSkin");\n - }\n - }\n - var callback = function() { editor.generate(); };\n - // Now load a specific browser plugin which will implement the above for us.\n - if (Xinha.is_ie)\n - {\n - url = _editor_url + \'modules/InternetExplorer/InternetExplorer.js\';\n - if ( !Xinha.loadPlugins([{plugin:"InternetExplorer",url:url}], callback ) )\n - { \n - return false;\n - }\n - if (!this.plugins.InternetExplorer)\n - {\n - editor._browserSpecificPlugin = editor.registerPlugin(\'InternetExplorer\');\n - }\n - }\n - else if (Xinha.is_webkit)\n - {\n - url = _editor_url + \'modules/WebKit/WebKit.js\';\n - if ( !Xinha.loadPlugins([{plugin:"WebKit",url:url}], callback ) )\n - {\n - return false;\n - }\n - if (!this.plugins.Webkit)\n - {\n - editor._browserSpecificPlugin = editor.registerPlugin(\'WebKit\');\n - }\n - }\n - else if (Xinha.is_opera)\n - {\n - url = _editor_url + \'modules/Opera/Opera.js\';\n - if ( !Xinha.loadPlugins([{plugin:"Opera",url:url}], callback ) )\n - { \n - return false;\n - }\n - if (!this.plugins.Opera)\n - {\n - editor._browserSpecificPlugin = editor.registerPlugin(\'Opera\');\n - }\n - }\n - else if (Xinha.is_gecko)\n - {\n - url = _editor_url + \'modules/Gecko/Gecko.js\';\n - if ( !Xinha.loadPlugins([{plugin:"Gecko",url:url}], callback ) )\n - { \n - return false;\n - }\n - if (!this.plugins.Gecko) \n - {\n - editor._browserSpecificPlugin = editor.registerPlugin(\'Gecko\');\n - }\n - }\n -\n - if ( typeof Dialog == \'undefined\' && !Xinha._loadback( _editor_url + \'modules/Dialogs/dialog.js\', callback, this ) )\n - { \n - return false;\n - }\n -\n - if ( typeof Xinha.Dialog == \'undefined\' && !Xinha._loadback( _editor_url + \'modules/Dialogs/XinhaDialog.js\' , callback, this ) )\n - { \n - return false;\n - }\n - \n - url = _editor_url + \'modules/FullScreen/full-screen.js\';\n - if ( !Xinha.loadPlugins([{plugin:"FullScreen",url:url}], callback ))\n - {\n - return false;\n - }\n - \n - url = _editor_url + \'modules/ColorPicker/ColorPicker.js\';\n - if ( !Xinha.loadPlugins([{plugin:"ColorPicker",url:url}], callback ) )\n - {\n - return false;\n - }\n - else if ( typeof Xinha.getPluginConstructor(\'ColorPicker\') != \'undefined\' && !this.plugins.colorPicker)\n - {\n - editor.registerPlugin(\'ColorPicker\');\n - }\n -\n - var toolbar = editor.config.toolbar;\n - for ( i = toolbar.length; --i >= 0; )\n - {\n - for ( var j = toolbar[i].length; --j >= 0; )\n - {\n - switch (toolbar[i][j])\n - {\n - case "popupeditor":\n - if (!this.plugins.FullScreen) \n - {\n - editor.registerPlugin(\'FullScreen\');\n - }\n - break;\n - case "insertimage":\n - url = _editor_url + \'modules/InsertImage/insert_image.js\';\n - if ( typeof Xinha.prototype._insertImage == \'undefined\' && !Xinha.loadPlugins([{plugin:"InsertImage",url:url}], callback ) )\n - {\n - return false;\n - }\n - else if ( typeof Xinha.getPluginConstructor(\'InsertImage\') != \'undefined\' && !this.plugins.InsertImage)\n - {\n - editor.registerPlugin(\'InsertImage\');\n - }\n - break;\n - case "createlink":\n - url = _editor_url + \'modules/CreateLink/link.js\';\n - if ( typeof Xinha.getPluginConstructor(\'Linker\') == \'undefined\' && !Xinha.loadPlugins([{plugin:"CreateLink",url:url}], callback ))\n - {\n - return false;\n - }\n - else if ( typeof Xinha.getPluginConstructor(\'CreateLink\') != \'undefined\' && !this.plugins.CreateLink) \n - {\n - editor.registerPlugin(\'CreateLink\');\n - }\n - break;\n - case "inserttable":\n - url = _editor_url + \'modules/InsertTable/insert_table.js\';\n - if ( !Xinha.loadPlugins([{plugin:"InsertTable",url:url}], callback ) )\n - {\n - return false;\n - }\n - else if ( typeof Xinha.getPluginConstructor(\'InsertTable\') != \'undefined\' && !this.plugins.InsertTable)\n - {\n - editor.registerPlugin(\'InsertTable\');\n - }\n - break;\n - case "about":\n - url = _editor_url + \'modules/AboutBox/AboutBox.js\';\n - if ( !Xinha.loadPlugins([{plugin:"AboutBox",url:url}], callback ) )\n - {\n - return false;\n - }\n - else if ( typeof Xinha.getPluginConstructor(\'AboutBox\') != \'undefined\' && !this.plugins.AboutBox)\n - {\n - editor.registerPlugin(\'AboutBox\');\n - }\n - break;\n - }\n - }\n - }\n -\n - // If this is gecko, set up the paragraph handling now\n - if ( Xinha.is_gecko && editor.config.mozParaHandler != \'built-in\' )\n - {\n - if ( !Xinha.loadPlugins([{plugin:"EnterParagraphs",url: _editor_url + \'modules/Gecko/paraHandlerBest.js\'}], callback ) )\n - {\n - return false;\n - }\n - if (!this.plugins.EnterParagraphs) \n - {\n - editor.registerPlugin(\'EnterParagraphs\');\n - }\n - }\n - var getHtmlMethodPlugin = this.config.getHtmlMethod == \'TransformInnerHTML\' ? _editor_url + \'modules/GetHtml/TransformInnerHTML.js\' : _editor_url + \'modules/GetHtml/DOMwalk.js\';\n -\n - if ( !Xinha.loadPlugins([{plugin:"GetHtmlImplementation",url:getHtmlMethodPlugin}], callback))\n - {\n - return false;\n - }\n - else if (!this.plugins.GetHtmlImplementation)\n - {\n - editor.registerPlugin(\'GetHtmlImplementation\');\n - }\n - function getTextContent(node)\n - {\n - return node.textContent || node.text;\n - }\n - if (_editor_skin)\n - {\n - this.skinInfo = {};\n - var skinXML = Xinha._geturlcontent(_editor_url + \'skins/\' + _editor_skin + \'/skin.xml\', true);\n - if (skinXML)\n - {\n - var meta = skinXML.getElementsByTagName(\'meta\');\n - for (i=0;i<meta.length;i++)\n - {\n - this.skinInfo[meta[i].getAttribute(\'name\')] = meta[i].getAttribute(\'value\');\n - }\n - var recommendedIcons = skinXML.getElementsByTagName(\'recommendedIcons\');\n - if (!_editor_icons && recommendedIcons.length && getTextContent(recommendedIcons[0]))\n - {\n - _editor_icons = getTextContent(recommendedIcons[0]);\n - }\n - }\n - }\n - if (_editor_icons) \n - {\n - var iconsXML = Xinha._geturlcontent(_editor_url + \'iconsets/\' + _editor_icons + \'/iconset.xml\', true);\n -\n - if (iconsXML)\n - {\n - var icons = iconsXML.getElementsByTagName(\'icon\');\n - var icon, id, path, type, x, y;\n -\n - for (i=0;i<icons.length;i++)\n - {\n - icon = icons[i];\n - id = icon.getAttribute(\'id\');\n - \n - if (icon.getElementsByTagName(_editor_lang).length)\n - {\n - icon = icon.getElementsByTagName(_editor_lang)[0];\n - }\n - else\n - {\n - icon = icon.getElementsByTagName(\'default\')[0];\n - }\n - path = getTextContent(icon.getElementsByTagName(\'path\')[0]);\n - path = (!/^\\//.test(path) ? _editor_url : \'\') + path;\n - type = icon.getAttribute(\'type\');\n - if (type == \'map\')\n - {\n - x = parseInt(getTextContent(icon.getElementsByTagName(\'x\')[0]), 10);\n - y = parseInt(getTextContent(icon.getElementsByTagName(\'y\')[0]), 10);\n - if (this.config.btnList[id]) \n - {\n - this.config.btnList[id][1] = [path, x, y];\n - }\n - if (this.config.iconList[id]) \n - {\n - this.config.iconList[id] = [path, x, y];\n - }\n - \n - }\n - else\n - {\n - if (this.config.btnList[id]) \n - {\n - this.config.btnList[id][1] = path;\n - }\n - if (this.config.iconList[id]) \n - {\n - this.config.iconList[id] = path;\n - }\n - }\n - }\n - }\n - }\n - \n - // create the editor framework, yah, table layout I know, but much easier\n - // to get it working correctly this way, sorry about that, patches welcome.\n - \n - this.setLoadingMessage(Xinha._lc(\'Generate Xinha framework\'));\n - \n - this._framework =\n - {\n - \'table\': document.createElement(\'table\'),\n - \'tbody\': document.createElement(\'tbody\'), // IE will not show the table if it doesn\'t have a tbody!\n - \'tb_row\': document.createElement(\'tr\'),\n - \'tb_cell\': document.createElement(\'td\'), // Toolbar\n -\n - \'tp_row\': document.createElement(\'tr\'),\n - \'tp_cell\': this._panels.top.container, // top panel\n -\n - \'ler_row\': document.createElement(\'tr\'),\n - \'lp_cell\': this._panels.left.container, // left panel\n - \'ed_cell\': document.createElement(\'td\'), // editor\n - \'rp_cell\': this._panels.right.container, // right panel\n -\n - \'bp_row\': document.createElement(\'tr\'),\n - \'bp_cell\': this._panels.bottom.container,// bottom panel\n -\n - \'sb_row\': document.createElement(\'tr\'),\n - \'sb_cell\': document.createElement(\'td\') // status bar\n -\n - };\n - Xinha.freeLater(this._framework);\n - \n - var fw = this._framework;\n - fw.table.border = "0";\n - fw.table.cellPadding = "0";\n - fw.table.cellSpacing = "0";\n -\n - fw.tb_row.style.verticalAlign = \'top\';\n - fw.tp_row.style.verticalAlign = \'top\';\n - fw.ler_row.style.verticalAlign= \'top\';\n - fw.bp_row.style.verticalAlign = \'top\';\n - fw.sb_row.style.verticalAlign = \'top\';\n - fw.ed_cell.style.position = \'relative\';\n -\n - // Put the cells in the rows set col & rowspans\n - // note that I\'ve set all these so that all panels are showing\n - // but they will be redone in sizeEditor() depending on which\n - // panels are shown. It\'s just here to clarify how the thing\n - // is put togethor.\n - fw.tb_row.appendChild(fw.tb_cell);\n - fw.tb_cell.colSpan = 3;\n -\n - fw.tp_row.appendChild(fw.tp_cell);\n - fw.tp_cell.colSpan = 3;\n -\n - fw.ler_row.appendChild(fw.lp_cell);\n - fw.ler_row.appendChild(fw.ed_cell);\n - fw.ler_row.appendChild(fw.rp_cell);\n -\n - fw.bp_row.appendChild(fw.bp_cell);\n - fw.bp_cell.colSpan = 3;\n -\n - fw.sb_row.appendChild(fw.sb_cell);\n - fw.sb_cell.colSpan = 3;\n -\n - // Put the rows in the table body\n - fw.tbody.appendChild(fw.tb_row); // Toolbar\n - fw.tbody.appendChild(fw.tp_row); // Left, Top, Right panels\n - fw.tbody.appendChild(fw.ler_row); // Editor/Textarea\n - fw.tbody.appendChild(fw.bp_row); // Bottom panel\n - fw.tbody.appendChild(fw.sb_row); // Statusbar\n -\n - // and body in the table\n - fw.table.appendChild(fw.tbody);\n -\n - var xinha = fw.table;\n - this._htmlArea = xinha;\n - Xinha.freeLater(this, \'_htmlArea\');\n - xinha.className = "htmlarea";\n -\n - // create the toolbar and put in the area\n - fw.tb_cell.appendChild( this._createToolbar() );\n -\n - // create the IFRAME & add to container\n - var iframe = document.createElement("iframe");\n - iframe.src = this.popupURL(editor.config.URIs.blank);\n - iframe.id = "XinhaIFrame_" + this._textArea.id;\n - fw.ed_cell.appendChild(iframe);\n - this._iframe = iframe;\n - this._iframe.className = \'xinha_iframe\';\n - Xinha.freeLater(this, \'_iframe\');\n - \n - // creates & appends the status bar\n - var statusbar = this._createStatusBar();\n - this._statusBar = fw.sb_cell.appendChild(statusbar);\n -\n -\n - // insert Xinha before the textarea.\n - var textarea = this._textArea;\n - textarea.parentNode.insertBefore(xinha, textarea);\n - textarea.className = \'xinha_textarea\';\n -\n - // extract the textarea and insert it into the xinha framework\n - Xinha.removeFromParent(textarea);\n - fw.ed_cell.appendChild(textarea);\n -\n - // if another editor is activated while this one is in text mode, toolbar is disabled \n - Xinha.addDom0Event(\n - this._textArea,\n - \'click\',\n - function()\n - {\n - \tif ( Xinha._currentlyActiveEditor != this)\n - \t{\n - \t editor.updateToolbar();\n - \t}\n - return true;\n - });\n - \n - // Set up event listeners for saving the iframe content to the textarea\n - if ( textarea.form )\n - {\n - // onsubmit get the Xinha content and update original textarea.\n - Xinha.prependDom0Event(\n - this._textArea.form,\n - \'submit\',\n - function()\n - {\n - editor.firePluginEvent(\'onBeforeSubmit\');\n - editor._textArea.value = editor.outwardHtml(editor.getHTML());\n - return true;\n - }\n - );\n -\n - var initialTAContent = textarea.value;\n -\n - // onreset revert the Xinha content to the textarea content\n - Xinha.prependDom0Event(\n - this._textArea.form,\n - \'reset\',\n - function()\n - {\n - editor.setHTML(editor.inwardHtml(initialTAContent));\n - editor.updateToolbar();\n - return true;\n - }\n - );\n -\n - // attach onsubmit handler to form.submit()\n - // note: catch error in IE if any form element has id="submit"\n - if ( !textarea.form.xinha_submit )\n - {\n - try \n - {\n - textarea.form.xinha_submit = textarea.form.submit;\n - textarea.form.submit = function() \n - {\n - this.onsubmit();\n - this.xinha_submit();\n - };\n - } catch(ex) {}\n - }\n - }\n -\n - // add a handler for the "back/forward" case -- on body.unload we save\n - // the HTML content into the original textarea and restore it in its place.\n - // apparently this does not work in IE?\n - Xinha.prependDom0Event(\n - window,\n - \'unload\',\n - function()\n - {\n - editor.firePluginEvent(\'onBeforeUnload\');\n - textarea.value = editor.outwardHtml(editor.getHTML());\n - if (!Xinha.is_ie)\n - {\n - xinha.parentNode.replaceChild(textarea,xinha);\n - }\n - return true;\n - }\n - );\n -\n - // Hide textarea\n - textarea.style.display = "none";\n -\n - // Initalize size\n - editor.initSize();\n - this.setLoadingMessage(Xinha._lc(\'Finishing\'));\n - // Add an event to initialize the iframe once loaded.\n - editor._iframeLoadDone = false;\n - if (Xinha.is_opera) \n - {\n - editor.initIframe();\n - }\n - else \n - {\n - Xinha._addEvent(\n - this._iframe,\n - \'load\',\n - function(e)\n - {\n - if ( !editor._iframeLoadDone )\n - {\n - editor._iframeLoadDone = true;\n - editor.initIframe();\n - }\n - return true;\n - }\n - );\n - }\n -};\n -\n -/**\n - * Size the editor according to the INITIAL sizing information.\n - * config.width\n - * The width may be set via three ways\n - * auto = the width is inherited from the original textarea\n - * toolbar = the width is set to be the same size as the toolbar\n - * <set size> = the width is an explicit size (any CSS measurement, eg 100em should be fine)\n - *\n - * config.height\n - * auto = the height is inherited from the original textarea\n - * <set size> = an explicit size measurement (again, CSS measurements)\n - *\n - * config.sizeIncludesBars\n - * true = the tool & status bars will appear inside the width & height confines\n - * false = the tool & status bars will appear outside the width & height confines\n - *\n - * @private\n - */\n -\n -Xinha.prototype.initSize = function()\n -{\n - this.setLoadingMessage(Xinha._lc(\'Init editor size\'));\n - var editor = this;\n - var width = null;\n - var height = null;\n -\n - switch ( this.config.width )\n - {\n - case \'auto\':\n - width = this._initial_ta_size.w;\n - break;\n -\n - case \'toolbar\':\n - width = this._toolBar.offsetWidth + \'px\';\n - break;\n -\n - default :\n - // @todo: check if this is better :\n - // width = (parseInt(this.config.width, 10) == this.config.width)? this.config.width + \'px\' : this.config.width;\n - width = /[^0-9]/.test(this.config.width) ? this.config.width : this.config.width + \'px\';\n - break;\n - }\n - // @todo: check if this is better :\n - // height = (parseInt(this.config.height, 10) == this.config.height)? this.config.height + \'px\' : this.config.height;\n - height = this.config.height == \'auto\' ? this._initial_ta_size.h : /[^0-9]/.test(this.config.height) ? this.config.height : this.config.height + \'px\';\n - \n - this.sizeEditor(width, height, this.config.sizeIncludesBars, this.config.sizeIncludesPanels);\n -\n - // why can\'t we use the following line instead ?\n -// this.notifyOn(\'panel_change\',this.sizeEditor);\n - this.notifyOn(\'panel_change\',function() { editor.sizeEditor(); });\n -};\n -\n -/**\n - * Size the editor to a specific size, or just refresh the size (when window resizes for example)\n - * @param {string} width optional width (CSS specification)\n - * @param {string} height optional height (CSS specification)\n - * @param {Boolean} includingBars optional to indicate if the size should include or exclude tool & status bars\n - * @param {Boolean} includingPanels optional to indicate if the size should include or exclude panels\n - */\n -Xinha.prototype.sizeEditor = function(width, height, includingBars, includingPanels)\n -{\n - if (this._risizing) \n - {\n - return;\n - }\n - this._risizing = true;\n - \n - var framework = this._framework;\n - \n - this.notifyOf(\'before_resize\', {width:width, height:height});\n - this.firePluginEvent(\'onBeforeResize\', width, height);\n - // We need to set the iframe & textarea to 100% height so that the htmlarea\n - // isn\'t "pushed out" when we get it\'s height, so we can change them later.\n - this._iframe.style.height = \'100%\';\n - //here 100% can lead to an effect that the editor is considerably higher in text mode\n - this._textArea.style.height = \'1px\';\n - \n - this._iframe.style.width = \'0px\';\n - this._textArea.style.width = \'0px\';\n -\n - if ( includingBars !== null )\n - {\n - this._htmlArea.sizeIncludesToolbars = includingBars;\n - }\n - if ( includingPanels !== null )\n - {\n - this._htmlArea.sizeIncludesPanels = includingPanels;\n - }\n -\n - if ( width )\n - {\n - this._htmlArea.style.width = width;\n - if ( !this._htmlArea.sizeIncludesPanels )\n - {\n - // Need to add some for l & r panels\n - var rPanel = this._panels.right;\n - if ( rPanel.on && rPanel.panels.length && Xinha.hasDisplayedChildren(rPanel.div) )\n - {\n - this._htmlArea.style.width = (this._htmlArea.offsetWidth + parseInt(this.config.panel_dimensions.right, 10)) + \'px\';\n - }\n -\n - var lPanel = this._panels.left;\n - if ( lPanel.on && lPanel.panels.length && Xinha.hasDisplayedChildren(lPanel.div) )\n - {\n - this._htmlArea.style.width = (this._htmlArea.offsetWidth + parseInt(this.config.panel_dimensions.left, 10)) + \'px\';\n - }\n - }\n - }\n -\n - if ( height )\n - {\n - this._htmlArea.style.height = height;\n - if ( !this._htmlArea.sizeIncludesToolbars )\n - {\n - // Need to add some for toolbars\n - this._htmlArea.style.height = (this._htmlArea.offsetHeight + this._toolbar.offsetHeight + this._statusBar.offsetHeight) + \'px\';\n - }\n -\n - if ( !this._htmlArea.sizeIncludesPanels )\n - {\n - // Need to add some for t & b panels\n - var tPanel = this._panels.top;\n - if ( tPanel.on && tPanel.panels.length && Xinha.hasDisplayedChildren(tPanel.div) )\n - {\n - this._htmlArea.style.height = (this._htmlArea.offsetHeight + parseInt(this.config.panel_dimensions.top, 10)) + \'px\';\n - }\n -\n - var bPanel = this._panels.bottom;\n - if ( bPanel.on && bPanel.panels.length && Xinha.hasDisplayedChildren(bPanel.div) )\n - {\n - this._htmlArea.style.height = (this._htmlArea.offsetHeight + parseInt(this.config.panel_dimensions.bottom, 10)) + \'px\';\n - }\n - }\n - }\n -\n - // At this point we have this._htmlArea.style.width & this._htmlArea.style.height\n - // which are the size for the OUTER editor area, including toolbars and panels\n - // now we size the INNER area and position stuff in the right places.\n - width = this._htmlArea.offsetWidth;\n - height = this._htmlArea.offsetHeight;\n -\n - // Set colspan for toolbar, and statusbar, rowspan for left & right panels, and insert panels to be displayed\n - // into thier rows\n - var panels = this._panels;\n - var editor = this;\n - var col_span = 1;\n -\n - function panel_is_alive(pan)\n - {\n - if ( panels[pan].on && panels[pan].panels.length && Xinha.hasDisplayedChildren(panels[pan].container) )\n - {\n - panels[pan].container.style.display = \'\';\n - return true;\n - }\n - // Otherwise make sure it\'s been removed from the framework\n - else\n - {\n - panels[pan].container.style.display=\'none\';\n - return false;\n - }\n - }\n -\n - if ( panel_is_alive(\'left\') )\n - {\n - col_span += 1; \n - }\n -\n -// if ( panel_is_alive(\'top\') )\n -// {\n - // NOP\n -// }\n -\n - if ( panel_is_alive(\'right\') )\n - {\n - col_span += 1;\n - }\n -\n -// if ( panel_is_alive(\'bottom\') )\n -// {\n - // NOP\n -// }\n -\n - framework.tb_cell.colSpan = col_span;\n - framework.tp_cell.colSpan = col_span;\n - framework.bp_cell.colSpan = col_span;\n - framework.sb_cell.colSpan = col_span;\n -\n - // Put in the panel rows, top panel goes above editor row\n - if ( !framework.tp_row.childNodes.length )\n - {\n - Xinha.removeFromParent(framework.tp_row);\n - }\n - else\n - {\n - if ( !Xinha.hasParentNode(framework.tp_row) )\n - {\n - framework.tbody.insertBefore(framework.tp_row, framework.ler_row);\n - }\n - }\n -\n - // bp goes after the editor\n - if ( !framework.bp_row.childNodes.length )\n - {\n - Xinha.removeFromParent(framework.bp_row);\n - }\n - else\n - {\n - if ( !Xinha.hasParentNode(framework.bp_row) )\n - {\n - framework.tbody.insertBefore(framework.bp_row, framework.ler_row.nextSibling);\n - }\n - }\n -\n - // finally if the statusbar is on, insert it\n - if ( !this.config.statusBar )\n - {\n - Xinha.removeFromParent(framework.sb_row);\n - }\n - else\n - {\n - if ( !Xinha.hasParentNode(framework.sb_row) )\n - {\n - framework.table.appendChild(framework.sb_row);\n - }\n - }\n -\n - // Size and set colspans, link up the framework\n - framework.lp_cell.style.width = this.config.panel_dimensions.left;\n - framework.rp_cell.style.width = this.config.panel_dimensions.right;\n - framework.tp_cell.style.height = this.config.panel_dimensions.top;\n - framework.bp_cell.style.height = this.config.panel_dimensions.bottom;\n - framework.tb_cell.style.height = this._toolBar.offsetHeight + \'px\';\n - framework.sb_cell.style.height = this._statusBar.offsetHeight + \'px\';\n -\n - var edcellheight = height - this._toolBar.offsetHeight - this._statusBar.offsetHeight;\n - if ( panel_is_alive(\'top\') )\n - {\n - edcellheight -= parseInt(this.config.panel_dimensions.top, 10);\n - }\n - if ( panel_is_alive(\'bottom\') )\n - {\n - edcellheight -= parseInt(this.config.panel_dimensions.bottom, 10);\n - }\n - this._iframe.style.height = edcellheight + \'px\'; \n - \n - var edcellwidth = width;\n - if ( panel_is_alive(\'left\') )\n - {\n - edcellwidth -= parseInt(this.config.panel_dimensions.left, 10);\n - }\n - if ( panel_is_alive(\'right\') )\n - {\n - edcellwidth -= parseInt(this.config.panel_dimensions.right, 10); \n - }\n - var iframeWidth = this.config.iframeWidth ? parseInt(this.config.iframeWidth,10) : null; \n - this._iframe.style.width = (iframeWidth && iframeWidth < edcellwidth) ? iframeWidth + "px": edcellwidth + "px"; \n -\n - this._textArea.style.height = this._iframe.style.height;\n - this._textArea.style.width = this._iframe.style.width;\n - \n - this.notifyOf(\'resize\', {width:this._htmlArea.offsetWidth, height:this._htmlArea.offsetHeight});\n - this.firePluginEvent(\'onResize\',this._htmlArea.offsetWidth, this._htmlArea.offsetWidth);\n - this._risizing = false;\n -};\n -/** FIXME: Never used, what is this for? \n -* @param {string} side \n -* @param {Object}\n -*/\n -Xinha.prototype.registerPanel = function(side, object)\n -{\n - if ( !side )\n - {\n - side = \'right\';\n - }\n - this.setLoadingMessage(\'Register \' + side + \' panel \');\n - var panel = this.addPanel(side);\n - if ( object )\n - {\n - object.drawPanelIn(panel);\n - }\n -};\n -/** Creates a panel in the panel container on the specified side\n -* @param {String} side the panel container to which the new panel will be added<br />\n -*\t\t\t\t\t\t\t\t\tPossible values are: "right","left","top","bottom"\n -* @returns {DomNode} Panel div\n -*/\n -Xinha.prototype.addPanel = function(side)\n -{\n - var div = document.createElement(\'div\');\n - div.side = side;\n - if ( side == \'left\' || side == \'right\' )\n - {\n - div.style.width = this.config.panel_dimensions[side];\n - if (this._iframe) \n - {\n - div.style.height = this._iframe.style.height;\n - }\n - }\n - Xinha.addClasses(div, \'panel\');\n - this._panels[side].panels.push(div);\n - this._panels[side].div.appendChild(div);\n -\n - this.notifyOf(\'panel_change\', {\'action\':\'add\',\'panel\':div});\n - this.firePluginEvent(\'onPanelChange\',\'add\',div);\n - return div;\n -};\n -/** Removes a panel\n -* @param {DomNode} panel object as returned by Xinha.prototype.addPanel()\n -*/\n -Xinha.prototype.removePanel = function(panel)\n -{\n - this._panels[panel.side].div.removeChild(panel);\n - var clean = [];\n - for ( var i = 0; i < this._panels[panel.side].panels.length; i++ )\n - {\n - if ( this._panels[panel.side].panels[i] != panel )\n - {\n - clean.push(this._panels[panel.side].panels[i]);\n - }\n - }\n - this._panels[panel.side].panels = clean;\n - this.notifyOf(\'panel_change\', {\'action\':\'remove\',\'panel\':panel});\n - this.firePluginEvent(\'onPanelChange\',\'remove\',panel);\n -};\n -/** Hides a panel\n -* @param {DomNode} panel object as returned by Xinha.prototype.addPanel()\n -*/\n -Xinha.prototype.hidePanel = function(panel)\n -{\n - if ( panel && panel.style.display != \'none\' )\n - {\n - try { var pos = this.scrollPos(this._iframe.contentWindow); } catch(e) { }\n - panel.style.display = \'none\';\n - this.notifyOf(\'panel_change\', {\'action\':\'hide\',\'panel\':panel});\n - this.firePluginEvent(\'onPanelChange\',\'hide\',panel);\n - try { this._iframe.contentWindow.scrollTo(pos.x,pos.y); } catch(e) { }\n - }\n -};\n -/** Shows a panel\n -* @param {DomNode} panel object as returned by Xinha.prototype.addPanel()\n -*/\n -Xinha.prototype.showPanel = function(panel)\n -{\n - if ( panel && panel.style.display == \'none\' )\n - {\n - try { var pos = this.scrollPos(this._iframe.contentWindow); } catch(e) {}\n - panel.style.display = \'\';\n - this.notifyOf(\'panel_change\', {\'action\':\'show\',\'panel\':panel});\n - this.firePluginEvent(\'onPanelChange\',\'show\',panel);\n - try { this._iframe.contentWindow.scrollTo(pos.x,pos.y); } catch(e) { }\n - }\n -};\n -/** Hides the panel(s) on one or more sides\n -* @param {Array} sides the sides on which the panels shall be hidden\n -*/\n -Xinha.prototype.hidePanels = function(sides)\n -{\n - if ( typeof sides == \'undefined\' )\n - {\n - sides = [\'left\',\'right\',\'top\',\'bottom\'];\n - }\n -\n - var reShow = [];\n - for ( var i = 0; i < sides.length;i++ )\n - {\n - if ( this._panels[sides[i]].on )\n - {\n - reShow.push(sides[i]);\n - this._panels[sides[i]].on = false;\n - }\n - }\n - this.notifyOf(\'panel_change\', {\'action\':\'multi_hide\',\'sides\':sides});\n - this.firePluginEvent(\'onPanelChange\',\'multi_hide\',sides);\n -};\n -/** Shows the panel(s) on one or more sides\n -* @param {Array} sides the sides on which the panels shall be hidden\n -*/\n -Xinha.prototype.showPanels = function(sides)\n -{\n - if ( typeof sides == \'undefined\' )\n - {\n - sides = [\'left\',\'right\',\'top\',\'bottom\'];\n - }\n -\n - var reHide = [];\n - for ( var i = 0; i < sides.length; i++ )\n - {\n - if ( !this._panels[sides[i]].on )\n - {\n - reHide.push(sides[i]);\n - this._panels[sides[i]].on = true;\n - }\n - }\n - this.notifyOf(\'panel_change\', {\'action\':\'multi_show\',\'sides\':sides});\n - this.firePluginEvent(\'onPanelChange\',\'multi_show\',sides);\n -};\n -/** Returns an array containig all properties that are set in an object\n -* @param {Object} obj\n -* @returns {Array}\n -*/\n -Xinha.objectProperties = function(obj)\n -{\n - var props = [];\n - for ( var x in obj )\n - {\n - props[props.length] = x;\n - }\n - return props;\n -};\n -\n -/** Checks if editor is active\n - *<br />\n - * EDITOR ACTIVATION NOTES:<br />\n - * when a page has multiple Xinha editors, ONLY ONE should be activated at any time (this is mostly to\n - * work around a bug in Mozilla, but also makes some sense). No editor should be activated or focused\n - * automatically until at least one editor has been activated through user action (by mouse-clicking in\n - * the editor).\n - * @private\n - * @returns {Boolean}\n - */\n -Xinha.prototype.editorIsActivated = function()\n -{\n - try\n - {\n - return Xinha.is_designMode ? this._doc.designMode == \'on\' : this._doc.body.contentEditable;\n - }\n - catch (ex)\n - {\n - return false;\n - }\n -};\n -/** We need to know that at least one editor on the page has been activated\n -* this is because we will not focus any editor until an editor has been activated\n -* @private\n -* @type {Boolean}\n -*/\n -Xinha._someEditorHasBeenActivated = false;\n -/** Stores a reference to the currently active editor\n -* @private\n -* @type {Xinha}\n -*/\n -Xinha._currentlyActiveEditor = null;\n -/** Enables one editor for editing, e.g. by a click in the editing area or after it has been \n - * deactivated programmatically before \n - * @private\n - * @returns {Boolean}\n - */\n -Xinha.prototype.activateEditor = function()\n -{\n - if (this.currentModal) \n - {\n - return;\n - }\n - // We only want ONE editor at a time to be active\n - if ( Xinha._currentlyActiveEditor )\n - {\n - if ( Xinha._currentlyActiveEditor == this )\n - {\n - return true;\n - }\n - Xinha._currentlyActiveEditor.deactivateEditor();\n - }\n -\n - if ( Xinha.is_designMode && this._doc.designMode != \'on\' )\n - {\n - try\n - {\n - // cannot set design mode if no display\n - if ( this._iframe.style.display == \'none\' )\n - {\n - this._iframe.style.display = \'\';\n - this._doc.designMode = \'on\';\n - this._iframe.style.display = \'none\';\n - }\n - else\n - {\n - this._doc.designMode = \'on\';\n - }\n -\n - // Opera loses some of it\'s event listeners when the designMode is set to on.\n -\t // the true just shortcuts the method to only set some listeners.\n - if(Xinha.is_opera) this.setEditorEvents(true);\n -\n - } catch (ex) {}\n - }\n - else if ( Xinha.is_ie&& this._doc.body.contentEditable !== true )\n - {\n - this._doc.body.contentEditable = true;\n - }\n -\n - Xinha._someEditorHasBeenActivated = true;\n - Xinha._currentlyActiveEditor = this;\n -\n - var editor = this;\n - this.enableToolbar();\n -};\n -/** Disables the editor \n - * @private\n - */\n -Xinha.prototype.deactivateEditor = function()\n -{\n - // If the editor isn\'t active then the user shouldn\'t use the toolbar\n - this.disableToolbar();\n -\n - if ( Xinha.is_designMode && this._doc.designMode != \'off\' )\n - {\n - try\n - {\n - this._doc.designMode = \'off\';\n - } catch (ex) {}\n - }\n - else if ( !Xinha.is_designMode && this._doc.body.contentEditable !== false )\n - {\n - this._doc.body.contentEditable = false;\n - }\n -\n - if ( Xinha._currentlyActiveEditor != this )\n - {\n - // We just deactivated an editor that wasn\'t marked as the currentlyActiveEditor\n -\n - return; // I think this should really be an error, there shouldn\'t be a situation where\n - // an editor is deactivated without first being activated. but it probably won\'t\n - // hurt anything.\n - }\n -\n - Xinha._currentlyActiveEditor = false;\n -};\n -/** Creates the iframe (editable area)\n - * @private\n - */\n -Xinha.prototype.initIframe = function()\n -{\n - this.disableToolbar();\n - var doc = null;\n - var editor = this;\n - try\n - {\n - if ( editor._iframe.contentDocument )\n - {\n - this._doc = editor._iframe.contentDocument; \n - }\n - else\n - {\n - this._doc = editor._iframe.contentWindow.document;\n - }\n - doc = this._doc;\n - // try later\n - if ( !doc )\n - {\n - if ( Xinha.is_gecko )\n - {\n - setTimeout(function() { editor.initIframe(); }, 50);\n - return false;\n - }\n - else\n - {\n - alert("ERROR: IFRAME can\'t be initialized.");\n - }\n - }\n - }\n - catch(ex)\n - { // try later\n - setTimeout(function() { editor.initIframe(); }, 50);\n - return false;\n - }\n - \n - Xinha.freeLater(this, \'_doc\');\n -\n - doc.open("text/html","replace");\n - var html = \'\', doctype;\n - if ( editor.config.browserQuirksMode === false )\n - {\n - doctype = \'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\';\n - }\n - else if ( editor.config.browserQuirksMode === true )\n - {\n - doctype = \'\';\n - }\n - else\n - {\n - doctype = Xinha.getDoctype(document);\n - }\n - \n - if ( !editor.config.fullPage )\n - {\n - html += doctype + "\\n";\n - html += "<html>\\n";\n - html += "<head>\\n";\n - html += "<meta http-equiv=\\"Content-Type\\" content=\\"text/html; charset=" + editor.config.charSet + "\\">\\n";\n - if ( typeof editor.config.baseHref != \'undefined\' && editor.config.baseHref !== null )\n - {\n - html += "<base href=\\"" + editor.config.baseHref + "\\"/>\\n";\n - }\n - \n - html += Xinha.addCoreCSS();\n - \n - if ( typeof editor.config.pageStyleSheets !== \'undefined\' )\n - {\n - for ( var i = 0; i < editor.config.pageStyleSheets.length; i++ )\n - {\n - if ( editor.config.pageStyleSheets[i].length > 0 )\n - {\n - html += "<link rel=\\"stylesheet\\" type=\\"text/css\\" href=\\"" + editor.config.pageStyleSheets[i] + "\\">";\n - //html += "<style> @import url(\'" + editor.config.pageStyleSheets[i] + "\'); </style>\\n";\n - }\n - }\n - }\n - \n - if ( editor.config.pageStyle )\n - {\n - html += "<style type=\\"text/css\\">\\n" + editor.config.pageStyle + "\\n</style>";\n - }\n - \n - html += "</head>\\n";\n - html += "<body" + (editor.config.bodyID ? (" id=\\"" + editor.config.bodyID + "\\"") : \'\') + (editor.config.bodyClass ? (" class=\\"" + editor.config.bodyClass + "\\"") : \'\') + ">\\n";\n - html += editor.inwardHtml(editor._textArea.value);\n - html += "</body>\\n";\n - html += "</html>";\n - }\n - else\n - {\n - html = editor.inwardHtml(editor._textArea.value);\n - if ( html.match(Xinha.RE_doctype) )\n - {\n - editor.setDoctype(RegExp.$1);\n - //html = html.replace(Xinha.RE_doctype, "");\n - }\n - \n - //Fix Firefox problem with link elements not in right place (just before head)\n - var match = html.match(/<link\\s+[\\s\\S]*?["\']\\s*\\/?>/gi);\n - html = html.replace(/<link\\s+[\\s\\S]*?["\']\\s*\\/?>\\s*/gi, \'\');\n - if (match)\n - {\n - html = html.replace(/<\\/head>/i, match.join(\'\\n\') + "\\n</head>");\n - }\n - }\n - doc.write(html);\n - doc.close();\n - if ( this.config.fullScreen )\n - {\n - this._fullScreen();\n - }\n - this.setEditorEvents();\n -\n -\n - // If this IFRAME had been configured for autofocus, we\'ll focus it now,\n - // since everything needed to do so is now fully loaded.\n - if ((typeof editor.config.autofocus != "undefined") && editor.config.autofocus !== false &&\n - ((editor.config.autofocus == editor._textArea.id) || editor.config.autofocus == true))\n - {\n - editor.activateEditor();\n - editor.focusEditor();\n - }\n -};\n - \n -/**\n - * Delay a function until the document is ready for operations.\n - * See ticket:547\n - * @public\n - * @param {Function} f The function to call once the document is ready\n - */\n -Xinha.prototype.whenDocReady = function(f)\n -{\n - var e = this;\n - if ( this._doc && this._doc.body )\n - {\n - f();\n - }\n - else\n - {\n - setTimeout(function() { e.whenDocReady(f); }, 50);\n - }\n -};\n -\n -\n -/** Switches editor mode between wysiwyg and text (HTML)\n - * @param {String} mode optional "textmode" or "wysiwyg", if omitted, toggles between modes.\n - */\n -Xinha.prototype.setMode = function(mode)\n -{\n - var html;\n - if ( typeof mode == "undefined" )\n - {\n - mode = this._editMode == "textmode" ? "wysiwyg" : "textmode";\n - }\n - switch ( mode )\n - {\n - case "textmode":\n - this.firePluginEvent(\'onBeforeMode\', \'textmode\');\n - this._toolbarObjects.htmlmode.swapImage(this.config.iconList.wysiwygmode); \n - this.setCC("iframe");\n - html = this.outwardHtml(this.getHTML());\n - this.setHTML(html);\n -\n - // Hide the iframe\n - this.deactivateEditor();\n - this._iframe.style.display = \'none\';\n - this._textArea.style.display = \'\';\n -\n - if ( this.config.statusBar )\n - {\n - this._statusBarTree.style.display = "none";\n - this._statusBarTextMode.style.display = "";\n - }\n - this.findCC("textarea");\n - this.notifyOf(\'modechange\', {\'mode\':\'text\'});\n - this.firePluginEvent(\'onMode\', \'textmode\');\n - break;\n -\n - case "wysiwyg":\n - this.firePluginEvent(\'onBeforeMode\', \'wysiwyg\');\n - this._toolbarObjects.htmlmode.swapImage([this.imgURL(\'images/ed_buttons_main.png\'),7,0]); \n - this.setCC("textarea");\n - html = this.inwardHtml(this.getHTML());\n - this.deactivateEditor();\n - this.setHTML(html);\n - this._iframe.style.display = \'\';\n - this._textArea.style.display = "none";\n - this.activateEditor();\n - if ( this.config.statusBar )\n - {\n - this._statusBarTree.style.display = "";\n - this._statusBarTextMode.style.display = "none";\n - }\n - this.findCC("iframe");\n - this.notifyOf(\'modechange\', {\'mode\':\'wysiwyg\'});\n - this.firePluginEvent(\'onMode\', \'wysiwyg\');\n -\n - break;\n -\n - default:\n - alert("Mode <" + mode + "> not defined!");\n - return false;\n - }\n - this._editMode = mode;\n -};\n -/** Sets the HTML in fullpage mode. Actually the whole iframe document is rewritten.\n - * @private\n - * @param {String} html\n - */\n -Xinha.prototype.setFullHTML = function(html)\n -{\n - var save_multiline = RegExp.multiline;\n - RegExp.multiline = true;\n - if ( html.match(Xinha.RE_doctype) )\n - {\n - this.setDoctype(RegExp.$1);\n - // html = html.replace(Xinha.RE_doctype, "");\n - }\n - RegExp.multiline = save_multiline;\n - // disabled to save body attributes see #459\n - if ( 0 )\n - {\n - if ( html.match(Xinha.RE_head) )\n - {\n - this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1;\n - }\n - if ( html.match(Xinha.RE_body) )\n - {\n - this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1;\n - }\n - }\n - else\n - {\n - // FIXME - can we do this without rewriting the entire document\n - // does the above not work for IE?\n - var reac = this.editorIsActivated();\n - if ( reac )\n - {\n - this.deactivateEditor();\n - }\n - var html_re = /<html>((.|\\n)*?)<\\/html>/i;\n - html = html.replace(html_re, "$1");\n - this._doc.open("text/html","replace");\n - this._doc.write(html);\n - this._doc.close();\n - if ( reac )\n - {\n - this.activateEditor();\n - } \n - this.setEditorEvents();\n - return true;\n - }\n -};\n -/** Initialize some event handlers\n - * @private\n - */\n -Xinha.prototype.setEditorEvents = function(resetting_events_for_opera)\n -{\n - var editor=this;\n - var doc = this._doc;\n -\n - editor.whenDocReady(\n - function()\n - {\n - if(!resetting_events_for_opera) {\n - // if we have multiple editors some bug in Mozilla makes some lose editing ability\n - Xinha._addEvents(\n - doc,\n - ["mousedown"],\n - function()\n - {\n - editor.activateEditor();\n - return true;\n - }\n - );\n - if (Xinha.is_ie)\n - { // #1019 Cusor not jumping to editable part of window when clicked in IE, see also #1039\n - Xinha._addEvent(\n - editor._doc.getElementsByTagName("html")[0],\n - "click",\n - function()\n - {\n - if (editor._iframe.contentWindow.event.srcElement.tagName.toLowerCase() == \'html\') // if clicked below the text (=body), the text cursor does not appear, see #1019\n - {\n - var r = editor._doc.body.createTextRange();\n - r.collapse();\n - r.select();\n - //setTimeout (function () { r.collapse(); r.select();},100); // won\'t do without timeout, dunno why\n - }\n - return true;\n - }\n - );\n - }\n - }\n -\n - // intercept some events; for updating the toolbar & keyboard handlers\n - Xinha._addEvents(\n - doc,\n - ["keydown", "keypress", "mousedown", "mouseup", "drag"],\n - function (event)\n - {\n - return editor._editorEvent(Xinha.is_ie ? editor._iframe.contentWindow.event : event);\n - }\n - );\n - \n - Xinha._addEvents(\n - doc, \n - ["dblclick"],\n - function (event)\n - {\n - return editor._onDoubleClick(Xinha.is_ie ? editor._iframe.contentWindow.event : event);\n - }\n - );\n - \n - if(resetting_events_for_opera) return;\n -\n - // FIXME - this needs to be cleaned up and use editor.firePluginEvent\n - // I don\'t like both onGenerate and onGenerateOnce, we should only\n - // have onGenerate and it should only be called when the editor is \n - // generated (once and only once)\n - // check if any plugins have registered refresh handlers\n - for ( var i in editor.plugins )\n - {\n - var plugin = editor.plugins[i].instance;\n - Xinha.refreshPlugin(plugin);\n - }\n -\n - // specific editor initialization\n - if ( typeof editor._onGenerate == "function" )\n - {\n - editor._onGenerate();\n - }\n - //ticket #1407 IE8 fires two resize events on one actual resize, seemingly causing an infinite loop (but not when Xinha is in an frame/iframe) \n - Xinha.addDom0Event(window, \'resize\', function(e) \n - {\n - if (Xinha.ie_version > 7 && !window.parent)\n - {\n - if (editor.execResize)\n - {\n - editor.sizeEditor(); \n - editor.execResize = false;\n - }\n - else\n - {\n - editor.execResize = true;\n - }\n - }\n - else\n - {\n - editor.sizeEditor(); \n - }\n - }); \n - editor.removeLoadingMessage();\n - }\n - );\n -};\n - \n -/***************************************************\n - * Category: PLUGINS\n - ***************************************************/\n -/** Plugins may either reside in the golbal scope (not recommended) or in Xinha.plugins. \n - * This function looks in both locations and is used to check the loading status and finally retrieve the plugin\'s constructor\n - * @private\n - * @type {Function|undefined}\n - * @param {String} pluginName\n - */\n -Xinha.getPluginConstructor = function(pluginName)\n -{\n - return Xinha.plugins[pluginName] || window[pluginName];\n -};\n -\n -/** Create the specified plugin and register it with this Xinha\n - * return the plugin created to allow refresh when necessary.<br />\n - * <strong>This is only useful if Xinha is generated without using Xinha.makeEditors()</strong>\n - */\n -Xinha.prototype.registerPlugin = function()\n -{\n - if (!Xinha.isSupportedBrowser)\n - {\n - return;\n - }\n - var plugin = arguments[0];\n -\n - // We can only register plugins that have been succesfully loaded\n - if ( plugin === null || typeof plugin == \'undefined\' || (typeof plugin == \'string\' && Xinha.getPluginConstructor(plugin) == \'undefined\') )\n - {\n - return false;\n - }\n - var args = [];\n - for ( var i = 1; i < arguments.length; ++i )\n - {\n - args.push(arguments[i]);\n - }\n - return this.registerPlugin2(plugin, args);\n -};\n -/** This is the variant of the function above where the plugin arguments are\n - * already packed in an array. Externally, it should be only used in the\n - * full-screen editor code, in order to initialize plugins with the same\n - * parameters as in the opener window.\n - * @private\n - */\n -Xinha.prototype.registerPlugin2 = function(plugin, args)\n -{\n - if ( typeof plugin == "string" && typeof Xinha.getPluginConstructor(plugin) == \'function\' )\n - {\n - var pluginName = plugin;\n - plugin = Xinha.getPluginConstructor(plugin);\n - }\n - if ( typeof plugin == "undefined" )\n - {\n - /* FIXME: This should never happen. But why does it do? */\n - return false;\n - }\n - if (!plugin._pluginInfo) \n - {\n - plugin._pluginInfo = \n - {\n - name: pluginName\n - };\n - }\n - var obj = new plugin(this, args);\n - if ( obj )\n - {\n - var clone = {};\n - var info = plugin._pluginInfo;\n - for ( var i in info )\n - {\n - clone[i] = info[i];\n - }\n - clone.instance = obj;\n - clone.args = args;\n - this.plugins[plugin._pluginInfo.name] = clone;\n - return obj;\n - }\n - else\n - {\n - Xinha.debugMsg("Can\'t register plugin " + plugin.toString() + ".", \'warn\');\n - }\n -};\n -\n -\n -/** Dynamically returns the directory from which the plugins are loaded<br />\n - * This could be overridden to change the dir<br />\n - * @TODO: Wouldn\'t this be better as a config option?\n - * @private\n - * @param {String} pluginName\n - * @param {Boolean} return the directory for an unsupported plugin\n - * @returns {String} path to plugin\n - */\n -Xinha.getPluginDir = function(plugin, forceUnsupported)\n -{\n - if (Xinha.externalPlugins[plugin])\n - {\n - return Xinha.externalPlugins[plugin][0];\n - }\n - if (forceUnsupported ||\n - // If the plugin is fully loaded, it\'s supported status is already set.\n - (Xinha.getPluginConstructor(plugin) && (typeof Xinha.getPluginConstructor(plugin).supported != \'undefined\') && !Xinha.getPluginConstructor(plugin).supported))\n - {\n - return _editor_url + "unsupported_plugins/" + plugin ;\n - }\n - return _editor_url + "plugins/" + plugin ;\n -};\n -/** Static function that loads the given plugin\n - * @param {String} pluginName\n - * @param {Function} callback function to be called when file is loaded\n - * @param {String} plugin_file URL of the file to load\n - * @returns {Boolean} true if plugin loaded, false otherwise\n - */\n -Xinha.loadPlugin = function(pluginName, callback, url)\n -{\n - if (!Xinha.isSupportedBrowser) \n - {\n - return;\n - }\n - Xinha.setLoadingMessage (Xinha._lc("Loading plugin $plugin="+pluginName+"$"));\n -\n - // Might already be loaded\n - if ( typeof Xinha.getPluginConstructor(pluginName) != \'undefined\' )\n - {\n - if ( callback )\n - {\n - callback(pluginName);\n - }\n - return true;\n - }\n - Xinha._pluginLoadStatus[pluginName] = \'loading\';\n - \n - // This function will try to load a plugin in multiple passes. It tries to\n - // load the plugin from either the plugin or unsupported directory, using\n - // both naming schemes in this order:\n - // 1. /plugins -> CurrentNamingScheme\n - // 2. /plugins -> old-naming-scheme\n - // 3. /unsupported -> CurrentNamingScheme\n - // 4. /unsupported -> old-naming-scheme\n -\n - function multiStageLoader(stage,pluginName)\n - {\n - var nextstage, dir, file, success_message;\n - switch (stage)\n - {\n - case \'start\':\n - nextstage = \'old_naming\';\n - dir = Xinha.getPluginDir(pluginName);\n - file = pluginName + ".js";\n - break;\n - case \'old_naming\':\n - nextstage = \'unsupported\';\n - dir = Xinha.getPluginDir(pluginName);\n - file = pluginName.replace(/([a-z])([A-Z])([a-z])/g, function (str, l1, l2, l3) { return l1 + "-" + l2.toLowerCase() + l3; }).toLowerCase() + ".js";\n - success_message = \'You are using an obsolete naming scheme for the Xinha plugin \'+pluginName+\'. Please rename \'+file+\' to \'+pluginName+\'.js\';\n - break;\n - case \'unsupported\':\n - nextstage = \'unsupported_old_name\';\n - dir = Xinha.getPluginDir(pluginName, true);\n - file = pluginName + ".js";\n - success_message = \'You are using the unsupported Xinha plugin \'+pluginName+\'. If you wish continued support, please see http://trac.xinha.org/ticket/1297\';\n - break;\n - case \'unsupported_old_name\':\n - nextstage = \'\';\n - dir = Xinha.getPluginDir(pluginName, true);\n - file = pluginName.replace(/([a-z])([A-Z])([a-z])/g, function (str, l1, l2, l3) { return l1 + "-" + l2.toLowerCase() + l3; }).toLowerCase() + ".js";\n - success_message = \'You are using the unsupported Xinha plugin \'+pluginName+\'. If you wish continued support, please see http://trac.xinha.org/ticket/1297\';\n - break;\n - default:\n - Xinha._pluginLoadStatus[pluginName] = \'failed\';\n - Xinha.debugMsg(\'Xinha was not able to find the plugin \'+pluginName+\'. Please make sure the plugin exists.\', \'warn\');\n - return;\n - }\n - var url = dir + "/" + file;\n -\n - // This is a callback wrapper that allows us to set the plugin\'s status\n - // once it loads.\n - function statusCallback(pluginName)\n - {\n - Xinha.getPluginConstructor(pluginName).supported = stage.indexOf(\'unsupported\') !== 0;\n - callback(pluginName);\n - }\n -\n - // To speed things up, we start loading the script file before pinging it.\n - // If the load fails, we\'ll just clean up afterwards.\n - Xinha._loadback(url, statusCallback, this, pluginName); \n -\n - Xinha.ping(url,\n - // On success, we\'ll display a success message if there is one.\n - function()\n - {\n - if (success_message) \n - {\n - Xinha.debugMsg(success_message);\n - }\n - },\n - // On failure, we\'ll clean up the failed load and try the next stage\n - function()\n - {\n - Xinha.removeFromParent(document.getElementById(url));\n - multiStageLoader(nextstage, pluginName);\n - });\n - }\n - \n - if(!url)\n - {\n - if (Xinha.externalPlugins[pluginName])\n - {\n - Xinha._loadback(Xinha.externalPlugins[pluginName][0]+Xinha.externalPlugins[pluginName][1], callback, this, pluginName);\n - }\n - else\n - {\n - var editor = this;\n - multiStageLoader(\'start\',pluginName);\n - }\n - }\n - else\n - {\n - Xinha._loadback(url, callback, this, pluginName);\n - }\n - \n - return false;\n -};\n -/** Stores a status for each loading plugin that may be one of "loading","ready", or "failed"\n - * @private\n - * @type {Object} \n - */\n -Xinha._pluginLoadStatus = {};\n -/** Stores the paths to plugins that are not in the default location\n - * @private\n - * @type {Object}\n - */\n -Xinha.externalPlugins = {};\n -/** The namespace for plugins\n - * @private\n - * @type {Object}\n - */\n -Xinha.plugins = {};\n -\n -/** Static function that loads the plugins (see xinha_plugins in NewbieGuide)\n - * @param {Array} plugins\n - * @param {Function} callbackIfNotReady function that is called repeatedly until all files are\n - * @param {String} optional url URL of the plugin file; obviously plugins should contain only one item if url is given\n - * @returns {Boolean} true if all plugins are loaded, false otherwise\n - */\n -Xinha.loadPlugins = function(plugins, callbackIfNotReady,url)\n -{\n - if (!Xinha.isSupportedBrowser) \n - {\n - return;\n - }\n - //Xinha.setLoadingMessage (Xinha._lc("Loading plugins"));\n - var m,i;\n - for (i=0;i<plugins.length;i++)\n - {\n - if (typeof plugins[i] == \'object\')\n - {\n - m = plugins[i].url.match(/(.*)(\\/[^\\/]*)$/);\n - Xinha.externalPlugins[plugins[i].plugin] = [m[1],m[2]];\n - plugins[i] = plugins[i].plugin;\n - }\n - }\n - \n - // Rip the ones that are loaded and look for ones that have failed\n - var retVal = true;\n - var nuPlugins = Xinha.cloneObject(plugins);\n - for (i=0;i<nuPlugins.length;i++ )\n - {\n - var p = nuPlugins[i];\n - \n - if (p == \'FullScreen\' && !Xinha.externalPlugins.FullScreen)\n - {\n - continue; //prevent trying to load FullScreen plugin from the plugins folder\n - } \n - \n - if ( typeof Xinha._pluginLoadStatus[p] == \'undefined\')\n - {\n - // Load it\n - Xinha.loadPlugin(p,\n - function(plugin)\n - {\n - Xinha.setLoadingMessage (Xinha._lc("Finishing"));\n -\n - if ( typeof Xinha.getPluginConstructor(plugin) != \'undefined\' )\n - {\n - Xinha._pluginLoadStatus[plugin] = \'ready\';\n - }\n - else\n - {\n - Xinha._pluginLoadStatus[plugin] = \'failed\';\n - }\n - }, url);\n - retVal = false;\n - }\n - else if ( Xinha._pluginLoadStatus[p] == \'loading\')\n - {\n - retVal = false;\n - }\n - }\n - \n - // All done, just return\n - if ( retVal )\n - {\n - return true;\n - }\n -\n - // Waiting on plugins to load, return false now and come back a bit later\n - // if we have to callback\n - if ( callbackIfNotReady )\n - {\n - setTimeout(function() \n - { \n - if ( Xinha.loadPlugins(plugins, callbackIfNotReady) ) \n - { \n - callbackIfNotReady(); \n - } \n - }, 50);\n - }\n - return retVal;\n -};\n -\n -// \n -/** Refresh plugin by calling onGenerate or onGenerateOnce method.\n - * @private\n - * @param {PluginInstance} plugin\n - */\n -Xinha.refreshPlugin = function(plugin)\n -{\n - if ( plugin && typeof plugin.onGenerate == "function" )\n - {\n - plugin.onGenerate();\n - }\n - if ( plugin && typeof plugin.onGenerateOnce == "function" )\n - {\n - //#1392: in fullpage mode this function is called recusively by setFullHTML() when it is used to set the editor content\n -\t// this is a temporary fix, that should better be handled by a better implemetation of setFullHTML\n -\tplugin._ongenerateOnce = plugin.onGenerateOnce;\n - delete(plugin.onGenerateOnce);\n -\tplugin._ongenerateOnce();\n -\tdelete(plugin._ongenerateOnce);\n - }\n -};\n -\n -/** Call a method of all plugins which define the method using the supplied arguments.<br /><br />\n - *\n - * Example: <code>editor.firePluginEvent(\'onExecCommand\', \'paste\')</code><br />\n - * The plugin would then define a method<br />\n - * <code>PluginName.prototype.onExecCommand = function (cmdID, UI, param) {do something...}</code><br /><br />\n - * The following methodNames are currently available:<br />\n - * <table border="1">\n - * <tr>\n - * <th>methodName</th><th>Parameters</th>\n - * </tr>\n - * <tr>\n - * <td>onExecCommand</td><td> cmdID, UI, param</td>\n - * </tr>\n - * <tr>\n - * <td>onKeyPress</td><td>ev</td>\n - * </tr> \n - * <tr>\n - * <td>onMouseDown</td><td>ev</td>\n - * </tr>\n - * </table><br /><br />\n - * \n - * The browser specific plugin (if any) is called last. The result of each call is \n - * treated as boolean. A true return means that the event will stop, no further plugins\n - * will get the event, a false return means the event will continue to fire.\n - *\n - * @param {String} methodName\n - * @param {mixed} arguments to pass to the method, optional [2..n] \n - * @returns {Boolean}\n - */\n -\n -Xinha.prototype.firePluginEvent = function(methodName)\n -{\n - // arguments is not a real array so we can\'t just .shift() it unfortunatly.\n - var argsArray = [ ];\n - for(var i = 1; i < arguments.length; i++)\n - {\n - argsArray[i-1] = arguments[i];\n - }\n - \n - for ( i in this.plugins )\n - {\n - var plugin = this.plugins[i].instance;\n -\n - // Skip the browser specific plugin\n - if (plugin == this._browserSpecificPlugin) \n - {\n - continue;\n - }\n - if ( plugin && typeof plugin[methodName] == "function" )\n - {\n - var thisArg = (i == \'Events\') ? this : plugin;\n - if ( plugin[methodName].apply(thisArg, argsArray) )\n - {\n - return true;\n - }\n - }\n - }\n - \n - // Now the browser speific\n - plugin = this._browserSpecificPlugin;\n - if ( plugin && typeof plugin[methodName] == "function" )\n - {\n - if ( plugin[methodName].apply(plugin, argsArray) )\n - {\n - return true;\n - }\n - }\n - return false;\n -};\n -/** Adds a stylesheet to the document\n - * @param {String} style name of the stylesheet file\n - * @param {String} plugin optional name of a plugin; if passed this function looks for the stylesheet file in the plugin directory \n - * @param {String} id optional a unique id for identifiing the created link element, e.g. for avoiding double loading \n - * or later removing it again\n - */\n -Xinha.loadStyle = function(style, plugin, id,prepend)\n -{\n - var url = _editor_url || \'\';\n - if ( plugin )\n - {\n - url = Xinha.getPluginDir( plugin ) + "/";\n - }\n - url += style;\n - // @todo: would not it be better to check the first character instead of a regex ?\n - // if ( typeof style == \'string\' && style.charAt(0) == \'/\' )\n - // {\n - // url = style;\n - // }\n - if ( /^\\//.test(style) )\n - {\n - url = style;\n - }\n - var head = document.getElementsByTagName("head")[0];\n - var link = document.createElement("link");\n - link.rel = "stylesheet";\n - link.href = url;\n - link.type = "text/css";\n - if (id)\n - {\n - link.id = id;\n - }\n - if (prepend && head.getElementsByTagName(\'link\')[0])\n - {\n - head.insertBefore(link,head.getElementsByTagName(\'link\')[0]);\n - }\n - else\n - {\n - head.appendChild(link);\n - }\n - \n -};\n -\n -/** Adds a script to the document\n - *\n - * Warning: Browsers may cause the script to load asynchronously.\n - *\n - * @param {String} style name of the javascript file\n - * @param {String} plugin optional name of a plugin; if passed this function looks for the stylesheet file in the plugin directory \n - *\n - */\n -Xinha.loadScript = function(script, plugin, callback)\n -{\n - var url = _editor_url || \'\';\n - if ( plugin )\n - {\n - url = Xinha.getPluginDir( plugin ) + "/";\n - }\n - url += script;\n - // @todo: would not it be better to check the first character instead of a regex ?\n - // if ( typeof style == \'string\' && style.charAt(0) == \'/\' )\n - // {\n - // url = style;\n - // }\n - if ( /^\\//.test(script) )\n - {\n - url = script;\n - }\n - \n - Xinha._loadback(url, callback);\n - \n -};\n -\n -/** Load one or more assets, sequentially, where an asset is a CSS file, or a javascript file.\n - * \n - * Example Usage:\n - *\n - * Xinha.includeAssets( \'foo.css\', \'bar.js\', [ \'foo.css\', \'MyPlugin\' ], { type: \'text/css\', url: \'foo.php\', plugin: \'MyPlugin } );\n - *\n - * Alternative usage, use Xinha.includeAssets() to make a loader, then use loadScript, loadStyle and whenReady methods\n - * on your loader object as and when you wish, you can chain the calls if you like.\n - *\n - * You may add any number of callbacks using .whenReady() multiple times.\n - *\n - * var myAssetLoader = Xinha.includeAssets();\n - * myAssetLoader.loadScript(\'foo.js\', \'MyPlugin\')\n - * .loadStyle(\'foo.css\', \'MyPlugin\'); \n - * \n - */\n -\n -Xinha.includeAssets = function()\n -{\n - var assetLoader = { pendingAssets: [ ], loaderRunning: false, loadedScripts: [ ] };\n - \n - assetLoader.callbacks = [ ];\n - \n - assetLoader.loadNext = function()\n - { \n - var self = this;\n - this.loaderRunning = true;\n - \n - if(this.pendingAssets.length)\n - {\n - var nxt = this.pendingAssets[0];\n - this.pendingAssets.splice(0,1); // Remove 1 element\n - switch(nxt.type)\n - {\n - case \'text/css\':\n - Xinha.loadStyle(nxt.url, nxt.plugin);\n - return this.loadNext();\n - \n - case \'text/javascript\':\n - Xinha.loadScript(nxt.url, nxt.plugin, function() { self.loadNext(); });\n - }\n - }\n - else\n - {\n - this.loaderRunning = false;\n - this.runCallback(); \n - }\n - };\n - \n - assetLoader.loadScript = function(url, plugin)\n - {\n - var self = this;\n - \n - this.pendingAssets.push({ \'type\': \'text/javascript\', \'url\': url, \'plugin\': plugin });\n - if(!this.loaderRunning) this.loadNext();\n - \n - return this;\n - };\n - \n - assetLoader.loadScriptOnce = function(url, plugin)\n - {\n - for(var i = 0; i < this.loadedScripts.length; i++)\n - {\n - if(this.loadedScripts[i].url == url && this.loadedScripts[i].plugin == plugin)\n - return this; // Already done (or in process)\n - }\n - \n - return this.loadScript(url, plugin);\n - }\n - \n - assetLoader.loadStyle = function(url, plugin)\n - {\n - var self = this;\n - \n - this.pendingAssets.push({ \'type\': \'text/css\', \'url\': url, \'plugin\': plugin });\n - if(!this.loaderRunning) this.loadNext();\n - \n - return this; \n - };\n - \n - assetLoader.whenReady = function(callback) \n - {\n - this.callbacks.push(callback); \n - if(!this.loaderRunning) this.loadNext();\n - \n - return this; \n - };\n - \n - assetLoader.runCallback = function()\n - {\n - while(this.callbacks.length)\n - { \n - var _callback = this.callbacks.splice(0,1);\n - _callback[0]();\n - _callback = null;\n - }\n - return this;\n - }\n - \n - for(var i = 0 ; i < arguments.length; i++)\n - {\n - if(typeof arguments[i] == \'string\')\n - {\n - if(arguments[i].match(/\\.css$/i))\n - {\n - assetLoader.loadStyle(arguments[i]);\n - }\n - else \n - {\n - assetLoader.loadScript(arguments[i]);\n - }\n - }\n - else if(arguments[i].type)\n - {\n - if(arguments[i].type.match(/text\\/css/i))\n - {\n - assetLoader.loadStyle(arguments[i].url, arguments[i].plugin);\n - }\n - else if(arguments[i].type.match(/text\\/javascript/i))\n - {\n - assetLoader.loadScript(arguments[i].url, arguments[i].plugin);\n - }\n - }\n - else if(arguments[i].length >= 1)\n - {\n - if(arguments[i][0].match(/\\.css$/i))\n - {\n - assetLoader.loadStyle(arguments[i][0], arguments[i][1]);\n - }\n - else \n - {\n - assetLoader.loadScript(arguments[i][0], arguments[i][1]);\n - }\n - }\n - }\n - \n - return assetLoader;\n -}\n -\n -/***************************************************\n - * Category: EDITOR UTILITIES\n - ***************************************************/\n -/** Utility function: Outputs the structure of the edited document */\n -Xinha.prototype.debugTree = function()\n -{\n - var ta = document.createElement("textarea");\n - ta.style.width = "100%";\n - ta.style.height = "20em";\n - ta.value = "";\n - function debug(indent, str)\n - {\n - for ( ; --indent >= 0; )\n - {\n - ta.value += " ";\n - }\n - ta.value += str + "\\n";\n - }\n - function _dt(root, level)\n - {\n - var tag = root.tagName.toLowerCase(), i;\n - var ns = Xinha.is_ie ? root.scopeName : root.prefix;\n - debug(level, "- " + tag + " [" + ns + "]");\n - for ( i = root.firstChild; i; i = i.nextSibling )\n - {\n - if ( i.nodeType == 1 )\n - {\n - _dt(i, level + 2);\n - }\n - }\n - }\n - _dt(this._doc.body, 0);\n - document.body.appendChild(ta);\n -};\n -/** Extracts the textual content of a given node\n - * @param {DomNode} el\n - */\n -\n -Xinha.getInnerText = function(el)\n -{\n - var txt = \'\', i;\n - for ( i = el.firstChild; i; i = i.nextSibling )\n - {\n - if ( i.nodeType == 3 )\n - {\n - txt += i.data;\n - }\n - else if ( i.nodeType == 1 )\n - {\n - txt += Xinha.getInnerText(i);\n - }\n - }\n - return txt;\n -};\n -/** Cleans dirty HTML from MS word; always cleans the whole editor content\n - * @TODO: move this in a separate file\n - * @TODO: turn this into a static function that cleans a given string\n - */\n -Xinha.prototype._wordClean = function()\n -{\n - var editor = this;\n - var stats =\n - {\n - empty_tags : 0,\n - cond_comm : 0,\n - mso_elmts : 0,\n - mso_class : 0,\n - mso_style : 0,\n - mso_xmlel : 0,\n - orig_len : this._doc.body.innerHTML.length,\n - T : new Date().getTime()\n - };\n - var stats_txt =\n - {\n - empty_tags : "Empty tags removed: ",\n - cond_comm : "Conditional comments removed",\n - mso_elmts : "MSO invalid elements removed",\n - mso_class : "MSO class names removed: ",\n - mso_style : "MSO inline style removed: ",\n - mso_xmlel : "MSO XML elements stripped: "\n - };\n -\n - function showStats()\n - {\n - var txt = "Xinha word cleaner stats: \\n\\n";\n - for ( var i in stats )\n - {\n - if ( stats_txt[i] )\n - {\n - txt += stats_txt[i] + stats[i] + "\\n";\n - }\n - }\n - txt += "\\nInitial document length: " + stats.orig_len + "\\n";\n - txt += "Final document length: " + editor._doc.body.innerHTML.length + "\\n";\n - txt += "Clean-up took " + ((new Date().getTime() - stats.T) / 1000) + " seconds";\n - alert(txt);\n - }\n -\n - function clearClass(node)\n - {\n - var newc = node.className.replace(/(^|\\s)mso.*?(\\s|$)/ig, \' \');\n - if ( newc != node.className )\n - {\n - node.className = newc;\n - if ( !/\\S/.test(node.className))\n - {\n - node.removeAttribute("className");\n - ++stats.mso_class;\n - }\n - }\n - }\n -\n - function clearStyle(node)\n - {\n - var declarations = node.style.cssText.split(/\\s*;\\s*/);\n - for ( var i = declarations.length; --i >= 0; )\n - {\n - if ( /^mso|^tab-stops/i.test(declarations[i]) || /^margin\\s*:\\s*0..\\s+0..\\s+0../i.test(declarations[i]) )\n - {\n - ++stats.mso_style;\n - declarations.splice(i, 1);\n - }\n - }\n - node.style.cssText = declarations.join("; ");\n - }\n + -------------------------------------------------------------------------*/\n \n - function removeElements(el)\n - {\n - if ((\'link\' == el.tagName.toLowerCase() &&\n - (el.attributes && /File-List|Edit-Time-Data|themeData|colorSchemeMapping/.test(el.attributes.rel.nodeValue))) ||\n - /^(style|meta)$/i.test(el.tagName))\n - {\n - Xinha.removeFromParent(el);\n - ++stats.mso_elmts;\n - return true;\n - }\n - return false;\n - }\n -\n - function checkEmpty(el)\n - {\n - // @todo : check if this is quicker\n - // if (![\'A\',\'SPAN\',\'B\',\'STRONG\',\'I\',\'EM\',\'FONT\'].contains(el.tagName) && !el.firstChild)\n - if ( /^(a|span|b|strong|i|em|font|div|p)$/i.test(el.tagName) && !el.firstChild)\n - {\n - Xinha.removeFromParent(el);\n - ++stats.empty_tags;\n - return true;\n - }\n - return false;\n - }\n -\n - function parseTree(root)\n - {\n - clearClass(root);\n - clearStyle(root);\n - var next;\n - for (var i = root.firstChild; i; i = next )\n - {\n - next = i.nextSibling;\n - if ( i.nodeType == 1 && parseTree(i) )\n - {\n - if ((Xinha.is_ie && root.scopeName != \'HTML\') || (!Xinha.is_ie && /:/.test(i.tagName)))\n - {\n - // Nowadays, Word spits out tags like \'<o:something />\'. Since the\n - // document being cleaned might be HTML4 and not XHTML, this tag is\n - // interpreted as \'<o:something /="/">\'. For HTML tags without\n - // closing elements (e.g. IMG) these two forms are equivalent. Since\n - // HTML does not recognize these tags, however, they end up as\n - // parents of elements that should be their siblings. We reparent\n - // the children and remove them from the document.\n - for (var index=i.childNodes && i.childNodes.length-1; i.childNodes && i.childNodes.length && i.childNodes[index]; --index)\n - {\n - if (i.nextSibling)\n - {\n - i.parentNode.insertBefore(i.childNodes[index],i.nextSibling);\n - }\n - else\n - {\n - i.parentNode.appendChild(i.childNodes[index]);\n - }\n - }\n - Xinha.removeFromParent(i);\n - continue;\n - }\n - if (checkEmpty(i))\n - {\n - continue;\n - }\n - if (removeElements(i))\n - {\n - continue;\n - }\n - }\n - else if (i.nodeType == 8)\n - {\n - // 8 is a comment node, and can contain conditional comments, which\n - // will be interpreted by IE as if they were not comments.\n - if (/(\\s*\\[\\s*if\\s*(([gl]te?|!)\\s*)?(IE|mso)\\s*(\\d+(\\.\\d+)?\\s*)?\\]>)/.test(i.nodeValue))\n - {\n - // We strip all conditional comments directly from the tree.\n - Xinha.removeFromParent(i);\n - ++stats.cond_comm;\n - }\n - }\n - }\n - return true;\n - }\n - parseTree(this._doc.body);\n - // showStats();\n - // this.debugTree();\n - // this.setHTML(this.getHTML());\n - // this.setHTML(this.getInnerHTML());\n - // this.forceRedraw();\n - this.updateToolbar();\n -};\n -\n -/** Removes <font> tags; always cleans the whole editor content\n - * @TODO: move this in a separate file\n - * @TODO: turn this into a static function that cleans a given string\n - */\n -Xinha.prototype._clearFonts = function()\n -{\n - var D = this.getInnerHTML();\n -\n - if ( confirm(Xinha._lc("Would you like to clear font typefaces?")) )\n - {\n - D = D.replace(/face="[^"]*"/gi, \'\');\n - D = D.replace(/font-family:[^;}"\']+;?/gi, \'\');\n - }\n -\n - if ( confirm(Xinha._lc("Would you like to clear font sizes?")) )\n - {\n - D = D.replace(/size="[^"]*"/gi, \'\');\n - D = D.replace(/font-size:[^;}"\']+;?/gi, \'\');\n - }\n -\n - if ( confirm(Xinha._lc("Would you like to clear font colours?")) )\n - {\n - D = D.replace(/color="[^"]*"/gi, \'\');\n - D = D.replace(/([^\\-])color:[^;}"\']+;?/gi, \'$1\');\n - }\n -\n - D = D.replace(/(style|class)="\\s*"/gi, \'\');\n - D = D.replace(/<(font|span)\\s*>/gi, \'\');\n - this.setHTML(D);\n - this.updateToolbar();\n -};\n -\n -Xinha.prototype._splitBlock = function()\n -{\n - this._doc.execCommand(\'formatblock\', false, \'div\');\n -};\n -\n -/** Sometimes the display has to be refreshed to make DOM changes visible (?) (Gecko bug?) */\n -Xinha.prototype.forceRedraw = function()\n -{\n - this._doc.body.style.visibility = "hidden";\n - this._doc.body.style.visibility = "";\n - // this._doc.body.innerHTML = this.getInnerHTML();\n -};\n -\n -/** Focuses the iframe window. \n - * @returns {document} a reference to the editor document\n - */\n -Xinha.prototype.focusEditor = function()\n -{\n - switch (this._editMode)\n - {\n - // notice the try { ... } catch block to avoid some rare exceptions in FireFox\n - // (perhaps also in other Gecko browsers). Manual focus by user is required in\n - // case of an error. Somebody has an idea?\n - case "wysiwyg" :\n - try\n - {\n - // We don\'t want to focus the field unless at least one field has been activated.\n - if ( Xinha._someEditorHasBeenActivated )\n - {\n - this.activateEditor(); // Ensure *this* editor is activated\n - this._iframe.contentWindow.focus(); // and focus it\n - }\n - } catch (ex) {}\n - break;\n - case "textmode":\n - try\n - {\n - this._textArea.focus();\n - } catch (e) {}\n - break;\n - default:\n - alert("ERROR: mode " + this._editMode + " is not defined");\n - }\n - return this._doc;\n -};\n -\n -/** Takes a snapshot of the current text (for undo)\n - * @private\n - */\n -Xinha.prototype._undoTakeSnapshot = function()\n -{\n - ++this._undoPos;\n - if ( this._undoPos >= this.config.undoSteps )\n - {\n - // remove the first element\n - this._undoQueue.shift();\n - --this._undoPos;\n - }\n - // use the fasted method (getInnerHTML);\n - var take = true;\n - var txt = this.getInnerHTML();\n - if ( this._undoPos > 0 )\n - {\n - take = (this._undoQueue[this._undoPos - 1] != txt);\n - }\n - if ( take )\n - {\n - this._undoQueue[this._undoPos] = txt;\n - }\n - else\n - {\n - this._undoPos--;\n - }\n -};\n -/** Custom implementation of undo functionality\n - * @private\n - */\n -Xinha.prototype.undo = function()\n -{\n - if ( this._undoPos > 0 )\n - {\n - var txt = this._undoQueue[--this._undoPos];\n - if ( txt )\n - {\n - this.setHTML(txt);\n - }\n - else\n - {\n - ++this._undoPos;\n - }\n - }\n -};\n -/** Custom implementation of redo functionality\n - * @private\n - */\n -Xinha.prototype.redo = function()\n -{\n - if ( this._undoPos < this._undoQueue.length - 1 )\n - {\n - var txt = this._undoQueue[++this._undoPos];\n - if ( txt )\n - {\n - this.setHTML(txt);\n - }\n - else\n - {\n - --this._undoPos;\n - }\n - }\n -};\n -/** Disables (greys out) the buttons of the toolbar\n - * @param {Array} except this array contains ids of toolbar objects that will not be disabled\n - */\n -Xinha.prototype.disableToolbar = function(except)\n -{\n - if ( this._timerToolbar )\n - {\n - clearTimeout(this._timerToolbar);\n - }\n - if ( typeof except == \'undefined\' )\n - {\n - except = [ ];\n - }\n - else if ( typeof except != \'object\' )\n - {\n - except = [except];\n - }\n -\n - for ( var i in this._toolbarObjects )\n - {\n - var btn = this._toolbarObjects[i];\n - if ( except.contains(i) )\n - {\n - continue;\n - }\n - // prevent iterating over wrong type\n - if ( typeof btn.state != \'function\' )\n - {\n - continue;\n - }\n - btn.state("enabled", false);\n - }\n -};\n -/** Enables the toolbar again when disabled by disableToolbar() */\n -Xinha.prototype.enableToolbar = function()\n -{\n - this.updateToolbar();\n -};\n -\n -/** Updates enabled/disable/active state of the toolbar elements, the statusbar and other things\n - * This function is called on every key stroke as well as by a timer on a regular basis.<br />\n - * Plugins have the opportunity to implement a prototype.onUpdateToolbar() method, which will also\n - * be called by this function.\n - * @param {Boolean} noStatus private use Exempt updating of statusbar\n - */\n -// FIXME : this function needs to be splitted in more functions.\n -// It is actually to heavy to be understable and very scary to manipulate\n -Xinha.prototype.updateToolbar = function(noStatus)\n -{\n - if (this.suspendUpdateToolbar)\n - {\n - return;\n - }\n - var doc = this._doc;\n - var text = (this._editMode == "textmode");\n - var ancestors = null;\n - if ( !text )\n - {\n - ancestors = this.getAllAncestors();\n - if ( this.config.statusBar && !noStatus )\n - {\n - while ( this._statusBarItems.length )\n - { \n - var item = this._statusBarItems.pop();\n - item.el = null;\n - item.editor = null;\n - item.onclick = null;\n - item.oncontextmenu = null;\n - item._xinha_dom0Events.click = null;\n - item._xinha_dom0Events.contextmenu = null;\n - item = null;\n - }\n -\n - this._statusBarTree.innerHTML = \' \';\n - this._statusBarTree.appendChild(document.createTextNode(Xinha._lc("Path") + ": ")); \n - for ( var i = ancestors.length; --i >= 0; )\n - {\n - var el = ancestors[i];\n - if ( !el )\n - {\n - // hell knows why we get here; this\n - // could be a classic example of why\n - // it\'s good to check for conditions\n - // that are impossible to happen ;-)\n - continue;\n - }\n - var a = document.createElement("a");\n - a.href = "javascript:void(0);";\n - a.el = el;\n - a.editor = this;\n - this._statusBarItems.push(a);\n - Xinha.addDom0Event(\n - a,\n - \'click\',\n - function() {\n - this.blur();\n - this.editor.selectNodeContents(this.el);\n - this.editor.updateToolbar(true);\n - return false;\n - }\n - );\n - Xinha.addDom0Event(\n - a,\n - \'contextmenu\',\n - function()\n - {\n - // TODO: add context menu here\n - this.blur();\n - var info = "Inline style:\\n\\n";\n - info += this.el.style.cssText.split(/;\\s*/).join(";\\n");\n - alert(info);\n - return false;\n - }\n - );\n - var txt = el.tagName.toLowerCase();\n - switch (txt)\n - {\n - case \'b\':\n - txt = \'strong\';\n - break;\n - case \'i\':\n - txt = \'em\';\n - break;\n - case \'strike\':\n - txt = \'del\';\n - break;\n - }\n - if (typeof el.style != \'undefined\')\n - {\n - a.title = el.style.cssText;\n - }\n - if ( el.id )\n - {\n - txt += "#" + el.id;\n - }\n - if ( el.className )\n - {\n - txt += "." + el.className;\n - }\n - a.appendChild(document.createTextNode(txt));\n - this._statusBarTree.appendChild(a);\n - if ( i !== 0 )\n - {\n - this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(0xbb)));\n - }\n - Xinha.freeLater(a);\n - }\n - }\n - }\n -\n - for ( var cmd in this._toolbarObjects )\n - {\n - var btn = this._toolbarObjects[cmd];\n - var inContext = true;\n - // prevent iterating over wrong type\n - if ( typeof btn.state != \'function\' )\n - {\n - continue;\n - }\n - if ( btn.context && !text )\n - {\n - inContext = false;\n - var context = btn.context;\n - var attrs = [];\n - if ( /(.*)\\[(.*?)\\]/.test(context) )\n - {\n - context = RegExp.$1;\n - attrs = RegExp.$2.split(",");\n - }\n - context = context.toLowerCase();\n - var match = (context == "*");\n - for ( var k = 0; k < ancestors.length; ++k )\n - {\n - if ( !ancestors[k] )\n - {\n - // the impossible really happens.\n - continue;\n - }\n - if ( match || ( ancestors[k].tagName.toLowerCase() == context ) )\n - {\n - inContext = true;\n - var contextSplit = null;\n - var att = null;\n - var comp = null;\n - var attVal = null;\n - for ( var ka = 0; ka < attrs.length; ++ka )\n - {\n - contextSplit = attrs[ka].match(/(.*)(==|!=|===|!==|>|>=|<|<=)(.*)/);\n - att = contextSplit[1];\n - comp = contextSplit[2];\n - attVal = contextSplit[3];\n -\n - if (!eval(ancestors[k][att] + comp + attVal))\n - {\n - inContext = false;\n - break;\n - }\n - }\n - if ( inContext )\n - {\n - break;\n - }\n - }\n - }\n - }\n - btn.state("enabled", (!text || btn.text) && inContext);\n - if ( typeof cmd == "function" )\n - {\n - continue;\n - }\n - // look-it-up in the custom dropdown boxes\n - var dropdown = this.config.customSelects[cmd];\n - if ( ( !text || btn.text ) && ( typeof dropdown != "undefined" ) )\n - {\n - dropdown.refresh(this);\n - continue;\n - }\n - switch (cmd)\n - {\n - case "fontname":\n - case "fontsize":\n - if ( !text )\n - {\n - try\n - {\n - var value = ("" + doc.queryCommandValue(cmd)).toLowerCase();\n - if ( !value )\n - {\n - btn.element.selectedIndex = 0;\n - break;\n - }\n -\n - // HACK -- retrieve the config option for this\n - // combo box. We rely on the fact that the\n - // variable in config has the same name as\n - // button name in the toolbar.\n - var options = this.config[cmd];\n - var sIndex = 0;\n - for ( var j in options )\n - {\n - // FIXME: the following line is scary.\n - if ( ( j.toLowerCase() == value ) || ( options[j].substr(0, value.length).toLowerCase() == value ) )\n - {\n - btn.element.selectedIndex = sIndex;\n - throw "ok";\n - }\n - ++sIndex;\n - }\n - btn.element.selectedIndex = 0;\n - } catch(ex) {}\n - }\n - break;\n -\n - // It\'s better to search for the format block by tag name from the\n - // current selection upwards, because IE has a tendancy to return\n - // things like \'heading 1\' for \'h1\', which breaks things if you want\n - // to call your heading blocks \'header 1\'. Stupid MS.\n - case "formatblock":\n - var blocks = [];\n - for ( var indexBlock in this.config.formatblock )\n - {\n - // prevent iterating over wrong type\n - if ( typeof this.config.formatblock[indexBlock] == \'string\' )\n - {\n - blocks[blocks.length] = this.config.formatblock[indexBlock];\n - }\n - }\n -\n - var deepestAncestor = this._getFirstAncestor(this.getSelection(), blocks);\n - if ( deepestAncestor )\n - {\n - for ( var x = 0; x < blocks.length; x++ )\n - {\n - if ( blocks[x].toLowerCase() == deepestAncestor.tagName.toLowerCase() )\n - {\n - btn.element.selectedIndex = x;\n - }\n - }\n - }\n - else\n - {\n - btn.element.selectedIndex = 0;\n - }\n - break;\n -\n - case "textindicator":\n - if ( !text )\n - {\n - try\n - {\n - var style = btn.element.style;\n - style.backgroundColor = Xinha._makeColor(doc.queryCommandValue(Xinha.is_ie ? "backcolor" : "hilitecolor"));\n - if ( /transparent/i.test(style.backgroundColor) )\n - {\n - // Mozilla\n - style.backgroundColor = Xinha._makeColor(doc.queryCommandValue("backcolor"));\n - }\n - style.color = Xinha._makeColor(doc.queryCommandValue("forecolor"));\n - style.fontFamily = doc.queryCommandValue("fontname");\n - style.fontWeight = doc.queryCommandState("bold") ? "bold" : "normal";\n - style.fontStyle = doc.queryCommandState("italic") ? "italic" : "normal";\n - } catch (ex) {\n - // alert(e + "\\n\\n" + cmd);\n - }\n - }\n - break;\n -\n - case "htmlmode":\n - btn.state("active", text);\n - break;\n -\n - case "lefttoright":\n - case "righttoleft":\n - var eltBlock = this.getParentElement();\n - while ( eltBlock && !Xinha.isBlockElement(eltBlock) )\n - {\n - eltBlock = eltBlock.parentNode;\n - }\n - if ( eltBlock )\n - {\n - btn.state("active", (eltBlock.style.direction == ((cmd == "righttoleft") ? "rtl" : "ltr")));\n - }\n - break;\n -\n - default:\n - cmd = cmd.replace(/(un)?orderedlist/i, "insert$1orderedlist");\n - try\n - {\n - btn.state("active", (!text && doc.queryCommandState(cmd)));\n - } catch (ex) {}\n - break;\n - }\n - }\n - // take undo snapshots\n - if ( this._customUndo && !this._timerUndo )\n - {\n - this._undoTakeSnapshot();\n - var editor = this;\n - this._timerUndo = setTimeout(function() { editor._timerUndo = null; }, this.config.undoTimeout);\n - }\n - this.firePluginEvent(\'onUpdateToolbar\');\n -};\n -\n -/** Returns a editor object referenced by the id or name of the textarea or the textarea node itself\n - * For example to retrieve the HTML of an editor made out of the textarea with the id "myTextArea" you would do<br />\n - * <code>\n - *\t var editor = Xinha.getEditor("myTextArea");\n - * var html = editor.getEditorContent(); \n - * </code>\n - * @returns {Xinha|null} \n - * @param {String|DomNode} ref id or name of the textarea or the textarea node itself\n - */\n -Xinha.getEditor = function(ref)\n -{\n - for ( var i = __xinhas.length; i--; )\n - {\n - var editor = __xinhas[i];\n - if ( editor && ( editor._textArea.id == ref || editor._textArea.name == ref || editor._textArea == ref ) )\n - {\n - return editor;\n - }\n - }\n - return null;\n -};\n -/** Sometimes one wants to call a plugin method directly, e.g. from outside the editor.\n - * This function returns the respective editor\'s instance of a plugin.\n - * For example you might want to have a button to trigger SaveSubmit\'s save() method:<br />\n - * <code>\n - *\t <button type="button" onclick="Xinha.getEditor(\'myTextArea\').getPluginInstance(\'SaveSubmit\').save();return false;">Save</button>\n - * </code>\n - * @returns {PluginObject|null} \n - * @param {String} plugin name of the plugin\n - */\n -Xinha.prototype.getPluginInstance = function (plugin)\n -{\n - if (this.plugins[plugin])\n - {\n - return this.plugins[plugin].instance;\n - }\n - else\n - {\n - return null;\n - }\n -};\n -/** Returns an array with all the ancestor nodes of the selection or current cursor position.\n -* @returns {Array}\n -*/\n -Xinha.prototype.getAllAncestors = function()\n -{\n - var p = this.getParentElement();\n - var a = [];\n - while ( p && (p.nodeType == 1) && ( p.tagName.toLowerCase() != \'body\' ) )\n - {\n - a.push(p);\n - p = p.parentNode;\n - }\n - a.push(this._doc.body);\n - return a;\n -};\n -\n -/** Traverses the DOM upwards and returns the first element that is of one of the specified types\n - * @param {Selection} sel Selection object as returned by getSelection\n - * @param {Array} types Array of matching criteria. Each criteria is either a string containing the tag name, or a callback used to select the element.\n - * @returns {DomNode|null} \n - */\n -Xinha.prototype._getFirstAncestor = function(sel, types)\n -{\n - var prnt = this.activeElement(sel);\n - if ( prnt === null )\n - {\n - // Hmm, I think Xinha.getParentElement() would do the job better?? - James\n - try\n - {\n - prnt = (Xinha.is_ie ? this.createRange(sel).parentElement() : this.createRange(sel).commonAncestorContainer);\n - }\n - catch(ex)\n - {\n - return null;\n - }\n - }\n -\n - if ( typeof types == \'string\' )\n - {\n - types = [types];\n - }\n -\n - while ( prnt )\n - {\n - if ( prnt.nodeType == 1 )\n - {\n - if ( types === null )\n - {\n - return prnt;\n - }\n - for (var index=0; index<types.length; ++index) {\n - if (typeof types[index] == \'string\' && types[index] == prnt.tagName.toLowerCase()){\n - // Criteria is a tag name. It matches\n - return prnt;\n - }\n - else if (typeof types[index] == \'function\' && types[index](this, prnt)) {\n - // Criteria is a callback. It matches\n - return prnt;\n - }\n - }\n -\n - if ( prnt.tagName.toLowerCase() == \'body\' )\n - {\n - break;\n - }\n - if ( prnt.tagName.toLowerCase() == \'table\' )\n - {\n - break;\n - }\n - }\n - prnt = prnt.parentNode;\n - }\n -\n - return null;\n -};\n -\n -/** Traverses the DOM upwards and returns the first element that is a block level element\n - * @param {Selection} sel Selection object as returned by getSelection\n - * @returns {DomNode|null} \n - */\n -Xinha.prototype._getAncestorBlock = function(sel)\n -{\n - // Scan upwards to find a block level element that we can change or apply to\n - var prnt = (Xinha.is_ie ? this.createRange(sel).parentElement : this.createRange(sel).commonAncestorContainer);\n -\n - while ( prnt && ( prnt.nodeType == 1 ) )\n - {\n - switch ( prnt.tagName.toLowerCase() )\n - {\n - case \'div\':\n - case \'p\':\n - case \'address\':\n - case \'blockquote\':\n - case \'center\':\n - case \'del\':\n - case \'ins\':\n - case \'pre\':\n - case \'h1\':\n - case \'h2\':\n - case \'h3\':\n - case \'h4\':\n - case \'h5\':\n - case \'h6\':\n - case \'h7\':\n - // Block Element\n - return prnt;\n -\n - case \'body\':\n - case \'noframes\':\n - case \'dd\':\n - case \'li\':\n - case \'th\':\n - case \'td\':\n - case \'noscript\' :\n - // Halting element (stop searching)\n - return null;\n -\n - default:\n - // Keep lookin\n - break;\n - }\n - }\n -\n - return null;\n -};\n -\n -/** What\'s this? does nothing, has to be removed\n - * \n - * @deprecated\n - */\n -Xinha.prototype._createImplicitBlock = function(type)\n -{\n - // expand it until we reach a block element in either direction\n - // then wrap the selection in a block and return\n - var sel = this.getSelection();\n - if ( Xinha.is_ie )\n - {\n - sel.empty();\n - }\n - else\n - {\n - sel.collapseToStart();\n - }\n -\n - var rng = this.createRange(sel);\n -\n - // Expand UP\n -\n - // Expand DN\n -};\n -\n -\n -\n -/**\n - * Call this function to surround the existing HTML code in the selection with\n - * your tags. FIXME: buggy! Don\'t use this \n - * @todo: when will it be deprecated ? Can it be removed already ?\n - * @private (tagged private to not further promote use of this function)\n - * @deprecated\n - */\n -Xinha.prototype.surroundHTML = function(startTag, endTag)\n -{\n - var html = this.getSelectedHTML();\n - // the following also deletes the selection\n - this.insertHTML(startTag + html + endTag);\n -};\n -\n -/** Return true if we have some selection\n - * @returns {Boolean} \n - */\n -Xinha.prototype.hasSelectedText = function()\n -{\n - // FIXME: come _on_ mishoo, you can do better than this ;-)\n - return this.getSelectedHTML() !== \'\';\n -};\n -\n -/***************************************************\n - * Category: EVENT HANDLERS\n - ***************************************************/\n -\n -/** onChange handler for dropdowns in toolbar \n - * @private\n - * @param {DomNode} el Reference to the SELECT object\n - * @param {String} txt The name of the select field, as in config.toolbar\n - * @returns {DomNode|null} \n - */\n -Xinha.prototype._comboSelected = function(el, txt)\n -{\n - this.focusEditor();\n - var value = el.options[el.selectedIndex].value;\n - switch (txt)\n - {\n - case "fontname":\n - case "fontsize":\n - this.execCommand(txt, false, value);\n - break;\n - case "formatblock":\n - // Mozilla inserts an empty tag (<>) if no parameter is passed \n - if ( !value )\n - {\n - \tthis.updateToolbar();\n - \tbreak;\n - }\n - if( !Xinha.is_gecko || value !== \'blockquote\' )\n - {\n - value = "<" + value + ">";\n - }\n - this.execCommand(txt, false, value);\n - break;\n - default:\n - // try to look it up in the registered dropdowns\n - var dropdown = this.config.customSelects[txt];\n - if ( typeof dropdown != "undefined" )\n - {\n - dropdown.action(this, value, el, txt);\n - }\n - else\n - {\n - alert("FIXME: combo box " + txt + " not implemented");\n - }\n - break;\n - }\n -};\n -\n -/** Open a popup to select the hilitecolor or forecolor\n - * @private\n - * @param {String} cmdID The commande ID (hilitecolor or forecolor)\n - */\n -Xinha.prototype._colorSelector = function(cmdID)\n -{\n - var editor = this;\t// for nested functions\n -\n - // backcolor only works with useCSS/styleWithCSS (see mozilla bug #279330 & Midas doc)\n - // and its also nicer as <font>\n - if ( Xinha.is_gecko )\n - {\n - try\n - {\n - editor._doc.execCommand(\'useCSS\', false, false); // useCSS deprecated & replaced by styleWithCSS \n - editor._doc.execCommand(\'styleWithCSS\', false, true); \n -\n - } catch (ex) {}\n - }\n - \n - var btn = editor._toolbarObjects[cmdID].element;\n - var initcolor;\n - if ( cmdID == \'hilitecolor\' )\n - {\n - if ( Xinha.is_ie )\n - {\n - cmdID = \'backcolor\';\n - initcolor = Xinha._colorToRgb(editor._doc.queryCommandValue("backcolor"));\n - }\n - else\n - {\n - initcolor = Xinha._colorToRgb(editor._doc.queryCommandValue("hilitecolor"));\n - }\n - }\n - else\n - {\n - \tinitcolor = Xinha._colorToRgb(editor._doc.queryCommandValue("forecolor"));\n - }\n - var cback = function(color) { editor._doc.execCommand(cmdID, false, color); };\n - if ( Xinha.is_ie )\n - {\n - var range = editor.createRange(editor.getSelection());\n - cback = function(color)\n - {\n - range.select();\n - editor._doc.execCommand(cmdID, false, color);\n - };\n - }\n - var picker = new Xinha.colorPicker(\n - {\n - \tcellsize:editor.config.colorPickerCellSize,\n - \tcallback:cback,\n - \tgranularity:editor.config.colorPickerGranularity,\n - \twebsafe:editor.config.colorPickerWebSafe,\n - \tsavecolors:editor.config.colorPickerSaveColors\n - });\n - picker.open(editor.config.colorPickerPosition, btn, initcolor);\n -};\n -\n -/** This is a wrapper for the browser\'s execCommand function that handles things like \n - * formatting, inserting elements, etc.<br />\n - * It intercepts some commands and replaces them with our own implementation.<br />\n - * It provides a hook for the "firePluginEvent" system ("onExecCommand").<br /><br />\n - * For reference see:<br />\n - * <a href="http://www.mozilla.org/editor/midas-spec.html">Mozilla implementation</a><br />\n - * <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/execcommand.asp">MS implementation</a>\n - *\n - * @see Xinha#firePluginEvent\n - * @param {String} cmdID command to be executed as defined in the browsers implemantations or Xinha custom\n - * @param {Boolean} UI for compatibility with the execCommand syntax; false in most (all) cases\n - * @param {Mixed} param Some commands require parameters\n - * @returns {Boolean} always false \n - */\n -Xinha.prototype.execCommand = function(cmdID, UI, param)\n -{\n - var editor = this;\t// for nested functions\n - this.focusEditor();\n - cmdID = cmdID.toLowerCase();\n - \n - // See if any plugins want to do something special\n - if(this.firePluginEvent(\'onExecCommand\', cmdID, UI, param))\n - {\n - this.updateToolbar();\n - return false;\n - }\n -\n - switch (cmdID)\n - {\n - case "htmlmode":\n - this.setMode();\n - break;\n -\n - case "hilitecolor":\n - case "forecolor":\n - this._colorSelector(cmdID);\n - break;\n -\n - case "createlink":\n - this._createLink();\n - break;\n -\n - case "undo":\n - case "redo":\n - if (this._customUndo)\n - {\n - this[cmdID]();\n - }\n - else\n - {\n - this._doc.execCommand(cmdID, UI, param);\n - }\n - break;\n -\n - case "inserttable":\n - this._insertTable();\n - break;\n -\n - case "insertimage":\n - this._insertImage();\n - break;\n -\n - case "showhelp":\n - this._popupDialog(editor.config.URIs.help, null, this);\n - break;\n -\n - case "killword":\n - this._wordClean();\n - break;\n -\n - case "cut":\n - case "copy":\n - case "paste":\n - this._doc.execCommand(cmdID, UI, param);\n - if ( this.config.killWordOnPaste )\n - {\n - this._wordClean();\n - }\n - break;\n - case "lefttoright":\n - case "righttoleft":\n - if (this.config.changeJustifyWithDirection) \n - {\n - this._doc.execCommand((cmdID == "righttoleft") ? "justifyright" : "justifyleft", UI, param);\n - }\n - var dir = (cmdID == "righttoleft") ? "rtl" : "ltr";\n - var el = this.getParentElement();\n - while ( el && !Xinha.isBlockElement(el) )\n - {\n - el = el.parentNode;\n - }\n - if ( el )\n - {\n - if ( el.style.direction == dir )\n - {\n - el.style.direction = "";\n - }\n - else\n - {\n - el.style.direction = dir;\n - }\n - }\n - break;\n - \n - case \'justifyleft\' :\n - case \'justifyright\' :\n - cmdID.match(/^justify(.*)$/);\n - var ae = this.activeElement(this.getSelection()); \n - if(ae && ae.tagName.toLowerCase() == \'img\')\n - {\n - ae.align = ae.align == RegExp.$1 ? \'\' : RegExp.$1;\n - }\n - else\n - {\n - this._doc.execCommand(cmdID, UI, param);\n - }\n - break;\n - \n - default:\n - try\n - {\n - this._doc.execCommand(cmdID, UI, param);\n - }\n - catch(ex)\n - {\n - if ( this.config.debug )\n - {\n - alert(ex + "\\n\\nby execCommand(" + cmdID + ");");\n - }\n - }\n - break;\n - }\n -\n - this.updateToolbar();\n - return false;\n -};\n -\n -/** A generic event handler for things that happen in the IFRAME\'s document.<br />\n - * It provides two hooks for the "firePluginEvent" system:<br />\n - * "onKeyPress"<br />\n - * "onMouseDown"\n - * @see Xinha#firePluginEvent\n - * @param {Event} ev\n - */\n -Xinha.prototype._editorEvent = function(ev)\n -{\n - var editor = this;\n -\n - //call events of textarea\n - if ( typeof editor._textArea[\'on\'+ev.type] == "function" )\n - {\n - editor._textArea[\'on\'+ev.type](ev);\n - }\n - \n - if ( this.isKeyEvent(ev) )\n - {\n - // Run the ordinary plugins first\n - if(editor.firePluginEvent(\'onKeyPress\', ev))\n - {\n - return false;\n - }\n - \n - // Handle the core shortcuts\n - if ( this.isShortCut( ev ) )\n - {\n - this._shortCuts(ev);\n - }\n - }\n -\n - if ( ev.type == \'mousedown\' )\n - {\n - if(editor.firePluginEvent(\'onMouseDown\', ev))\n - {\n - return false;\n - }\n - }\n -\n - // update the toolbar state after some time\n - if ( editor._timerToolbar )\n - {\n - clearTimeout(editor._timerToolbar);\n - }\n - if (!this.suspendUpdateToolbar)\n - {\n - editor._timerToolbar = setTimeout(\n - function()\n - {\n - editor.updateToolbar();\n - editor._timerToolbar = null;\n - },\n - 250);\n - }\n -};\n -\n -/** Handle double click events.\n - * See dblclickList in the config.\n - */\n - \n -Xinha.prototype._onDoubleClick = function(ev)\n -{\n - var editor=this;\n - var target = Xinha.is_ie ? ev.srcElement : ev.target;\n - var tag = target.tagName;\n - var className = target.className;\n - if (tag) {\n - tag = tag.toLowerCase();\n - if (className && (this.config.dblclickList[tag+"."+className] != undefined))\n - this.config.dblclickList[tag+"."+className][0](editor, target);\n - else if (this.config.dblclickList[tag] != undefined)\n - this.config.dblclickList[tag][0](editor, target);\n - };\n -};\n -\n -/** Handles ctrl + key shortcuts \n - * @TODO: make this mor flexible\n - * @private\n - * @param {Event} ev\n - */\n -Xinha.prototype._shortCuts = function (ev)\n -{\n - var key = this.getKey(ev).toLowerCase();\n - var cmd = null;\n - var value = null;\n - switch (key)\n - {\n - // simple key commands follow\n -\n - case \'b\': cmd = "bold"; break;\n - case \'i\': cmd = "italic"; break;\n - case \'u\': cmd = "underline"; break;\n - case \'s\': cmd = "strikethrough"; break;\n - case \'l\': cmd = "justifyleft"; break;\n - case \'e\': cmd = "justifycenter"; break;\n - case \'r\': cmd = "justifyright"; break;\n - case \'j\': cmd = "justifyfull"; break;\n - case \'z\': cmd = "undo"; break;\n - case \'y\': cmd = "redo"; break;\n - case \'v\': cmd = "paste"; break;\n - case \'n\':\n - cmd = "formatblock";\n - value = "p";\n - break;\n -\n - case \'0\': cmd = "killword"; break;\n -\n - // headings\n - case \'1\':\n - case \'2\':\n - case \'3\':\n - case \'4\':\n - case \'5\':\n - case \'6\':\n - cmd = "formatblock";\n - value = "h" + key;\n - break;\n - }\n - if ( cmd )\n - {\n - // execute simple command\n - this.execCommand(cmd, false, value);\n - Xinha._stopEvent(ev);\n - }\n -};\n -/** Changes the type of a given node\n - * @param {DomNode} el The element to convert\n - * @param {String} newTagName The type the element will be converted to\n - * @returns {DomNode} A reference to the new element\n - */\n -Xinha.prototype.convertNode = function(el, newTagName)\n -{\n - var newel = this._doc.createElement(newTagName);\n - while ( el.firstChild )\n - {\n - newel.appendChild(el.firstChild);\n - }\n - return newel;\n -};\n -\n -/** Scrolls the editor iframe to a given element or to the cursor\n - * @param {DomNode} e optional The element to scroll to; if ommitted, element the element the cursor is in\n - */\n -Xinha.prototype.scrollToElement = function(e)\n -{\n - if(!e)\n - {\n - e = this.getParentElement();\n - if(!e)\n - {\n - return;\n - }\n - }\n - \n - // This was at one time limited to Gecko only, but I see no reason for it to be. - James\n - var position = Xinha.getElementTopLeft(e); \n - this._iframe.contentWindow.scrollTo(position.left, position.top);\n -};\n -\n -/** Get the edited HTML\n - * \n - * @public\n - * @returns {String} HTML content\n - */\n -Xinha.prototype.getEditorContent = function()\n -{\n - return this.outwardHtml(this.getHTML());\n -};\n -\n -/** Completely change the HTML inside the editor\n - *\n - * @public\n - * @param {String} html new content\n - */\n -Xinha.prototype.setEditorContent = function(html)\n -{\n - this.setHTML(this.inwardHtml(html));\n -};\n -/** Saves the contents of all Xinhas to their respective textareas\n - * @public \n - */\n -Xinha.updateTextareas = function()\n -{\n - var e;\n - for (var i=0;i<__xinhas.length;i++)\n - {\n - e = __xinhas[i];\n - e._textArea.value = e.getEditorContent();\n - }\n -}\n -/** Get the raw edited HTML, should not be used without Xinha.prototype.outwardHtml()\n - * \n - * @private\n - * @returns {String} HTML content\n - */\n -Xinha.prototype.getHTML = function()\n -{\n - var html = \'\';\n - switch ( this._editMode )\n - {\n - case "wysiwyg":\n - if ( !this.config.fullPage )\n - {\n - html = Xinha.getHTML(this._doc.body, false, this).trim();\n - }\n - else\n - {\n - html = this.doctype + "\\n" + Xinha.getHTML(this._doc.documentElement, true, this);\n - }\n - break;\n - case "textmode":\n - html = this._textArea.value;\n - break;\n - default:\n - alert("Mode <" + this._editMode + "> not defined!");\n - return false;\n - }\n - return html;\n -};\n -\n -/** Performs various transformations of the HTML used internally, complement to Xinha.prototype.inwardHtml() \n - * Plugins can provide their own, additional transformations by defining a plugin.prototype.outwardHtml() implematation,\n - * which is called by this function\n - *\n - * @private\n - * @see Xinha#inwardHtml\n - * @param {String} html\n - * @returns {String} HTML content\n - */\n -Xinha.prototype.outwardHtml = function(html)\n -{\n - for ( var i in this.plugins )\n - {\n - var plugin = this.plugins[i].instance; \n - if ( plugin && typeof plugin.outwardHtml == "function" )\n - {\n - html = plugin.outwardHtml(html);\n - }\n - }\n - \n - html = html.replace(/<(\\/?)b(\\s|>|\\/)/ig, "<$1strong$2");\n - html = html.replace(/<(\\/?)i(\\s|>|\\/)/ig, "<$1em$2");\n - html = html.replace(/<(\\/?)strike(\\s|>|\\/)/ig, "<$1del$2");\n - \n - // remove disabling of inline event handle inside Xinha iframe\n - html = html.replace(/(<[^>]*on(click|mouse(over|out|up|down))=[\'"])if\\(window\\.parent && window\\.parent\\.Xinha\\)\\{return false\\}/gi,\'$1\');\n -\n - // Figure out what our server name is, and how it\'s referenced\n - var serverBase = location.href.replace(/(https?:\\/\\/[^\\/]*)\\/.*/, \'$1\') + \'/\';\n -\n - // IE puts this in can\'t figure out why\n - // leaving this in the core instead of InternetExplorer \n - // because it might be something we are doing so could present itself\n - // in other browsers - James \n - html = html.replace(/https?:\\/\\/null\\//g, serverBase);\n -\n - // Make semi-absolute links to be truely absolute\n - // we do this just to standardize so that special replacements knows what\n - // to expect\n - html = html.replace(/((href|src|background)=[\\\'\\"])\\/+/ig, \'$1\' + serverBase);\n -\n - html = this.outwardSpecialReplacements(html);\n -\n - html = this.fixRelativeLinks(html);\n -\n - if ( this.config.sevenBitClean )\n - {\n - html = html.replace(/[^ -~\\r\\n\\t]/g, function(c) { return (c != Xinha.cc) ? \'&#\'+c.charCodeAt(0)+\';\' : c; });\n - }\n -\n - //prevent execution of JavaScript (Ticket #685)\n - html = html.replace(/(<script[^>]*((type=[\\"\\\']text\\/)|(language=[\\"\\\'])))(freezescript)/gi,"$1javascript");\n -\n - // If in fullPage mode, strip the coreCSS\n - if(this.config.fullPage)\n - {\n - html = Xinha.stripCoreCSS(html);\n - }\n -\n - if (typeof this.config.outwardHtml == \'function\' )\n - {\n - html = this.config.outwardHtml(html);\n - }\n -\n - return html;\n -};\n -\n -/** Performs various transformations of the HTML to be edited \n - * Plugins can provide their own, additional transformations by defining a plugin.prototype.inwardHtml() implematation,\n - * which is called by this function\n - * \n - * @private\n - * @see Xinha#outwardHtml\n - * @param {String} html \n - * @returns {String} transformed HTML\n - */\n -Xinha.prototype.inwardHtml = function(html)\n -{ \n - for ( var i in this.plugins )\n - {\n - var plugin = this.plugins[i].instance; \n - if ( plugin && typeof plugin.inwardHtml == "function" )\n - {\n - html = plugin.inwardHtml(html);\n - } \n - }\n - \n - // Both IE and Gecko use strike instead of del (#523)\n - html = html.replace(/<(\\/?)del(\\s|>|\\/)/ig, "<$1strike$2");\n -\n - // disable inline event handle inside Xinha iframe\n - html = html.replace(/(<[^>]*on(click|mouse(over|out|up|down))=["\'])/gi,\'$1if(window.parent && window.parent.Xinha){return false}\');\n - \n - html = this.inwardSpecialReplacements(html);\n -\n - html = html.replace(/(<script[^>]*((type=[\\"\\\']text\\/)|(language=[\\"\\\'])))(javascript)/gi,"$1freezescript");\n -\n - // For IE\'s sake, make any URLs that are semi-absolute (="/....") to be\n - // truely absolute\n - var nullRE = new RegExp(\'((href|src|background)=[\\\'"])/+\', \'gi\');\n - html = html.replace(nullRE, \'$1\' + location.href.replace(/(https?:\\/\\/[^\\/]*)\\/.*/, \'$1\') + \'/\');\n -\n - html = this.fixRelativeLinks(html);\n - \n - // If in fullPage mode, add the coreCSS\n - if(this.config.fullPage)\n - {\n - html = Xinha.addCoreCSS(html);\n - }\n -\n - if (typeof this.config.inwardHtml == \'function\' )\n - {\n - html = this.config.inwardHtml(html);\n - }\n -\n - return html;\n -};\n -/** Apply the replacements defined in Xinha.Config.specialReplacements\n - * \n - * @private\n - * @see Xinha#inwardSpecialReplacements\n - * @param {String} html\n - * @returns {String} transformed HTML\n - */\n -Xinha.prototype.outwardSpecialReplacements = function(html)\n -{\n - for ( var i in this.config.specialReplacements )\n - {\n - var from = this.config.specialReplacements[i];\n - var to = i; // why are declaring a new variable here ? Seems to be better to just do : for (var to in config)\n - // prevent iterating over wrong type\n - if ( typeof from.replace != \'function\' || typeof to.replace != \'function\' )\n - {\n - continue;\n - } \n - // alert(\'out : \' + from + \'=>\' + to);\n - var reg = new RegExp(Xinha.escapeStringForRegExp(from), \'g\');\n - html = html.replace(reg, to.replace(/\\$/g, \'$$$$\'));\n - //html = html.replace(from, to);\n - }\n - return html;\n -};\n -/** Apply the replacements defined in Xinha.Config.specialReplacements\n - * \n - * @private\n - * @see Xinha#outwardSpecialReplacements\n - * @param {String} html\n - * @returns {String} transformed HTML\n - */\n -Xinha.prototype.inwardSpecialReplacements = function(html)\n -{\n - // alert("inward");\n - for ( var i in this.config.specialReplacements )\n - {\n - var from = i; // why are declaring a new variable here ? Seems to be better to just do : for (var from in config)\n - var to = this.config.specialReplacements[i];\n - // prevent iterating over wrong type\n - if ( typeof from.replace != \'function\' || typeof to.replace != \'function\' )\n - {\n - continue;\n - }\n - // alert(\'in : \' + from + \'=>\' + to);\n - //\n - // html = html.replace(reg, to);\n - // html = html.replace(from, to);\n - var reg = new RegExp(Xinha.escapeStringForRegExp(from), \'g\');\n - html = html.replace(reg, to.replace(/\\$/g, \'$$$$\')); // IE uses doubled dollar signs to escape backrefs, also beware that IE also implements $& $_ and $\' like perl.\n - }\n - return html;\n -};\n -/** Transforms the paths in src & href attributes\n - * \n - * @private\n - * @see Xinha.Config#expandRelativeUrl\n - * @see Xinha.Config#stripSelfNamedAnchors\n - * @see Xinha.Config#stripBaseHref\n - * @see Xinha.Config#baseHref\n - * @param {String} html \n - * @returns {String} transformed HTML\n - */\n -Xinha.prototype.fixRelativeLinks = function(html)\n -{\n - if ( typeof this.config.expandRelativeUrl != \'undefined\' && this.config.expandRelativeUrl ) \n - {\n - if (html == null)\n - {\n - return "";\n - }\n - var src = html.match(/(src|href)="([^"]*)"/gi);\n - var b = document.location.href;\n - if ( src )\n - {\n - var url,url_m,relPath,base_m,absPath;\n - for ( var i=0;i<src.length;++i )\n - {\n - url = src[i].match(/(src|href)="([^"]*)"/i);\n - url_m = url[2].match( /\\.\\.\\//g );\n - if ( url_m )\n - {\n - relPath = new RegExp( "(.*?)(([^\\/]*\\/){"+ url_m.length+"})[^\\/]*$" );\n - base_m = b.match( relPath );\n - absPath = url[2].replace(/(\\.\\.\\/)*/,base_m[1]);\n - html = html.replace( new RegExp(Xinha.escapeStringForRegExp(url[2])),absPath );\n - }\n - }\n - }\n - }\n - \n - if ( typeof this.config.stripSelfNamedAnchors != \'undefined\' && this.config.stripSelfNamedAnchors )\n - {\n - var stripRe = new RegExp("((href|src|background)=\\")("+Xinha.escapeStringForRegExp(window.unescape(document.location.href.replace(/&/g,\'&\'))) + \')([#?][^\\\'" ]*)\', \'g\');\n - html = html.replace(stripRe, \'$1$4\');\n - }\n -\n - if ( typeof this.config.stripBaseHref != \'undefined\' && this.config.stripBaseHref )\n - {\n - var baseRe = null;\n - if ( typeof this.config.baseHref != \'undefined\' && this.config.baseHref !== null )\n - {\n - baseRe = new RegExp( "((href|src|background|action)=\\")(" + Xinha.escapeStringForRegExp(this.config.baseHref.replace(/([^\\/]\\/)(?=.+\\.)[^\\/]*$/, "$1")) + ")", \'g\' );\n -\t html = html.replace(baseRe, \'$1\');\n - }\n - baseRe = new RegExp( "((href|src|background|action)=\\")(" + Xinha.escapeStringForRegExp(document.location.href.replace( /^(https?:\\/\\/[^\\/]*)(.*)/, \'$1\' )) + ")", \'g\' );\n - html = html.replace(baseRe, \'$1\');\n - }\n -\n - return html;\n -};\n -\n -/** retrieve the HTML (fastest version, but uses innerHTML)\n - * \n - * @private\n - * @returns {String} HTML content\n - */\n -Xinha.prototype.getInnerHTML = function()\n -{\n - if ( !this._doc.body )\n - {\n - return \'\';\n - }\n - var html = "";\n - switch ( this._editMode )\n - {\n - case "wysiwyg":\n - if ( !this.config.fullPage )\n - {\n - // return this._doc.body.innerHTML;\n - html = this._doc.body.innerHTML;\n - }\n - else\n - {\n - html = this.doctype + "\\n" + this._doc.documentElement.innerHTML;\n - }\n - break;\n - case "textmode" :\n - html = this._textArea.value;\n - break;\n - default:\n - alert("Mode <" + this._editMode + "> not defined!");\n - return false;\n - }\n -\n - return html;\n -};\n -\n -/** Completely change the HTML inside\n - *\n - * @private\n - * @param {String} html new content, should have been run through inwardHtml() first\n - */\n -Xinha.prototype.setHTML = function(html)\n -{\n - if ( !this.config.fullPage )\n - {\n - this._doc.body.innerHTML = html;\n - }\n - else\n - {\n - this.setFullHTML(html);\n - }\n - this._textArea.value = html;\n -};\n -\n -/** sets the given doctype (useful only when config.fullPage is true)\n - * \n - * @private\n - * @param {String} doctype\n - */\n -Xinha.prototype.setDoctype = function(doctype)\n -{\n - this.doctype = doctype;\n -};\n -\n -/***************************************************\n - * Category: UTILITY FUNCTIONS\n - ***************************************************/\n -\n -/** Variable used to pass the object to the popup editor window.\n - * @FIXME: Is this in use?\n - * @deprecated \n - * @private\n - * @type {Object}\n - */\n -Xinha._object = null;\n -\n -/** Arrays are identified as "object" in typeof calls. Adding this tag to the Array prototype allows to distinguish between the two\n - */\n -Array.prototype.isArray = true;\n -/** RegExps are identified as "object" in typeof calls. Adding this tag to the RegExp prototype allows to distinguish between the two\n - */\n -RegExp.prototype.isRegExp = true;\n -/** function that returns a clone of the given object\n - * \n - * @private\n - * @param {Object} obj\n - * @returns {Object} cloned object\n - */\n -Xinha.cloneObject = function(obj)\n -{\n - if ( !obj )\n - {\n - return null;\n - }\n - var newObj = obj.isArray ? [] : {};\n -\n - // check for function and RegExp objects (as usual, IE is fucked up)\n - if ( obj.constructor.toString().match( /\\s*function Function\\(/ ) || typeof obj == \'function\' )\n - {\n - newObj = obj; // just copy reference to it\n - }\n - else if ( obj.isRegExp )\n - {\n - newObj = eval( obj.toString() ); //see no way without eval\n - }\n - else\n - {\n - for ( var n in obj )\n - {\n - var node = obj[n];\n - if ( typeof node == \'object\' )\n - {\n - newObj[n] = Xinha.cloneObject(node);\n - }\n - else\n - {\n - newObj[n] = node;\n - }\n - }\n - }\n -\n - return newObj;\n -};\n -\n -\n -/** Extend one class from another, that is, make a sub class.\n - * This manner of doing it was probably first devised by Kevin Lindsey\n - *\n - * http://kevlindev.com/tutorials/javascript/inheritance/index.htm\n - *\n - * It has subsequently been used in one form or another by various toolkits \n - * such as the YUI.\n - *\n - * I make no claim as to understanding it really, but it works.\n - * \n - * Example Usage:\n - * {{{\n - * -------------------------------------------------------------------------\n - \n - // ========= MAKING THE INITIAL SUPER CLASS ===========\n - \n - document.write("<h1>Superclass Creation And Test</h1>");\n - \n - function Vehicle(name, sound)\n - { \n - this.name = name;\n - this.sound = sound\n - }\n - \n - Vehicle.prototype.pressHorn = function()\n - {\n - document.write(this.name + \': \' + this.sound + \'<br/>\');\n - }\n - \n - var Bedford = new Vehicle(\'Bedford Van\', \'Honk Honk\');\n - Bedford.pressHorn(); // Vehicle::pressHorn() is defined\n - \n - \n - // ========= MAKING A SUBCLASS OF A SUPER CLASS =========\n - \n - document.write("<h1>Subclass Creation And Test</h1>");\n - \n - // Make the sub class constructor first\n - Car = function(name)\n - {\n - // This is how we call the parent\'s constructor, note that\n - // we are using Car.parent.... not "this", we can\'t use this.\n - Car.parentConstructor.call(this, name, \'Toot Toot\');\n - }\n - \n - // Remember the subclass comes first, then the base class, you are extending\n - // Car with the methods and properties of Vehicle.\n - Xinha.extend(Car, Vehicle);\n - \n - var MazdaMx5 = new Car(\'Mazda MX5\'); \n - MazdaMx5.pressHorn(); // Car::pressHorn() is inherited from Vehicle::pressHorn()\n - \n - // ========= ADDING METHODS TO THE SUB CLASS ===========\n -\n - document.write("<h1>Add Method to Sub Class And Test</h1>");\n - \n - Car.prototype.isACar = function()\n - {\n - document.write(this.name + ": Car::isACar() is implemented, this is a car! <br/>");\n - this.pressHorn();\n - }\n - \n - MazdaMx5.isACar(); // Car::isACar() is defined as above\n - try { Bedford.isACar(); } // Vehicle::isACar() is not defined, will throw this exception\n - catch(e) { document.write("Bedford: Vehicle::onGettingCutOff() not implemented, this is not a car!<br/>"); }\n - \n - // ========= EXTENDING A METHOD (CALLING MASKED PARENT METHODS) ===========\n - \n - document.write("<h1>Extend/Override Inherited Method in Sub Class And Test</h1>");\n - \n - Car.prototype.pressHorn = function()\n - { \n - document.write(this.name + \': I am going to press the horn... <br/>\');\n - Car.superClass.pressHorn.call(this); \n - }\n - MazdaMx5.pressHorn(); // Car::pressHorn()\n - Bedford.pressHorn(); // Vehicle::pressHorn()\n - \n - // ========= MODIFYING THE SUPERCLASS AFTER SUBCLASSING ===========\n - \n - document.write("<h1>Add New Method to Superclass And Test In Subclass</h1>"); \n - \n - Vehicle.prototype.startUp = function() { document.write(this.name + ": Vroooom <br/>"); } \n - MazdaMx5.startUp(); // Cars get the prototype\'d startUp() also.\n - \n - * -------------------------------------------------------------------------\n - * }}} \n - *\n - * @param subclass_constructor (optional) Constructor function for the subclass\n - * @param superclass Constructor function for the superclass \n - */\n -\n -Xinha.extend = function(subClass, baseClass) {\n - function inheritance() {}\n - inheritance.prototype = baseClass.prototype;\n -\n - subClass.prototype = new inheritance();\n - subClass.prototype.constructor = subClass;\n - subClass.parentConstructor = baseClass;\n - subClass.superClass = baseClass.prototype;\n -}\n -\n -/** Event Flushing\n - * To try and work around memory leaks in the rather broken\n - * garbage collector in IE, Xinha.flushEvents can be called\n - * onunload, it will remove any event listeners (that were added\n - * through _addEvent(s)) and clear any DOM-0 events.\n - * @private\n - *\n - */\n -Xinha.flushEvents = function()\n -{\n - var x = 0;\n - // @todo : check if Array.prototype.pop exists for every supported browsers\n - var e = Xinha._eventFlushers.pop();\n - while ( e )\n - {\n - try\n - {\n - if ( e.length == 3 )\n - {\n - Xinha._removeEvent(e[0], e[1], e[2]);\n - x++;\n - }\n - else if ( e.length == 2 )\n - {\n - e[0][\'on\' + e[1]] = null;\n - e[0]._xinha_dom0Events[e[1]] = null;\n - x++;\n - }\n - }\n - catch(ex)\n - {\n - // Do Nothing\n - }\n - e = Xinha._eventFlushers.pop();\n - }\n - \n - /* \n - // This code is very agressive, and incredibly slow in IE, so I\'ve disabled it.\n - \n - if(document.all)\n - {\n - for(var i = 0; i < document.all.length; i++)\n - {\n - for(var j in document.all[i])\n - {\n - if(/^on/.test(j) && typeof document.all[i][j] == \'function\')\n - {\n - document.all[i][j] = null;\n - x++;\n - }\n - }\n - }\n - }\n - */\n - \n - // alert(\'Flushed \' + x + \' events.\');\n -};\n - /** Holds the events to be flushed\n - * @type Array\n - */\n -Xinha._eventFlushers = [];\n -\n -if ( document.addEventListener )\n -{\n - /** adds an event listener for the specified element and event type\n - * \n - * @public\n - * @see Xinha#_addEvents\n - * @see Xinha#addDom0Event\n - * @see Xinha#prependDom0Event\n - * @param {DomNode} el the DOM element the event should be attached to \n - * @param {String} evname the name of the event to listen for (without leading "on")\n - * @param {function} func the function to be called when the event is fired\n - */\n - Xinha._addEvent = function(el, evname, func)\n - {\n - el.addEventListener(evname, func, false);\n - Xinha._eventFlushers.push([el, evname, func]);\n - };\n - \n - /** removes an event listener previously added\n - * \n - * @public\n - * @see Xinha#_removeEvents\n - * @param {DomNode} el the DOM element the event should be removed from \n - * @param {String} evname the name of the event the listener should be removed from (without leading "on")\n - * @param {function} func the function to be removed\n - */\n - Xinha._removeEvent = function(el, evname, func)\n - {\n - el.removeEventListener(evname, func, false);\n - };\n - \n - /** stops bubbling of the event, if no further listeners should be triggered\n - * \n - * @public\n - * @param {event} ev the event to be stopped\n - */\n - Xinha._stopEvent = function(ev)\n - {\n - ev.preventDefault();\n - ev.stopPropagation();\n - };\n -}\n - /** same as above, for IE\n - * \n - */\n -else if ( document.attachEvent )\n -{\n - Xinha._addEvent = function(el, evname, func)\n - {\n - el.attachEvent("on" + evname, func);\n - Xinha._eventFlushers.push([el, evname, func]);\n - };\n - Xinha._removeEvent = function(el, evname, func)\n - {\n - el.detachEvent("on" + evname, func);\n - };\n - Xinha._stopEvent = function(ev)\n - {\n - try\n - {\n - ev.cancelBubble = true;\n - ev.returnValue = false;\n - }\n - catch (ex)\n - {\n - // Perhaps we could try here to stop the window.event\n - // window.event.cancelBubble = true;\n - // window.event.returnValue = false;\n - }\n - };\n -}\n -else\n -{\n - Xinha._addEvent = function(el, evname, func)\n - {\n - alert(\'_addEvent is not supported\');\n - };\n - Xinha._removeEvent = function(el, evname, func)\n - {\n - alert(\'_removeEvent is not supported\');\n - };\n - Xinha._stopEvent = function(ev)\n - {\n - alert(\'_stopEvent is not supported\');\n - };\n -}\n - /** add several events at once to one element\n - * \n - * @public\n - * @see Xinha#_addEvent\n - * @param {DomNode} el the DOM element the event should be attached to \n - * @param {Array} evs the names of the event to listen for (without leading "on")\n - * @param {function} func the function to be called when the event is fired\n - */\n -Xinha._addEvents = function(el, evs, func)\n -{\n - for ( var i = evs.length; --i >= 0; )\n - {\n - Xinha._addEvent(el, evs[i], func);\n - }\n -};\n - /** remove several events at once to from element\n - * \n - * @public\n - * @see Xinha#_removeEvent\n - * @param {DomNode} el the DOM element the events should be remove from\n - * @param {Array} evs the names of the events the listener should be removed from (without leading "on")\n - * @param {function} func the function to be removed\n - */\n -Xinha._removeEvents = function(el, evs, func)\n -{\n - for ( var i = evs.length; --i >= 0; )\n - {\n - Xinha._removeEvent(el, evs[i], func);\n - }\n -};\n -\n -/** Adds a function that is executed in the moment the DOM is ready, but as opposed to window.onload before images etc. have been loaded\n -* http://dean.edwards.name/weblog/2006/06/again/\n -* IE part from jQuery\n -* @public\n -* @author Dean Edwards/Matthias Miller/ John Resig / Diego Perini\n -* @param {Function} func the function to be executed\n -* @param {Window} scope the window that is listened to\n -*/\n -Xinha.addOnloadHandler = function (func, scope)\n -{\n - scope = scope ? scope : window;\n -\n - var init = function ()\n - {\n - // quit if this function has already been called\n - if (arguments.callee.done) \n - {\n - return;\n - }\n - // flag this function so we don\'t do the same thing twice\n - arguments.callee.done = true;\n - // kill the timer\n - if (Xinha.onloadTimer)\n - {\n - clearInterval(Xinha.onloadTimer);\n - }\n -\n - func();\n - };\n - if (Xinha.is_ie)\n - {\n - // ensure firing before onload,\n - // maybe late but safe also for iframes\n - document.attachEvent("onreadystatechange", function(){\n - if ( document.readyState === "complete" ) {\n - document.detachEvent( "onreadystatechange", arguments.callee );\n - init();\n - }\n - });\n - if ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){\n - if (arguments.callee.done) return;\n - try {\n - // If IE is used, use the trick by Diego Perini\n - // http://javascript.nwbox.com/IEContentLoaded/\n - document.documentElement.doScroll("left");\n - } catch( error ) {\n - setTimeout( arguments.callee, 0 );\n - return;\n - }\n - // and execute any waiting functions\n - init();\n - })();\n - }\n - else if (/applewebkit|KHTML/i.test(navigator.userAgent) ) /* Safari/WebKit/KHTML */\n - {\n - Xinha.onloadTimer = scope.setInterval(function()\n - {\n - if (/loaded|complete/.test(scope.document.readyState))\n - {\n - init(); // call the onload handler\n - }\n - }, 10);\n - }\n - else /* for Mozilla/Opera9 */\n - {\n - scope.document.addEventListener("DOMContentLoaded", init, false);\n -\n - }\n - Xinha._addEvent(scope, \'load\', init); // incase anything went wrong\n -};\n -\n -/**\n - * Adds a standard "DOM-0" event listener to an element.\n - * The DOM-0 events are those applied directly as attributes to\n - * an element - eg element.onclick = stuff;\n - *\n - * By using this function instead of simply overwriting any existing\n - * DOM-0 event by the same name on the element it will trigger as well\n - * as the existing ones. Handlers are triggered one after the other\n - * in the order they are added.\n - *\n - * Remember to return true/false from your handler, this will determine\n - * whether subsequent handlers will be triggered (ie that the event will\n - * continue or be canceled).\n - * \n - * @public\n - * @see Xinha#_addEvent\n - * @see Xinha#prependDom0Event\n - * @param {DomNode} el the DOM element the event should be attached to \n - * @param {String} ev the name of the event to listen for (without leading "on")\n - * @param {function} fn the function to be called when the event is fired\n - */\n -\n -Xinha.addDom0Event = function(el, ev, fn)\n -{\n - Xinha._prepareForDom0Events(el, ev);\n - el._xinha_dom0Events[ev].unshift(fn);\n -};\n -\n -\n -/** See addDom0Event, the difference is that handlers registered using\n - * prependDom0Event will be triggered before existing DOM-0 events of the\n - * same name on the same element.\n - * \n - * @public\n - * @see Xinha#_addEvent\n - * @see Xinha#addDom0Event\n - * @param {DomNode} the DOM element the event should be attached to \n - * @param {String} the name of the event to listen for (without leading "on")\n - * @param {function} the function to be called when the event is fired\n - */\n -\n -Xinha.prependDom0Event = function(el, ev, fn)\n -{\n - Xinha._prepareForDom0Events(el, ev);\n - el._xinha_dom0Events[ev].push(fn);\n -};\n -\n -Xinha.getEvent = function(ev)\n -{\n - return ev || window.event;\n -};\n -/**\n - * Prepares an element to receive more than one DOM-0 event handler\n - * when handlers are added via addDom0Event and prependDom0Event.\n - *\n - * @private\n - */\n -Xinha._prepareForDom0Events = function(el, ev)\n -{\n - // Create a structure to hold our lists of event handlers\n - if ( typeof el._xinha_dom0Events == \'undefined\' )\n - {\n - el._xinha_dom0Events = {};\n - Xinha.freeLater(el, \'_xinha_dom0Events\');\n - }\n -\n - // Create a list of handlers for this event type\n - if ( typeof el._xinha_dom0Events[ev] == \'undefined\' )\n - {\n - el._xinha_dom0Events[ev] = [ ];\n - if ( typeof el[\'on\'+ev] == \'function\' )\n - {\n - el._xinha_dom0Events[ev].push(el[\'on\'+ev]);\n - }\n -\n - // Make the actual event handler, which runs through\n - // each of the handlers in the list and executes them\n - // in the correct context.\n - el[\'on\'+ev] = function(event)\n - {\n - var a = el._xinha_dom0Events[ev];\n - // call previous submit methods if they were there.\n - var allOK = true;\n - for ( var i = a.length; --i >= 0; )\n - {\n - // We want the handler to be a member of the form, not the array, so that "this" will work correctly\n - el._xinha_tempEventHandler = a[i];\n - if ( el._xinha_tempEventHandler(event) === false )\n - {\n - el._xinha_tempEventHandler = null;\n - allOK = false;\n - break;\n - }\n - el._xinha_tempEventHandler = null;\n - }\n - return allOK;\n - };\n -\n - Xinha._eventFlushers.push([el, ev]);\n - }\n -};\n -\n -Xinha.prototype.notifyOn = function(ev, fn)\n -{\n - if ( typeof this._notifyListeners[ev] == \'undefined\' )\n - {\n - this._notifyListeners[ev] = [];\n - Xinha.freeLater(this, \'_notifyListeners\');\n - }\n - this._notifyListeners[ev].push(fn);\n -};\n -\n -Xinha.prototype.notifyOf = function(ev, args)\n -{\n - if ( this._notifyListeners[ev] )\n - {\n - for ( var i = 0; i < this._notifyListeners[ev].length; i++ )\n - {\n - this._notifyListeners[ev][i](ev, args);\n - }\n - }\n -};\n -\n -/** List of tag names that are defined as block level elements in HTML\n - * \n - * @private\n - * @see Xinha#isBlockElement\n - * @type {String}\n - */\n -Xinha._blockTags = " body form textarea fieldset ul ol dl li div " +\n -"p h1 h2 h3 h4 h5 h6 quote pre table thead " +\n -"tbody tfoot tr td th iframe address blockquote title meta link style head ";\n -\n -/** Checks if one element is in the list of elements that are defined as block level elements in HTML\n - * \n - * @param {DomNode} el The DOM element to check\n - * @returns {Boolean}\n - */\n -Xinha.isBlockElement = function(el)\n -{\n - return el && el.nodeType == 1 && (Xinha._blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);\n -};\n -/** List of tag names that are allowed to contain a paragraph\n - * \n - * @private\n - * @see Xinha#isParaContainer\n - * @type {String}\n - */\n -Xinha._paraContainerTags = " body td th caption fieldset div ";\n -/** Checks if one element is in the list of elements that are allowed to contain a paragraph in HTML\n - * \n - * @param {DomNode} el The DOM element to check\n - * @returns {Boolean}\n - */\n -Xinha.isParaContainer = function(el)\n -{\n - return el && el.nodeType == 1 && (Xinha._paraContainerTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);\n -};\n -\n -\n -/** These are all the tags for which the end tag is not optional or forbidden, taken from the list at:\n - * http: www.w3.org/TR/REC-html40/index/elements.html\n - * \n - * @private\n - * @see Xinha#needsClosingTag\n - * @type String\n - */\n -Xinha._closingTags = " a abbr acronym address applet b bdo big blockquote button caption center cite code del dfn dir div dl em fieldset font form frameset h1 h2 h3 h4 h5 h6 i iframe ins kbd label legend map menu noframes noscript object ol optgroup pre q s samp script select small span strike strong style sub sup table textarea title tt u ul var ";\n -\n -/** Checks if one element is in the list of elements for which the end tag is not optional or forbidden in HTML\n - * \n - * @param {DomNode} el The DOM element to check\n - * @returns {Boolean}\n - */\n -Xinha.needsClosingTag = function(el)\n -{\n - return el && el.nodeType == 1 && (Xinha._closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);\n -};\n -\n -/** Performs HTML encoding of some given string (converts HTML special characters to entities)\n - * \n - * @param {String} str The unencoded input\n - * @returns {String} The encoded output\n - */\n -Xinha.htmlEncode = function(str)\n -{\n - if (!str)\n - {\n - return \'\';\n - } if ( typeof str.replace == \'undefined\' )\n - {\n - str = str.toString();\n - }\n - // we don\'t need regexp for that, but.. so be it for now.\n - str = str.replace(/&/ig, "&");\n - str = str.replace(/</ig, "<");\n - str = str.replace(/>/ig, ">");\n - str = str.replace(/\\xA0/g, " "); // Decimal 160, non-breaking-space\n - str = str.replace(/\\x22/g, """);\n - // \\x22 means \'"\' -- we use hex reprezentation so that we don\'t disturb\n - // JS compressors (well, at least mine fails.. ;)\n - return str;\n -};\n -\n -/** Strips host-part of URL which is added by browsers to links relative to server root\n - * \n - * @param {String} string \n - * @returns {String} \n - */\n -Xinha.prototype.stripBaseURL = function(string)\n -{\n - if ( this.config.baseHref === null || !this.config.stripBaseHref )\n - {\n - return string;\n - }\n - var baseurl = this.config.baseHref.replace(/^(https?:\\/\\/[^\\/]+)(.*)$/, \'$1\');\n - var basere = new RegExp(baseurl);\n - return string.replace(basere, "");\n -};\n -\n -if (typeof String.prototype.trim != \'function\')\n -{\n - /** Removes whitespace from beginning and end of a string. Custom implementation for JS engines that don\'t support it natively\n - * \n - * @returns {String} \n - */\n - String.prototype.trim = function()\n - {\n - return this.replace(/^\\s+/, \'\').replace(/\\s+$/, \'\');\n - };\n -}\n -\n -/** Creates a rgb-style rgb(r,g,b) color from a (24bit) number\n - * \n - * @param {Integer}\n - * @returns {String} rgb(r,g,b) color definition\n - */\n -Xinha._makeColor = function(v)\n -{\n - if ( typeof v != "number" )\n - {\n - // already in rgb (hopefully); IE doesn\'t get here.\n - return v;\n - }\n - // IE sends number; convert to rgb.\n - var r = v & 0xFF;\n - var g = (v >> 8) & 0xFF;\n - var b = (v >> 16) & 0xFF;\n - return "rgb(" + r + "," + g + "," + b + ")";\n -};\n -\n -/** Returns hexadecimal color representation from a number or a rgb-style color.\n - * \n - * @param {String|Integer} v rgb(r,g,b) or 24bit color definition\n - * @returns {String} #RRGGBB color definition\n - */\n -Xinha._colorToRgb = function(v)\n -{\n - if ( !v )\n - {\n - return \'\';\n - }\n - var r,g,b;\n - // @todo: why declaring this function here ? This needs to be a public methode of the object Xinha._colorToRgb\n - // returns the hex representation of one byte (2 digits)\n - function hex(d)\n - {\n - return (d < 16) ? ("0" + d.toString(16)) : d.toString(16);\n - }\n -\n - if ( typeof v == "number" )\n - {\n - // we\'re talking to IE here\n - r = v & 0xFF;\n - g = (v >> 8) & 0xFF;\n - b = (v >> 16) & 0xFF;\n - return "#" + hex(r) + hex(g) + hex(b);\n - }\n -\n - if ( v.substr(0, 3) == "rgb" )\n - {\n - // in rgb(...) form -- Mozilla\n - var re = /rgb\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)/;\n - if ( v.match(re) )\n - {\n - r = parseInt(RegExp.$1, 10);\n - g = parseInt(RegExp.$2, 10);\n - b = parseInt(RegExp.$3, 10);\n - return "#" + hex(r) + hex(g) + hex(b);\n - }\n - // doesn\'t match RE?! maybe uses percentages or float numbers\n - // -- FIXME: not yet implemented.\n - return null;\n - }\n -\n - if ( v.substr(0, 1) == "#" )\n - {\n - // already hex rgb (hopefully :D )\n - return v;\n - }\n -\n - // if everything else fails ;)\n - return null;\n -};\n -\n -/** Modal popup dialogs\n - * \n - * @param {String} url URL to the popup dialog\n - * @param {Function} action A function that receives one value; this function will get called \n - * after the dialog is closed, with the return value of the dialog.\n - * @param {Mixed} init A variable that is passed to the popup window to pass arbitrary data\n - */\n -Xinha.prototype._popupDialog = function(url, action, init)\n -{\n - Dialog(this.popupURL(url), action, init);\n -};\n -\n -/** Creates a path in the form _editor_url + "plugins/" + plugin + "/img/" + file\n - * \n - * @deprecated\n - * @param {String} file Name of the image\n - * @param {String} plugin optional If omitted, simply _editor_url + file is returned \n - * @returns {String}\n - */\n -Xinha.prototype.imgURL = function(file, plugin)\n -{\n - if ( typeof plugin == "undefined" )\n - {\n - return _editor_url + file;\n - }\n - else\n - {\n - return Xinha.getPluginDir(plugin) + "/img/" + file;\n - }\n -};\n -/** Creates a path\n - * \n - * @deprecated\n - * @param {String} file Name of the popup\n - * @returns {String}\n - */\n -Xinha.prototype.popupURL = function(file)\n -{\n - var url = "";\n - if ( file.match(/^plugin:\\/\\/(.*?)\\/(.*)/) )\n - {\n - var plugin = RegExp.$1;\n - var popup = RegExp.$2;\n - if ( !/\\.(html?|php)$/.test(popup) )\n - {\n - popup += ".html";\n - }\n - url = Xinha.getPluginDir(plugin) + "/popups/" + popup;\n - }\n - else if ( file.match(/^\\/.*?/) || file.match(/^https?:\\/\\//))\n - {\n - url = file;\n - }\n - else\n - {\n - url = _editor_url + this.config.popupURL + file;\n - }\n - return url;\n -};\n -\n -\n -\n -/** FIX: Internet Explorer returns an item having the _name_ equal to the given\n - * id, even if it\'s not having any id. This way it can return a different form\n - * field, even if it\'s not a textarea. This workarounds the problem by\n - * specifically looking to search only elements having a certain tag name.\n - * @param {String} tag The tag name to limit the return to\n - * @param {String} id\n - * @returns {DomNode}\n - */\n -Xinha.getElementById = function(tag, id)\n -{\n - var el, i, objs = document.getElementsByTagName(tag);\n - for ( i = objs.length; --i >= 0 && (el = objs[i]); )\n - {\n - if ( el.id == id )\n - {\n - return el;\n - }\n - }\n - return null;\n -};\n -\n -\n -/** Use some CSS trickery to toggle borders on tables \n - *\t@returns {Boolean} always true\n - */\n -\n -Xinha.prototype._toggleBorders = function()\n -{\n - var tables = this._doc.getElementsByTagName(\'TABLE\');\n - if ( tables.length !== 0 )\n - {\n - if ( !this.borders )\n - { \n - this.borders = true;\n - }\n - else\n - {\n - this.borders = false;\n - }\n -\n - for ( var i=0; i < tables.length; i++ )\n - {\n - if ( this.borders )\n - {\n - Xinha._addClass(tables[i], \'htmtableborders\');\n - }\n - else\n - {\n - Xinha._removeClass(tables[i], \'htmtableborders\');\n - }\n - }\n - }\n - return true;\n -};\n -/** Adds the styles for table borders to the iframe during generation\n - * \n - * @private\n - * @see Xinha#stripCoreCSS\n - * @param {String} html optional \n - * @returns {String} html HTML with added styles or only styles if html omitted\n - */\n -Xinha.addCoreCSS = function(html)\n -{\n - var coreCSS = "<style title=\\"XinhaInternalCSS\\" type=\\"text/css\\">" +\n - ".htmtableborders, .htmtableborders td, .htmtableborders th {border : 1px dashed lightgrey ! important;}\\n" +\n - "html, body { border: 0px; } \\n" +\n - "body { background-color: #ffffff; } \\n" +\n - "img, hr { cursor: default } \\n" +\n - "</style>\\n";\n - \n - if( html && /<head>/i.test(html))\n - {\n - return html.replace(/<head>/i, \'<head>\' + coreCSS); \n - }\n - else if ( html)\n - {\n - return coreCSS + html;\n - }\n - else\n - {\n - return coreCSS;\n - }\n -};\n -/** Allows plugins to add a stylesheet for internal use to the edited document that won\'t appear in the HTML output\n - * \n - * @see Xinha#stripCoreCSS\n - * @param {String} stylesheet URL of the styleshett to be added\n - */\n -Xinha.prototype.addEditorStylesheet = function (stylesheet)\n -{\n - var style = this._doc.createElement("link");\n - style.rel = \'stylesheet\';\n - style.type = \'text/css\';\n - style.title = \'XinhaInternalCSS\';\n - style.href = stylesheet;\n - this._doc.getElementsByTagName("HEAD")[0].appendChild(style);\n -};\n -/** Remove internal styles\n - * \n - * @private\n - * @see Xinha#addCoreCSS\n - * @param {String} html \n - * @returns {String} \n - */\n -Xinha.stripCoreCSS = function(html)\n -{\n - return html.replace(/<style[^>]+title="XinhaInternalCSS"(.|\\n)*?<\\/style>/ig, \'\').replace(/<link[^>]+title="XinhaInternalCSS"(.|\\n)*?>/ig, \'\'); \n -};\n -/** Removes one CSS class (that is one of possible more parts \n - * separated by spaces) from a given element\n - * \n - * @see Xinha#_removeClasses\n - * @param {DomNode} el The DOM element the class will be removed from\n - * @param {String} className The class to be removed\n - */\n -Xinha._removeClass = function(el, className)\n -{\n - if ( ! ( el && el.className ) )\n - {\n - return;\n - }\n - var cls = el.className.split(" ");\n - var ar = [];\n - for ( var i = cls.length; i > 0; )\n - {\n - if ( cls[--i] != className )\n - {\n - ar[ar.length] = cls[i];\n - }\n - }\n - el.className = ar.join(" ");\n -};\n -/** Adds one CSS class to a given element (that is, it expands its className property by the given string,\n - * separated by a space)\n - * \n - * @see Xinha#addClasses\n - * @param {DomNode} el The DOM element the class will be added to\n - * @param {String} className The class to be added\n - */\n -Xinha._addClass = function(el, className)\n -{\n - // remove the class first, if already there\n - Xinha._removeClass(el, className);\n - el.className += " " + className;\n -};\n -\n -/** Adds CSS classes to a given element (that is, it expands its className property by the given string,\n - * separated by a space, thereby checking that no class is doubly added)\n - * \n - * @see Xinha#addClass\n - * @param {DomNode} el The DOM element the classes will be added to\n - * @param {String} classes The classes to be added\n - */\n -Xinha.addClasses = function(el, classes)\n -{\n - if ( el !== null )\n - {\n - var thiers = el.className.trim().split(\' \');\n - var ours = classes.split(\' \');\n - for ( var x = 0; x < ours.length; x++ )\n - {\n - var exists = false;\n - for ( var i = 0; exists === false && i < thiers.length; i++ )\n - {\n - if ( thiers[i] == ours[x] )\n - {\n - exists = true;\n - }\n - }\n - if ( exists === false )\n - {\n - thiers[thiers.length] = ours[x];\n - }\n - }\n - el.className = thiers.join(\' \').trim();\n - }\n -};\n -\n -/** Removes CSS classes (that is one or more of possibly several parts \n - * separated by spaces) from a given element\n - * \n - * @see Xinha#_removeClasses\n - * @param {DomNode} el The DOM element the class will be removed from\n - * @param {String} className The class to be removed\n - */\n -Xinha.removeClasses = function(el, classes)\n -{\n - var existing = el.className.trim().split();\n - var new_classes = [];\n - var remove = classes.trim().split();\n -\n - for ( var i = 0; i < existing.length; i++ )\n - {\n - var found = false;\n - for ( var x = 0; x < remove.length && !found; x++ )\n - {\n - if ( existing[i] == remove[x] )\n - {\n - found = true;\n - }\n - }\n - if ( !found )\n - {\n - new_classes[new_classes.length] = existing[i];\n - }\n - }\n - return new_classes.join(\' \');\n -};\n -\n -/** Alias of Xinha._addClass()\n - * @see Xinha#_addClass\n - */\n -Xinha.addClass = Xinha._addClass;\n -/** Alias of Xinha.Xinha._removeClass()\n - * @see Xinha#_removeClass\n - */\n -Xinha.removeClass = Xinha._removeClass;\n -/** Alias of Xinha.addClasses()\n - * @see Xinha#addClasses\n - */\n -Xinha._addClasses = Xinha.addClasses;\n -/** Alias of Xinha.removeClasses()\n - * @see Xinha#removeClasses\n - */\n -Xinha._removeClasses = Xinha.removeClasses;\n -\n -/** Checks if one element has set the given className\n - * \n - * @param {DomNode} el The DOM element to check\n - * @param {String} className The class to be looked for\n - * @returns {Boolean}\n - */\n -Xinha._hasClass = function(el, className)\n -{\n - if ( ! ( el && el.className ) )\n - {\n - return false;\n - }\n - var cls = el.className.split(" ");\n - for ( var i = cls.length; i > 0; )\n - {\n - if ( cls[--i] == className )\n - {\n - return true;\n - }\n - }\n - return false;\n -};\n -\n -/**\n - * Use XMLHTTPRequest to post some data back to the server and do something\n - * with the response (asyncronously!), this is used by such things as the tidy\n - * functions\n - * @param {String} url The address for the HTTPRequest\n - * @param {Object} data The data to be passed to the server like {name:"value"}\n - * @param {Function} success A function that is called when an answer is\n - * received from the server with the responseText as argument.\n - * @param {Function} failure A function that is called when we fail to receive\n - * an answer from the server. We pass it the request object.\n - */\n - \n -/** mod_security (an apache module which scans incoming requests for potential hack attempts)\n - * has a rule which triggers when it gets an incoming Content-Type with a charset\n - * see ticket:1028 to try and work around this, if we get a failure in a postback\n - * then Xinha._postback_send_charset will be set to false and the request tried again (once)\n - * @type Boolean\n - * @private\n - */ \n -// \n -// \n -// \n -Xinha._postback_send_charset = true;\n -/** Use XMLHTTPRequest to send some some data to the server and do something\n - * with the getback (asyncronously!)\n - * @param {String} url The address for the HTTPRequest\n - * @param {Function} success A function that is called when an answer is\n - * received from the server with the responseText as argument.\n - * @param {Function} failure A function that is called when we fail to receive\n - * an answer from the server. We pass it the request object.\n - */\n -Xinha._postback = function(url, data, success, failure)\n -{\n - var req = null;\n - req = Xinha.getXMLHTTPRequestObject();\n -\n - var content = \'\';\n - if (typeof data == \'string\')\n - {\n - content = data;\n - }\n - else if(typeof data == "object")\n - {\n - for ( var i in data )\n - {\n - content += (content.length ? \'&\' : \'\') + i + \'=\' + encodeURIComponent(data[i]);\n - }\n - }\n -\n - function callBack()\n - {\n - if ( req.readyState == 4 )\n - {\n - if ( ((req.status / 100) == 2) || Xinha.isRunLocally && req.status === 0 )\n - {\n - if ( typeof success == \'function\' )\n - {\n - success(req.responseText, req);\n - }\n - }\n - else if(Xinha._postback_send_charset)\n - { \n - Xinha._postback_send_charset = false;\n - Xinha._postback(url,data,success, failure);\n - }\n - else if (typeof failure == \'function\')\n - {\n - failure(req);\n - }\n - else\n - {\n - alert(\'An error has occurred: \' + req.statusText + \'\\nURL: \' + url);\n - }\n - }\n - }\n -\n - req.onreadystatechange = callBack;\n -\n - req.open(\'POST\', url, true);\n - req.setRequestHeader(\'Content-Type\', \'application/x-www-form-urlencoded\'+(Xinha._postback_send_charset ? \'; charset=UTF-8\' : \'\'));\n -\n - req.send(content);\n -};\n -\n -/** Use XMLHTTPRequest to receive some data from the server and do something\n - * with the it (asyncronously!)\n - * @param {String} url The address for the HTTPRequest\n - * @param {Function} success A function that is called when an answer is\n - * received from the server with the responseText as argument.\n - * @param {Function} failure A function that is called when we fail to receive\n - * an answer from the server. We pass it the request object.\n - */\n -Xinha._getback = function(url, success, failure)\n -{\n - var req = null;\n - req = Xinha.getXMLHTTPRequestObject();\n -\n - function callBack()\n - {\n - if ( req.readyState == 4 )\n - {\n - if ( ((req.status / 100) == 2) || Xinha.isRunLocally && req.status === 0 )\n - {\n - success(req.responseText, req);\n - }\n - else if (typeof failure == \'function\')\n - {\n - failure(req);\n - }\n - else\n - {\n - alert(\'An error has occurred: \' + req.statusText + \'\\nURL: \' + url);\n - }\n - }\n - }\n -\n - req.onreadystatechange = callBack;\n - req.open(\'GET\', url, true);\n - req.send(null);\n -};\n -\n -Xinha.ping = function(url, successHandler, failHandler)\n -{\n - var req = null;\n - req = Xinha.getXMLHTTPRequestObject();\n -\n - function callBack()\n - {\n - if ( req.readyState == 4 )\n - {\n - if ( ((req.status / 100) == 2) || Xinha.isRunLocally && req.status === 0 )\n - {\n - if (successHandler) \n - {\n - successHandler(req);\n - }\n - }\n - else\n - {\n - if (failHandler) \n - {\n - failHandler(req);\n - }\n - }\n - }\n - }\n -\n - // Opera seems to have some problems mixing HEAD requests with GET requests.\n - // The GET is slower, so it\'s a net slowdown for Opera, but it keeps things\n - // from breaking.\n - var method = \'GET\';\n - req.onreadystatechange = callBack;\n - req.open(method, url, true);\n - req.send(null);\n -};\n -\n -/** Use XMLHTTPRequest to receive some data from the server syncronously\n - * @param {String} url The address for the HTTPRequest\n - */\n -Xinha._geturlcontent = function(url, returnXML)\n -{\n - var req = null;\n - req = Xinha.getXMLHTTPRequestObject();\n -\n - // Synchronous!\n - req.open(\'GET\', url, false);\n - req.send(null);\n - if ( ((req.status / 100) == 2) || Xinha.isRunLocally && req.status === 0 )\n - {\n - return (returnXML) ? req.responseXML : req.responseText;\n - }\n - else\n - {\n - return \'\';\n - }\n -};\n -\n -// Unless somebody already has, make a little function to debug things\n -\n -if (typeof dumpValues == \'undefined\') \n -{\n - dumpValues = function(o)\n - {\n - var s = \'\';\n - for (var prop in o) \n - {\n - if (window.console && typeof window.console.log == \'function\') \n - {\n - if (typeof console.firebug != \'undefined\') \n - {\n - console.log(o);\n - }\n - else \n - {\n - console.log(prop + \' = \' + o[prop] + \'\\n\');\n - }\n - }\n - else\n - {\n - s += prop + \' = \' + o[prop] + \'\\n\';\n - }\n - }\n - if (s) \n - {\n - if (document.getElementById(\'errors\'))\n - {\n - document.getElementById(\'errors\').value += s;\n - }\n - else\n - {\n - var x = window.open("", "debugger");\n - x.document.write(\'<pre>\' + s + \'</pre>\');\n - }\n -\n - }\n - };\n -}\n -if ( !Array.prototype.contains )\n -{\n - /** Walks through an array and checks if the specified item exists in it\n - * @param {String} needle The string to search for\n - * @returns {Boolean} True if item found, false otherwise \n - */\n - Array.prototype.contains = function(needle)\n - {\n - var haystack = this;\n - for ( var i = 0; i < haystack.length; i++ )\n - {\n - if ( needle == haystack[i] )\n - {\n - return true;\n - }\n - }\n - return false;\n - };\n -}\n -\n -if ( !Array.prototype.indexOf )\n -{\n - /** Walks through an array and, if the specified item exists in it, returns the position\n - * @param {String} needle The string to search for\n - * @returns {Integer|null} Index position if item found, null otherwise \n - */\n - Array.prototype.indexOf = function(needle)\n - {\n - var haystack = this;\n - for ( var i = 0; i < haystack.length; i++ )\n - {\n - if ( needle == haystack[i] )\n - {\n - return i;\n - }\n - }\n - return null;\n - };\n -}\n -if ( !Array.prototype.append )\n -{\n - /** Adds an item to an array\n - * @param {Mixed} a Item to add\n - * @returns {Array} The array including the newly added item\n - */\n - Array.prototype.append = function(a)\n - {\n - for ( var i = 0; i < a.length; i++ )\n - {\n - this.push(a[i]);\n - }\n - return this;\n - };\n -}\n -/** Executes a provided function once per array element.\n - * Custom implementation for JS engines that don\'t support it natively\n - * @source http://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array/ForEach\n - * @param {Function} fn Function to execute for each element\n - * @param {Object} thisObject Object to use as this when executing callback. \n - */\n -if (!Array.prototype.forEach)\n -{\n - Array.prototype.forEach = function(fn /*, thisObject*/)\n - {\n - var len = this.length;\n - if (typeof fn != "function")\n - {\n - throw new TypeError();\n - }\n -\n - var thisObject = arguments[1];\n - for (var i = 0; i < len; i++)\n - {\n - if (i in this)\n - {\n - fn.call(thisObject, this[i], i, this);\n - }\n - }\n - };\n -}\n -/** Returns all elements within a given class name inside an element\n - * @type Array\n - * @param {DomNode|document} el wherein to search\n - * @param {Object} className\n - */\n -Xinha.getElementsByClassName = function(el,className)\n -{\n - if (el.getElementsByClassName)\n - {\n - return Array.prototype.slice.call(el.getElementsByClassName(className));\n - }\n - else\n - {\n - var els = el.getElementsByTagName(\'*\');\n - var result = [];\n - var classNames;\n - for (var i=0;i<els.length;i++)\n - {\n - classNames = els[i].className.split(\' \');\n - if (classNames.contains(className)) \n - {\n - result.push(els[i]);\n - }\n - }\n - return result;\n - }\n -};\n -\n -/** Returns true if all elements of <em>a2</em> are also contained in <em>a1</em> (at least I think this is what it does)\n -* @param {Array} a1\n -* @param {Array} a2\n -* @returns {Boolean}\n -*/\n -Xinha.arrayContainsArray = function(a1, a2)\n -{\n - var all_found = true;\n - for ( var x = 0; x < a2.length; x++ )\n - {\n - var found = false;\n - for ( var i = 0; i < a1.length; i++ )\n - {\n - if ( a1[i] == a2[x] )\n - {\n - found = true;\n - break;\n - }\n - }\n - if ( !found )\n - {\n - all_found = false;\n - break;\n - }\n - }\n - return all_found;\n -};\n -/** Walks through an array and applies a filter function to each item\n -* @param {Array} a1 The array to filter\n -* @param {Function} filterfn If this function returns true, the item is added to the new array\n -* @returns {Array} Filtered array\n -*/\n -Xinha.arrayFilter = function(a1, filterfn)\n -{\n - var new_a = [ ];\n - for ( var x = 0; x < a1.length; x++ )\n - {\n - if ( filterfn(a1[x]) )\n - {\n - new_a[new_a.length] = a1[x];\n - }\n - }\n - return new_a;\n -};\n -/** Converts a Collection object to an array \n -* @param {Collection} collection The array to filter\n -* @returns {Array} Array containing the item of collection\n -*/\n -Xinha.collectionToArray = function(collection)\n -{\n - try\n - {\n - return collection.length ? Array.prototype.slice.call(collection) : []; //Collection to Array\n - }\n - catch(e)\n - {\n - // In certain implementations (*cough* IE), you can\'t call slice on a\n - // collection. We\'ll fallback to using the simple, non-native iterative\n - // approach.\n - }\n -\n - var array = [ ];\n - for ( var i = 0; i < collection.length; i++ )\n - {\n - array.push(collection.item(i));\n - }\n - return array;\n -};\n -\n -/** Index for Xinha.uniq function \n -*\t@private\n -*/\n -Xinha.uniq_count = 0;\n -/** Returns a string that is unique on the page\n -*\t@param {String} prefix This string is prefixed to a running number\n -* @returns {String}\n -*/\n -Xinha.uniq = function(prefix)\n -{\n - return prefix + Xinha.uniq_count++;\n -};\n -\n -// New language handling functions\n -\n -/** Load a language file.\n - * This function should not be used directly, Xinha._lc will use it when necessary.\n - * @private\n - * @param {String} context Case sensitive context name, eg \'Xinha\', \'TableOperations\', ...\n - * @returns {Object}\n - */\n -Xinha._loadlang = function(context,url)\n -{\n - var lang;\n - \n - if ( typeof _editor_lcbackend == "string" )\n - {\n - //use backend\n - url = _editor_lcbackend;\n - url = url.replace(/%lang%/, _editor_lang);\n - url = url.replace(/%context%/, context);\n - }\n - else if (!url)\n - {\n - //use internal files\n - if ( context != \'Xinha\')\n - {\n - url = Xinha.getPluginDir(context)+"/lang/"+_editor_lang+".js";\n - }\n - else\n - {\n - Xinha.setLoadingMessage("Loading language");\n - url = _editor_url+"lang/"+_editor_lang+".js";\n - }\n - }\n -\n - var langData = Xinha._geturlcontent(url);\n - if ( langData !== "" )\n - {\n - try\n - {\n - eval(\'lang = \' + langData);\n - }\n - catch(ex)\n - {\n - alert(\'Error reading Language-File (\'+url+\'):\\n\'+Error.toString());\n - lang = {};\n - }\n - }\n - else\n - {\n - lang = {};\n - }\n -\n - return lang;\n -};\n -\n -/** Return a localised string.\n - * @param {String} string English language string. It can also contain variables in the form "Some text with $variable=replaced text$". \n - * This replaces $variable in "Some text with $variable" with "replaced text"\n - * @param {String} context Case sensitive context name, eg \'Xinha\' (default), \'TableOperations\'...\n - * @param {Object} replace Replace $variables in String, eg {foo: \'replaceText\'} ($foo in string will be replaced by replaceText)\n - */\n -Xinha._lc = function(string, context, replace)\n -{\n - var url,ret;\n - if (typeof context == \'object\' && context.url && context.context)\n - {\n - url = context.url + _editor_lang + ".js";\n - context = context.context;\n - }\n -\n - var m = null;\n - if (typeof string == \'string\') \n - {\n - m = string.match(/\\$(.*?)=(.*?)\\$/g);\n - }\n - if (m) \n - {\n - if (!replace) \n - {\n - replace = {};\n - }\n - for (var i = 0;i<m.length;i++)\n - {\n - var n = m[i].match(/\\$(.*?)=(.*?)\\$/);\n - replace[n[1]] = n[2];\n - string = string.replace(n[0],\'$\'+n[1]);\n - }\n - }\n - if ( _editor_lang == "en" )\n - {\n - if ( typeof string == \'object\' && string.string )\n - {\n - ret = string.string;\n - }\n - else\n - {\n - ret = string;\n - }\n - }\n - else\n - {\n - if ( typeof Xinha._lc_catalog == \'undefined\' )\n - {\n - Xinha._lc_catalog = [ ];\n - }\n -\n - if ( typeof context == \'undefined\' )\n - {\n - context = \'Xinha\';\n - }\n -\n - if ( typeof Xinha._lc_catalog[context] == \'undefined\' )\n - {\n - Xinha._lc_catalog[context] = Xinha._loadlang(context,url);\n - }\n -\n - var key;\n - if ( typeof string == \'object\' && string.key )\n - {\n - key = string.key;\n - }\n - else if ( typeof string == \'object\' && string.string )\n - {\n - key = string.string;\n - }\n - else\n - {\n - key = string;\n - }\n -\n - if ( typeof Xinha._lc_catalog[context][key] == \'undefined\' )\n - {\n - if ( context==\'Xinha\' )\n - {\n - // Indicate it\'s untranslated\n - if ( typeof string == \'object\' && string.string )\n - {\n - ret = string.string;\n - }\n - else\n - {\n - ret = string;\n - }\n - }\n - else\n - {\n - //if string is not found and context is not Xinha try if it is in Xinha\n - return Xinha._lc(string, \'Xinha\', replace);\n - }\n - }\n - else\n - {\n - ret = Xinha._lc_catalog[context][key];\n - }\n - }\n -\n - if ( typeof string == \'object\' && string.replace )\n - {\n - replace = string.replace;\n - }\n - if ( typeof replace != "undefined" )\n - {\n - for ( i in replace )\n - {\n - ret = ret.replace(\'$\'+i, replace[i]);\n - }\n - }\n -\n - return ret;\n -};\n -/** Walks through the children of a given element and checks if any of the are visible (= not display:none)\n - * @param {DomNode} el \n - * @returns {Boolean} \n - */\n -Xinha.hasDisplayedChildren = function(el)\n -{\n - var children = el.childNodes;\n - for ( var i = 0; i < children.length; i++ )\n - {\n - if ( children[i].tagName )\n - {\n - if ( children[i].style.display != \'none\' )\n - {\n - return true;\n - }\n - }\n - }\n - return false;\n -};\n -\n -/** Load a javascript file by inserting it in the HEAD tag and eventually call a function when loaded\n - *\n - * Note that this method cannot be abstracted into browser specific files\n - * because this method LOADS the browser specific files. Hopefully it should work for most\n - * browsers as it is.\n - *\n - * @param {String} url Source url of the file to load\n - * @param {Object} callback optional Callback function to launch once ready \n - * @param {Object} scope optional Application scope for the callback function\n - * @param {Object} bonus optional Arbitrary object send as a param to the callback function\n - */\n -Xinha._loadback = function(url, callback, scope, bonus)\n -{ \n - if ( document.getElementById(url) )\n - {\n - return true;\n - }\n - var t = !Xinha.is_ie ? "onload" : \'onreadystatechange\';\n - var s = document.createElement("script");\n - s.type = "text/javascript";\n - s.src = url;\n - s.id = url;\n - if ( callback )\n - {\n - s[t] = function()\n - { \n - if (Xinha.is_ie && (!/loaded|complete/.test(window.event.srcElement.readyState)))\n - {\n - return;\n - }\n - \n - callback.call(scope ? scope : this, bonus);\n - s[t] = null;\n - };\n - }\n - document.getElementsByTagName("head")[0].appendChild(s);\n - return false;\n -};\n -\n -/** Xinha\'s main loading function (see NewbieGuide)\n - * @param {Array} editor_names\n - * @param {Xinha.Config} default_config\n - * @param {Array} plugin_names\n - * @returns {Object} An object that contains references to all created editors indexed by the IDs of the textareas \n - */\n -Xinha.makeEditors = function(editor_names, default_config, plugin_names)\n -{\n - if (!Xinha.isSupportedBrowser) \n - {\n - return;\n - }\n - \n - if ( typeof default_config == \'function\' )\n - {\n - default_config = default_config();\n - }\n -\n - var editors = {};\n - var textarea;\n - for ( var x = 0; x < editor_names.length; x++ )\n - {\n - if ( typeof editor_names[x] == \'string\' ) // the regular case, an id of a textarea\n - {\n - textarea = Xinha.getElementById(\'textarea\', editor_names[x] );\n - if (!textarea) // the id may be specified for a textarea that is maybe on another page; we simply skip it and go on\n - {\n - editor_names[x] = null;\n - continue;\n - }\n - }\n -\t // make it possible to pass a reference instead of an id, for example from document.getElementsByTagName(\'textarea\')\n - else if ( typeof editor_names[x] == \'object\' && editor_names[x].tagName && editor_names[x].tagName.toLowerCase() == \'textarea\' )\n - {\n - textarea = editor_names[x];\n - if ( !textarea.id ) // we\'d like to have the textarea have an id\n - {\n - textarea.id = \'xinha_id_\' + x;\n - } \n - }\n - var editor = new Xinha(textarea, Xinha.cloneObject(default_config));\n - editor.registerPlugins(plugin_names);\n - editors[textarea.id] = editor;\n - }\n - return editors;\n -};\n -/** Another main loading function (see NewbieGuide)\n - * @param {Object} editors As returned by Xinha.makeEditors()\n - */\n -Xinha.startEditors = function(editors)\n -{\n - if (!Xinha.isSupportedBrowser) \n - {\n - return;\n - }\n - \n - for ( var i in editors )\n - {\n - if ( editors[i].generate )\n - {\n - editors[i].generate();\n - }\n - }\n -};\n -/** Registers the loaded plugins with the editor\n - * @private\n - * @param {Array} plugin_names\n - */\n -Xinha.prototype.registerPlugins = function(plugin_names)\n -{\n - if (!Xinha.isSupportedBrowser) \n - {\n - return;\n - }\n - \n - if ( plugin_names )\n - {\n - for ( var i = 0; i < plugin_names.length; i++ )\n - {\n - this.setLoadingMessage(Xinha._lc(\'Register plugin $plugin\', \'Xinha\', {\'plugin\': plugin_names[i]}));\n - this.registerPlugin(plugin_names[i]);\n - }\n - }\n -};\n -\n -/** Utility function to base64_encode some arbitrary data, uses the builtin btoa() if it exists (Moz) \n -* @param {String} input\n -* @returns {String}\n -*/\n -Xinha.base64_encode = function(input)\n -{\n - var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";\n - var output = "";\n - var chr1, chr2, chr3;\n - var enc1, enc2, enc3, enc4;\n - var i = 0;\n -\n - do\n - {\n - chr1 = input.charCodeAt(i++);\n - chr2 = input.charCodeAt(i++);\n - chr3 = input.charCodeAt(i++);\n -\n - enc1 = chr1 >> 2;\n - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n - enc4 = chr3 & 63;\n -\n - if ( isNaN(chr2) )\n - {\n - enc3 = enc4 = 64;\n - }\n - else if ( isNaN(chr3) )\n - {\n - enc4 = 64;\n - }\n -\n - output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);\n - } while ( i < input.length );\n -\n - return output;\n -};\n -\n -/** Utility function to base64_decode some arbitrary data, uses the builtin atob() if it exists (Moz)\n - * @param {String} input\n - * @returns {String}\n - */\n -Xinha.base64_decode = function(input)\n -{\n - var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";\n - var output = "";\n - var chr1, chr2, chr3;\n - var enc1, enc2, enc3, enc4;\n - var i = 0;\n -\n - // remove all characters that are not A-Z, a-z, 0-9, +, /, or =\n - input = input.replace(/[^A-Za-z0-9\\+\\/\\=]/g, "");\n -\n - do\n - {\n - enc1 = keyStr.indexOf(input.charAt(i++));\n - enc2 = keyStr.indexOf(input.charAt(i++));\n - enc3 = keyStr.indexOf(input.charAt(i++));\n - enc4 = keyStr.indexOf(input.charAt(i++));\n -\n - chr1 = (enc1 << 2) | (enc2 >> 4);\n - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n - chr3 = ((enc3 & 3) << 6) | enc4;\n -\n - output = output + String.fromCharCode(chr1);\n -\n - if ( enc3 != 64 )\n - {\n - output = output + String.fromCharCode(chr2);\n - }\n - if ( enc4 != 64 )\n - {\n - output = output + String.fromCharCode(chr3);\n - }\n - } while ( i < input.length );\n -\n - return output;\n -};\n -/** Removes a node from the DOM\n - * @param {DomNode} el The element to be removed\n - * @returns {DomNode} The removed element\n - */\n -Xinha.removeFromParent = function(el)\n -{\n - if ( !el.parentNode )\n - {\n - return;\n - }\n - var pN = el.parentNode;\n - return pN.removeChild(el);\n -};\n -/** Checks if some element has a parent node\n - * @param {DomNode} el \n - * @returns {Boolean}\n - */\n -Xinha.hasParentNode = function(el)\n -{\n - if ( el.parentNode )\n - {\n - // When you remove an element from the parent in IE it makes the parent\n - // of the element a document fragment. Moz doesn\'t.\n - if ( el.parentNode.nodeType == 11 )\n - {\n - return false;\n - }\n - return true;\n - }\n -\n - return false;\n -};\n -\n -/** Detect the size of visible area\n - * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup\n - * @returns {Object} Object with Integer properties x and y\n - */\n -Xinha.viewportSize = function(scope)\n -{\n - scope = (scope) ? scope : window;\n - var x,y;\n - if (scope.innerHeight) // all except Explorer\n - {\n - x = scope.innerWidth;\n - y = scope.innerHeight;\n - }\n - else if (scope.document.documentElement && scope.document.documentElement.clientHeight)\n - // Explorer 6 Strict Mode\n - {\n - x = scope.document.documentElement.clientWidth;\n - y = scope.document.documentElement.clientHeight;\n - }\n - else if (scope.document.body) // other Explorers\n - {\n - x = scope.document.body.clientWidth;\n - y = scope.document.body.clientHeight;\n - }\n - return {\'x\':x,\'y\':y};\n -};\n -/** Detect the size of the whole document\n - * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup\n - * @returns {Object} Object with Integer properties x and y\n - */\n -Xinha.pageSize = function(scope)\n -{\n - scope = (scope) ? scope : window;\n - var x,y;\n - \n - var test1 = scope.document.body.scrollHeight; //IE Quirks\n - var test2 = scope.document.documentElement.scrollHeight; // IE Standard + Moz Here quirksmode.org errs! \n -\n - if (test1 > test2) \n - {\n - x = scope.document.body.scrollWidth;\n - y = scope.document.body.scrollHeight;\n - }\n - else\n - {\n - x = scope.document.documentElement.scrollWidth;\n - y = scope.document.documentElement.scrollHeight;\n - } \n - return {\'x\':x,\'y\':y};\n -};\n -/** Detect the current scroll position\n - * @param {Window} scope optional When calling from a popup window, pass its window object to get the values of the popup\n - * @returns {Object} Object with Integer properties x and y\n - */\n -Xinha.prototype.scrollPos = function(scope)\n -{\n - scope = (scope) ? scope : window;\n - var x,y;\n - if (typeof scope.pageYOffset != \'undefined\') // all except Explorer\n - {\n - x = scope.pageXOffset;\n - y = scope.pageYOffset;\n - }\n - else if (scope.document.documentElement && typeof document.documentElement.scrollTop != \'undefined\')\n - // Explorer 6 Strict\n - {\n - x = scope.document.documentElement.scrollLeft;\n - y = scope.document.documentElement.scrollTop;\n - }\n - else if (scope.document.body) // all other Explorers\n - {\n - x = scope.document.body.scrollLeft;\n - y = scope.document.body.scrollTop;\n - }\n - return {\'x\':x,\'y\':y};\n -};\n -\n -/** Calculate the top and left pixel position of an element in the DOM.\n - * @param {DomNode} element HTML Element\n - * @returns {Object} Object with Integer properties top and left\n - */\n - \n -Xinha.getElementTopLeft = function(element) \n -{\n - var curleft = 0;\n - var curtop = 0;\n - if (element.offsetParent) \n - {\n - curleft = element.offsetLeft;\n - curtop = element.offsetTop;\n - while (element = element.offsetParent) \n - {\n - curleft += element.offsetLeft;\n - curtop += element.offsetTop;\n - }\n - }\n - return { top:curtop, left:curleft };\n -};\n -/** Find left pixel position of an element in the DOM.\n - * @param {DomNode} element HTML Element\n - * @returns {Integer} \n - */\n -Xinha.findPosX = function(obj)\n -{\n - var curleft = 0;\n - if ( obj.offsetParent )\n - {\n - return Xinha.getElementTopLeft(obj).left;\n - }\n - else if ( obj.x )\n - {\n - curleft += obj.x;\n - }\n - return curleft;\n -};\n -/** Find top pixel position of an element in the DOM.\n - * @param {DomNode} element HTML Element\n - * @returns {Integer} \n - */\n -Xinha.findPosY = function(obj)\n -{\n - var curtop = 0;\n - if ( obj.offsetParent )\n - {\n - return Xinha.getElementTopLeft(obj).top; \n - }\n - else if ( obj.y )\n - {\n - curtop += obj.y;\n - }\n - return curtop;\n -};\n -\n -Xinha.createLoadingMessages = function(xinha_editors)\n -{\n - if ( Xinha.loadingMessages || !Xinha.isSupportedBrowser ) \n - {\n - return;\n - }\n - Xinha.loadingMessages = [];\n - \n - for (var i=0;i<xinha_editors.length;i++)\n - {\n - if (!document.getElementById(xinha_editors[i])) \n - {\n - continue;\n - }\n - Xinha.loadingMessages.push(Xinha.createLoadingMessage(Xinha.getElementById(\'textarea\', xinha_editors[i])));\n - }\n -};\n -\n -Xinha.createLoadingMessage = function(textarea,text)\n -{ \n - if ( document.getElementById("loading_" + textarea.id) || !Xinha.isSupportedBrowser)\n - {\n - return;\n - }\n - // Create and show the main loading message and the sub loading message for details of loading actions\n - // global element\n - var loading_message = document.createElement("div");\n - loading_message.id = "loading_" + textarea.id;\n - loading_message.className = "loading";\n - \n - loading_message.style.left = (Xinha.findPosX(textarea) + textarea.offsetWidth / 2) - 106 + \'px\';\n - loading_message.style.top = (Xinha.findPosY(textarea) + textarea.offsetHeight / 2) - 50 + \'px\';\n - // main static message\n - var loading_main = document.createElement("div");\n - loading_main.className = "loading_main";\n - loading_main.id = "loading_main_" + textarea.id;\n - loading_main.appendChild(document.createTextNode(Xinha._lc("Loading in progress. Please wait!")));\n - // sub dynamic message\n - var loading_sub = document.createElement("div");\n - loading_sub.className = "loading_sub";\n - loading_sub.id = "loading_sub_" + textarea.id;\n - text = text ? text : Xinha._lc("Loading Core");\n - loading_sub.appendChild(document.createTextNode(text));\n - loading_message.appendChild(loading_main);\n - loading_message.appendChild(loading_sub);\n - document.body.appendChild(loading_message);\n - \n - Xinha.freeLater(loading_message);\n - Xinha.freeLater(loading_main);\n - Xinha.freeLater(loading_sub);\n - \n - return loading_sub;\n -};\n -\n -Xinha.prototype.setLoadingMessage = function(subMessage, mainMessage)\n -{\n - if ( !document.getElementById("loading_sub_" + this._textArea.id) )\n - {\n - return;\n - }\n - document.getElementById("loading_main_" + this._textArea.id).innerHTML = mainMessage ? mainMessage : Xinha._lc("Loading in progress. Please wait!");\n - document.getElementById("loading_sub_" + this._textArea.id).innerHTML = subMessage;\n -};\n -\n -Xinha.setLoadingMessage = function(string)\n -{\n - if (!Xinha.loadingMessages) \n - {\n - return;\n - }\n - for ( var i = 0; i < Xinha.loadingMessages.length; i++ )\n - {\n - Xinha.loadingMessages[i].innerHTML = string;\n - }\n -};\n -\n -Xinha.prototype.removeLoadingMessage = function()\n -{\n - if (document.getElementById("loading_" + this._textArea.id) )\n - {\n - document.body.removeChild(document.getElementById("loading_" + this._textArea.id));\n - }\n -};\n -\n -Xinha.removeLoadingMessages = function(xinha_editors)\n -{\n - for (var i=0;i< xinha_editors.length;i++)\n - {\n - if (!document.getElementById(xinha_editors[i])) \n - {\n - continue;\n - }\n - var main = document.getElementById("loading_" + document.getElementById(xinha_editors[i]).id);\n - main.parentNode.removeChild(main);\n - }\n - Xinha.loadingMessages = null;\n -};\n -\n -/** List of objects that have to be trated on page unload in order to work around the broken \n - * Garbage Collector in IE\n - * @private\n - * @see Xinha#freeLater\n - * @see Xinha#free\n - * @see Xinha#collectGarbageForIE\n - */\n -Xinha.toFree = [];\n -/** Adds objects to Xinha.toFree \n - * @param {Object} object The object to free memory\n - * @param (String} prop optional The property to release\n - * @private\n - * @see Xinha#toFree\n - * @see Xinha#free\n - * @see Xinha#collectGarbageForIE\n - */\n -Xinha.freeLater = function(obj,prop)\n -{\n - Xinha.toFree.push({o:obj,p:prop});\n -};\n -\n -/** Release memory properties from object\n - * @param {Object} object The object to free memory\n - * @param (String} prop optional The property to release\n - * @private\n - * @see Xinha#collectGarbageForIE\n - * @see Xinha#free\n - */\n -Xinha.free = function(obj, prop)\n -{\n - if ( obj && !prop )\n - {\n - for ( var p in obj )\n - {\n - Xinha.free(obj, p);\n - }\n - }\n - else if ( obj )\n - {\n - if ( prop.indexOf(\'src\') == -1 ) // if src (also lowsrc, and maybe dynsrc ) is set to null, a file named "null" is requested from the server (see #1001)\n - {\n - try { obj[prop] = null; } catch(x) {}\n - }\n - }\n -};\n -\n -/** IE\'s Garbage Collector is broken very badly. We will do our best to \n - * do it\'s job for it, but we can\'t be perfect. Takes all objects from Xinha.free and releases sets the null\n - * @private\n - * @see Xinha#toFree\n - * @see Xinha#free\n - */\n -\n -Xinha.collectGarbageForIE = function() \n -{ \n - Xinha.flushEvents(); \n - for ( var x = 0; x < Xinha.toFree.length; x++ )\n - {\n - Xinha.free(Xinha.toFree[x].o, Xinha.toFree[x].p);\n - Xinha.toFree[x].o = null;\n - }\n -};\n -\n -\n -// The following methods may be over-ridden or extended by the browser specific\n -// javascript files.\n -\n -\n -/** Insert a node at the current selection point. \n - * @param {DomNode} toBeInserted\n - */\n -\n -Xinha.prototype.insertNodeAtSelection = function(toBeInserted) { Xinha.notImplemented("insertNodeAtSelection"); };\n -\n -/** Get the parent element of the supplied or current selection. \n - * @param {Selection} sel optional selection as returned by getSelection\n - * @returns {DomNode}\n - */\n - \n -Xinha.prototype.getParentElement = function(sel) { Xinha.notImplemented("getParentElement"); };\n -\n -/**\n - * Returns the selected element, if any. That is,\n - * the element that you have last selected in the "path"\n - * at the bottom of the editor, or a "control" (eg image)\n - *\n - * @returns {DomNode|null}\n - */\n - \n -Xinha.prototype.activeElement = function(sel) { Xinha.notImplemented("activeElement"); };\n -\n -/** \n - * Determines if the given selection is empty (collapsed).\n - * @param {Selection} sel Selection object as returned by getSelection\n - * @returns {Boolean}\n - */\n - \n -Xinha.prototype.selectionEmpty = function(sel) { Xinha.notImplemented("selectionEmpty"); };\n -/** \n - * Returns a range object to be stored \n - * and later restored with Xinha.prototype.restoreSelection()\n - * @returns {Range}\n - */\n -\n -Xinha.prototype.saveSelection = function() { Xinha.notImplemented("saveSelection"); };\n -\n -/** Restores a selection previously stored\n - * @param {Range} savedSelection Range object as returned by Xinha.prototype.restoreSelection()\n - */\n -Xinha.prototype.restoreSelection = function(savedSelection) { Xinha.notImplemented("restoreSelection"); };\n -\n -/**\n - * Selects the contents of the given node. If the node is a "control" type element, (image, form input, table)\n - * the node itself is selected for manipulation.\n - *\n - * @param {DomNode} node \n - * @param {Integer} pos Set to a numeric position inside the node to collapse the cursor here if possible. \n - */\n -Xinha.prototype.selectNodeContents = function(node,pos) { Xinha.notImplemented("selectNodeContents"); };\n -\n -/** Insert HTML at the current position, deleting the selection if any. \n - * \n - * @param {String} html\n - */\n - \n -Xinha.prototype.insertHTML = function(html) { Xinha.notImplemented("insertHTML"); };\n -\n -/** Get the HTML of the current selection. HTML returned has not been passed through outwardHTML.\n - *\n - * @returns {String}\n - */\n -Xinha.prototype.getSelectedHTML = function() { Xinha.notImplemented("getSelectedHTML"); };\n -\n -/** Get a Selection object of the current selection. Note that selection objects are browser specific.\n - *\n - * @returns {Selection}\n - */\n - \n -Xinha.prototype.getSelection = function() { Xinha.notImplemented("getSelection"); };\n -\n -/** Create a Range object from the given selection. Note that range objects are browser specific.\n - * @see Xinha#getSelection\n - * @param {Selection} sel Selection object \n - * @returns {Range}\n - */\n -Xinha.prototype.createRange = function(sel) { Xinha.notImplemented("createRange"); };\n -\n -/** Determine if the given event object is a keydown/press event.\n - *\n - * @param {Event} event \n - * @returns {Boolean}\n - */\n - \n -Xinha.prototype.isKeyEvent = function(event) { Xinha.notImplemented("isKeyEvent"); };\n -\n -/** Determines if the given key event object represents a combination of CTRL-<key>,\n - * which for Xinha is a shortcut. Note that CTRL-ALT-<key> is not a shortcut.\n - *\n - * @param {Event} keyEvent\n - * @returns {Boolean}\n - */\n - \n -Xinha.prototype.isShortCut = function(keyEvent)\n -{\n - if(keyEvent.ctrlKey && !keyEvent.altKey)\n - {\n - return true;\n - }\n - \n - return false;\n -};\n -\n -/** Return the character (as a string) of a keyEvent - ie, press the \'a\' key and\n - * this method will return \'a\', press SHIFT-a and it will return \'A\'.\n - * \n - * @param {Event} keyEvent\n - * @returns {String}\n - */\n - \n -Xinha.prototype.getKey = function(keyEvent) { Xinha.notImplemented("getKey"); };\n -\n -/** Return the HTML string of the given Element, including the Element.\n - * \n - * @param {DomNode} element HTML Element\n - * @returns {String}\n - */\n - \n -Xinha.getOuterHTML = function(element) { Xinha.notImplemented("getOuterHTML"); };\n -\n -/** Get a new XMLHTTPRequest Object ready to be used. \n - *\n - * @returns {XMLHTTPRequest}\n - */\n -\n -Xinha.getXMLHTTPRequestObject = function() \n -{\n - try\n - { \n - if (typeof XMLHttpRequest != "undefined" && typeof XMLHttpRequest.constructor == \'function\' ) // Safari\'s XMLHttpRequest is typeof object\n - {\n - \t return new XMLHttpRequest();\n - }\n - \telse if (typeof ActiveXObject == "function")\n - \t{\n - \t return new ActiveXObject("Microsoft.XMLHTTP");\n - \t}\n - }\n - catch(e)\n - {\n - Xinha.notImplemented(\'getXMLHTTPRequestObject\');\n - }\n -};\n - \n -// Compatability - all these names are deprecated and will be removed in a future version\n -/** Alias of activeElement()\n - * @see Xinha#activeElement\n - * @deprecated\n - * @returns {DomNode|null}\n - */\n -Xinha.prototype._activeElement = function(sel) { return this.activeElement(sel); };\n -/** Alias of selectionEmpty()\n - * @see Xinha#selectionEmpty\n - * @deprecated\n - * @param {Selection} sel Selection object as returned by getSelection\n - * @returns {Boolean}\n - */\n -Xinha.prototype._selectionEmpty = function(sel) { return this.selectionEmpty(sel); };\n -/** Alias of getSelection()\n - * @see Xinha#getSelection\n - * @deprecated\n - * @returns {Selection}\n - */\n -Xinha.prototype._getSelection = function() { return this.getSelection(); };\n -/** Alias of createRange()\n - * @see Xinha#createRange\n - * @deprecated\n - * @param {Selection} sel Selection object\n - * @returns {Range}\n - */\n -Xinha.prototype._createRange = function(sel) { return this.createRange(sel); };\n -HTMLArea = Xinha;\n -\n -//what is this for? Do we need it?\n -Xinha.init();\n -\n -if ( Xinha.ie_version < 8 )\n -{\n - Xinha.addDom0Event(window,\'unload\',Xinha.collectGarbageForIE);\n -}\n -/** Print some message to Firebug, Webkit, Opera, or IE8 console\n - * \n - * @param {String} text\n - * @param {String} level one of \'warn\', \'info\', or empty \n - */\n -Xinha.debugMsg = function(text, level)\n -{\n - if (typeof console != \'undefined\' && typeof console.log == \'function\') \n - {\n - if (level && level == \'warn\' && typeof console.warn == \'function\') \n - {\n - console.warn(text);\n - }\n - else \n - if (level && level == \'info\' && typeof console.info == \'function\') \n - {\n - console.info(text);\n - }\n - else \n - {\n - console.log(text);\n - }\n - }\n - else if (typeof opera != \'undefined\' && typeof opera.postError == \'function\') \n - {\n - opera.postError(text);\n - }\n -};\n -Xinha.notImplemented = function(methodName) \n -{\n - throw new Error("Method Not Implemented", "Part of Xinha has tried to call the " + methodName + " method which has not been implemented.");\n -};\n - +Xinha.version={Release:"Trunk",Head:"$HeadURL: http://svn.xinha.org/trunk/XinhaCore.js $".replace(/^[^:]*:\\s*(.*)\\s*\\$$/,"$1"),Date:"$LastChangedDate: 2010-05-12 09:40:06 +1200 (Wed, 12 May 2010) $".replace(/^[^:]*:\\s*([0-9\\-]*) ([0-9:]*) ([+0-9]*) \\((.*)\\)\\s*\\$/,"$4 $2 $3"),Revision:"$LastChangedRevision: 1263 $".replace(/^[^:]*:\\s*(.*)\\s*\\$$/,"$1"),RevisionBy:"$LastChangedBy: gogo $".replace(/^[^:]*:\\s*(.*)\\s*\\$$/,"$1")};Xinha._resolveRelativeUrl=function(d,c){if(c.match(/^([^:]+\\:)?\\/\\//)){return c}else{var a=d.split("/");if(a[a.length-1]===""){a.pop()}var e=c.split("/");if(e[0]=="."){e.shift()}while(e[0]==".."){a.pop();e.shift()}return a.join("/")+"/"+e.join("/")}};if(typeof _editor_url=="string"){_editor_url=_editor_url.replace(/\\x2f*$/,"/");if(!_editor_url.match(/^([^:]+\\:)?\\//)){(function(){var a=window.location.toString().replace(/\\?.*$/,"").split("/");a.pop();_editor_url=Xinha._resolveRelativeUrl(a.join("/"),_editor_url)})()}}else{alert("WARNING: _editor_url is not set! You should set this variable to the editor files path; it should preferably be an absolute path, like in \'/xinha/\', but it can be relative if you prefer. Further we will try to load the editor files correctly but we\'ll probably fail.");_editor_url=""}if(typeof _editor_lang=="string"){_editor_lang=_editor_lang.toLowerCase()}else{_editor_lang="en"}if(typeof _editor_skin!=="string"){_editor_skin=""}if(typeof _editor_icons!=="string"){_editor_icons=""}var __xinhas=[];Xinha.agt=navigator.userAgent.toLowerCase();Xinha.is_ie=((Xinha.agt.indexOf("msie")!=-1)&&(Xinha.agt.indexOf("opera")==-1));Xinha.ie_version=parseFloat(Xinha.agt.substring(Xinha.agt.indexOf("msie")+5));Xinha.is_opera=(Xinha.agt.indexOf("opera")!=-1);if(Xinha.is_opera&&Xinha.agt.match(/opera[\\/ ]([0-9.]+)/)){Xinha.opera_version=parseFloat(RegExp.$1)}else{Xinha.opera_version=0}Xinha.is_khtml=(Xinha.agt.indexOf("khtml")!=-1);Xinha.is_webkit=(Xinha.agt.indexOf("applewebkit")!=-1);Xinha.webkit_version=parseInt(navigator.appVersion.replace(/.*?AppleWebKit\\/([\\d]).*?/,"$1"),10);Xinha.is_safari=(Xinha.agt.indexOf("safari")!=-1);Xinha.is_chrome=(Xinha.agt.indexOf("chrome")!=-1);Xinha.is_mac=(Xinha.agt.indexOf("mac")!=-1);Xinha.is_mac_ie=(Xinha.is_ie&&Xinha.is_mac);Xinha.is_win_ie=(Xinha.is_ie&&!Xinha.is_mac);Xinha.is_gecko=(navigator.product=="Gecko")||Xinha.is_opera;Xinha.is_real_gecko=(navigator.product=="Gecko"&&!Xinha.is_webkit);Xinha.is_ff2=Xinha.is_real_gecko&&parseInt(navigator.productSub.substr(0,10),10)<20071210;Xinha.isRunLocally=document.URL.toLowerCase().search(/^file:/)!=-1;Xinha.is_designMode=(typeof document.designMode!="undefined"&&!Xinha.is_ie);Xinha.checkSupportedBrowser=function(){return Xinha.is_real_gecko||(Xinha.is_opera&&Xinha.opera_version>=9.2)||Xinha.ie_version>=5.5||Xinha.webkit_version>=522};Xinha.isSupportedBrowser=Xinha.checkSupportedBrowser();if(Xinha.isRunLocally&&Xinha.isSupportedBrowser){alert(\'Xinha *must* be installed on a web server. Locally opened files (those that use the "file://" protocol) cannot properly function. Xinha will try to initialize but may not be correctly loaded.\')}function Xinha(d,c){if(!Xinha.isSupportedBrowser){return}if(!d){throw new Error("Tried to create Xinha without textarea specified.")}if(typeof c=="undefined"){this.config=new Xinha.Config()}else{this.config=c}if(typeof d!="object"){d=Xinha.getElementById("textarea",d)}this._textArea=d;this._textArea.spellcheck=false;Xinha.freeLater(this,"_textArea");this._initial_ta_size={w:d.style.width?d.style.width:(d.offsetWidth?(d.offsetWidth+"px"):(d.cols+"em")),h:d.style.height?d.style.height:(d.offsetHeight?(d.offsetHeight+"px"):(d.rows+"em"))};if(document.getElementById("loading_"+d.id)||this.config.showLoading){if(!document.getElementById("loading_"+d.id)){Xinha.createLoadingMessage(d)}this.setLoadingMessage(Xinha._lc("Constructing object"))}this._editMode="wysiwyg";this.plugins={};this._timerToolbar=null;this._timerUndo=null;this._undoQueue=[this.config.undoSteps];this._undoPos=-1;this._customUndo=true;this._mdoc=document;this.doctype="";this.__htmlarea_id_num=__xinhas.length;__xinhas[this.__htmlarea_id_num]=this;this._notifyListeners={};var b={right:{on:true,container:document.createElement("td"),panels:[]},left:{on:true,container:document.createElement("td"),panels:[]},top:{on:true,container:document.createElement("td"),panels:[]},bottom:{on:true,container:document.createElement("td"),panels:[]}};for(var a in b){if(!b[a].container){continue}b[a].div=b[a].container;b[a].container.className="panels panels_"+a;Xinha.freeLater(b[a],"container");Xinha.freeLater(b[a],"div")}this._panels=b;this._statusBar=null;this._statusBarTree=null;this._statusBarTextMode=null;this._statusBarItems=[];this._framework={};this._htmlArea=null;this._iframe=null;this._doc=null;this._toolBar=this._toolbar=null;this._toolbarObjects={};this.plugins.Events={name:"Events",developer:"The Xinha Core Developer Team",instance:c.Events}}Xinha.onload=function(){};Xinha.init=function(){Xinha.onload()};Xinha.RE_tagName=/(<\\/|<)\\s*([^ \\t\\n>]+)/ig;Xinha.RE_doctype=/(<!doctype((.|\\n)*?)>)\\n?/i;Xinha.RE_head=/<head>((.|\\n)*?)<\\/head>/i;Xinha.RE_body=/<body[^>]*>((.|\\n|\\r|\\t)*?)<\\/body>/i;Xinha.RE_Specials=/([\\/\\^$*+?.()|{}\\[\\]])/g;Xinha.escapeStringForRegExp=function(a){return a.replace(Xinha.RE_Specials,"\\\\$1")};Xinha.RE_email=/^[_a-z\\d\\-\\.]{3,}@[_a-z\\d\\-]{2,}(\\.[_a-z\\d\\-]{2,})+$/i;Xinha.RE_url=/(https?:\\/\\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_\\-]{2,}(\\.[a-z0-9_\\-]{2,}){2,}(:[0-9]+)?(\\/\\S+)*)/i;Xinha.Config=function(){this.version=Xinha.version.Revision;this.width="auto";this.height="auto";this.sizeIncludesBars=true;this.sizeIncludesPanels=true;this.panel_dimensions={left:"200px",right:"200px",top:"100px",bottom:"100px"};this.iframeWidth=null;this.statusBar=true;this.htmlareaPaste=false;this.mozParaHandler="best";this.getHtmlMethod="DOMwalk";this.undoSteps=20;this.undoTimeout=500;this.changeJustifyWithDirection=false;this.fullPage=false;this.pageStyle="";this.pageStyleSheets=[];this.baseHref=null;this.expandRelativeUrl=true;this.stripBaseHref=true;this.stripSelfNamedAnchors=true;this.only7BitPrintablesInURLs=true;this.sevenBitClean=false;this.specialReplacements={};this.inwardHtml=function(c){return c};this.outwardHtml=function(c){return c};this.autofocus=false;this.killWordOnPaste=true;this.makeLinkShowsTarget=true;this.charSet=(typeof document.characterSet!="undefined")?document.characterSet:document.charset;this.browserQuirksMode=null;this.imgURL="images/";this.popupURL="popups/";this.htmlRemoveTags=null;this.flowToolbars=true;this.toolbarAlign="left";this.showFontStylesInToolbar=false;this.showLoading=false;this.stripScripts=true;this.convertUrlsToLinks=true;this.colorPickerCellSize="6px";this.colorPickerGranularity=18;this.colorPickerPosition="bottom,right";this.colorPickerWebSafe=false;this.colorPickerSaveColors=20;this.fullScreen=false;this.fullScreenMargins=[0,0,0,0];this.fullScreenSizeDownMethod="initSize";this.toolbar=[["popupeditor"],["separator","formatblock","fontname","fontsize","bold","italic","underline","strikethrough"],["separator","forecolor","hilitecolor","textindicator"],["separator","subscript","superscript"],["linebreak","separator","justifyleft","justifycenter","justifyright","justifyfull"],["separator","insertorderedlist","insertunorderedlist","outdent","indent"],["separator","inserthorizontalrule","createlink","insertimage","inserttable"],["linebreak","separator","undo","redo","selectall","print"],(Xinha.is_gecko?[]:["cut","copy","paste","overwrite","saveas"]),["separator","killword","clearfonts","removeformat","toggleborders","splitblock","lefttoright","righttoleft"],["separator","htmlmode","showhelp","about"]];this.fontname={"— font —":"",Arial:"arial,helvetica,sans-serif","Courier New":"courier new,courier,monospace",Georgia:"georgia,times new roman,times,serif",Tahoma:"tahoma,arial,helvetica,sans-serif","Times New Roman":"times new roman,times,serif",Verdana:"verdana,arial,helvetica,sans-serif",impact:"impact",WingDings:"wingdings"};this.fontsize={"— size —":"","1 (8 pt)":"1","2 (10 pt)":"2","3 (12 pt)":"3","4 (14 pt)":"4","5 (18 pt)":"5","6 (24 pt)":"6","7 (36 pt)":"7"};this.formatblock={"— format —":"","Heading 1":"h1","Heading 2":"h2","Heading 3":"h3","Heading 4":"h4","Heading 5":"h5","Heading 6":"h6",Normal:"p",Address:"address",Formatted:"pre"};this.dialogOptions={centered:true,greyout:true,closeOnEscape:true};this.Events={};this.customSelects={};this.debug=false;this.URIs={blank:_editor_url+"popups/blank.html",link:_editor_url+"modules/CreateLink/link.html",insert_image:_editor_url+"modules/InsertImage/insert_image.html",insert_table:_editor_url+"modules/InsertTable/insert_table.html",select_color:_editor_url+"popups/select_color.html",help:_editor_url+"popups/editor_help.html"};this.btnList={bold:["Bold",Xinha._lc({key:"button_bold",string:["ed_buttons_main.png",3,2]},"Xinha"),false,function(c){c.execCommand("bold")}],italic:["Italic",Xinha._lc({key:"button_italic",string:["ed_buttons_main.png",2,2]},"Xinha"),false,function(c){c.execCommand("italic")}],underline:["Underline",Xinha._lc({key:"button_underline",string:["ed_buttons_main.png",2,0]},"Xinha"),false,function(c){c.execCommand("underline")}],strikethrough:["Strikethrough",Xinha._lc({key:"button_strikethrough",string:["ed_buttons_main.png",3,0]},"Xinha"),false,function(c){c.execCommand("strikethrough")}],subscript:["Subscript",Xinha._lc({key:"button_subscript",string:["ed_buttons_main.png",3,1]},"Xinha"),false,function(c){c.execCommand("subscript")}],superscript:["Superscript",Xinha._lc({key:"button_superscript",string:["ed_buttons_main.png",2,1]},"Xinha"),false,function(c){c.execCommand("superscript")}],justifyleft:["Justify Left",["ed_buttons_main.png",0,0],false,function(c){c.execCommand("justifyleft")}],justifycenter:["Justify Center",["ed_buttons_main.png",1,1],false,function(c){c.execCommand("justifycenter")}],justifyright:["Justify Right",["ed_buttons_main.png",1,0],false,function(c){c.execCommand("justifyright")}],justifyfull:["Justify Full",["ed_buttons_main.png",0,1],false,function(c){c.execCommand("justifyfull")}],orderedlist:["Ordered List",["ed_buttons_main.png",0,3],false,function(c){c.execCommand("insertorderedlist")}],unorderedlist:["Bulleted List",["ed_buttons_main.png",1,3],false,function(c){c.execCommand("insertunorderedlist")}],insertorderedlist:["Ordered List",["ed_buttons_main.png",0,3],false,function(c){c.execCommand("insertorderedlist")}],insertunorderedlist:["Bulleted List",["ed_buttons_main.png",1,3],false,function(c){c.execCommand("insertunorderedlist")}],outdent:["Decrease Indent",["ed_buttons_main.png",1,2],false,function(c){c.execCommand("outdent")}],indent:["Increase Indent",["ed_buttons_main.png",0,2],false,function(c){c.execCommand("indent")}],forecolor:["Font Color",["ed_buttons_main.png",3,3],false,function(c){c.execCommand("forecolor")}],hilitecolor:["Background Color",["ed_buttons_main.png",2,3],false,function(c){c.execCommand("hilitecolor")}],undo:["Undoes your last action",["ed_buttons_main.png",4,2],false,function(c){c.execCommand("undo")}],redo:["Redoes your last action",["ed_buttons_main.png",5,2],false,function(c){c.execCommand("redo")}],cut:["Cut selection",["ed_buttons_main.png",5,0],false,function(d,c){d.execCommand(c)}],copy:["Copy selection",["ed_buttons_main.png",4,0],false,function(d,c){d.execCommand(c)}],paste:["Paste from clipboard",["ed_buttons_main.png",4,1],false,function(d,c){d.execCommand(c)}],selectall:["Select all",["ed_buttons_main.png",3,5],false,function(c){c.execCommand("selectall")}],inserthorizontalrule:["Horizontal Rule",["ed_buttons_main.png",6,0],false,function(c){c.execCommand("inserthorizontalrule")}],createlink:["Insert Web Link",["ed_buttons_main.png",6,1],false,function(c){c._createLink()}],insertimage:["Insert/Modify Image",["ed_buttons_main.png",6,3],false,function(c){c.execCommand("insertimage")}],inserttable:["Insert Table",["ed_buttons_main.png",6,2],false,function(c){c.execCommand("inserttable")}],htmlmode:["Toggle HTML Source",["ed_buttons_main.png",7,0],true,function(c){c.execCommand("htmlmode")}],toggleborders:["Toggle Borders",["ed_buttons_main.png",7,2],false,function(c){c._toggleBorders()}],print:["Print document",["ed_buttons_main.png",8,1],false,function(c){if(Xinha.is_gecko){c._iframe.contentWindow.print()}else{c.focusEditor();print()}}],saveas:["Save as",["ed_buttons_main.png",9,1],false,function(c){c.execCommand("saveas",false,"noname.htm")}],about:["About this editor",["ed_buttons_main.png",8,2],true,function(c){c.getPluginInstance("AboutBox").show()}],showhelp:["Help using editor",["ed_buttons_main.png",9,2],true,function(c){c.execCommand("showhelp")}],splitblock:["Split Block","ed_splitblock.gif",false,function(c){c._splitBlock()}],lefttoright:["Direction left to right",["ed_buttons_main.png",0,2],false,function(c){c.execCommand("lefttoright")}],righttoleft:["Direction right to left",["ed_buttons_main.png",1,2],false,function(c){c.execCommand("righttoleft")}],overwrite:["Insert/Overwrite","ed_overwrite.gif",false,function(c){c.execCommand("overwrite")}],wordclean:["MS Word Cleaner",["ed_buttons_main.png",5,3],false,function(c){c._wordClean()}],clearfonts:["Clear Inline Font Specifications",["ed_buttons_main.png",5,4],true,function(c){c._clearFonts()}],removeformat:["Remove formatting",["ed_buttons_main.png",4,4],false,function(c){c.execCommand("removeformat")}],killword:["Clear MSOffice tags",["ed_buttons_main.png",4,3],false,function(c){c.execCommand("killword")}]};this.dblclickList={a:[function(c,d){c._createLink(d)}],img:[function(c,d){c._insertImage(d)}]};this.iconList={dialogCaption:_editor_url+"images/xinha-small-icon.gif",wysiwygmode:[_editor_url+"images/ed_buttons_main.png",7,1]};for(var b in this.btnList){var a=this.btnList[b];if(typeof a!="object"){continue}if(typeof a[1]!="string"){a[1][0]=_editor_url+this.imgURL+a[1][0]}else{a[1]=_editor_url+this.imgURL+a[1]}a[0]=Xinha._lc(a[0])}};Xinha.Config.prototype.registerIcon=function(b,a){this.iconList[b]=a};Xinha.Config.prototype.registerButton=function(f,b,e,d,a,c){if(typeof f=="string"){this.btnList[f]=[b,e,d,a,c]}else{if(typeof f=="object"){this.btnList[f.id]=[f.tooltip,f.image,f.textMode,f.action,f.context]}else{alert("ERROR [Xinha.Config::registerButton]:\\ninvalid arguments");return false}}};Xinha.prototype.registerPanel=function(c,b){if(!c){c="right"}this.setLoadingMessage("Register "+c+" panel ");var a=this.addPanel(c);if(b){b.drawPanelIn(a)}};Xinha.Config.prototype.registerDropdown=function(a){this.customSelects[a.id]=a};Xinha.Config.prototype.hideSomeButtons=function(f){var c=this.toolbar;for(var e=c.length;--e>=0;){var b=c[e];for(var d=b.length;--d>=0;){if(f.indexOf(" "+b[d]+" ")>=0){var a=1;if(/separator|space/.test(b[d+1])){a=2}b.splice(d,a)}}}};Xinha.Config.prototype.addToolbarElement=function(d,k,m){var s=this.toolbar;var q,l,h,f,c;var p=false;var b=false;var n=0;var g=0;var e=0;var r=false;var t=false;if((d&&typeof d=="object")&&(d.constructor==Array)){p=true}if((k&&typeof k=="object")&&(k.constructor==Array)){b=true;n=k.length}if(p){for(l=0;l<d.length;++l){if((d[l]!="separator")&&(d[l].indexOf("T[")!==0)){c=d[l]}}}else{c=d}for(l=0;l<s.length;++l){q=s[l];for(h=0;h<q.length;++h){if(q[h]==c){return}}}for(l=0;!t&&l<s.length;++l){q=s[l];for(h=0;!t&&h<q.length;++h){if(b){for(f=0;f<n;++f){if(q[h]==k[f]){if(f===0){t=true;h--;break}else{e=l;g=h;n=f}}}}else{if(q[h]==k){t=true;break}}}}if(!t&&b){if(k.length!=n){h=g;q=s[e];t=true}}if(t){if(m===0){if(p){q[h]=d[d.length-1];for(l=d.length-1;--l>=0;){q.splice(h,0,d[l])}}else{q[h]=d}}else{if(m<0){h=h+m+1}else{if(m>0){h=h+m}}if(p){for(l=d.length;--l>=0;){q.splice(h,0,d[l])}}else{q.splice(h,0,d)}}}else{s[0].splice(0,0,"separator");if(p){for(l=d.length;--l>=0;){s[0].splice(0,0,d[l])}}else{s[0].splice(0,0,d)}}};Xinha.Config.prototype.removeToolbarElement=Xinha.Config.prototype.hideSomeButtons;Xinha.replaceAll=function(b){var c=document.getElementsByTagName("textarea");for(var a=c.length;a>0;new Xinha(c[--a],b).generate()){}};Xinha.replace=function(c,b){var a=Xinha.getElementById("textarea",c);return a?new Xinha(a,b).generate():null};Xinha.prototype._createToolbar=function(){this.setLoadingMessage(Xinha._lc("Create Toolbar"));var b=this;var a=document.createElement("div");this._toolBar=this._toolbar=a;a.className="toolbar";a.align=this.config.toolbarAlign;Xinha.freeLater(this,"_toolBar");Xinha.freeLater(this,"_toolbar");var c=null;var e={};this._toolbarObjects=e;this._createToolbar1(b,a,e);function d(g){if(g.tagName){g.unselectable="on"}if(g.childNodes){for(var f=0;f<g.childNodes.length;f++){if(g.tagName){d(g.childNodes(f))}}}}if(Xinha.is_ie){d(a)}this._htmlArea.appendChild(a);return a};Xinha.prototype._setConfig=function(a){this.config=a};Xinha.prototype._rebuildToolbar=function(){this._createToolbar1(this,this._toolbar,this._toolbarObjects);if(Xinha._currentlyActiveEditor){if(Xinha._currentlyActiveEditor==this){this.activateEditor()}}else{this.disableToolbar()}};Xinha._createToolbarBreakingElement=function(){var a=document.createElement("div");a.style.height="1px";a.style.width="1px";a.style.lineHeight="1px";a.style.fontSize="1px";a.style.clear="both";return a};Xinha.prototype._createToolbar1=function(d,s,p){while(s.lastChild){s.removeChild(s.lastChild)}var l;if(d.config.flowToolbars){s.appendChild(Xinha._createToolbarBreakingElement())}function n(){if(typeof l!="undefined"&&l.childNodes.length===0){return}var i=document.createElement("table");i.border="0px";i.cellSpacing="0px";i.cellPadding="0px";if(d.config.flowToolbars){if(Xinha.is_ie){i.style.styleFloat="left"}else{i.style.cssFloat="left"}}s.appendChild(i);var j=document.createElement("tbody");i.appendChild(j);l=document.createElement("tr");j.appendChild(l);i.className="toolbarRow"}n();function m(u,i){var j=this[u];var t=this.element;if(j!=i){switch(u){case"enabled":if(i){Xinha._removeClass(t,"buttonDisabled");t.disabled=false}else{Xinha._addClass(t,"buttonDisabled");t.disabled=true}break;case"active":if(i){Xinha._addClass(t,"buttonPressed")}else{Xinha._removeClass(t,"buttonPressed")}break}this[u]=i}}function c(x){var A=null;var t=null;var u=null;var C=d.config.customSelects;var j=null;var z="";switch(x){case"fontsize":case"fontname":case"formatblock":A=d.config[x];u=x;break;default:u=x;var B=C[u];if(typeof B!="undefined"){A=B.options;j=B.context;if(typeof B.tooltip!="undefined"){z=B.tooltip}}else{alert("ERROR [createSelect]:\\nCan\'t find the requested dropdown definition")}break}if(A){t=document.createElement("select");t.title=z;t.style.width="auto";t.name=x;var w={name:x,element:t,enabled:true,text:false,cmd:u,state:m,context:j};Xinha.freeLater(w);p[x]=w;for(var v in A){if(typeof A[v]!="string"){continue}var y=document.createElement("option");y.innerHTML=Xinha._lc(v);y.value=A[v];if(x=="fontname"&&d.config.showFontStylesInToolbar){y.style.fontFamily=A[v]}t.appendChild(y)}Xinha._addEvent(t,"change",function(){d._comboSelected(t,x)})}return t}function q(i){var u,t,w=null;switch(i){case"separator":if(d.config.flowToolbars){n()}u=document.createElement("div");u.className="separator";break;case"space":u=document.createElement("div");u.className="space";break;case"linebreak":n();return false;case"textindicator":u=document.createElement("div");u.appendChild(document.createTextNode("A"));u.className="indicator";u.title=Xinha._lc("Current style");w={name:i,element:u,enabled:true,active:false,text:false,cmd:"textindicator",state:m};Xinha.freeLater(w);p[i]=w;break;default:t=d.config.btnList[i]}if(!u&&t){u=document.createElement("a");u.style.display="block";u.href="javascript:void(0)";u.style.textDecoration="none";u.title=t[0];u.className="button";u.style.direction="ltr";w={name:i,element:u,enabled:true,active:false,text:t[2],cmd:t[3],state:m,context:t[4]||null};Xinha.freeLater(u);Xinha.freeLater(w);p[i]=w;u.ondrag=function(){return false};Xinha._addEvent(u,"mouseout",function(x){if(w.enabled){Xinha._removeClass(u,"buttonActive");if(w.active){Xinha._addClass(u,"buttonPressed")}}});Xinha._addEvent(u,"mousedown",function(x){if(w.enabled){Xinha._addClass(u,"buttonActive");Xinha._removeClass(u,"buttonPressed");Xinha._stopEvent(Xinha.is_ie?window.event:x)}});Xinha._addEvent(u,"click",function(x){x=x||window.event;d.btnClickEvent={clientX:x.clientX,clientY:x.clientY};if(w.enabled){Xinha._removeClass(u,"buttonActive");if(Xinha.is_gecko){d.activateEditor()}w.cmd(d,w.name,w,x);Xinha._stopEvent(x)}});var v=Xinha.makeBtnImg(t[1]);var j=v.firstChild;Xinha.freeLater(v);Xinha.freeLater(j);u.appendChild(v);w.imgel=j;w.swapImage=function(x){if(typeof x!="string"){j.src=x[0];j.style.position="relative";j.style.top=x[2]?("-"+(18*(x[2]+1))+"px"):"-18px";j.style.left=x[1]?("-"+(18*(x[1]+1))+"px"):"-18px"}else{w.imgel.src=x;j.style.top="0px";j.style.left="0px"}}}else{if(!u){u=c(i)}}return u}var k=true;for(var h=0;h<this.config.toolbar.length;++h){if(!k){}else{k=false}if(this.config.toolbar[h]===null){this.config.toolbar[h]=["separator"]}var r=this.config.toolbar[h];for(var g=0;g<r.length;++g){var b=r[g];var a;if(/^([IT])\\[(.*?)\\]/.test(b)){var f=RegExp.$1=="I";var o=RegExp.$2;if(f){o=Xinha._lc(o)}a=document.createElement("td");l.appendChild(a);a.className="label";a.innerHTML=o}else{if(typeof b!="function"){var e=q(b);if(e){a=document.createElement("td");a.className="toolbarElement";l.appendChild(a);a.appendChild(e)}else{if(e===null){alert("FIXME: Unknown toolbar item: "+b)}}}}}}if(d.config.flowToolbars){s.appendChild(Xinha._createToolbarBreakingElement())}return s};Xinha.makeBtnImg=function(b,d){if(!d){d=document}if(!d._xinhaImgCache){d._xinhaImgCache={};Xinha.freeLater(d._xinhaImgCache)}var c=null;if(Xinha.is_ie&&((!d.compatMode)||(d.compatMode&&d.compatMode=="BackCompat"))){c=d.createElement("span")}else{c=d.createElement("div");c.style.position="relative"}c.style.overflow="hidden";c.style.width="18px";c.style.height="18px";c.className="buttonImageContainer";var a=null;if(typeof b=="string"){if(d._xinhaImgCache[b]){a=d._xinhaImgCache[b].cloneNode()}else{if(Xinha.ie_version<7&&/\\.png$/.test(b[0])){a=d.createElement("span");a.style.display="block";a.style.width="18px";a.style.height="18px";a.style.filter=\'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="\'+b+\'")\';a.unselectable="on"}else{a=d.createElement("img");a.src=b}}}else{if(d._xinhaImgCache[b[0]]){a=d._xinhaImgCache[b[0]].cloneNode()}else{if(Xinha.ie_version<7&&/\\.png$/.test(b[0])){a=d.createElement("span");a.style.display="block";a.style.width="18px";a.style.height="18px";a.style.filter=\'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="\'+b[0]+\'")\';a.unselectable="on"}else{a=d.createElement("img");a.src=b[0]}a.style.position="relative"}a.style.top=b[2]?("-"+(18*(b[2]+1))+"px"):"-18px";a.style.left=b[1]?("-"+(18*(b[1]+1))+"px"):"-18px"}c.appendChild(a);return c};Xinha.prototype._createStatusBar=function(){this.setLoadingMessage(Xinha._lc("Create Statusbar"));var b=document.createElement("div");b.style.position="relative";b.className="statusBar";b.style.width="100%";Xinha.freeLater(this,"_statusBar");var d=document.createElement("div");d.className="statusBarWidgetContainer";d.style.position="absolute";d.style.right="0";d.style.top="0";d.style.padding="3px 3px 3px 10px";b.appendChild(d);var e=document.createElement("span");e.className="statusBarTree";e.innerHTML=Xinha._lc("Path")+": ";this._statusBarTree=e;Xinha.freeLater(this,"_statusBarTree");b.appendChild(e);var c=document.createElement("span");c.innerHTML=Xinha.htmlEncode(Xinha._lc("You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG."));c.style.display="none";this._statusBarTextMode=c;Xinha.freeLater(this,"_statusBarTextMode");b.appendChild(c);b.style.whiteSpace="nowrap";var a=this;this.notifyOn("before_resize",function(f,g){a._statusBar.style.width=null});this.notifyOn("resize",function(f,g){if(Xinha.is_ie&&Xinha.ie_version==6){a._statusBar.style.width="100%"}else{var h=g.width;a._statusBar.style.width=h+"px"}});this.notifyOn("modechange",function(g,l){for(var j in a._statusWidgets){var f=a._statusWidgets[j];for(var h=0;h<f.modes.length;h++){if(f.modes[h]==l.mode){var k=true}}if(typeof k=="undefined"){f.block.style.display="none"}else{f.block.style.display=""}}});if(!this.config.statusBar){b.style.display="none"}return b};Xinha.prototype.registerStatusWidget=function(e,c){c=c||["wysiwyg"];if(!this._statusWidgets){this._statusWidgets={}}var d=document.createElement("div");d.className="statusBarWidget";d=this._statusBar.firstChild.appendChild(d);var b=false;for(var a=0;a<c.length;a++){if(c[a]==this._editMode){b=true}}d.style.display=b==true?"":"none";this._statusWidgets[e]={block:d,modes:c};return d};Xinha.prototype.generate=function(){if(!Xinha.isSupportedBrowser){return}var w;var k=this;var g;var o=false;var c=document.getElementsByTagName("link");if(!document.getElementById("XinhaCoreDesign")){_editor_css=(typeof _editor_css=="string")?_editor_css:"Xinha.css";for(w=0;w<c.length;w++){if((c[w].rel=="stylesheet")&&(c[w].href==_editor_url+_editor_css)){o=true}}if(!o){Xinha.loadStyle(_editor_css,null,"XinhaCoreDesign",true)}}if(_editor_skin!==""&&!document.getElementById("XinhaSkin")){o=false;for(w=0;w<c.length;w++){if((c[w].rel=="stylesheet")&&(c[w].href==_editor_url+"skins/"+_editor_skin+"/skin.css")){o=true}}if(!o){Xinha.loadStyle("skins/"+_editor_skin+"/skin.css",null,"XinhaSkin")}}var h=function(){k.generate()};if(Xinha.is_ie){g=_editor_url+"modules/InternetExplorer/InternetExplorer.js";if(!Xinha.loadPlugins([{plugin:"InternetExplorer",url:g}],h)){return false}if(!this.plugins.InternetExplorer){k._browserSpecificPlugin=k.registerPlugin("InternetExplorer")}}else{if(Xinha.is_webkit){g=_editor_url+"modules/WebKit/WebKit.js";if(!Xinha.loadPlugins([{plugin:"WebKit",url:g}],h)){return false}if(!this.plugins.Webkit){k._browserSpecificPlugin=k.registerPlugin("WebKit")}}else{if(Xinha.is_opera){g=_editor_url+"modules/Opera/Opera.js";if(!Xinha.loadPlugins([{plugin:"Opera",url:g}],h)){return false}if(!this.plugins.Opera){k._browserSpecificPlugin=k.registerPlugin("Opera")}}else{if(Xinha.is_gecko){g=_editor_url+"modules/Gecko/Gecko.js";if(!Xinha.loadPlugins([{plugin:"Gecko",url:g}],h)){return false}if(!this.plugins.Gecko){k._browserSpecificPlugin=k.registerPlugin("Gecko")}}}}}if(typeof Dialog=="undefined"&&!Xinha._loadback(_editor_url+"modules/Dialogs/dialog.js",h,this)){return false}if(typeof Xinha.Dialog=="undefined"&&!Xinha._loadback(_editor_url+"modules/Dialogs/XinhaDialog.js",h,this)){return false}g=_editor_url+"modules/FullScreen/full-screen.js";if(!Xinha.loadPlugins([{plugin:"FullScreen",url:g}],h)){return false}g=_editor_url+"modules/ColorPicker/ColorPicker.js";if(!Xinha.loadPlugins([{plugin:"ColorPicker",url:g}],h)){return false}else{if(typeof Xinha.getPluginConstructor("ColorPicker")!="undefined"&&!this.plugins.colorPicker){k.registerPlugin("ColorPicker")}}var a=k.config.toolbar;for(w=a.length;--w>=0;){for(var v=a[w].length;--v>=0;){switch(a[w][v]){case"popupeditor":if(!this.plugins.FullScreen){k.registerPlugin("FullScreen")}break;case"insertimage":g=_editor_url+"modules/InsertImage/insert_image.js";if(typeof Xinha.prototype._insertImage=="undefined"&&!Xinha.loadPlugins([{plugin:"InsertImage",url:g}],h)){return false}else{if(typeof Xinha.getPluginConstructor("InsertImage")!="undefined"&&!this.plugins.InsertImage){k.registerPlugin("InsertImage")}}break;case"createlink":g=_editor_url+"modules/CreateLink/link.js";if(typeof Xinha.getPluginConstructor("Linker")=="undefined"&&!Xinha.loadPlugins([{plugin:"CreateLink",url:g}],h)){return false}else{if(typeof Xinha.getPluginConstructor("CreateLink")!="undefined"&&!this.plugins.CreateLink){k.registerPlugin("CreateLink")}}break;case"inserttable":g=_editor_url+"modules/InsertTable/insert_table.js";if(!Xinha.loadPlugins([{plugin:"InsertTable",url:g}],h)){return false}else{if(typeof Xinha.getPluginConstructor("InsertTable")!="undefined"&&!this.plugins.InsertTable){k.registerPlugin("InsertTable")}}break;case"about":g=_editor_url+"modules/AboutBox/AboutBox.js";if(!Xinha.loadPlugins([{plugin:"AboutBox",url:g}],h)){return false}else{if(typeof Xinha.getPluginConstructor("AboutBox")!="undefined"&&!this.plugins.AboutBox){k.registerPlugin("AboutBox")}}break}}}if(Xinha.is_gecko&&k.config.mozParaHandler!="built-in"){if(!Xinha.loadPlugins([{plugin:"EnterParagraphs",url:_editor_url+"modules/Gecko/paraHandlerBest.js"}],h)){return false}if(!this.plugins.EnterParagraphs){k.registerPlugin("EnterParagraphs")}}var C=this.config.getHtmlMethod=="TransformInnerHTML"?_editor_url+"modules/GetHtml/TransformInnerHTML.js":_editor_url+"modules/GetHtml/DOMwalk.js";if(!Xinha.loadPlugins([{plugin:"GetHtmlImplementation",url:C}],h)){return false}else{if(!this.plugins.GetHtmlImplementation){k.registerPlugin("GetHtmlImplementation")}}function D(i){return i.textContent||i.text}if(_editor_skin){this.skinInfo={};var s=Xinha._geturlcontent(_editor_url+"skins/"+_editor_skin+"/skin.xml",true);if(s){var p=s.getElementsByTagName("meta");for(w=0;w<p.length;w++){this.skinInfo[p[w].getAttribute("name")]=p[w].getAttribute("value")}var t=s.getElementsByTagName("recommendedIcons");if(!_editor_icons&&t.length&&D(t[0])){_editor_icons=D(t[0])}}}if(_editor_icons){var b=Xinha._geturlcontent(_editor_url+"iconsets/"+_editor_icons+"/iconset.xml",true);if(b){var E=b.getElementsByTagName("icon");var A,r,q,f,n,m;for(w=0;w<E.length;w++){A=E[w];r=A.getAttribute("id");if(A.getElementsByTagName(_editor_lang).length){A=A.getElementsByTagName(_editor_lang)[0]}else{A=A.getElementsByTagName("default")[0]}q=D(A.getElementsByTagName("path")[0]);q=(!/^\\//.test(q)?_editor_url:"")+q;f=A.getAttribute("type");if(f=="map"){n=parseInt(D(A.getElementsByTagName("x")[0]),10);m=parseInt(D(A.getElementsByTagName("y")[0]),10);if(this.config.btnList[r]){this.config.btnList[r][1]=[q,n,m]}if(this.config.iconList[r]){this.config.iconList[r]=[q,n,m]}}else{if(this.config.btnList[r]){this.config.btnList[r][1]=q}if(this.config.iconList[r]){this.config.iconList[r]=q}}}}}this.setLoadingMessage(Xinha._lc("Generate Xinha framework"));this._framework={table:document.createElement("table"),tbody:document.createElement("tbody"),tb_row:document.createElement("tr"),tb_cell:document.createElement("td"),tp_row:document.createElement("tr"),tp_cell:this._panels.top.container,ler_row:document.createElement("tr"),lp_cell:this._panels.left.container,ed_cell:document.createElement("td"),rp_cell:this._panels.right.container,bp_row:document.createElement("tr"),bp_cell:this._panels.bottom.container,sb_row:document.createElement("tr"),sb_cell:document.createElement("td")};Xinha.freeLater(this._framework);var e=this._framework;e.table.border="0";e.table.cellPadding="0";e.table.cellSpacing="0";e.tb_row.style.verticalAlign="top";e.tp_row.style.verticalAlign="top";e.ler_row.style.verticalAlign="top";e.bp_row.style.verticalAlign="top";e.sb_row.style.verticalAlign="top";e.ed_cell.style.position="relative";e.tb_row.appendChild(e.tb_cell);e.tb_cell.colSpan=3;e.tp_row.appendChild(e.tp_cell);e.tp_cell.colSpan=3;e.ler_row.appendChild(e.lp_cell);e.ler_row.appendChild(e.ed_cell);e.ler_row.appendChild(e.rp_cell);e.bp_row.appendChild(e.bp_cell);e.bp_cell.colSpan=3;e.sb_row.appendChild(e.sb_cell);e.sb_cell.colSpan=3;e.tbody.appendChild(e.tb_row);e.tbody.appendChild(e.tp_row);e.tbody.appendChild(e.ler_row);e.tbody.appendChild(e.bp_row);e.tbody.appendChild(e.sb_row);e.table.appendChild(e.tbody);var B=e.table;this._htmlArea=B;Xinha.freeLater(this,"_htmlArea");B.className="htmlarea";e.tb_cell.appendChild(this._createToolbar());var d=document.createElement("iframe");d.src=this.popupURL(k.config.URIs.blank);d.id="XinhaIFrame_"+this._textArea.id;e.ed_cell.appendChild(d);this._iframe=d;this._iframe.className="xinha_iframe";Xinha.freeLater(this,"_iframe");var u=this._createStatusBar();this._statusBar=e.sb_cell.appendChild(u);var F=this._textArea;F.parentNode.insertBefore(B,F);F.className="xinha_textarea";Xinha.removeFromParent(F);e.ed_cell.appendChild(F);Xinha.addDom0Event(this._textArea,"click",function(){if(Xinha._currentlyActiveEditor!=this){k.updateToolbar()}return true});if(F.form){Xinha.prependDom0Event(this._textArea.form,"submit",function(){k.firePluginEvent("onBeforeSubmit");k._textArea.value=k.outwardHtml(k.getHTML());return true});var l=F.value;Xinha.prependDom0Event(this._textArea.form,"reset",function(){k.setHTML(k.inwardHtml(l));k.updateToolbar();return true});if(!F.form.xinha_submit){try{F.form.xinha_submit=F.form.submit;F.form.submit=function(){this.onsubmit();this.xinha_submit()}}catch(z){}}}Xinha.prependDom0Event(window,"unload",function(){k.firePluginEvent("onBeforeUnload");F.value=k.outwardHtml(k.getHTML());if(!Xinha.is_ie){B.parentNode.replaceChild(F,B)}return true});F.style.display="none";k.initSize();this.setLoadingMessage(Xinha._lc("Finishing"));k._iframeLoadDone=false;if(Xinha.is_opera){k.initIframe()}else{Xinha._addEvent(this._iframe,"load",function(i){if(!k._iframeLoadDone){k._iframeLoadDone=true;k.initIframe()}return true})}};Xinha.prototype.initSize=function(){this.setLoadingMessage(Xinha._lc("Init editor size"));var a=this;var b=null;var c=null;switch(this.config.width){case"auto":b=this._initial_ta_size.w;break;case"toolbar":b=this._toolBar.offsetWidth+"px";break;default:b=/[^0-9]/.test(this.config.width)?this.config.width:this.config.width+"px";break}c=this.config.height=="auto"?this._initial_ta_size.h:/[^0-9]/.test(this.config.height)?this.config.height:this.config.height+"px";this.sizeEditor(b,c,this.config.sizeIncludesBars,this.config.sizeIncludesPanels);this.notifyOn("panel_change",function(){a.sizeEditor()})};Xinha.prototype.sizeEditor=function(c,o,j,a){if(this._risizing){return}this._risizing=true;var k=this._framework;this.notifyOf("before_resize",{width:c,height:o});this.firePluginEvent("onBeforeResize",c,o);this._iframe.style.height="100%";this._textArea.style.height="1px";this._iframe.style.width="0px";this._textArea.style.width="0px";if(j!==null){this._htmlArea.sizeIncludesToolbars=j}if(a!==null){this._htmlArea.sizeIncludesPanels=a}if(c){this._htmlArea.style.width=c;if(!this._htmlArea.sizeIncludesPanels){var p=this._panels.right;if(p.on&&p.panels.length&&Xinha.hasDisplayedChildren(p.div)){this._htmlArea.style.width=(this._htmlArea.offsetWidth+parseInt(this.config.panel_dimensions.right,10))+"px"}var l=this._panels.left;if(l.on&&l.panels.length&&Xinha.hasDisplayedChildren(l.div)){this._htmlArea.style.width=(this._htmlArea.offsetWidth+parseInt(this.config.panel_dimensions.left,10))+"px"}}}if(o){this._htmlArea.style.height=o;if(!this._htmlArea.sizeIncludesToolbars){this._htmlArea.style.height=(this._htmlArea.offsetHeight+this._toolbar.offsetHeight+this._statusBar.offsetHeight)+"px"}if(!this._htmlArea.sizeIncludesPanels){var e=this._panels.top;if(e.on&&e.panels.length&&Xinha.hasDisplayedChildren(e.div)){this._htmlArea.style.height=(this._htmlArea.offsetHeight+parseInt(this.config.panel_dimensions.top,10))+"px"}var n=this._panels.bottom;if(n.on&&n.panels.length&&Xinha.hasDisplayedChildren(n.div)){this._htmlArea.style.height=(this._htmlArea.offsetHeight+parseInt(this.config.panel_dimensions.bottom,10))+"px"}}}c=this._htmlArea.offsetWidth;o=this._htmlArea.offsetHeight;var b=this._panels;var d=this;var i=1;function h(q){if(b[q].on&&b[q].panels.length&&Xinha.hasDisplayedChildren(b[q].container)){b[q].container.style.display="";return true}else{b[q].container.style.display="none";return false}}if(h("left")){i+=1}if(h("right")){i+=1}k.tb_cell.colSpan=i;k.tp_cell.colSpan=i;k.bp_cell.colSpan=i;k.sb_cell.colSpan=i;if(!k.tp_row.childNodes.length){Xinha.removeFromParent(k.tp_row)}else{if(!Xinha.hasParentNode(k.tp_row)){k.tbody.insertBefore(k.tp_row,k.ler_row)}}if(!k.bp_row.childNodes.length){Xinha.removeFromParent(k.bp_row)}else{if(!Xinha.hasParentNode(k.bp_row)){k.tbody.insertBefore(k.bp_row,k.ler_row.nextSibling)}}if(!this.config.statusBar){Xinha.removeFromParent(k.sb_row)}else{if(!Xinha.hasParentNode(k.sb_row)){k.table.appendChild(k.sb_row)}}k.lp_cell.style.width=this.config.panel_dimensions.left;k.rp_cell.style.width=this.config.panel_dimensions.right;k.tp_cell.style.height=this.config.panel_dimensions.top;k.bp_cell.style.height=this.config.panel_dimensions.bottom;k.tb_cell.style.height=this._toolBar.offsetHeight+"px";k.sb_cell.style.height=this._statusBar.offsetHeight+"px";var m=o-this._toolBar.offsetHeight-this._statusBar.offsetHeight;if(h("top")){m-=parseInt(this.config.panel_dimensions.top,10)}if(h("bottom")){m-=parseInt(this.config.panel_dimensions.bottom,10)}this._iframe.style.height=m+"px";var f=c;if(h("left")){f-=parseInt(this.config.panel_dimensions.left,10)}if(h("right")){f-=parseInt(this.config.panel_dimensions.right,10)}var g=this.config.iframeWidth?parseInt(this.config.iframeWidth,10):null;this._iframe.style.width=(g&&g<f)?g+"px":f+"px";this._textArea.style.height=this._iframe.style.height;this._textArea.style.width=this._iframe.style.width;this.notifyOf("resize",{width:this._htmlArea.offsetWidth,height:this._htmlArea.offsetHeight});this.firePluginEvent("onResize",this._htmlArea.offsetWidth,this._htmlArea.offsetWidth);this._risizing=false};Xinha.prototype.registerPanel=function(c,b){if(!c){c="right"}this.setLoadingMessage("Register "+c+" panel ");var a=this.addPanel(c);if(b){b.drawPanelIn(a)}};Xinha.prototype.addPanel=function(a){var b=document.createElement("div");b.side=a;if(a=="left"||a=="right"){b.style.width=this.config.panel_dimensions[a];if(this._iframe){b.style.height=this._iframe.style.height}}Xinha.addClasses(b,"panel");this._panels[a].panels.push(b);this._panels[a].div.appendChild(b);this.notifyOf("panel_change",{action:"add",panel:b});this.firePluginEvent("onPanelChange","add",b);return b};Xinha.prototype.removePanel=function(a){this._panels[a.side].div.removeChild(a);var c=[];for(var b=0;b<this._panels[a.side].panels.length;b++){if(this._panels[a.side].panels[b]!=a){c.push(this._panels[a.side].panels[b])}}this._panels[a.side].panels=c;this.notifyOf("panel_change",{action:"remove",panel:a});this.firePluginEvent("onPanelChange","remove",a)};Xinha.prototype.hidePanel=function(a){if(a&&a.style.display!="none"){try{var c=this.scrollPos(this._iframe.contentWindow)}catch(b){}a.style.display="none";this.notifyOf("panel_change",{action:"hide",panel:a});this.firePluginEvent("onPanelChange","hide",a);try{this._iframe.contentWindow.scrollTo(c.x,c.y)}catch(b){}}};Xinha.prototype.showPanel=function(a){if(a&&a.style.display=="none"){try{var c=this.scrollPos(this._iframe.contentWindow)}catch(b){}a.style.display="";this.notifyOf("panel_change",{action:"show",panel:a});this.firePluginEvent("onPanelChange","show",a);try{this._iframe.contentWindow.scrollTo(c.x,c.y)}catch(b){}}};Xinha.prototype.hidePanels=function(b){if(typeof b=="undefined"){b=["left","right","top","bottom"]}var c=[];for(var a=0;a<b.length;a++){if(this._panels[b[a]].on){c.push(b[a]);this._panels[b[a]].on=false}}this.notifyOf("panel_change",{action:"multi_hide",sides:b});this.firePluginEvent("onPanelChange","multi_hide",b)};Xinha.prototype.showPanels=function(b){if(typeof b=="undefined"){b=["left","right","top","bottom"]}var c=[];for(var a=0;a<b.length;a++){if(!this._panels[b[a]].on){c.push(b[a]);this._panels[b[a]].on=true}}this.notifyOf("panel_change",{action:"multi_show",sides:b});this.firePluginEvent("onPanelChange","multi_show",b)};Xinha.objectProperties=function(c){var b=[];for(var a in c){b[b.length]=a}return b};Xinha.prototype.editorIsActivated=function(){try{return Xinha.is_designMode?this._doc.designMode=="on":this._doc.body.contentEditable}catch(a){return false}};Xinha._someEditorHasBeenActivated=false;Xinha._currentlyActiveEditor=null;Xinha.prototype.activateEditor=function(){if(this.currentModal){return}if(Xinha._currentlyActiveEditor){if(Xinha._currentlyActiveEditor==this){return true}Xinha._currentlyActiveEditor.deactivateEditor()}if(Xinha.is_designMode&&this._doc.designMode!="on"){try{if(this._iframe.style.display=="none"){this._iframe.style.display="";this._doc.designMode="on";this._iframe.style.display="none"}else{this._doc.designMode="on"}if(Xinha.is_opera){this.setEditorEvents(true)}}catch(b){}}else{if(Xinha.is_ie&&this._doc.body.contentEditable!==true){this._doc.body.contentEditable=true}}Xinha._someEditorHasBeenActivated=true;Xinha._currentlyActiveEditor=this;var a=this;this.enableToolbar()};Xinha.prototype.deactivateEditor=function(){this.disableToolbar();if(Xinha.is_designMode&&this._doc.designMode!="off"){try{this._doc.designMode="off"}catch(a){}}else{if(!Xinha.is_designMode&&this._doc.body.contentEditable!==false){this._doc.body.contentEditable=false}}if(Xinha._currentlyActiveEditor!=this){return}Xinha._currentlyActiveEditor=false};Xinha.prototype.initIframe=function(){this.disableToolbar();var g=null;var b=this;try{if(b._iframe.contentDocument){this._doc=b._iframe.contentDocument}else{this._doc=b._iframe.contentWindow.document}g=this._doc;if(!g){if(Xinha.is_gecko){setTimeout(function(){b.initIframe()},50);return false}else{alert("ERROR: IFRAME can\'t be initialized.")}}}catch(f){setTimeout(function(){b.initIframe()},50);return false}Xinha.freeLater(this,"_doc");g.open("text/html","replace");var e="",a;if(b.config.browserQuirksMode===false){a=\'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\'}else{if(b.config.browserQuirksMode===true){a=""}else{a=Xinha.getDoctype(document)}}if(!b.config.fullPage){e+=a+"\\n";e+="<html>\\n";e+="<head>\\n";e+=\'<meta http-equiv="Content-Type" content="text/html; charset=\'+b.config.charSet+\'">\\n\';if(typeof b.config.baseHref!="undefined"&&b.config.baseHref!==null){e+=\'<base href="\'+b.config.baseHref+\'"/>\\n\'}e+=Xinha.addCoreCSS();if(typeof b.config.pageStyleSheets!=="undefined"){for(var d=0;d<b.config.pageStyleSheets.length;d++){if(b.config.pageStyleSheets[d].length>0){e+=\'<link rel="stylesheet" type="text/css" href="\'+b.config.pageStyleSheets[d]+\'">\'}}}if(b.config.pageStyle){e+=\'<style type="text/css">\\n\'+b.config.pageStyle+"\\n</style>"}e+="</head>\\n";e+="<body"+(b.config.bodyID?(\' id="\'+b.config.bodyID+\'"\'):"")+(b.config.bodyClass?(\' class="\'+b.config.bodyClass+\'"\'):"")+">\\n";e+=b.inwardHtml(b._textArea.value);e+="</body>\\n";e+="</html>"}else{e=b.inwardHtml(b._textArea.value);if(e.match(Xinha.RE_doctype)){b.setDoctype(RegExp.$1)}var c=e.match(/<link\\s+[\\s\\S]*?["\']\\s*\\/?>/gi);e=e.replace(/<link\\s+[\\s\\S]*?["\']\\s*\\/?>\\s*/gi,"");if(c){e=e.replace(/<\\/head>/i,c.join("\\n")+"\\n</head>")}}g.write(e);g.close();if(this.config.fullScreen){this._fullScreen()}this.setEditorEvents();if((typeof b.config.autofocus!="undefined")&&b.config.autofocus!==false&&((b.config.autofocus==b._textArea.id)||b.config.autofocus==true)){b.activateEditor();b.focusEditor()}};Xinha.prototype.whenDocReady=function(a){var b=this;if(this._doc&&this._doc.body){a()}else{setTimeout(function(){b.whenDocReady(a)},50)}};Xinha.prototype.setMode=function(b){var a;if(typeof b=="undefined"){b=this._editMode=="textmode"?"wysiwyg":"textmode"}switch(b){case"textmode":this.firePluginEvent("onBeforeMode","textmode");this._toolbarObjects.htmlmode.swapImage(this.config.iconList.wysiwygmode);this.setCC("iframe");a=this.outwardHtml(this.getHTML());this.setHTML(a);this.deactivateEditor();this._iframe.style.display="none";this._textArea.style.display="";if(this.config.statusBar){this._statusBarTree.style.display="none";this._statusBarTextMode.style.display=""}this.findCC("textarea");this.notifyOf("modechange",{mode:"text"});this.firePluginEvent("onMode","textmode");break;case"wysiwyg":this.firePluginEvent("onBeforeMode","wysiwyg");this._toolbarObjects.htmlmode.swapImage([this.imgURL("images/ed_buttons_main.png"),7,0]);this.setCC("textarea");a=this.inwardHtml(this.getHTML());this.deactivateEditor();this.setHTML(a);this._iframe.style.display="";this._textArea.style.display="none";this.activateEditor();if(this.config.statusBar){this._statusBarTree.style.display="";this._statusBarTextMode.style.display="none"}this.findCC("iframe");this.notifyOf("modechange",{mode:"wysiwyg"});this.firePluginEvent("onMode","wysiwyg");break;default:alert("Mode <"+b+"> not defined!");return false}this._editMode=b};Xinha.prototype.setFullHTML=function(c){var a=RegExp.multiline;RegExp.multiline=true;if(c.match(Xinha.RE_doctype)){this.setDoctype(RegExp.$1)}RegExp.multiline=a;if(0){if(c.match(Xinha.RE_head)){this._doc.getElementsByTagName("head")[0].innerHTML=RegExp.$1}if(c.match(Xinha.RE_body)){this._doc.getElementsByTagName("body")[0].innerHTML=RegExp.$1}}else{var d=this.editorIsActivated();if(d){this.deactivateEditor()}var b=/<html>((.|\\n)*?)<\\/html>/i;c=c.replace(b,"$1");this._doc.open("text/html","replace");this._doc.write(c);this._doc.close();if(d){this.activateEditor()}this.setEditorEvents();return true}};Xinha.prototype.setEditorEvents=function(c){var a=this;var b=this._doc;a.whenDocReady(function(){if(!c){Xinha._addEvents(b,["mousedown"],function(){a.activateEditor();return true});if(Xinha.is_ie){Xinha._addEvent(a._doc.getElementsByTagName("html")[0],"click",function(){if(a._iframe.contentWindow.event.srcElement.tagName.toLowerCase()=="html"){var f=a._doc.body.createTextRange();f.collapse();f.select()}return true})}}Xinha._addEvents(b,["keydown","keypress","mousedown","mouseup","drag"],function(f){return a._editorEvent(Xinha.is_ie?a._iframe.contentWindow.event:f)});Xinha._addEvents(b,["dblclick"],function(f){return a._onDoubleClick(Xinha.is_ie?a._iframe.contentWindow.event:f)});if(c){return}for(var e in a.plugins){var d=a.plugins[e].instance;Xinha.refreshPlugin(d)}if(typeof a._onGenerate=="function"){a._onGenerate()}Xinha.addDom0Event(window,"resize",function(f){if(Xinha.ie_version>7&&!window.parent){if(a.execResize){a.sizeEditor();a.execResize=false}else{a.execResize=true}}else{a.sizeEditor()}});a.removeLoadingMessage()})};Xinha.getPluginConstructor=function(a){return Xinha.plugins[a]||window[a]};Xinha.prototype.registerPlugin=function(){if(!Xinha.isSupportedBrowser){return}var a=arguments[0];if(a===null||typeof a=="undefined"||(typeof a=="string"&&Xinha.getPluginConstructor(a)=="undefined")){return false}var b=[];for(var c=1;c<arguments.length;++c){b.push(arguments[c])}return this.registerPlugin2(a,b)};Xinha.prototype.registerPlugin2=function(b,c){if(typeof b=="string"&&typeof Xinha.getPluginConstructor(b)=="function"){var a=b;b=Xinha.getPluginConstructor(b)}if(typeof b=="undefined"){return false}if(!b._pluginInfo){b._pluginInfo={name:a}}var f=new b(this,c);if(f){var g={};var e=b._pluginInfo;for(var d in e){g[d]=e[d]}g.instance=f;g.args=c;this.plugins[b._pluginInfo.name]=g;return f}else{Xinha.debugMsg("Can\'t register plugin "+b.toString()+".","warn")}};Xinha.getPluginDir=function(a,b){if(Xinha.externalPlugins[a]){return Xinha.externalPlugins[a][0]}if(b||(Xinha.getPluginConstructor(a)&&(typeof Xinha.getPluginConstructor(a).supported!="undefined")&&!Xinha.getPluginConstructor(a).supported)){return _editor_url+"unsupported_plugins/"+a}return _editor_url+"plugins/"+a};Xinha.loadPlugin=function(b,e,d){if(!Xinha.isSupportedBrowser){return}Xinha.setLoadingMessage(Xinha._lc("Loading plugin $plugin="+b+"$"));if(typeof Xinha.getPluginConstructor(b)!="undefined"){if(e){e(b)}return true}Xinha._pluginLoadStatus[b]="loading";function a(j,f){var m,i,l,k;switch(j){case"start":m="old_naming";i=Xinha.getPluginDir(f);l=f+".js";break;case"old_naming":m="unsupported";i=Xinha.getPluginDir(f);l=f.replace(/([a-z])([A-Z])([a-z])/g,function(p,o,n,q){return o+"-"+n.toLowerCase()+q}).toLowerCase()+".js";k="You are using an obsolete naming scheme for the Xinha plugin "+f+". Please rename "+l+" to "+f+".js";break;case"unsupported":m="unsupported_old_name";i=Xinha.getPluginDir(f,true);l=f+".js";k="You are using the unsupported Xinha plugin "+f+". If you wish continued support, please see http://trac.xinha.org/ticket/1297";break;case"unsupported_old_name":m="";i=Xinha.getPluginDir(f,true);l=f.replace(/([a-z])([A-Z])([a-z])/g,function(p,o,n,q){return o+"-"+n.toLowerCase()+q}).toLowerCase()+".js";k="You are using the unsupported Xinha plugin "+f+". If you wish continued support, please see http://trac.xinha.org/ticket/1297";break;default:Xinha._pluginLoadStatus[f]="failed";Xinha.debugMsg("Xinha was not able to find the plugin "+f+". Please make sure the plugin exists.","warn");return}var h=i+"/"+l;function g(n){Xinha.getPluginConstructor(n).supported=j.indexOf("unsupported")!==0;e(n)}Xinha._loadback(h,g,this,f);Xinha.ping(h,function(){if(k){Xinha.debugMsg(k)}},function(){Xinha.removeFromParent(document.getElementById(h));a(m,f)})}if(!d){if(Xinha.externalPlugins[b]){Xinha._loadback(Xinha.externalPlugins[b][0]+Xinha.externalPlugins[b][1],e,this,b)}else{var c=this;a("start",b)}}else{Xinha._loadback(d,e,this,b)}return false};Xinha._pluginLoadStatus={};Xinha.externalPlugins={};Xinha.plugins={};Xinha.loadPlugins=function(f,c,d){if(!Xinha.isSupportedBrowser){return}var b,e;for(e=0;e<f.length;e++){if(typeof f[e]=="object"){b=f[e].url.match(/(.*)(\\/[^\\/]*)$/);Xinha.externalPlugins[f[e].plugin]=[b[1],b[2]];f[e]=f[e].plugin}}var h=true;var a=Xinha.cloneObject(f);for(e=0;e<a.length;e++){var g=a[e];if(g=="FullScreen"&&!Xinha.externalPlugins.FullScreen){continue}if(typeof Xinha._pluginLoadStatus[g]=="undefined"){Xinha.loadPlugin(g,function(i){Xinha.setLoadingMessage(Xinha._lc("Finishing"));if(typeof Xinha.getPluginConstructor(i)!="undefined"){Xinha._pluginLoadStatus[i]="ready"}else{Xinha._pluginLoadStatus[i]="failed"}},d);h=false}else{if(Xinha._pluginLoadStatus[g]=="loading"){h=false}}}if(h){return true}if(c){setTimeout(function(){if(Xinha.loadPlugins(f,c)){c()}},50)}return h};Xinha.refreshPlugin=function(a){if(a&&typeof a.onGenerate=="function"){a.onGenerate()}if(a&&typeof a.onGenerateOnce=="function"){a._ongenerateOnce=a.onGenerateOnce;delete (a.onGenerateOnce);a._ongenerateOnce();delete (a._ongenerateOnce)}};Xinha.prototype.firePluginEvent=function(c){var e=[];for(var b=1;b<arguments.length;b++){e[b-1]=arguments[b]}for(b in this.plugins){var a=this.plugins[b].instance;if(a==this._browserSpecificPlugin){continue}if(a&&typeof a[c]=="function"){var d=(b=="Events")?this:a;if(a[c].apply(d,e)){return true}}}a=this._browserSpecificPlugin;if(a&&typeof a[c]=="function"){if(a[c].apply(a,e)){return true}}return false};Xinha.loadStyle=function(e,a,g,d){var b=_editor_url||"";if(a){b=Xinha.getPluginDir(a)+"/"}b+=e;if(/^\\//.test(e)){b=e}var c=document.getElementsByTagName("head")[0];var f=document.createElement("link");f.rel="stylesheet";f.href=b;f.type="text/css";if(g){f.id=g}if(d&&c.getElementsByTagName("link")[0]){c.insertBefore(f,c.getElementsByTagName("link")[0])}else{c.appendChild(f)}};Xinha.loadScript=function(c,a,d){var b=_editor_url||"";if(a){b=Xinha.getPluginDir(a)+"/"}b+=c;if(/^\\//.test(c)){b=c}Xinha._loadback(b,d)};Xinha.includeAssets=function(){var b={pendingAssets:[],loaderRunning:false,loadedScripts:[]};b.callbacks=[];b.loadNext=function(){var d=this;this.loaderRunning=true;if(this.pendingAssets.length){var c=this.pendingAssets[0];this.pendingAssets.splice(0,1);switch(c.type){case"text/css":Xinha.loadStyle(c.url,c.plugin);return this.loadNext();case"text/javascript":Xinha.loadScript(c.url,c.plugin,function(){d.loadNext()})}}else{this.loaderRunning=false;this.runCallback()}};b.loadScript=function(e,c){var d=this;this.pendingAssets.push({type:"text/javascript",url:e,plugin:c});if(!this.loaderRunning){this.loadNext()}return this};b.loadScriptOnce=function(d,c){for(var e=0;e<this.loadedScripts.length;e++){if(this.loadedScripts[e].url==d&&this.loadedScripts[e].plugin==c){return this}}return this.loadScript(d,c)};b.loadStyle=function(e,c){var d=this;this.pendingAssets.push({type:"text/css",url:e,plugin:c});if(!this.loaderRunning){this.loadNext()}return this};b.whenReady=function(c){this.callbacks.push(c);if(!this.loaderRunning){this.loadNext()}return this};b.runCallback=function(){while(this.callbacks.length){var c=this.callbacks.splice(0,1);c[0]();c=null}return this};for(var a=0;a<arguments.length;a++){if(typeof arguments[a]=="string"){if(arguments[a].match(/\\.css$/i)){b.loadStyle(arguments[a])}else{b.loadScript(arguments[a])}}else{if(arguments[a].type){if(arguments[a].type.match(/text\\/css/i)){b.loadStyle(arguments[a].url,arguments[a].plugin)}else{if(arguments[a].type.match(/text\\/javascript/i)){b.loadScript(arguments[a].url,arguments[a].plugin)}}}else{if(arguments[a].length>=1){if(arguments[a][0].match(/\\.css$/i)){b.loadStyle(arguments[a][0],arguments[a][1])}else{b.loadScript(arguments[a][0],arguments[a][1])}}}}}return b};Xinha.prototype.debugTree=function(){var c=document.createElement("textarea");c.style.width="100%";c.style.height="20em";c.value="";function b(d,e){for(;--d>=0;){c.value+=" "}c.value+=e+"\\n"}function a(e,h){var d=e.tagName.toLowerCase(),f;var g=Xinha.is_ie?e.scopeName:e.prefix;b(h,"- "+d+" ["+g+"]");for(f=e.firstChild;f;f=f.nextSibling){if(f.nodeType==1){a(f,h+2)}}}a(this._doc.body,0);document.body.appendChild(c)};Xinha.getInnerText=function(c){var a="",b;for(b=c.firstChild;b;b=b.nextSibling){if(b.nodeType==3){a+=b.data}else{if(b.nodeType==1){a+=Xinha.getInnerText(b)}}}return a};Xinha.prototype._wordClean=function(){var b=this;var e={empty_tags:0,cond_comm:0,mso_elmts:0,mso_class:0,mso_style:0,mso_xmlel:0,orig_len:this._doc.body.innerHTML.length,T:new Date().getTime()};var g={empty_tags:"Empty tags removed: ",cond_comm:"Conditional comments removed",mso_elmts:"MSO invalid elements removed",mso_class:"MSO class names removed: ",mso_style:"MSO inline style removed: ",mso_xmlel:"MSO XML elements stripped: "};function f(){var j="Xinha word cleaner stats: \\n\\n";for(var k in e){if(g[k]){j+=g[k]+e[k]+"\\n"}}j+="\\nInitial document length: "+e.orig_len+"\\n";j+="Final document length: "+b._doc.body.innerHTML.length+"\\n";j+="Clean-up took "+((new Date().getTime()-e.T)/1000)+" seconds";alert(j)}function h(j){var k=j.className.replace(/(^|\\s)mso.*?(\\s|$)/ig," ");if(k!=j.className){j.className=k;if(!/\\S/.test(j.className)){j.removeAttribute("className");++e.mso_class}}}function a(k){var l=k.style.cssText.split(/\\s*;\\s*/);for(var j=l.length;--j>=0;){if(/^mso|^tab-stops/i.test(l[j])||/^margin\\s*:\\s*0..\\s+0..\\s+0../i.test(l[j])){++e.mso_style;l.splice(j,1)}}k.style.cssText=l.join("; ")}function c(j){if(("link"==j.tagName.toLowerCase()&&(j.attributes&&/File-List|Edit-Time-Data|themeData|colorSchemeMapping/.test(j.attributes.rel.nodeValue)))||/^(style|meta)$/i.test(j.tagName)){Xinha.removeFromParent(j);++e.mso_elmts;return true}return false}function d(j){if(/^(a|span|b|strong|i|em|font|div|p)$/i.test(j.tagName)&&!j.firstChild){Xinha.removeFromParent(j);++e.empty_tags;return true}return false}function i(j){h(j);a(j);var m;for(var l=j.firstChild;l;l=m){m=l.nextSibling;if(l.nodeType==1&&i(l)){if((Xinha.is_ie&&j.scopeName!="HTML")||(!Xinha.is_ie&&/:/.test(l.tagName))){for(var k=l.childNodes&&l.childNodes.length-1;l.childNodes&&l.childNodes.length&&l.childNodes[k];--k){if(l.nextSibling){l.parentNode.insertBefore(l.childNodes[k],l.nextSibling)}else{l.parentNode.appendChild(l.childNodes[k])}}Xinha.removeFromParent(l);continue}if(d(l)){continue}if(c(l)){continue}}else{if(l.nodeType==8){if(/(\\s*\\[\\s*if\\s*(([gl]te?|!)\\s*)?(IE|mso)\\s*(\\d+(\\.\\d+)?\\s*)?\\]>)/.test(l.nodeValue)){Xinha.removeFromParent(l);++e.cond_comm}}}}return true}i(this._doc.body);this.updateToolbar()};Xinha.prototype._clearFonts=function(){var a=this.getInnerHTML();if(confirm(Xinha._lc("Would you like to clear font typefaces?"))){a=a.replace(/face="[^"]*"/gi,"");a=a.replace(/font-family:[^;}"\']+;?/gi,"")}if(confirm(Xinha._lc("Would you like to clear font sizes?"))){a=a.replace(/size="[^"]*"/gi,"");a=a.replace(/font-size:[^;}"\']+;?/gi,"")}if(confirm(Xinha._lc("Would you like to clear font colours?"))){a=a.replace(/color="[^"]*"/gi,"");a=a.replace(/([^\\-])color:[^;}"\']+;?/gi,"$1")}a=a.replace(/(style|class)="\\s*"/gi,"");a=a.replace(/<(font|span)\\s*>/gi,"");this.setHTML(a);this.updateToolbar()};Xinha.prototype._splitBlock=function(){this._doc.execCommand("formatblock",false,"div")};Xinha.prototype.forceRedraw=function(){this._doc.body.style.visibility="hidden";this._doc.body.style.visibility=""};Xinha.prototype.focusEditor=function(){switch(this._editMode){case"wysiwyg":try{if(Xinha._someEditorHasBeenActivated){this.activateEditor();this._iframe.contentWindow.focus()}}catch(a){}break;case"textmode":try{this._textArea.focus()}catch(b){}break;default:alert("ERROR: mode "+this._editMode+" is not defined")}return this._doc};Xinha.prototype._undoTakeSnapshot=function(){++this._undoPos;if(this._undoPos>=this.config.undoSteps){this._undoQueue.shift();--this._undoPos}var b=true;var a=this.getInnerHTML();if(this._undoPos>0){b=(this._undoQueue[this._undoPos-1]!=a)}if(b){this._undoQueue[this._undoPos]=a}else{this._undoPos--}};Xinha.prototype.undo=function(){if(this._undoPos>0){var a=this._undoQueue[--this._undoPos];if(a){this.setHTML(a)}else{++this._undoPos}}};Xinha.prototype.redo=function(){if(this._undoPos<this._undoQueue.length-1){var a=this._undoQueue[++this._undoPos];if(a){this.setHTML(a)}else{--this._undoPos}}};Xinha.prototype.disableToolbar=function(a){if(this._timerToolbar){clearTimeout(this._timerToolbar)}if(typeof a=="undefined"){a=[]}else{if(typeof a!="object"){a=[a]}}for(var c in this._toolbarObjects){var b=this._toolbarObjects[c];if(a.contains(c)){continue}if(typeof b.state!="function"){continue}b.state("enabled",false)}};Xinha.prototype.enableToolbar=function(){this.updateToolbar()};Xinha.prototype.updateToolbar=function(noStatus){if(this.suspendUpdateToolbar){return}var doc=this._doc;var text=(this._editMode=="textmode");var ancestors=null;if(!text){ancestors=this.getAllAncestors();if(this.config.statusBar&&!noStatus){while(this._statusBarItems.length){var item=this._statusBarItems.pop();item.el=null;item.editor=null;item.onclick=null;item.oncontextmenu=null;item._xinha_dom0Events.click=null;item._xinha_dom0Events.contextmenu=null;item=null}this._statusBarTree.innerHTML=" ";this._statusBarTree.appendChild(document.createTextNode(Xinha._lc("Path")+": "));for(var i=ancestors.length;--i>=0;){var el=ancestors[i];if(!el){continue}var a=document.createElement("a");a.href="javascript:void(0);";a.el=el;a.editor=this;this._statusBarItems.push(a);Xinha.addDom0Event(a,"click",function(){this.blur();this.editor.selectNodeContents(this.el);this.editor.updateToolbar(true);return false});Xinha.addDom0Event(a,"contextmenu",function(){this.blur();var info="Inline style:\\n\\n";info+=this.el.style.cssText.split(/;\\s*/).join(";\\n");alert(info);return false});var txt=el.tagName.toLowerCase();switch(txt){case"b":txt="strong";break;case"i":txt="em";break;case"strike":txt="del";break}if(typeof el.style!="undefined"){a.title=el.style.cssText}if(el.id){txt+="#"+el.id}if(el.className){txt+="."+el.className}a.appendChild(document.createTextNode(txt));this._statusBarTree.appendChild(a);if(i!==0){this._statusBarTree.appendChild(document.createTextNode(String.fromCharCode(187)))}Xinha.freeLater(a)}}}for(var cmd in this._toolbarObjects){var btn=this._toolbarObjects[cmd];var inContext=true;if(typeof btn.state!="function"){continue}if(btn.context&&!text){inContext=false;var context=btn.context;var attrs=[];if(/(.*)\\[(.*?)\\]/.test(context)){context=RegExp.$1;attrs=RegExp.$2.split(",")}context=context.toLowerCase();var match=(context=="*");for(var k=0;k<ancestors.length;++k){if(!ancestors[k]){continue}if(match||(ancestors[k].tagName.toLowerCase()==context)){inContext=true;var contextSplit=null;var att=null;var comp=null;var attVal=null;for(var ka=0;ka<attrs.length;++ka){contextSplit=attrs[ka].match(/(.*)(==|!=|===|!==|>|>=|<|<=)(.*)/);att=contextSplit[1];comp=contextSplit[2];attVal=contextSplit[3];if(!eval(ancestors[k][att]+comp+attVal)){inContext=false;break}}if(inContext){break}}}}btn.state("enabled",(!text||btn.text)&&inContext);if(typeof cmd=="function"){continue}var dropdown=this.config.customSelects[cmd];if((!text||btn.text)&&(typeof dropdown!="undefined")){dropdown.refresh(this);continue}switch(cmd){case"fontname":case"fontsize":if(!text){try{var value=(""+doc.queryCommandValue(cmd)).toLowerCase();if(!value){btn.element.selectedIndex=0;break}var options=this.config[cmd];var sIndex=0;for(var j in options){if((j.toLowerCase()==value)||(options[j].substr(0,value.length).toLowerCase()==value)){btn.element.selectedIndex=sIndex;throw"ok"}++sIndex}btn.element.selectedIndex=0}catch(ex){}}break;case"formatblock":var blocks=[];for(var indexBlock in this.config.formatblock){if(typeof this.config.formatblock[indexBlock]=="string"){blocks[blocks.length]=this.config.formatblock[indexBlock]}}var deepestAncestor=this._getFirstAncestor(this.getSelection(),blocks);if(deepestAncestor){for(var x=0;x<blocks.length;x++){if(blocks[x].toLowerCase()==deepestAncestor.tagName.toLowerCase()){btn.element.selectedIndex=x}}}else{btn.element.selectedIndex=0}break;case"textindicator":if(!text){try{var style=btn.element.style;style.backgroundColor=Xinha._makeColor(doc.queryCommandValue(Xinha.is_ie?"backcolor":"hilitecolor"));if(/transparent/i.test(style.backgroundColor)){style.backgroundColor=Xinha._makeColor(doc.queryCommandValue("backcolor"))}style.color=Xinha._makeColor(doc.queryCommandValue("forecolor"));style.fontFamily=doc.queryCommandValue("fontname");style.fontWeight=doc.queryCommandState("bold")?"bold":"normal";style.fontStyle=doc.queryCommandState("italic")?"italic":"normal"}catch(ex){}}break;case"htmlmode":btn.state("active",text);break;case"lefttoright":case"righttoleft":var eltBlock=this.getParentElement();while(eltBlock&&!Xinha.isBlockElement(eltBlock)){eltBlock=eltBlock.parentNode}if(eltBlock){btn.state("active",(eltBlock.style.direction==((cmd=="righttoleft")?"rtl":"ltr")))}break;default:cmd=cmd.replace(/(un)?orderedlist/i,"insert$1orderedlist");try{btn.state("active",(!text&&doc.queryCommandState(cmd)))}catch(ex){}break}}if(this._customUndo&&!this._timerUndo){this._undoTakeSnapshot();var editor=this;this._timerUndo=setTimeout(function(){editor._timerUndo=null},this.config.undoTimeout)}this.firePluginEvent("onUpdateToolbar")};Xinha.getEditor=function(c){for(var b=__xinhas.length;b--;){var a=__xinhas[b];if(a&&(a._textArea.id==c||a._textArea.name==c||a._textArea==c)){return a}}return null};Xinha.prototype.getPluginInstance=function(a){if(this.plugins[a]){return this.plugins[a].instance}else{return null}};Xinha.prototype.getAllAncestors=function(){var c=this.getParentElement();var b=[];while(c&&(c.nodeType==1)&&(c.tagName.toLowerCase()!="body")){b.push(c);c=c.parentNode}b.push(this._doc.body);return b};Xinha.prototype._getFirstAncestor=function(e,d){var c=this.activeElement(e);if(c===null){try{c=(Xinha.is_ie?this.createRange(e).parentElement():this.createRange(e).commonAncestorContainer)}catch(b){return null}}if(typeof d=="string"){d=[d]}while(c){if(c.nodeType==1){if(d===null){return c}for(var a=0;a<d.length;++a){if(typeof d[a]=="string"&&d[a]==c.tagName.toLowerCase()){return c}else{if(typeof d[a]=="function"&&d[a](this,c)){return c}}}if(c.tagName.toLowerCase()=="body"){break}if(c.tagName.toLowerCase()=="table"){break}}c=c.parentNode}return null};Xinha.prototype._getAncestorBlock=function(b){var a=(Xinha.is_ie?this.createRange(b).parentElement:this.createRange(b).commonAncestorContainer);while(a&&(a.nodeType==1)){switch(a.tagName.toLowerCase()){case"div":case"p":case"address":case"blockquote":case"center":case"del":case"ins":case"pre":case"h1":case"h2":case"h3":case"h4":case"h5":case"h6":case"h7":return a;case"body":case"noframes":case"dd":case"li":case"th":case"td":case"noscript":return null;default:break}}return null};Xinha.prototype._createImplicitBlock=function(b){var c=this.getSelection();if(Xinha.is_ie){c.empty()}else{c.collapseToStart()}var a=this.createRange(c)};Xinha.prototype.surroundHTML=function(c,a){var b=this.getSelectedHTML();this.insertHTML(c+b+a)};Xinha.prototype.hasSelectedText=function(){return this.getSelectedHTML()!==""};Xinha.prototype._comboSelected=function(b,a){this.focusEditor();var c=b.options[b.selectedIndex].value;switch(a){case"fontname":case"fontsize":this.execCommand(a,false,c);break;case"formatblock":if(!c){this.updateToolbar();break}if(!Xinha.is_gecko||c!=="blockquote"){c="<"+c+">"}this.execCommand(a,false,c);break;default:var d=this.config.customSelects[a];if(typeof d!="undefined"){d.action(this,c,b,a)}else{alert("FIXME: combo box "+a+" not implemented")}break}};Xinha.prototype._colorSelector=function(h){var d=this;if(Xinha.is_gecko){try{d._doc.execCommand("useCSS",false,false);d._doc.execCommand("styleWithCSS",false,true)}catch(g){}}var f=d._toolbarObjects[h].element;var c;if(h=="hilitecolor"){if(Xinha.is_ie){h="backcolor";c=Xinha._colorToRgb(d._doc.queryCommandValue("backcolor"))}else{c=Xinha._colorToRgb(d._doc.queryCommandValue("hilitecolor"))}}else{c=Xinha._colorToRgb(d._doc.queryCommandValue("forecolor"))}var b=function(i){d._doc.execCommand(h,false,i)};if(Xinha.is_ie){var a=d.createRange(d.getSelection());b=function(i){a.select();d._doc.execCommand(h,false,i)}}var e=new Xinha.colorPicker({cellsize:d.config.colorPickerCellSize,callback:b,granularity:d.config.colorPickerGranularity,websafe:d.config.colorPickerWebSafe,savecolors:d.config.colorPickerSaveColors});e.open(d.config.colorPickerPosition,f,c)};Xinha.prototype.execCommand=function(h,f,g){var a=this;this.focusEditor();h=h.toLowerCase();if(this.firePluginEvent("onExecCommand",h,f,g)){this.updateToolbar();return false}switch(h){case"htmlmode":this.setMode();break;case"hilitecolor":case"forecolor":this._colorSelector(h);break;case"createlink":this._createLink();break;case"undo":case"redo":if(this._customUndo){this[h]()}else{this._doc.execCommand(h,f,g)}break;case"inserttable":this._insertTable();break;case"insertimage":this._insertImage();break;case"showhelp":this._popupDialog(a.config.URIs.help,null,this);break;case"killword":this._wordClean();break;case"cut":case"copy":case"paste":this._doc.execCommand(h,f,g);if(this.config.killWordOnPaste){this._wordClean()}break;case"lefttoright":case"righttoleft":if(this.config.changeJustifyWithDirection){this._doc.execCommand((h=="righttoleft")?"justifyright":"justifyleft",f,g)}var b=(h=="righttoleft")?"rtl":"ltr";var e=this.getParentElement();while(e&&!Xinha.isBlockElement(e)){e=e.parentNode}if(e){if(e.style.direction==b){e.style.direction=""}else{e.style.direction=b}}break;case"justifyleft":case"justifyright":h.match(/^justify(.*)$/);var d=this.activeElement(this.getSelection());if(d&&d.tagName.toLowerCase()=="img"){d.align=d.align==RegExp.$1?"":RegExp.$1}else{this._doc.execCommand(h,f,g)}break;default:try{this._doc.execCommand(h,f,g)}catch(c){if(this.config.debug){alert(c+"\\n\\nby execCommand("+h+");")}}break}this.updateToolbar();return false};Xinha.prototype._editorEvent=function(b){var a=this;if(typeof a._textArea["on"+b.type]=="function"){a._textArea["on"+b.type](b)}if(this.isKeyEvent(b)){if(a.firePluginEvent("onKeyPress",b)){return false}if(this.isShortCut(b)){this._shortCuts(b)}}if(b.type=="mousedown"){if(a.firePluginEvent("onMouseDown",b)){return false}}if(a._timerToolbar){clearTimeout(a._timerToolbar)}if(!this.suspendUpdateToolbar){a._timerToolbar=setTimeout(function(){a.updateToolbar();a._timerToolbar=null},250)}};Xinha.prototype._onDoubleClick=function(d){var c=this;var e=Xinha.is_ie?d.srcElement:d.target;var a=e.tagName;var b=e.className;if(a){a=a.toLowerCase();if(b&&(this.config.dblclickList[a+"."+b]!=undefined)){this.config.dblclickList[a+"."+b][0](c,e)}else{if(this.config.dblclickList[a]!=undefined){this.config.dblclickList[a][0](c,e)}}}};Xinha.prototype._shortCuts=function(b){var a=this.getKey(b).toLowerCase();var d=null;var c=null;switch(a){case"b":d="bold";break;case"i":d="italic";break;case"u":d="underline";break;case"s":d="strikethrough";break;case"l":d="justifyleft";break;case"e":d="justifycenter";break;case"r":d="justifyright";break;case"j":d="justifyfull";break;case"z":d="undo";break;case"y":d="redo";break;case"v":d="paste";break;case"n":d="formatblock";c="p";break;case"0":d="killword";break;case"1":case"2":case"3":case"4":case"5":case"6":d="formatblock";c="h"+a;break}if(d){this.execCommand(d,false,c);Xinha._stopEvent(b)}};Xinha.prototype.convertNode=function(a,c){var b=this._doc.createElement(c);while(a.firstChild){b.appendChild(a.firstChild)}return b};Xinha.prototype.scrollToElement=function(b){if(!b){b=this.getParentElement();if(!b){return}}var a=Xinha.getElementTopLeft(b);this._iframe.contentWindow.scrollTo(a.left,a.top)};Xinha.prototype.getEditorContent=function(){return this.outwardHtml(this.getHTML())};Xinha.prototype.setEditorContent=function(a){this.setHTML(this.inwardHtml(a))};Xinha.updateTextareas=function(){var b;for(var a=0;a<__xinhas.length;a++){b=__xinhas[a];b._textArea.value=b.getEditorContent()}};Xinha.prototype.getHTML=function(){var a="";switch(this._editMode){case"wysiwyg":if(!this.config.fullPage){a=Xinha.getHTML(this._doc.body,false,this).trim()}else{a=this.doctype+"\\n"+Xinha.getHTML(this._doc.documentElement,true,this)}break;case"textmode":a=this._textArea.value;break;default:alert("Mode <"+this._editMode+"> not defined!");return false}return a};Xinha.prototype.outwardHtml=function(d){for(var c in this.plugins){var a=this.plugins[c].instance;if(a&&typeof a.outwardHtml=="function"){d=a.outwardHtml(d)}}d=d.replace(/<(\\/?)b(\\s|>|\\/)/ig,"<$1strong$2");d=d.replace(/<(\\/?)i(\\s|>|\\/)/ig,"<$1em$2");d=d.replace(/<(\\/?)strike(\\s|>|\\/)/ig,"<$1del$2");d=d.replace(/(<[^>]*on(click|mouse(over|out|up|down))=[\'"])if\\(window\\.parent && window\\.parent\\.Xinha\\)\\{return false\\}/gi,"$1");var b=location.href.replace(/(https?:\\/\\/[^\\/]*)\\/.*/,"$1")+"/";d=d.replace(/https?:\\/\\/null\\//g,b);d=d.replace(/((href|src|background)=[\\\'\\"])\\/+/ig,"$1"+b);d=this.outwardSpecialReplacements(d);d=this.fixRelativeLinks(d);if(this.config.sevenBitClean){d=d.replace(/[^ -~\\r\\n\\t]/g,function(e){return(e!=Xinha.cc)?"&#"+e.charCodeAt(0)+";":e})}d=d.replace(/(<script[^>]*((type=[\\"\\\']text\\/)|(language=[\\"\\\'])))(freezescript)/gi,"$1javascript");if(this.config.fullPage){d=Xinha.stripCoreCSS(d)}if(typeof this.config.outwardHtml=="function"){d=this.config.outwardHtml(d)}return d};Xinha.prototype.inwardHtml=function(c){for(var b in this.plugins){var a=this.plugins[b].instance;if(a&&typeof a.inwardHtml=="function"){c=a.inwardHtml(c)}}c=c.replace(/<(\\/?)del(\\s|>|\\/)/ig,"<$1strike$2");c=c.replace(/(<[^>]*on(click|mouse(over|out|up|down))=["\'])/gi,"$1if(window.parent && window.parent.Xinha){return false}");c=this.inwardSpecialReplacements(c);c=c.replace(/(<script[^>]*((type=[\\"\\\']text\\/)|(language=[\\"\\\'])))(javascript)/gi,"$1freezescript");var d=new RegExp("((href|src|background)=[\'\\"])/+","gi");c=c.replace(d,"$1"+location.href.replace(/(https?:\\/\\/[^\\/]*)\\/.*/,"$1")+"/");c=this.fixRelativeLinks(c);if(this.config.fullPage){c=Xinha.addCoreCSS(c)}if(typeof this.config.inwardHtml=="function"){c=this.config.inwardHtml(c)}return c};Xinha.prototype.outwardSpecialReplacements=function(b){for(var a in this.config.specialReplacements){var e=this.config.specialReplacements[a];var d=a;if(typeof e.replace!="function"||typeof d.replace!="function"){continue}var c=new RegExp(Xinha.escapeStringForRegExp(e),"g");b=b.replace(c,d.replace(/\\$/g,"$$$$"))}return b};Xinha.prototype.inwardSpecialReplacements=function(b){for(var a in this.config.specialReplacements){var e=a;var d=this.config.specialReplacements[a];if(typeof e.replace!="function"||typeof d.replace!="function"){continue}var c=new RegExp(Xinha.escapeStringForRegExp(e),"g");b=b.replace(c,d.replace(/\\$/g,"$$$$"))}return b};Xinha.prototype.fixRelativeLinks=function(f){if(typeof this.config.expandRelativeUrl!="undefined"&&this.config.expandRelativeUrl){if(f==null){return""}var c=f.match(/(src|href)="([^"]*)"/gi);var j=document.location.href;if(c){var d,l,k,m,h;for(var e=0;e<c.length;++e){d=c[e].match(/(src|href)="([^"]*)"/i);l=d[2].match(/\\.\\.\\//g);if(l){k=new RegExp("(.*?)(([^/]*/){"+l.length+"})[^/]*$");m=j.match(k);h=d[2].replace(/(\\.\\.\\/)*/,m[1]);f=f.replace(new RegExp(Xinha.escapeStringForRegExp(d[2])),h)}}}}if(typeof this.config.stripSelfNamedAnchors!="undefined"&&this.config.stripSelfNamedAnchors){var g=new RegExp(\'((href|src|background)=")(\'+Xinha.escapeStringForRegExp(window.unescape(document.location.href.replace(/&/g,"&")))+")([#?][^\'\\" ]*)","g");f=f.replace(g,"$1$4")}if(typeof this.config.stripBaseHref!="undefined"&&this.config.stripBaseHref){var a=null;if(typeof this.config.baseHref!="undefined"&&this.config.baseHref!==null){a=new RegExp(\'((href|src|background|action)=")(\'+Xinha.escapeStringForRegExp(this.config.baseHref.replace(/([^\\/]\\/)(?=.+\\.)[^\\/]*$/,"$1"))+")","g");f=f.replace(a,"$1")}a=new RegExp(\'((href|src|background|action)=")(\'+Xinha.escapeStringForRegExp(document.location.href.replace(/^(https?:\\/\\/[^\\/]*)(.*)/,"$1"))+")","g");f=f.replace(a,"$1")}return f};Xinha.prototype.getInnerHTML=function(){if(!this._doc.body){return""}var a="";switch(this._editMode){case"wysiwyg":if(!this.config.fullPage){a=this._doc.body.innerHTML}else{a=this.doctype+"\\n"+this._doc.documentElement.innerHTML}break;case"textmode":a=this._textArea.value;break;default:alert("Mode <"+this._editMode+"> not defined!");return false}return a};Xinha.prototype.setHTML=function(a){if(!this.config.fullPage){this._doc.body.innerHTML=a}else{this.setFullHTML(a)}this._textArea.value=a};Xinha.prototype.setDoctype=function(a){this.doctype=a};Xinha._object=null;Array.prototype.isArray=true;RegExp.prototype.isRegExp=true;Xinha.cloneObject=function(obj){if(!obj){return null}var newObj=obj.isArray?[]:{};if(obj.constructor.toString().match(/\\s*function Function\\(/)||typeof obj=="function"){newObj=obj}else{if(obj.isRegExp){newObj=eval(obj.toString())}else{for(var n in obj){var node=obj[n];if(typeof node=="object"){newObj[n]=Xinha.cloneObject(node)}else{newObj[n]=node}}}}return newObj};Xinha.extend=function(a,c){function b(){}b.prototype=c.prototype;a.prototype=new b();a.prototype.constructor=a;a.parentConstructor=c;a.superClass=c.prototype};Xinha.flushEvents=function(){var a=0;var c=Xinha._eventFlushers.pop();while(c){try{if(c.length==3){Xinha._removeEvent(c[0],c[1],c[2]);a++}else{if(c.length==2){c[0]["on"+c[1]]=null;c[0]._xinha_dom0Events[c[1]]=null;a++}}}catch(b){}c=Xinha._eventFlushers.pop()}};Xinha._eventFlushers=[];if(document.addEventListener){Xinha._addEvent=function(b,a,c){b.addEventListener(a,c,false);Xinha._eventFlushers.push([b,a,c])};Xinha._removeEvent=function(b,a,c){b.removeEventListener(a,c,false)};Xinha._stopEvent=function(a){a.preventDefault();a.stopPropagation()}}else{if(document.attachEvent){Xinha._addEvent=function(b,a,c){b.attachEvent("on"+a,c);Xinha._eventFlushers.push([b,a,c])};Xinha._removeEvent=function(b,a,c){b.detachEvent("on"+a,c)};Xinha._stopEvent=function(b){try{b.cancelBubble=true;b.returnValue=false}catch(a){}}}else{Xinha._addEvent=function(b,a,c){alert("_addEvent is not supported")};Xinha._removeEvent=function(b,a,c){alert("_removeEvent is not supported")};Xinha._stopEvent=function(a){alert("_stopEvent is not supported")}}}Xinha._addEvents=function(c,a,d){for(var b=a.length;--b>=0;){Xinha._addEvent(c,a[b],d)}};Xinha._removeEvents=function(c,a,d){for(var b=a.length;--b>=0;){Xinha._removeEvent(c,a[b],d)}};Xinha.addOnloadHandler=function(b,a){a=a?a:window;var c=function(){if(arguments.callee.done){return}arguments.callee.done=true;if(Xinha.onloadTimer){clearInterval(Xinha.onloadTimer)}b()};if(Xinha.is_ie){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);c()}});if(document.documentElement.doScroll&&typeof window.frameElement==="undefined"){(function(){if(arguments.callee.done){return}try{document.documentElement.doScroll("left")}catch(d){setTimeout(arguments.callee,0);return}c()})()}}else{if(/applewebkit|KHTML/i.test(navigator.userAgent)){Xinha.onloadTimer=a.setInterval(function(){if(/loaded|complete/.test(a.document.readyState)){c()}},10)}else{a.document.addEventListener("DOMContentLoaded",c,false)}}Xinha._addEvent(a,"load",c)};Xinha.addDom0Event=function(b,c,a){Xinha._prepareForDom0Events(b,c);b._xinha_dom0Events[c].unshift(a)};Xinha.prependDom0Event=function(b,c,a){Xinha._prepareForDom0Events(b,c);b._xinha_dom0Events[c].push(a)};Xinha.getEvent=function(a){return a||window.event};Xinha._prepareForDom0Events=function(a,b){if(typeof a._xinha_dom0Events=="undefined"){a._xinha_dom0Events={};Xinha.freeLater(a,"_xinha_dom0Events")}if(typeof a._xinha_dom0Events[b]=="undefined"){a._xinha_dom0Events[b]=[];if(typeof a["on"+b]=="function"){a._xinha_dom0Events[b].push(a["on"+b])}a["on"+b]=function(e){var c=a._xinha_dom0Events[b];var f=true;for(var d=c.length;--d>=0;){a._xinha_tempEventHandler=c[d];if(a._xinha_tempEventHandler(e)===false){a._xinha_tempEventHandler=null;f=false;break}a._xinha_tempEventHandler=null}return f};Xinha._eventFlushers.push([a,b])}};Xinha.prototype.notifyOn=function(b,a){if(typeof this._notifyListeners[b]=="undefined"){this._notifyListeners[b]=[];Xinha.freeLater(this,"_notifyListeners")}this._notifyListeners[b].push(a)};Xinha.prototype.notifyOf=function(c,a){if(this._notifyListeners[c]){for(var b=0;b<this._notifyListeners[c].length;b++){this._notifyListeners[c][b](c,a)}}};Xinha._blockTags=" body form textarea fieldset ul ol dl li div p h1 h2 h3 h4 h5 h6 quote pre table thead tbody tfoot tr td th iframe address blockquote title meta link style head ";Xinha.isBlockElement=function(a){return a&&a.nodeType==1&&(Xinha._blockTags.indexOf(" "+a.tagName.toLowerCase()+" ")!=-1)};Xinha._paraContainerTags=" body td th caption fieldset div ";Xinha.isParaContainer=function(a){return a&&a.nodeType==1&&(Xinha._paraContainerTags.indexOf(" "+a.tagName.toLowerCase()+" ")!=-1)};Xinha._closingTags=" a abbr acronym address applet b bdo big blockquote button caption center cite code del dfn dir div dl em fieldset font form frameset h1 h2 h3 h4 h5 h6 i iframe ins kbd label legend map menu noframes noscript object ol optgroup pre q s samp script select small span strike strong style sub sup table textarea title tt u ul var ";Xinha.needsClosingTag=function(a){return a&&a.nodeType==1&&(Xinha._closingTags.indexOf(" "+a.tagName.toLowerCase()+" ")!=-1)};Xinha.htmlEncode=function(a){if(!a){return""}if(typeof a.replace=="undefined"){a=a.toString()}a=a.replace(/&/ig,"&");a=a.replace(/</ig,"<");a=a.replace(/>/ig,">");a=a.replace(/\\xA0/g," ");a=a.replace(/\\x22/g,""");return a};Xinha.prototype.stripBaseURL=function(b){if(this.config.baseHref===null||!this.config.stripBaseHref){return b}var c=this.config.baseHref.replace(/^(https?:\\/\\/[^\\/]+)(.*)$/,"$1");var a=new RegExp(c);return b.replace(a,"")};if(typeof String.prototype.trim!="function"){String.prototype.trim=function(){return this.replace(/^\\s+/,"").replace(/\\s+$/,"")}}Xinha._makeColor=function(c){if(typeof c!="number"){return c}var e=c&255;var d=(c>>8)&255;var a=(c>>16)&255;return"rgb("+e+","+d+","+a+")"};Xinha._colorToRgb=function(c){if(!c){return""}var h,f,a;function e(b){return(b<16)?("0"+b.toString(16)):b.toString(16)}if(typeof c=="number"){h=c&255;f=(c>>8)&255;a=(c>>16)&255;return"#"+e(h)+e(f)+e(a)}if(c.substr(0,3)=="rgb"){var d=/rgb\\s*\\(\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*\\)/;if(c.match(d)){h=parseInt(RegExp.$1,10);f=parseInt(RegExp.$2,10);a=parseInt(RegExp.$3,10);return"#"+e(h)+e(f)+e(a)}return null}if(c.substr(0,1)=="#"){return c}return null};Xinha.prototype._popupDialog=function(b,a,c){Dialog(this.popupURL(b),a,c)};Xinha.prototype.imgURL=function(b,a){if(typeof a=="undefined"){return _editor_url+b}else{return Xinha.getPluginDir(a)+"/img/"+b}};Xinha.prototype.popupURL=function(d){var c="";if(d.match(/^plugin:\\/\\/(.*?)\\/(.*)/)){var b=RegExp.$1;var a=RegExp.$2;if(!/\\.(html?|php)$/.test(a)){a+=".html"}c=Xinha.getPluginDir(b)+"/popups/"+a}else{if(d.match(/^\\/.*?/)||d.match(/^https?:\\/\\//)){c=d}else{c=_editor_url+this.config.popupURL+d}}return c};Xinha.getElementById=function(a,e){var c,b,d=document.getElementsByTagName(a);for(b=d.length;--b>=0&&(c=d[b]);){if(c.id==e){return c}}return null};Xinha.prototype._toggleBorders=function(){var a=this._doc.getElementsByTagName("TABLE");if(a.length!==0){if(!this.borders){this.borders=true}else{this.borders=false}for(var b=0;b<a.length;b++){if(this.borders){Xinha._addClass(a[b],"htmtableborders")}else{Xinha._removeClass(a[b],"htmtableborders")}}}return true};Xinha.addCoreCSS=function(b){var a=\'<style title="XinhaInternalCSS" type="text/css">.htmtableborders, .htmtableborders td, .htmtableborders th {border : 1px dashed lightgrey ! important;}\\nhtml, body { border: 0px; } \\nbody { background-color: #ffffff; } \\nimg, hr { cursor: default } \\n</style>\\n\';if(b&&/<head>/i.test(b)){return b.replace(/<head>/i,"<head>"+a)}else{if(b){return a+b}else{return a}}};Xinha.prototype.addEditorStylesheet=function(a){var b=this._doc.createElement("link");b.rel="stylesheet";b.type="text/css";b.title="XinhaInternalCSS";b.href=a;this._doc.getElementsByTagName("HEAD")[0].appendChild(b)};Xinha.stripCoreCSS=function(a){return a.replace(/<style[^>]+title="XinhaInternalCSS"(.|\\n)*?<\\/style>/ig,"").replace(/<link[^>]+title="XinhaInternalCSS"(.|\\n)*?>/ig,"")};Xinha._removeClass=function(e,c){if(!(e&&e.className)){return}var a=e.className.split(" ");var b=[];for(var d=a.length;d>0;){if(a[--d]!=c){b[b.length]=a[d]}}e.className=b.join(" ")};Xinha._addClass=function(b,a){Xinha._removeClass(b,a);b.className+=" "+a};Xinha.addClasses=function(g,e){if(g!==null){var f=g.className.trim().split(" ");var d=e.split(" ");for(var a=0;a<d.length;a++){var b=false;for(var c=0;b===false&&c<f.length;c++){if(f[c]==d[a]){b=true}}if(b===false){f[f.length]=d[a]}}g.className=f.join(" ").trim()}};Xinha.removeClasses=function(e,d){var b=e.className.trim().split();var f=[];var h=d.trim().split();for(var c=0;c<b.length;c++){var g=false;for(var a=0;a<h.length&&!g;a++){if(b[c]==h[a]){g=true}}if(!g){f[f.length]=b[c]}}return f.join(" ")};Xinha.addClass=Xinha._addClass;Xinha.removeClass=Xinha._removeClass;Xinha._addClasses=Xinha.addClasses;Xinha._removeClasses=Xinha.removeClasses;Xinha._hasClass=function(d,b){if(!(d&&d.className)){return false}var a=d.className.split(" ");for(var c=a.length;c>0;){if(a[--c]==b){return true}}return false};Xinha._postback_send_charset=true;Xinha._postback=function(b,g,h,d){var f=null;f=Xinha.getXMLHTTPRequestObject();var e="";if(typeof g=="string"){e=g}else{if(typeof g=="object"){for(var c in g){e+=(e.length?"&":"")+c+"="+encodeURIComponent(g[c])}}}function a(){if(f.readyState==4){if(((f.status/100)==2)||Xinha.isRunLocally&&f.status===0){if(typeof h=="function"){h(f.responseText,f)}}else{if(Xinha._postback_send_charset){Xinha._postback_send_charset=false;Xinha._postback(b,g,h,d)}else{if(typeof d=="function"){d(f)}else{alert("An error has occurred: "+f.statusText+"\\nURL: "+b)}}}}}f.onreadystatechange=a;f.open("POST",b,true);f.setRequestHeader("Content-Type","application/x-www-form-urlencoded"+(Xinha._postback_send_charset?"; charset=UTF-8":""));f.send(e)};Xinha._getback=function(b,e,c){var d=null;d=Xinha.getXMLHTTPRequestObject();function a(){if(d.readyState==4){if(((d.status/100)==2)||Xinha.isRunLocally&&d.status===0){e(d.responseText,d)}else{if(typeof c=="function"){c(d)}else{alert("An error has occurred: "+d.statusText+"\\nURL: "+b)}}}}d.onreadystatechange=a;d.open("GET",b,true);d.send(null)};Xinha.ping=function(d,c,b){var e=null;e=Xinha.getXMLHTTPRequestObject();function a(){if(e.readyState==4){if(((e.status/100)==2)||Xinha.isRunLocally&&e.status===0){if(c){c(e)}}else{if(b){b(e)}}}}var f="GET";e.onreadystatechange=a;e.open(f,d,true);e.send(null)};Xinha._geturlcontent=function(a,c){var b=null;b=Xinha.getXMLHTTPRequestObject();b.open("GET",a,false);b.send(null);if(((b.status/100)==2)||Xinha.isRunLocally&&b.status===0){return(c)?b.responseXML:b.responseText}else{return""}};if(typeof dumpValues=="undefined"){dumpValues=function(c){var b="";for(var d in c){if(window.console&&typeof window.console.log=="function"){if(typeof console.firebug!="undefined"){console.log(c)}else{console.log(d+" = "+c[d]+"\\n")}}else{b+=d+" = "+c[d]+"\\n"}}if(b){if(document.getElementById("errors")){document.getElementById("errors").value+=b}else{var a=window.open("","debugger");a.document.write("<pre>"+b+"</pre>")}}}}if(!Array.prototype.contains){Array.prototype.contains=function(c){var b=this;for(var a=0;a<b.length;a++){if(c==b[a]){return true}}return false}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){var b=this;for(var a=0;a<b.length;a++){if(c==b[a]){return a}}return null}}if(!Array.prototype.append){Array.prototype.append=function(b){for(var c=0;c<b.length;c++){this.push(b[c])}return this}}if(!Array.prototype.forEach){Array.prototype.forEach=function(d){var a=this.length;if(typeof d!="function"){throw new TypeError()}var c=arguments[1];for(var b=0;b<a;b++){if(b in this){d.call(c,this[b],b,this)}}}}Xinha.getElementsByClassName=function(d,a){if(d.getElementsByClassName){return Array.prototype.slice.call(d.getElementsByClassName(a))}else{var c=d.getElementsByTagName("*");var e=[];var f;for(var b=0;b<c.length;b++){f=c[b].className.split(" ");if(f.contains(a)){e.push(c[b])}}return e}};Xinha.arrayContainsArray=function(c,b){var e=true;for(var a=0;a<b.length;a++){var f=false;for(var d=0;d<c.length;d++){if(c[d]==b[a]){f=true;break}}if(!f){e=false;break}}return e};Xinha.arrayFilter=function(c,b){var d=[];for(var a=0;a<c.length;a++){if(b(c[a])){d[d.length]=c[a]}}return d};Xinha.collectionToArray=function(c){try{return c.length?Array.prototype.slice.call(c):[]}catch(b){}var d=[];for(var a=0;a<c.length;a++){d.push(c.item(a))}return d};Xinha.uniq_count=0;Xinha.uniq=function(a){return a+Xinha.uniq_count++};Xinha._loadlang=function(context,url){var lang;if(typeof _editor_lcbackend=="string"){url=_editor_lcbackend;url=url.replace(/%lang%/,_editor_lang);url=url.replace(/%context%/,context)}else{if(!url){if(context!="Xinha"){url=Xinha.getPluginDir(context)+"/lang/"+_editor_lang+".js"}else{Xinha.setLoadingMessage("Loading language");url=_editor_url+"lang/"+_editor_lang+".js"}}}var langData=Xinha._geturlcontent(url);if(langData!==""){try{eval("lang = "+langData)}catch(ex){alert("Error reading Language-File ("+url+"):\\n"+Error.toString());lang={}}}else{lang={}}return lang};Xinha._lc=function(d,b,c){var a,h;if(typeof b=="object"&&b.url&&b.context){a=b.url+_editor_lang+".js";b=b.context}var f=null;if(typeof d=="string"){f=d.match(/\\$(.*?)=(.*?)\\$/g)}if(f){if(!c){c={}}for(var g=0;g<f.length;g++){var e=f[g].match(/\\$(.*?)=(.*?)\\$/);c[e[1]]=e[2];d=d.replace(e[0],"$"+e[1])}}if(_editor_lang=="en"){if(typeof d=="object"&&d.string){h=d.string}else{h=d}}else{if(typeof Xinha._lc_catalog=="undefined"){Xinha._lc_catalog=[]}if(typeof b=="undefined"){b="Xinha"}if(typeof Xinha._lc_catalog[b]=="undefined"){Xinha._lc_catalog[b]=Xinha._loadlang(b,a)}var j;if(typeof d=="object"&&d.key){j=d.key}else{if(typeof d=="object"&&d.string){j=d.string}else{j=d}}if(typeof Xinha._lc_catalog[b][j]=="undefined"){if(b=="Xinha"){if(typeof d=="object"&&d.string){h=d.string}else{h=d}}else{return Xinha._lc(d,"Xinha",c)}}else{h=Xinha._lc_catalog[b][j]}}if(typeof d=="object"&&d.replace){c=d.replace}if(typeof c!="undefined"){for(g in c){h=h.replace("$"+g,c[g])}}return h};Xinha.hasDisplayedChildren=function(c){var b=c.childNodes;for(var a=0;a<b.length;a++){if(b[a].tagName){if(b[a].style.display!="none"){return true}}}return false};Xinha._loadback=function(a,e,d,f){if(document.getElementById(a)){return true}var b=!Xinha.is_ie?"onload":"onreadystatechange";var c=document.createElement("script");c.type="text/javascript";c.src=a;c.id=a;if(e){c[b]=function(){if(Xinha.is_ie&&(!/loaded|complete/.test(window.event.srcElement.readyState))){return}e.call(d?d:this,f);c[b]=null}}document.getElementsByTagName("head")[0].appendChild(c);return false};Xinha.makeEditors=function(d,f,g){if(!Xinha.isSupportedBrowser){return}if(typeof f=="function"){f=f()}var b={};var e;for(var a=0;a<d.length;a++){if(typeof d[a]=="string"){e=Xinha.getElementById("textarea",d[a]);if(!e){d[a]=null;continue}}else{if(typeof d[a]=="object"&&d[a].tagName&&d[a].tagName.toLowerCase()=="textarea"){e=d[a];if(!e.id){e.id="xinha_id_"+a}}}var c=new Xinha(e,Xinha.cloneObject(f));c.registerPlugins(g);b[e.id]=c}return b};Xinha.startEditors=function(a){if(!Xinha.isSupportedBrowser){return}for(var b in a){if(a[b].generate){a[b].generate()}}};Xinha.prototype.registerPlugins=function(b){if(!Xinha.isSupportedBrowser){return}if(b){for(var a=0;a<b.length;a++){this.setLoadingMessage(Xinha._lc("Register plugin $plugin","Xinha",{plugin:b[a]}));this.registerPlugin(b[a])}}};Xinha.base64_encode=function(d){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var b="";var k,h,g;var l,j,f,e;var a=0;do{k=d.charCodeAt(a++);h=d.charCodeAt(a++);g=d.charCodeAt(a++);l=k>>2;j=((k&3)<<4)|(h>>4);f=((h&15)<<2)|(g>>6);e=g&63;if(isNaN(h)){f=e=64}else{if(isNaN(g)){e=64}}b=b+c.charAt(l)+c.charAt(j)+c.charAt(f)+c.charAt(e)}while(a<d.length);return b};Xinha.base64_decode=function(d){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var b="";var k,h,g;var l,j,f,e;var a=0;d=d.replace(/[^A-Za-z0-9\\+\\/\\=]/g,"");do{l=c.indexOf(d.charAt(a++));j=c.indexOf(d.charAt(a++));f=c.indexOf(d.charAt(a++));e=c.indexOf(d.charAt(a++));k=(l<<2)|(j>>4);h=((j&15)<<4)|(f>>2);g=((f&3)<<6)|e;b=b+String.fromCharCode(k);if(f!=64){b=b+String.fromCharCode(h)}if(e!=64){b=b+String.fromCharCode(g)}}while(a<d.length);return b};Xinha.removeFromParent=function(b){if(!b.parentNode){return}var a=b.parentNode;return a.removeChild(b)};Xinha.hasParentNode=function(a){if(a.parentNode){if(a.parentNode.nodeType==11){return false}return true}return false};Xinha.viewportSize=function(b){b=(b)?b:window;var a,c;if(b.innerHeight){a=b.innerWidth;c=b.innerHeight}else{if(b.document.documentElement&&b.document.documentElement.clientHeight){a=b.document.documentElement.clientWidth;c=b.document.documentElement.clientHeight}else{if(b.document.body){a=b.document.body.clientWidth;c=b.document.body.clientHeight}}}return{x:a,y:c}};Xinha.pageSize=function(d){d=(d)?d:window;var a,e;var c=d.document.body.scrollHeight;var b=d.document.documentElement.scrollHeight;if(c>b){a=d.document.body.scrollWidth;e=d.document.body.scrollHeight}else{a=d.document.documentElement.scrollWidth;e=d.document.documentElement.scrollHeight}return{x:a,y:e}};Xinha.prototype.scrollPos=function(b){b=(b)?b:window;var a,c;if(typeof b.pageYOffset!="undefined"){a=b.pageXOffset;c=b.pageYOffset}else{if(b.document.documentElement&&typeof document.documentElement.scrollTop!="undefined"){a=b.document.documentElement.scrollLeft;c=b.document.documentElement.scrollTop}else{if(b.document.body){a=b.document.body.scrollLeft;c=b.document.body.scrollTop}}}return{x:a,y:c}};Xinha.getElementTopLeft=function(b){var c=0;var a=0;if(b.offsetParent){c=b.offsetLeft;a=b.offsetTop;while(b=b.offsetParent){c+=b.offsetLeft;a+=b.offsetTop}}return{top:a,left:c}};Xinha.findPosX=function(a){var b=0;if(a.offsetParent){return Xinha.getElementTopLeft(a).left}else{if(a.x){b+=a.x}}return b};Xinha.findPosY=function(b){var a=0;if(b.offsetParent){return Xinha.getElementTopLeft(b).top}else{if(b.y){a+=b.y}}return a};Xinha.createLoadingMessages=function(b){if(Xinha.loadingMessages||!Xinha.isSupportedBrowser){return}Xinha.loadingMessages=[];for(var a=0;a<b.length;a++){if(!document.getElementById(b[a])){continue}Xinha.loadingMessages.push(Xinha.createLoadingMessage(Xinha.getElementById("textarea",b[a])))}};Xinha.createLoadingMessage=function(d,e){if(document.getElementById("loading_"+d.id)||!Xinha.isSupportedBrowser){return}var a=document.createElement("div");a.id="loading_"+d.id;a.className="loading";a.style.left=(Xinha.findPosX(d)+d.offsetWidth/2)-106+"px";a.style.top=(Xinha.findPosY(d)+d.offsetHeight/2)-50+"px";var b=document.createElement("div");b.className="loading_main";b.id="loading_main_"+d.id;b.appendChild(document.createTextNode(Xinha._lc("Loading in progress. Please wait!")));var c=document.createElement("div");c.className="loading_sub";c.id="loading_sub_"+d.id;e=e?e:Xinha._lc("Loading Core");c.appendChild(document.createTextNode(e));a.appendChild(b);a.appendChild(c);document.body.appendChild(a);Xinha.freeLater(a);Xinha.freeLater(b);Xinha.freeLater(c);return c};Xinha.prototype.setLoadingMessage=function(b,a){if(!document.getElementById("loading_sub_"+this._textArea.id)){return}document.getElementById("loading_main_"+this._textArea.id).innerHTML=a?a:Xinha._lc("Loading in progress. Please wait!");document.getElementById("loading_sub_"+this._textArea.id).innerHTML=b};Xinha.setLoadingMessage=function(b){if(!Xinha.loadingMessages){return}for(var a=0;a<Xinha.loadingMessages.length;a++){Xinha.loadingMessages[a].innerHTML=b}};Xinha.prototype.removeLoadingMessage=function(){if(document.getElementById("loading_"+this._textArea.id)){document.body.removeChild(document.getElementById("loading_"+this._textArea.id))}};Xinha.removeLoadingMessages=function(c){for(var b=0;b<c.length;b++){if(!document.getElementById(c[b])){continue}var a=document.getElementById("loading_"+document.getElementById(c[b]).id);a.parentNode.removeChild(a)}Xinha.loadingMessages=null};Xinha.toFree=[];Xinha.freeLater=function(a,b){Xinha.toFree.push({o:a,p:b})};Xinha.free=function(c,d){if(c&&!d){for(var b in c){Xinha.free(c,b)}}else{if(c){if(d.indexOf("src")==-1){try{c[d]=null}catch(a){}}}}};Xinha.collectGarbageForIE=function(){Xinha.flushEvents();for(var a=0;a<Xinha.toFree.length;a++){Xinha.free(Xinha.toFree[a].o,Xinha.toFree[a].p);Xinha.toFree[a].o=null}};Xinha.prototype.insertNodeAtSelection=function(a){Xinha.notImplemented("insertNodeAtSelection")};Xinha.prototype.getParentElement=function(a){Xinha.notImplemented("getParentElement")};Xinha.prototype.activeElement=function(a){Xinha.notImplemented("activeElement")};Xinha.prototype.selectionEmpty=function(a){Xinha.notImplemented("selectionEmpty")};Xinha.prototype.saveSelection=function(){Xinha.notImplemented("saveSelection")};Xinha.prototype.restoreSelection=function(a){Xinha.notImplemented("restoreSelection")};Xinha.prototype.selectNodeContents=function(a,b){Xinha.notImplemented("selectNodeContents")};Xinha.prototype.insertHTML=function(a){Xinha.notImplemented("insertHTML")};Xinha.prototype.getSelectedHTML=function(){Xinha.notImplemented("getSelectedHTML")};Xinha.prototype.getSelection=function(){Xinha.notImplemented("getSelection")};Xinha.prototype.createRange=function(a){Xinha.notImplemented("createRange")};Xinha.prototype.isKeyEvent=function(a){Xinha.notImplemented("isKeyEvent")};Xinha.prototype.isShortCut=function(a){if(a.ctrlKey&&!a.altKey){return true}return false};Xinha.prototype.getKey=function(a){Xinha.notImplemented("getKey")};Xinha.getOuterHTML=function(a){Xinha.notImplemented("getOuterHTML")};Xinha.getXMLHTTPRequestObject=function(){try{if(typeof XMLHttpRequest!="undefined"&&typeof XMLHttpRequest.constructor=="function"){return new XMLHttpRequest()}else{if(typeof ActiveXObject=="function"){return new ActiveXObject("Microsoft.XMLHTTP")}}}catch(a){Xinha.notImplemented("getXMLHTTPRequestObject")}};Xinha.prototype._activeElement=function(a){return this.activeElement(a)};Xinha.prototype._selectionEmpty=function(a){return this.selectionEmpty(a)};Xinha.prototype._getSelection=function(){return this.getSelection()};Xinha.prototype._createRange=function(a){return this.createRange(a)};HTMLArea=Xinha;Xinha.init();if(Xinha.ie_version<8){Xinha.addDom0Event(window,"unload",Xinha.collectGarbageForIE)}Xinha.debugMsg=function(a,b){if(typeof console!="undefined"&&typeof console.log=="function"){if(b&&b=="warn"&&typeof console.warn=="function"){console.warn(a)}else{if(b&&b=="info"&&typeof console.info=="function"){console.info(a)}else{console.log(a)}}}else{if(typeof opera!="undefined"&&typeof opera.postError=="function"){opera.postError(a)}}};Xinha.notImplemented=function(a){throw new Error("Method Not Implemented","Part of Xinha has tried to call the "+a+" method which has not been implemented.")}; ]]></string> </value> </item> diff --git a/bt5/erp5_xinha_editor/bt/revision b/bt5/erp5_xinha_editor/bt/revision index c7930257df..301160a930 100644 --- a/bt5/erp5_xinha_editor/bt/revision +++ b/bt5/erp5_xinha_editor/bt/revision @@ -1 +1 @@ -7 \ No newline at end of file +8 \ No newline at end of file -- 2.30.9