diff --git a/xinha/contrib/lc_parse_strings.php b/xinha/contrib/lc_parse_strings.php new file mode 100755 index 0000000..22e3a96 --- /dev/null +++ b/xinha/contrib/lc_parse_strings.php @@ -0,0 +1,261 @@ +$strings) +{ + if(sizeof($strings)==0) continue; + + + $data = "// I18N constants\n"; + $data .= "//\n"; + $data .= "//LANG: \"base\", ENCODING: UTF-8\n"; + $data .= "//Author: Translator-Name, \n"; + $data .= "// FOR TRANSLATORS:\n"; + $data .= "//\n"; + $data .= "// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE\n"; + $data .= "// (at least a valid email address)\n"; + $data .= "//\n"; + $data .= "// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING;\n"; + $data .= "// (if this is not possible, please include a comment\n"; + $data .= "// that states what encoding is necessary.)\n"; + $data .= "\n"; + $data .= "{\n"; + sort($strings); + foreach($strings as $string) { + $string = str_replace(array('\\', '"'), array('\\\\', '\\"'), $string); + $data .= " \"".$string."\": \"\",\n"; + } + $data = substr($data, 0, -2); + $data .= "\n"; + $data .= "}\n"; + + if($plugin=="HTMLArea") + $file = "../lang/base.js"; + else + $file = "../plugins/$plugin/lang/base.js"; + + $fp = fopen($file, "w"); + if(!$fp) continue; + fwrite($fp, $data); + fclose($fp); + echo "$file written...
"; +} + + + + +function parseHtmlFile($file, $plugin="") +{ + $ret = array(); + + $fp = fopen($file, "r"); + if(!$fp) { + die("invalid fp"); + } + $data = ""; + while(!feof($fp)) { + $data .= fread($fp, 1024); + } + + if($plugin=="FormOperations" || $plugin=="SuperClean" || $plugin=="Linker") { + //-tags for inline-dialog or panel-dialog based dialogs + $elems = array("l10n"); + } else { + $elems = array("title", "input", "select", "legend", "span", "option", "td", "button", "div", "label"); + } + foreach($elems as $elem) { + preg_match_all("#<{$elem}[^>]*>([^<^\"]+)#i", $data, $m); + foreach($m[1] as $i) { + if(trim(strip_tags($i))=="") continue; + if($i=="/") continue; + if($plugin=="ImageManager" && preg_match('#^--+$#', $i)) continue; //skip those ------ + if($plugin=="CharacterMap" && preg_match('#&[a-z0-9]+;#i', trim($i)) || $i=="@") continue; + if($plugin=="SpellChecker" && preg_match('#^\'\\.\\$[a-z]+\\.\'$#', $i)) continue; + $ret[] = trim($i); + } + } + + if($plugin=="FormOperations" || $plugin=="SuperClean" || $plugin=="Linker") + { + //_( for inline-dialog or panel-dialog based dialogs + preg_match_all('#"_\(([^"]+)\)"#i', $data, $m); + foreach($m[1] as $i) { + if(trim($i)=="") continue; + $ret[] = $i; + } + } + else + { + preg_match_all('#title="([^"]+)"#i', $data, $m); + foreach($m[1] as $i) { + if(trim(strip_tags($i))=="") continue; + if(strip_tags($i)==" - ") continue; //skip those - (ImageManager) + $ret[] = $i; + } + } + return($ret); +} + + +function getFiles($rootdirpath, $eregi_match='') { + $array = array(); + if ($dir = @opendir($rootdirpath)) { + $array = array(); + while (($file = readdir($dir)) !== false) { + if($file=="." || $file==".." || $file==".svn") continue; + if($eregi_match=="") + $array[] = $rootdirpath."/".$file; + else if(eregi($eregi_match,$file)) + $array[] = $rootdirpath."/".$file; + + } + closedir($dir); + } + return $array; +} + + + + + +?> \ No newline at end of file diff --git a/xinha/dialog.js b/xinha/dialog.js new file mode 100644 index 0000000..09c000e --- /dev/null +++ b/xinha/dialog.js @@ -0,0 +1,76 @@ +// htmlArea v3.0 - Copyright (c) 2003-2004 interactivetools.com, inc. +// This copyright notice MUST stay intact for use (see license.txt). +// +// Portions (c) dynarch.com, 2003-2004 +// +// A free WYSIWYG editor replacement for + + + + + + + + + + + + + + diff --git a/xinha/examples/full_example-menu.html b/xinha/examples/full_example-menu.html new file mode 100644 index 0000000..d652105 --- /dev/null +++ b/xinha/examples/full_example-menu.html @@ -0,0 +1,187 @@ + + + + + +Example of Xinha + + + + + + +
+

+ Select from the options below and +

+
+ Settings + + + +
+ +
+ Plugins + + +
+ mode : +
+ + + + + + + + + + + + + + + + + + +
+ mode : +
+ + + + + + +
+ +
+ PHP Plugins +

+ These plugins require PHP in order to run. +

+ + + + + +
+ +
+ + + + \ No newline at end of file diff --git a/xinha/examples/full_example.css b/xinha/examples/full_example.css new file mode 100644 index 0000000..cfaf514 --- /dev/null +++ b/xinha/examples/full_example.css @@ -0,0 +1,47 @@ + /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- + -- Xinha example CSS file. This is ripped from Trac ;) + -- + -- $HeadURL: http://svn.xinha.python-hosting.com/trunk/examples/full_example.css $ + -- $LastChangedDate: 2005-02-19 17:10:03 +1300 (Sat, 19 Feb 2005) $ + -- $LastChangedRevision: 14 $ + -- $LastChangedBy: gogo $ + --------------------------------------------------------------------------*/ + + body { + background: #fff; + color: #000; + margin: 10px; + } + body, th, td { + font: normal 13px verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif; + } + h1, h2, h3, h4 { + font-family: arial,verdana,'Bitstream Vera Sans',helvetica,sans-serif; + font-weight: bold; + letter-spacing: -0.018em; + } + h1 { font-size: 21px; margin: .15em 1em 0 0 } + h2 { font-size: 16px; margin: 2em 0 .5em; } + h3 { font-size: 14px; margin: 1.5em 0 .5em; } + hr { border: none; border-top: 1px solid #ccb; margin: 2em 0; } + address { font-style: normal } + img { border: none } + + :link, :visited { + text-decoration: none; + color: #b00; + border-bottom: 1px dotted #bbb; + } + :link:hover, :visited:hover { + background-color: #eee; + color: #555; + } + h1 :link, h1 :visited ,h2 :link, h2 :visited, h3 :link, h3 :visited, + h4 :link, h4 :visited, h5 :link, h5 :visited, h6 :link, h6 :visited { + color: inherit; + } + + .area_holder + { + margin:10px; + } \ No newline at end of file diff --git a/xinha/examples/full_example.html b/xinha/examples/full_example.html new file mode 100644 index 0000000..b31441b --- /dev/null +++ b/xinha/examples/full_example.html @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/xinha/examples/full_example.js b/xinha/examples/full_example.js new file mode 100644 index 0000000..27bcfdf --- /dev/null +++ b/xinha/examples/full_example.js @@ -0,0 +1,150 @@ + + /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- + -- Xinha example logic. This javascript is used to auto-generate examples + -- as controlled by the options set in full_example-menu.html. it's called + -- from full_example-body.html. + -- + -- $HeadURL: http://svn.xinha.python-hosting.com/trunk/examples/full_example.js $ + -- $LastChangedDate: 2005-09-15 00:09:22 +1200 (Thu, 15 Sep 2005) $ + -- $LastChangedRevision: 318 $ + -- $LastChangedBy: mokhet $ + --------------------------------------------------------------------------*/ + + var num = 1; + if(window.parent && window.parent != window) + { + var f = window.parent.menu.document.forms[0]; + _editor_lang = f.lang.value; + _editor_skin = f.skin.value; + num = parseInt(f.num.value); + if(isNaN(num)) + { + num = 1; + f.num.value = 1; + } + xinha_plugins = [ ]; + for(var x = 0; x < f.plugins.length; x++) + { + if(f.plugins[x].checked) xinha_plugins.push(f.plugins[x].value); + } + } + + xinha_editors = [ ] + for(var x = 0; x < num; x++) + { + var ta = 'myTextarea' + x; + xinha_editors.push(ta); + } + + xinha_config = function() + { + var config = new HTMLArea.Config(); + + if(typeof CSS != 'undefined') + { + config.pageStyle = "@import url(custom.css);"; + } + + if(typeof Stylist != 'undefined') + { + // We can load an external stylesheet like this - NOTE : YOU MUST GIVE AN ABSOLUTE URL + // otherwise it won't work! + config.stylistLoadStylesheet(document.location.href.replace(/[^\/]*\.html/, 'stylist.css')); + + // Or we can load styles directly + config.stylistLoadStyles('p.red_text { color:red }'); + + // If you want to provide "friendly" names you can do so like + // (you can do this for stylistLoadStylesheet as well) + config.stylistLoadStyles('p.pink_text { color:pink }', {'p.pink_text' : 'Pretty Pink'}); + } + + if(typeof DynamicCSS != 'undefined') + { + config.pageStyle = "@import url(dynamic.css);"; + } + + if(typeof InsertWords != 'undefined') + { + // Register the keyword/replacement list + var keywrds1 = new Object(); + var keywrds2 = new Object(); + + keywrds1['-- Dropdown Label --'] = ''; + keywrds1['onekey'] = 'onevalue'; + keywrds1['twokey'] = 'twovalue'; + keywrds1['threekey'] = 'threevalue'; + + keywrds2['-- Insert Keyword --'] = ''; + keywrds2['Username'] = '%user%'; + keywrds2['Last login date'] = '%last_login%'; + config.InsertWords = { + combos : [ { options: keywrds1, context: "body" }, + { options: keywrds2, context: "li" } ] + } + + } + + if (typeof ListType != 'undefined') + { + if(window.parent && window.parent != window) + { + var f = window.parent.menu.document.forms[0]; + config.ListType.mode = f.elements['ListTypeMode'].options[f.elements['ListTypeMode'].selectedIndex].value; + } + } + + if (typeof CharacterMap != 'undefined') + { + if(window.parent && window.parent != window) + { + var f = window.parent.menu.document.forms[0]; + config.CharacterMap.mode = f.elements['CharacterMapMode'].options[f.elements['CharacterMapMode'].selectedIndex].value; + } + } + + return config; + } + + + var f = document.forms[0]; + f.innerHTML = ''; + + var lipsum = document.getElementById('lipsum').innerHTML; + + for(var x = 0; x < num; x++) + { + var ta = 'myTextarea' + x; + + var div = document.createElement('div'); + div.className = 'area_holder'; + + var txta = document.createElement('textarea'); + txta.id = ta; + txta.name = ta; + txta.value = lipsum; + txta.style.width="100%"; + txta.style.height="420px"; + + div.appendChild(txta); + f.appendChild(div); + } + + //check submitted values + var submit = document.createElement('input'); + submit.type = "submit"; + submit.id = "submit"; + submit.value = "submit"; + f.appendChild(submit); + + var _oldSubmitHandler = null; + if (document.forms[0].onsubmit != null) { + _oldSubmitHandler = document.forms[0].onsubmit; + } + function frame_onSubmit(){ + alert(document.getElementById("myTextarea0").value); + if (_oldSubmitHandler != null) { + _oldSubmitHandler(); + } + } + document.forms[0].onsubmit = frame_onSubmit; \ No newline at end of file diff --git a/xinha/examples/stylist.css b/xinha/examples/stylist.css new file mode 100644 index 0000000..d330628 --- /dev/null +++ b/xinha/examples/stylist.css @@ -0,0 +1,31 @@ + /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- + -- Stylist plugin example CSS file. Used by full_example.js + -- when the Stylist plugin is included in an auto-generated example. + -- + -- $HeadURL: http://svn.xinha.python-hosting.com/trunk/examples/stylist.css $ + -- $LastChangedDate: 2005-07-19 18:23:58 +1200 (Tue, 19 Jul 2005) $ + -- $LastChangedRevision: 277 $ + -- $LastChangedBy: gogo $ + --------------------------------------------------------------------------*/ + +.bluetext +{ + color:blue; +} + +p.blue_paragraph +{ + color:darkblue; +} + +li.green_list_item +{ + color:green; +} + +h1.webdings_lvl_1 +{ + font-family:webdings; +} + +img.polaroid { border:1px solid black; background-color:white; padding:10px; padding-bottom:30px; } \ No newline at end of file diff --git a/xinha/examples/testbed.html b/xinha/examples/testbed.html new file mode 100644 index 0000000..8ce2b23 --- /dev/null +++ b/xinha/examples/testbed.html @@ -0,0 +1,174 @@ + + + + + + + + + Example of Xinha + + + + + + + + + + + + +
+ + + +
+ + Hide + Show + + \ No newline at end of file diff --git a/xinha/htmlarea.css b/xinha/htmlarea.css new file mode 100644 index 0000000..e2df14f --- /dev/null +++ b/xinha/htmlarea.css @@ -0,0 +1,239 @@ +.htmlarea { background: #fff; margin:2px; } + +.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: 0px 3px; } + +.htmlarea .toolbar .button { + background: ButtonFace; + color: ButtonText; + border: 1px solid ButtonFace; + padding: 1px; + margin: 0px; + 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 0px 0px 2px; + border: 1px solid; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; +} +.htmlarea .toolbar .buttonPressed { + background: ButtonHighlight; +} +.htmlarea .toolbar .indicator { + padding: 0px 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: 0.25; +} + +.htmlarea .toolbar .separator { + /*position: relative;*/ + margin: 3px; + border-left: 1px solid ButtonShadow; + border-right: 1px solid ButtonHighlight; + width: 0px; + height: 18px; + padding: 0px; +} + +.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 { + margin-top: 2px; + margin-bottom: 1px; + background: FieldFace; + color: ButtonText; +} + +.htmlarea iframe.xinha_iframe, .htmlarea textarea.xinha_textarea +{ + border: none; /*1px solid;*/ +} + +.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; +} + +.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; +} + + +/* Hidden DIV popup dialogs (PopupDiv) */ + +.dialog { + color: ButtonText; + background: ButtonFace; +} + +.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: #008; + color: #ff8; + border-bottom: 1px solid #000; + padding: 1px 0px 2px 5px; + font-size: 12px; + font-weight: bold; + cursor: default; +} +.dialog h1 { margin:0px;} +.dialog .title .button { + float: right; + border: 1px solid #66a; + padding: 0px 1px 0px 2px; + margin-right: 1px; + color: #fff; + text-align: center; +} + +.dialog .title .button-hilite { border-color: #88f; background: #44c; } + +.dialog button { + width: 5em; + padding: 0px; +} + +.dialog .buttonColor { + padding: 1px; + cursor: default; + border: 1px solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; +} + +.dialog .buttonColor-hilite { + border-color: #000; +} + +.dialog .buttonColor .chooser, .dialog .buttonColor .nocolor { + height: 0.6em; + border: 1px solid; + padding: 0px 1em; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; +} + +.dialog .buttonColor .nocolor { padding: 0px; } +.dialog .buttonColor .nocolor-hilite { background-color: #fff; color: #f00; } + +.dialog .label { text-align: right; width: 6em; } +.dialog .value input { width: 100%; } +.dialog .buttons { text-align: right; padding: 2px 4px 0px 4px; } + +.dialog legend { font-weight: bold; } +.dialog fieldset table { margin: 2px 0px; } + +.popupdiv { + border: 2px solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; +} + +.popupwin { + padding: 0px; + margin: 0px; +} + +.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: 0px; border: none; } + + +/** Panels **/ +.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 { + background: ButtonFace; + border: 1px solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; + margin: 0px; + padding: 0px; + font-size:100%; + font-weight:bold; + padding: 2px; +} + +.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; } diff --git a/xinha/htmlarea.js b/xinha/htmlarea.js new file mode 100644 index 0000000..f8590b3 --- /dev/null +++ b/xinha/htmlarea.js @@ -0,0 +1,5517 @@ + + /*--------------------------------------:noTabs=true:tabSize=2:indentSize=2:-- + -- Xinha (is not htmlArea) - http://xinha.gogo.co.nz/ + -- + -- Use of Xinha is granted by the terms of the htmlArea License (based on + -- BSD license) please read license.txt in this package for details. + -- + -- Xinha was originally based on work by Mihai Bazon which is: + -- Copyright (c) 2003-2004 dynarch.com. + -- Copyright (c) 2002-2003 interactivetools.com, inc. + -- This copyright notice MUST stay intact for use. + -- + -- Developers - Coding Style: + -- For the sake of not committing needlessly conflicting changes, + -- + -- * New code to be indented with 2 spaces ("soft tab"). + -- * New code preferably uses BSD-Style Bracing + -- if(foo) + -- { + -- bar(); + -- } + -- * Don't change brace styles unless you're working on the non BSD-Style + -- area (so we don't get spurious changes in line numbering). + -- * Don't change indentation unless you're working on the badly indented + -- area (so we don't get spurious changes of large blocks of code). + -- * Jedit is the recommended editor, a comment of this format should be + -- included in the top 10 lines of the file (see the embedded edit mode) + -- + -- $HeadURL: http://svn.xinha.python-hosting.com/trunk/htmlarea.js $ + -- $LastChangedDate: 2005-09-14 19:13:33 +1200 (Wed, 14 Sep 2005) $ + -- $LastChangedRevision: 316 $ + -- $LastChangedBy: niko $ + --------------------------------------------------------------------------*/ + +HTMLArea.version = +{ + 'Release' : 'Trunk', + 'Head' : '$HeadURL: http://svn.xinha.python-hosting.com/trunk/htmlarea.js $'.replace(/^[^:]*: (.*) \$$/, '$1'), + 'Date' : '$LastChangedDate: 2005-09-14 19:13:33 +1200 (Wed, 14 Sep 2005) $'.replace(/^[^:]*: ([0-9-]*) ([0-9:]*) ([+0-9]*) \((.*)\) \$/, '$4 $2 $3'), + 'Revision' : '$LastChangedRevision: 316 $'.replace(/^[^:]*: (.*) \$$/, '$1'), + 'RevisionBy': '$LastChangedBy: niko $'.replace(/^[^:]*: (.*) \$$/, '$1') +} + +if (typeof _editor_url == "string") { + // Leave exactly one backslash at the end of _editor_url + _editor_url = _editor_url.replace(/\x2f*$/, '/'); +} 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 '/htmlarea/', 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 = ''; +} + +// make sure we have a language +if (typeof _editor_lang == "string") { + _editor_lang = _editor_lang.toLowerCase(); +} else { + _editor_lang = "en"; +} + +// skin stylesheet to load +if (!(typeof _editor_skin == "string")) { + _editor_skin = ""; +} + +var __htmlareas = [ ]; + +// browser identification +HTMLArea.agt = navigator.userAgent.toLowerCase(); +HTMLArea.is_ie = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1)); +HTMLArea.is_opera = (HTMLArea.agt.indexOf("opera") != -1); +HTMLArea.is_mac = (HTMLArea.agt.indexOf("mac") != -1); +HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac); +HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac); +HTMLArea.is_gecko = (navigator.product == "Gecko"); + +// Creates a new HTMLArea object. Tries to replace the textarea with the given +// ID with it. +function HTMLArea(textarea, config) +{ + if(!textarea) throw("Tried to create HTMLArea without textarea specified."); + + if (HTMLArea.checkSupportedBrowser()) { + if (typeof config == "undefined") { + this.config = new HTMLArea.Config(); + } else { + this.config = config; + } + this._htmlArea = null; + + if(typeof textarea != 'object') + { + textarea = HTMLArea.getElementById('textarea', textarea); + } + this._textArea = textarea; + + // Before we modify anything, get the initial textarea size + this._initial_ta_size = + { + w: textarea.style.width ? textarea.style.width : (textarea.offsetWidth + 'px'), + h: textarea.style.height ? textarea.style.height : (textarea.offsetHeight + 'px') + } + + this._editMode = "wysiwyg"; + this.plugins = {}; + this._timerToolbar = null; + this._timerUndo = null; + this._undoQueue = new Array(this.config.undoSteps); + this._undoPos = -1; + this._customUndo = true; + this._mdoc = document; // cache the document, we need it in plugins + this.doctype = ''; + this.__htmlarea_id_num = __htmlareas.length; + __htmlareas[this.__htmlarea_id_num] = this; + + this._notifyListeners = { }; + + // Panels + var panels = this._panels = + { + 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 i in panels) + { + panels[i].div = panels[i].container; // legacy + panels[i].container.className = 'panels ' + i; + HTMLArea.freeLater(panels[i], 'container'); + HTMLArea.freeLater(panels[i], 'div'); + } + HTMLArea.freeLater(this, '_textArea'); + } +}; + +HTMLArea.onload = function(){}; +HTMLArea.init = function() { + HTMLArea.onload(); +}; + + +// cache some regexps +HTMLArea.RE_tagName = /(<\/|<)\s*([^ \t\n>]+)/ig; +HTMLArea.RE_doctype = /()\n?/i; +HTMLArea.RE_head = /((.|\n)*?)<\/head>/i; +HTMLArea.RE_body = /]*>((.|\n|\r|\t)*?)<\/body>/i; +HTMLArea.RE_Specials = /([\/\^$*+?.()|{}[\]])/g; +HTMLArea.RE_email = /[a-z0-9_]{3,}@[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,})+/i; +HTMLArea.RE_url = /(https?:\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,}){2,}(:[0-9]+)?(\/\S+)*)/i; + +HTMLArea.Config = function () { + var cfg = this; + this.version = HTMLArea.version.Revision; + + // Width and Height + // you may set these as follows + // width = 'auto' -- the width of the original textarea will be used + // width = 'toolbar' -- the width of the toolbar will be used + // width = '' -- use any css measurement, eg width = '75%' + // + // height = 'auto' -- the height of the original textarea + // height = '' -- any css measurement, eg height = '480px' + this.width = "auto"; + this.height = "auto"; + + // the next parameter specifies whether the toolbar should be included + // in the size above, or are extra to it. If false then it's recommended + // to have explicit pixel sizes above (or on your textarea and have auto above) + this.sizeIncludesBars = true; + + // the next parameter specifies whether the panels should be included + // in the size above, or are extra to it. If false then it's recommended + // to have explicit pixel sizes above (or on your textarea and have auto above) + this.sizeIncludesPanels = true; + + // each of the panels has a dimension, for the left/right it's the width + // for the top/bottom it's the height. + // + // WARNING: PANEL DIMENSIONS MUST BE SPECIFIED AS PIXEL WIDTHS + this.panel_dimensions = + { + left: '200px', // Width + right: '200px', + top: '100px', // Height + bottom: '100px' + } + + // enable creation of a status bar? + this.statusBar = true; + + // intercept ^V and use the HTMLArea paste command + // If false, then passes ^V through to browser editor widget + this.htmlareaPaste = false; + + this.mozParaHandler = 'best'; // set to 'built-in', 'dirty' or 'best' + // built-in: will (may) use 'br' instead of 'p' tags + // dirty : will use p and work good enough for the majority of cases, + // best : works the best, but it's about 12kb worth of javascript + // and will probably be slower than 'dirty'. This is the "EnterParagraphs" + // plugin from "hipikat", rolled in to be part of the core code + + // maximum size of the undo queue + this.undoSteps = 20; + + // the time interval at which undo samples are taken + this.undoTimeout = 500; // 1/2 sec. + + // if true then HTMLArea will retrieve the full HTML, starting with the + // tag. + this.fullPage = false; + + // style included in the iframe document + this.pageStyle = ""; + + // external stylesheets to load (REFERENCE THESE ABSOLUTELY) + this.pageStyleSheets = [ ]; + + // specify a base href for relative links + this.baseHref = null; + + // we can strip the base href out of relative links to leave them relative, reason for this + // especially if you don't specify a baseHref is that mozilla at least (& IE ?) will prefix + // the baseHref to any relative links to make them absolute, which isn't what you want most the time. + this.stripBaseHref = true; + + // and we can strip the url of the editor page from named links (eg ...) + // reason for this is that mozilla at least (and IE ?) prefixes location.href to any + // that don't have a url prefixing them + this.stripSelfNamedAnchors = true; + + // sometimes high-ascii in links can cause problems for servers (basically they don't recognise them) + // so you can use this flag to ensure that all characters other than the normal ascii set (actually + // only ! through ~) are escaped in URLs to % codes + this.only7BitPrintablesInURLs = true; + + // if you are putting the HTML written in Xinha into an email you might want it to be 7-bit + // characters only. This config option (off by default) will convert all characters consuming + // more than 7bits into UNICODE decimal entity references (actually it will convert anything + // below (chr 20) except cr, lf and tab and above (~, chr 7E)) + this.sevenBitClean = false; + + // sometimes we want to be able to replace some string in the html comng in and going out + // so that in the editor we use the "internal" string, and outside and in the source view + // we use the "external" string this is useful for say making special codes for + // your absolute links, your external string might be some special code, say "{server_url}" + // an you say that the internal represenattion of that should be http://your.server/ + this.specialReplacements = { }; // { 'external_string' : 'internal_string' } + + // set to true if you want Word code to be cleaned upon Paste + this.killWordOnPaste = true; + + // enable the 'Target' field in the Make Link dialog + this.makeLinkShowsTarget = true; + + // CharSet of the iframe, default is the charset of the document + this.charSet = HTMLArea.is_gecko ? document.characterSet : document.charset; + + // URL-s + this.imgURL = "images/"; + this.popupURL = "popups/"; + this.helpURL = _editor_url + "reference.html"; + + // remove tags (these have to be a regexp, or null if this functionality is not desired) + this.htmlRemoveTags = null; + + // Turning this on will turn all "linebreak" and "separator" items in your toolbar into soft-breaks, + // this means that if the items between that item and the next linebreak/separator can + // fit on the same line as that which came before then they will, otherwise they will + // float down to the next line. + + // If you put a linebreak and separator next to each other, only the separator will + // take effect, this allows you to have one toolbar that works for both flowToolbars = true and false + // infact the toolbar below has been designed in this way, if flowToolbars is false then it will + // create explictly two lines (plus any others made by plugins) breaking at justifyleft, however if + // flowToolbars is false and your window is narrow enough then it will create more than one line + // even neater, if you resize the window the toolbars will reflow. Niiiice. + + this.flowToolbars = true; + + /** CUSTOMIZING THE TOOLBAR + * ------------------------- + * + * It is recommended that you customize the toolbar contents in an + * external file (i.e. the one calling HTMLArea) and leave this one + * unchanged. That's because when we (InteractiveTools.com) release a + * new official version, it's less likely that you will have problems + * upgrading HTMLArea. + */ + 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"], + ["separator","undo","redo","selectall"], (HTMLArea.is_gecko ? [] : ["cut","copy","paste","overwrite","saveas"]), + ["separator","killword","removeformat","toggleborders","lefttoright", "righttoleft","separator","htmlmode","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.customSelects = {}; + + function cut_copy_paste(e, cmd, obj) { + e.execCommand(cmd); + }; + + this.debug = true; + + this.URIs = { + "blank": "popups/blank.html", + "link": "link.html", + "insert_image": "insert_image.html", + "insert_table": "insert_table.html", + "select_color": "select_color.html", + "about": "about.html" + }; + + + // ADDING CUSTOM BUTTONS: please read below! + // format of the btnList elements is "ID: [ ToolTip, Icon, Enabled in text mode?, ACTION ]" + // - ID: unique ID for the button. If the button calls document.execCommand + // it's wise to give it the same name as the called command. + // - ACTION: function that gets called when the button is clicked. + // it has the following prototype: + // function(editor, buttonName) + // - editor is the HTMLArea object that triggered the call + // - buttonName is the ID of the clicked button + // These 2 parameters makes it possible for you to use the same + // handler for more HTMLArea objects or for more different buttons. + // - ToolTip: tooltip, will be translated below + // - Icon: path to an icon image file for the button + // OR; you can use an 18x18 block of a larger image by supllying an array + // that has three elemtents, the first is the larger image, the second is the column + // the third is the row. The ros and columns numbering starts at 0 but there is + // a header row and header column which have numbering to make life easier. + // See images/buttons_main.gif to see how it's done. + // - Enabled in text mode: if false the button gets disabled for text-only mode; otherwise enabled all the time. + this.btnList = { + bold: [ "Bold", HTMLArea._lc({key: 'button_bold', string: ["ed_buttons_main.gif",3,2]}, 'HTMLArea'), false, function(e) {e.execCommand("bold");} ], + italic: [ "Italic", HTMLArea._lc({key: 'button_italic', string: ["ed_buttons_main.gif",2,2]}, 'HTMLArea'), false, function(e) {e.execCommand("italic");} ], + underline: [ "Underline", HTMLArea._lc({key: 'button_underline', string: ["ed_buttons_main.gif",2,0]}, 'HTMLArea'), false, function(e) {e.execCommand("underline");} ], + strikethrough: [ "Strikethrough", HTMLArea._lc({key: 'button_strikethrough', string: ["ed_buttons_main.gif",3,0]}, 'HTMLArea'), false, function(e) {e.execCommand("strikethrough");} ], + subscript: [ "Subscript", HTMLArea._lc({key: 'button_subscript', string: ["ed_buttons_main.gif",3,1]}, 'HTMLArea'), false, function(e) {e.execCommand("subscript");} ], + superscript: [ "Superscript", HTMLArea._lc({key: 'button_superscript', string: ["ed_buttons_main.gif",2,1]}, 'HTMLArea'), false, function(e) {e.execCommand("superscript");} ], + + justifyleft: [ "Justify Left", ["ed_buttons_main.gif",0,0], false, function(e) {e.execCommand("justifyleft");} ], + justifycenter: [ "Justify Center", ["ed_buttons_main.gif",1,1], false, function(e){e.execCommand("justifycenter");}], + justifyright: [ "Justify Right", ["ed_buttons_main.gif",1,0], false, function(e) {e.execCommand("justifyright");} ], + justifyfull: [ "Justify Full", ["ed_buttons_main.gif",0,1], false, function(e) {e.execCommand("justifyfull");} ], + + + orderedlist: [ "Ordered List", ["ed_buttons_main.gif",0,3], false, function(e) {e.execCommand("insertorderedlist");} ], + unorderedlist: [ "Bulleted List", ["ed_buttons_main.gif",1,3], false, function(e) {e.execCommand("insertunorderedlist");} ], + insertorderedlist: [ "Ordered List", ["ed_buttons_main.gif",0,3], false, function(e) {e.execCommand("insertorderedlist");} ], + insertunorderedlist: [ "Bulleted List", ["ed_buttons_main.gif",1,3], false, function(e) {e.execCommand("insertunorderedlist");} ], + + outdent: [ "Decrease Indent", ["ed_buttons_main.gif",1,2], false, function(e) {e.execCommand("outdent");} ], + indent: [ "Increase Indent",["ed_buttons_main.gif",0,2], false, function(e) {e.execCommand("indent");} ], + forecolor: [ "Font Color", ["ed_buttons_main.gif",3,3], false, function(e) {e.execCommand("forecolor");} ], + hilitecolor: [ "Background Color", ["ed_buttons_main.gif",2,3], false, function(e) {e.execCommand("hilitecolor");} ], + + undo: [ "Undoes your last action", ["ed_buttons_main.gif",4,2], false, function(e) {e.execCommand("undo");} ], + redo: [ "Redoes your last action", ["ed_buttons_main.gif",5,2], false, function(e) {e.execCommand("redo");} ], + cut: [ "Cut selection", ["ed_buttons_main.gif",5,0], false, cut_copy_paste ], + copy: [ "Copy selection", ["ed_buttons_main.gif",4,0], false, cut_copy_paste ], + paste: [ "Paste from clipboard", ["ed_buttons_main.gif",4,1], false, cut_copy_paste ], + selectall: [ "Select all", "ed_selectall.gif", false, function(e) {e.execCommand("selectall");} ], + + + inserthorizontalrule: [ "Horizontal Rule", ["ed_buttons_main.gif",6,0], false, function(e) {e.execCommand("inserthorizontalrule");} ], + createlink: [ "Insert Web Link", ["ed_buttons_main.gif",6,1], false, function(e) {e._createLink();} ], + insertimage: [ "Insert/Modify Image", ["ed_buttons_main.gif",6,3], false, function(e) {e.execCommand("insertimage");} ], + inserttable: [ "Insert Table", ["ed_buttons_main.gif",6,2], false, function(e) {e.execCommand("inserttable");} ], + + + htmlmode: [ "Toggle HTML Source", ["ed_buttons_main.gif",7,0], true, function(e) {e.execCommand("htmlmode");} ], + toggleborders: [ "Toggle Borders", ["ed_buttons_main.gif",7,2], false, function(e) { e._toggleBorders() } ], + print: [ "Print document", ["ed_buttons_main.gif",8,1], false, function(e) {e._iframe.contentWindow.print();} ], + saveas: [ "Save as", "ed_saveas.gif", false, function(e) {e.execCommand("saveas",false,"noname.htm");} ], + about: [ "About this editor", ["ed_buttons_main.gif",8,2], true, function(e) {e.execCommand("about");} ], + showhelp: [ "Help using editor", ["ed_buttons_main.gif",9,2], true, function(e) {e.execCommand("showhelp");} ], + + splitblock: [ "Split Block", "ed_splitblock.gif", false, function(e) {e._splitBlock();} ], + lefttoright: [ "Direction left to right", ["ed_buttons_main.gif",0,4], false, function(e) {e.execCommand("lefttoright");} ], + righttoleft: [ "Direction right to left", ["ed_buttons_main.gif",1,4], false, function(e) {e.execCommand("righttoleft");} ], + overwrite: [ "Insert/Overwrite", "ed_overwrite.gif", false, function(e) {e.execCommand("overwrite");} ], + + wordclean: [ "MS Word Cleaner", ["ed_buttons_main.gif",5,3], false, function(e) {e._wordClean();} ], + clearfonts: [ "Clear Inline Font Specifications", ["ed_buttons_main.gif",5,4], false, function(e) {e._clearFonts();} ], + removeformat: [ "Remove formatting", ["ed_buttons_main.gif",4,4], false, function(e) {e.execCommand("removeformat");} ], + killword: [ "Clear MSOffice tags", ["ed_buttons_main.gif",4,3], false, function(e) {e.execCommand("killword");} ] + + }; + /* ADDING CUSTOM BUTTONS + * --------------------- + * + * It is recommended that you add the custom buttons in an external + * file and leave this one unchanged. That's because when we + * (InteractiveTools.com) release a new official version, it's less + * likely that you will have problems upgrading HTMLArea. + * + * Example on how to add a custom button when you construct the HTMLArea: + * + * var editor = new HTMLArea("your_text_area_id"); + * var cfg = editor.config; // this is the default configuration + * cfg.btnList["my-hilite"] = + * [ function(editor) { editor.surroundHTML('', ''); }, // action + * "Highlight selection", // tooltip + * "my_hilite.gif", // image + * false // disabled in text mode + * ]; + * cfg.toolbar.push(["linebreak", "my-hilite"]); // add the new button to the toolbar + * + * An alternate (also more convenient and recommended) way to + * accomplish this is to use the registerButton function below. + */ + // initialize tooltips from the I18N module and generate correct image path + for (var i in this.btnList) { + var btn = this.btnList[i]; + if(typeof btn[1] != 'string') + { + btn[1][0] = _editor_url + this.imgURL + btn[1][0]; + } + else + { + btn[1] = _editor_url + this.imgURL + btn[1]; + } + btn[0] = HTMLArea._lc(btn[0]); //initialize tooltip + } + +}; + +/** Helper function: register a new button with the configuration. It can be + * called with all 5 arguments, or with only one (first one). When called with + * only one argument it must be an object with the following properties: id, + * tooltip, image, textMode, action. Examples: + * + * 1. config.registerButton("my-hilite", "Hilite text", "my-hilite.gif", false, function(editor) {...}); + * 2. config.registerButton({ + * id : "my-hilite", // the ID of your button + * tooltip : "Hilite text", // the tooltip + * image : "my-hilite.gif", // image to be displayed in the toolbar + * textMode : false, // disabled in text mode + * action : function(editor) { // called when the button is clicked + * editor.surroundHTML('', ''); + * }, + * context : "p" // will be disabled if outside a

element + * }); + */ +HTMLArea.Config.prototype.registerButton = function(id, tooltip, image, textMode, action, context) { + var the_id; + if (typeof id == "string") { + the_id = id; + } else if (typeof id == "object") { + the_id = id.id; + } else { + alert("ERROR [HTMLArea.Config::registerButton]:\ninvalid arguments"); + return false; + } + // check for existing id + if (typeof this.customSelects[the_id] != "undefined") { + // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); + } + if (typeof this.btnList[the_id] != "undefined") { + // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); + } + switch (typeof id) { + case "string": this.btnList[id] = [ tooltip, image, textMode, action, context ]; break; + case "object": this.btnList[id.id] = [ id.tooltip, id.image, id.textMode, id.action, id.context ]; break; + } +}; + +HTMLArea.prototype.registerPanel = function(side, object) +{ + if(!side) side = 'right'; + var panel = this.addPanel(side); + if(object) + { + object.drawPanelIn(panel); + } +} + +/** The following helper function registers a dropdown box with the editor + * configuration. You still have to add it to the toolbar, same as with the + * buttons. Call it like this: + * + * FIXME: add example + */ +HTMLArea.Config.prototype.registerDropdown = function(object) { + // check for existing id + if (typeof this.customSelects[object.id] != "undefined") { + // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA dropdown with the same ID already exists."); + } + if (typeof this.btnList[object.id] != "undefined") { + // alert("WARNING [HTMLArea.Config::registerDropdown]:\nA button with the same ID already exists."); + } + this.customSelects[object.id] = object; +}; + +/** Call this function to remove some buttons/drop-down boxes from the toolbar. + * Pass as the only parameter a string containing button/drop-down names + * delimited by spaces. Note that the string should also begin with a space + * and end with a space. Example: + * + * config.hideSomeButtons(" fontname fontsize textindicator "); + * + * It's useful because it's easier to remove stuff from the defaul toolbar than + * create a brand new toolbar ;-) + */ +HTMLArea.Config.prototype.hideSomeButtons = function(remove) { + var toolbar = this.toolbar; + for (var i = toolbar.length; --i >= 0;) { + var line = toolbar[i]; + for (var j = line.length; --j >= 0; ) { + if (remove.indexOf(" " + line[j] + " ") >= 0) { + var len = 1; + if (/separator|space/.test(line[j + 1])) { + len = 2; + } + line.splice(j, len); + } + } + } +}; + +/** Helper Function: add buttons/drop-downs boxes with title or separator to the toolbar + * if the buttons/drop-downs boxes doesn't allready exists. + * id: button or selectbox (as array with separator or title) + * where: button or selectbox (as array if the first is not found take the second and so on) + * position: + * -1 = insert button (id) one position before the button (where) + * 0 = replace button (where) by button (id) + * +1 = insert button (id) one position after button (where) + * + * cfg.addToolbarElement(["T[title]", "button_id", "separator"] , ["first_id","second_id"], -1); +*/ + +HTMLArea.Config.prototype.addToolbarElement = function(id, where, position) { + var toolbar = this.toolbar; + var a, i, j, o, sid; + var idIsArray = false; + var whereIsArray = false; + var whereLength = 0; + var whereJ = 0; + var whereI = 0; + var exists = false; + var found = false; + // check if id and where are arrys + if ((id && typeof id == "object") && (id.constructor == Array)) { + idIsArray = true; + } + if ((where && typeof where == "object") && (where.constructor == Array)) { + whereIsArray = true; + whereLength = where.length; + } + + if (idIsArray) { //find the button/select box in input array + for (i = 0; i < id.length; ++i) { + if ((id[i] != "separator") && (id[i].indexOf("T[") != 0)) { + sid = id[i]; + } + } + } else { + sid = id; + } + + for (var i = 0; !exists && !found && i < toolbar.length; ++i) { + a = toolbar[i] + for (j = 0; !found && j < a.length; ++j) { + if (a[i] == sid) { // check if button/select box exists + exists = true; + break; + } + if (whereIsArray) { + for (o = 0; o < whereLength; ++o) { + if(a[j] == where[o]) { + if (o == 0) { + found = true; + j--; + break; + } else { + whereI = i; + whereJ = j; + whereLength = o; + } + } + } + } else { + if (a[j] == where) { // find the position to insert + found = true; + break; + } + } + } + } + + if (!exists) { + if (!found && whereIsArray) { //if check found any other as the first button + if (where.length != whereLength) { + j = whereJ; + a = toolbar[whereI]; + found = true; + } + } + if (found) { + if (position == 0) { // replace the found button + if (idIsArray) { + a[j] = id[id.length-1]; + for (i = id.length-1; --i >= 0;) { + a.splice(j, 0, id[i]); + } + } else { + a[j] = id; + } + } else { // insert before/after the found button + if (position < 0) { + j = j + position + 1; //correct position before + } else if (position > 0) { + j = j + position; //correct posion after + } + if (idIsArray) { + for (i = id.length; --i >= 0;) { + a.splice(j, 0, id[i]); + } + } else { + a.splice(j, 0, id); + } + } + } else { // no button found + toolbar[0].splice(0, 0, "separator"); + if (idIsArray) { + for (i = id.length; --i >= 0;) { + toolbar[0].splice(0, 0, id[i]); + } + } else { + toolbar[0].splice(0, 0, id); + } + } + } +} + +/** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */ +HTMLArea.replaceAll = function(config) { + var tas = document.getElementsByTagName("textarea"); + for (var i = tas.length; i > 0; (new HTMLArea(tas[--i], config)).generate()); +}; + +/** Helper function: replaces the TEXTAREA with the given ID with HTMLArea. */ +HTMLArea.replace = function(id, config) +{ + var ta = HTMLArea.getElementById("textarea", id); + return ta ? (new HTMLArea(ta, config)).generate() : null;; +}; + +// Creates the toolbar and appends it to the _htmlarea +HTMLArea.prototype._createToolbar = function () { + var editor = this; // to access this in nested functions + + var toolbar = document.createElement("div"); + // ._toolbar is for legacy, ._toolBar is better thanks. + this._toolBar = this._toolbar = toolbar; + toolbar.className = "toolbar"; + toolbar.unselectable = "1"; + + HTMLArea.freeLater(this, '_toolBar'); + HTMLArea.freeLater(this, '_toolbar'); + + var tb_row = null; + var tb_objects = new Object(); + this._toolbarObjects = tb_objects; + + this._createToolbar1(editor, toolbar, tb_objects); + this._htmlArea.appendChild(toolbar); + + return toolbar; +} + + +HTMLArea.prototype._setConfig = function(config) { + this.config = config; +} + +HTMLArea.prototype._addToolbar = function() { + this._createToolbar1(this, this._toolbar, this._toolbarObjects); +} + +// separate from previous createToolBar to allow dynamic change of toolbar +HTMLArea.prototype._createToolbar1 = function (editor, toolbar, tb_objects) { + + // This shouldn't be necessary, but IE seems to float outside of the container + // when we float toolbar sections, so we have to clear:both here as well + // as at the end (which we do have to do). + if(editor.config.flowToolbars) + { + var brk = document.createElement('div'); + brk.style.height = + brk.style.width = + brk.style.lineHeight = + brk.style.fontSize = '1px'; + brk.style.clear = 'both'; + toolbar.appendChild(brk); + } + + // creates a new line in the toolbar + function newLine() { + if(typeof tb_row != 'undefined' && tb_row.childNodes.length == 0) return; + + var table = document.createElement("table"); + table.border = "0px"; + table.cellSpacing = "0px"; + table.cellPadding = "0px"; + if(editor.config.flowToolbars) + { + if(HTMLArea.is_ie) + { + table.style.styleFloat = "left"; + } + else + { + table.style.cssFloat = "left"; + } + } + + toolbar.appendChild(table); + // TBODY is required for IE, otherwise you don't see anything + // in the TABLE. + var tb_body = document.createElement("tbody"); + table.appendChild(tb_body); + tb_row = document.createElement("tr"); + tb_body.appendChild(tb_row); + + table.className = 'toolbarRow'; // meh, kinda. + }; // END of function: newLine + + // init first line + newLine(); + + // updates the state of a toolbar element. This function is member of + // a toolbar element object (unnamed objects created by createButton or + // createSelect functions below). + function setButtonStatus(id, newval) { + var oldval = this[id]; + var el = this.element; + if (oldval != newval) { + switch (id) { + case "enabled": + if (newval) { + HTMLArea._removeClass(el, "buttonDisabled"); + el.disabled = false; + } else { + HTMLArea._addClass(el, "buttonDisabled"); + el.disabled = true; + } + break; + case "active": + if (newval) { + HTMLArea._addClass(el, "buttonPressed"); + } else { + HTMLArea._removeClass(el, "buttonPressed"); + } + break; + } + this[id] = newval; + } + }; // END of function: setButtonStatus + + // this function will handle creation of combo boxes. Receives as + // parameter the name of a button as defined in the toolBar config. + // This function is called from createButton, above, if the given "txt" + // doesn't match a button. + function createSelect(txt) { + var options = null; + var el = null; + var cmd = null; + var customSelects = editor.config.customSelects; + var context = null; + var tooltip = ""; + switch (txt) { + case "fontsize": + case "fontname": + case "formatblock": + // the following line retrieves the correct + // configuration option because the variable name + // inside the Config object is named the same as the + // button/select in the toolbar. For instance, if txt + // == "formatblock" we retrieve config.formatblock (or + // a different way to write it in JS is + // config["formatblock"]. + options = editor.config[txt]; + cmd = txt; + break; + default: + // try to fetch it from the list of registered selects + cmd = txt; + var dropdown = customSelects[cmd]; + if (typeof dropdown != "undefined") { + options = dropdown.options; + context = dropdown.context; + if (typeof dropdown.tooltip != "undefined") { + tooltip = dropdown.tooltip; + } + } else { + alert("ERROR [createSelect]:\nCan't find the requested dropdown definition"); + } + break; + } + if (options) { + el = document.createElement("select"); + el.title = tooltip; + var obj = { + name : txt, // field name + element : el, // the UI element (SELECT) + enabled : true, // is it enabled? + text : false, // enabled in text mode? + cmd : cmd, // command ID + state : setButtonStatus, // for changing state + context : context + }; + + HTMLArea.freeLater(obj); + + tb_objects[txt] = obj; + + for (var i in options) { + var op = document.createElement("option"); + op.innerHTML = HTMLArea._lc(i); + op.value = options[i]; + el.appendChild(op); + } + HTMLArea._addEvent(el, "change", function () { + editor._comboSelected(el, txt); + }); + } + return el; + }; // END of function: createSelect + + // appends a new button to toolbar + function createButton(txt) { + // the element that will be created + var el = null; + var btn = null; + switch (txt) { + case "separator": + if(editor.config.flowToolbars) newLine(); + el = document.createElement("div"); + el.className = "separator"; + break; + case "space": + el = document.createElement("div"); + el.className = "space"; + break; + case "linebreak": + newLine(); + return false; + case "textindicator": + el = document.createElement("div"); + el.appendChild(document.createTextNode("A")); + el.className = "indicator"; + el.title = HTMLArea._lc("Current style"); + var obj = { + name : txt, // the button name (i.e. 'bold') + element : el, // the UI element (DIV) + enabled : true, // is it enabled? + active : false, // is it pressed? + text : false, // enabled in text mode? + cmd : "textindicator", // the command ID + state : setButtonStatus // for changing state + }; + + HTMLArea.freeLater(obj); + + tb_objects[txt] = obj; + break; + default: + btn = editor.config.btnList[txt]; + } + if (!el && btn) { + el = document.createElement("a"); + el.style.display = 'block'; + el.href = 'javascript:void(0)'; + el.style.textDecoration = 'none'; + el.title = btn[0]; + el.className = "button"; + // let's just pretend we have a button object, and + // assign all the needed information to it. + var obj = { + name : txt, // the button name (i.e. 'bold') + element : el, // the UI element (DIV) + enabled : true, // is it enabled? + active : false, // is it pressed? + text : btn[2], // enabled in text mode? + cmd : btn[3], // the command ID + state : setButtonStatus, // for changing state + context : btn[4] || null // enabled in a certain context? + }; + + HTMLArea.freeLater(obj); + + tb_objects[txt] = obj; + // handlers to emulate nice flat toolbar buttons + HTMLArea._addEvent(el, "mouseout", function () { + if (obj.enabled) with (HTMLArea) { + //_removeClass(el, "buttonHover"); + _removeClass(el, "buttonActive"); + (obj.active) && _addClass(el, "buttonPressed"); + } + }); + + HTMLArea._addEvent(el, "mousedown", function (ev) { + if (obj.enabled) with (HTMLArea) { + _addClass(el, "buttonActive"); + _removeClass(el, "buttonPressed"); + _stopEvent(is_ie ? window.event : ev); + } + }); + // when clicked, do the following: + HTMLArea._addEvent(el, "click", function (ev) { + if (obj.enabled) with (HTMLArea) { + _removeClass(el, "buttonActive"); + //_removeClass(el, "buttonHover"); + if(HTMLArea.is_gecko) + { + editor.activateEditor(); + } + obj.cmd(editor, obj.name, obj); + _stopEvent(is_ie ? window.event : ev); + } + }); + + var i_contain = HTMLArea.makeBtnImg(btn[1]); + var img = i_contain.firstChild; + el.appendChild(i_contain); + + obj.imgel = img; + obj.swapImage = function(newimg) + { + if(typeof newimg != 'string') + { + img.src = newimg[0]; + img.style.position = 'relative'; + img.style.top = newimg[2] ? ('-' + (18 * (newimg[2] + 1)) + 'px') : '-18px'; + img.style.left = newimg[1] ? ('-' + (18 * (newimg[1] + 1)) + 'px') : '-18px'; + } + else + { + obj.imgel.src = newimg; + img.style.top = '0px'; + img.style.left = '0px'; + } + } + + } else if (!el) { + el = createSelect(txt); + } + + return el; + }; + + var first = true; + for (var i = 0; i < this.config.toolbar.length; ++i) { + if (!first) { + // createButton("linebreak"); + } else { + first = false; + } + if(this.config.toolbar[i] == null) this.config.toolbar[i] = ['separator']; + var group = this.config.toolbar[i]; + + for (var j = 0; j < group.length; ++j) + { + var code = group[j]; + if (/^([IT])\[(.*?)\]/.test(code)) + { + // special case, create text label + var l7ed = RegExp.$1 == "I"; // localized? + var label = RegExp.$2; + if (l7ed) { + label = HTMLArea._lc(label); + } + var tb_cell = document.createElement("td"); + tb_row.appendChild(tb_cell); + tb_cell.className = "label"; + tb_cell.innerHTML = label; + } + else if(typeof code != 'function') + { + var tb_element = createButton(code); + + if (tb_element) + { + var tb_cell = document.createElement("td"); + tb_cell.className = 'toolbarElement'; + tb_row.appendChild(tb_cell); + tb_cell.appendChild(tb_element); + } + else if (tb_element == null) + { + alert("FIXME: Unknown toolbar item: " + code); + } + } + } + } + + if(editor.config.flowToolbars) + { + var brk = document.createElement('div'); + brk.style.height = + brk.style.width = + brk.style.lineHeight = + brk.style.fontSize = '1px'; + brk.style.clear = 'both'; + toolbar.appendChild(brk); + } + + return toolbar; +}; + +use_clone_img = false; +HTMLArea.makeBtnImg = function(imgDef, doc) +{ + if(!doc) doc = document; + + if(!doc._htmlareaImgCache) + { + doc._htmlareaImgCache = { }; + HTMLArea.freeLater(doc._htmlareaImgCache); + } + + var i_contain = null; + if(HTMLArea.is_ie && ((!doc.compatMode) || (doc.compatMode && doc.compatMode == "BackCompat"))) + { + i_contain = doc.createElement('span'); + } + else + { + i_contain = doc.createElement('div'); + i_contain.style.position = 'relative'; + } + + i_contain.style.overflow = 'hidden'; + i_contain.style.width = "18px"; + i_contain.style.height = "18px"; + i_contain.className = 'buttonImageContainer'; + + var img = null; + if(typeof imgDef == 'string') + { + if(doc._htmlareaImgCache[imgDef]) + { + img = doc._htmlareaImgCache[imgDef].cloneNode(); + } + else + { + img = doc.createElement("img"); + img.src = imgDef; + img.style.width = "18px"; + img.style.height = "18px"; + if(use_clone_img) + doc._htmlareaImgCache[imgDef] = img.cloneNode(); + } + } + else + { + if(doc._htmlareaImgCache[imgDef[0]]) + { + img = doc._htmlareaImgCache[imgDef[0]].cloneNode(); + } + else + { + img = doc.createElement("img"); + img.src = imgDef[0]; + img.style.position = 'relative'; + if(use_clone_img) + doc._htmlareaImgCache[imgDef[0]] = img.cloneNode(); + } + img.style.top = imgDef[2] ? ('-' + (18 * (imgDef[2] + 1)) + 'px') : '-18px'; + img.style.left = imgDef[1] ? ('-' + (18 * (imgDef[1] + 1)) + 'px') : '-18px'; + } + i_contain.appendChild(img); + return i_contain; +} + +HTMLArea.prototype._createStatusBar = function() { + var statusbar = document.createElement("div"); + statusbar.className = "statusBar"; + this._statusBar = statusbar; + HTMLArea.freeLater(this, '_statusBar'); + + // statusbar.appendChild(document.createTextNode(HTMLArea._lc("Path") + ": ")); + // creates a holder for the path view + div = document.createElement("span"); + div.className = "statusBarTree"; + div.innerHTML = HTMLArea._lc("Path") + ": "; + this._statusBarTree = div; + HTMLArea.freeLater(this, '_statusBarTree'); + this._statusBar.appendChild(div); + + div = document.createElement("span"); + div.innerHTML = HTMLArea._lc("You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG."); + div.style.display = "none"; + this._statusBarTextMode = div; + HTMLArea.freeLater(this, '_statusBarTextMode'); + this._statusBar.appendChild(div); + + if (!this.config.statusBar) + { + // disable it... + statusbar.style.display = "none"; + } + + return statusbar; +}; + +// Creates the HTMLArea object and replaces the textarea with it. +HTMLArea.prototype.generate = function () +{ + var editor = this; // we'll need "this" in some nested functions + + if(typeof Dialog == 'undefined') + { + HTMLArea._loadback + (_editor_url + 'dialog.js', function() { editor.generate(); } ); + return false; + } + + if(typeof HTMLArea.Dialog == 'undefined') + { + HTMLArea._loadback + (_editor_url + 'inline-dialog.js', function() { editor.generate(); } ); + return false; + } + + if(typeof PopupWin == 'undefined') + { + HTMLArea._loadback + (_editor_url + 'popupwin.js', function() { editor.generate(); } ); + return false; + } + + if(_editor_skin != "") { + var found=false; + var head = document.getElementsByTagName("head")[0]; + var links = document.getElementsByTagName("link"); + for(var i = 0; i= 0;) { + for (var j = toolbar[i].length; --j >= 0; ) { + if (toolbar[i][j]=="popupeditor") { + if(typeof FullScreen == "undefined") { + HTMLArea.loadPlugin("FullScreen", function() { editor.generate(); } ); + return false; + } + editor.registerPlugin('FullScreen'); + } + } + } + + // If this is gecko, set up the paragraph handling now + if(HTMLArea.is_gecko) + { + switch(editor.config.mozParaHandler) + { + case 'best': + { + if(typeof EnterParagraphs == 'undefined') + { + HTMLArea.loadPlugin("EnterParagraphs", function() { editor.generate(); } ); + return false; + } + editor.registerPlugin('EnterParagraphs'); + } + break; + + case 'dirty' : + case 'built-in': + default : + { + // See _editorEvent + } + break; + } + } + + // create the editor framework, yah, table layout I know, but much easier + // to get it working correctly this way, sorry about that, patches welcome. + + this._framework = + { + 'table' :document.createElement('table'), + 'tbody' :document.createElement('tbody'), // IE will not show the table if it doesn't have a tbody! + 'tb_row' :document.createElement('tr'), + 'tb_cell' :document.createElement('td'), // Toolbar + + 'tp_row' :document.createElement('tr'), + 'tp_cell' :this._panels.top.container, // top panel + + 'ler_row' :document.createElement('tr'), + 'lp_cell' :this._panels.left.container, // left panel + 'ed_cell' :document.createElement('td'), // editor + 'rp_cell' :this._panels.right.container, // right panel + + 'bp_row' :document.createElement('tr'), + 'bp_cell' :this._panels.bottom.container,// bottom panel + + 'sb_row' :document.createElement('tr'), + 'sb_cell' :document.createElement('td') // status bar + + } + + HTMLArea.freeLater(this._framework); + + var fw = this._framework; + fw.table.border="0"; + fw.table.cellPadding="0"; + fw.table.cellSpacing="0"; + + fw.tb_row.style.verticalAlign = 'top'; + fw.tp_row.style.verticalAlign = 'top'; + fw.ler_row.style.verticalAlign= 'top'; + fw.bp_row.style.verticalAlign = 'top'; + fw.sb_row.style.verticalAlign = 'top'; + fw.ed_cell.style.position = 'relative'; + + // Put the cells in the rows set col & rowspans + // note that I've set all these so that all panels are showing + // but they will be redone in sizeEditor() depending on which + // panels are shown. It's just here to clarify how the thing + // is put togethor. + fw.tb_row.appendChild(fw.tb_cell); fw.tb_cell.colSpan = 3; + + fw.tp_row.appendChild(fw.tp_cell); fw.tp_cell.colSpan = 3; + + fw.ler_row.appendChild(fw.lp_cell); + fw.ler_row.appendChild(fw.ed_cell); + fw.ler_row.appendChild(fw.rp_cell); + + fw.bp_row.appendChild(fw.bp_cell); fw.bp_cell.colSpan = 3; + + fw.sb_row.appendChild(fw.sb_cell); fw.sb_cell.colSpan = 3; + + // Put the rows in the table body + fw.tbody.appendChild(fw.tb_row); // Toolbar + fw.tbody.appendChild(fw.tp_row); // Left, Top, Right panels + fw.tbody.appendChild(fw.ler_row); // Editor/Textarea + fw.tbody.appendChild(fw.bp_row); // Bottom panel + fw.tbody.appendChild(fw.sb_row); // Statusbar + + // and body in the table + fw.table.appendChild(fw.tbody); + + var htmlarea = this._framework.table; + this._htmlArea = htmlarea; + HTMLArea.freeLater(this, '_htmlArea'); + htmlarea.className = "htmlarea"; + + // create the toolbar and put in the area + var toolbar = this._createToolbar(); + this._framework.tb_cell.appendChild(toolbar); + + // create the IFRAME & add to container + var iframe = document.createElement("iframe"); + iframe.src = _editor_url + editor.config.URIs["blank"]; + this._framework.ed_cell.appendChild(iframe); + this._iframe = iframe; + this._iframe.className = 'xinha_iframe'; + HTMLArea.freeLater(this, '_iframe'); + + // creates & appends the status bar + var statusbar = this._createStatusBar(); + this._framework.sb_cell.appendChild(statusbar); + + // insert Xinha before the textarea. + var textarea = this._textArea; + textarea.parentNode.insertBefore(htmlarea, textarea); + textarea.className = 'xinha_textarea'; + + // extract the textarea and insert it into the htmlarea + HTMLArea.removeFromParent(textarea); + this._framework.ed_cell.appendChild(textarea); + + + // Set up event listeners for saving the iframe content to the textarea + if (textarea.form) + { + // onsubmit get the HTMLArea content and update original textarea. + HTMLArea.prependDom0Event + ( + this._textArea.form, + 'submit', + function() {editor._textArea.value = editor.outwardHtml(editor.getHTML()); return true;} + ); + + var initialTAContent = textarea.value; + + // onreset revert the HTMLArea content to the textarea content + HTMLArea.prependDom0Event + ( + this._textArea.form, + 'reset', + function() { editor.setHTML(editor.inwardHtml(initialTAContent)); editor.updateToolbar(); return true; } + ); + } + + // add a handler for the "back/forward" case -- on body.unload we save + // the HTML content into the original textarea. + HTMLArea.prependDom0Event(window, 'unload', function() {textarea.value = editor.outwardHtml(editor.getHTML()); return true; }); + + // Hide textarea + textarea.style.display = "none"; + + // Initalize size + editor.initSize(); + + // Add an event to initialize the iframe once loaded. + editor._iframeLoadDone = false; + HTMLArea._addEvent + ( + this._iframe, + 'load', + function(e) + { + if(! editor._iframeLoadDone) + { + editor._iframeLoadDone = true; + editor.initIframe(); + } + return true; + } + ); + +}; + + + /** + * Size the editor according to the INITIAL sizing information. + * config.width + * The width may be set via three ways + * auto = the width is inherited from the original textarea + * toolbar = the width is set to be the same size as the toolbar + * = the width is an explicit size (any CSS measurement, eg 100em should be fine) + * + * config.height + * auto = the height is inherited from the original textarea + * = an explicit size measurement (again, CSS measurements) + * + * config.sizeIncludesBars + * true = the tool & status bars will appear inside the width & height confines + * false = the tool & status bars will appear outside the width & height confines + * + */ + + HTMLArea.prototype.initSize = function() + { + var editor = this; + + var width = null; + var height = null; + switch(this.config.width) + { + case 'auto': + { + width = this._initial_ta_size.w; + } + break; + + case 'toolbar': + { + width = this._toolBar.offsetWidth; + } + break; + + default : + { + width = this.config.width; + } + break; + } + + switch(this.config.height) + { + case 'auto': + { + height = this._initial_ta_size.h; + } + break; + + default : + { + height = this.config.height; + } + break; + } + + this.sizeEditor(width, height, this.config.sizeIncludesBars, this.config.sizeIncludesPanels); + + HTMLArea.addDom0Event(window, 'resize', function(e) { editor.sizeEditor(); }); + + this.notifyOn('panel_change',function(){editor.sizeEditor();}); + } + + /** + * Size the editor to a specific size, or just refresh the size (when window resizes for example) + * @param width optional width (CSS specification) + * @param height optional height (CSS specification) + * @param includingBars optional boolean to indicate if the size should include or exclude tool & status bars + */ + + HTMLArea.prototype.sizeEditor = function(width, height, includingBars, includingPanels) + { + + // We need to set the iframe & textarea to 100% height so that the htmlarea + // isn't "pushed out" when we get it's height, so we can change them later. + this._iframe.style.height = '100%'; + this._textArea.style.height = '100%'; + this._iframe.style.width = ''; + this._textArea.style.width = ''; + + if(includingBars != null) this._htmlArea.sizeIncludesToolbars = includingBars; + if(includingPanels != null) this._htmlArea.sizeIncludesPanels = includingPanels; + + if(width != null) + { + this._htmlArea.style.width = width; + if(!this._htmlArea.sizeIncludesPanels) + { + // Need to add some for l & r panels + var panel = this._panels.right; + if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) + { + this._htmlArea.style.width = this._htmlArea.offsetWidth + parseInt(this.config.panel_dimensions.right); + } + + var panel = this._panels.left; + if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) + { + this._htmlArea.style.width = this._htmlArea.offsetWidth + parseInt(this.config.panel_dimensions.left); + } + } + } + + if(height != null) + { + this._htmlArea.style.height = height; + if(!this._htmlArea.sizeIncludesToolbars) + { + // Need to add some for toolbars + this._htmlArea.style.height = this._htmlArea.offsetHeight + this._toolbar.offsetHeight + this._statusBar.offsetHeight; + } + + if(!this._htmlArea.sizeIncludesPanels) + { + // Need to add some for l & r panels + var panel = this._panels.top; + if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) + { + this._htmlArea.style.height = this._htmlArea.offsetHeight + parseInt(this.config.panel_dimensions.top); + } + + var panel = this._panels.bottom; + if(panel.on && panel.panels.length && HTMLArea.hasDisplayedChildren(panel.div)) + { + this._htmlArea.style.height = this._htmlArea.offsetHeight + parseInt(this.config.panel_dimensions.bottom); + } + } + } + + // At this point we have this._htmlArea.style.width & this._htmlArea.style.height + // which are the size for the OUTER editor area, including toolbars and panels + // now we size the INNER area and position stuff in the right places. + width = this._htmlArea.offsetWidth; + height = this._htmlArea.offsetHeight; + + // Set colspan for toolbar, and statusbar, rowspan for left & right panels, and insert panels to be displayed + // into thier rows + var panels = this._panels; + var editor = this; + var col_span = 1; + + function panel_is_alive(pan) + { + if(panels[pan].on && panels[pan].panels.length && HTMLArea.hasDisplayedChildren(panels[pan].container)) + { + panels[pan].container.style.display = ''; + return true; + } + + // Otherwise make sure it's been removed from the framework + else + { + panels[pan].container.style.display='none'; + return false; + } + } + + if(panel_is_alive('left')) + { + col_span += 1; + } + + if(panel_is_alive('top')) + { + // NOP + } + + if(panel_is_alive('right')) + { + col_span += 1; + } + + if(panel_is_alive('bottom')) + { + // NOP + } + + this._framework.tb_cell.colSpan = col_span; + this._framework.tp_cell.colSpan = col_span; + this._framework.bp_cell.colSpan = col_span; + this._framework.sb_cell.colSpan = col_span; + + // Put in the panel rows, top panel goes above editor row + if(!this._framework.tp_row.childNodes.length) + { + HTMLArea.removeFromParent(this._framework.tp_row); + } + else + { + if(!HTMLArea.hasParentNode(this._framework.tp_row)) + { + this._framework.tbody.insertBefore(this._framework.tp_row, this._framework.ler_row); + } + } + + // bp goes after the editor + if(!this._framework.bp_row.childNodes.length) + { + HTMLArea.removeFromParent(this._framework.bp_row); + } + else + { + if(!HTMLArea.hasParentNode(this._framework.bp_row)) + { + this._framework.tbody.insertBefore(this._framework.bp_row, this._framework.ler_row.nextSibling); + } + } + + // finally if the statusbar is on, insert it + if(!this.config.statusBar) + { + HTMLArea.removeFromParent(this._framework.sb_row); + } + else + { + if(!HTMLArea.hasParentNode(this._framework.sb_row)) + { + this._framework.table.appendChild(this._framework.sb_row); + } + } + + // Size and set colspans, link up the framework + this._framework.lp_cell.style.width = this.config.panel_dimensions.left; + this._framework.rp_cell.style.width = this.config.panel_dimensions.right; + this._framework.tp_cell.style.height = this.config.panel_dimensions.top; + this._framework.bp_cell.style.height = this.config.panel_dimensions.bottom; + this._framework.tb_cell.style.height = this._toolBar.offsetHeight + 'px'; + this._framework.sb_cell.style.height = this._statusBar.offsetHeight + 'px'; + + var edcellheight = height - this._toolBar.offsetHeight - this._statusBar.offsetHeight; + if(panel_is_alive('top')) edcellheight -= parseInt(this.config.panel_dimensions.top); + if(panel_is_alive('bottom')) edcellheight -= parseInt(this.config.panel_dimensions.bottom);; + this._iframe.style.height = edcellheight + 'px'; + + var edcellwidth = width; + if(panel_is_alive('left')) edcellwidth -= parseInt(this.config.panel_dimensions.left); + if(panel_is_alive('right')) edcellwidth -= parseInt(this.config.panel_dimensions.right); + this._iframe.style.width = edcellwidth + '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}); + } + + HTMLArea.prototype.addPanel = function(side) + { + var div = document.createElement('div'); + div.side = side; + if(side == 'left' || side == 'right') + { + div.style.width = this.config.panel_dimensions[side]; + } + HTMLArea.addClasses(div, 'panel'); + this._panels[side].panels.push(div); + this._panels[side].div.appendChild(div); + + this.notifyOf('panel_change', {'action':'add','panel':div}); + + return div; + } + + HTMLArea.prototype.removePanel = function(panel) + { + this._panels[panel.side].div.removeChild(panel); + var clean = [ ]; + for(var i = 0; i < this._panels[panel.side].panels.length; i++) + { + if(this._panels[panel.side].panels[i] != panel) + { + clean.push(this._panels[panel.side].panels[i]); + } + } + this._panels[panel.side].panels = clean; + this.notifyOf('panel_change', {'action':'remove','panel':panel}); + } + + HTMLArea.prototype.hidePanel = function(panel) + { + if(panel) + { + panel.style.display = 'none'; + this.notifyOf('panel_change', {'action':'hide','panel':panel}); + } + } + + HTMLArea.prototype.showPanel = function(panel) + { + if(panel) + { + panel.style.display = ''; + this.notifyOf('panel_change', {'action':'show','panel':panel}); + } + } + + HTMLArea.prototype.hidePanels = function(sides) + { + if(typeof sides == 'undefined') + { + sides = ['left','right','top','bottom']; + } + + var reShow = []; + for(var i = 0; i < sides.length;i++) + { + if(this._panels[sides[i]].on) + { + reShow.push(sides[i]); + this._panels[sides[i]].on = false; + } + } + this.notifyOf('panel_change', {'action':'multi_hide','sides':sides}); + } + + HTMLArea.prototype.showPanels = function(sides) + { + if(typeof sides == 'undefined') + { + sides = ['left','right','top','bottom']; + } + + var reHide = []; + for(var i = 0; i < sides.length;i++) + { + if(!this._panels[sides[i]].on) + { + reHide.push(sides[i]); + this._panels[sides[i]].on = true; + } + } + this.notifyOf('panel_change', {'action':'multi_show','sides':sides}); + } + + HTMLArea.objectProperties = function(obj) + { + var props = [ ]; + for(var x in obj) + { + props[props.length] = x; + } + return props; + } + + /* + * EDITOR ACTIVATION NOTES: + * when a page has multiple Xinha editors, ONLY ONE should be activated at any time (this is mostly to + * work around a bug in Mozilla, but also makes some sense). No editor should be activated or focused + * automatically until at least one editor has been activated through user action (by mouse-clicking in + * the editor). + */ + + HTMLArea.prototype.editorIsActivated = function() { + try { + if (HTMLArea.is_gecko) return (this._doc.designMode == 'on'); + else return (this._doc.body.contentEditable); + } catch (e) + { + return false; + } + } + + HTMLArea._someEditorHasBeenActivated = false; + HTMLArea._currentlyActiveEditor = false; + HTMLArea.prototype.activateEditor = function() + { + // We only want ONE editor at a time to be active + if(HTMLArea._currentlyActiveEditor) + { + if(HTMLArea._currentlyActiveEditor == this) return true; + HTMLArea._currentlyActiveEditor.deactivateEditor(); + } + + if (HTMLArea.is_gecko && this._doc.designMode != 'on') + { + try + { + // cannot set design mode if no display + if (this._iframe.style.display == 'none') + { + this._iframe.style.display = ''; + this._doc.designMode = 'on'; + this._iframe.style.display = 'none'; + } + else + { + this._doc.designMode = 'on'; + } + } catch (e) {} + } + else if(!HTMLArea.is_gecko && this._doc.body.contentEditable != true) + { + this._doc.body.contentEditable = true; + } + + // We need to know that at least one editor on the page has been activated + // this is because we will not focus any editor until an editor has been activated + HTMLArea._someEditorHasBeenActivated = true; + HTMLArea._currentlyActiveEditor = this; + + var editor = this; + this.enableToolbar(); + } + + HTMLArea.prototype.deactivateEditor = function() + { + // If the editor isn't active then the user shouldn't use the toolbar + this.disableToolbar(); + + if (HTMLArea.is_gecko && this._doc.designMode != 'off') + { + try {this._doc.designMode = 'off';} catch (e) {} + } + else if(!HTMLArea.is_gecko && this._doc.body.contentEditable != false) + { + this._doc.body.contentEditable = false; + } + + if(HTMLArea._currentlyActiveEditor != this) + { + // We just deactivated an editor that wasn't marked as the currentlyActiveEditor + + return; // I think this should really be an error, there shouldn't be a situation where + // an editor is deactivated without first being activated. but it probably won't + // hurt anything. + } + + HTMLArea._currentlyActiveEditor = false; + } + + HTMLArea.prototype.initIframe = function() + { + this.disableToolbar(); + var doc = null; + var editor = this; + try + { + if (editor._iframe.contentDocument) + { + this._doc = editor._iframe.contentDocument; + } + else + { + this._doc = editor._iframe.contentWindow.document; + } + doc = this._doc; + if (!doc) { // try later + if (HTMLArea.is_gecko) { + setTimeout(function() { editor.initIframe()}, 50); + return false; + } else { + alert("ERROR: IFRAME can't be initialized."); + } + } + } + catch(e) + { // try later + setTimeout(function() { editor.initIframe()}, 50); + } + + HTMLArea.freeLater(this, '_doc'); + + doc.open(); + if (!editor.config.fullPage) { + var html = "\n"; + html += "\n"; + html += "\n"; + if(typeof editor.config.baseHref != 'undefined' && editor.config.baseHref != null) + { + html += "\n"; + } + html += "\n"; + html += "\n"; + + if(editor.config.pageStyle) + { + html += ""; + } + + if(typeof editor.config.pageStyleSheets !== 'undefined') + { + for(style_i = 0; style_i < editor.config.pageStyleSheets.length; style_i++) + { + if(editor.config.pageStyleSheets[style_i].length > 0) + html += ""; + //html += "\n"; + } + } + html += "\n"; + html += "\n"; + html += editor.inwardHtml(editor._textArea.value); + html += "\n"; + html += ""; + } else { + var html = editor.inwardHtml(editor._textArea.value); + if (html.match(HTMLArea.RE_doctype)) { + editor.setDoctype(RegExp.$1); + html = html.replace(HTMLArea.RE_doctype, ""); + } + } + doc.write(html); + doc.close(); + + // if we have multiple editors some bug in Mozilla makes some lose editing ability + HTMLArea._addEvents + ( + doc, + ["mousedown"], + function() { editor.activateEditor(); return true; } + ); + + + // intercept some events; for updating the toolbar & keyboard handlers + HTMLArea._addEvents + (doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"], + function (event) { + return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event); + }); + + // check if any plugins have registered refresh handlers + for (var i in editor.plugins) { + var plugin = editor.plugins[i].instance; + HTMLArea.refreshPlugin(plugin); + } + + // specific editor initialization + if(typeof editor._onGenerate == "function") { + editor._onGenerate(); + } + } + +// Switches editor mode; parameter can be "textmode" or "wysiwyg". If no +// parameter was passed this function toggles between modes. +HTMLArea.prototype.setMode = function(mode) { + if (typeof mode == "undefined") { + mode = ((this._editMode == "textmode") ? "wysiwyg" : "textmode"); + } + switch (mode) { + case "textmode": + { + var html = this.outwardHtml(this.getHTML()); + this.setHTML(html); + + // Hide the iframe + 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.notifyOf('modechange', {'mode':'text'}); + break; + } + + case "wysiwyg": + { + var html = this.inwardHtml(this.getHTML()); + this.deactivateEditor(); + this.setHTML(html); + 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.notifyOf('modechange', {'mode':'wysiwyg'}); + break; + } + + default: + { + alert("Mode <" + mode + "> not defined!"); + return false; + } + } + this._editMode = mode; + + for (var i in this.plugins) { + var plugin = this.plugins[i].instance; + if (typeof plugin.onMode == "function") plugin.onMode(mode); + } +}; + +HTMLArea.prototype.setFullHTML = function(html) { + var save_multiline = RegExp.multiline; + RegExp.multiline = true; + if (html.match(HTMLArea.RE_doctype)) { + this.setDoctype(RegExp.$1); + html = html.replace(HTMLArea.RE_doctype, ""); + } + RegExp.multiline = save_multiline; + if (!HTMLArea.is_ie) { + if (html.match(HTMLArea.RE_head)) + this._doc.getElementsByTagName("head")[0].innerHTML = RegExp.$1; + if (html.match(HTMLArea.RE_body)) + this._doc.getElementsByTagName("body")[0].innerHTML = RegExp.$1; + } else { + var reac = this.editorIsActivated(); + if(reac) this.deactivateEditor(); + var html_re = /((.|\n)*?)<\/html>/i; + html = html.replace(html_re, "$1"); + this._doc.open(); + this._doc.write(html); + this._doc.close(); + if(reac) this.activateEditor(); + return true; + } +}; + +/*************************************************** + * Category: PLUGINS + ***************************************************/ + +// Create the specified plugin and register it with this HTMLArea +// return the plugin created to allow refresh when necessary +HTMLArea.prototype.registerPlugin = function() { + var plugin = arguments[0]; + + // We can only register plugins that have been succesfully loaded + if + ( + plugin == null + || typeof plugin == 'undefined' + || (typeof plugin == 'string' && eval('typeof ' + plugin) == 'undefined') + ) return false; + + var args = []; + for (var i = 1; i < arguments.length; ++i) + args.push(arguments[i]); + return this.registerPlugin2(plugin, args); +}; + +// this is the variant of the function above where the plugin arguments are +// already packed in an array. Externally, it should be only used in the +// full-screen editor code, in order to initialize plugins with the same +// parameters as in the opener window. +HTMLArea.prototype.registerPlugin2 = function(plugin, args) { + if (typeof plugin == "string") + plugin = eval(plugin); + if (typeof plugin == "undefined") { + /* FIXME: This should never happen. But why does it do? */ + return false; + } + var obj = new plugin(this, args); + if (obj) { + var clone = {}; + var info = plugin._pluginInfo; + for (var i in info) + clone[i] = info[i]; + clone.instance = obj; + clone.args = args; + this.plugins[plugin._pluginInfo.name] = clone; + return obj; + } else + alert("Can't register plugin " + plugin.toString() + "."); +}; + +// static function that loads the required plugin and lang file, based on the +// language loaded already for HTMLArea. You better make sure that the plugin +// _has_ that language, otherwise shit might happen ;-) +HTMLArea.getPluginDir = function(pluginName) { + return _editor_url + "plugins/" + pluginName; +}; + +HTMLArea.loadPlugin = function(pluginName, callback) { + // Might already be loaded + if(eval('typeof ' + pluginName) != 'undefined') + { + if(callback) + { + callback(pluginName); + } + return true; + } + + var dir = this.getPluginDir(pluginName); + var plugin = pluginName.replace(/([a-z])([A-Z])([a-z])/g, + function (str, l1, l2, l3) { + return l1 + "-" + l2.toLowerCase() + l3; + }).toLowerCase() + ".js"; + var plugin_file = dir + "/" + plugin; + + if(callback) + { + HTMLArea._loadback(plugin_file, function() { callback(pluginName); }); + } + else + { + document.write(""); + } + return false; +}; + +HTMLArea._pluginLoadStatus = { }; +HTMLArea.loadPlugins = function(plugins, callbackIfNotReady) +{ + // Rip the ones that are loaded and look for ones that have failed + var retVal = true; + var nuPlugins = HTMLArea.cloneObject(plugins); + while(nuPlugins.length) + { + var p = nuPlugins.pop(); + if(typeof HTMLArea._pluginLoadStatus[p] == 'undefined') + { + // Load it + HTMLArea._pluginLoadStatus[p] = 'loading'; + HTMLArea.loadPlugin(p, + function(plugin) + { + if(eval('typeof ' + plugin) != 'undefined') + { + HTMLArea._pluginLoadStatus[plugin] = 'ready'; + } + else + { + // Actually, this won't happen, because if the script fails + // it will throw an exception preventing the callback from + // running. This will leave it always in the "loading" state + // unfortunatly that means we can't fail plugins gracefully + // by just skipping them. + HTMLArea._pluginLoadStatus[plugin] = 'failed'; + } + } + ); + retVal = false; + } + else + { + switch(HTMLArea._pluginLoadStatus[p]) + { + case 'failed': + case 'ready' : + break; + + case 'loading': + default : + retVal = false; + break; + } + } + } + + if(retVal) return true; // All done, just return + + // Waiting on plugins to load, return false now and come back a bit later + // if we have to callback + if(callbackIfNotReady) + { + setTimeout(function() { if(HTMLArea.loadPlugins(plugins, callbackIfNotReady)) callbackIfNotReady(); }, 150); + } + return retVal; +} + +// refresh plugin by calling onGenerate or onGenerateOnce method. +HTMLArea.refreshPlugin = function(plugin) { + if (typeof plugin.onGenerate == "function") + plugin.onGenerate(); + if (typeof plugin.onGenerateOnce == "function") { + plugin.onGenerateOnce(); + plugin.onGenerateOnce = null; + } +}; + +HTMLArea.loadStyle = function(style, plugin) { + var url = _editor_url || ''; + if (typeof plugin != "undefined") { + url += "plugins/" + plugin + "/"; + } + url += style; + if (/^\//.test(style)) + url = style; + var head = document.getElementsByTagName("head")[0]; + var link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = url; + head.appendChild(link); + //document.write(""); +}; +HTMLArea.loadStyle(typeof _editor_css == "string" ? _editor_css : "htmlarea.css"); + +/*************************************************** + * Category: EDITOR UTILITIES + ***************************************************/ + +HTMLArea.prototype.debugTree = function() { + var ta = document.createElement("textarea"); + ta.style.width = "100%"; + ta.style.height = "20em"; + ta.value = ""; + function debug(indent, str) { + for (; --indent >= 0;) + ta.value += " "; + ta.value += str + "\n"; + }; + function _dt(root, level) { + var tag = root.tagName.toLowerCase(), i; + var ns = HTMLArea.is_ie ? root.scopeName : root.prefix; + debug(level, "- " + tag + " [" + ns + "]"); + for (i = root.firstChild; i; i = i.nextSibling) + if (i.nodeType == 1) + _dt(i, level + 2); + }; + _dt(this._doc.body, 0); + document.body.appendChild(ta); +}; + +HTMLArea.getInnerText = function(el) { + var txt = '', i; + for (i = el.firstChild; i; i = i.nextSibling) { + if (i.nodeType == 3) + txt += i.data; + else if (i.nodeType == 1) + txt += HTMLArea.getInnerText(i); + } + return txt; +}; + +HTMLArea.prototype._wordClean = function() { + var + editor = this, + stats = { + empty_tags : 0, + mso_class : 0, + mso_style : 0, + mso_xmlel : 0, + orig_len : this._doc.body.innerHTML.length, + T : (new Date()).getTime() + }, + stats_txt = { + empty_tags : "Empty tags removed: ", + mso_class : "MSO class names removed: ", + mso_style : "MSO inline style removed: ", + mso_xmlel : "MSO XML elements stripped: " + }; + function showStats() { + var txt = "HTMLArea word cleaner stats: \n\n"; + for (var i in stats) + if (stats_txt[i]) + txt += stats_txt[i] + stats[i] + "\n"; + txt += "\nInitial document length: " + stats.orig_len + "\n"; + txt += "Final document length: " + editor._doc.body.innerHTML.length + "\n"; + txt += "Clean-up took " + (((new Date()).getTime() - stats.T) / 1000) + " seconds"; + alert(txt); + }; + function clearClass(node) { + var newc = node.className.replace(/(^|\s)mso.*?(\s|$)/ig, ' '); + if (newc != node.className) { + node.className = newc; + if (!/\S/.test(node.className)) { + node.removeAttribute("className"); + ++stats.mso_class; + } + } + }; + function clearStyle(node) { + var declarations = node.style.cssText.split(/\s*;\s*/); + for (var i = declarations.length; --i >= 0;) + if (/^mso|^tab-stops/i.test(declarations[i]) || + /^margin\s*:\s*0..\s+0..\s+0../i.test(declarations[i])) { + ++stats.mso_style; + declarations.splice(i, 1); + } + node.style.cssText = declarations.join("; "); + }; + function stripTag(el) { + if (HTMLArea.is_ie) + el.outerHTML = HTMLArea.htmlEncode(el.innerText); + else { + var txt = document.createTextNode(HTMLArea.getInnerText(el)); + el.parentNode.insertBefore(txt, el); + HTMLArea.removeFromParent(el); + } + ++stats.mso_xmlel; + }; + function checkEmpty(el) { + if (/^(a|span|b|strong|i|em|font)$/i.test(el.tagName) && + !el.firstChild) { + HTMLArea.removeFromParent(el); + ++stats.empty_tags; + } + }; + function parseTree(root) { + var tag = root.tagName.toLowerCase(), i, next; + if ((HTMLArea.is_ie && root.scopeName != 'HTML') || (!HTMLArea.is_ie && /:/.test(tag))) { + stripTag(root); + return false; + } else { + clearClass(root); + clearStyle(root); + for (i = root.firstChild; i; i = next) { + next = i.nextSibling; + if (i.nodeType == 1 && parseTree(i)) + checkEmpty(i); + } + } + return true; + }; + parseTree(this._doc.body); + // showStats(); + // this.debugTree(); + // this.setHTML(this.getHTML()); + // this.setHTML(this.getInnerHTML()); + // this.forceRedraw(); + this.updateToolbar(); +}; + +HTMLArea.prototype._clearFonts = function() { + var D = this.getInnerHTML(); + + if(confirm('Would you like to clear font typefaces?')) + { + D = D.replace(/face="[^"]*"/gi, ''); + D = D.replace(/font-family:[^;}"']+;?/gi, ''); + } + + if(confirm('Would you like to clear font sizes?')) + { + D = D.replace(/size="[^"]*"/gi, ''); + D = D.replace(/font-size:[^;}"']+;?/gi, ''); + } + + if(confirm('Would you like to clear font colours?')) + { + D = D.replace(/color="[^"]*"/gi, ''); + D = D.replace(/([^-])color:[^;}"']+;?/gi, '$1'); + } + + D = D.replace(/(style|class)="\s*"/gi, ''); + D = D.replace(/<(font|span)\s*>/gi, ''); + this.setHTML(D); + this.updateToolbar(); +} + +HTMLArea.prototype._splitBlock = function() +{ + this._doc.execCommand('formatblock', false, '

'); +} + +HTMLArea.prototype.forceRedraw = function() { + this._doc.body.style.visibility = "hidden"; + this._doc.body.style.visibility = "visible"; + // this._doc.body.innerHTML = this.getInnerHTML(); +}; + +// focuses the iframe window. returns a reference to the editor document. +HTMLArea.prototype.focusEditor = function() { + switch (this._editMode) { + // notice the try { ... } catch block to avoid some rare exceptions in FireFox + // (perhaps also in other Gecko browsers). Manual focus by user is required in + // case of an error. Somebody has an idea? + case "wysiwyg" : + try + { + // We don't want to focus the field unless at least one field has been activated. + if(HTMLArea._someEditorHasBeenActivated) + { + this.activateEditor(); // Ensure *this* editor is activated + this._iframe.contentWindow.focus(); // and focus it + } + } catch (e) {} break; + case "textmode": try { this._textArea.focus() } catch (e) {} break; + default : alert("ERROR: mode " + this._editMode + " is not defined"); + } + return this._doc; +}; + +// takes a snapshot of the current text (for undo) +HTMLArea.prototype._undoTakeSnapshot = function() { + ++this._undoPos; + if (this._undoPos >= this.config.undoSteps) { + // remove the first element + this._undoQueue.shift(); + --this._undoPos; + } + // use the fasted method (getInnerHTML); + var take = true; + var txt = this.getInnerHTML(); + if (this._undoPos > 0) + take = (this._undoQueue[this._undoPos - 1] != txt); + if (take) { + this._undoQueue[this._undoPos] = txt; + } else { + this._undoPos--; + } +}; + +HTMLArea.prototype.undo = function() { + if (this._undoPos > 0) { + var txt = this._undoQueue[--this._undoPos]; + if (txt) this.setHTML(txt); + else ++this._undoPos; + } +}; + +HTMLArea.prototype.redo = function() { + if (this._undoPos < this._undoQueue.length - 1) { + var txt = this._undoQueue[++this._undoPos]; + if (txt) this.setHTML(txt); + else --this._undoPos; + } +}; + +HTMLArea.prototype.disableToolbar = function(except) +{ + if(this._timerToolbar) clearTimeout(this._timerToolbar); + if(typeof except == 'undefined') + { + except = [ ]; + } + else if(typeof except != 'object') + { + except = [except]; + } + + for (var i in this._toolbarObjects) + { + var btn = this._toolbarObjects[i]; + if(except.contains(i)) + { + continue; + } + btn.state("enabled", false); + } +} + +HTMLArea.prototype.enableToolbar = function() +{ + this.updateToolbar(); +} + +if(!Array.prototype.contains) +{ + Array.prototype.contains = function(needle) + { + var haystack = this; + for(var i = 0; i < haystack.length; i++) + { + if(needle == haystack[i]) return true; + } + + return false; + } +} + +if(!Array.prototype.indexOf) +{ + Array.prototype.indexOf = function(needle) + { + var haystack = this; + for(var i = 0; i < haystack.length; i++) + { + if(needle == haystack[i]) return i; + } + + return null; + } +} + + +// updates enabled/disable/active state of the toolbar elements +HTMLArea.prototype.updateToolbar = function(noStatus) { + var doc = this._doc; + var text = (this._editMode == "textmode"); + var ancestors = null; + if (!text) { + ancestors = this.getAllAncestors(); + if (this.config.statusBar && !noStatus) { + this._statusBarTree.innerHTML = HTMLArea._lc("Path") + ": "; // clear + for (var i = ancestors.length; --i >= 0;) { + var el = ancestors[i]; + if (!el) { + // hell knows why we get here; this + // could be a classic example of why + // it's good to check for conditions + // that are impossible to happen ;-) + continue; + } + var a = document.createElement("a"); + a.href = "javascript:void(0)"; + a.el = el; + a.editor = this; + HTMLArea.addDom0Event(a, 'click', function() { + this.blur(); + this.editor.selectNodeContents(this.el); + this.editor.updateToolbar(true); + return false; + }); + HTMLArea.addDom0Event(a, 'contextmenu', function() { + // TODO: add context menu here + 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(); + 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(0xbb))); + } + } + } + } + + for (var i in this._toolbarObjects) { + var btn = this._toolbarObjects[i]; + var cmd = i; + var inContext = true; + 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]) { + // the impossible really happens. + continue; + } + if (match || (ancestors[k].tagName.toLowerCase() == context)) { + inContext = true; + for (var ka = 0; ka < attrs.length; ++ka) { + if (!eval("ancestors[k]." + attrs[ka])) { + inContext = false; + break; + } + } + if (inContext) { + break; + } + } + } + } + btn.state("enabled", (!text || btn.text) && inContext); + if (typeof cmd == "function") { + continue; + } + // look-it-up in the custom dropdown boxes + 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; + } + + // HACK -- retrieve the config option for this + // combo box. We rely on the fact that the + // variable in config has the same name as + // button name in the toolbar. + var options = this.config[cmd]; + var k = 0; + for (var j in options) + { + // FIXME: the following line is scary. + if ((j.toLowerCase() == value) || (options[j].substr(0, value.length).toLowerCase() == value)) + { + btn.element.selectedIndex = k; + throw "ok"; + } + ++k; + } + btn.element.selectedIndex = 0; + } catch(e) {}; + } + break; + + // It's better to search for the format block by tag name from the + // current selection upwards, because IE has a tendancy to return + // things like 'heading 1' for 'h1', which breaks things if you want + // to call your heading blocks 'header 1'. Stupid MS. + case "formatblock" : + { + var blocks = [ ]; + for(var i in this.config['formatblock']) + { + blocks[blocks.length] = this.config['formatblock'][i]; + } + + 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 {with (btn.element.style) { + backgroundColor = HTMLArea._makeColor( + doc.queryCommandValue(HTMLArea.is_ie ? "backcolor" : "hilitecolor")); + if (/transparent/i.test(backgroundColor)) { + // Mozilla + backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor")); + } + color = HTMLArea._makeColor(doc.queryCommandValue("forecolor")); + fontFamily = doc.queryCommandValue("fontname"); + fontWeight = doc.queryCommandState("bold") ? "bold" : "normal"; + fontStyle = doc.queryCommandState("italic") ? "italic" : "normal"; + }} catch (e) { + // alert(e + "\n\n" + cmd); + } + } + break; + case "htmlmode": btn.state("active", text); break; + case "lefttoright": + case "righttoleft": + var el = this.getParentElement(); + while (el && !HTMLArea.isBlockElement(el)) + el = el.parentNode; + if (el) + btn.state("active", (el.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 (e) {} + } + } + // take undo snapshots + if (this._customUndo && !this._timerUndo) { + this._undoTakeSnapshot(); + var editor = this; + this._timerUndo = setTimeout(function() { + editor._timerUndo = null; + }, this.config.undoTimeout); + } + + // Insert a space in certain locations, this is just to make editing a little + // easier (to "get out of" tags), it's not essential. + // TODO: Make this work for IE? + // TODO: Perhaps should use a plain space character, I'm not sure. + // OK, I've disabled this temporarily, to be honest, I can't rightly remember what the + // original problem was I was trying to solve with it. I think perhaps that EnterParagraphs + // might solve the problem, whatever the hell it was. I'm going senile, I'm sure. + if(0 && HTMLArea.is_gecko) + { + var s = this._getSelection(); + // If the last character in the last text node of the parent tag + // and the parent tag is not a block tag + if(s && s.isCollapsed && s.anchorNode + && s.anchorNode.parentNode.tagName.toLowerCase() != 'body' + && s.anchorNode.nodeType == 3 && s.anchorOffset == s.anchorNode.length + && ! + ( s.anchorNode.parentNode.nextSibling + && s.anchorNode.parentNode.nextSibling.nodeType == 3 + ) + && !HTMLArea.isBlockElement(s.anchorNode.parentNode) + ) + { + // Insert hair-width-space after the close tag if there isn't another text node on the other side + // It could also work with zero-width-space (\u200B) but I don't like it so much. + // Perhaps this won't work well in various character sets and we should use plain space (20)? + try + { + s.anchorNode.parentNode.parentNode.insertBefore + (this._doc.createTextNode('\t'), s.anchorNode.parentNode.nextSibling); + } + catch(e) + { + // Disregard + } + } + } + + // check if any plugins have registered refresh handlers + for (var i in this.plugins) { + var plugin = this.plugins[i].instance; + if (typeof plugin.onUpdateToolbar == "function") + plugin.onUpdateToolbar(); + } + + +} + +/** Returns a node after which we can insert other nodes, in the current + * selection. The selection is removed. It splits a text node, if needed. + */ +HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) { + if (!HTMLArea.is_ie) { + var sel = this._getSelection(); + var range = this._createRange(sel); + // remove the current selection + sel.removeAllRanges(); + range.deleteContents(); + var node = range.startContainer; + var pos = range.startOffset; + switch (node.nodeType) { + case 3: // Node.TEXT_NODE + // we have to split it at the caret position. + if (toBeInserted.nodeType == 3) { + // do optimized insertion + node.insertData(pos, toBeInserted.data); + range = this._createRange(); + range.setEnd(node, pos + toBeInserted.length); + range.setStart(node, pos + toBeInserted.length); + sel.addRange(range); + } else { + node = node.splitText(pos); + var selnode = toBeInserted; + if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { + selnode = selnode.firstChild; + } + node.parentNode.insertBefore(toBeInserted, node); + this.selectNodeContents(selnode); + this.updateToolbar(); + } + break; + case 1: // Node.ELEMENT_NODE + var selnode = toBeInserted; + if (toBeInserted.nodeType == 11 /* Node.DOCUMENT_FRAGMENT_NODE */) { + selnode = selnode.firstChild; + } + node.insertBefore(toBeInserted, node.childNodes[pos]); + this.selectNodeContents(selnode); + this.updateToolbar(); + break; + } + } else { + return null; // this function not yet used for IE + } +}; + +// Returns the deepest node that contains both endpoints of the selection. +HTMLArea.prototype.getParentElement = function(sel) { + if(typeof sel == 'undefined') + { + sel = this._getSelection(); + } + var range = this._createRange(sel); + if (HTMLArea.is_ie) { + switch (sel.type) { + case "Text": + case "None": + // It seems that even for selection of type "None", + // there _is_ a parent element and it's value is not + // only correct, but very important to us. MSIE is + // certainly the buggiest browser in the world and I + // wonder, God, how can Earth stand it? + return range.parentElement(); + case "Control": + return range.item(0); + default: + return this._doc.body; + } + } else try { + var p = range.commonAncestorContainer; + if (!range.collapsed && range.startContainer == range.endContainer && + range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes()) + p = range.startContainer.childNodes[range.startOffset]; + /* + alert(range.startContainer + ":" + range.startOffset + "\n" + + range.endContainer + ":" + range.endOffset); + */ + while (p.nodeType == 3) { + p = p.parentNode; + } + return p; + } catch (e) { + return null; + } +}; + +// Returns an array with all the ancestor nodes of the selection. +HTMLArea.prototype.getAllAncestors = function() { + var p = this.getParentElement(); + var a = []; + while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) { + a.push(p); + p = p.parentNode; + } + a.push(this._doc.body); + return a; +}; + +// Returns the deepest ancestor of the selection that is of the current type +HTMLArea.prototype._getFirstAncestor = function(sel, types) +{ + var prnt = this._activeElement(sel); + if(prnt == null) + { + try + { + prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); + } + catch(e) + { + return null; + } + } + + if(typeof types == 'string') + { + types = [types]; + } + + while(prnt) + { + if(prnt.nodeType == 1) + { + if(types == null) return prnt; + if(types.contains(prnt.tagName.toLowerCase())) + { + + return prnt; + } + if(prnt.tagName.toLowerCase() == 'body') break; + if(prnt.tagName.toLowerCase() == 'table') break; + } + prnt = prnt.parentNode; + } + + return null; +} + +/** + * Returns the selected element, if any. That is, + * the element that you have last selected in the "path" + * at the bottom of the editor, or a "control" (eg image) + * + * @returns null | element + */ +HTMLArea.prototype._activeElement = function(sel) +{ + if(sel == null) return null; + if(this._selectionEmpty(sel)) return null; + + if(HTMLArea.is_ie) + { + if(sel.type.toLowerCase() == "control") + { + return sel.createRange().item(0); + } + else + { + + // If it's not a control, then we need to see if + // the selection is the _entire_ text of a parent node + // (this happens when a node is clicked in the tree) + var range = sel.createRange(); + var p_elm = this.getParentElement(sel); + if(p_elm.innerHTML == range.htmlText) + { + return p_elm; + } + /* + if(p_elm) + { + var p_rng = this._doc.body.createTextRange(); + p_rng.moveToElementText(p_elm); + if(p_rng.isEqual(range)) + { + return p_elm; + } + } + + if(range.parentElement()) + { + var prnt_range = this._doc.body.createTextRange(); + prnt_range.moveToElementText(range.parentElement()); + if(prnt_range.isEqual(range)) + { + return range.parentElement(); + } + } + */ + return null; + } + } + else + { + // For Mozilla we just see if the selection is not collapsed (something is selected) + // and that the anchor (start of selection) is an element. This might not be totally + // correct, we possibly should do a simlar check to IE? + if(! sel.isCollapsed) + { + if(sel.anchorNode.childNodes.length > sel.anchorOffset && sel.anchorNode.childNodes[sel.anchorOffset].nodeType == 1) + { + return sel.anchorNode.childNodes[sel.anchorOffset]; + } + else if(sel.anchorNode.nodeType == 1) + { + return sel.anchorNode; + } + else + { + return sel.anchorNode.parentNode; + } + } + return null; + } +} + + +HTMLArea.prototype._selectionEmpty = function(sel) +{ + if(!sel) return true; + + if(HTMLArea.is_ie) + { + return this._createRange(sel).htmlText == ''; + } + else if(typeof sel.isCollapsed != 'undefined') + { + return sel.isCollapsed; + } + + return true; +} + +HTMLArea.prototype._getAncestorBlock = function(sel) +{ + // Scan upwards to find a block level element that we can change or apply to + var prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement : this._createRange(sel).commonAncestorContainer); + + while(prnt && (prnt.nodeType == 1)) + { + switch(prnt.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' : + // Block Element + return prnt; + + case 'body' : + case 'noframes' : + case 'dd' : + case 'li' : + case 'th' : + case 'td' : + case 'noscript' : + // Halting element (stop searching) + return null; + + default : + // Keep lookin + break; + } + } + + return null; +} + +HTMLArea.prototype._createImplicitBlock = function(type) +{ + // expand it until we reach a block element in either direction + // then wrap the selection in a block and return + var sel = this._getSelection(); + if(HTMLArea.is_ie) + { + sel.empty(); + } + else + { + sel.collapseToStart(); + } + + var rng = this._createRange(sel); + + // Expand UP + + // Expand DN +} + +HTMLArea.prototype._formatBlock = function(block_format) +{ + var ancestors = this.getAllAncestors(); + var apply_to = null; + + // Block format can be a tag followed with class defs + // eg div.blue.left + var target_tag = null; + var target_classNames = [ ]; + + if(block_format.indexOf('.') >= 0) + { + target_tag = block_format.substr(0, block_format.indexOf('.')).toLowerCase();; + + target_classNames = block_format.substr(block_format.indexOf('.'), block_format.length - block_format.indexOf('.')).replace(/\./g, '').replace(/^\s*/, '').replace(/\s*$/, '').split(' '); + } + else + { + target_tag = block_format.toLowerCase(); + } + + var sel = this._getSelection(); + var rng = this._createRange(sel); + var apply_to = null; + + if(HTMLArea.is_gecko) + { + if(sel.isCollapsed) + { + // With no selection we want to apply to the whole contents of the ancestor block + apply_to = this._getAncestorBlock(sel); + if(apply_to == null) + { + // If there wasn't an ancestor, make one. + apply_to = this._createImplicitBlock(sel, target_tag); + } + } + else + { + // With a selection it's more tricky + switch(target_tag) + { + + case 'h1' : + case 'h2' : + case 'h3' : + case 'h4' : + case 'h5' : + case 'h6' : + case 'h7' : + apply_to = [ ]; + var search_tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']; + for(var y = 0; y < search_tags.length; y++) + { + var headers = this._doc.getElementsByTagName(search_tag[y]); + for(var x = 0; x < headers.length; x++) + { + if(sel.containsNode(headers[x])) + { + apply_to[apply_to.length] = headers[x]; + } + } + } + if(apply_to.length > 0) break; + // If there wern't any in the selection drop through + case 'div' : + apply_to = this._doc.createElement(target_tag); + apply_to.appendChild(rng.extractContents()); + rng.insertNode(apply_to); + break; + + case 'p' : + case 'center' : + case 'pre' : + case 'ins' : + case 'del' : + case 'blockquote' : + case 'address' : + apply_to = [ ]; + var paras = this._doc.getElementsByTagName(target_tag); + for(var x = 0; x < paras.length; x++) + { + if(sel.containsNode(paras[x])) + { + apply_to[apply_to.length] = paras[x]; + } + } + + if(apply_to.length == 0) + { + sel.collapseToStart(); + return this._formatBlock(block_format); + } + break; + } + } + } + +} + +// Selects the contents inside the given node +HTMLArea.prototype.selectNodeContents = function(node, pos) { + this.focusEditor(); + this.forceRedraw(); + var range; + var collapsed = typeof pos == "undefined" ? true : false; + if (HTMLArea.is_ie) { + // Tables and Images get selected as "objects" rather than the text contents + if(collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img|input|select|textarea/)) + { + range = this._doc.body.createControlRange(); + range.add(node); + } + else + { + range = this._doc.body.createTextRange(); + range.moveToElementText(node); + //(collapsed) && range.collapse(pos); + } + range.select(); + } else { + var sel = this._getSelection(); + range = this._doc.createRange(); + // Tables and Images get selected as "objects" rather than the text contents + if(collapsed && node.tagName && node.tagName.toLowerCase().match(/table|img|input|textarea|select/)) + { + range.selectNode(node); + } + else + { + range.selectNodeContents(node); + //(collapsed) && range.collapse(pos); + } + sel.removeAllRanges(); + sel.addRange(range); + } +}; + +/** Call this function to insert HTML code at the current position. It deletes + * the selection, if any. + */ +HTMLArea.prototype.insertHTML = function(html) { + var sel = this._getSelection(); + var range = this._createRange(sel); + if (HTMLArea.is_ie) { + range.pasteHTML(html); + } else { + // construct a new document fragment with the given HTML + var fragment = this._doc.createDocumentFragment(); + var div = this._doc.createElement("div"); + div.innerHTML = html; + while (div.firstChild) { + // the following call also removes the node from div + fragment.appendChild(div.firstChild); + } + // this also removes the selection + var node = this.insertNodeAtSelection(fragment); + } +}; + +/** + * Call this function to surround the existing HTML code in the selection with + * your tags. FIXME: buggy! This function will be deprecated "soon". + */ +HTMLArea.prototype.surroundHTML = function(startTag, endTag) { + var html = this.getSelectedHTML(); + // the following also deletes the selection + this.insertHTML(startTag + html + endTag); +}; + +/// Retrieve the selected block +HTMLArea.prototype.getSelectedHTML = function() { + var sel = this._getSelection(); + var range = this._createRange(sel); + var existing = null; + if (HTMLArea.is_ie) { + existing = range.htmlText; + } else { + existing = HTMLArea.getHTML(range.cloneContents(), false, this); + } + return existing; +}; + +/// Return true if we have some selection +HTMLArea.prototype.hasSelectedText = function() { + // FIXME: come _on_ mishoo, you can do better than this ;-) + return this.getSelectedHTML() != ''; +}; + +HTMLArea.prototype._createLink = function(link) { + var editor = this; + var outparam = null; + if (typeof link == "undefined") { + link = this.getParentElement(); + if (link) { + if (/^img$/i.test(link.tagName)) + link = link.parentNode; + if (!/^a$/i.test(link.tagName)) + link = null; + } + } + if (!link) { + var sel = editor._getSelection(); + var range = editor._createRange(sel); + var compare = 0; + if (HTMLArea.is_ie) { + if(sel.type == "Control") + { + compare = range.length; + } + else + { + compare = range.compareEndPoints("StartToEnd", range); + } + } else { + compare = range.compareBoundaryPoints(range.START_TO_END, range); + } + if (compare == 0) { + alert(HTMLArea._lc("You need to select some text before creating a link")); + return; + } + outparam = { + f_href : '', + f_title : '', + f_target : '', + f_usetarget : editor.config.makeLinkShowsTarget + }; + } else + outparam = { + f_href : HTMLArea.is_ie ? editor.stripBaseURL(link.href) : link.getAttribute("href"), + f_title : link.title, + f_target : link.target, + f_usetarget : editor.config.makeLinkShowsTarget + }; + this._popupDialog(editor.config.URIs["link"], function(param) { + if (!param) + return false; + var a = link; + if (!a) try { + editor._doc.execCommand("createlink", false, param.f_href); + a = editor.getParentElement(); + var sel = editor._getSelection(); + var range = editor._createRange(sel); + if (!HTMLArea.is_ie) { + a = range.startContainer; + if (!/^a$/i.test(a.tagName)) { + a = a.nextSibling; + if (a == null) + a = range.startContainer.parentNode; + } + } + } catch(e) {} + else { + var href = param.f_href.trim(); + editor.selectNodeContents(a); + if (href == "") { + editor._doc.execCommand("unlink", false, null); + editor.updateToolbar(); + return false; + } + else { + a.href = href; + } + } + if (!(a && /^a$/i.test(a.tagName))) + return false; + a.target = param.f_target.trim(); + a.title = param.f_title.trim(); + editor.selectNodeContents(a); + editor.updateToolbar(); + }, outparam); +}; + +// Called when the user clicks on "InsertImage" button. If an image is already +// there, it will just modify it's properties. +HTMLArea.prototype._insertImage = function(image) { + var editor = this; // for nested functions + var outparam = null; + if (typeof image == "undefined") { + image = this.getParentElement(); + if (image && !/^img$/i.test(image.tagName)) + image = null; + } + if (image) outparam = { + f_base : editor.config.baseHref, + f_url : HTMLArea.is_ie ? editor.stripBaseURL(image.src) : image.getAttribute("src"), + f_alt : image.alt, + f_border : image.border, + f_align : image.align, + f_vert : image.vspace, + f_horiz : image.hspace + }; + this._popupDialog(editor.config.URIs["insert_image"], function(param) { + if (!param) { // user must have pressed Cancel + return false; + } + var img = image; + if (!img) { + var sel = editor._getSelection(); + var range = editor._createRange(sel); + editor._doc.execCommand("insertimage", false, param.f_url); + if (HTMLArea.is_ie) { + img = range.parentElement(); + // wonder if this works... + if (img.tagName.toLowerCase() != "img") { + img = img.previousSibling; + } + } else { + img = range.startContainer.previousSibling; + if (!img.tagName) { + // if the cursor is at the beginning of the document + img = range.startContainer.firstChild; + } + } + } else { + img.src = param.f_url; + } + + for (var field in param) { + var value = param[field]; + switch (field) { + case "f_alt" : img.alt = value; break; + case "f_border" : img.border = parseInt(value || "0"); break; + case "f_align" : img.align = value; break; + case "f_vert" : img.vspace = parseInt(value || "0"); break; + case "f_horiz" : img.hspace = parseInt(value || "0"); break; + } + } + }, outparam); +}; + +// Called when the user clicks the Insert Table button +HTMLArea.prototype._insertTable = function() { + var sel = this._getSelection(); + var range = this._createRange(sel); + var editor = this; // for nested functions + this._popupDialog(editor.config.URIs["insert_table"], function(param) { + if (!param) { // user must have pressed Cancel + return false; + } + var doc = editor._doc; + // create the table element + var table = doc.createElement("table"); + // assign the given arguments + + for (var field in param) { + var value = param[field]; + if (!value) { + continue; + } + switch (field) { + case "f_width" : table.style.width = value + param["f_unit"]; break; + case "f_align" : table.align = value; break; + case "f_border" : table.border = parseInt(value); break; + case "f_spacing" : table.cellSpacing = parseInt(value); break; + case "f_padding" : table.cellPadding = parseInt(value); break; + } + } + var cellwidth = 0; + if (param.f_fixed) + cellwidth = Math.floor(100 / parseInt(param.f_cols)); + var tbody = doc.createElement("tbody"); + table.appendChild(tbody); + for (var i = 0; i < param["f_rows"]; ++i) { + var tr = doc.createElement("tr"); + tbody.appendChild(tr); + for (var j = 0; j < param["f_cols"]; ++j) { + var td = doc.createElement("td"); + if (cellwidth) + td.style.width = cellwidth + "%"; + tr.appendChild(td); + // Mozilla likes to see something inside the cell. + (HTMLArea.is_gecko) && td.appendChild(doc.createElement("br")); + } + } + if (HTMLArea.is_ie) { + range.pasteHTML(table.outerHTML); + } else { + // insert the table + editor.insertNodeAtSelection(table); + } + return true; + }, null); +}; + +/*************************************************** + * Category: EVENT HANDLERS + ***************************************************/ + +// el is reference to the SELECT object +// txt is the name of the select field, as in config.toolbar +HTMLArea.prototype._comboSelected = function(el, txt) { + this.focusEditor(); + var value = el.options[el.selectedIndex].value; + switch (txt) { + case "fontname": + case "fontsize": this.execCommand(txt, false, value); break; + case "formatblock": + // (HTMLArea.is_ie) && (value = "<" + value + ">"); + value = "<" + value + ">" + this.execCommand(txt, false, value); + break; + default: + // try to look it up in the registered dropdowns + var dropdown = this.config.customSelects[txt]; + if (typeof dropdown != "undefined") { + dropdown.action(this); + } else { + alert("FIXME: combo box " + txt + " not implemented"); + } + } +}; + +// the execCommand function (intercepts some commands and replaces them with +// our own implementation) +HTMLArea.prototype.execCommand = function(cmdID, UI, param) { + var editor = this; // for nested functions + this.focusEditor(); + cmdID = cmdID.toLowerCase(); + if (HTMLArea.is_gecko) try { this._doc.execCommand('useCSS', false, true); } catch (e) {}; //switch useCSS off (true=off) + switch (cmdID) { + case "htmlmode" : this.setMode(); break; + case "hilitecolor": + (HTMLArea.is_ie) && (cmdID = "backcolor"); + if (HTMLArea.is_gecko) try { editor._doc.execCommand('useCSS', false, false); } catch (e) {};//switch on useCSS (mozilla bug #279330) + case "forecolor": + this._popupDialog(editor.config.URIs["select_color"], function(color) { + if (color) { // selection not canceled + editor._doc.execCommand(cmdID, false, "#" + color); + } + }, HTMLArea._colorToRgb(this._doc.queryCommandValue(cmdID))); + break; + case "createlink": + this._createLink(); + break; + case "undo": + case "redo": + if (this._customUndo) + this[cmdID](); + else + this._doc.execCommand(cmdID, UI, param); + break; + case "inserttable": this._insertTable(); break; + case "insertimage": this._insertImage(); break; + case "about" : this._popupDialog(editor.config.URIs["about"], null, this); break; + case "showhelp" : window.open(this.config.helpURL, "ha_help"); break; + + case "killword": this._wordClean(); break; + + case "cut": + case "copy": + case "paste": + try { + this._doc.execCommand(cmdID, UI, param); + if (this.config.killWordOnPaste) + this._wordClean(); + } catch (e) { + if (HTMLArea.is_gecko) { + alert(HTMLArea._lc("The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.")); + } + } + break; + case "lefttoright": + case "righttoleft": + var dir = (cmdID == "righttoleft") ? "rtl" : "ltr"; + var el = this.getParentElement(); + while (el && !HTMLArea.isBlockElement(el)) + el = el.parentNode; + if (el) { + if (el.style.direction == dir) + el.style.direction = ""; + else + el.style.direction = dir; + } + break; + default: try { this._doc.execCommand(cmdID, UI, param); } + catch(e) { if (this.config.debug) { alert(e + "\n\nby execCommand(" + cmdID + ");"); } } + } + + this.updateToolbar(); + return false; +}; + +/** A generic event handler for things that happen in the IFRAME's document. + * This function also handles key bindings. */ +HTMLArea.prototype._editorEvent = function(ev) { + var editor = this; + var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (!HTMLArea.is_ie && ev.type == "keypress"); + + //call events of textarea + if(typeof editor._textArea['on'+ev.type] == "function") { + editor._textArea['on'+ev.type](); + } + + if(HTMLArea.is_gecko && keyEvent && ev.ctrlKey && this._unLink && this._unlinkOnUndo) + { + if(String.fromCharCode(ev.charCode).toLowerCase() == 'z') + { + HTMLArea._stopEvent(ev); + this._unLink(); + editor.updateToolbar(); + return; + } + } + + if (keyEvent) + { + for (var i in editor.plugins) + { + var plugin = editor.plugins[i].instance; + if (typeof plugin.onKeyPress == "function") + if (plugin.onKeyPress(ev)) + return false; + } + } + + if (keyEvent && ev.ctrlKey && !ev.altKey) + { + var sel = null; + var range = null; + var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase(); + var cmd = null; + var value = null; + switch (key) { + case 'a': + if (!HTMLArea.is_ie) { + // KEY select all + sel = this._getSelection(); + sel.removeAllRanges(); + range = this._createRange(); + range.selectNodeContents(this._doc.body); + sel.addRange(range); + HTMLArea._stopEvent(ev); + } + break; + + // simple key commands follow + + case 'b': cmd = "bold"; break; + case 'i': cmd = "italic"; break; + case 'u': cmd = "underline"; break; + case 's': cmd = "strikethrough"; break; + case 'l': cmd = "justifyleft"; break; + case 'e': cmd = "justifycenter"; break; + case 'r': cmd = "justifyright"; break; + case 'j': cmd = "justifyfull"; break; + case 'z': cmd = "undo"; break; + case 'y': cmd = "redo"; break; + case 'v': if (HTMLArea.is_ie || editor.config.htmlareaPaste) { cmd = "paste"; } break; + case 'n': cmd = "formatblock"; value = HTMLArea.is_ie ? "

" : "p"; break; + + case '0': cmd = "killword"; break; + + // headings + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + cmd = "formatblock"; + value = "h" + key; + if (HTMLArea.is_ie) + value = "<" + value + ">"; + break; + } + if (cmd) { + // execute simple command + this.execCommand(cmd, false, value); + HTMLArea._stopEvent(ev); + } + } + else if (keyEvent) + { + + // IE's textRange and selection object is woefully inadequate, + // which means this fancy stuff is gecko only sorry :-| + // Die Bill, Die. (IE supports it somewhat nativly though) + if(HTMLArea.is_gecko) + { + var s = editor._getSelection() + var autoWrap = function (textNode, tag) + { + var rightText = textNode.nextSibling; + if(typeof tag == 'string') tag = editor._doc.createElement(tag); + var a = textNode.parentNode.insertBefore(tag, rightText); + HTMLArea.removeFromParent(textNode); + a.appendChild(textNode); + rightText.data = ' ' + rightText.data; + + if(HTMLArea.is_ie) + { + var r = editor._createRange(s); + s.moveToElementText(rightText); + s.move('character', 1); + } + else + { + s.collapse(rightText, 1); + } + HTMLArea._stopEvent(ev); + + editor._unLink = function() + { + var t = a.firstChild; + a.removeChild(t); + a.parentNode.insertBefore(t, a); + HTMLArea.removeFromParent(a); + editor._unLink = null; + editor._unlinkOnUndo = false; + } + editor._unlinkOnUndo = true; + + return a; + } + + switch(ev.which) + { + // Space, see if the text just typed looks like a URL, or email address + // and link it appropriatly + case 32: + { + if(s && s.isCollapsed && s.anchorNode.nodeType == 3 && s.anchorNode.data.length > 3 && s.anchorNode.data.indexOf('.') >= 0) + { + var midStart = s.anchorNode.data.substring(0,s.anchorOffset).search(/\S{4,}$/); + if(midStart == -1) break; + + if(this._getFirstAncestor(s, 'a')) + { + break; // already in an anchor + } + + var matchData = s.anchorNode.data.substring(0,s.anchorOffset).replace(/^.*?(\S*)$/, '$1'); + + var m = matchData.match(HTMLArea.RE_email); + if(m) + { + var leftText = s.anchorNode; + var rightText = leftText.splitText(s.anchorOffset); + var midText = leftText.splitText(midStart); + + autoWrap(midText, 'a').href = 'mailto:' + m[0]; + break; + } + + var m = matchData.match(HTMLArea.RE_url); + if(m) + { + var leftText = s.anchorNode; + var rightText = leftText.splitText(s.anchorOffset); + var midText = leftText.splitText(midStart); + autoWrap(midText, 'a').href = (m[1] ? m[1] : 'http://') + m[2]; + break; + } + } + + } + break; + + default : + { + if(ev.keyCode == 27 || (this._unlinkOnUndo && ev.ctrlKey && ev.which == 122) ) + { + if(this._unLink) + { + this._unLink(); + HTMLArea._stopEvent(ev); + } + break; + } + else if(ev.which || ev.keyCode == 8 || ev.keyCode == 46) + { + this._unlinkOnUndo = false; + + if(s.anchorNode && s.anchorNode.nodeType == 3) + { + // See if we might be changing a link + var a = this._getFirstAncestor(s, 'a'); + if(!a) break; // not an anchor + if(!a._updateAnchTimeout) + { + if( s.anchorNode.data.match(HTMLArea.RE_email) + && (a.href.match('mailto:' + s.anchorNode.data.trim())) + ) + { + var textNode = s.anchorNode; + var fn = function() + { + a.href = 'mailto:' + textNode.data.trim(); + a._updateAnchTimeout = setTimeout(fn, 250); + } + a._updateAnchTimeout = setTimeout(fn, 250); + break; + } + + var m = s.anchorNode.data.match(HTMLArea.RE_url); + if(m && a.href.match(s.anchorNode.data.trim()) ) + { + var textNode = s.anchorNode; + var fn = function() + { + var m = textNode.data.match(HTMLArea.RE_url); + a.href = (m[1] ? m[1] : 'http://') + m[2]; + a._updateAnchTimeout = setTimeout(fn, 250); + } + a._updateAnchTimeout = setTimeout(fn, 250); + } + } + } + + } + } + break; + } + } + + // other keys here + switch (ev.keyCode) + { + case 13: // KEY enter + if (HTMLArea.is_gecko && !ev.shiftKey && this.config.mozParaHandler == 'dirty' ) + { + this.dom_checkInsertP(); + HTMLArea._stopEvent(ev); + } + break; + case 8: // KEY backspace + case 46: // KEY delete + if (HTMLArea.is_gecko && !ev.shiftKey) { + if (this.dom_checkBackspace()) + HTMLArea._stopEvent(ev); + } else if (HTMLArea.is_ie) { + if (this.ie_checkBackspace()) + HTMLArea._stopEvent(ev); + } + break; + } + } + + // update the toolbar state after some time + if (editor._timerToolbar) { + clearTimeout(editor._timerToolbar); + } + editor._timerToolbar = setTimeout(function() { + editor.updateToolbar(); + editor._timerToolbar = null; + }, 250); +}; + +HTMLArea.prototype.convertNode = function(el, newTagName) { + var newel = this._doc.createElement(newTagName); + while (el.firstChild) + newel.appendChild(el.firstChild); + return newel; +}; + +HTMLArea.prototype.ie_checkBackspace = function() { + var sel = this._getSelection(); + if(HTMLArea.is_ie && sel.type == 'Control') + { + var elm = this._activeElement(sel); + HTMLArea.removeFromParent(elm); + return true; + } + + // This bit of code preseves links when you backspace over the + // endpoint of the link in IE. Without it, if you have something like + // link_here | + // where | is the cursor, and backspace over the last e, then the link + // will de-link, which is a bit tedious + var range = this._createRange(sel); + var r2 = range.duplicate(); + r2.moveStart("character", -1); + var a = r2.parentElement(); + if (a != range.parentElement() && + /^a$/i.test(a.tagName)) { + r2.collapse(true); + r2.moveEnd("character", 1); + r2.pasteHTML(''); + r2.select(); + return true; + } +}; + +HTMLArea.prototype.dom_checkBackspace = function() { + var self = this; + setTimeout(function() { + var sel = self._getSelection(); + var range = self._createRange(sel); + var SC = range.startContainer; + var SO = range.startOffset; + var EC = range.endContainer; + var EO = range.endOffset; + var newr = SC.nextSibling; + if (SC.nodeType == 3) + SC = SC.parentNode; + if (!/\S/.test(SC.tagName)) { + var p = document.createElement("p"); + while (SC.firstChild) + p.appendChild(SC.firstChild); + SC.parentNode.insertBefore(p, SC); + HTMLArea.removeFromParent(SC); + var r = range.cloneRange(); + r.setStartBefore(newr); + r.setEndAfter(newr); + r.extractContents(); + sel.removeAllRanges(); + sel.addRange(r); + } + }, 10); +}; + +/** The idea here is + * 1. See if we are in a block element + * 2. If we are not, then wrap the current "block" of text into a paragraph + * 3. Now that we have a block element, select all the text between the insertion point + * and just AFTER the end of the block + * eg

The quick |brown fox jumped over the lazy dog.

| + * --------------------------------------- + * 4. Extract that from the document, making + *

The quick

+ * and a document fragment with + *

brown fox jumped over the lazy dog.

+ * 5. Reinsert it just after the block element + *

The quick

brown fox jumped over the lazy dog.

+ * + * Along the way, allow inserting blank paragraphs, which will look like


+ */ + +HTMLArea.prototype.dom_checkInsertP = function() { + + // Get the insertion point, we'll scrub any highlighted text the user wants rid of while we are there. + var sel = this._getSelection(); + var range = this._createRange(sel); + if (!range.collapsed) + { + range.deleteContents(); + } + this.deactivateEditor(); + //sel.removeAllRanges(); + //sel.addRange(range); + + var SC = range.startContainer; + var SO = range.startOffset; + var EC = range.endContainer; + var EO = range.endOffset; + + // If the insertion point is character 0 of the + // document, then insert a space character that we will wrap into a paragraph + // in a bit. + if (SC == EC && SC == body && !SO && !EO) + { + p = this._doc.createTextNode(" "); + body.insertBefore(p, body.firstChild); + range.selectNodeContents(p); + SC = range.startContainer; + SO = range.startOffset; + EC = range.endContainer; + EO = range.endOffset; + } + + // See if we are in a block element, if so, great. + var p = this.getAllAncestors(); + + var block = null; + var body = this._doc.body; + for (var i = 0; i < p.length; ++i) + { + if(HTMLArea.isParaContainer(p[i])) + { + break; + } + else if (HTMLArea.isBlockElement(p[i]) && !/body|html/i.test(p[i].tagName)) + { + block = p[i]; + break; + } + } + + // If not in a block element, we'll have to turn some stuff into a paragraph + if (!block) + { + // We want to wrap as much stuff as possible into the paragraph in both directions + // from the insertion point. We start with the start container and walk back up to the + // node just before any of the paragraph containers. + var wrap = range.startContainer; + while(wrap.parentNode && !HTMLArea.isParaContainer(wrap.parentNode)) + { + wrap = wrap.parentNode; + } + var start = wrap; + var end = wrap; + + // Now we walk up the sibling list until we hit the top of the document + // or an element that we shouldn't put in a p (eg other p, div, ul, ol, table) + while(start.previousSibling) + { + if(start.previousSibling.tagName) + { + if(!HTMLArea.isBlockElement(start.previousSibling)) + { + start = start.previousSibling; + } + else + { + break; + } + } + else + { + start = start.previousSibling; + } + } + + // Same down the list + while(end.nextSibling) + { + if(end.nextSibling.tagName) + { + if(!HTMLArea.isBlockElement(end.nextSibling)) + { + end = end.nextSibling; + } + else + { + break; + } + } + else + { + end = end.nextSibling; + } + } + + // Select the entire block + range.setStartBefore(start); + range.setEndAfter(end); + + // Make it a paragraph + range.surroundContents(this._doc.createElement('p')); + + // Which becomes the block element + block = range.startContainer.firstChild; + + // And finally reset the insertion point to where it was originally + range.setStart(SC, SO); + } + + // The start point is the insertion point, so just move the end point to immediatly + // after the block + range.setEndAfter(block); + + // Extract the range, to split the block + // If we just did range.extractContents() then Mozilla does wierd stuff + // with selections, but if we clone, then remove the original range and extract + // the clone, it's quite happy. + var r2 = range.cloneRange(); + sel.removeRange(range); + var df = r2.extractContents(); + + if(df.childNodes.length == 0) + { + df.appendChild(this._doc.createElement('p')); + df.firstChild.appendChild(this._doc.createElement('br')); + } + + if(df.childNodes.length > 1) + { + var nb = this._doc.createElement('p'); + while(df.firstChild) + { + var s = df.firstChild; + df.removeChild(s); + nb.appendChild(s); + } + df.appendChild(nb); + } + + // If the original block is empty, put a nsbp in it. + if (!/\S/.test(block.innerHTML)) + block.innerHTML = " "; + + p = df.firstChild; + if (!/\S/.test(p.innerHTML)) + p.innerHTML = "
"; + + // If the new block is empty and it's a heading, make it a paragraph + // note, the new block is empty when you are hitting enter at the end of the existing block + if (/^\s*\s*$/.test(p.innerHTML) && /^h[1-6]$/i.test(p.tagName)) + { + df.appendChild(this.convertNode(p, "p")); + df.removeChild(p); + } + + var newblock = block.parentNode.insertBefore(df.firstChild, block.nextSibling); + + // Select the range (to set the insertion) + // collapse to the start of the new block + // (remember the block might be


, so if we collapsed to the end the
would be noticable) + + //range.selectNode(newblock.firstChild); + //range.collapse(true); + + this.activateEditor(); + + var sel = this._getSelection(); + sel.removeAllRanges(); + sel.collapse(newblock,0); + + // scroll into view + this.scrollToElement(newblock); + + //this.forceRedraw(); + +}; + +HTMLArea.prototype.scrollToElement = function(e) +{ + if(HTMLArea.is_gecko) + { + var top = 0; + var left = 0; + while(e) + { + top += e.offsetTop; + left += e.offsetLeft; + if(e.offsetParent && e.offsetParent.tagName.toLowerCase() != 'body') + { + e = e.offsetParent; + } + else + { + e = null; + } + } + this._iframe.contentWindow.scrollTo(left, top); + } +} + +// retrieve the HTML +HTMLArea.prototype.getHTML = function() { + var html = ''; + switch (this._editMode) { + case "wysiwyg" : + { + if (!this.config.fullPage) + html = HTMLArea.getHTML(this._doc.body, false, this); + else + html = this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement, true, this); + break; + } + case "textmode" : + { + html = this._textArea.value; + break; + } + default : + { + alert("Mode <" + mode + "> not defined!"); + return false; + } + } + return html; +}; + +HTMLArea.prototype.outwardHtml = function(html) +{ + html = html.replace(/<(\/?)b(\s|>|\/)/ig, "<$1strong$2"); + html = html.replace(/<(\/?)i(\s|>|\/)/ig, "<$1em$2"); + html = html.replace(/<(\/?)strike(\s|>|\/)/ig, "<$1del$2"); + + // replace window.open to that any clicks won't open a popup in designMode + html = html.replace("onclick=\"try{if(document.designMode && document.designMode == 'on') return false;}catch(e){} window.open(", "onclick=\"window.open("); + + // Figure out what our server name is, and how it's referenced + var serverBase = location.href.replace(/(https?:\/\/[^\/]*)\/.*/, '$1') + '/'; + + // IE puts this in can't figure out why + html = html.replace(/https?:\/\/null\//g, serverBase); + + // Make semi-absolute links to be truely absolute + // we do this just to standardize so that special replacements knows what + // to expect + html = html.replace(/((href|src|background)=[\'\"])\/+/ig, '$1' + serverBase); + + html = this.outwardSpecialReplacements(html); + + html = this.fixRelativeLinks(html); + + if(this.config.sevenBitClean) + { + html = html.replace(/[^ -~\r\n\t]/g, function(c){ return '&#'+c.charCodeAt(0)+';';}); + } + + // ticket:56, the "greesemonkey" plugin for Firefox adds this junk, + // so we strip it out. Original submitter gave a plugin, but that's + // a bit much just for this IMHO - james + if(HTMLArea.is_gecko) + { + html = html.replace(/[\s]*<\/script>/ig, ''); + } + + return html; +} + +HTMLArea.prototype.inwardHtml = function(html) +{ + // Midas uses b and i instead of strong and em, um, hello, + // mozilla, this is the 21st century calling! + if (HTMLArea.is_gecko) { + html = html.replace(/<(\/?)strong(\s|>|\/)/ig, "<$1b$2"); + html = html.replace(/<(\/?)em(\s|>|\/)/ig, "<$1i$2"); + html = html.replace(/<(\/?)strike(\s|>|\/)/ig, "<$1del$2"); + } + + // replace window.open to that any clicks won't open a popup in designMode + html = html.replace("onclick=\"window.open(", "onclick=\"try{if(document.designMode && document.designMode == 'on') return false;}catch(e){} window.open("); + + html = this.inwardSpecialReplacements(html); + + // For IE's sake, make any URLs that are semi-absolute (="/....") to be + // truely absolute + var nullRE = new RegExp('((href|src|background)=[\'"])/+', 'gi'); + html = html.replace(nullRE, '$1' + location.href.replace(/(https?:\/\/[^\/]*)\/.*/, '$1') + '/'); + + html = this.fixRelativeLinks(html); + return html; +} + +HTMLArea.prototype.outwardSpecialReplacements = function(html) +{ + for(var i in this.config.specialReplacements) + { + var from = this.config.specialReplacements[i]; + var to = i; + // alert('out : ' + from + '=>' + to); + var reg = new RegExp(from.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); + html = html.replace(reg, to.replace(/\$/g, '$$$$')); + //html = html.replace(from, to); + } + return html; +} + +HTMLArea.prototype.inwardSpecialReplacements = function(html) +{ + // alert("inward"); + for(var i in this.config.specialReplacements) + { + var from = i; + var to = this.config.specialReplacements[i]; + // alert('in : ' + from + '=>' + to); + // + // html = html.replace(reg, to); + // html = html.replace(from, to); + var reg = new RegExp(from.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); + html = html.replace(reg, to.replace(/\$/g, '$$$$')); // IE uses doubled dollar signs to escape backrefs, also beware that IE also implements $& $_ and $' like perl. + } + return html; +} + + +HTMLArea.prototype.fixRelativeLinks = function(html) +{ + + if(typeof this.config.stripSelfNamedAnchors != 'undefined' && this.config.stripSelfNamedAnchors) + { + var stripRe = new RegExp(document.location.href.replace(HTMLArea.RE_Specials, '\\$1') + '(#[^\'" ]*)', 'g'); + html = html.replace(stripRe, '$1'); + } + + + if(typeof this.config.stripBaseHref != 'undefined' && this.config.stripBaseHref) + { + var baseRe = null + if(typeof this.config.baseHref != 'undefined' && this.config.baseHref != null) + { + baseRe = new RegExp(this.config.baseHref.replace(HTMLArea.RE_Specials, '\\$1'), 'g'); + } + else + { + baseRe = new RegExp(document.location.href.replace(/([^\/]*\/?)$/, '').replace(HTMLArea.RE_Specials, '\\$1'), 'g'); + } + + html = html.replace(baseRe, ''); + } + + if(HTMLArea.is_ie) + { + // This is now done in inward & outward + // Don't know why but IE is doing this (putting http://null/ on links?! + // alert(html); + // var nullRE = new RegExp('https?:\/\/null\/', 'g'); + // html = html.replace(nullRE, location.href.replace(/(https?:\/\/[^\/]*\/).*/, '$1')); + // alert(html); + } + + return html; +} + +// retrieve the HTML (fastest version, but uses innerHTML) +HTMLArea.prototype.getInnerHTML = function() { + if(!this._doc.body) return ''; + switch (this._editMode) { + case "wysiwyg" : + if (!this.config.fullPage) + // return this._doc.body.innerHTML; + html = this._doc.body.innerHTML; + else + html = this.doctype + "\n" + this._doc.documentElement.innerHTML; + break; + case "textmode" : + html = this._textArea.value; + break; + default : + alert("Mode <" + mode + "> not defined!"); + return false; + } + + return html; +}; + +// completely change the HTML inside +HTMLArea.prototype.setHTML = function(html) { + if (!this.config.fullPage) + { + this._doc.body.innerHTML = html; + } + else + { + this.setFullHTML(html); + } + this._textArea.value = html; +}; + +// sets the given doctype (useful when config.fullPage is true) +HTMLArea.prototype.setDoctype = function(doctype) { + this.doctype = doctype; +}; + +/*************************************************** + * Category: UTILITY FUNCTIONS + ***************************************************/ + +// variable used to pass the object to the popup editor window. +HTMLArea._object = null; + +// function that returns a clone of the given object +HTMLArea.cloneObject = function(obj) { + if (!obj) return null; + var newObj = new Object; + + // check for array objects + if (obj.constructor.toString().indexOf("function Array(") == 1) { + newObj = obj.constructor(); + } + + // check for function objects (as usual, IE is fucked up) + if (obj.constructor.toString().indexOf("function Function(") == 1) { + newObj = obj; // just copy reference to it + } else for (var n in obj) { + var node = obj[n]; + if (typeof node == 'object') { newObj[n] = HTMLArea.cloneObject(node); } + else { newObj[n] = node; } + } + + return newObj; +}; + +// FIXME!!! this should return false for IE < 5.5 +HTMLArea.checkSupportedBrowser = function() { + if (HTMLArea.is_gecko) { + if (navigator.productSub < 20021201) { + alert("You need at least Mozilla-1.3 Alpha.\n" + + "Sorry, your Gecko is not supported."); + return false; + } + if (navigator.productSub < 20030210) { + alert("Mozilla < 1.3 Beta is not supported!\n" + + "I'll try, though, but it might not work."); + } + } + return HTMLArea.is_gecko || HTMLArea.is_ie; +}; + +// selection & ranges + +// returns the current selection object +HTMLArea.prototype._getSelection = function() { + if (HTMLArea.is_ie) { + return this._doc.selection; + } else { + return this._iframe.contentWindow.getSelection(); + } +}; + +// returns a range for the current selection +HTMLArea.prototype._createRange = function(sel) { + if (HTMLArea.is_ie) { + return sel.createRange(); + } else { + this.activateEditor(); + if (typeof sel != "undefined") { + try { + return sel.getRangeAt(0); + } catch(e) { + return this._doc.createRange(); + } + } else { + return this._doc.createRange(); + } + } +}; + +// event handling + +/** Event Flushing + * To try and work around memory leaks in the rather broken + * garbage collector in IE, HTMLArea.flushEvents can be called + * onunload, it will remove any event listeners (that were added + * through _addEvent(s)) and clear any DOM-0 events. + */ +HTMLArea._eventFlushers = [ ]; +HTMLArea.flushEvents = function() +{ + var x = 0; + var e = null; + while(e = HTMLArea._eventFlushers.pop()) + { + if(e.length == 3) + { + HTMLArea._removeEvent(e[0], e[1], e[2]); + x++; + } + else if (e.length == 2) + { + e[0]['on' + e[1]] = null; + e[0]._xinha_dom0Events[e[1]] = null; + x++; + } + } + + /* + // This code is very agressive, and incredibly slow in IE, so I've disabled it. + + if(document.all) + { + for(var i = 0; i < document.all.length; i++) + { + for(var j in document.all[i]) + { + if(/^on/.test(j) && typeof document.all[i][j] == 'function') + { + document.all[i][j] = null; + x++; + } + } + } + } + */ + + // alert('Flushed ' + x + ' events.'); +} + +HTMLArea._addEvent = function(el, evname, func) { + if (HTMLArea.is_ie) { + el.attachEvent("on" + evname, func); + } else { + el.addEventListener(evname, func, true); + } + HTMLArea._eventFlushers.push([el, evname, func]); +}; + +HTMLArea._addEvents = function(el, evs, func) { + for (var i = evs.length; --i >= 0;) { + HTMLArea._addEvent(el, evs[i], func); + } +}; + +HTMLArea._removeEvent = function(el, evname, func) { + if (HTMLArea.is_ie) { + el.detachEvent("on" + evname, func); + } else { + el.removeEventListener(evname, func, true); + } +}; + +HTMLArea._removeEvents = function(el, evs, func) { + for (var i = evs.length; --i >= 0;) { + HTMLArea._removeEvent(el, evs[i], func); + } +}; + +HTMLArea._stopEvent = function(ev) { + if (HTMLArea.is_ie) { + ev.cancelBubble = true; + ev.returnValue = false; + } else { + ev.preventDefault(); + ev.stopPropagation(); + } +}; + +/** + * Adds a standard "DOM-0" event listener to an element. + * The DOM-0 events are those applied directly as attributes to + * an element - eg element.onclick = stuff; + * + * By using this function instead of simply overwriting any existing + * DOM-0 event by the same name on the element it will trigger as well + * as the existing ones. Handlers are triggered one after the other + * in the order they are added. + * + * Remember to return true/false from your handler, this will determine + * whether subsequent handlers will be triggered (ie that the event will + * continue or be canceled). + * + */ + +HTMLArea.addDom0Event = function(el, ev, fn) +{ + HTMLArea._prepareForDom0Events(el, ev); + el._xinha_dom0Events[ev].unshift(fn); +} + + +/** + * See addDom0Event, the difference is that handlers registered using + * prependDom0Event will be triggered before existing DOM-0 events of the + * same name on the same element. + */ + +HTMLArea.prependDom0Event = function(el, ev, fn) +{ + HTMLArea._prepareForDom0Events(el, ev); + el._xinha_dom0Events[ev].push(fn); +} + +/** + * Prepares an element to receive more than one DOM-0 event handler + * when handlers are added via addDom0Event and prependDom0Event. + */ +HTMLArea._prepareForDom0Events = function(el, ev) +{ + // Create a structure to hold our lists of event handlers + if(typeof el._xinha_dom0Events == 'undefined') + { + el._xinha_dom0Events = { }; + HTMLArea.freeLater(el, '_xinha_dom0Events'); + } + + // Create a list of handlers for this event type + if(typeof el._xinha_dom0Events[ev] == 'undefined') + { + el._xinha_dom0Events[ev] = [ ]; + if(typeof el['on'+ev] == 'function') + { + el._xinha_dom0Events[ev].push(el['on'+ev]); + } + + // Make the actual event handler, which runs through + // each of the handlers in the list and executes them + // in the correct context. + el['on'+ev] = function(event) + { + var a = el._xinha_dom0Events[ev]; + // call previous submit methods if they were there. + var allOK = true; + for (var i = a.length; --i >= 0;) + { + // We want the handler to be a member of the form, not the array, so that "this" will work correctly + el._xinha_tempEventHandler = a[i]; + if(el._xinha_tempEventHandler(event) == false) + { + el._xinha_tempEventHandler = null; + allOK = false; + break; + } + el._xinha_tempEventHandler = null; + } + return allOK; + } + + HTMLArea._eventFlushers.push([el, ev]); + } +} + +HTMLArea.prototype.notifyOn = function(ev, fn) +{ + if(typeof this._notifyListeners[ev] == 'undefined') + { + this._notifyListeners[ev] = [ ]; + HTMLArea.freeLater(this, '_notifyListeners'); + } + + this._notifyListeners[ev].push(fn); +} + +HTMLArea.prototype.notifyOf = function(ev, args) +{ + + if(this._notifyListeners[ev]) + { + + for(var i = 0; i < this._notifyListeners[ev].length; i++) + { + this._notifyListeners[ev][i](ev, args); + } + } +} + + +HTMLArea._removeClass = function(el, className) { + if (!(el && el.className)) { + return; + } + var cls = el.className.split(" "); + var ar = new Array(); + for (var i = cls.length; i > 0;) { + if (cls[--i] != className) { + ar[ar.length] = cls[i]; + } + } + el.className = ar.join(" "); +}; + +HTMLArea._addClass = function(el, className) { + // remove the class first, if already there + HTMLArea._removeClass(el, className); + el.className += " " + className; +}; + +HTMLArea._hasClass = function(el, className) { + if (!(el && el.className)) { + return false; + } + var cls = el.className.split(" "); + for (var i = cls.length; i > 0;) { + if (cls[--i] == className) { + return true; + } + } + return false; +}; + +HTMLArea._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"; +HTMLArea.isBlockElement = function(el) { + return el && el.nodeType == 1 && (HTMLArea._blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); +}; + +HTMLArea._paraContainerTags = " body td th caption fieldset div"; +HTMLArea.isParaContainer = function(el) +{ + return el && el.nodeType == 1 && (HTMLArea._paraContainerTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); +} + +HTMLArea._closingTags = " head script style div span tr td tbody table em strong b i strike code cite dfn abbr acronym font a title textarea select form "; +HTMLArea.needsClosingTag = function(el) { + return el && el.nodeType == 1 && (HTMLArea._closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1); +}; + +// performs HTML encoding of some given string +HTMLArea.htmlEncode = function(str) { + if(typeof str.replace == 'undefined') str = str.toString(); + // we don't need regexp for that, but.. so be it for now. + str = str.replace(/&/ig, "&"); + str = str.replace(//ig, ">"); + str = str.replace(/\xA0/g, " "); // Decimal 160, non-breaking-space + str = str.replace(/\x22/g, """); + // \x22 means '"' -- we use hex reprezentation so that we don't disturb + // JS compressors (well, at least mine fails.. ;) + return str; +}; + +// Retrieves the HTML code from the given node. This is a replacement for +// getting innerHTML, using standard DOM calls. +// Wrapper catch a Mozilla-Exception with non well formed html source code +HTMLArea.getHTML = function(root, outputRoot, editor){ + try{ + return HTMLArea.getHTMLWrapper(root,outputRoot,editor); + } + catch(e){ + alert(HTMLArea._lc('Your Document is not well formed. Check JavaScript console for details.')); + return editor._iframe.contentWindow.document.body.innerHTML; + } +} + +HTMLArea.getHTMLWrapper = function(root, outputRoot, editor, indent) { + var html = ""; + if(!indent) indent = ''; + + switch (root.nodeType) { + case 10:// Node.DOCUMENT_TYPE_NODE + case 6: // Node.ENTITY_NODE + case 12:// Node.NOTATION_NODE + // this all are for the document type, probably not necessary + break; + + case 2: // Node.ATTRIBUTE_NODE + // Never get here, this has to be handled in the ELEMENT case because + // of IE crapness requring that some attributes are grabbed directly from + // the attribute (nodeValue doesn't return correct values), see + //http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3porgu4mc4ofcoa1uqkf7u8kvv064kjjb4%404ax.com + // for information + break; + + case 4: // Node.CDATA_SECTION_NODE + // Mozilla seems to convert CDATA into a comment when going into wysiwyg mode, + // don't know about IE + html += (HTMLArea.is_ie ? ('\n' + indent) : '') + '' ; + break; + + case 5: // Node.ENTITY_REFERENCE_NODE + html += '&' + root.nodeValue + ';'; + break; + + case 7: // Node.PROCESSING_INSTRUCTION_NODE + // PI's don't seem to survive going into the wysiwyg mode, (at least in moz) + // so this is purely academic + html += (HTMLArea.is_ie ? ('\n' + indent) : '') + ''; + break; + + + case 1: // Node.ELEMENT_NODE + case 11: // Node.DOCUMENT_FRAGMENT_NODE + case 9: // Node.DOCUMENT_NODE + { + var closed; + var i; + var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : ''; + if (outputRoot) + outputRoot = !(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(root_tag)); + if (HTMLArea.is_ie && root_tag == "head") { + if (outputRoot) + html += (HTMLArea.is_ie ? ('\n' + indent) : '') + ""; + // lowercasize + var save_multiline = RegExp.multiline; + RegExp.multiline = true; + var txt = root.innerHTML.replace(HTMLArea.RE_tagName, function(str, p1, p2) { + return p1 + p2.toLowerCase(); + }); + RegExp.multiline = save_multiline; + html += txt + '\n'; + if (outputRoot) + html += (HTMLArea.is_ie ? ('\n' + indent) : '') + ""; + break; + } else if (outputRoot) { + closed = (!(root.hasChildNodes() || HTMLArea.needsClosingTag(root))); + html += (HTMLArea.is_ie && HTMLArea.isBlockElement(root) ? ('\n' + indent) : '') + "<" + root.tagName.toLowerCase(); + var attrs = root.attributes; + for (i = 0; i < attrs.length; ++i) { + var a = attrs.item(i); + if (!a.specified && !(root.tagName.toLowerCase().match(/input|option/) && a.nodeName == 'value')) { + continue; + } + var name = a.nodeName.toLowerCase(); + if (/_moz_editor_bogus_node/.test(name)) { + html = ""; + break; + } + if (/(_moz)|(contenteditable)|(_msh)/.test(name)) { + // avoid certain attributes + continue; + } + var value; + if (name != "style") { + // IE5.5 reports 25 when cellSpacing is + // 1; other values might be doomed too. + // For this reason we extract the + // values directly from the root node. + // I'm starting to HATE JavaScript + // development. Browser differences + // suck. + // + // Using Gecko the values of href and src are converted to absolute links + // unless we get them using nodeValue() + if (typeof root[a.nodeName] != "undefined" && name != "href" && name != "src" && !/^on/.test(name)) { + value = root[a.nodeName]; + } else { + value = a.nodeValue; + // IE seems not willing to return the original values - it converts to absolute + // links using a.nodeValue, a.value, a.stringValue, root.getAttribute("href") + // So we have to strip the baseurl manually :-/ + if (HTMLArea.is_ie && (name == "href" || name == "src")) { + value = editor.stripBaseURL(value); + } + + // High-ascii (8bit) characters in links seem to cause problems for some sites, + // while this seems to be consistent with RFC 3986 Section 2.4 + // because these are not "reserved" characters, it does seem to + // cause links to international resources not to work. See ticket:167 + + // IE always returns high-ascii characters un-encoded in links even if they + // were supplied as % codes (it unescapes them when we pul the value from the link). + + // Hmmm, very strange if we use encodeURI here, or encodeURIComponent in place + // of escape below, then the encoding is wrong. I mean, completely. + // Nothing like it should be at all. Using escape seems to work though. + // It's in both browsers too, so either I'm doing something wrong, or + // something else is going on? + + if(editor.config.only7BitPrintablesInURLs && (name == "href" || name == "src")) + { + value = value.replace(/([^!-~]+)/g, function(match) { return escape(match); }); + } + } + } else { // IE fails to put style in attributes list + // FIXME: cssText reported by IE is UPPERCASE + value = root.style.cssText; + } + if (/^(_moz)?$/.test(value)) { + // Mozilla reports some special tags + // here; we don't need them. + continue; + } + html += " " + name + '="' + HTMLArea.htmlEncode(value) + '"'; + } + if (html != "") { + if(closed && root_tag=="p") { + //never use

as empty paragraphs won't be visible + html += "> 

"; + } else if(closed) { + html += " />"; + } else { + html += ">"; + } + } + } + var containsBlock = false; + for (i = root.firstChild; i; i = i.nextSibling) { + if(!containsBlock && i.nodeType == 1 && HTMLArea.isBlockElement(i)) containsBlock = true; + html += HTMLArea.getHTMLWrapper(i, true, editor, indent + ' '); + } + if (outputRoot && !closed) { + html += (HTMLArea.is_ie && HTMLArea.isBlockElement(root) && containsBlock ? ('\n' + indent) : '') + ""; + } + break; + } + case 3: // Node.TEXT_NODE + html = /^script|style$/i.test(root.parentNode.tagName) ? root.data : HTMLArea.htmlEncode(root.data); + break; + + case 8: // Node.COMMENT_NODE + html = ""; + break; + } + return html; +}; + +/** @see getHTMLWrapper (search for "value = a.nodeValue;") */ + +HTMLArea.prototype.stripBaseURL = function(string) +{ + if(this.config.baseHref==null || !this.config.stripBaseHref) + { + return(string); + } + var baseurl = this.config.baseHref; + + // strip host-part of URL which is added by MSIE to links relative to server root + baseurl = baseurl.replace(/^(https?:\/\/[^\/]+)(.*)$/, '$1'); + basere = new RegExp(baseurl); + return string.replace(basere, ""); +}; + +String.prototype.trim = function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); +}; + +// creates a rgb-style color from a number +HTMLArea._makeColor = function(v) { + if (typeof v != "number") { + // already in rgb (hopefully); IE doesn't get here. + return v; + } + // IE sends number; convert to rgb. + var r = v & 0xFF; + var g = (v >> 8) & 0xFF; + var b = (v >> 16) & 0xFF; + return "rgb(" + r + "," + g + "," + b + ")"; +}; + +// returns hexadecimal color representation from a number or a rgb-style color. +HTMLArea._colorToRgb = function(v) { + if (!v) + return ''; + + // returns the hex representation of one byte (2 digits) + function hex(d) { + return (d < 16) ? ("0" + d.toString(16)) : d.toString(16); + }; + + if (typeof v == "number") { + // we're talking to IE here + var r = v & 0xFF; + var g = (v >> 8) & 0xFF; + var b = (v >> 16) & 0xFF; + return "#" + hex(r) + hex(g) + hex(b); + } + + if (v.substr(0, 3) == "rgb") { + // in rgb(...) form -- Mozilla + var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/; + if (v.match(re)) { + var r = parseInt(RegExp.$1); + var g = parseInt(RegExp.$2); + var b = parseInt(RegExp.$3); + return "#" + hex(r) + hex(g) + hex(b); + } + // doesn't match RE?! maybe uses percentages or float numbers + // -- FIXME: not yet implemented. + return null; + } + + if (v.substr(0, 1) == "#") { + // already hex rgb (hopefully :D ) + return v; + } + + // if everything else fails ;) + return null; +}; + +// modal dialogs for Mozilla (for IE we're using the showModalDialog() call). + +// receives an URL to the popup dialog and a function that receives one value; +// this function will get called after the dialog is closed, with the return +// value of the dialog. +HTMLArea.prototype._popupDialog = function(url, action, init) { + Dialog(this.popupURL(url), action, init); +}; + +// paths + +HTMLArea.prototype.imgURL = function(file, plugin) { + if (typeof plugin == "undefined") + return _editor_url + file; + else + return _editor_url + "plugins/" + plugin + "/img/" + file; +}; + +HTMLArea.prototype.popupURL = function(file) { + var url = ""; + if (file.match(/^plugin:\/\/(.*?)\/(.*)/)) { + var plugin = RegExp.$1; + var popup = RegExp.$2; + if (!/\.html$/.test(popup)) + popup += ".html"; + url = _editor_url + "plugins/" + plugin + "/popups/" + popup; + } else if(file.match(/^\/.*?/)) + url = file; + else + url = _editor_url + this.config.popupURL + file; + return url; +}; + +/** + * FIX: Internet Explorer returns an item having the _name_ equal to the given + * id, even if it's not having any id. This way it can return a different form + * field even if it's not a textarea. This workarounds the problem by + * specifically looking to search only elements having a certain tag name. + */ +HTMLArea.getElementById = function(tag, id) { + var el, i, objs = document.getElementsByTagName(tag); + for (i = objs.length; --i >= 0 && (el = objs[i]);) + if (el.id == id) + return el; + return null; +}; + + +/** Use some CSS trickery to toggle borders on tables */ + +HTMLArea.prototype._toggleBorders = function() +{ + tables = this._doc.getElementsByTagName('TABLE'); + if(tables.length != 0) + { + if(!this.borders) + { + name = "bordered"; + this.borders = true; + } + else + { + name = ""; + this.borders = false; + } + + for (var ix=0;ix < tables.length;ix++) + { + if(this.borders) + { + // flashing the display forces moz to listen (JB:18-04-2005) - #102 + if(HTMLArea.is_gecko) + { + tables[ix].style.display="none"; + tables[ix].style.display="table"; + } + HTMLArea._addClass(tables[ix], 'htmtableborders'); + } + else + { + HTMLArea._removeClass(tables[ix], 'htmtableborders'); + } + } + } + return true; +} + + +HTMLArea.addClasses = function(el, classes) + { + if(el != null) + { + var thiers = el.className.trim().split(' '); + var ours = classes.split(' '); + for(var x = 0; x < ours.length; x++) + { + var exists = false; + for(var i = 0; exists == false && i < thiers.length; i++) + { + if(thiers[i] == ours[x]) + { + exists = true; + } + } + if(exists == false) + { + thiers[thiers.length] = ours[x]; + } + } + el.className = thiers.join(' ').trim(); + } + } + +HTMLArea.removeClasses = function(el, classes) +{ + var existing = el.className.trim().split(); + var new_classes = [ ]; + var remove = classes.trim().split(); + + for(var i = 0; i < existing.length; i++) + { + var found = false; + for(var x = 0; x < remove.length && !found; x++) + { + if(existing[i] == remove[x]) + { + found = true; + } + } + if(!found) + { + new_classes[new_classes.length] = existing[i]; + } + } + return new_classes.join(' '); +} + +/** Alias these for convenience */ +HTMLArea.addClass = HTMLArea._addClass; +HTMLArea.removeClass = HTMLArea._removeClass; +HTMLArea._addClasses = HTMLArea.addClasses; +HTMLArea._removeClasses = HTMLArea.removeClasses; + +/** Use XML HTTPRequest to post some data back to the server and do something + * with the response (asyncronously!), this is used by such things as the tidy functions + */ +HTMLArea._postback = function(url, data, handler) +{ + var req = null; + if(HTMLArea.is_ie) + { + req = new ActiveXObject("Microsoft.XMLHTTP"); + } + else + { + req = new XMLHttpRequest(); + } + + var content = ''; + for(var i in data) + { + content += (content.length ? '&' : '') + i + '=' + encodeURIComponent(data[i]); + } + + function callBack() + { + if(req.readyState == 4) + { + if(req.status == 200) + { + if(typeof handler == 'function') + handler(req.responseText, req); + } + else + { + alert('An error has occurred: ' + req.statusText); + } + } + } + + req.onreadystatechange = callBack; + + req.open('POST', url, true); + req.setRequestHeader + ( + 'Content-Type', + 'application/x-www-form-urlencoded; charset=UTF-8' + ); + //alert(content); + req.send(content); +} + +HTMLArea._getback = function(url, handler) +{ + var req = null; + if(HTMLArea.is_ie) + { + req = new ActiveXObject("Microsoft.XMLHTTP"); + } + else + { + req = new XMLHttpRequest(); + } + + function callBack() + { + if(req.readyState == 4) + { + if(req.status == 200) + { + handler(req.responseText, req); + } + else + { + alert('An error has occurred: ' + req.statusText); + } + } + } + + req.onreadystatechange = callBack; + req.open('GET', url, true); + req.send(null); +} + +HTMLArea._geturlcontent = function(url) +{ + var req = null; + if(HTMLArea.is_ie) + { + req = new ActiveXObject("Microsoft.XMLHTTP"); + } + else + { + req = new XMLHttpRequest(); + } + + // Synchronous! + req.open('GET', url, false); + req.send(null); + if(req.status == 200) + { + return req.responseText; + } + else + { + return ''; + } + +} + +/** + * Unless somebody already has, make a little function to debug things + */ +if(typeof dump == 'undefined') +{ + function dump(o) { + var s = ''; + for (var prop in o) { + s += prop + ' = ' + o[prop] + '\n'; + } + + x = window.open("", "debugger"); + x.document.write('
' + s + '
'); + } +} + + +HTMLArea.arrayContainsArray = function(a1, a2) +{ + var all_found = true; + for(var x = 0; x < a2.length; x++) + { + var found = false; + for(var i = 0; i < a1.length; i++) + { + if(a1[i] == a2[x]) + { + found = true; + break; + } + } + if(!found) + { + all_found = false; + break; + } + } + return all_found; +} + +HTMLArea.arrayFilter = function(a1, filterfn) +{ + var new_a = [ ]; + for(var x = 0; x < a1.length; x++) + { + if(filterfn(a1[x])) + new_a[new_a.length] = a1[x]; + } + + return new_a; +} + +HTMLArea.uniq_count = 0; +HTMLArea.uniq = function(prefix) +{ + return prefix + HTMLArea.uniq_count++; +} + +/** New language handling functions **/ + + +/** Load a language file. + * This function should not be used directly, HTMLArea._lc will use it when necessary. + * @param context Case sensitive context name, eg 'HTMLArea', 'TableOperations', ... + */ +HTMLArea._loadlang = function(context) +{ + if(typeof _editor_lcbackend == "string") + { + //use backend + var url = _editor_lcbackend; + url = url.replace(/%lang%/, _editor_lang); + url = url.replace(/%context%/, context); + } + else + { + //use internal files + if(context != 'HTMLArea') { + var url = _editor_url+"plugins/"+context+"/lang/"+_editor_lang+".js"; + } else { + var url = _editor_url+"lang/"+_editor_lang+".js"; + } + } + + var lang; + var langData = HTMLArea._geturlcontent(url); + if(langData != "") { + try { + eval('lang = ' + langData); + } catch(Error) { + alert('Error reading Language-File ('+url+'):\n'+Error.toString()); + lang = { } + } + } else { + lang = { }; + } + + return lang; +} + +/** Return a localised string. + * @param string English language string + * @param context Case sensitive context name, eg 'HTMLArea' (default), 'TableOperations'... + * @param replace Replace $variables in String, eg {foo: 'replaceText'} ($foo in string will be replaced) + */ +HTMLArea._lc = function(string, context, replace) +{ + var ret; + if(_editor_lang == "en") + { + if(typeof string == 'object' && string.string) { + ret = string.string; + } else { + ret = string; + } + } + else + { + if(typeof HTMLArea._lc_catalog == 'undefined') + { + HTMLArea._lc_catalog = [ ]; + } + + if(typeof context == 'undefined') + { + context = 'HTMLArea'; + } + + if(typeof HTMLArea._lc_catalog[context] == 'undefined') + { + HTMLArea._lc_catalog[context] = HTMLArea._loadlang(context); + } + + var key; + if(typeof string == 'object' && string.key) + { + key = string.key; + } + else + { + key = string; + } + + if(typeof HTMLArea._lc_catalog[context][key] == 'undefined') + { + if(context=='HTMLArea') + { + // Indicate it's untranslated + if(typeof string == 'object' && string.string) { + ret = string.string; + } else { + ret = string; + } + } + else + { + //if string is not found and context is not HTMLArea try if it is in HTMLArea + return HTMLArea._lc(string, 'HTMLArea', replace); + } + } + else + { + ret = HTMLArea._lc_catalog[context][key]; + } + } + + if(typeof string == 'object' && string.replace) + { + replace = string.replace; + } + if(typeof replace != "undefined") + { + for(var i in replace) + { + ret = ret.replace('$'+i, replace[i]); + } + } + + return ret; +} + +HTMLArea.hasDisplayedChildren = function(el) +{ + var children = el.childNodes; + for(var i =0; i < children.length;i++) + { + if(children[i].tagName) + { + if(children[i].style.display != 'none') + { + return true; + } + } + } + return false; +} + + +HTMLArea._loadback = function(src, callback) +{ + var head = document.getElementsByTagName("head")[0]; + var evt = HTMLArea.is_ie ? "onreadystatechange" : "onload"; + + var script = document.createElement("script"); + script.type = "text/javascript"; + script.src = src; + script[evt] = function() + { + if(HTMLArea.is_ie && !/loaded|complete/.test(window.event.srcElement.readyState)) return; + callback(); + } + head.appendChild(script); +}; + +HTMLArea.collectionToArray = function(collection) +{ + var array = [ ]; + for(var i = 0; i < collection.length; i++) + { + array.push(collection.item(i)); + } + return array; +} + +if(!Array.prototype.append) +{ + Array.prototype.append = function(a) + { + for(var i = 0; i> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + keyStr.charAt(enc4); + } while (i < input.length); + + return output; +} + +/** Utility function to base64_decode some arbitrary data, uses the builtin atob() if it exists (Moz) */ + +HTMLArea.base64_decode =function(input) +{ + var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + do { + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } while (i < input.length); + + return output; +} + +HTMLArea.removeFromParent = function(el) +{ + if(!el.parentNode) return; + var pN = el.parentNode; + pN.removeChild(el); + return el; +} + +HTMLArea.hasParentNode = function(el) +{ + if(el.parentNode) + { + // When you remove an element from the parent in IE it makes the parent + // of the element a document fragment. Moz doesn't. + if(el.parentNode.nodeType == 11) + { + return false; + } + return true; + } + + return false; +} + +HTMLArea.getOuterHTML = function(element) +{ + if(HTMLArea.is_ie) + { + return element.outerHTML; + } + else + { + return (new XMLSerializer()).serializeToString(element); + } +} + +HTMLArea.toFree = [ ]; +HTMLArea.freeLater = function(obj,prop) +{ + HTMLArea.toFree.push({o:obj,p:prop}); +} + +HTMLArea.free = function(obj, prop) +{ + if(obj && !prop) + { + for(var p in obj) + { + HTMLArea.free(obj, p); + } + } + else if (obj) + { + obj[prop] = null; + } +} + +/** IE's Garbage Collector is broken very badly. We will do our best to + * do it's job for it, but we can't be perfect. + */ + +HTMLArea.collectGarbageForIE = function() +{ + HTMLArea.flushEvents(); + for(var x = 0; x < HTMLArea.toFree.length; x++) + { + if(!HTMLArea.toFree[x].o) alert("What is " + x + ' ' + HTMLArea.toFree[x].o); + HTMLArea.free(HTMLArea.toFree[x].o, HTMLArea.toFree[x].p); + } +} + +HTMLArea.init(); +HTMLArea.addDom0Event(window,'unload',HTMLArea.collectGarbageForIE); \ No newline at end of file diff --git a/xinha/images/de/bold.gif b/xinha/images/de/bold.gif new file mode 100644 index 0000000..298e737 Binary files /dev/null and b/xinha/images/de/bold.gif differ diff --git a/xinha/images/de/italic.gif b/xinha/images/de/italic.gif new file mode 100644 index 0000000..d340dbe Binary files /dev/null and b/xinha/images/de/italic.gif differ diff --git a/xinha/images/de/underline.gif b/xinha/images/de/underline.gif new file mode 100644 index 0000000..6ebdd87 Binary files /dev/null and b/xinha/images/de/underline.gif differ diff --git a/xinha/images/ed_about.gif b/xinha/images/ed_about.gif new file mode 100644 index 0000000..f0a338b Binary files /dev/null and b/xinha/images/ed_about.gif differ diff --git a/xinha/images/ed_align.gif b/xinha/images/ed_align.gif new file mode 100644 index 0000000..c971e2a Binary files /dev/null and b/xinha/images/ed_align.gif differ diff --git a/xinha/images/ed_align_center.gif b/xinha/images/ed_align_center.gif new file mode 100644 index 0000000..9505db2 Binary files /dev/null and b/xinha/images/ed_align_center.gif differ diff --git a/xinha/images/ed_align_justify.gif b/xinha/images/ed_align_justify.gif new file mode 100644 index 0000000..29cf731 Binary files /dev/null and b/xinha/images/ed_align_justify.gif differ diff --git a/xinha/images/ed_align_left.gif b/xinha/images/ed_align_left.gif new file mode 100644 index 0000000..d0356d4 Binary files /dev/null and b/xinha/images/ed_align_left.gif differ diff --git a/xinha/images/ed_align_right.gif b/xinha/images/ed_align_right.gif new file mode 100644 index 0000000..b9f7a96 Binary files /dev/null and b/xinha/images/ed_align_right.gif differ diff --git a/xinha/images/ed_blank.gif b/xinha/images/ed_blank.gif new file mode 100644 index 0000000..1ea396b Binary files /dev/null and b/xinha/images/ed_blank.gif differ diff --git a/xinha/images/ed_buttons_main.gif b/xinha/images/ed_buttons_main.gif new file mode 100644 index 0000000..2a43c10 Binary files /dev/null and b/xinha/images/ed_buttons_main.gif differ diff --git a/xinha/images/ed_charmap.gif b/xinha/images/ed_charmap.gif new file mode 100644 index 0000000..9fac54d Binary files /dev/null and b/xinha/images/ed_charmap.gif differ diff --git a/xinha/images/ed_clearfonts.gif b/xinha/images/ed_clearfonts.gif new file mode 100644 index 0000000..0d3343f Binary files /dev/null and b/xinha/images/ed_clearfonts.gif differ diff --git a/xinha/images/ed_color_bg.gif b/xinha/images/ed_color_bg.gif new file mode 100644 index 0000000..8b464c9 Binary files /dev/null and b/xinha/images/ed_color_bg.gif differ diff --git a/xinha/images/ed_color_fg.gif b/xinha/images/ed_color_fg.gif new file mode 100644 index 0000000..44af9c4 Binary files /dev/null and b/xinha/images/ed_color_fg.gif differ diff --git a/xinha/images/ed_copy.gif b/xinha/images/ed_copy.gif new file mode 100644 index 0000000..975740a Binary files /dev/null and b/xinha/images/ed_copy.gif differ diff --git a/xinha/images/ed_custom.gif b/xinha/images/ed_custom.gif new file mode 100644 index 0000000..9529a52 Binary files /dev/null and b/xinha/images/ed_custom.gif differ diff --git a/xinha/images/ed_cut.gif b/xinha/images/ed_cut.gif new file mode 100644 index 0000000..2066038 Binary files /dev/null and b/xinha/images/ed_cut.gif differ diff --git a/xinha/images/ed_delete.gif b/xinha/images/ed_delete.gif new file mode 100644 index 0000000..3c3df5b Binary files /dev/null and b/xinha/images/ed_delete.gif differ diff --git a/xinha/images/ed_format_bold.gif b/xinha/images/ed_format_bold.gif new file mode 100644 index 0000000..c6291f0 Binary files /dev/null and b/xinha/images/ed_format_bold.gif differ diff --git a/xinha/images/ed_format_italic.gif b/xinha/images/ed_format_italic.gif new file mode 100644 index 0000000..7bb67aa Binary files /dev/null and b/xinha/images/ed_format_italic.gif differ diff --git a/xinha/images/ed_format_strike.gif b/xinha/images/ed_format_strike.gif new file mode 100644 index 0000000..0e00304 Binary files /dev/null and b/xinha/images/ed_format_strike.gif differ diff --git a/xinha/images/ed_format_sub.gif b/xinha/images/ed_format_sub.gif new file mode 100644 index 0000000..effcf57 Binary files /dev/null and b/xinha/images/ed_format_sub.gif differ diff --git a/xinha/images/ed_format_sup.gif b/xinha/images/ed_format_sup.gif new file mode 100644 index 0000000..1b6f401 Binary files /dev/null and b/xinha/images/ed_format_sup.gif differ diff --git a/xinha/images/ed_format_underline.gif b/xinha/images/ed_format_underline.gif new file mode 100644 index 0000000..ef8c19e Binary files /dev/null and b/xinha/images/ed_format_underline.gif differ diff --git a/xinha/images/ed_help.gif b/xinha/images/ed_help.gif new file mode 100644 index 0000000..06c2256 Binary files /dev/null and b/xinha/images/ed_help.gif differ diff --git a/xinha/images/ed_hr.gif b/xinha/images/ed_hr.gif new file mode 100644 index 0000000..9f6e5e8 Binary files /dev/null and b/xinha/images/ed_hr.gif differ diff --git a/xinha/images/ed_html.gif b/xinha/images/ed_html.gif new file mode 100644 index 0000000..807f084 Binary files /dev/null and b/xinha/images/ed_html.gif differ diff --git a/xinha/images/ed_image.gif b/xinha/images/ed_image.gif new file mode 100644 index 0000000..9d2bff1 Binary files /dev/null and b/xinha/images/ed_image.gif differ diff --git a/xinha/images/ed_indent_less.gif b/xinha/images/ed_indent_less.gif new file mode 100644 index 0000000..f320b3e Binary files /dev/null and b/xinha/images/ed_indent_less.gif differ diff --git a/xinha/images/ed_indent_more.gif b/xinha/images/ed_indent_more.gif new file mode 100644 index 0000000..a67139d Binary files /dev/null and b/xinha/images/ed_indent_more.gif differ diff --git a/xinha/images/ed_killword.gif b/xinha/images/ed_killword.gif new file mode 100644 index 0000000..d44e951 Binary files /dev/null and b/xinha/images/ed_killword.gif differ diff --git a/xinha/images/ed_left_to_right.gif b/xinha/images/ed_left_to_right.gif new file mode 100644 index 0000000..9edfa63 Binary files /dev/null and b/xinha/images/ed_left_to_right.gif differ diff --git a/xinha/images/ed_link.gif b/xinha/images/ed_link.gif new file mode 100644 index 0000000..76e568b Binary files /dev/null and b/xinha/images/ed_link.gif differ diff --git a/xinha/images/ed_list_bullet.gif b/xinha/images/ed_list_bullet.gif new file mode 100644 index 0000000..caedfd2 Binary files /dev/null and b/xinha/images/ed_list_bullet.gif differ diff --git a/xinha/images/ed_list_num.gif b/xinha/images/ed_list_num.gif new file mode 100644 index 0000000..427839d Binary files /dev/null and b/xinha/images/ed_list_num.gif differ diff --git a/xinha/images/ed_overwrite.gif b/xinha/images/ed_overwrite.gif new file mode 100644 index 0000000..0daf0a8 Binary files /dev/null and b/xinha/images/ed_overwrite.gif differ diff --git a/xinha/images/ed_paste.gif b/xinha/images/ed_paste.gif new file mode 100644 index 0000000..13e2324 Binary files /dev/null and b/xinha/images/ed_paste.gif differ diff --git a/xinha/images/ed_print.gif b/xinha/images/ed_print.gif new file mode 100644 index 0000000..f5bd102 Binary files /dev/null and b/xinha/images/ed_print.gif differ diff --git a/xinha/images/ed_redo.gif b/xinha/images/ed_redo.gif new file mode 100644 index 0000000..2bc002a Binary files /dev/null and b/xinha/images/ed_redo.gif differ diff --git a/xinha/images/ed_right_to_left.gif b/xinha/images/ed_right_to_left.gif new file mode 100644 index 0000000..231f183 Binary files /dev/null and b/xinha/images/ed_right_to_left.gif differ diff --git a/xinha/images/ed_rmformat.gif b/xinha/images/ed_rmformat.gif new file mode 100644 index 0000000..5d8ce2d Binary files /dev/null and b/xinha/images/ed_rmformat.gif differ diff --git a/xinha/images/ed_save.gif b/xinha/images/ed_save.gif new file mode 100644 index 0000000..df3aaab Binary files /dev/null and b/xinha/images/ed_save.gif differ diff --git a/xinha/images/ed_save.png b/xinha/images/ed_save.png new file mode 100644 index 0000000..881fe5d Binary files /dev/null and b/xinha/images/ed_save.png differ diff --git a/xinha/images/ed_saveas.gif b/xinha/images/ed_saveas.gif new file mode 100644 index 0000000..89d5a70 Binary files /dev/null and b/xinha/images/ed_saveas.gif differ diff --git a/xinha/images/ed_selectall.gif b/xinha/images/ed_selectall.gif new file mode 100644 index 0000000..1608e07 Binary files /dev/null and b/xinha/images/ed_selectall.gif differ diff --git a/xinha/images/ed_show_border.gif b/xinha/images/ed_show_border.gif new file mode 100644 index 0000000..9e3fdd2 Binary files /dev/null and b/xinha/images/ed_show_border.gif differ diff --git a/xinha/images/ed_splitblock.gif b/xinha/images/ed_splitblock.gif new file mode 100644 index 0000000..7a8e352 Binary files /dev/null and b/xinha/images/ed_splitblock.gif differ diff --git a/xinha/images/ed_splitcel.gif b/xinha/images/ed_splitcel.gif new file mode 100644 index 0000000..a619d8a Binary files /dev/null and b/xinha/images/ed_splitcel.gif differ diff --git a/xinha/images/ed_undo.gif b/xinha/images/ed_undo.gif new file mode 100644 index 0000000..f90faad Binary files /dev/null and b/xinha/images/ed_undo.gif differ diff --git a/xinha/images/ed_word_cleaner.gif b/xinha/images/ed_word_cleaner.gif new file mode 100644 index 0000000..500f8ee Binary files /dev/null and b/xinha/images/ed_word_cleaner.gif differ diff --git a/xinha/images/fullscreen_maximize.gif b/xinha/images/fullscreen_maximize.gif new file mode 100644 index 0000000..07620bc Binary files /dev/null and b/xinha/images/fullscreen_maximize.gif differ diff --git a/xinha/images/fullscreen_minimize.gif b/xinha/images/fullscreen_minimize.gif new file mode 100644 index 0000000..09c0383 Binary files /dev/null and b/xinha/images/fullscreen_minimize.gif differ diff --git a/xinha/images/insert_table.gif b/xinha/images/insert_table.gif new file mode 100644 index 0000000..027f7c8 Binary files /dev/null and b/xinha/images/insert_table.gif differ diff --git a/xinha/images/insertfilelink.gif b/xinha/images/insertfilelink.gif new file mode 100644 index 0000000..d4959ce Binary files /dev/null and b/xinha/images/insertfilelink.gif differ diff --git a/xinha/images/insertmacro.png b/xinha/images/insertmacro.png new file mode 100644 index 0000000..3c874be Binary files /dev/null and b/xinha/images/insertmacro.png differ diff --git a/xinha/images/tidy.gif b/xinha/images/tidy.gif new file mode 100644 index 0000000..2c6dcc4 Binary files /dev/null and b/xinha/images/tidy.gif differ diff --git a/xinha/images/toggle_borders.gif b/xinha/images/toggle_borders.gif new file mode 100644 index 0000000..7a43c6d Binary files /dev/null and b/xinha/images/toggle_borders.gif differ diff --git a/xinha/inline-dialog.js b/xinha/inline-dialog.js new file mode 100644 index 0000000..9efd444 --- /dev/null +++ b/xinha/inline-dialog.js @@ -0,0 +1,327 @@ + +HTMLArea.Dialog = function(editor, html, localizer) +{ + this.id = { }; + this.r_id = { }; // reverse lookup id + this.editor = editor; + this.document = document; + + this.rootElem = document.createElement('div'); + this.rootElem.className = 'dialog'; + this.rootElem.style.position = 'absolute'; + this.rootElem.style.display = 'none'; + this.editor._framework.ed_cell.insertBefore(this.rootElem, this.editor._framework.ed_cell.firstChild); + this.rootElem.style.width = this.width = this.editor._framework.ed_cell.offsetWidth + 'px'; + this.rootElem.style.height = this.height = this.editor._framework.ed_cell.offsetHeight + 'px'; + + var dialog = this; + if(typeof localizer == 'function') + { + this._lc = localizer; + } + else if(localizer) + { + this._lc = function(string) + { + return HTMLArea._lc(string,localizer); + } + } + else + { + this._lc = function(string) + { + return string; + } + } + + html = html.replace(/\[([a-z0-9_]+)\]/ig, + function(fullString, id) + { + if(typeof dialog.id[id] == 'undefined') + { + dialog.id[id] = HTMLArea.uniq('Dialog'); + dialog.r_id[dialog.id[id]] = id; + } + return dialog.id[id]; + } + ).replace(/(.*?)<\/l10n>/ig, + function(fullString,translate) + { + return dialog._lc(translate) ; + } + ).replace(/="_\((.*?)\)"/g, + function(fullString, translate) + { + return '="' + dialog._lc(translate) + '"'; + } + ); + + this.rootElem.innerHTML = html; + + + + + this.editor.notifyOn + ('resize', + function(e, args) + { + dialog.rootElem.style.width = dialog.width = dialog.editor._framework.ed_cell.offsetWidth + 'px'; + dialog.rootElem.style.height = dialog.height = dialog.editor._framework.ed_cell.offsetHeight + 'px'; + dialog.onresize(); + } + ); +} + +HTMLArea.Dialog.prototype.onresize = function() +{ + return true; +} + +HTMLArea.Dialog.prototype.show = function(values) +{ + // We need to preserve the selection for IE + if(HTMLArea.is_ie) + { + this._lastRange = this.editor._createRange(this.editor._getSelection()); + } + + if(typeof values != 'undefined') + { + this.setValues(values); + } + this._restoreTo = [this.editor._textArea.style.display, this.editor._iframe.style.visibility, this.editor.hidePanels()]; + + this.editor._textArea.style.display = 'none'; + this.editor._iframe.style.visibility = 'hidden'; + this.rootElem.style.display = ''; +} + +HTMLArea.Dialog.prototype.hide = function() +{ + this.rootElem.style.display = 'none'; + this.editor._textArea.style.display = this._restoreTo[0]; + this.editor._iframe.style.visibility = this._restoreTo[1]; + this.editor.showPanels(this._restoreTo[2]); + + // Restore the selection + if(HTMLArea.is_ie) + { + this._lastRange.select(); + } + this.editor.updateToolbar(); + return this.getValues(); +} + +HTMLArea.Dialog.prototype.toggle = function() +{ + if(this.rootElem.style.display == 'none') + { + this.show(); + } + else + { + this.hide(); + } +} + +HTMLArea.Dialog.prototype.setValues = function(values) +{ + for(var i in values) + { + var elems = this.getElementsByName(i); + if(!elems) continue; + for(var x = 0; x < elems.length; x++) + { + var e = elems[x]; + switch(e.tagName.toLowerCase()) + { + case 'select' : + { + for(var j = 0; j < e.options.length; j++) + { + if(typeof values[i] == 'object') + { + for(var k = 0; k < values[i].length; k++) + { + if(values[i][k] == e.options[j].value) + { + e.options[j].selected = true; + } + } + } + else if(values[i] == e.options[j].value) + { + e.options[j].selected = true; + } + } + break; + } + + + case 'textarea': + case 'input' : + { + switch(e.getAttribute('type')) + { + case 'radio' : + { + if(e.value == values[i]) + { + e.checked = true; + } + break; + } + + case 'checkbox': + { + if(typeof values[i] == 'object') + { + for(var j in values[i]) + { + if(values[i][j] == e.value) + { + e.checked = true; + } + } + } + else + { + if(values[i] == e.value) + { + e.checked = true; + } + } + break; + } + + default : + { + e.value = values[i]; + } + } + break; + } + + default : + break; + } + } + } +} + +HTMLArea.Dialog.prototype.getValues = function() +{ + var values = [ ]; + var inputs = HTMLArea.collectionToArray(this.rootElem.getElementsByTagName('input')) + .append(HTMLArea.collectionToArray(this.rootElem.getElementsByTagName('textarea'))) + .append(HTMLArea.collectionToArray(this.rootElem.getElementsByTagName('select'))); + + for(var x = 0; x < inputs.length; x++) + { + var i = inputs[x]; + if(!(i.name && this.r_id[i.name])) continue; + + if(typeof values[this.r_id[i.name]] == 'undefined') + { + values[this.r_id[i.name]] = null; + } + var v = values[this.r_id[i.name]]; + + switch(i.tagName.toLowerCase()) + { + case 'select': + { + if(i.multiple) + { + if(!v.push) + { + if(v != null) + { + v = [v]; + } + else + { + v = new Array(); + } + } + for(var j = 0; j < i.options.length; j++) + { + if(i.options[j].selected) + { + v.push(i.options[j].value); + } + } + } + else + { + if(i.selectedIndex >= 0) + { + v = i.options[i.selectedIndex]; + } + } + break; + } + + case 'textarea': + case 'input' : + default : + { + switch(i.type.toLowerCase()) + { + case 'radio': + { + if(i.checked) + { + v = i.value; + break; + } + } + + case 'checkbox': + { + if(v == null) + { + if(this.getElementsByName(this.r_id[i.name]).length > 1) + { + v = new Array(); + } + } + + if(i.checked) + { + if(v != null && typeof v == 'object' && v.push) + { + v.push(i.value); + } + else + { + v = i.value; + } + } + break; + } + + default : + { + v = i.value; + break; + } + } + } + + } + + values[this.r_id[i.name]] = v; + } + return values; +} + +HTMLArea.Dialog.prototype.getElementById = function(id) +{ + return this.document.getElementById(this.id[id] ? this.id[id] : id); +} + +HTMLArea.Dialog.prototype.getElementsByName = function(name) +{ + return this.document.getElementsByName(this.id[name] ? this.id[name] : name); +} diff --git a/xinha/lang/b5.js b/xinha/lang/b5.js new file mode 100644 index 0000000..86d1e65 --- /dev/null +++ b/xinha/lang/b5.js @@ -0,0 +1,29 @@ +// I18N constants -- UTF-8 +// by Dave Lo -- dlo@interactivetools.com +{ + "Bold": "ç²—é«”", + "Italic": "斜體", + "Underline": "底線", + "Strikethrough": "刪除線", + "Subscript": "下標", + "Superscript": "上標", + "Justify Left": "ä½ç½®é å·¦", + "Justify Center": "ä½ç½®å±…中", + "Justify Right": "ä½ç½®é å³", + "Justify Full": "ä½ç½®å·¦å³å¹³ç­‰", + "Ordered List": "é †åºæ¸…å–®", + "Bulleted List": "ç„¡åºæ¸…å–®", + "Decrease Indent": "減å°è¡Œå‰ç©ºç™½", + "Increase Indent": "加寬行å‰ç©ºç™½", + "Font Color": "文字é¡è‰²", + "Background Color": "背景é¡è‰²", + "Horizontal Rule": "水平線", + "Insert Web Link": "æ’入連çµ", + "Insert/Modify Image": "æ’入圖形", + "Insert Table": "æ’入表格", + "Toggle HTML Source": "切æ›HTML原始碼", + "Enlarge Editor": "放大", + "About this editor": "關於 HTMLArea", + "Help using editor": "說明", + "Current style": "字體例å­" +} diff --git a/xinha/lang/ch.js b/xinha/lang/ch.js new file mode 100644 index 0000000..a0fe7e5 --- /dev/null +++ b/xinha/lang/ch.js @@ -0,0 +1,56 @@ +// I18N constants + +// LANG: "ch", ENCODING: UTF-8 +// Samuel Stone, http://stonemicro.com/ + +{ + "Bold": "ç²—é«”", + "Italic": "斜體", + "Underline": "底線", + "Strikethrough": "刪線", + "Subscript": "下標", + "Superscript": "上標", + "Justify Left": "é å·¦", + "Justify Center": "居中", + "Justify Right": "é å³", + "Justify Full": "整齊", + "Ordered List": "é †åºæ¸…å–®", + "Bulleted List": "ç„¡åºæ¸…å–®", + "Decrease Indent": "伸排", + "Increase Indent": "縮排", + "Font Color": "文字é¡è‰²", + "Background Color": "背景é¡è‰²", + "Horizontal Rule": "水平線", + "Insert Web Link": "æ’入連çµ", + "Insert/Modify Image": "æ’入圖åƒ", + "Insert Table": "æ’入表格", + "Toggle HTML Source": "切æ›HTML原始碼", + "Enlarge Editor": "伸出編輯系統", + "About this editor": "關於 HTMLArea", + "Help using editor": "說明", + "Current style": "字體例å­", + "Undoes your last action": "回原", + "Redoes your last action": "釿¥", + "Cut selection": "剪制选项", + "Copy selection": "å¤åˆ¶é€‰é¡¹", + "Paste from clipboard": "贴上", + "Direction left to right": "从左到å³", + "Direction right to left": "从å³åˆ°å·¦", + "OK": "好", + "Cancel": "å–æ¶ˆ", + "Path": "途徑", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "你在用純字編輯方å¼. 用 [<>] 按鈕轉回 æ‰€è¦‹å³æ‰€å¾— 編輯方å¼.", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "æ•´é å¼åœ¨Internet Explorer 上常出å•題, 因為這是 Internet Explorer 的無åå•題,我們無法解決。你å¯èƒ½çœ‹è¦‹ä¸€äº›åžƒåœ¾ï¼Œæˆ–é‡åˆ°å…¶ä»–å•題。我們已警告了你. 如果è¦è½‰åˆ° æ­£é å¼ 請按 好.", + "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.": "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.", + "Cancel": "å–æ¶ˆ", + "Insert/Modify Link": "æ’å…¥/改寫連çµ", + "New window (_blank)": "新窗户(_blank)", + "None (use implicit)": "ç„¡(use implicit)", + "Other": "å…¶ä»–", + "Same frame (_self)": "本匡 (_self)", + "Target:": "目標匡:", + "Title (tooltip):": "主題 (tooltip):", + "Top frame (_top)": "上匡 (_top)", + "URL:": "ç¶²å€:", + "You must enter the URL where this link points to": "你必須輸入你è¦è¿žç»“的網å€" +} diff --git a/xinha/lang/cz.js b/xinha/lang/cz.js new file mode 100644 index 0000000..8cc7424 --- /dev/null +++ b/xinha/lang/cz.js @@ -0,0 +1,50 @@ +// I18N constants + +// LANG: "cz", ENCODING: UTF-8 +// Author: Jiri Löw, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "TuÄnÄ›", + "Italic": "Kurzíva", + "Underline": "Podtržení", + "Strikethrough": "PÅ™eÅ¡krtnutí", + "Subscript": "Dolní index", + "Superscript": "Horní index", + "Justify Left": "Zarovnat doleva", + "Justify Center": "Na stÅ™ed", + "Justify Right": "Zarovnat doprava", + "Justify Full": "Zarovnat do stran", + "Ordered List": "Seznam", + "Bulleted List": "Odrážky", + "Decrease Indent": "PÅ™edsadit", + "Increase Indent": "Odsadit", + "Font Color": "Barva písma", + "Background Color": "Barva pozadí", + "Horizontal Rule": "Vodorovná Äára", + "Insert Web Link": "Vložit odkaz", + "Insert/Modify Image": "Vložit obrázek", + "Insert Table": "Vložit tabulku", + "Toggle HTML Source": "PÅ™epnout HTML", + "Enlarge Editor": "Nové okno editoru", + "About this editor": "O této aplikaci", + "Help using editor": "NápovÄ›da aplikace", + "Current style": "Zvolený styl", + "Undoes your last action": "Vrátí poslední akci", + "Redoes your last action": "Opakuje poslední akci", + "Cut selection": "Vyjmout", + "Copy selection": "Kopírovat", + "Paste from clipboard": "Vložit", + "OK": "OK", + "Cancel": "ZruÅ¡it", + "Path": "Cesta", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Jste v TEXTOVÉM REŽIMU. Použijte tlaÄítko [<>] pro pÅ™epnutí do WYSIWIG." +} diff --git a/xinha/lang/da.js b/xinha/lang/da.js new file mode 100644 index 0000000..7d3d2fc --- /dev/null +++ b/xinha/lang/da.js @@ -0,0 +1,30 @@ +// LANG: "da", ENCODING: UTF-8 +// Author: rene, + +{ + "Bold": "Fed", + "Italic": "Kursiv", + "Underline": "Understregning", + "Strikethrough": "Overstregning ", + "Subscript": "Sænket skrift", + "Superscript": "Hævet skrift", + "Justify Left": "Venstrejuster", + "Justify Center": "Centrer", + "Justify Right": "Højrejuster", + "Justify Full": "Lige margener", + "Ordered List": "Opstilling med tal", + "Bulleted List": "Opstilling med punkttegn", + "Decrease Indent": "Formindsk indrykning", + "Increase Indent": "Forøg indrykning", + "Font Color": "Skriftfarve", + "Background Color": "Baggrundsfarve", + "Horizontal Rule": "Horisontal linie", + "Insert Web Link": "Indsæt hyperlink", + "Insert/Modify Image": "Indsæt billede", + "Insert Table": "Indsæt tabel", + "Toggle HTML Source": "HTML visning", + "Enlarge Editor": "Vis editor i popup", + "About this editor": "Om htmlarea", + "Help using editor": "Hjælp", + "Current style": "Anvendt stil" +} diff --git a/xinha/lang/de.js b/xinha/lang/de.js new file mode 100644 index 0000000..434d7d2 --- /dev/null +++ b/xinha/lang/de.js @@ -0,0 +1,138 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 + +{ + "Bold": "Fett", + "Italic": "Kursiv", + "Underline": "Unterstrichen", + "Strikethrough": "Durchgestrichen", + "Subscript": "Tiefgestellt", + "Superscript": "Hochgestellt", + "Justify Left": "Linksbündig", + "Justify Center": "Zentriert", + "Justify Right": "Rechtsbündig", + "Justify Full": "Blocksatz", + "Ordered List": "Nummerierte Liste", + "Bulleted List": "Aufzählungsliste", + "Decrease Indent": "Einzug verkleinern", + "Increase Indent": "Einzug vergrößern", + "Font Color": "Schriftfarbe", + "Background Color": "Hindergrundfarbe", + "Horizontal Rule": "Horizontale Linie", + "Insert Web Link": "Hyperlink einfügen", + "Insert/Modify Image": "Bild einfügen/verändern", + "Insert Table": "Tabelle einfügen", + "Toggle HTML Source": "HTML Quelltext ein/ausschalten", + "Enlarge Editor": "Editor vergrößern", + "About this editor": "Über diesen Editor", + "Help using editor": "Hilfe", + "Current style": "Derzeitiger Stil", + "Undoes your last action": "Rückgängig", + "Redoes your last action": "Wiederholen", + "Cut selection": "Ausschneiden", + "Copy selection": "Kopieren", + "Paste from clipboard": "Einfügen aus der Zwischenablage", + "Direction left to right": "Textrichtung von Links nach Rechts", + "Direction right to left": "Textrichtung von Rechts nach Links", + "Remove formatting": "Formatierung entfernen", + "Select all": "Alles markieren", + "Print document": "Dokument ausdrucken", + "Clear MSOffice tags": "MSOffice filter", + "Clear Inline Font Specifications": "Zeichensatz Formatierungen entfernen", + "Split Block": "Block teilen", + "Toggle Borders": "Tabellenränder ein/ausblenden", + "Save as": "speichern unter", + "Insert/Overwrite": "Einfügen/Überschreiben", + "— format —": "— Format —", + "Heading 1": "Überschrift 1", + "Heading 2": "Überschrift 2", + "Heading 3": "Überschrift 3", + "Heading 4": "Überschrift 4", + "Heading 5": "Überschrift 5", + "Heading 6": "Überschrift 6", + "Normal": "Normal (Absatz)", + "Address": "Adresse", + "Formatted": "Formatiert", + + //dialogs + "OK": "OK", + "Cancel": "Abbrechen", + "Path": "Pfad", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Sie sind im Text-Modus. Benutzen Sie den [<>] Button, um in den visuellen Modus (WYSIWIG) zu gelangen.", + "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.": "Aus Sicherheitsgründen dürfen Skripte normalerweise nicht auf Ausschneiden/Kopieren/Einfügen zugreifen. Bitte klicken Sie OK um die technische Erläuterung auf mozilla.org zu öffnen, in der erklärt wird, wie einem Skript Zugriff gewährt werden kann.", + + "You need to select some text before create a link": "Sie müssen einen Text markieren, um einen Link zu erstellen", + "Your Document is not well formed. Check JavaScript console for details.": "Ihr Dokument ist in keinem sauberen Format. Benutzen Sie die Javascript Console für weitere Informationen.", + + "Alignment:": "Ausrichtung:", + "Not set": "nicht eingestellt", + "Left": "links", + "Right": "rechts", + "Texttop": "oben bündig", + "Absmiddle": "mittig", + "Baseline": "Grundlinie", + "Absbottom": "unten bündig", + "Bottom": "unten", + "Middle": "zentriert", + "Top": "oben", + + "Layout": "Layout", + "Spacing": "Abstand", + "Horizontal:": "horizontal:", + "Horizontal padding": "horizontaler Inhaltsabstand", + "Vertical:": "vertikal:", + "Vertical padding": "vertikaler Inhaltsabstand", + "Border thickness:": "Randstärke:", + "Leave empty for no border": "leer lassen für keinen Rand", + + //Insert Link + "Insert/Modify Link": "Verknüpfung hinzufügen/ändern", + "None (use implicit)": "k.A. (implizit)", + "New window (_blank)": "Neues Fenster (_blank)", + "Same frame (_self)": "Selber Rahmen (_self)", + "Top frame (_top)": "Oberster Rahmen (_top)", + "Other": "Anderes", + "Target:": "Ziel:", + "Title (tooltip):": "Titel (Tooltip):", + "URL:": "URL:", + "You must enter the URL where this link points to": "Sie müssen eine Ziel-URL angeben für die Verknüpfung angeben", + + // Insert Table + "Insert Table": "Table einfügen", + "Rows:": "Zeilen:", + "Number of rows": "Zeilenanzahl", + "Cols:": "Spalten:", + "Number of columns": "Spaltenanzahl", + "Width:": "Breite:", + "Width of the table": "Tabellenbreite", + "Percent": "Prozent", + "Pixels": "Pixel", + "Em": "Geviert", + "Width unit": "Größeneinheit", + "Fixed width columns": "Spalten mit fester Breite", + "Positioning of this table": "Positionierung der Tabelle", + "Cell spacing:": "Zellenabstand:", + "Space between adjacent cells": "Raum zwischen angrenzenden Zellen", + "Cell padding:": "Innenabstand:", + "Space between content and border in cell": "Raum zwischen Inhalt und Rand der Zelle", + "You must enter a number of rows": "Bitte geben Sie die Anzahl der Zeilen an", + "You must enter a number of columns": "Bitte geben Sie die Anzahl der Spalten an", + + // Insert Image + "Insert Image": "Bild einfügen", + "Image URL:": "Bild URL:", + "Enter the image URL here": "Bitte geben sie hier die Bild URL ein", + "Preview": "Voransicht", + "Preview the image in a new window": "Voransicht des Bildes in einem neuen Fenster", + "Alternate text:": "Alternativer Text:", + "For browsers that don't support images": "für Browser, die keine Bilder unterstützen", + "Positioning of this image": "Positionierung dieses Bildes", + "Image Preview:": "Bild Voransicht:", + "You must enter the URL": "Bitte geben Sie die URL ein", + + "button_bold": "de/bold.gif", + "button_italic": "de/italic.gif", + "button_underline": "de/underline.gif" + +} \ No newline at end of file diff --git a/xinha/lang/ee.js b/xinha/lang/ee.js new file mode 100644 index 0000000..2534271 --- /dev/null +++ b/xinha/lang/ee.js @@ -0,0 +1,50 @@ +// I18N constants + +// LANG: "ee", ENCODING: UTF-8 +// Author: Martin Raie, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "Paks", + "Italic": "Kursiiv", + "Underline": "Allakriipsutatud", + "Strikethrough": "Läbikriipsutatud", + "Subscript": "Allindeks", + "Superscript": "Ülaindeks", + "Justify Left": "Joonda vasakule", + "Justify Center": "Joonda keskele", + "Justify Right": "Joonda paremale", + "Justify Full": "Rööpjoonda", + "Ordered List": "Nummerdus", + "Bulleted List": "Täpploend", + "Decrease Indent": "Vähenda taanet", + "Increase Indent": "Suurenda taanet", + "Font Color": "Fondi värv", + "Background Color": "Tausta värv", + "Horizontal Rule": "Horisontaaljoon", + "Insert Web Link": "Lisa viit", + "Insert/Modify Image": "Lisa pilt", + "Insert Table": "Lisa tabel", + "Toggle HTML Source": "HTML/tavaline vaade", + "Enlarge Editor": "Suurenda toimeti aken", + "About this editor": "Teave toimeti kohta", + "Help using editor": "Spikker", + "Current style": "Kirjastiil", + "Undoes your last action": "Võta tagasi", + "Redoes your last action": "Tee uuesti", + "Cut selection": "Lõika", + "Copy selection": "Kopeeri", + "Paste from clipboard": "Kleebi", + "OK": "OK", + "Cancel": "Loobu", + "Path": "Path", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Sa oled tekstireziimis. Kasuta nuppu [<>] lülitamaks tagasi WYSIWIG reziimi." +} diff --git a/xinha/lang/el.js b/xinha/lang/el.js new file mode 100644 index 0000000..bc3df96 --- /dev/null +++ b/xinha/lang/el.js @@ -0,0 +1,55 @@ +// I18N constants + +// LANG: "el", ENCODING: UTF-8 +// Author: Dimitris Glezos, dimitris@glezos.com + +{ + "Bold": "ΞˆΞ½Ο„ΞÎΞ½Ξ±", + "Italic": "Πλάγια", + "Underline": "Ξ�Ο€ΞÎΞ³ΟÂαμμισμένα", + "Strikethrough": "ΔιαγΟÂΞ±ΞΌΞΌΞ­Ξ½Ξ±", + "Subscript": "ΔΡίκτης", + "Superscript": "ΔΡίκτης", + "Justify Left": "ΣτΞÎίχιση Ξ‘ΟÂιστΡΟÂΞ¬", + "Justify Center": "ΣτΞÎίχιση ΞšΞ­Ξ½Ο„ΟÂΞÎ", + "Justify Right": "ΣτΞÎίχιση ΔΡξιά", + "Justify Full": "Ξ Ξ»Ξ�ΟÂΞ·Ο‚ ΣτΞÎίχιση", + "Ordered List": "Ξ‘ΟÂίθμηση", + "Bulleted List": "ΚΞÎυκκίδΡς", + "Decrease Indent": "ΞœΞ΅Ξ―Ο‰ΟƒΞ· ΕσΞÎχ�ς", + "Increase Indent": "Ξ‘ΟÂξηση ΕσΞÎχ�ς", + "Font Color": "Ξ§ΟÂώμα Ξ“ΟÂΞ±ΞΌΞΌΞ±Ο„ΞÎσΡιΟÂάς", + "Background Color": "Ξ§ΟÂώμα Ξ¦ΟŒΞ½Ο„ΞÎΟ…", + "Horizontal Rule": "ΟΟÂΞΉΞΆΟŒΞ½Ο„ΞΉΞ± Ξ“ΟÂΞ±ΞΌΞΌΞ�", + "Insert Web Link": "ΕισαγωγΞ� ΣυνδέσμΞÎΟ…", + "Insert/Modify Image": "ΕισαγωγΞ�/Ξ�ΟÂΞÎΟ€ΞÎΟ€ΞÎίηση Ξ•ΞΉΞΊΟŒΞ½Ξ±Ο‚", + "Insert Table": "ΕισαγωγΞ� Ξ Ξ―Ξ½Ξ±ΞΊΞ±", + "Toggle HTML Source": "ΕναλλαγΞ� σΡ/Ξ±Ο€ΟŒ HTML", + "Enlarge Editor": "ΞœΞ΅Ξ³Ξ­Ξ½ΞΈΟ…Ξ½ΟƒΞ· ΡπΡξΡΟÂγαστΞ�", + "About this editor": "ΠληΟÂΞÎΟ†ΞÎΟÂίΡς", + "Help using editor": "Ξ’ΞÎ�θΡια", + "Current style": "Ξ Ξ±ΟÂών στυλ", + "Undoes your last action": "ΑναίΟÂΡση τΡλΡυταίας ΡνέΟÂγΡιας", + "Redoes your last action": "ΕπαναφΞÎΟÂΞ¬ Ξ±Ο€ΟŒ Ξ±Ξ½Ξ±Ξ―ΟÂΡση", + "Cut selection": "ΑπΞÎΞΊΞÎπ�", + "Copy selection": "ΑντιγΟÂαφ�", + "Paste from clipboard": "Ξ•Ο€ΞΉΞΊΟŒΞ»Ξ»Ξ·ΟƒΞ·", + "Direction left to right": "ΞšΞ±Ο„Ξ΅ΟÂθυνση Ξ±ΟÂιστΡΟÂΞ¬ Ο€ΟÂΞÎΟ‚ δΡξιά", + "Direction right to left": "ΞšΞ±Ο„Ξ΅ΟÂθυνση Ξ±Ο€ΟŒ δΡξιά Ο€ΟÂΞÎΟ‚ τα Ξ±ΟÂιστΡΟÂΞ¬", + "OK": "OK", + "Cancel": "ΑκΟÂΟÂωση", + "Path": "ΔιαδΟÂΞÎΞΌΞ�", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "ΕίστΡ σΡ TEXT MODE. Ξ§ΟÂησιμΞÎΟ€ΞÎΞΉΞ�στΡ Ο„ΞΠΞΊΞÎυμπί [<>] Ξ³ΞΉΞ± Ξ½Ξ± ΡπανέΟÂθΡτΡ στΞΠWYSIWIG.", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "Ξ— κατάσταση πλΞ�ΟÂΞ·Ο‚ ΞÎΞΈΟŒΞ½Ξ·Ο‚ έχΡι Ο€ΟÂΞÎΞ²Ξ»Ξ�ματα ΞΌΞ΅ Ο„ΞÎΞ½ Internet Explorer, Ξ»ΟŒΞ³Ο‰ σφαλμάτων στΞÎΞ½ ίδιΞΠΟ„ΞÎΞ½ browser. Αν Ο„ΞΠΟƒΟÂστημα σας Ρίναι Windows 9x ΞΌΟ€ΞÎΟÂΡί ΞΊΞ±ΞΉ Ξ½Ξ± Ο‡ΟÂΡιαστΡίτΡ reboot. Αν ΡίστΡ σίγΞÎΟ…ΟÂΞÎΞΉ, πατΞ�στΡ ΟΚ.", + "Cancel": "ΑκΟÂΟÂωση", + "Insert/Modify Link": "ΕισαγωγΞ�/Ξ�ΟÂΞÎΟ€ΞÎΟ€ΞÎίηση ΟƒΟÂνδΡσμΞÎΟ…", + "New window (_blank)": "ΞÂΞ­ΞΠπαΟÂάθυΟÂΞΠ(_blank)", + "None (use implicit)": "Κανένα (Ο‡ΟÂΞ�ση Ξ±Ο€ΟŒΞ»Ο…Ο„ΞÎΟ…)", + "Other": "ΑλλΞÎ", + "Same frame (_self)": "ΊδιΞΠframe (_self)", + "Target:": "Target:", + "Title (tooltip):": "Ξ�ίτλΞÎΟ‚ (tooltip):", + "Top frame (_top)": "Πάνω frame (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Ξ ΟÂέπΡι Ξ½Ξ± ΡισάγΡτΡ Ο„ΞΠURL Ο€ΞÎΟ… ΞÎδηγΡί Ξ±Ο…Ο„ΟŒΟ‚ ΞΠΟƒΟÂνδΡσμΞÎΟ‚" +} diff --git a/xinha/lang/es.js b/xinha/lang/es.js new file mode 100644 index 0000000..885f0e0 --- /dev/null +++ b/xinha/lang/es.js @@ -0,0 +1,40 @@ +// I18N constants + +// LANG: "es", ENCODING: UTF-8 + +{ + "Bold": "Negrita", + "Italic": "Cursiva", + "Underline": "Subrayado", + "Strikethrough": "Tachado", + "Subscript": "Sub?ndice", + "Superscript": "Super?ndice", + "Justify Left": "Alinear a la Izquierda", + "Justify Center": "Centrar", + "Justify Right": "Alinear a la Derecha", + "Justify Full": "Justificar", + "Ordered List": "Lista Ordenada", + "Bulleted List": "Lista No Ordenada", + "Decrease Indent": "Aumentar Sangr?a", + "Increase Indent": "Disminuir Sangr?a", + "Font Color": "Color del Texto", + "Background Color": "Color del Fondo", + "Horizontal Rule": "L?nea Horizontal", + "Insert Web Link": "Insertar Enlace", + "Insert/Modify Image": "Insertar Imagen", + "Insert Table": "Insertar Tabla", + "Toggle HTML Source": "Ver Documento en HTML", + "Enlarge Editor": "Ampliar Editor", + "About this editor": "Acerca del Editor", + "Help using editor": "Ayuda", + "Current style": "Estilo Actual", + "Undoes your last action": "Deshacer", + "Redoes your last action": "Rehacer", + "Cut selection": "Cortar selecci?n", + "Copy selection": "Copiar selecci?n", + "Paste from clipboard": "Pegar desde el portapapeles", + "OK": "Aceptar", + "Cancel": "Cancelar", + "Path": "Ruta", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Esta en modo TEXTO. Use el boton [<>] para cambiar a WYSIWIG" +} diff --git a/xinha/lang/fi.js b/xinha/lang/fi.js new file mode 100644 index 0000000..e057b9a --- /dev/null +++ b/xinha/lang/fi.js @@ -0,0 +1,38 @@ +// I18N constants + +// LANG: "en", ENCODING: UTF-8 + +{ + "Bold": "Lihavoitu", + "Italic": "Kursivoitu", + "Underline": "Alleviivattu", + "Strikethrough": "Yliviivattu", + "Subscript": "Alaindeksi", + "Superscript": "Yläindeksi", + "Justify Left": "Tasaa vasemmat reunat", + "Justify Center": "Keskitä", + "Justify Right": "Tasaa oikeat reunat", + "Justify Full": "Tasaa molemmat reunat", + "Ordered List": "Numerointi", + "Bulleted List": "Luettelomerkit", + "Decrease Indent": "Pienennä sisennystä", + "Increase Indent": "Lisää sisennystä", + "Font Color": "Fontin väri", + "Background Color": "Taustaväri", + "Horizontal Rule": "Vaakaviiva", + "Insert Web Link": "Lisää linkki", + "Insert/Modify Image": "Lisää kuva", + "Insert Table": "Lisää taulukko", + "Toggle HTML Source": "HTML-lähdekoodi vs WYSIWYG", + "Enlarge Editor": "Suurenna editori", + "About this editor": "Tietoja editorista", + "Help using editor": "Näytä ohje", + "Current style": "Nykyinen tyyli", + "Undoes your last action": "Peruuta viimeinen toiminto", + "Redoes your last action": "Palauta viimeinen toiminto", + "Cut selection": "Leikkaa maalattu", + "Copy selection": "Kopioi maalattu", + "Paste from clipboard": "Liitä leikepyödältä", + "OK": "Hyväksy", + "Cancel": "Peruuta" +} diff --git a/xinha/lang/fr.js b/xinha/lang/fr.js new file mode 100644 index 0000000..3faec8b --- /dev/null +++ b/xinha/lang/fr.js @@ -0,0 +1,129 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + "Bold": "Gras", + "Italic": "Italique", + "Underline": "Souligné", + "Strikethrough": "Barré", + "Subscript": "Indice", + "Superscript": "Exposant", + "Justify Left": "Aligner à gauche", + "Justify Center": "Centrer", + "Justify Right": "Aligner à droite", + "Justify Full": "Justifier", + "Ordered List": "Numérotation", + "Bulleted List": "Puces", + "Decrease Indent": "Diminuer le retrait", + "Increase Indent": "Augmenter le retrait", + "Font Color": "Couleur de police", + "Background Color": "Surlignage", + "Horizontal Rule": "Ligne horizontale", + "Insert Web Link": "Insérer un lien", + "Insert/Modify Image": "Insérer / Modifier une image", + "Insert Table": "Insérer un tableau", + "Toggle HTML Source": "Afficher / Masquer code source", + "Enlarge Editor": "Agrandir l'éditeur", + "About this editor": "A propos", + "Help using editor": "Aide", + "Current style": "Style courant", + "Undoes your last action": "Annuler la dernière action", + "Redoes your last action": "Répéter la dernière action", + "Cut selection": "Couper la sélection", + "Copy selection": "Copier la sélection", + "Paste from clipboard": "Coller depuis le presse-papier", + "Direction left to right": "Direction de gauche à droite", + "Direction right to left": "Direction de droite à gauche", + "Remove formatting": "Supprimer mise en forme", + "Select all": "Tout sélectionner", + "Print document": "Imprimer document", + "Clear MSOffice tags": "Effacer tags MSOffice", + "Clear Inline Font Specifications": "Supprimer paramètres inline de la fonte", + "Split Block": "Séparer les blocks", + "Toggle Borders": "Afficher / Masquer les bordures", + "Save as": "Enregistrer sous", + "Insert/Overwrite": "Insertion / Remplacement", + "— format —": "— Format —", + "Heading 1": "Titre 1", + "Heading 2": "Titre 2", + "Heading 3": "Titre 3", + "Heading 4": "Titre 4", + "Heading 5": "Titre 5", + "Heading 6": "Titre 6", + "Normal": "Normal", + "Address": "Adresse", + "Formatted": "Formaté", + + //dialogs + "OK": "OK", + "Cancel": "Annuler", + "Path": "Chemin", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Vous êtes en MODE TEXTE. Appuyez sur le bouton [<>] pour retourner au mode WYSIWYG.", + "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.": "Le bouton Coller ne fonctionne pas sur les navigateurs basés sur Mozilla (pour des raisons de sécurité). Pressez simplement CTRL-V au clavier pour coller directement.", + "Your Document is not well formed. Check JavaScript console for details.": "Le document est mal formé. Vérifiez la console JavaScript pour plus de détail.", + + "Alignment:": "Alignement", + "Not set": "Indéfini", + "Left": "Gauche", + "Right": "Droite", + "Texttop": "Texttop", + "Absmiddle": "Absmiddle", + "Baseline": "Baseline", + "Absbottom": "Absbottom", + "Bottom": "Bas", + "Middle": "Milieu", + "Top": "Haut", + + "Layout": "Mise en page", + "Spacing": "Espacement", + "Horizontal:": "Horizontal", + "Horizontal padding": "Marge horizontale interne", + "Vertical:": "Vertical", + "Vertical padding": "Marge verticale interne", + "Border thickness:": "Epaisseur bordure", + "Leave empty for no border": "Laisser vide pour pas de bordure", + + //Insert Link + "Insert/Modify Link": "Insérer / Modifier un lien", + "None (use implicit)": "Aucune (implicite)", + "New window (_blank)": "Nouvelle fenêtre (_blank)", + "Same frame (_self)": "Même frame (_self)", + "Top frame (_top)": "Frame principale (_top)", + "Other": "Autre", + "Target:": "Cible", + "Title (tooltip):": "Text alternatif", + "URL:": "URL:", + "You must enter the URL where this link points to": "Vous devez entrer l'URL de ce lien", + + // Insert Table + "Insert Table": "Insérer un tableau", + "Rows:": "Lignes", + "Number of rows": "Nombre de lignes", + "Cols:": "Colonnes", + "Number of columns": "Nombre de colonnes", + "Width:": "Largeur", + "Width of the table": "Largeur du tableau", + "Percent": "Pourcent", + "Pixels": "Pixels", + "Em": "Em", + "Width unit": "Unités de largeur", + "Fixed width columns": "Colonnes à taille fixe", + "Positioning of this table": "Position du tableau", + "Cell spacing:": "Espacement", + "Space between adjacent cells": "Espace entre les cellules adjacentes", + "Cell padding:": "Marge interne", + "Space between content and border in cell": "Espace entre le contenu et la bordure d'une cellule", + "You must enter a number of rows": "Vous devez entrez le nombre de lignes", + "You must enter a number of columns": "Vous devez entrer le nombre de colonnes", + + // Insert Image + "Insert Image": "Insérer une image", + "Image URL:": "URL image", + "Enter the image URL here": "Entrer l'url de l'image ici", + "Preview": "Prévisualiser", + "Preview the image in a new window": "Prévisualiser l'image dans une nouvelle fenêtre", + "Alternate text:": "Text alternatif", + "For browsers that don't support images": "Pour les navigateurs qui ne supportent pas les images", + "Positioning of this image": "Position de l'image", + "Image Preview:": "Prévisualisation", + "You must enter the URL": "Vous devez entrer l'URL" +} \ No newline at end of file diff --git a/xinha/lang/gb.js b/xinha/lang/gb.js new file mode 100644 index 0000000..fdeebcd --- /dev/null +++ b/xinha/lang/gb.js @@ -0,0 +1,29 @@ +// I18N constants -- Chinese GB +// by Dave Lo -- dlo@interactivetools.com +{ + "Bold": "粗体", + "Italic": "斜体", + "Underline": "底线", + "Strikethrough": "删除线", + "Subscript": "下标", + "Superscript": "上标", + "Justify Left": "ä½ç½®é å·¦", + "Justify Center": "ä½ç½®å±…中", + "Justify Right": "ä½ç½®é å³", + "Justify Full": "ä½ç½®å·¦å³å¹³ç­‰", + "Ordered List": "é¡ºåºæ¸…å•", + "Bulleted List": "æ— åºæ¸…å•", + "Decrease Indent": "å‡å°è¡Œå‰ç©ºç™½", + "Increase Indent": "加宽行å‰ç©ºç™½", + "Font Color": "文字颜色", + "Background Color": "背景颜色", + "Horizontal Rule": "水平线", + "Insert Web Link": "æ’入连结", + "Insert/Modify Image": "æ’入图形", + "Insert Table": "æ’入表格", + "Toggle HTML Source": "切æ¢HTML原始ç ", + "Enlarge Editor": "放大", + "About this editor": "关於 HTMLArea", + "Help using editor": "说明", + "Current style": "字体例å­" +} diff --git a/xinha/lang/he.js b/xinha/lang/he.js new file mode 100644 index 0000000..e39d3fc --- /dev/null +++ b/xinha/lang/he.js @@ -0,0 +1,64 @@ +// I18N constants + +// LANG: "he", ENCODING: UTF-8 +// Author: Liron Newman, http://www.eesh.net, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "מודגש", + "Italic": "נטוי", + "Underline": "קו תחתי", + "Strikethrough": "קו ×מצע", + "Subscript": "כתב עילי", + "Superscript": "כתב תחתי", + "Justify Left": " ישור לשמ×ל", + "Justify Center": "ישור למרכז", + "Justify Right": "ישור לימין", + "Justify Full": "ישור לשורה מל××”", + "Ordered List": "רשימה ממוספרת", + "Bulleted List": "רשימה ×œ× ×ž×ž×•×¡×¤×¨×ª", + "Decrease Indent": "הקטן כניסה", + "Increase Indent": "הגדל כניסה", + "Font Color": "צבע גופן", + "Background Color": "צבע רקע", + "Horizontal Rule": "קו ×× ×›×™", + "Insert Web Link": "הכנס היפר-קישור", + "Insert/Modify Image": "הכנס/שנה תמונה", + "Insert Table": "הכנס טבלה", + "Toggle HTML Source": "שנה מצב קוד HTML", + "Enlarge Editor": "הגדל ×ת העורך", + "About this editor": "×ודות עורך ×–×”", + "Help using editor": "עזרה לשימוש בעורך", + "Current style": "סגנון נוכחי", + "Undoes your last action": "מבטל ×ת פעולתך ×”×חרונה", + "Redoes your last action": "מבצע מחדש ×ת הפעולה ×”×חרונה שביטלת", + "Cut selection": "גזור בחירה", + "Copy selection": "העתק בחירה", + "Paste from clipboard": "הדבק מהלוח", + "Direction left to right": "כיוון משמ×ל לימין", + "Direction right to left": "כיוון מימין לשמ×ל", + "OK": "×ישור", + "Cancel": "ביטול", + "Path": "נתיב עיצוב", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "×תה במצב טקסט × ×§×™ (קוד). השתמש בכפתור [<>] כדי לחזור למצב WYSIWYG (תצוגת עיצוב).", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "מצב מסך ×ž×œ× ×™×•×¦×¨ בעיות בדפדפן Internet Explorer, עקב ב××’×™× ×‘×“×¤×“×¤×Ÿ ×œ× ×™×›×•×œ× ×• לפתור ×ת ×–×”. ×ת/×” עלול/×” לחוות תצוגת זבל, בעיות בתפקוד העורך ו/×ו קריסה של הדפדפן. ×× ×”×ž×¢×¨×›×ª שלך ×”×™× Windows 9x סביר להניח שתקבל/×™ ", + "Cancel": "ביטול", + "Insert/Modify Link": "הוסף/שנה קישור", + "New window (_blank)": "חלון חדש (_blank)", + "None (use implicit)": "×œ×œ× (השתמש ב-frame ×”×§×™×™×)", + "Other": "×חר", + "Same frame (_self)": "×ותו frame (_self)", + "Target:": "יעד:", + "Title (tooltip):": "כותרת (tooltip):", + "Top frame (_top)": "Frame עליון (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "חובה לכתוב URL ש×ליו קישור ×–×” מצביע" +} diff --git a/xinha/lang/hu.js b/xinha/lang/hu.js new file mode 100644 index 0000000..a4b1fa4 --- /dev/null +++ b/xinha/lang/hu.js @@ -0,0 +1,64 @@ +// I18N constants + +// LANG: "hu", ENCODING: UTF-8 +// Author: Miklós Somogyi, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "Félkövér", + "Italic": "DÅ‘lt", + "Underline": "Aláhúzott", + "Strikethrough": "Ãthúzott", + "Subscript": "Alsó index", + "Superscript": "FelsÅ‘ index", + "Justify Left": "Balra zárt", + "Justify Center": "Középre zárt", + "Justify Right": "Jobbra zárt", + "Justify Full": "Sorkizárt", + "Ordered List": "Számozott lista", + "Bulleted List": "Számozatlan lista", + "Decrease Indent": "Behúzás csökkentése", + "Increase Indent": "Behúzás növelése", + "Font Color": "Karakterszín", + "Background Color": "Háttérszín", + "Horizontal Rule": "Elválasztó vonal", + "Insert Web Link": "Hiperhivatkozás beszúrása", + "Insert/Modify Image": "Kép beszúrása", + "Insert Table": "Táblázat beszúrása", + "Toggle HTML Source": "HTML forrás be/ki", + "Enlarge Editor": "SzerkesztÅ‘ külön ablakban", + "About this editor": "Névjegy", + "Help using editor": "Súgó", + "Current style": "Aktuális stílus", + "Undoes your last action": "Visszavonás", + "Redoes your last action": "Újra végrehajtás", + "Cut selection": "Kivágás", + "Copy selection": "Másolás", + "Paste from clipboard": "Beillesztés", + "Direction left to right": "Irány balról jobbra", + "Direction right to left": "Irány jobbról balra", + "OK": "Rendben", + "Cancel": "Mégsem", + "Path": "Hierarchia", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Forrás mód. Visszaváltás [<>] gomb", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "A teljesképrenyÅ‘s szerkesztés hibát okozhat Internet Explorer használata esetén, ez a böngészÅ‘ a hibája, amit nem tudunk kikerülni. Szemetet észlelhet a képrenyÅ‘n, illetve néhány funkció hiányozhat és/vagy véletlenszerűen lefagyhat a böngészÅ‘. Windows 9x operaciós futtatása esetén elég valószínű, hogy ", + "Cancel": "Mégsem", + "Insert/Modify Link": "Hivatkozás Beszúrása/Módosítása", + "New window (_blank)": "Új ablak (_blank)", + "None (use implicit)": "Nincs (use implicit)", + "Other": "Más", + "Same frame (_self)": "Ugyanabba a keretbe (_self)", + "Target:": "Cél:", + "Title (tooltip):": "Cím (tooltip):", + "Top frame (_top)": "FelsÅ‘ keret (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Be kell írnia az URL-t, ahova a hivatkozás mutasson" +} diff --git a/xinha/lang/it.js b/xinha/lang/it.js new file mode 100644 index 0000000..15e346e --- /dev/null +++ b/xinha/lang/it.js @@ -0,0 +1,55 @@ +// I18N constants + +// LANG: "it", ENCODING: UTF-8 +// Author: Mattia Landoni, http://www.webpresident.org/ + +{ + "Bold": "Grassetto", + "Italic": "Corsivo", + "Underline": "Sottolineato", + "Strikethrough": "Barrato", + "Subscript": "Pedice", + "Superscript": "Apice", + "Justify Left": "Sinistra", + "Justify Center": "Centrato", + "Justify Right": "Destra", + "Justify Full": "Giustificato", + "Ordered List": "Lista numerata", + "Bulleted List": "Lista non numerata", + "Decrease Indent": "Diminuisci indentazione", + "Increase Indent": "Aumenta indentazione", + "Font Color": "Colore font", + "Background Color": "Colore sfondo", + "Horizontal Rule": "Righello orizzontale", + "Insert Web Link": "Inserisci link", + "Insert/Modify Image": "Inserisci/modifica Immagine", + "Insert Table": "Inserisci tabella", + "Toggle HTML Source": "Visualizza/nascondi sorgente HTML", + "Enlarge Editor": "Allarga editor", + "About this editor": "Informazioni su HTMLArea", + "Help using editor": "Aiuto", + "Current style": "Stile corrente", + "Undoes your last action": "Annulla ultima azione", + "Redoes your last action": "Ripeti ultima azione", + "Cut selection": "Taglia", + "Copy selection": "Copia", + "Paste from clipboard": "Incolla", + "Direction left to right": "Testo da sx a dx", + "Direction right to left": "Testo da dx a sx", + "OK": "OK", + "Cancel": "Annulla", + "Path": "Percorso", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Sei in MODALITA", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "E", + "Cancel": "Annulla", + "Insert/Modify Link": "Inserisci/modifica link", + "New window (_blank)": "Nuova finestra (_blank)", + "None (use implicit)": "Niente (usa implicito)", + "Other": "Altro", + "Same frame (_self)": "Stessa frame (_self)", + "Target:": "Target:", + "Title (tooltip):": "Title (suggerimento):", + "Top frame (_top)": "Pagina intera (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Devi inserire l'indirizzo a cui punta il link" +} diff --git a/xinha/lang/ja.js b/xinha/lang/ja.js new file mode 100644 index 0000000..e7f1520 --- /dev/null +++ b/xinha/lang/ja.js @@ -0,0 +1,30 @@ +// I18N constants -- Japanese UTF-8 +// by Manabu Onoue -- tmocsys@tmocsys.com + +{ + "Bold": "太字", + "Italic": "斜体", + "Underline": "下線", + "Strikethrough": "æ‰“ã¡æ¶ˆã—ç·š", + "Subscript": "ä¸‹ä»˜ãæ·»ãˆå­—", + "Superscript": "ä¸Šä»˜ãæ·»ãˆå­—", + "Justify Left": "左寄ã›", + "Justify Center": "中央寄ã›", + "Justify Right": "å³å¯„ã›", + "Justify Full": "å‡ç­‰å‰²ä»˜", + "Ordered List": "番å·ä»˜ãç®‡æ¡æ›¸ã", + "Bulleted List": "記å·ä»˜ãç®‡æ¡æ›¸ã", + "Decrease Indent": "インデント解除", + "Increase Indent": "インデント設定", + "Font Color": "文字色", + "Background Color": "背景色", + "Horizontal Rule": "水平線", + "Insert Web Link": "リンク作æˆ", + "Insert/Modify Image": "ç”»åƒæŒ¿å…¥", + "Insert Table": "テーブル挿入", + "Toggle HTML Source": "HTML表示切替", + "Enlarge Editor": "エディタ拡大", + "About this editor": "ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…å ±", + "Help using editor": "ヘルプ", + "Current style": "ç¾åœ¨ã®ã‚¹ã‚¿ã‚¤ãƒ«" +} diff --git a/xinha/lang/lt.js b/xinha/lang/lt.js new file mode 100644 index 0000000..ea34009 --- /dev/null +++ b/xinha/lang/lt.js @@ -0,0 +1,53 @@ +// I18N constants + +// LANG: "lt", ENCODING: UTF-8 +// Author: Jaroslav Å atkeviÄ, + +{ + "Bold": "ParyÅ¡kinti", + "Italic": "Kursyvas", + "Underline": "Pabraukti", + "Strikethrough": "Perbraukti", + "Subscript": "Apatinis indeksas", + "Superscript": "VirÅ¡utinis indeksas", + "Justify Left": "Lygiavimas pagal kairÄ™", + "Justify Center": "Lygiavimas pagal centrÄ…", + "Justify Right": "Lygiavimas pagal deÅ¡inÄ™", + "Justify Full": "Lygiuoti pastraipÄ…", + "Ordered List": "Numeruotas sÄ…raÅ¡as", + "Bulleted List": "Suženklintas sÄ…raÅ¡as", + "Decrease Indent": "Sumažinti paraÅ¡tÄ™", + "Increase Indent": "Padidinti paraÅ¡tÄ™", + "Font Color": "Å rifto spalva", + "Background Color": "Fono spalva", + "Horizontal Rule": "Horizontali linija", + "Insert Web Link": "Ä®terpti nuorodÄ…", + "Insert/Modify Image": "Ä®terpti paveiksliukÄ…", + "Insert Table": "Ä®terpti lentelÄ™", + "Toggle HTML Source": "Perjungti į HTML/WYSIWYG", + "Enlarge Editor": "IÅ¡plÄ—stas redagavimo ekranas/Enlarge Editor", + "About this editor": "Apie redaktorių", + "Help using editor": "Pagalba naudojant redaktorių", + "Current style": "Dabartinis stilius", + "Undoes your last action": "AtÅ¡aukia paskutini jÅ«sų veiksmÄ…", + "Redoes your last action": "Pakartoja paskutinį atÅ¡auktÄ… jÅ«sų veiksmÄ…", + "Cut selection": "IÅ¡kirpti", + "Copy selection": "Kopijuoti", + "Paste from clipboard": "Ä®terpti", + "OK": "OK", + "Cancel": "AtÅ¡aukti", + "Path": "Kelias", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "JÅ«s esete teksto režime. Naudokite [<>] mygtukÄ… grįžimui į WYSIWYG.", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren", + "Cancel": "AtÅ¡aukti", + "Insert/Modify Link": "IdÄ—ti/Modifikuoti", + "New window (_blank)": "Naujas langas (_blank)", + "None (use implicit)": "None (use implicit)", + "Other": "Kitas", + "Same frame (_self)": "Same frame (_self)", + "Target:": "Target:", + "Title (tooltip):": "Pavadinimas (tooltip):", + "Top frame (_top)": "Top frame (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Jus privalote nurodyti URL į kuri rodo Å¡itÄ… nuoroda" +} diff --git a/xinha/lang/lv.js b/xinha/lang/lv.js new file mode 100644 index 0000000..840b4e7 --- /dev/null +++ b/xinha/lang/lv.js @@ -0,0 +1,42 @@ +// I18N constants + +// LANG: "lv", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo +// Translated by: Janis Klavins, + +{ + "Bold": "Trekniem burtiem", + "Italic": "Kursîvâ", + "Underline": "Pasvîtrots", + "Strikethrough": "Pârsvîtrots", + "Subscript": "Novietot zem rindas", + "Superscript": "Novietot virs rindas", + "Justify Left": "Izlîdzinât pa kreisi", + "Justify Center": "Izlîdzinât centrâ", + "Justify Right": "Izlîdzinât pa labi", + "Justify Full": "Izlîdzinât pa visu lapu", + "Ordered List": "Numurçts saraksts", + "Bulleted List": "Saraksts", + "Decrease Indent": "Samazinât atkâpi", + "Increase Indent": "Palielinât atkâpi", + "Font Color": "Burtu krâsa", + "Background Color": "Fona krâsa", + "Horizontal Rule": "Horizontâla atdalîtâjsvîtra", + "Insert Web Link": "Ievietot hipersaiti", + "Insert/Modify Image": "Ievietot attçlu", + "Insert Table": "Ievietot tabulu", + "Toggle HTML Source": "Skatît HTML kodu", + "Enlarge Editor": "Palielinât Rediìçtâju", + "About this editor": "Par ðo rediìçtâju", + "Help using editor": "Rediìçtâja palîgs", + "Current style": "Patreizçjais stils", + "Undoes your last action": "Atcelt pçdçjo darbîbu", + "Redoes your last action": "Atkârtot pçdçjo darbîbu", + "Cut selection": "Izgriezt iezîmçto", + "Copy selection": "Kopçt iezîmçto", + "Paste from clipboard": "Ievietot iezîmçto", + "OK": "Labi", + "Cancel": "Atcelt", + "Path": "Ceïð", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Jûs patlaban darbojaties TEKSTA REÞÎMÂ. Lai pârietu atpakaï uz GRAFISKO REÞÎMU (WYSIWIG), lietojiet [<>] pogu." +} diff --git a/xinha/lang/nb.js b/xinha/lang/nb.js new file mode 100644 index 0000000..835b9a8 --- /dev/null +++ b/xinha/lang/nb.js @@ -0,0 +1,31 @@ +// I18N constants + +// LANG: "en", ENCODING: UTF-8 + +{ + "Bold": "Fet", + "Italic": "Kursiv", + "Underline": "Understreket", + "Strikethrough": "Gjennomstreket", + "Subscript": "Senket", + "Superscript": "Hevet", + "Justify Left": "Venstrejuster", + "Justify Center": "Midtjuster", + "Justify Right": "Høyrejuster", + "Justify Full": "Blokkjuster", + "Ordered List": "Nummerert liste", + "Bulleted List": "Punktmerket liste", + "Decrease Indent": "Øke innrykk", + "Increase Indent": "Reduser innrykk", + "Font Color": "Skriftfarge", + "Background Color": "Bakgrunnsfarge", + "Horizontal Rule": "Horisontal linje", + "Insert Web Link": "Sett inn lenke", + "Insert/Modify Image": "Sett inn bilde", + "Insert Table": "Sett inn tabell", + "Toggle HTML Source": "Vis HTML kode", + "Enlarge Editor": "Forstørr redigeringsvindu", + "About this editor": "Om..", + "Help using editor": "Hjelp", + "Current style": "Gjeldende stil" +} diff --git a/xinha/lang/nl.js b/xinha/lang/nl.js new file mode 100644 index 0000000..4b4f721 --- /dev/null +++ b/xinha/lang/nl.js @@ -0,0 +1,64 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "Vet", + "Italic": "Cursief", + "Underline": "Onderstrepen", + "Strikethrough": "Doorhalen", + "Subscript": "Subscript", + "Superscript": "Superscript", + "Justify Left": "Links uitlijnen", + "Justify Center": "Centreren", + "Justify Right": "Rechts uitlijnen", + "Justify Full": "Uitvullen", + "Ordered List": "Nummering", + "Bulleted List": "Opsommingstekens", + "Decrease Indent": "Inspringing verkleinen", + "Increase Indent": "Inspringing vergroten", + "Font Color": "Tekstkleur", + "Background Color": "Achtergrondkleur", + "Horizontal Rule": "Horizontale lijn", + "Insert Web Link": "Hyperlink invoegen/aanpassen", + "Insert/Modify Image": "Afbeelding invoegen/aanpassen", + "Insert Table": "Tabel invoegen", + "Toggle HTML Source": "HTML broncode", + "Enlarge Editor": "Vergroot Editor", + "About this editor": "Over deze editor", + "Help using editor": "HTMLArea help", + "Current style": "Huidige stijl", + "Undoes your last action": "Ongedaan maken", + "Redoes your last action": "Herhalen", + "Cut selection": "Knippen", + "Copy selection": "Kopi?ren", + "Paste from clipboard": "Plakken", + "Direction left to right": "Tekstrichting links naar rechts", + "Direction right to left": "Tekstrichting rechts naar links", + "OK": "OK", + "Cancel": "Annuleren", + "Path": "Pad", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Je bent in TEKST-mode. Gebruik de [<>] knop om terug te keren naar WYSIWYG-mode.", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "Fullscreen-mode veroorzaakt problemen met Internet Explorer door bugs in de webbrowser die we niet kunnen omzeilen. Hierdoor kunnen de volgende effecten optreden: verknoeide teksten, een verlies aan editor-functionaliteit en/of willekeurig vastlopen van de webbrowser. Als u Windows 95 of 98 gebruikt, is het zeer waarschijnlijk dat u een algemene beschermingsfout (", + "Cancel": "Annuleren", + "Insert/Modify Link": "Hyperlink invoegen/aanpassen", + "New window (_blank)": "Nieuw venster (_blank)", + "None (use implicit)": "Geen", + "Other": "Ander", + "Same frame (_self)": "Zelfde frame (_self)", + "Target:": "Doel:", + "Title (tooltip):": "Titel (tooltip):", + "Top frame (_top)": "Bovenste frame (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Geef de URL in waar de link naar verwijst" +} diff --git a/xinha/lang/no.js b/xinha/lang/no.js new file mode 100644 index 0000000..8f7a905 --- /dev/null +++ b/xinha/lang/no.js @@ -0,0 +1,61 @@ +// I18N constants + +// LANG: "no", ENCODING: UTF-8 + +// - translated by ses +// Additional translations by HÃ¥vard Wigtil +// Additional translations by Kim Steinhaug + +{ + "Bold": "Fet", + "Italic": "Kursiv", + "Underline": "Understreket", + "Strikethrough": "Gjennomstreket", + "Subscript": "Nedsenket", + "Superscript": "Opphøyet", + "Justify Left": "Venstrejuster", + "Justify Center": "Midtjuster", + "Justify Right": "Høyrejuster", + "Justify Full": "Blokkjuster", + "Ordered List": "Nummerert liste", + "Bulleted List": "Punktliste", + "Decrease Indent": "Reduser innrykk", + "Increase Indent": "Øke innrykk", + "Font Color": "Tekstfarge", + "Background Color": "Bakgrundsfarge", + "Horizontal Rule": "Vannrett linje", + "Insert Web Link": "Lag lenke", + "Insert/Modify Image": "Sett inn bilde", + "Insert Table": "Sett inn tabell", + "Toggle HTML Source": "Vis kildekode", + "Enlarge Editor": "Vis i eget vindu", + "About this editor": "Om denne editor", + "Help using editor": "Hjelp", + "Current style": "NÃ¥værende stil", + "Undoes your last action": "Angrer siste redigering", + "Redoes your last action": "Gjør om siste angring", + "Cut selection": "Klipp ut omrÃ¥de", + "Copy selection": "Kopier omrÃ¥de", + "Save as": "Lagre som", + "Paste from clipboard": "Lim inn", + "Remove formatting": "Fjern formattering", + "Direction left to right": "Fra venstre mot høyre", + "Direction right to left": "Fra høyre mot venstre", + "Insert/Overwrite": "Sett inn/Overskriv", + "OK": "OK", + "Cancel": "Avbryt", + "Path": "Tekstvelger", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Du er i tekstmodus Klikk pÃ¥ [<>] for Ã¥ gÃ¥ tilbake til WYSIWIG.", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "Visning i eget vindu har kjente problemer med Internet Explorer, pÃ¥ grunn av problemer med denne nettleseren. Mulige problemer er et uryddig skjermbilde, manglende editorfunksjoner og/eller at nettleseren crasher. Hvis du bruker Windows 95 eller Windows 98 er det ogsÃ¥ muligheter for at Windows will crashe.\n\nTrykk ", + "Cancel": "Avbryt", + "Insert/Modify Link": "Rediger lenke", + "New window (_blank)": "Eget vindu (_blank)", + "None (use implicit)": "Ingen (bruk standardinnstilling)", + "Other": "Annen", + "Same frame (_self)": "Samme ramme (_self)", + "Target:": "MÃ¥l:", + "Title (tooltip):": "Tittel (tooltip):", + "Top frame (_top)": "Toppramme (_top)", + "URL:": "Adresse:", + "You must enter the URL where this link points to": "Du mÃ¥ skrive inn en adresse som denne lenken skal peke til" +} diff --git a/xinha/lang/pl.js b/xinha/lang/pl.js new file mode 100644 index 0000000..0bb858f --- /dev/null +++ b/xinha/lang/pl.js @@ -0,0 +1,125 @@ +// I18N constants +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, http://www.eskot.krakow.pl/portfolio/, koto@webworkers.pl +{ + "Bold": "Pogrubienie", + "Italic": "Pochylenie", + "Underline": "PodkreÅ›lenie", + "Strikethrough": "PrzekreÅ›lenie", + "Subscript": "Indeks dolny", + "Superscript": "Indeks górny", + "Justify Left": "Wyrównaj do lewej", + "Justify Center": "WyÅ›rodkuj", + "Justify Right": "Wyrównaj do prawej", + "Justify Full": "Wyjustuj", + "Ordered List": "Numerowanie", + "Bulleted List": "Wypunktowanie", + "Decrease Indent": "Zmniejsz wciÄ™cie", + "Increase Indent": "ZwiÄ™ksz wciÄ™cie", + "Font Color": "Kolor czcionki", + "Background Color": "Kolor tÅ‚a", + "Horizontal Rule": "Linia pozioma", + "Insert Web Link": "Wstaw adres sieci Web", + "Insert/Modify Image": "Wstaw obraz", + "Insert Table": "Wstaw tabelÄ™", + "Toggle HTML Source": "Edycja WYSIWYG/w źródle strony", + "Enlarge Editor": "PeÅ‚ny ekran", + "About this editor": "Informacje o tym edytorze", + "Help using editor": "Pomoc", + "Current style": "Obecny styl", + "Undoes your last action": "Cofa ostatnio wykonane polecenie", + "Redoes your last action": "Ponawia ostatnio wykonane polecenie", + "Cut selection": "Wycina zaznaczenie do schowka", + "Copy selection": "Kopiuje zaznaczenie do schowka", + "Paste from clipboard": "Wkleja zawartość schowka", + "Direction left to right": "Kierunek tekstu lewo-prawo", + "Direction right to left": "Kierunek tekstu prawo-lewo", + "Remove formatting": "UsuÅ„ formatowanie", + "Select all": "Zaznacz wszystko", + "Print document": "Drukuj dokument", + "Clear MSOffice tags": "Wyczyść tagi MSOffice", + "Clear Inline Font Specifications": "Wycisz bezpoÅ›rednie przypisania czcionek", + "Split Block": "Podziel blok", + "Toggle Borders": "Włącz / wyłącz ramki", + + "— format —": "— Format —", + "Heading 1": "Nagłówek 1", + "Heading 2": "Nagłówek 2", + "Heading 3": "Nagłówek 3", + "Heading 4": "Nagłówek 4", + "Heading 5": "Nagłówek 5", + "Heading 6": "Nagłówek 6", + "Normal": "Normalny", + "Address": "Adres", + "Formatted": "Preformatowany", + + //dialogs + "OK": "OK", + "Cancel": "Anuluj", + "Path": "Åšcieżka", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "JesteÅ› w TRYBIE TEKSTOWYM. Użyj przycisku [<>], aby przełączyć siÄ™ na tryb WYSIWYG.", + "The Paste button does not work in Mozilla based web browsers (technical security reasons). Press CTRL-V on your keyboard to paste directly.": "Przycisk Wklej nie dziaÅ‚a w przeglÄ…darkach Mozilla z uwagi na ustawienia bezpieczeÅ„stwa. NaciÅ›nij CRTL-V, aby wkleić zawartość schowka.", + + "Alignment:": "Wyrównanie:", + "Not set": "Nie ustawione", + "Left": "Do lewej", + "Right": "Do prawej", + "Texttop": "Góra tekstu", + "Absmiddle": "Absolutny Å›rodek", + "Baseline": "Linia bazowa", + "Absbottom": "Absolutny dół", + "Bottom": "Dół", + "Middle": "Åšrodek", + "Top": "Góra", + + "Layout": "Layout", + "Spacing": "Spacjowanie", + "Horizontal:": "Poziome:", + "Horizontal padding": "WciÄ™cie poziome", + "Vertical:": "Pionowe:", + "Vertical padding": "WciÄ™cie pionowe", + "Border thickness:": "Grubość obramowania:", + "Leave empty for no border": "Bez ramek - zostaw puste", + + //Insert Link + "Insert/Modify Link": "Wstaw/edytuj odnoÅ›nik", + "None (use implicit)": "Brak", + "New window (_blank)": "Nowe okno (_blank)", + "Same frame (_self)": "Ta sama ramka (_self)", + "Top frame (_top)": "Główna ramka (_top)", + "Other": "Inne", + "Target:": "Okno docelowe:", + "Title (tooltip):": "TytuÅ‚ (tooltip):", + "URL:": "URL:", + "You must enter the URL where this link points to": "Musisz podać URL, na jaki bÄ™dzie wskazywaÅ‚ odnoÅ›nik", + + // Insert Table + "Insert Table": "Wstaw tabelÄ™", + "Rows:": "Wierszy:", + "Number of rows": "Liczba wierszy", + "Cols:": "Kolumn:", + "Number of columns": "Liczba kolumn", + "Width:": "Szerokość:", + "Width of the table": "Szerokość tabeli", + "Percent": "Procent", + "Pixels": "Pikseli", + "Em": "Em", + "Width unit": "Jednostka", + "Fixed width columns": "Kolumny o staÅ‚ej szerokoÅ›ci", + "Positioning of this table": "Pozycjonowanie tabeli", + "Cell spacing:": "Spacjowanie komórek:", + "Space between adjacent cells": "PrzestrzeÅ„ pomiÄ™dzy komórkami", + "Cell padding:": "WciÄ™cie komórek:", + "Space between content and border in cell": "PrzestrzeÅ„ miÄ™dzy krawÄ™dziÄ… a zawartoÅ›ciÄ… komórki", + + // Insert Image + "Insert Image": "Wstaw obrazek", + "Image URL:": "URL obrazka:", + "Enter the image URL here": "Podaj URL obrazka", + "Preview": "PodglÄ…d", + "Preview the image in a new window": "PodglÄ…d obrazka w nowym oknie", + "Alternate text:": "Tekst alternatywny:", + "For browsers that don't support images": "Dla przeglÄ…darek, które nie obsÅ‚ugujÄ… obrazków", + "Positioning of this image": "Pozycjonowanie obrazka", + "Image Preview:": "PodglÄ…d obrazka:" +} diff --git a/xinha/lang/pt_br.js b/xinha/lang/pt_br.js new file mode 100644 index 0000000..156216d --- /dev/null +++ b/xinha/lang/pt_br.js @@ -0,0 +1,32 @@ +// I18N constants + +// LANG: "bt_br", ENCODING: UTF-8 +// Brazilian Portuguese Translation by Alex Piaz + +{ + "Bold": "Negrito", + "Italic": "Itálico", + "Underline": "Sublinhado", + "Strikethrough": "Tachado", + "Subscript": "Subescrito", + "Superscript": "Sobrescrito", + "Justify Left": "Alinhar à Esquerda", + "Justify Center": "Centralizar", + "Justify Right": "Alinhar à Direita", + "Justify Full": "Justificar", + "Ordered List": "Lista Numerada", + "Bulleted List": "Lista Marcadores", + "Decrease Indent": "Diminuir Indentação", + "Increase Indent": "Aumentar Indentação", + "Font Color": "Cor da Fonte", + "Background Color": "Cor do Fundo", + "Horizontal Rule": "Linha Horizontal", + "Insert Web Link": "Inserir Link", + "Insert/Modify Image": "Inserir Imagem", + "Insert Table": "Inserir Tabela", + "Toggle HTML Source": "Ver Código-Fonte", + "Enlarge Editor": "Expandir Editor", + "About this editor": "Sobre", + "Help using editor": "Ajuda", + "Current style": "Estilo Atual" +} diff --git a/xinha/lang/ro.js b/xinha/lang/ro.js new file mode 100644 index 0000000..e622932 --- /dev/null +++ b/xinha/lang/ro.js @@ -0,0 +1,63 @@ +// I18N constants + +// LANG: "ro", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "ÃŽngroÅŸat", + "Italic": "Italic", + "Underline": "Subliniat", + "Strikethrough": "Tăiat", + "Subscript": "Indice jos", + "Superscript": "Indice sus", + "Justify Left": "Aliniere la stânga", + "Justify Center": "Aliniere pe centru", + "Justify Right": "Aliniere la dreapta", + "Justify Full": "Aliniere în ambele părÅ£i", + "Ordered List": "Listă ordonată", + "Bulleted List": "Listă marcată", + "Decrease Indent": "MicÅŸorează alineatul", + "Increase Indent": "MăreÅŸte alineatul", + "Font Color": "Culoarea textului", + "Background Color": "Culoare de fundal", + "Horizontal Rule": "Linie orizontală", + "Insert Web Link": "Inserează/modifică link", + "Insert/Modify Image": "Inserează/modifică imagine", + "Insert Table": "Inserează un tabel", + "Toggle HTML Source": "Sursa HTML / WYSIWYG", + "Enlarge Editor": "Maximizează editorul", + "About this editor": "Despre editor", + "Help using editor": "DocumentaÅ£ie (devel)", + "Current style": "Stilul curent", + "Undoes your last action": "Anulează ultima acÅ£iune", + "Redoes your last action": "Reface ultima acÅ£iune anulată", + "Cut selection": "Taie în clipboard", + "Copy selection": "Copie în clipboard", + "Paste from clipboard": "Aduce din clipboard", + "Direction left to right": "DirecÅ£ia de scriere: stânga - dreapta", + "Direction right to left": "DirecÅ£ia de scriere: dreapta - stânga", + "OK": "OK", + "Cancel": "Anulează", + "Path": "Calea", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "EÅŸti în modul TEXT. Apasă butonul [<>] pentru a te întoarce în modul WYSIWYG.", + "Cancel": "Renunţă", + "Insert/Modify Link": "Inserează/modifcă link", + "New window (_blank)": "Fereastră nouă (_blank)", + "None (use implicit)": "Nimic (foloseÅŸte ce-i implicit)", + "Other": "Alt target", + "Same frame (_self)": "AceeaÅŸi fereastră (_self)", + "Target:": "Å¢inta:", + "Title (tooltip):": "Titlul (tooltip):", + "Top frame (_top)": "Fereastra principală (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Trebuie să introduceÅ£i un URL" +} diff --git a/xinha/lang/ru.js b/xinha/lang/ru.js new file mode 100644 index 0000000..85ba601 --- /dev/null +++ b/xinha/lang/ru.js @@ -0,0 +1,50 @@ +// I18N constants + +// LANG: "ru", ENCODING: UTF-8 +// Author: Yulya Shtyryakova, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "Полужирный", + "Italic": "Ðаклонный", + "Underline": "Подчеркнутый", + "Strikethrough": "Перечеркнутый", + "Subscript": "Ðижний индекÑ", + "Superscript": "Верхний индекÑ", + "Justify Left": "По левому краю", + "Justify Center": "По центру", + "Justify Right": "По правому краю", + "Justify Full": "По ширине", + "Ordered List": "Ðумерованный лиÑÑ‚", + "Bulleted List": "Маркированный лиÑÑ‚", + "Decrease Indent": "Уменьшить отÑтуп", + "Increase Indent": "Увеличить отÑтуп", + "Font Color": "Цвет шрифта", + "Background Color": "Цвет фона", + "Horizontal Rule": "Горизонтальный разделитель", + "Insert Web Link": "Ð’Ñтавить гиперÑÑылку", + "Insert/Modify Image": "Ð’Ñтавить изображение", + "Insert Table": "Ð’Ñтавить таблицу", + "Toggle HTML Source": "Показать Html-код", + "Enlarge Editor": "Увеличить редактор", + "About this editor": "О редакторе", + "Help using editor": "Помощь", + "Current style": "Текущий Ñтиль", + "Undoes your last action": "Отменить", + "Redoes your last action": "Повторить", + "Cut selection": "Вырезать", + "Copy selection": "Копировать", + "Paste from clipboard": "Ð’Ñтавить", + "OK": "OK", + "Cancel": "Отмена", + "Path": "Путь", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Ð’Ñ‹ в режиме Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Html-кода. нажмите кнопку [<>], чтобы переключитьÑÑ Ð² визуальный режим." +} diff --git a/xinha/lang/se.js b/xinha/lang/se.js new file mode 100644 index 0000000..88087ee --- /dev/null +++ b/xinha/lang/se.js @@ -0,0 +1,32 @@ +// LANG: "se", ENCODING: UTF-8 + +// Swedish version for htmlArea v3.0 - Alpha Release +// - translated by pat + +{ + "Bold": "Fet", + "Italic": "Kursiv", + "Underline": "Understruken", + "Strikethrough": "Genomstruken", + "Subscript": "Nedsänkt", + "Superscript": "Upphöjd", + "Justify Left": "Vänsterjustera", + "Justify Center": "Centrera", + "Justify Right": "Högerjustera", + "Justify Full": "Marginaljustera", + "Ordered List": "Numrerad lista", + "Bulleted List": "Punktlista", + "Decrease Indent": "Minska indrag", + "Increase Indent": "Öka indrag", + "Font Color": "Textfärg", + "Background Color": "Bakgrundsfärg", + "Horizontal Rule": "VÃ¥grät linje", + "Insert Web Link": "Infoga länk", + "Insert/Modify Image": "Infoga bild", + "Insert Table": "Infoga tabell", + "Toggle HTML Source": "Visa källkod", + "Enlarge Editor": "Visa i eget fönster", + "About this editor": "Om denna editor", + "Help using editor": "Hjälp", + "Current style": "Nuvarande stil" +} diff --git a/xinha/lang/si.js b/xinha/lang/si.js new file mode 100644 index 0000000..c34abbe --- /dev/null +++ b/xinha/lang/si.js @@ -0,0 +1,50 @@ +// I18N constants + +// LANG: "si", ENCODING: UTF-8 +// Author: Tomaz Kregar, x_tomo_x@email.si + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Bold": "Krepko", + "Italic": "LežeÄe", + "Underline": "PodÄrtano", + "Strikethrough": "PreÄrtano", + "Subscript": "Podpisano", + "Superscript": "Nadpisano", + "Justify Left": "Poravnaj levo", + "Justify Center": "Na sredino", + "Justify Right": "Poravnaj desno", + "Justify Full": "Porazdeli vsebino", + "Ordered List": "OÅ¡tevilÄevanje", + "Bulleted List": "OznaÄevanje", + "Decrease Indent": "ZmanjÅ¡aj zamik", + "Increase Indent": "PoveÄaj zamik", + "Font Color": "Barva pisave", + "Background Color": "Barva ozadja", + "Horizontal Rule": "Vodoravna Ärta", + "Insert Web Link": "Vstavi hiperpovezavo", + "Insert/Modify Image": "Vstavi sliko", + "Insert Table": "Vstavi tabelo", + "Toggle HTML Source": "Preklopi na HTML kodo", + "Enlarge Editor": "PoveÄaj urejevalnik", + "About this editor": "Vizitka za urejevalnik", + "Help using editor": "PomoÄ za urejevalnik", + "Current style": "Trenutni slog", + "Undoes your last action": "Razveljavi zadnjo akcijo", + "Redoes your last action": "Uveljavi zadnjo akcijo", + "Cut selection": "Izreži", + "Copy selection": "Kopiraj", + "Paste from clipboard": "Prilepi", + "OK": "V redu", + "Cancel": "PrekliÄi", + "Path": "Pot", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Si v tekstovnem naÄinu. Uporabi [<>] gumb za prklop nazaj na WYSIWYG." +} diff --git a/xinha/lang/vn.js b/xinha/lang/vn.js new file mode 100644 index 0000000..0aa6416 --- /dev/null +++ b/xinha/lang/vn.js @@ -0,0 +1,56 @@ +// I18N constants : Vietnamese +// LANG: "en", ENCODING: UTF-8 +// Author: Nguyá»…n Äình Nam, +// Modified 21/07/2004 by Phạm Mai Quân + +{ + "Bold": "Äậm", + "Italic": "Nghiêng", + "Underline": "Gạch Chân", + "Strikethrough": "Gạch Xóa", + "Subscript": "Viết Xuống Dưới", + "Superscript": "Viết Lên Trên", + "Justify Left": "Căn Trái", + "Justify Center": "Căn Giữa", + "Justify Right": "Căn Phải", + "Justify Full": "Căn Äá»u", + "Ordered List": "Danh Sách Có Thứ Tá»± (1, 2, 3)", + "Bulleted List": "Danh Sách Phi Thứ Tá»± (Chấm đầu dòng)", + "Decrease Indent": "Lùi Ra Ngoài", + "Increase Indent": "Thụt Vào Trong", + "Font Color": "Màu Chữ", + "Background Color": "Màu Ná»n", + "Horizontal Rule": "Dòng Kẻ Ngang", + "Insert Web Link": "Tạo Liên Kết", + "Insert/Modify Image": "Chèn Ảnh", + "Insert Table": "Chèn Bảng", + "Toggle HTML Source": "Chế Äá»™ Mã HTML", + "Enlarge Editor": "Phóng To Ô Soạn Thảo", + "About this editor": "Tá»± Giá»›i Thiệu", + "Help using editor": "Giúp Äỡ", + "Current style": "Äịnh Dạng Hiện Thá»i", + "Undoes your last action": "Há»§y thao tác trước", + "Redoes your last action": "Lấy lại thao tác vừa bá»", + "Cut selection": "Cắt", + "Copy selection": "Sao chép", + "Paste from clipboard": "Dán", + "Direction left to right": "Viết từ trái sang phải", + "Direction right to left": "Viết từ phải sang trái", + "OK": "Äồng ý", + "Cancel": "Há»§y", + "The full screen mode is known to cause problems with Internet Explorer, due to browser bugs that we weren": "Chế độ phóng to ô soạn thảo có thể gây lá»—i vá»›i Internet Explorer vì má»™t số lá»—i cá»§a trình duyệt này, vì thế chế độ này có thể sẽ không chạy. Hiển thị không đúng, lá»™n xá»™n, không có đầy đủ chức năng, và cÅ©ng có thể làm trình duyệt cá»§a bạn bị tắt ngang. Nếu bạn Ä‘ang sá»­ dụng Windows 9x bạn có thể bị báo lá»—i ", + "Path": "ÄÆ°á»ng Dẫn", + "You are in TEXT MODE. Use the [<>] button to switch back to WYSIWYG.": "Bạn Ä‘ang ở chế độ text. Sá»­ dụng nút [<>] để chuyển lại chế độ WYSIWIG.", + "Cancel": "Há»§y", + "Insert/Modify Link": "Thêm/Chỉnh sá»­a đưá»ng dẫn", + "New window (_blank)": "Cá»­a sổ má»›i (_blank)", + "None (use implicit)": "Không (sá»­ dụng implicit)", + "OK": "Äồng ý", + "Other": "Khác", + "Same frame (_self)": "Trên cùng khung (_self)", + "Target:": "NÆ¡i hiện thị:", + "Title (tooltip):": "Tiêu đỠ(cá»§a hướng dẫn):", + "Top frame (_top)": "Khung trên cùng (_top)", + "URL:": "URL:", + "You must enter the URL where this link points to": "Bạn phải Ä‘iá»n địa chỉ (URL) mà đưá»ng dẫn sẽ liên kết tá»›i" +} diff --git a/xinha/license.txt b/xinha/license.txt new file mode 100644 index 0000000..e7798cf --- /dev/null +++ b/xinha/license.txt @@ -0,0 +1,30 @@ +htmlArea License (based on BSD license) +Copyright (c) 2002-2004, interactivetools.com, inc. +Copyright (c) 2003-2004 dynarch.com +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1) Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2) Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3) Neither the name of interactivetools.com, inc. nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/xinha/panel-dialog.js b/xinha/panel-dialog.js new file mode 100644 index 0000000..a3c98d7 --- /dev/null +++ b/xinha/panel-dialog.js @@ -0,0 +1,76 @@ + +HTMLArea.PanelDialog = function(editor, side, html, localizer) +{ + this.id = { }; + this.r_id = { }; // reverse lookup id + this.editor = editor; + this.document = document; + this.rootElem = editor.addPanel(side); + + var dialog = this; + if(typeof localizer == 'function') + { + this._lc = localizer; + } + else if(localizer) + { + this._lc = function(string) + { + return HTMLArea._lc(string,localizer); + } + } + else + { + this._lc = function(string) + { + return string; + } + } + + html = html.replace(/\[([a-z0-9_]+)\]/ig, + function(fullString, id) + { + if(typeof dialog.id[id] == 'undefined') + { + dialog.id[id] = HTMLArea.uniq('Dialog'); + dialog.r_id[dialog.id[id]] = id; + } + return dialog.id[id]; + } + ).replace(/(.*?)<\/l10n>/ig, + function(fullString,translate) + { + return dialog._lc(translate) ; + } + ).replace(/="_\((.*?)\)"/g, + function(fullString, translate) + { + return '="' + dialog._lc(translate) + '"'; + } + ); + + this.rootElem.innerHTML = html; +} + +HTMLArea.PanelDialog.prototype.show = function(values) +{ + this.editor.showPanel(this.rootElem); +} + +HTMLArea.PanelDialog.prototype.hide = function() +{ + this.editor.hidePanel(this.rootElem); + return this.getValues(); +} + +HTMLArea.PanelDialog.prototype.onresize = HTMLArea.Dialog.prototype.onresize; + +HTMLArea.PanelDialog.prototype.toggle = HTMLArea.Dialog.prototype.toggle; + +HTMLArea.PanelDialog.prototype.setValues = HTMLArea.Dialog.prototype.setValues; + +HTMLArea.PanelDialog.prototype.getValues = HTMLArea.Dialog.prototype.getValues; + +HTMLArea.PanelDialog.prototype.getElementById = HTMLArea.Dialog.prototype.getElementById; + +HTMLArea.PanelDialog.prototype.getElementsByName = HTMLArea.Dialog.prototype.getElementsByName; diff --git a/xinha/plugins/CSS/css.js b/xinha/plugins/CSS/css.js new file mode 100644 index 0000000..673818b --- /dev/null +++ b/xinha/plugins/CSS/css.js @@ -0,0 +1,149 @@ +// Simple CSS (className) plugin for the editor +// Sponsored by http://www.miro.com.au +// Implementation by Mihai Bazon, http://dynarch.com/mishoo. +// +// (c) dynarch.com 2003 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// $Id$ +// @TODO This is the default and won't be very useful to others. +// We should make this better. +HTMLArea.Config.prototype.cssPluginConfig = + { + combos : [ + { label: "Syntax", + // menu text // CSS class + options: { "None" : "", + "Code" : "code", + "String" : "string", + "Comment" : "comment", + "Variable name" : "variable-name", + "Type" : "type", + "Reference" : "reference", + "Preprocessor" : "preprocessor", + "Keyword" : "keyword", + "Function name" : "function-name", + "Html tag" : "html-tag", + "Html italic" : "html-helper-italic", + "Warning" : "warning", + "Html bold" : "html-helper-bold" + }, + context: "pre" + }, + { label: "Info", + options: { "None" : "", + "Quote" : "quote", + "Highlight" : "highlight", + "Deprecated" : "deprecated" + } + } + ] + }; + +function CSS(editor, params) { + this.editor = editor; + var cfg = editor.config; + var self = this; + var plugin_config; + if(params && params.length) + { + plugin_config = params[0]; + } + else + { + plugin_config = editor.config.cssPluginConfig; + } + + var combos = plugin_config.combos; + + for (var i = 0; i < combos.length; i++) { + var combo = combos[i]; + var id = "CSS-class" + i; + var css_class = { + id : id, + options : combo.options, + action : function(editor) { self.onSelect(editor, this, combo.context, combo.updatecontextclass); }, + refresh : function(editor) { self.updateValue(editor, this); }, + context : combo.context + }; + cfg.registerDropdown(css_class); + cfg.addToolbarElement(["T[" + combo.label + "]", id, "separator"] , "formatblock", -1); + } +}; + +CSS._pluginInfo = { + name : "CSS", + version : "1.0", + developer : "Mihai Bazon", + developer_url : "http://dynarch.com/mishoo/", + c_owner : "Mihai Bazon", + sponsor : "Miro International", + sponsor_url : "http://www.miro.com.au", + license : "htmlArea" +}; + +CSS.prototype.onSelect = function(editor, obj, context, updatecontextclass) { + var tbobj = editor._toolbarObjects[obj.id]; + var index = tbobj.element.selectedIndex; + var className = tbobj.element.value; + + // retrieve parent element of the selection + var parent = editor.getParentElement(); + var surround = true; + + var is_span = (parent && parent.tagName.toLowerCase() == "span"); + var update_parent = (context && updatecontextclass && parent && parent.tagName.toLowerCase() == context); + + if (update_parent) { + parent.className = className; + editor.updateToolbar(); + return; + } + + if (is_span && index == 0 && !/\S/.test(parent.style.cssText)) { + while (parent.firstChild) { + parent.parentNode.insertBefore(parent.firstChild, parent); + } + parent.parentNode.removeChild(parent); + editor.updateToolbar(); + return; + } + + if (is_span) { + // maybe we could simply change the class of the parent node? + if (parent.childNodes.length == 1) { + parent.className = className; + surround = false; + // in this case we should handle the toolbar updation + // ourselves. + editor.updateToolbar(); + } + } + + // Other possibilities could be checked but require a lot of code. We + // can't afford to do that now. + if (surround) { + // shit happens ;-) most of the time. this method works, but + // it's dangerous when selection spans multiple block-level + // elements. + editor.surroundHTML("", ""); + } +}; + +CSS.prototype.updateValue = function(editor, obj) { + var select = editor._toolbarObjects[obj.id].element; + var parent = editor.getParentElement(); + if (typeof parent.className != "undefined" && /\S/.test(parent.className)) { + var options = select.options; + var value = parent.className; + for (var i = options.length; --i >= 0;) { + var option = options[i]; + if (value == option.value) { + select.selectedIndex = i; + return; + } + } + } + select.selectedIndex = 0; +}; diff --git a/xinha/plugins/CharCounter/char-counter.js b/xinha/plugins/CharCounter/char-counter.js new file mode 100644 index 0000000..8ad8ea4 --- /dev/null +++ b/xinha/plugins/CharCounter/char-counter.js @@ -0,0 +1,87 @@ +// Charcounter for HTMLArea-3.0 +// (c) Udo Schmal & L.N.Schaffrath NeueMedien +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +function CharCounter(editor) { + this.editor = editor; +}; + +CharCounter._pluginInfo = { + name : "CharCounter", + version : "1.0", + developer : "Udo Schmal", + developer_url : "http://www.schaffrath-neuemedien.de", + sponsor : "L.N.Schaffrath NeueMedien", + sponsor_url : "http://www.schaffrath-neuemedien.de", + c_owner : "Udo Schmal & L.N.Schaffrath NeueMedien", + license : "htmlArea" +}; + +CharCounter.prototype._lc = function(string) { + return HTMLArea._lc(string, "CharCounter"); +}; + + +CharCounter.prototype.onGenerate = function() { + var self = this; + var charCount = document.createElement("span"); + charCount.style.padding = "2px 5px"; + if(HTMLArea.is_ie) { + charCount.style.styleFloat = "right"; + } else { + charCount.style.cssFloat = "right"; + } + var brk = document.createElement('div'); + brk.style.height = + brk.style.width = + brk.style.lineHeight = + brk.style.fontSize = '1px'; + brk.style.clear = 'both'; + if(HTMLArea.is_ie) { + this.editor._statusBarTree.style.styleFloat = "left"; + } else { + this.editor._statusBarTree.style.cssFloat = "left"; + } + this.editor._statusBar.appendChild(charCount); + this.editor._statusBar.appendChild(brk); + this.charCount = charCount; +}; + +CharCounter.prototype.onUpdateToolbar = function() { + this.updateCharCount(); +} + +CharCounter.prototype.onMode = function (mode) +{ + //Hide Chars in statusbar when switching into textmode + switch (mode) + { + case "textmode": + this.charCount.style.display = "none"; + break; + case "wysiwyg": + this.charCount.style.display = ""; + break; + default: + alert("Mode <" + mode + "> not defined!"); + return false; + } +} + +CharCounter.prototype.updateCharCount = function(ev) { + editor = this.editor; + var contents = editor.getHTML(); + contents = contents.replace(/<(.+?)>/g, '');//Don't count HTML tags + contents = contents.replace(/([\n\r\t])/g, ' ');//convert newlines and tabs into space + contents = contents.replace(/( +)/g, ' ');//count spaces only once + contents = contents.replace(/&(.*);/g, ' ');//Count htmlentities as one keystroke + contents = contents.replace(/^\s*|\s*$/g, '');//trim +// var words=0; +// for (var x=0;x +// +// (c) Udo Schmal & L.N.Schaffrath NeueMedien 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Chars": "Zeichen" +} diff --git a/xinha/plugins/CharCounter/lang/fr.js b/xinha/plugins/CharCounter/lang/fr.js new file mode 100644 index 0000000..f445052 --- /dev/null +++ b/xinha/plugins/CharCounter/lang/fr.js @@ -0,0 +1,5 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + "Chars": "Caractères" +} \ No newline at end of file diff --git a/xinha/plugins/CharCounter/lang/no.js b/xinha/plugins/CharCounter/lang/no.js new file mode 100644 index 0000000..f752b68 --- /dev/null +++ b/xinha/plugins/CharCounter/lang/no.js @@ -0,0 +1,7 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Chars": "Tegn" +} \ No newline at end of file diff --git a/xinha/plugins/CharacterMap/CharacterMap.css b/xinha/plugins/CharacterMap/CharacterMap.css new file mode 100644 index 0000000..faea58b --- /dev/null +++ b/xinha/plugins/CharacterMap/CharacterMap.css @@ -0,0 +1,41 @@ +.CharacterMap { } +.CharacterMap a.entity { + font-size:12px; + width:18px; + display:block; + float:left; + padding:2px; + text-decoration:none; + color:#000; + text-align:center; + +} +.CharacterMap a.light { + background-color:#ffffff; +} +.CharacterMap a.dark { + background-color:#f7f8fd; +} +.CharacterMap a.entity:hover { + background-color:#ffd760; + color:#000; +} +.popup td.character { + font-family:Verdana,Arial,Helvetica,sans-serif; + font-size:14px; + font-weight:bold; + text-align:center; + background:#fff; + padding:4px; +} +.popup td.character-hilite { + background:#ffd760; +} +.popup form { + text-align:center; +} +.popup table { + cursor:pointer; + background-color:#ADAD9C; + border:1px inset; +} \ No newline at end of file diff --git a/xinha/plugins/CharacterMap/character-map.js b/xinha/plugins/CharacterMap/character-map.js new file mode 100644 index 0000000..d6dbf52 --- /dev/null +++ b/xinha/plugins/CharacterMap/character-map.js @@ -0,0 +1,123 @@ +// Character Map plugin for HTMLArea +// Original Author - Bernhard Pfeifer novocaine@gmx.net +HTMLArea.loadStyle( 'CharacterMap.css', 'CharacterMap' ); + +function CharacterMap( editor ) +{ + this.editor = editor; + var cfg = editor.config; + var self = this; + cfg.registerButton( + { + id : 'insertcharacter', + tooltip : HTMLArea._lc( 'Insert special character', 'CharacterMap' ), + image : editor.imgURL( 'ed_charmap.gif', 'CharacterMap' ), + textMode : false, + action : function( editor ) { self.buttonPress( editor ); } + } + ); + cfg.addToolbarElement('insertcharacter', 'createlink', -1); + + if ( cfg.CharacterMap.mode == 'panel' ) + { + editor._CharacterMap = editor.addPanel( 'right' ); + HTMLArea._addClass( editor._CharacterMap, 'CharacterMap' ); + + editor.notifyOn( 'modechange', + function( e, args ) + { + if ( args.mode == 'text' ) editor.hidePanel( editor._CharacterMap ); + } + ); + + var entites = + [ + 'Ÿ', 'š', '@', '"', '¡', '¢', '£', '¤', '¥', '¦', + '§', '¨', '©', 'ª', '«', '¬', '¯', '°', '±', '²', + '³', '´', 'µ', '¶', '·', '¸', '¹', 'º', '»', '¼', + '½', '¾', '¿', '×', 'Ø', '÷', 'ø', 'ƒ', 'ˆ', + '˜', '–', '—', '‘', '’', '‚', '“', '”', '„', + '†', '‡', '•', '…', '‰', '‹', '›', '€', '™', + 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', + 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', + 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', '®', '×', 'Ù', 'Ú', + 'Û', 'Ü', 'Ý', 'Þ', 'ß', 'à', 'á', 'â', 'ã', + 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', + 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', + 'ö', '÷', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'þ', + 'ÿ', 'Œ', 'œ', 'Š' + ]; + + for ( var i=0; i +// +// (c) systemconcept.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Insert special character": "Sonderzeichen einfügen", + "Cancel": "Abbrechen" +} diff --git a/xinha/plugins/CharacterMap/lang/fr.js b/xinha/plugins/CharacterMap/lang/fr.js new file mode 100644 index 0000000..05c4a5f --- /dev/null +++ b/xinha/plugins/CharacterMap/lang/fr.js @@ -0,0 +1,18 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Insert special character": "Insérer caractère spécial", + "Cancel": "Annuler" +} diff --git a/xinha/plugins/CharacterMap/lang/it.js b/xinha/plugins/CharacterMap/lang/it.js new file mode 100644 index 0000000..383680c --- /dev/null +++ b/xinha/plugins/CharacterMap/lang/it.js @@ -0,0 +1,10 @@ +// I18N constants + +// LANG: "it", ENCODING: UTF-8 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Insert special character" : "Inserisca il carattere speciale", + "Cancel" : "Annullamento" +} diff --git a/xinha/plugins/CharacterMap/lang/nl.js b/xinha/plugins/CharacterMap/lang/nl.js new file mode 100644 index 0000000..755470a --- /dev/null +++ b/xinha/plugins/CharacterMap/lang/nl.js @@ -0,0 +1,14 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Sponsored by http://www.systemconcept.de +// Author: Holger Hees, +// +// (c) systemconcept.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Insert special character": "Speciaal character invoegen", + "Cancel": "Annuleer" +} diff --git a/xinha/plugins/CharacterMap/lang/no.js b/xinha/plugins/CharacterMap/lang/no.js new file mode 100644 index 0000000..6ee8566 --- /dev/null +++ b/xinha/plugins/CharacterMap/lang/no.js @@ -0,0 +1,8 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Insert special character": "Sett inn tegn", + "Cancel": "Avbryt" +} \ No newline at end of file diff --git a/xinha/plugins/CharacterMap/popups/select_character.html b/xinha/plugins/CharacterMap/popups/select_character.html new file mode 100644 index 0000000..5f13c74 --- /dev/null +++ b/xinha/plugins/CharacterMap/popups/select_character.html @@ -0,0 +1,183 @@ + + + +Insert special character + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Ÿš@"¡¢£¤¥¦§¨©ª«¬
¯°±²³´µ·¸¹º»¼½¾
¿×Ø÷øƒˆ˜
ÀÁÂÃÄÅÆ
ÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ
®×ÙÚÛÜÝÞßàáâãäåæ
çèéêëìíîïðñòóôõö
÷øùúûüýþÿŒœŠ 

+
+ + \ No newline at end of file diff --git a/xinha/plugins/ContextMenu/1.pl b/xinha/plugins/ContextMenu/1.pl new file mode 100755 index 0000000..fdf6679 --- /dev/null +++ b/xinha/plugins/ContextMenu/1.pl @@ -0,0 +1,38 @@ +#! /usr/bin/perl -w + +use strict; + +my $file = 'context-menu.js'; +my $outfile = $file.'-i18n'; +my $langfile = 'en.js'; + +open FILE, "<$file"; +#open OUTFILE, ">$outfile"; +#open LANGFILE, ">$langfile"; +my %texts = (); +while () { + if (/"(.*?)"/) { + my $inline = $_; + chomp $inline; + my $key = $1; + my $val = $1; + print "Key: [$key]: "; + my $line = ; + if (defined $line) { + chomp $line; + if ($line =~ /(\S+)/) { + $key = $1; + print "-- using $key\n"; + } + $texts{$val} = $key; + } else { + print " -- skipped...\n"; + } + } +} +#close LANGFILE; +#close OUTFILE; +close FILE; + +print "\n\n\n"; +print '"', join("\"\n\"", sort keys %texts), '"', "\n"; diff --git a/xinha/plugins/ContextMenu/context-menu.js b/xinha/plugins/ContextMenu/context-menu.js new file mode 100644 index 0000000..2ccbbf0 --- /dev/null +++ b/xinha/plugins/ContextMenu/context-menu.js @@ -0,0 +1,448 @@ +// Context Menu Plugin for HTMLArea-3.0 +// Sponsored by www.americanbible.org +// Implementation by Mihai Bazon, http://dynarch.com/mishoo/ +// +// (c) dynarch.com 2003. +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// $Id$ + +HTMLArea.loadStyle("menu.css", "ContextMenu"); + +function ContextMenu(editor) { + this.editor = editor; +}; + +ContextMenu._pluginInfo = { + name : "ContextMenu", + version : "1.0", + developer : "Mihai Bazon", + developer_url : "http://dynarch.com/mishoo/", + c_owner : "dynarch.com", + sponsor : "American Bible Society", + sponsor_url : "http://www.americanbible.org", + license : "htmlArea" +}; + +ContextMenu.prototype.onGenerate = function() { + var self = this; + var doc = this.editordoc = this.editor._iframe.contentWindow.document; + HTMLArea._addEvents(doc, ["contextmenu"], + function (event) { + return self.popupMenu(HTMLArea.is_ie ? self.editor._iframe.contentWindow.event : event); + }); + this.currentMenu = null; +}; + +ContextMenu.prototype.getContextMenu = function(target) { + var self = this; + var editor = this.editor; + var config = editor.config; + var menu = []; + var tbo = this.editor.plugins.TableOperations; + if (tbo) tbo = tbo.instance; + + var selection = editor.hasSelectedText(); + if (selection) + menu.push([ HTMLArea._lc("Cut", "ContextMenu"), function() { editor.execCommand("cut"); }, null, config.btnList["cut"][1] ], + [ HTMLArea._lc("Copy", "ContextMenu"), function() { editor.execCommand("copy"); }, null, config.btnList["copy"][1] ]); + menu.push([ HTMLArea._lc("Paste", "ContextMenu"), function() { editor.execCommand("paste"); }, null, config.btnList["paste"][1] ]); + + var currentTarget = target; + var elmenus = []; + + var link = null; + var table = null; + var tr = null; + var td = null; + var img = null; + + function tableOperation(opcode) { + tbo.buttonPress(editor, opcode); + }; + + function insertPara(after) { + var el = currentTarget; + var par = el.parentNode; + var p = editor._doc.createElement("p"); + p.appendChild(editor._doc.createElement("br")); + par.insertBefore(p, after ? el.nextSibling : el); + var sel = editor._getSelection(); + var range = editor._createRange(sel); + if (!HTMLArea.is_ie) { + sel.removeAllRanges(); + range.selectNodeContents(p); + range.collapse(true); + sel.addRange(range); + } else { + range.moveToElementText(p); + range.collapse(true); + range.select(); + } + }; + + for (; target; target = target.parentNode) { + var tag = target.tagName; + if (!tag) + continue; + tag = tag.toLowerCase(); + switch (tag) { + case "img": + img = target; + elmenus.push(null, + [ HTMLArea._lc("_Image Properties...", "ContextMenu"), + function() { + editor._insertImage(img); + }, + HTMLArea._lc("Show the image properties dialog", "ContextMenu"), + config.btnList["insertimage"][1] ] + ); + break; + case "a": + link = target; + elmenus.push(null, + [ HTMLArea._lc("_Modify Link...", "ContextMenu"), + function() { editor.config.btnList['createlink'][3](editor); }, + HTMLArea._lc("Current URL is", "ContextMenu") + ': ' + link.href, + config.btnList["createlink"][1] ], + + [ HTMLArea._lc("Chec_k Link...", "ContextMenu"), + function() { window.open(link.href); }, + HTMLArea._lc("Opens this link in a new window", "ContextMenu") ], + + [ HTMLArea._lc("_Remove Link...", "ContextMenu"), + function() { + if (confirm(HTMLArea._lc("Please confirm that you want to unlink this element.", "ContextMenu") + "\n" + + HTMLArea._lc("Link points to:", "ContextMenu") + " " + link.href)) { + while (link.firstChild) + link.parentNode.insertBefore(link.firstChild, link); + link.parentNode.removeChild(link); + } + }, + HTMLArea._lc("Unlink the current element", "ContextMenu") ] + ); + break; + case "td": + td = target; + if (!tbo) break; + elmenus.push(null, + [ HTMLArea._lc("C_ell Properties...", "ContextMenu"), + function() { tableOperation("TO-cell-prop"); }, + HTMLArea._lc("Show the Table Cell Properties dialog", "ContextMenu"), + config.btnList["TO-cell-prop"][1] ] + ); + break; + case "tr": + tr = target; + if (!tbo) break; + elmenus.push(null, + [ HTMLArea._lc("Ro_w Properties...", "ContextMenu"), + function() { tableOperation("TO-row-prop"); }, + HTMLArea._lc("Show the Table Row Properties dialog", "ContextMenu"), + config.btnList["TO-row-prop"][1] ], + + [ HTMLArea._lc("I_nsert Row Before", "ContextMenu"), + function() { tableOperation("TO-row-insert-above"); }, + HTMLArea._lc("Insert a new row before the current one", "ContextMenu"), + config.btnList["TO-row-insert-above"][1] ], + + [ HTMLArea._lc("In_sert Row After", "ContextMenu"), + function() { tableOperation("TO-row-insert-under"); }, + HTMLArea._lc("Insert a new row after the current one", "ContextMenu"), + config.btnList["TO-row-insert-under"][1] ], + + [ HTMLArea._lc("_Delete Row", "ContextMenu"), + function() { tableOperation("TO-row-delete"); }, + HTMLArea._lc("Delete the current row", "ContextMenu"), + config.btnList["TO-row-delete"][1] ] + ); + break; + case "table": + table = target; + if (!tbo) break; + elmenus.push(null, + [ HTMLArea._lc("_Table Properties...", "ContextMenu"), + function() { tableOperation("TO-table-prop"); }, + HTMLArea._lc("Show the Table Properties dialog", "ContextMenu"), + config.btnList["TO-table-prop"][1] ], + + [ HTMLArea._lc("Insert _Column Before", "ContextMenu"), + function() { tableOperation("TO-col-insert-before"); }, + HTMLArea._lc("Insert a new column before the current one", "ContextMenu"), + config.btnList["TO-col-insert-before"][1] ], + + [ HTMLArea._lc("Insert C_olumn After", "ContextMenu"), + function() { tableOperation("TO-col-insert-after"); }, + HTMLArea._lc("Insert a new column after the current one", "ContextMenu"), + config.btnList["TO-col-insert-after"][1] ], + + [ HTMLArea._lc("De_lete Column", "ContextMenu"), + function() { tableOperation("TO-col-delete"); }, + HTMLArea._lc("Delete the current column", "ContextMenu"), + config.btnList["TO-col-delete"][1] ] + ); + break; + case "body": + elmenus.push(null, + [ HTMLArea._lc("Justify Left", "ContextMenu"), + function() { editor.execCommand("justifyleft"); }, null, + config.btnList["justifyleft"][1] ], + [ HTMLArea._lc("Justify Center", "ContextMenu"), + function() { editor.execCommand("justifycenter"); }, null, + config.btnList["justifycenter"][1] ], + [ HTMLArea._lc("Justify Right", "ContextMenu"), + function() { editor.execCommand("justifyright"); }, null, + config.btnList["justifyright"][1] ], + [ HTMLArea._lc("Justify Full", "ContextMenu"), + function() { editor.execCommand("justifyfull"); }, null, + config.btnList["justifyfull"][1] ] + ); + break; + } + } + + if (selection && !link) + menu.push(null, [ HTMLArea._lc("Make lin_k...", "ContextMenu"), + function() { editor.config.btnList['createlink'][3](editor); }, + HTMLArea._lc("Create a link", "ContextMenu"), + config.btnList["createlink"][1] ]); + + for (var i = 0; i < elmenus.length; ++i) + menu.push(elmenus[i]); + + if (!/html|body/i.test(currentTarget.tagName)) + menu.push(null, + [ HTMLArea._lc({string: "Remove the $elem Element...", replace: {elem: "<" + currentTarget.tagName + ">"}}, "ContextMenu"), + function() { + if (confirm(HTMLArea._lc("Please confirm that you want to remove this element:", "ContextMenu") + " " + + currentTarget.tagName)) { + var el = currentTarget; + var p = el.parentNode; + p.removeChild(el); + if (HTMLArea.is_gecko) { + if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes()) + p.appendChild(editor._doc.createElement("br")); + editor.forceRedraw(); + editor.focusEditor(); + editor.updateToolbar(); + if (table) { + var save_collapse = table.style.borderCollapse; + table.style.borderCollapse = "collapse"; + table.style.borderCollapse = "separate"; + table.style.borderCollapse = save_collapse; + } + } + } + }, + HTMLArea._lc("Remove this node from the document", "ContextMenu") ], + [ HTMLArea._lc("Insert paragraph before", "ContextMenu"), + function() { insertPara(false); }, + HTMLArea._lc("Insert a paragraph before the current node", "ContextMenu") ], + [ HTMLArea._lc("Insert paragraph after", "ContextMenu"), + function() { insertPara(true); }, + HTMLArea._lc("Insert a paragraph after the current node", "ContextMenu") ] + ); + return menu; +}; + +ContextMenu.prototype.popupMenu = function(ev) { + var self = this; + if (this.currentMenu) + this.currentMenu.parentNode.removeChild(this.currentMenu); + function getPos(el) { + var r = { x: el.offsetLeft, y: el.offsetTop }; + if (el.offsetParent) { + var tmp = getPos(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; + }; + function documentClick(ev) { + ev || (ev = window.event); + if (!self.currentMenu) { + alert(HTMLArea._lc("How did you get here? (Please report!)", "ContextMenu")); + return false; + } + var el = HTMLArea.is_ie ? ev.srcElement : ev.target; + for (; el != null && el != self.currentMenu; el = el.parentNode); + if (el == null) + self.closeMenu(); + //HTMLArea._stopEvent(ev); + //return false; + }; + var keys = []; + function keyPress(ev) { + ev || (ev = window.event); + HTMLArea._stopEvent(ev); + if (ev.keyCode == 27) { + self.closeMenu(); + return false; + } + var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase(); + for (var i = keys.length; --i >= 0;) { + var k = keys[i]; + if (k[0].toLowerCase() == key) + k[1].__msh.activate(); + } + }; + self.closeMenu = function() { + self.currentMenu.parentNode.removeChild(self.currentMenu); + self.currentMenu = null; + HTMLArea._removeEvent(document, "mousedown", documentClick); + HTMLArea._removeEvent(self.editordoc, "mousedown", documentClick); + if (keys.length > 0) + HTMLArea._removeEvent(self.editordoc, "keypress", keyPress); + if (HTMLArea.is_ie) + self.iePopup.hide(); + }; + var target = HTMLArea.is_ie ? ev.srcElement : ev.target; + var ifpos = getPos(self.editor._htmlArea);//_iframe); + var x = ev.clientX + ifpos.x; + var y = ev.clientY + ifpos.y; + + var div; + var doc; + if (!HTMLArea.is_ie) { + doc = document; + } else { + // IE stinks + var popup = this.iePopup = window.createPopup(); + doc = popup.document; + doc.open(); + doc.write(""); + doc.close(); + } + div = doc.createElement("div"); + if (HTMLArea.is_ie) + div.unselectable = "on"; + div.oncontextmenu = function() { return false; }; + div.className = "htmlarea-context-menu"; + if (!HTMLArea.is_ie) + div.style.left = div.style.top = "0px"; + doc.body.appendChild(div); + + var table = doc.createElement("table"); + div.appendChild(table); + table.cellSpacing = 0; + table.cellPadding = 0; + var parent = doc.createElement("tbody"); + table.appendChild(parent); + + var options = this.getContextMenu(target); + for (var i = 0; i < options.length; ++i) { + var option = options[i]; + var item = doc.createElement("tr"); + parent.appendChild(item); + if (HTMLArea.is_ie) + item.unselectable = "on"; + else item.onmousedown = function(ev) { + HTMLArea._stopEvent(ev); + return false; + }; + if (!option) { + item.className = "separator"; + var td = doc.createElement("td"); + td.className = "icon"; + var IE_IS_A_FUCKING_SHIT = '>'; + if (HTMLArea.is_ie) { + td.unselectable = "on"; + IE_IS_A_FUCKING_SHIT = " unselectable='on' style='height=1px'> "; + } + td.innerHTML = ""; + var td1 = td.cloneNode(true); + td1.className = "label"; + item.appendChild(td); + item.appendChild(td1); + } else { + var label = option[0]; + item.className = "item"; + item.__msh = { + item: item, + label: label, + action: option[1], + tooltip: option[2] || null, + icon: option[3] || null, + activate: function() { + self.closeMenu(); + self.editor.focusEditor(); + this.action(); + } + }; + label = label.replace(/_([a-zA-Z0-9])/, "$1"); + if (label != option[0]) + keys.push([ RegExp.$1, item ]); + label = label.replace(/__/, "_"); + var td1 = doc.createElement("td"); + if (HTMLArea.is_ie) + td1.unselectable = "on"; + item.appendChild(td1); + td1.className = "icon"; + if (item.__msh.icon) + { + var t = HTMLArea.makeBtnImg(item.__msh.icon, doc); + td1.appendChild(t); + // td1.innerHTML = ""; + } + var td2 = doc.createElement("td"); + if (HTMLArea.is_ie) + td2.unselectable = "on"; + item.appendChild(td2); + td2.className = "label"; + td2.innerHTML = label; + item.onmouseover = function() { + this.className += " hover"; + self.editor._statusBarTree.innerHTML = this.__msh.tooltip || ' '; + }; + item.onmouseout = function() { this.className = "item"; }; + item.oncontextmenu = function(ev) { + this.__msh.activate(); + if (!HTMLArea.is_ie) + HTMLArea._stopEvent(ev); + return false; + }; + item.onmouseup = function(ev) { + var timeStamp = (new Date()).getTime(); + if (timeStamp - self.timeStamp > 500) + this.__msh.activate(); + if (!HTMLArea.is_ie) + HTMLArea._stopEvent(ev); + return false; + }; + //if (typeof option[2] == "string") + //item.title = option[2]; + } + } + + if (!HTMLArea.is_ie) { + /* FIXME: I think this is to stop the popup from running off the bottom of the screen? + var dx = x + div.offsetWidth - window.innerWidth + 4; + var dy = y + div.offsetHeight - window.innerHeight + 4; + // alert('dy= (' + y + '+' + div.offsetHeight + '-' + window.innerHeight + ' + 4 ) = ' + dy); + if (dx > 0) x -= dx; + if (dy > 0) y -= dy; + */ + div.style.left = x + "px"; + div.style.top = y + "px"; + } else { + // To get the size we need to display the popup with some width/height + // then we can get the actual size of the div and redisplay the popup at the + // correct dimensions. + this.iePopup.show(ev.screenX, ev.screenY, 300,50); + var w = div.offsetWidth; + var h = div.offsetHeight; + this.iePopup.show(ev.screenX, ev.screenY, w, h); + } + + this.currentMenu = div; + this.timeStamp = (new Date()).getTime(); + + HTMLArea._addEvent(document, "mousedown", documentClick); + HTMLArea._addEvent(this.editordoc, "mousedown", documentClick); + if (keys.length > 0) + HTMLArea._addEvent(this.editordoc, "keypress", keyPress); + + HTMLArea._stopEvent(ev); + return false; +}; diff --git a/xinha/plugins/ContextMenu/lang/de.js b/xinha/plugins/ContextMenu/lang/de.js new file mode 100644 index 0000000..9fef91d --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/de.js @@ -0,0 +1,54 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 + +// translated: Raimund Meyer xinha@ray-of-light.org + + +{ + "Cut": "Ausschneiden", + "Copy": "Kopieren", + "Paste": "Einfügen", + "_Image Properties...": "Eigenschaften", + "Show the image properties dialog": "Fenster für die Bildoptionen anzeigen", + "_Modify Link...": "Link ändern", + "Current URL is": "Aktuelle URL ist", + "Chec_k Link...": "Link testen", + "Opens this link in a new window": "Diesen Link in neuem Fenster öffnen", + "_Remove Link...": "Link entfernen", + "Please confirm that you want to unlink this element.": "Wollen sie diesen Link wirklich entfernen?", + "Link points to:": "Link zeigt auf:", + "Unlink the current element": "Link auf Element entfernen", + "C_ell Properties...": "Zellenoptionen", + "Show the Table Cell Properties dialog": "Zellenoptionen anzeigen", + "Ro_w Properties...": "Zeilenoptionen", + "Show the Table Row Properties dialog": "Zeilenoptionen anzeigen", + "I_nsert Row Before": "Zeile einfügen vor Position", + "Insert a new row before the current one": "Zeile einfügen vor der aktuellen Position", + "In_sert Row After": "Zeile einügen nach Position", + "Insert a new row after the current one": "Zeile einfügen nach der aktuellen Position", + "_Delete Row": "Zeile löschen", + "Delete the current row": "Zeile löschen", + "_Table Properties...": "Tabellenoptionen", + "Show the Table Properties dialog": "Tabellenoptionen anzeigen", + "Insert _Column Before": "Spalte einfügen vor Position", + "Insert a new column before the current one": "Spalte einfügen vor der aktuellen Position", + "Insert C_olumn After": "Spalte einfügen nach Position", + "Insert a new column after the current one": "Spalte einfügen nach der aktuellen Position", + "De_lete Column": "Spalte löschen", + "Delete the current column": "Spalte löschen", + "Justify Left": "Linksbündig", + "Justify Center": "Zentriert", + "Justify Right": "Rechtsbündig", + "Justify Full": "Blocksatz", + "Make lin_k...": "Link erstellen", + "Create a link": "Link erstellen", + "Remove the $elem Element...": "Element $elem entfernen...", + "Please confirm that you want to remove this element:": "Wollen sie dieses Element wirklich entfernen?", + "Remove this node from the document": "Dieses Element aus dem Dokument entfernen", + "Insert paragraph before": "Absatz einfügen vor Position", + "Insert a paragraph before the current node": "Absatz einfügen vor der aktuellen Position", + "Insert paragraph after": "Absatz einfügen hinter Position", + "Insert a paragraph after the current node": "Absatz einfügen hinter der aktuellen Position", + "How did you get here? (Please report!)": "Wie sind Sie denn hier hin gekommen? (Please report!)" +} diff --git a/xinha/plugins/ContextMenu/lang/el.js b/xinha/plugins/ContextMenu/lang/el.js new file mode 100644 index 0000000..b099704 --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/el.js @@ -0,0 +1,49 @@ +// I18N constants + +// LANG: "el", ENCODING: UTF-8 +// Author: Dimitris Glezos, dimitris@glezos.com + +{ + "Cut": "ΑπΞÎΞΊΞÎπ�", + "Copy": "ΑντιγΟÂαφ�", + "Paste": "Ξ•Ο€ΞΉΞΊΟŒΞ»Ξ»Ξ·ΟƒΞ·", + "_Image Properties...": "Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ Ξ•ΞΉΞΊΟŒΞ½Ξ±Ο‚...", + "_Modify Link...": "Ξ�ΟÂΞÎΟ€ΞÎΟ€ΞÎίηση συνδέσμΞÎΟ…...", + "Chec_k Link...": "ΞˆΞ»Ξ΅Ξ³Ο‡ΞÎΟ‚ συνδέσμων...", + "_Remove Link...": "ΔιαγΟÂαφ� συνδέσμΞÎΟ…...", + "C_ell Properties...": "Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ κΡλιΞÎΟÂ...", + "Ro_w Properties...": "Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ Ξ³ΟÂαμμ�ς...", + "I_nsert Row Before": "ΕισαγωγΞ� Ξ³ΟÂαμμ�ς Ο€ΟÂΞΉΞ½", + "In_sert Row After": "ΕισαγωγΞ� Ξ³ΟÂαμμ�ς μΡτά", + "_Delete Row": "ΔιαγΟÂαφ� Ξ³ΟÂαμμ�ς", + "_Table Properties...": "Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ πίνακα...", + "Insert _Column Before": "ΕισαγωγΞ� στΞ�λης Ο€ΟÂΞΉΞ½", + "Insert C_olumn After": "ΕισαγωγΞ� στΞ�λης μΡτά", + "De_lete Column": "ΔιαγΟÂαφ� στΞ�λης", + "Justify Left": "ΣτΞÎίχηση Ξ‘ΟÂιστΡΟÂΞ¬", + "Justify Center": "ΣτΞÎίχηση ΞšΞ­Ξ½Ο„ΟÂΞÎ", + "Justify Right": "ΣτΞÎίχηση ΔΡξιά", + "Justify Full": "Ξ Ξ»Ξ�ΟÂΞ·Ο‚ ΣτΞÎίχηση", + "Make lin_k...": "ΔημιΞÎΟ…ΟÂΞ³Ξ―Ξ± συνδέσμΞÎΟ…...", + "Remove the $elem Element...": "ΑφαίΟÂΡση $elem στΞÎιχΡίΞÎΟ…...", + "Please confirm that you want to remove this element:": "ΕίστΡ Ξ²Ξ­Ξ²Ξ±ΞΉΞÎΟ‚ πως θέλΡτΡ Ξ½Ξ± αφαιΟÂέσΡτΡ Ο„ΞΠστΞÎιχΡίΞΠ", + "Remove this node from the document": "ΑφαίΟÂΡση Ξ±Ο…Ο„ΞÎΟ Ο„ΞÎΟ… κόμβΞÎΟ… Ξ±Ο€ΟŒ Ο„ΞΠΞ­Ξ³Ξ³ΟÂΞ±Ο†ΞÎ", + "How did you get here? (Please report!)": "Ξ ΟŽΟ‚ Ξ�ΟÂθατΡ ΞΌΞ­Ο‡ΟÂΞΉ Ρδώ; (Ξ Ξ±ΟÂΞ±ΞΊΞ±Ξ»ΞÎΟÂΞΌΞ΅ αναφέΟÂΡτΡ Ο„ΞÎ!)", + "Show the image properties dialog": "Εμφάνιση διαλόγΞÎΟ… ΞΌΞ΅ τις Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ Ξ΅ΞΉΞΊΟŒΞ½Ξ±Ο‚", + "Modify URL": "Ξ�ΟÂΞÎΟ€ΞÎΟ€ΞÎίηση URL", + "Current URL is": "Ξ�ΞΠΟ„ΟÂέχων URL Ρίναι", + "Opens this link in a new window": "ΑνΞÎίγΡι Ξ±Ο…Ο„ΟŒ Ο„ΞÎΞ½ ΟƒΟÂνδΡσμΞΠσΡ Ξ­Ξ½Ξ± Ξ½Ξ­ΞΠπαΟÂάθυΟÂΞÎ", + "Please confirm that you want to unlink this element.": "ΕίστΡ Ξ²Ξ­Ξ²Ξ±ΞΉΞÎΟ‚ πως θέλΡτΡ Ξ½Ξ± αφαιΟÂέσΡτΡ Ο„ΞÎΞ½ ΟƒΟÂνδΡσμΞΠΞ±Ο€ΟŒ Ξ±Ο…Ο„ΟŒ Ο„ΞΠστΞÎιχΡίΞÎ:", + "Link points to:": "Ο ΟƒΟÂνδΡμΞÎΟ‚ ΞÎδηγΡί Ρδώ:", + "Unlink the current element": "ΑφαίΟÂΡση συνδέσμΞÎΟ… Ξ±Ο€ΟŒ Ο„ΞΠπαΟÂών στΞÎιχΡίΞÎ", + "Show the Table Cell Properties dialog": "Εμφάνιση διαλόγΞÎΟ… ΞΌΞ΅ τις Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ κΡλιΞÎΟ Ξ Ξ―Ξ½Ξ±ΞΊΞ±", + "Show the Table Row Properties dialog": "Εμφάνιση διαλόγΞÎΟ… ΞΌΞ΅ τις Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ Ξ³ΟÂαμμ�ς Ξ Ξ―Ξ½Ξ±ΞΊΞ±", + "Insert a new row before the current one": "ΕισαγωγΞ� ΞΌΞΉΞ±Ο‚ Ξ½Ξ­Ξ±Ο‚ Ξ³ΟÂαμμ�ς Ο€ΟÂΞΉΞ½ την ΡπιλΡγμένη", + "Insert a new row after the current one": "ΕισαγωγΞ� ΞΌΞΉΞ±Ο‚ Ξ½Ξ­Ξ±Ο‚ Ξ³ΟÂαμμ�ς μΡτά την ΡπιλΡγμένη", + "Delete the current row": "ΔιαγΟÂαφ� ΡπιλΡγμένης Ξ³ΟÂαμμ�ς", + "Show the Table Properties dialog": "Εμφάνιση διαλόγΞÎΟ… ΞΌΞ΅ τις Ξ™Ξ΄ΞΉΟŒΟ„Ξ·Ο„Ξ΅Ο‚ Ξ Ξ―Ξ½Ξ±ΞΊΞ±", + "Insert a new column before the current one": "ΕισαγωγΞ� Ξ½Ξ­Ξ±Ο‚ στΞ�λης Ο€ΟÂΞΉΞ½ την ΡπιλΡγμένη", + "Insert a new column after the current one": "ΕισαγωγΞ� Ξ½Ξ­Ξ±Ο‚ στΞ�λης μΡτά την ΡπιλΡγμένη", + "Delete the current column": "ΔιαγΟÂαφ� ΡπιλΡγμένης στΞ�λης", + "Create a link": "ΔημιΞÎΟ…ΟÂΞ³Ξ―Ξ± συνδέσμΞÎΟ…" +} diff --git a/xinha/plugins/ContextMenu/lang/fr.js b/xinha/plugins/ContextMenu/lang/fr.js new file mode 100644 index 0000000..3136855 --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/fr.js @@ -0,0 +1,50 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + "Cut": "Couper", + "Copy": "Copier", + "Paste": "Coller", + "_Image Properties...": "_Propriétés de l'image...", + "_Modify Link...": "_Modifier le lien...", + "Chec_k Link...": "_Vérifier le lien...", + "_Remove Link...": "_Supprimer le lien...", + "C_ell Properties...": "P_ropriétés de la cellule...", + "Ro_w Properties...": "Pr_opriétés de la rangée...", + "I_nsert Row Before": "Insérer une rangée a_vant", + "In_sert Row After": "Insér_er une rangée après", + "_Delete Row": "Suppr_imer une rangée", + "_Table Properties...": "Proprié_tés de la table...", + "Insert _Column Before": "I_nsérer une colonne avant", + "Insert C_olumn After": "Insérer une colonne après", + "De_lete Column": "_Supprimer la colonne", + "Justify Left": "Aligner à gauche", + "Justify Center": "Aligner au centre", + "Justify Right": "Aligner à droite", + "Justify Full": "Justifier", + "Make lin_k...": "Convertir en lien...", + "Remove the $elem Element...": "Supprimer Élément $elem...", + "Insert paragraph before": "Insérer un paragraphe avant", + "Insert paragraph after": "Insérer un paragraphe après", + "Please confirm that you want to remove this element:": "Confirmer la suppression de cet élément:", + "Remove this node from the document": "Supprimer ce noeud du document", + "How did you get here? (Please report!)": "Comment êtes-vous arrivé ici ? (Reportez le bug SVP !)", + "Show the image properties dialog": "Afficher le dialogue des propriétés d'image", + "Modify URL": "Modifier l'URL", + "Current URL is": "L'URL courante est", + "Opens this link in a new window": "Ouvrir ce lien dans une nouvelle fenêtre", + "Please confirm that you want to unlink this element.": "Voulez-vous vraiment enlever le lien présent sur cet élément.", + "Link points to:": "Le lien pointe sur:", + "Unlink the current element": "Enlever le lien sur cet élément", + "Show the Table Cell Properties dialog": "Afficher la boite de propriété des cellules", + "Show the Table Row Properties dialog": "Afficher la boite de propriété des rangées", + "Insert a new row before the current one": "Insérer une nouvelle rangée avant celle-ci", + "Insert a new row after the current one": "Insérer une nouvelle rangée après celle-ci", + "Delete the current row": "Supprimer la rangée courante", + "Show the Table Properties dialog": "Afficher la boite de propriété de tableau", + "Insert a new column before the current one": "Insérer une nouvelle rangée avant celle-ci", + "Insert a new column after the current one": "Insérer une nouvelle colonne après celle-ci", + "Delete the current column": "Supprimer cette colonne", + "Create a link": "Créer un lien", + "Insert a paragraph before the current node": "Insérer un paragraphe avant le noeud courant", + "Insert a paragraph after the current node": "Insérer un paragraphe après le noeud courant" +} \ No newline at end of file diff --git a/xinha/plugins/ContextMenu/lang/he.js b/xinha/plugins/ContextMenu/lang/he.js new file mode 100644 index 0000000..5d880d7 --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/he.js @@ -0,0 +1,58 @@ +// I18N constants + +// LANG: "he", ENCODING: UTF-8 +// Author: Liron Newman, http://www.eesh.net, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Cut": "גזור", + "Copy": "העתק", + "Paste": "הדבק", + "_Image Properties...": "_מ×פייני תמונה...", + "_Modify Link...": "_שנה קישור...", + "Chec_k Link...": "בדו_×§ קישור...", + "_Remove Link...": "_הסר קישור...", + "C_ell Properties...": "מ×פייני ת_×...", + "Ro_w Properties...": "מ×פייני _טור...", + "I_nsert Row Before": "×”_כנס שורה לפני", + "In_sert Row After": "×”×›× _ס שורה ×חרי", + "_Delete Row": "_מחק שורה", + "_Table Properties...": "מ×פייני ט_בלה...", + "Insert _Column Before": "הכנס _טור לפני", + "Insert C_olumn After": "הכנס ט_ור ×חרי", + "De_lete Column": "מח_×§ טור", + "Justify Left": "ישור לשמ×ל", + "Justify Center": "ישור למרכז", + "Justify Right": "ישור לימין", + "Justify Full": "ישור לשורה מל××”", + "Make lin_k...": "צור ×§×™_שור...", + "Remove the $elem Element...": "הסר ×ת ×למנט ×”- $elem...", + "Please confirm that you want to remove this element:": "×× × ×שר שברצונך להסיר ×ת ×”×למנט ×”×–×”:", + "Remove this node from the document": "הסרה של node ×–×” מהמסמך", + "How did you get here? (Please report!)": "×יך הגעת ×”× ×”? (×× × ×“×•×•×—!)", + "Show the image properties dialog": "מציג ×ת חלון הדו-שיח של מ×פייני תמונה", + "Modify URL": "שינוי URL", + "Current URL is": "URL נוכחי הו×", + "Opens this link in a new window": "פתיחת קישור ×–×” בחלון חדש", + "Please confirm that you want to unlink this element.": "×× × ×שר ש×תה רוצה לנתק ×ת ×למנט ×–×”.", + "Link points to:": "הקישור מצביע ×ל:", + "Unlink the current element": "ניתוק ×ת ×”×למנט הנוכחי", + "Show the Table Cell Properties dialog": "מציג ×ת חלון הדו-שיח של מ×פייני ×ª× ×‘×˜×‘×œ×”", + "Show the Table Row Properties dialog": "מציג ×ת חלון הדו-שיח של מ×פייני שורה בטבלה", + "Insert a new row before the current one": "הוספת שורה חדשה לפני הנוכחית", + "Insert a new row after the current one": "הוספת שורה חדשה ×חרי הנוכחית", + "Delete the current row": "מחיקת ×ת השורה הנוכחית", + "Show the Table Properties dialog": "מציג ×ת חלון הדו-שיח של מ×פייני טבלה", + "Insert a new column before the current one": "הוספת טור חדש לפני הנוכחי", + "Insert a new column after the current one": "הוספת טור חדש ×חרי הנוכחי", + "Delete the current column": "מחיקת ×ת הטור הנוכחי", + "Create a link": "יצירת קישור" +} diff --git a/xinha/plugins/ContextMenu/lang/nl.js b/xinha/plugins/ContextMenu/lang/nl.js new file mode 100644 index 0000000..b457993 --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/nl.js @@ -0,0 +1,58 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Cut": "Knippen", + "Copy": "Kopiëren", + "Paste": "Plakken", + "_Image Properties...": "Eigenschappen afbeelding...", + "_Modify Link...": "Hyperlin_k aanpassen...", + "Chec_k Link...": "Controleer hyperlin_k...", + "_Remove Link...": "Ve_rwijder hyperlink...", + "C_ell Properties...": "C_eleigenschappen...", + "Ro_w Properties...": "Rijeigenscha_ppen...", + "I_nsert Row Before": "Rij invoegen boven", + "In_sert Row After": "Rij invoegen onder", + "_Delete Row": "Rij _verwijderen", + "_Table Properties...": "_Tabeleigenschappen...", + "Insert _Column Before": "Kolom invoegen voor", + "Insert C_olumn After": "Kolom invoegen na", + "De_lete Column": "Kolom verwijderen", + "Justify Left": "Links uitlijnen", + "Justify Center": "Centreren", + "Justify Right": "Rechts uitlijnen", + "Justify Full": "Uitvullen", + "Make lin_k...": "Maak hyperlin_k...", + "Remove the $elem Element...": "Verwijder het $elem element...", + "Please confirm that you want to remove this element:": "Is het werkelijk de bedoeling dit element te verwijderen:", + "Remove this node from the document": "Verwijder dit punt van het document", + "How did you get here? (Please report!)": "Hoe kwam je hier? (A.U.B. doorgeven!)", + "Show the image properties dialog": "Laat het afbeeldingseigenschappen dialog zien", + "Modify URL": "Aanpassen URL", + "Current URL is": "Huidig URL is", + "Opens this link in a new window": "Opend deze hyperlink in een nieuw venster", + "Please confirm that you want to unlink this element.": "Is het werkelijk de bedoeling dit element te unlinken.", + "Link points to:": "Hyperlink verwijst naar:", + "Unlink the current element": "Unlink het huidige element", + "Show the Table Cell Properties dialog": "Laat de tabel celeigenschappen dialog zien", + "Show the Table Row Properties dialog": "Laat de tabel rijeigenschappen dialog zien", + "Insert a new row before the current one": "Voeg een nieuwe rij in boven de huidige", + "Insert a new row after the current one": "Voeg een nieuwe rij in onder de huidige", + "Delete the current row": "Verwijder de huidige rij", + "Show the Table Properties dialog": "Laat de tabel eigenschappen dialog zien", + "Insert a new column before the current one": "Voeg een nieuwe kolom in voor de huidige", + "Insert a new column after the current one": "Voeg een nieuwe kolom in na de huidige", + "Delete the current column": "Verwijder de huidige kolom", + "Create a link": "Maak een hyperlink" +} diff --git a/xinha/plugins/ContextMenu/lang/no.js b/xinha/plugins/ContextMenu/lang/no.js new file mode 100644 index 0000000..386537b --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/no.js @@ -0,0 +1,55 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +// Used key commands +// C,D,e, ,I, ,k,k,l,M, ,n,o,R, ,s,T, ,w : English +// H B j R m F v : Norwegian + +{ + "Cut": "Klipp ut", + "Copy": "Kopier", + "Paste": "Lim inn", + "_Image Properties...": "_Bilde Egenskaper...", + "Show the image properties dialog": "Vis bildeegenskaper", + "_Modify Link...": "_Rediger Link...", + "Current URL is": "Gjeldende URL er", + "Chec_k Link...": "Sje_kk Link...", + "Opens this link in a new window": "Ã…pner denne link i nytt vindu", + "_Remove Link...": "_Fjerne Link...", + "Please confirm that you want to unlink this element.": "Vennligst bekreft at du ønsker Ã¥ fjerne link pÃ¥ elementet", + "Link points to:": "Link peker til:", + "Unlink the current element": "Fjerne link pÃ¥ gjeldende element", + "C_ell Properties...": "C_elle Egenskaper...", + "Show the Table Cell Properties dialog": "Vis egenskaper for celle", + "Ro_w Properties...": "Rad Egenskaper... (_w)", + "Show the Table Row Properties dialog": "Vis egenskaper for rad", + "I_nsert Row Before": "Sett I_nn rad før", + "Insert a new row before the current one": "Sett inn ny rad før gjeldende", + "In_sert Row After": "_Sett inn rad etter", + "Insert a new row after the current one": "Sett inn ny rad etter gjeldende", + "_Delete Row": "Slett rad (_d)", + "Delete the current row": "Slett gjeldende rad", + "_Table Properties...": "_Tabell Egenskaper...", + "Show the Table Properties dialog": "Vis egenskaper for tabellen", + "Insert _Column Before": "Sett inn kolonne etter (_c)", + "Insert a new column before the current one": "Sett inn kolonne før gjeldende", + "Insert C_olumn After": "Sett inn k_olonne etter", + "Insert a new column after the current one": "Sett inn kolonne etter gjeldende", + "De_lete Column": "S_lett kolonne", + "Delete the current column": "Slett gjeldende kolonne", + "Justify Left": "_Venstrejuster", + "Justify Center": "_Midtjuster", + "Justify Right": "_Høyrejuster", + "Justify Full": "Blokk_juster", + "Make lin_k...": "Lag len_ke...", + "Create a link": "Lag ny link", + "Remove the $elem Element...": "Fjerne $elem elementet...", + "Please confirm that you want to remove this element:": "Vennligst bekreft at du ønsker Ã¥ fjerne elementet:", + "Remove this node from the document": "Fjerne denne node fra dokumentet", + "Insert paragraph before": "Sett inn paragraf før", + "Insert a paragraph before the current node": "Sett inn paragraf før gjeldende node", + "Insert paragraph after": "Sett inn paragraf etter", + "Insert a paragraph after the current node": "Sett inn paragraf etter gjeldende node", + "How did you get here? (Please report!)": "Hva skjedde? (Vennligst beskriv)" +} \ No newline at end of file diff --git a/xinha/plugins/ContextMenu/lang/pl.js b/xinha/plugins/ContextMenu/lang/pl.js new file mode 100644 index 0000000..882150a --- /dev/null +++ b/xinha/plugins/ContextMenu/lang/pl.js @@ -0,0 +1,51 @@ +// I18N constants +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, http://www.eskot.krakow.pl/portfolio/, koto@webworkers.pl +{ + "Cut": "Wytnij", + "Copy": "Kopiuj", + "Paste": "Wklej", + "_Image Properties...": "WÅ‚aÅ›ciwoÅ›ci obrazka", + "Show the image properties dialog": "Pokaż okienko wÅ‚aÅ›ciwoÅ›ci obrazka", + "_Modify Link...": "ZmieÅ„ odnoÅ›nik", + "Current URL is": "Bieżący URL odnoÅ›nika", + "Chec_k Link...": "Sprawdź odnoÅ›nik", + "Opens this link in a new window": "Otwiera ten odnoÅ›nik w nowym oknie", + "_Remove Link...": "UsuÅ„ odnoÅ›nik", + "Please confirm that you want to unlink this element.": "Na pewno chcesz usunąć odnoÅ›nik?", + "Link points to:": "OdnoÅ›nik wskazuje na:", + "Unlink the current element": "UsuÅ„ odnoÅ›nik z zaznaczonego elementu", + "C_ell Properties...": "WÅ‚aÅ›ciwoÅ›ci komórki", + "Show the Table Cell Properties dialog": "Pokaż okno wÅ‚aÅ›ciwoÅ›ci komórki", + "Ro_w Properties...": "WÅ‚aÅ›ciwoÅ›ci wiersza", + "Show the Table Row Properties dialog": "Pokaż okno wÅ‚aÅ›ciwoÅ›ci wiersza", + "I_nsert Row Before": "Wstaw wiersz przed", + "Insert a new row before the current one": "Wstaw nowy wiersz przed bieżącym", + "In_sert Row After": "Wstaw wiersz po", + "Insert a new row after the current one": "Wstaw nowy wiersz po bieżącym", + "_Delete Row": "UsuÅ„ wiersz", + "Delete the current row": "UsuÅ„ bieżący wiersz", + "_Table Properties...": "WÅ‚aÅ›ciwoÅ›ci tabeli", + "Show the Table Properties dialog": "Pokaż okienko wÅ‚aÅ›ciwoÅ›ci tabeli", + "Insert _Column Before": "Wstaw kolumnÄ™ przed", + "Insert a new column before the current one": "Wstaw nowÄ… kolumnÄ™ przed bieżącÄ…", + "Insert C_olumn After": "Wstaw kolumnÄ™ po", + "Insert a new column after the current one": "Wstaw nowÄ… kolumnÄ™ po bieżącej", + "De_lete Column": "UsuÅ„ kolumnÄ™", + "Delete the current column": "Usuwa bieżącÄ… kolumnÄ™", + "Justify Left": "Wyrównaj do lewej", + "Justify Center": "Wycentruj", + "Justify Right": "Wyrównaj do prawej", + "Justify Full": "Wyjustuj", + "Make lin_k...": "Utwórz odnoÅ›nik", + "Create a link": "Utwórz odnoÅ›nik", + "Remove the": "UsuÅ„", + "Element...": "element...", + "Please confirm that you want to remove this element:": "Na pewno chcesz usunąć ten element?", + "Remove this node from the document": "UsuÅ„ ten element z dokumentu", + "Insert paragraph before": "Wstaw akapit przed", + "Insert a paragraph before the current node": "Wstaw akapit przed bieżącym elementem", + "Insert paragraph after": "Wstaw akapit po", + "Insert a paragraph after the current node": "Wstaw akapit po bieżącym elemencie", + "How did you get here? (Please report!)": "Jak tu trafiÅ‚eÅ› (ProszÄ™, podaj okolicznoÅ›ci!)" +} diff --git a/xinha/plugins/ContextMenu/menu.css b/xinha/plugins/ContextMenu/menu.css new file mode 100644 index 0000000..34c64b5 --- /dev/null +++ b/xinha/plugins/ContextMenu/menu.css @@ -0,0 +1,67 @@ +/* styles for the ContextMenu /HTMLArea */ +/* The ContextMenu plugin is (c) dynarch.com 2003. */ +/* Distributed under the same terms as HTMLArea itself */ + +div.htmlarea-context-menu { + position: absolute; + border: 1px solid #aca899; + padding: 2px; + background-color: #fff; + color: #000; + cursor: default; + z-index: 1000; +} + +div.htmlarea-context-menu table { + font: 11px tahoma,verdana,sans-serif; + border-collapse: collapse; +} + +div.htmlarea-context-menu tr.item td.icon img { +/* taken care of by xinha.makeBtnImg() */ +/* width: 18px; */ +/* height: 18px; */ +} + +div.htmlarea-context-menu tr.item td.icon { + padding: 0px 3px; + width: 18px; + height: 18px; + background-color: #cdf; +} + +div.htmlarea-context-menu tr.item td.label { + padding: 1px 10px 1px 3px; +} + +div.htmlarea-context-menu tr.separator td { + padding: 2px 0px; +} + +div.htmlarea-context-menu tr.separator td div { + border-top: 1px solid #aca899; + overflow: hidden; + position: relative; +} + +div.htmlarea-context-menu tr.separator td.icon { + background-color: #cdf; +} + +div.htmlarea-context-menu tr.separator td.icon div { +/* margin-left: 3px; */ + border-color: #fff; +} + +div.htmlarea-context-menu tr.separator td.label div { + margin-right: 3px; +} + +div.htmlarea-context-menu tr.item.hover { + background-color: #316ac5; + color: #fff; +} + +div.htmlarea-context-menu tr.item.hover td.icon { + background-color: #619af5; +} diff --git a/xinha/plugins/DoubleClick/double-click.js b/xinha/plugins/DoubleClick/double-click.js new file mode 100644 index 0000000..8ba9426 --- /dev/null +++ b/xinha/plugins/DoubleClick/double-click.js @@ -0,0 +1,70 @@ +// Double Click Plugin for HTMLArea-3.0 +// Implementation by Marijn Kampf http://www.marijn.org +// Sponsored by http://www.smiling-faces.com +// +// (c) Marijn Kampf 2004. +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// Cut-n-paste version of double click plugin. +// Almost no original code used. Based on +// Luis HTMLarea and Mihai Bazon Context Menu +// +// +// + +DoubleClick._pluginInfo = { + name : "DoubleClick", + version : "1.0", + developer : "Marijn Kampf", + developer_url : "http://www.marijn.org", + c_owner : "Marijn Kampf", + sponsor : "smiling-faces.com", + sponsor_url : "http://www.smiling-faces.com", + license : "htmlArea" +}; + +function DoubleClick(editor) { + this.editor = editor; + + // ADDING CUSTOM DOUBLE CLICK ACTIONS + // format of the dblClickList elements is "TAGNAME: [ ACTION ]" + // - TAGNAME: tagname of the tag that is double clicked + // - ACTION: function that gets called when the button is clicked. + // it has the following prototype: + // function(editor, event) + // - editor is the HTMLArea object that triggered the call + // - target is the selected object + this.editor.dblClickList = { + u: [ function(e) {e.execCommand("underline");} ], + strike: [ function(e) {e.execCommand("strikethrough");} ], + sub: [ function(e) {e.execCommand("subscript");} ], + sup: [ function(e) {e.execCommand("superscript");} ], + // Edit Link dialog + a: [ function(e) {e.execCommand("createlink");} ], + // Follow link + //a: [ function(editor, target) { window.location = target.href; properties(target); } ], + + img: [ function(e) {e.execCommand("insertimage");} ], + td: [ function(e) {e.execCommand("inserttable");} ] + }; +}; + +DoubleClick.prototype.onGenerate = function() { + var self = this; + var doc = this.editordoc = this.editor._iframe.contentWindow.document; + HTMLArea._addEvents(doc, ["dblclick"], + function (event) { + return self.onDoubleClick(HTMLArea.is_ie ? self.editor._iframe.contentWindow.event : event); + }); + this.currentClick = null; +}; + +DoubleClick.prototype.onDoubleClick = function(ev) { + var target = HTMLArea.is_ie ? ev.srcElement : ev.target; + var tagName = target.tagName.toLowerCase(); + + if (this.editor.dblClickList[tagName] != undefined) { + this.editor.dblClickList[tagName][0](this.editor, target); + } +} \ No newline at end of file diff --git a/xinha/plugins/DynamicCSS/dynamiccss.js b/xinha/plugins/DynamicCSS/dynamiccss.js new file mode 100644 index 0000000..43c2c45 --- /dev/null +++ b/xinha/plugins/DynamicCSS/dynamiccss.js @@ -0,0 +1,237 @@ +// Dynamic CSS (className) plugin for HTMLArea +// Sponsored by http://www.systemconcept.de +// Implementation by Holger Hees +// +// (c) systemconcept.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +function DynamicCSS(editor, args) { + this.editor = editor; + var cfg = editor.config; + var self = this; + +/*var cssArray=null; + var cssLength=0;*/ + var lastTag=null; + var lastClass=null; + + var css_class = { + id : "DynamicCSS-class", + tooltip : this._lc("Choose stylesheet"), + options : {"":""}, + action : function(editor) { self.onSelect(editor, this); }, + refresh : function(editor) { self.updateValue(editor, this); } + }; + cfg.registerDropdown(css_class); + cfg.addToolbarElement(["T[CSS]", "DynamicCSS-class", "separator"] , "formatblock", -1); +}; + +DynamicCSS.parseStyleSheet=function(editor){ + iframe = editor._iframe.contentWindow.document; + + cssArray=DynamicCSS.cssArray; + if(!cssArray) cssArray=new Array(); + + for(i=0;i'; + } + else{ + className='none'; + if(tagName=='all') cssName=HTMLArea._lc("Default", 'DynamicCSS'); + else cssName='<'+HTMLArea._lc("Default", 'DynamicCSS')+'>'; + } + cssArray[tagName][className]=cssName; + DynamicCSS.cssLength++; + } + } + } + // ImportRule (Mozilla) + else if(cssRules[rule].styleSheet){ + cssArray=DynamicCSS.applyCSSRule(cssRules[rule].styleSheet.cssRules,cssArray); + } + } + return cssArray; +} + +DynamicCSS._pluginInfo = { + name : "DynamicCSS", + version : "1.5.2", + developer : "Holger Hees", + developer_url : "http://www.systemconcept.de/", + c_owner : "Holger Hees", + sponsor : "System Concept GmbH", + sponsor_url : "http://www.systemconcept.de/", + license : "htmlArea" +}; + +DynamicCSS.prototype._lc = function(string) { + return HTMLArea._lc(string, 'DynamicCSS'); +} + +DynamicCSS.prototype.onSelect = function(editor, obj) { + var tbobj = editor._toolbarObjects[obj.id]; + var index = tbobj.element.selectedIndex; + var className = tbobj.element.value; + + var parent = editor.getParentElement(); + + if(className!='none'){ + parent.className=className; + DynamicCSS.lastClass=className; + } + else{ + if(HTMLArea.is_gecko) parent.removeAttribute('class'); + else parent.removeAttribute('className'); + } + editor.updateToolbar(); +}; + +/*DynamicCSS.prototype.onMode = function(mode) { + if(mode=='wysiwyg'){ + // reparse possible changed css files + DynamicCSS.cssArray=null; + this.updateValue(this.editor,this.editor.config.customSelects["DynamicCSS-class"]); + } +}*/ + +DynamicCSS.prototype.reparseTimer = function(editor, obj, instance) { + // new attempt of rescan stylesheets in 1,2,4 and 8 second (e.g. for external css-files with longer initialisation) + if(DynamicCSS.parseCount<9){ + setTimeout(function () { + DynamicCSS.cssLength=0; + DynamicCSS.parseStyleSheet(editor); + if(DynamicCSS.cssOldLength!=DynamicCSS.cssLength){ + DynamicCSS.cssOldLength=DynamicCSS.cssLength; + DynamicCSS.lastClass=null; + instance.updateValue(editor, obj); + } + instance.reparseTimer(editor, obj, instance); + },DynamicCSS.parseCount*1000); + DynamicCSS.parseCount=DynamicCSS.parseCount*2; + } +} + +DynamicCSS.prototype.updateValue = function(editor, obj) { + cssArray=DynamicCSS.cssArray; + // initial style init + if(!cssArray){ + DynamicCSS.cssLength=0; + DynamicCSS.parseStyleSheet(editor); + cssArray=DynamicCSS.cssArray; + DynamicCSS.cssOldLength=DynamicCSS.cssLength; + DynamicCSS.parseCount=1; + this.reparseTimer(editor,obj,this); + } + + var parent = editor.getParentElement(); + var tagName = parent.tagName.toLowerCase(); + var className = parent.className; + + if(this.lastTag!=tagName || this.lastClass!=className){ + this.lastTag=tagName; + this.lastClass=className; + + var select = editor._toolbarObjects[obj.id].element; + + while(select.length>0){ + select.options[select.length-1] = null; + } + + select.options[0]=new Option(this._lc("Default"),'none'); + if(cssArray){ + // style class only allowed if parent tag is not body or editor is in fullpage mode + if(tagName!='body' || editor.config.fullPage){ + if(cssArray[tagName]){ + for(cssClass in cssArray[tagName]){ + if(typeof cssArray[tagName][cssClass] != 'string') continue; + if(cssClass=='none') select.options[0]=new Option(cssArray[tagName][cssClass],cssClass); + else select.options[select.length]=new Option(cssArray[tagName][cssClass],cssClass); + } + } + + if(cssArray['all']){ + for(cssClass in cssArray['all']){ + if(typeof cssArray['all'][cssClass] != 'string') continue; + select.options[select.length]=new Option(cssArray['all'][cssClass],cssClass); + } + } + } + else if(cssArray[tagName] && cssArray[tagName]['none']) select.options[0]=new Option(cssArray[tagName]['none'],'none'); + } + + select.selectedIndex = 0; + + if (typeof className != "undefined" && /\S/.test(className)) { + var options = select.options; + for (var i = options.length; --i >= 0;) { + var option = options[i]; + if (className == option.value) { + select.selectedIndex = i; + break; + } + } + if(select.selectedIndex == 0){ + select.options[select.length]=new Option(this._lc("Undefined"),className); + select.selectedIndex=select.length-1; + } + } + + if(select.length>1) select.disabled=false; + else select.disabled=true; + } +}; diff --git a/xinha/plugins/DynamicCSS/lang/de.js b/xinha/plugins/DynamicCSS/lang/de.js new file mode 100644 index 0000000..b051902 --- /dev/null +++ b/xinha/plugins/DynamicCSS/lang/de.js @@ -0,0 +1,15 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// Sponsored by http://www.systemconcept.de +// Author: Holger Hees, +// +// (c) systemconcept.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Default": "Standard", + "Undefined": "Nicht definiert", + "Choose stylesheet": "Wählen Sie einen StyleSheet aus" +} diff --git a/xinha/plugins/DynamicCSS/lang/fr.js b/xinha/plugins/DynamicCSS/lang/fr.js new file mode 100644 index 0000000..45c5e91 --- /dev/null +++ b/xinha/plugins/DynamicCSS/lang/fr.js @@ -0,0 +1,15 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Sponsored by http://www.ebdata.com +// Author: Cédric Guillemette, +// +// (c) www.ebdata.com 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Default": "Défaut", + "Undefined": "Non défini", + "Choose stylesheet": "Choisir feuille de style" +} diff --git a/xinha/plugins/DynamicCSS/lang/nl.js b/xinha/plugins/DynamicCSS/lang/nl.js new file mode 100644 index 0000000..9091343 --- /dev/null +++ b/xinha/plugins/DynamicCSS/lang/nl.js @@ -0,0 +1,15 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Sponsored by http://www.systemconcept.de +// Author: Holger Hees, +// +// (c) systemconcept.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "Default": "Default", + "Undefined": "Ungedefinieerd", + "Choose stylesheet": "Kies stylesheet" +} diff --git a/xinha/plugins/DynamicCSS/lang/no.js b/xinha/plugins/DynamicCSS/lang/no.js new file mode 100644 index 0000000..68f8352 --- /dev/null +++ b/xinha/plugins/DynamicCSS/lang/no.js @@ -0,0 +1,9 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Default": "Standard", + "Undefined": "Udefinert", + "Choose stylesheet": "Velg stilsett" +} \ No newline at end of file diff --git a/xinha/plugins/EnterParagraphs/enter-paragraphs.js b/xinha/plugins/EnterParagraphs/enter-paragraphs.js new file mode 100644 index 0000000..00df1ff --- /dev/null +++ b/xinha/plugins/EnterParagraphs/enter-paragraphs.js @@ -0,0 +1,1087 @@ +// tabs 2 + +/** +* @fileoverview By Adam Wright, for The University of Western Australia +* +* Distributed under the same terms as HTMLArea itself. +* This notice MUST stay intact for use (see license.txt). +* +* Heavily modified by Yermo Lamers of DTLink, LLC, College Park, Md., USA. +* For more info see http://www.areaedit.com +*/ + +/** +* plugin Info +*/ + +EnterParagraphs._pluginInfo = + { + name : "EnterParagraphs", + version : "1.0", + developer : "Adam Wright", + developer_url : "http://www.hipikat.org/", + sponsor : "The University of Western Australia", + sponsor_url : "http://www.uwa.edu.au/", + license : "htmlArea" + }; + +// ------------------------------------------------------------------ + +// "constants" + +/** +* Whitespace Regex +*/ + +EnterParagraphs.prototype._whiteSpace = /^\s*$/; + +/** +* The pragmatic list of which elements a paragraph may not contain +*/ + +EnterParagraphs.prototype._pExclusions = /^(address|blockquote|body|dd|div|dl|dt|fieldset|form|h1|h2|h3|h4|h5|h6|hr|li|noscript|ol|p|pre|table|ul)$/i; + +/** +* elements which may contain a paragraph +*/ + +EnterParagraphs.prototype._pContainers = /^(body|del|div|fieldset|form|ins|map|noscript|object|td|th)$/i; + +/** +* Elements which may not contain paragraphs, and would prefer a break to being split +*/ + +EnterParagraphs.prototype._pBreak = /^(address|pre|blockquote)$/i; + +/** +* Elements which may not contain children +*/ + +EnterParagraphs.prototype._permEmpty = /^(area|base|basefont|br|col|frame|hr|img|input|isindex|link|meta|param)$/i; + +/** +* Elements which count as content, as distinct from whitespace or containers +*/ + +EnterParagraphs.prototype._elemSolid = /^(applet|br|button|hr|img|input|table)$/i; + +/** +* Elements which should get a new P, before or after, when enter is pressed at either end +*/ + +EnterParagraphs.prototype._pifySibling = /^(address|blockquote|del|div|dl|fieldset|form|h1|h2|h3|h4|h5|h6|hr|ins|map|noscript|object|ol|p|pre|table|ul|)$/i; +EnterParagraphs.prototype._pifyForced = /^(ul|ol|dl|table)$/i; + +/** +* Elements which should get a new P, before or after a close parent, when enter is pressed at either end +*/ + +EnterParagraphs.prototype._pifyParent = /^(dd|dt|li|td|th|tr)$/i; + +// --------------------------------------------------------------------- + +/** +* EnterParagraphs Constructor +*/ + +function EnterParagraphs(editor) + { + + this.editor = editor; + + // [STRIP + // create a ddt debug trace object. There may be multiple editors on + // the page each EnterParagraphs .. to distinguish which instance + // is generating the message we tack on the name of the textarea. + + //this.ddt = new DDT( editor._textArea + ":EnterParagraphs Plugin" ); + + // uncomment to turn on debugging messages. + + //this.ddt._ddtOn(); + + //this.ddt._ddt( "enter-paragraphs.js","23", "EnterParagraphs(): constructor" ); + + // STRIP] + + // hook into the event handler to intercept key presses if we are using + // gecko (Mozilla/FireFox) + + if (HTMLArea.is_gecko) + { + //this.ddt._ddt( "enter-paragraphs.js","23", "EnterParagraphs(): we are gecko. Setting event handler." ); + this.onKeyPress = this.__onKeyPress; + } + + }; // end of constructor. + +// ------------------------------------------------------------------ + +/** +* name member for debugging +* +* This member is used to identify objects of this class in debugging +* messages. +*/ + +EnterParagraphs.prototype.name = "EnterParagraphs"; + +/** +* Gecko's a bit lacking in some odd ways... +*/ + +EnterParagraphs.prototype.insertAdjacentElement = function(ref,pos,el) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): top with pos '" + pos + "' ref:", ref ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): top with el:", el ); + + if ( pos == 'BeforeBegin' ) + { + ref.parentNode.insertBefore(el,ref); + } + else if ( pos == 'AfterEnd' ) + { + ref.nextSibling ? ref.parentNode.insertBefore(el,ref.nextSibling) : ref.parentNode.appendChild(el); + } + else if ( pos == 'AfterBegin' && ref.firstChild ) + { + ref.insertBefore(el,ref.firstChild); + } + else if ( pos == 'BeforeEnd' || pos == 'AfterBegin' ) + { + ref.appendChild(el); + } + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "122", "insertAdjacentElement(): bottom with ref:", ref ); + + }; // end of insertAdjacentElement() + +// ---------------------------------------------------------------- + +/** +* Passes a global parent node or document fragment to forEachNode +* +* @param root node root node to start search from. +* @param mode string function to apply to each node. +* @param direction string traversal direction "ltr" (left to right) or "rtl" (right_to_left) +* @param init boolean +*/ + +EnterParagraphs.prototype.forEachNodeUnder = function ( root, mode, direction, init ) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): top mode is '" + mode + "' direction is '" + direction + "' starting with root node:", root ); + + // Identify the first and last nodes to deal with + + var start, end; + + // nodeType 11 is DOCUMENT_FRAGMENT_NODE which is a container. + + if ( root.nodeType == 11 && root.firstChild ) + { + start = root.firstChild; + end = root.lastChild; + } + else + { + start = end = root; + } + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): start node is:", start ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): initial end node is:", end ); + + // traverse down the right hand side of the tree getting the last child of the last + // child in each level until we reach bottom. + while ( end.lastChild ) + end = end.lastChild; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "144", "forEachNodeUnder(): end node after descent is:", end ); + + return this.forEachNode( start, end, mode, direction, init); + + }; // end of forEachNodeUnder() + +// ----------------------------------------------------------------------- + +/** +* perform a depth first descent in the direction requested. +* +* @param left_node node "start node" +* @param right_node node "end node" +* @param mode string function to apply to each node. cullids or emptyset. +* @param direction string traversal direction "ltr" (left to right) or "rtl" (right_to_left) +* @param init boolean or object. +*/ + +EnterParagraphs.prototype.forEachNode = function (left_node, right_node, mode, direction, init) + { + + //this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): top - mode is:" + mode + "' direction '" + direction + "'" ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): top - left node is:", left_node ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): top - right node is:", right_node ); + + // returns "Brother" node either left or right. + + var getSibling = function(elem, direction) + { + return ( direction == "ltr" ? elem.nextSibling : elem.previousSibling ); + }; + + var getChild = function(elem, direction) + { + return ( direction == "ltr" ? elem.firstChild : elem.lastChild ); + }; + + var walk, lookup, fnReturnVal; + + // FIXME: init is a boolean in the emptyset case and an object in + // the cullids case. Used inconsistently. + + var next_node = init; + + // used to flag having reached the last node. + + var done_flag = false; + + // loop ntil we've hit the last node in the given direction. + // if we're going left to right that's the right_node and visa-versa. + + while ( walk != direction == "ltr" ? right_node : left_node ) + { + + // on first entry, walk here is null. So this is how + // we prime the loop with the first node. + + if ( !walk ) + { + walk = direction == "ltr" ? left_node : right_node; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): !walk - current node is:", walk ); + } + else + { + + // is there a child node? + + if ( getChild(walk,direction) ) + { + + // descend down into the child. + + walk = getChild(walk,direction); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode():descending to child node:", walk ); + + } + else + { + + // is there a sibling node on this level? + + if ( getSibling(walk,direction) ) + { + + // move to the sibling. + + walk = getSibling(walk,direction); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): moving to sibling node:", walk ); + + } + else + { + lookup = walk; + + // climb back up the tree until we find a level where we are not the end + // node on the level (i.e. that we have a sibling in the direction + // we are searching) or until we reach the end. + + while ( !getSibling(lookup,direction) && lookup != (direction == "ltr" ? right_node : left_node) ) + { + lookup = lookup.parentNode; + } + + // did we find a level with a sibling? + + // walk = ( lookup.nextSibling ? lookup.nextSibling : lookup ) ; + + walk = ( getSibling(lookup,direction) ? getSibling(lookup,direction) : lookup ) ; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): climbed back up (or found right node):", walk ); + + } + } + + } // end of else walk. + + // have we reached the end? either as a result of the top while loop or climbing + // back out above. + + done_flag = (walk==( direction == "ltr" ? right_node : left_node)); + + // call the requested function on the current node. Functions + // return an array. + // + // Possible functions are _fenCullIds, _fenEmptySet + // + // The situation is complicated by the fact that sometimes we want to + // return the base node and sometimes we do not. + // + // next_node can be an object (this.takenIds), a node (text, el, etc) or false. + + //this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): calling function" ); + + switch( mode ) + { + + case "cullids": + + fnReturnVal = this._fenCullIds(walk, next_node ); + break; + + case "find_fill": + + fnReturnVal = this._fenEmptySet(walk, next_node, mode, done_flag); + break; + + case "find_cursorpoint": + + fnReturnVal = this._fenEmptySet(walk, next_node, mode, done_flag); + break; + + } + + // If this node wants us to return, return next_node + + if ( fnReturnVal[0] ) + { + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "175", "forEachNode(): returning node:", fnReturnVal[1] ); + + return fnReturnVal[1]; + } + + // are we done with the loop? + + if ( done_flag ) + { + break; + } + + // Otherwise, pass to the next node + + if ( fnReturnVal[1] ) + { + next_node = fnReturnVal[1]; + } + + } // end of while loop + + //this.ddt._ddt( "enter-paragraphs.js", "175", "forEachNode(): returning false." ); + + return false; + + }; // end of forEachNode() + +// ------------------------------------------------------------------- + +/** +* Find a post-insertion node, only if all nodes are empty, or the first content +* +* @param node node current node beinge examined. +* @param next_node node next node to be examined. +* @param node string "find_fill" or "find_cursorpoint" +* @param last_flag boolean is this the last node? +*/ + +EnterParagraphs.prototype._fenEmptySet = function( node, next_node, mode, last_flag) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : top with mode '" + mode + "' and last_flag '" + last_flag + "' and node:", node ); + + // Mark this if it's the first base + + if ( !next_node && !node.firstChild ) + { + next_node = node; + } + + // Is it an element node and is it considered content? (br, hr, etc) + // or is it a text node that is not just whitespace? + // or is it not an element node and not a text node? + + if ( (node.nodeType == 1 && this._elemSolid.test(node.nodeName)) || + (node.nodeType == 3 && !this._whiteSpace.test(node.nodeValue)) || + (node.nodeType != 1 && node.nodeType != 3) ) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : found content in node:", node ); + + switch( mode ) + { + + case "find_fill": + + // does not return content. + + return new Array(true, false ); + breal; + + case "find_cursorpoint": + + // returns content + + return new Array(true, node ); + break; + + } + + } + + // In either case (fill or findcursor) we return the base node. The avoids + // problems in terminal cases (beginning or end of document or container tags) + + if ( last_flag ) + { + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : return 'base' node:", next_node ); + + return new Array( true, next_node ); + } + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "263", "_fenEmptySet() : bottom returning false and :", next_node ); + + return new Array( false, next_node ); + + }; // end of _fenEmptySet() + +// ------------------------------------------------------------------------------ + +/** +* remove duplicate Id's. +* +* @param ep_ref enterparagraphs reference to enterparagraphs object +*/ + +EnterParagraphs.prototype._fenCullIds = function ( ep_ref, node, pong ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "299", "_fenCullIds(): top" ); + + // Check for an id, blast it if it's in the store, otherwise add it + + if ( node.id ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "299", "_fenCullIds(): node '" + node.nodeName + "' has an id '" + node.id + "'" ); + + pong[node.id] ? node.id = '' : pong[node.id] = true; + } + + return new Array(false,pong); + + }; + +// --------------------------------------------------------------------------------- + +/** +* Grabs a range suitable for paragraph stuffing +* +* @param rng Range +* @param search_direction string "left" or "right" +* +* @todo check blank node issue in roaming loop. +*/ + +EnterParagraphs.prototype.processSide = function( rng, search_direction) + { + + //this.ddt._ddt( "enter-paragraphs.js", "329", "processSide(): top search_direction == '" + search_direction + "'" ); + + var next = function(element, search_direction) + { + return ( search_direction == "left" ? element.previousSibling : element.nextSibling ); + }; + + var node = search_direction == "left" ? rng.startContainer : rng.endContainer; + var offset = search_direction == "left" ? rng.startOffset : rng.endOffset; + var roam, start = node; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "337", "processSide(): starting with node:", node ); + + // Never start with an element, because then the first roaming node might + // be on the exclusion list and we wouldn't know until it was too late + + while ( start.nodeType == 1 && !this._permEmpty.test(start.nodeName) ) + { + start = ( offset ? start.lastChild : start.firstChild ); + } + + // Climb the tree, left or right, until our course of action presents itself + // + // if roam is NULL try start. + // if roam is NOT NULL, try next node in our search_direction + // If that node is NULL, get our parent node. + // + // If all the above turns out NULL end the loop. + // + // FIXME: gecko (firefox 1.0.3) - enter "test" into an empty document and press enter. + // sometimes this loop finds a blank text node, sometimes it doesn't. + + while ( roam = roam ? ( next(roam,search_direction) ? next(roam,search_direction) : roam.parentNode ) : start ) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "357", "processSide(): roaming loop, search_direction is '" + search_direction + "' current node is: ", roam ); + + // next() is an inline function defined above that returns the next node depending + // on the direction we're searching. + + if ( next(roam,search_direction) ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Checking next node '" + next(roam,search_direction).NodeName + "' for _pExclusions list." ); + + // If the next sibling's on the exclusion list, stop before it + + if ( this._pExclusions.test(next(roam,search_direction).nodeName) ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Node '" + next(roam,search_direction).NodeName + "' is on the _pExclusions list. Stopping before it." ); + + return this.processRng(rng, search_direction, roam, next(roam,search_direction), (search_direction == "left"?'AfterEnd':'BeforeBegin'), true, false); + } + } + else + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): No next node, examing parent node '" + roam.parentNode.nodeName + "' for containers or exclusions." ); + + // If our parent's on the container list, stop inside it + + if (this._pContainers.test(roam.parentNode.nodeName)) + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pContainer list. Stopping inside it." ); + + return this.processRng(rng, search_direction, roam, roam.parentNode, (search_direction == "left"?'AfterBegin':'BeforeEnd'), true, false); + } + else if (this._pExclusions.test(roam.parentNode.nodeName)) + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pExclusion list." ); + + // chop without wrapping + + if (this._pBreak.test(roam.parentNode.nodeName)) + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is on the _pBreak list." ); + + return this.processRng(rng, search_direction, roam, roam.parentNode, + (search_direction == "left"?'AfterBegin':'BeforeEnd'), false, (search_direction == "left" ?true:false)); + } + else + { + + //this.ddt._ddt( "enter-paragraphs.js", "371", "processSide(): Parent Node '" + roam.parentNode.nodeName + "' is not on the _pBreak list." ); + + // the next(roam,search_direction) in this call is redundant since we know it's false + // because of the "if next(roam,search_direction)" above. + // + // the final false prevents this range from being wrapped in

's most likely + // because it's already wrapped. + + return this.processRng(rng, + search_direction, + (roam = roam.parentNode), + (next(roam,search_direction) ? next(roam,search_direction) : roam.parentNode), + (next(roam,search_direction) ? (search_direction == "left"?'AfterEnd':'BeforeBegin') : (search_direction == "left"?'AfterBegin':'BeforeEnd')), + false, + false); + } + } + } + } + + //this.ddt._ddt( "enter-paragraphs.js", "424", "processSide(): bottom" ); + + }; // end of processSide() + +// ------------------------------------------------------------------------------ + +/** +* processRng - process Range. +* +* Neighbour and insertion identify where the new node, roam, needs to enter +* the document; landmarks in our selection will be deleted before insertion +* +* @param rn Range original selected range +* @param search_direction string Direction to search in. +* @param roam node +* @param insertion string may be AfterBegin of BeforeEnd +* @return array +*/ + +EnterParagraphs.prototype.processRng = function(rng, search_direction, roam, neighbour, insertion, pWrap, preBr) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "398", "processRng(): top - roam arg is:", roam ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "398", "processRng(): top - neighbor arg is:", neighbour ); + + //this.ddt._ddt( "enter-paragraphs.js", "398", "processRng(): top - insertion arg is: '" + insertion + "'" ); + + var node = search_direction == "left" ? rng.startContainer : rng.endContainer; + var offset = search_direction == "left" ? rng.startOffset : rng.endOffset; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "447", "processRng(): range start (or end) is at offset '" + offset + "' is node :", node ); + + // Define the range to cut, and extend the selection range to the same boundary + + var editor = this.editor; + var newRng = editor._doc.createRange(); + + newRng.selectNode(roam); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): selecting newRng is:", newRng ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): selecting original rng is:", rng ); + + // extend the range in the given direction. + + if ( search_direction == "left") + { + newRng.setEnd(node, offset); + rng.setStart(newRng.startContainer, newRng.startOffset); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): extending direction left - newRng is:", newRng ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): extending direction left - rng is:", rng ); + + } + else if ( search_direction == "right" ) + { + + newRng.setStart(node, offset); + rng.setEnd(newRng.endContainer, newRng.endOffset); + + //this.ddt._ddt( "enter-paragraphs.js", "522", "processRng(): right - new range start is '" + offset + "' end offset is '" + newRng.endOffset + "'" ); + } + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): rng is:", rng ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "522", "processRng(): newRng is:", newRng ); + + // Clone the range and remove duplicate ids it would otherwise produce + + var cnt = newRng.cloneContents(); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "509", "processRng(): culling duplicate ids from:", cnt ); + + // in this case "init" is an object not a boolen. + + this.forEachNodeUnder( cnt, "cullids", "ltr", this.takenIds, false, false); + + // Special case, for inserting paragraphs before some blocks when caret is at + // their zero offset. + // + // Used to "open up space" in front of a list, table. Usefull if the list is at + // the top of the document. (otherwise you'd have no way of "moving it down"). + + var pify, pifyOffset, fill; + pify = search_direction == "left" ? (newRng.endContainer.nodeType == 3 ? true:false) : (newRng.startContainer.nodeType == 3 ? false:true); + pifyOffset = pify ? newRng.startOffset : newRng.endOffset; + pify = pify ? newRng.startContainer : newRng.endContainer; + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "521", "processRng(): pify is '" + pify.nodeName + "' pifyOffset is '" + pifyOffset + "':", pify ); + + if ( this._pifyParent.test(pify.nodeName) && pify.parentNode.childNodes.item(0) == pify ) + { + while ( !this._pifySibling.test(pify.nodeName) ) + { + pify = pify.parentNode; + } + } + + // NODE TYPE 11 is DOCUMENT_FRAGMENT NODE + + if ( cnt.nodeType == 11 && !cnt.firstChild ) + { + cnt.appendChild(editor._doc.createElement(pify.nodeName)); + } + + // YmL: Added additional last parameter for fill case to work around logic + // error in forEachNode() + + //this.ddt._ddt( "enter-paragraphs.js", "612", "processRng(): find_fill in cnt." ); + + fill = this.forEachNodeUnder(cnt, "find_fill", "ltr", false ); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "612", "processRng(): fill node:" , fill ); + + if ( fill && + this._pifySibling.test(pify.nodeName) && + ( (pifyOffset == 0) || ( pifyOffset == 1 && this._pifyForced.test(pify.nodeName) ) ) ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "544", "processRng(): pify handling. Creating p tag followed by nbsp tag" ); + + roam = editor._doc.createElement( 'p' ); + roam.innerHTML = " "; + + // roam = editor._doc.createElement('p'); + // roam.appendChild(editor._doc.createElement('br')); + + // for these cases, if we are processing the left hand side we want it to halt + // processing instead of doing the right hand side. (Avoids adding another

 

+ // after the list etc. + + if ((search_direction == "left" ) && pify.previousSibling) + { + + //this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam AfterEnd" ); + + return new Array(pify.previousSibling, 'AfterEnd', roam); + } + else if (( search_direction == "right") && pify.nextSibling) + { + + //this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam BeforeBegin" ); + + return new Array(pify.nextSibling, 'BeforeBegin', roam); + } + else + { + + //this.ddt._ddt( "enter-paragraphs.js", "682", "processRng(): returning created roam for direction '" + search_direction + "'" ); + + return new Array(pify.parentNode, (search_direction == "left"?'AfterBegin':'BeforeEnd'), roam); + } + + } + + // If our cloned contents are 'content'-less, shove a break in them + + if ( fill ) + { + + // Ill-concieved? + // + // 3 is a TEXT node and it should be empty. + // + + if ( fill.nodeType == 3 ) + { + // fill = fill.parentNode; + + fill = editor._doc.createDocumentFragment(); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "575", "processRng(): fill.nodeType is 3. Moving up to parent:", fill ); + } + + if ( (fill.nodeType == 1 && !this._elemSolid.test()) || fill.nodeType == 11 ) + { + + // FIXME:/CHECKME: When Xinha is switched from WYSIWYG to text mode + // HTMLArea.getHTMLWrapper() will strip out the trailing br. Not sure why. + + // fill.appendChild(editor._doc.createElement('br')); + + var pterminator = editor._doc.createElement( 'p' ); + pterminator.innerHTML = " "; + + fill.appendChild( pterminator ); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "583", "processRng(): fill type is 1 and !elemsolid or it's type 11. Appending an nbsp tag:", fill ); + + } + else + { + + //this.ddt._ddt( "enter-paragraphs.js", "583", "processRng(): inserting a br tag before." ); + + // fill.parentNode.insertBefore(editor._doc.createElement('br'),fill); + + var pterminator = editor._doc.createElement( 'p' ); + pterminator.innerHTML = " "; + + fill.parentNode.insertBefore(parentNode,fill); + + } + } + + // YmL: If there was no content replace with fill + // (previous code did not use fill and we ended up with the + //

test

because Gecko was finding two empty text nodes + // when traversing on the right hand side of an empty document. + + if ( fill ) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): no content. Using fill.", fill ); + + roam = fill; + } + else + { + // And stuff a shiny new object with whatever contents we have + + //this.ddt._ddt( "enter-paragraphs.js", "606", "processRng(): creating p tag or document fragment - pWrap is '" + pWrap + "' " ); + + roam = (pWrap || (cnt.nodeType == 11 && !cnt.firstChild)) ? editor._doc.createElement('p') : editor._doc.createDocumentFragment(); + roam.appendChild(cnt); + } + + if (preBr) + { + //this.ddt._ddt( "enter-paragraphs.js", "767", "processRng(): appending a br based on preBr flag" ); + + roam.appendChild(editor._doc.createElement('br')); + } + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): bottom with roam:", roam ); + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "606", "processRng(): bottom with neighbour:", neighbour ); + + // Return the nearest relative, relative insertion point and fragment to insert + + return new Array(neighbour, insertion, roam); + + }; // end of processRng() + +// ---------------------------------------------------------------------------------- + +/** +* are we an
  • that should be handled by the browser? +* +* there is no good way to "get out of" ordered or unordered lists from Javascript. +* We have to pass the onKeyPress 13 event to the browser so it can take care of +* getting us "out of" the list. +* +* The Gecko engine does a good job of handling all the normal
  • cases except the "press +* enter at the first position" where we want a

     

    inserted before the list. The +* built-in behavior is to open up a
  • before the current entry (not good). +* +* @param rng Range range. +*/ + +EnterParagraphs.prototype.isNormalListItem = function(rng) + { + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "863", "isNormaListItem(): checking rng for list end:", rng ); + + var node, listNode; + + node = rng.startContainer; + + if (( typeof node.nodeName != 'undefined') && + ( node.nodeName.toLowerCase() == 'li' )) + { + + //this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): node is a list item"); + + // are we a list item? + + listNode = node; + } + else if (( typeof node.parentNode != 'undefined' ) && + ( typeof node.parentNode.nodeName != 'undefined' ) && + ( node.parentNode.nodeName.toLowerCase() == 'li' )) + { + + //this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): parent is a list item"); + + // our parent is a list item. + + listNode = node.parentNode; + + } + else + { + //this.ddt._ddt( "enter-paragraphs.js", "863", "isNormaListItem(): not list item"); + + // neither we nor our parent are a list item. this is not a normal + // li case. + + return false; + } + + // at this point we have a listNode. Is it the first list item? + + if ( ! listNode.previousSibling ) + { + //this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): we are the first li." ); + + // are we on the first character of the first li? + + if ( rng.startOffset == 0 ) + { + //this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): we are on the first character." ); + + return false; + } + } + + //this.ddt._ddt( "enter-paragraphs.js", "839", "isNormaListItem(): this is a normal list item case." ); + return true; + + }; // end of isNormalListItem() + +// ---------------------------------------------------------------------------------- +/** +* Called when a key is pressed in the editor +*/ + +EnterParagraphs.prototype.__onKeyPress = function(ev) + { + + //this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): top with keyCode '" + ev.keyCode + "'" ); + + // If they've hit enter and shift is not pressed, handle it + + if (ev.keyCode == 13 && !ev.shiftKey && this.editor._iframe.contentWindow.getSelection) + { + //this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): calling handleEnter" ); + + return this.handleEnter(ev); + } + + //this.ddt._ddt( "enter-paragraphs.js", "517", "__onKeyPress(): bottom" ); + + }; // end of _onKeyPress() + +// ----------------------------------------------------------------------------------- + +/** +* Handles the pressing of an unshifted enter for Gecko +*/ + +EnterParagraphs.prototype.handleEnter = function(ev) + { + + //this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): top" ); + + var cursorNode; + + // Grab the selection and associated range + + var sel = this.editor._getSelection(); + var rng = this.editor._createRange(sel); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "757", "handleEnter(): initial range is: ", rng ); + + // if we are at the end of a list and the node is empty let the browser handle + // it to get us out of the list. + + if ( this.isNormalListItem(rng) ) + { + //this.ddt._ddt( "enter-paragraphs.js", "757", "handleEnter(): we are at the end of a list with a blank item. Letting the browser handle it." ); + return true; + } + + // as far as I can tell this isn't actually used. + + this.takenIds = new Object(); + + // Grab ranges for document re-stuffing, if appropriate + // + // pStart and pEnd are arrays consisting of + // [0] neighbor node + // [1] insertion type + // [2] roam + + //this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): calling processSide on left side." ); + + var pStart = this.processSide(rng, "left"); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "757", "handleEnter(): after processing left side range is: ", rng ); + + //this.ddt._ddt( "enter-paragraphs.js", "537", "handleEnter(): calling processSide on right side." ); + + var pEnd = this.processSide(rng, "right"); + + // used to position the cursor after insertion. + + cursorNode = pEnd[2]; + + // Get rid of everything local to the selection + + sel.removeAllRanges(); + rng.deleteContents(); + + // Grab a node we'll have after insertion, since fragments will be lost + // + // we'll use this to position the cursor. + + //this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): looking for cursor position" ); + + var holdEnd = this.forEachNodeUnder( cursorNode, "find_cursorpoint", "ltr", false, true); + + if ( ! holdEnd ) + { + alert( "INTERNAL ERROR - could not find place to put cursor after ENTER" ); + } + + // Insert our carefully chosen document fragments + + if ( pStart ) + { + + //this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): inserting pEnd" ); + + this.insertAdjacentElement(pStart[0], pStart[1], pStart[2]); + } + + if ( pEnd && pEnd.nodeType != 1) + { + + //this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): inserting pEnd" ); + + this.insertAdjacentElement(pEnd[0], pEnd[1], pEnd[2]); + } + + // Move the caret in front of the first good text element + + if ((holdEnd) && (this._permEmpty.test(holdEnd.nodeName) )) + { + + //this.ddt._ddt( "enter-paragraphs.js", "712", "handleEnter(): looping to find cursor element." ); + + var prodigal = 0; + while ( holdEnd.parentNode.childNodes.item(prodigal) != holdEnd ) + { + prodigal++; + } + + sel.collapse( holdEnd.parentNode, prodigal); + } + else + { + + // holdEnd might be false. + + try + { + sel.collapse(holdEnd, 0); + + //this.ddt._ddtDumpNode( "enter-paragraphs.js", "1057", "handleEnter(): scrolling to element:", holdEnd ); + + // interestingly, scrollToElement() scroll so the top if holdEnd is a text node. + + if ( holdEnd.nodeType == 3 ) + { + holdEnd = holdEnd.parentNode; + } + + this.editor.scrollToElement(holdEnd); + } + catch (e) + { + // we could try to place the cursor at the end of the document. + } + } + + this.editor.updateToolbar(); + + HTMLArea._stopEvent(ev); + + return true; + + }; // end of handleEnter() + +// END diff --git a/xinha/plugins/FindReplace/find-replace.js b/xinha/plugins/FindReplace/find-replace.js new file mode 100644 index 0000000..51e60d7 --- /dev/null +++ b/xinha/plugins/FindReplace/find-replace.js @@ -0,0 +1,42 @@ +/*---------------------------------------*\ + Find and Replace Plugin for HTMLArea-3.0 + ----------------------------------------- + author: Cau guanabara + e-mail: caugb@ibest.com.br +\*---------------------------------------*/ + +function FindReplace(editor) { +this.editor = editor; +var cfg = editor.config; +var self = this; +cfg.registerButton("FR-findreplace", this._lc("Find and Replace"), + editor.imgURL("ed_find.gif", "FindReplace"), false, + function(editor) { self.buttonPress(editor); }); +cfg.addToolbarElement(["FR-findreplace","separator"], ["formatblock","fontsize","fontname"], -1); +}; + +FindReplace.prototype.buttonPress = function(editor) { +FindReplace.editor = editor; +var sel = editor.getSelectedHTML(); + if(/\w/.test(sel)) { + sel = sel.replace(/<[^>]*>/g,""); + sel = sel.replace(/ /g,""); + } +var param = /\w/.test(sel) ? {fr_pattern: sel} : null; +editor._popupDialog("plugin://FindReplace/find_replace", null, param); +}; + +FindReplace._pluginInfo = { + name : "FindReplace", + version : "1.0 - beta", + developer : "Cau Guanabara", + developer_url : "mailto:caugb@ibest.com.br", + c_owner : "Cau Guanabara", + sponsor : "Independent production", + sponsor_url : "http://www.netflash.com.br/gb/HA3-rc1/examples/find-replace.html", + license : "htmlArea" +}; + +FindReplace.prototype._lc = function(string) { + return HTMLArea._lc(string, 'FindReplace'); +} diff --git a/xinha/plugins/FindReplace/fr_engine.js b/xinha/plugins/FindReplace/fr_engine.js new file mode 100644 index 0000000..d190dcc --- /dev/null +++ b/xinha/plugins/FindReplace/fr_engine.js @@ -0,0 +1,149 @@ +/*---------------------------------------*\ + Find and Replace Plugin for HTMLArea-3.0 + ----------------------------------------- + author: Cau guanabara + e-mail: caugb@ibest.com.br +\*---------------------------------------*/ + +var FindReplace = window.opener.FindReplace; +var editor = FindReplace.editor; +var is_mo = window.opener.HTMLArea.is_gecko; +var tosearch = ''; +var pater = null; +var buffer = null; +var matches = 0; +var replaces = 0; +var fr_spans = new Array(); +function _lc(string) { + return(window.opener.HTMLArea._lc(string, 'FindReplace')); +} +function execSearch(params) { +var ihtml = editor._doc.body.innerHTML; + if(buffer == null) + buffer = ihtml; + + if(params['fr_pattern'] != tosearch) { + if(tosearch != '') + clearDoc(); + tosearch = params['fr_pattern']; + } + + if(matches == 0) { + er = params['fr_words'] ? "/(?!<[^>]*)(\\b"+params['fr_pattern']+"\\b)(?![^<]*>)/g" : + "/(?!<[^>]*)("+params['fr_pattern']+")(?![^<]*>)/g"; + if(!params['fr_matchcase']) + er += "i"; + + pater = eval(er); + + var tago = ''; + var tagc = ''; + var newHtml = ihtml.replace(pater,tago+"$1"+tagc); + + editor.setHTML(newHtml); + + var getallspans = editor._doc.body.getElementsByTagName("span"); + for (var i = 0; i < getallspans.length; i++) + if(/^frmark/.test(getallspans[i].id)) + fr_spans.push(getallspans[i]); + } + +spanWalker(params['fr_pattern'],params['fr_replacement'],params['fr_replaceall']); +}; + +function spanWalker(pattern,replacement,replaceall) { +var foundtrue = false; +clearMarks(); + + for (var i = matches; i < fr_spans.length; i++) { + var elm = fr_spans[i]; + foundtrue = true; + if(!(/[0-9]$/.test(elm.id))) { + matches++; + disab('fr_clear',false); + elm.id = 'frmark_'+matches; + elm.style.color = 'white'; + elm.style.backgroundColor = 'highlight'; + elm.style.fontWeight = 'bold'; + elm.scrollIntoView(false); + if(/\w/.test(replacement)) { + if(replaceall || confirm(_lc("Substitute this occurrence?"))) { + elm.firstChild.replaceData(0,elm.firstChild.data.length,replacement); + replaces++; + disab('fr_undo',false); + } + if(replaceall) { + clearMarks(); + continue; + } + } + break; + } + } + var last = (i >= fr_spans.length - 1); + if(last || !foundtrue) { // EOF + var message = _lc("Done")+':\n\n'; + if(matches > 0) { + if(matches == 1) message += matches+' '+_lc("found item"); + else message += matches+' '+_lc("found items"); + if(replaces > 0) { + if(replaces == 1) message += ',\n'+replaces+' '+_lc("replaced item"); + else message += ',\n'+replaces+' '+_lc("replaced items"); + } + hiliteAll(); + disab('fr_hiliteall',false); + } else { message += '"'+pattern+'" '+_lc("not found"); } + alert(message+'.'); + } +}; + +function clearDoc() { +var doc = editor._doc.body.innerHTML; +var er = /(]*id=.?frmark[^>]*>)([^<>]*)(<\/span>)/gi; +editor._doc.body.innerHTML = doc.replace(er,"$2"); +pater = null; +tosearch = ''; +fr_spans = new Array(); +matches = 0; +replaces = 0; +disab("fr_hiliteall,fr_clear",true); +}; + +function clearMarks() { +var getall = editor._doc.body.getElementsByTagName("span"); + for (var i = 0; i < getall.length; i++) { + var elm = getall[i]; + if(/^frmark/.test(elm.id)) { + var objStyle = editor._doc.getElementById(elm.id).style; + objStyle.backgroundColor = ""; + objStyle.color = ""; + objStyle.fontWeight = ""; + } + } +}; + +function hiliteAll() { +var getall = editor._doc.body.getElementsByTagName("span"); + for (var i = 0; i < getall.length; i++) { + var elm = getall[i]; + if(/^frmark/.test(elm.id)) { + var objStyle = editor._doc.getElementById(elm.id).style; + objStyle.backgroundColor = "highlight"; + objStyle.color = "white"; + objStyle.fontWeight = "bold"; + } + } +}; + +function resetContents() { + if(buffer == null) return; +var transp = editor._doc.body.innerHTML; +editor._doc.body.innerHTML = buffer; +buffer = transp; +}; + +function disab(elms,toset) { +var names = elms.split(/[,; ]+/); + for(var i = 0; i < names.length; i++) + document.getElementById(names[i]).disabled = toset; +}; diff --git a/xinha/plugins/FindReplace/img/ed_find.gif b/xinha/plugins/FindReplace/img/ed_find.gif new file mode 100644 index 0000000..60b5ec8 Binary files /dev/null and b/xinha/plugins/FindReplace/img/ed_find.gif differ diff --git a/xinha/plugins/FindReplace/lang/de.js b/xinha/plugins/FindReplace/lang/de.js new file mode 100644 index 0000000..6acfbc6 --- /dev/null +++ b/xinha/plugins/FindReplace/lang/de.js @@ -0,0 +1,38 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: gocher / udo.schmal@t-online.de + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + // messages + "Substitute this occurrence?": "Treffer ersetzen?", + "Enter the text you want to find": "Geben Sie einen Text ein den Sie finden möchten", + "Inform a replacement word": "Geben sie einen Text zum ersetzen ein", + "found items": "alle Treffer", + "replaced items": "ersetzte Treffer", + "found item": "Treffer", + "replaced item": "ersetzter Treffer", + "not found": "kein Teffer", + // window + "Find and Replace": "Suchen und ersetzen", + "Search for:": "Suchen nach:", + "Replace with:": "Ersetzen durch:", + "Options": "Optionen", + "Whole words only": "Ganze Wörter", + "Case sensitive search": "Groß-/Kleinschreibung", + "Substitute all occurrences": "alle Treffer ersetzen", + "Clear": "Nächstes ersetzen", + "Highlight": "Hervorheben", + "Undo": "Rückgängig", + "Next": "Nächster", + "Done": "Fertig" +} \ No newline at end of file diff --git a/xinha/plugins/FindReplace/lang/fr.js b/xinha/plugins/FindReplace/lang/fr.js new file mode 100644 index 0000000..f161c99 --- /dev/null +++ b/xinha/plugins/FindReplace/lang/fr.js @@ -0,0 +1,26 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + // messages + "Substitute this occurrence?": "Remplacer cette occurrence ?", + "Enter the text you want to find": "Texte à trouver", + "Inform a replacement word": "Geben sie einen Text zum ersetzen ein", + "found items": "éléments trouvés", + "replaced items": "éléments remplacés", + "found item": "élément trouvé", + "replaced item": "élément remplacé", + "not found": "non trouvé", + // window + "Find and Replace": "Chercher et Remplacer", + "Search for:": "Chercher", + "Replace with:": "Remplacer par", + "Options": "Options", + "Whole words only": "Mots entiers seulement", + "Case sensitive search": "Recherche sensible à la casse", + "Substitute all occurrences": "Remplacer toutes les occurences", + "Clear": "Effacer", + "Highlight": "Surligner", + "Undo": "Annuler", + "Next": "Suivant", + "Done": "Fin" +} \ No newline at end of file diff --git a/xinha/plugins/FindReplace/lang/no.js b/xinha/plugins/FindReplace/lang/no.js new file mode 100644 index 0000000..d2fd2b5 --- /dev/null +++ b/xinha/plugins/FindReplace/lang/no.js @@ -0,0 +1,28 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + // messages + "Substitute this occurrence?": "Vennligst bekreft at du vil erstatte?", + "Enter the text you want to find": "Skriv inn teksten du ønsker Ã¥ finne", + "Inform a replacement word": "Vennligst skriv inn et erstattningsord / settning", + "found items": "forekomster funnet i søket", + "replaced items": "forekomster erstattet", + "found item": "Treff", + "replaced item": "erstattet treff", + "not found": "ikke funnet", + // window + "Find and Replace": "Søk og erstatt", + "Search for:": "Søk etter:", + "Replace with:": "Erstatt med:", + "Options": "Valg", + "Whole words only": "Bare hele ord", + "Case sensitive search": "Skille mellom store og smÃ¥ bokstaver", + "Substitute all occurrences": "Erstatt alle treff", + "Clear": "Tøm", + "Highlight": "Uthev", + "Undo": "Tilbake", + "Next": "Neste", + "Done": "Ferdig" +} \ No newline at end of file diff --git a/xinha/plugins/FindReplace/lang/pl.js b/xinha/plugins/FindReplace/lang/pl.js new file mode 100644 index 0000000..ee06549 --- /dev/null +++ b/xinha/plugins/FindReplace/lang/pl.js @@ -0,0 +1,38 @@ +/ I18N constants + +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, koto1sa@o2.pl, http://www.eskot.krakow.pl/portfolio + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + // messages + "Substitute this occurrence?": "Zamienić to wystÄ…pienie?", + "Enter the text you want to find": "Podaj tekst, jaki chcesz wyszukać", + "Inform a replacement word": "Podaj tekst do zamiany", + "found items": "znalezionych", + "replaced items": "zamienionych", + "found item": "znaleziony", + "replaced item": "zamieniony", + "not found": "nie znaleziony", + // window + "Find and Replace": "Znajdź i zamieÅ„", + "Search for:": "Szukaj:", + "Replace with:": "ZamieÅ„ na:", + "Options": "Opcje", + "Whole words only": "CaÅ‚e sÅ‚owa", + "Case sensitive search": "Wg wielkoÅ›ci liter", + "Substitute all occurrences": "ZamieÅ„ wszystkie wystÄ…pienia", + "Clear": "Wyczyść", + "Highlight": "PodÅ›wietl", + "Undo": "Cofnij", + "Next": "NastÄ™pny", + "Done": "Gotowe" +} \ No newline at end of file diff --git a/xinha/plugins/FindReplace/lang/pt_br.js b/xinha/plugins/FindReplace/lang/pt_br.js new file mode 100644 index 0000000..f32471b --- /dev/null +++ b/xinha/plugins/FindReplace/lang/pt_br.js @@ -0,0 +1,35 @@ +/*---------------------------------------*\ + Find and Replace Plugin for HTMLArea-3.0 + + by Cau guanabara (independent developer) + e-mail: caugb@ibest.com.br + + * Feito no Brasil * +\*---------------------------------------*/ + +// I18N {pt-br) for FindReplace plugin + +{ + // mensagens + "Substitute this occurrence?": "Substituir?", + "Enter the text you want to find": "Digite um termo para a busca", + "Inform a replacement word": "Informe um termo para a substituição", + "found items": "itens localizados", + "replaced items": "itens substituídos", + "found item": "item localizado", + "replaced item": "item substituído", + "not found": "não encontrado", + // janela + "Find and Replace": "Localizar e Substituir", + "Search for:": "Localizar:", + "Replace with:": "Substituir por:", + "Options": "Opções", + "Whole words only": "Apenas palavras inteiras", + "Case sensitive search": "Diferenciar caixa alta/baixa", + "Substitute all occurrences": "Substituir todas", + "Highlight": "Remarcar", + "Clear": "Limpar", + "Undo": "Desfazer", + "Next": "Próxima", + "Done": "Concluído" +}; diff --git a/xinha/plugins/FindReplace/popups/find_replace.html b/xinha/plugins/FindReplace/popups/find_replace.html new file mode 100644 index 0000000..84f87f3 --- /dev/null +++ b/xinha/plugins/FindReplace/popups/find_replace.html @@ -0,0 +1,162 @@ + + + Find and Replace + + + + + + + + + + +
    +
    Find and Replace
    + + + + + + + + + + + + + + +
    Search for: + +
    Replace with: + +
    + + + + +
    +
    + Options + + + Whole words only
    + + + Case sensitive search
    + + + Substitute all occurrences +
    + +
    + +
    + +
    +
    + +
    +
    + + diff --git a/xinha/plugins/Forms/forms.css b/xinha/plugins/Forms/forms.css new file mode 100644 index 0000000..ba0fca6 --- /dev/null +++ b/xinha/plugins/Forms/forms.css @@ -0,0 +1,3 @@ +form { + border: 1px dotted red; +} diff --git a/xinha/plugins/Forms/forms.js b/xinha/plugins/Forms/forms.js new file mode 100644 index 0000000..069b2c0 --- /dev/null +++ b/xinha/plugins/Forms/forms.js @@ -0,0 +1,354 @@ +// Form plugin for HTMLArea +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + + +function Forms(editor) { + this.editor = editor; + var cfg = editor.config; + var bl = Forms.btnList; + var self = this; + // register the toolbar buttons provided by this plugin + var toolbar = ["linebreak"]; + for (var i = 0; i < bl.length; ++i) { + var btn = bl[i]; + if (!btn) { + toolbar.push("separator"); + } else { + var id = btn[0]; + cfg.registerButton(id, HTMLArea._lc(btn[1]), editor.imgURL("ed_" + btn[0] + ".gif", "Forms"), false, + function(editor, id) { + // dispatch button press event + self.buttonPress(editor, id); + }); + toolbar.push(id); + } + } + // add a new line in the toolbar + cfg.toolbar.push(toolbar); +}; + +Forms._pluginInfo = { + name : "Forms", + origin : "version: 1.0, by Nelson Bright, BrightWork, Inc., http://www.brightworkweb.com", + version : "2.0", + developer : "Udo Schmal", + developer_url : "", + sponsor : "L.N.Schaffrath NeueMedien", + sponsor_url : "http://www.schaffrath-neuemedien.de/", + c_owner : "Udo Schmal & Schaffrath-NeueMedien", + license : "htmlArea" +}; + +// the list of buttons added by this plugin +Forms.btnList = [ + // form properties button + null, // separator + ["form", "Form"], + null, // separator + // form elements + ["textarea", "Textarea"], + ["select", "Selection Field"], + ["checkbox", "Checkbox"], + ["radio", "Radio Button"], + ["text", "Text Field"], + ["password", "Password Field"], + ["file", "File Field"], + ["button", "Button"], + ["submit", "Submit Button"], + ["reset", "Reset Button"], + ["image", "Image Button"], + ["hidden", "Hidden Field"], + ["label", "Label"], + ["fieldset", "Field Set"] + ]; + +Forms.prototype._lc = function(string) { + return HTMLArea._lc(string, 'Forms'); +} + +Forms.prototype.onGenerate = function() { + var style_id = "Form-style" + var style = this.editor._doc.getElementById(style_id); + if (style == null) { + style = this.editor._doc.createElement("link"); + style.id = style_id; + style.rel = 'stylesheet'; + style.href = _editor_url + 'plugins/Forms/forms.css'; + this.editor._doc.getElementsByTagName("HEAD")[0].appendChild(style); + } +} + +Forms.prototype.buttonPress = function(editor,button_id, node) { + function optionValues(text,value) { + this.text = text; + this.value = value; + } + var outparam = new Object(); + var type = button_id; + var sel = editor._getSelection(); + var range = editor._createRange(sel); + if (button_id=="form") { //Form + // see if selection is inside an existing 'form' tag + var pe = editor.getParentElement(); + var frm = null; + while (pe && (pe.nodeType == 1) && (pe.tagName.toLowerCase() != 'body')) { + if(pe.tagName.toLowerCase() == "form") { + frm = pe; + break; + } else + pe = pe.parentNode; + } + if (frm) { + outparam.f_name = frm.name; + outparam.f_action = frm.action; + outparam.f_method = frm.method; + outparam.f_enctype = frm.enctype; + outparam.f_target = frm.target; + } else {; + outparam.f_name = ""; + outparam.f_action = ""; + outparam.f_method = ""; + outparam.f_enctype = ""; + outparam.f_target = ""; + } + editor._popupDialog("plugin://Forms/form", function(param) { + if (param) { + if(frm) { + frm.name = param["f_name"]; + setAttr(frm, "action", param["f_action"]); + setAttr(frm, "method", param["f_method"]); + setAttr(frm, "enctype",param["f_enctype"]); + setAttr(frm, "target", param["f_target"]); + } else { + frm = '
    '); + } + } + }, outparam); + + } else { // form element (checkbox, radio, text, password, textarea, select, button, submit, reset, image, hidden) + var tagName = ""; + // see if selection is an form element + if (typeof node == "undefined") { + node = editor.getParentElement(); + var tag = node.tagName.toLowerCase() + if (node && (tag == "legend")) { + node = node.parentElement; + tag = node.tagName.toLowerCase(); + } + if (node && !(tag == "textarea" || tag == "select" || tag == "input" || tag == "label" || tag == "fieldset")) + node = null; + } + + if(node) { + type = node.tagName.toLowerCase(); + outparam.f_name = node.name; + tagName = node.tagName; + if (type == "input") { + outparam.f_type = node.type; + type = node.type; + } + switch (type) { + case "textarea": + outparam.f_cols = node.cols; + outparam.f_rows = node.rows; + outparam.f_text = node.innerHTML; + outparam.f_wrap = node.getAttribute("wrap"); + outparam.f_readOnly = node.getAttribute("readOnly"); + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "select": + outparam.f_size = parseInt(node.size); + outparam.f_multiple = node.getAttribute("multiple"); + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + var a_options = new Array(); + for (var i=0; i<=node.options.length-1; i++) { + a_options[i] = new optionValues(node.options[i].text, node.options[i].value); + }; + outparam.f_options = a_options; + break; + case "text": + case "password": + outparam.f_value = node.value; + outparam.f_size = node.size; + outparam.f_maxLength = node.maxLength; + outparam.f_readOnly = node.getAttribute("readOnly"); + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "hidden": + outparam.f_value = node.value; + break; + case "submit": + case "reset": + outparam.f_value = node.value; + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "checkbox": + case "radio": + outparam.f_value = node.value; + outparam.f_checked = node.checked; + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "button": + outparam.f_value = node.value; + outparam.f_onclick = node.getAttribute("onclick"); + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "image": + outparam.f_value = node.value; + outparam.f_src = node.src; + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "file": + outparam.f_disabled = node.getAttribute("disabled"); + outparam.f_tabindex = node.getAttribute("tabindex"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "label": + outparam.f_text = node.innerHTML; + outparam.f_for = node.getAttribute("for"); + outparam.f_accesskey = node.getAttribute("accesskey"); + break; + case "fieldset": + if(node.firstChild.tagName.toLowerCase()=="legend") + outparam.f_text = node.firstChild.innerHTML; + else + outparam.f_text = ""; + break; + } + } else { + outparam.f_name = ""; + switch (button_id) { + case "textarea": + case "select": + case "label": + case "fieldset": + tagName = button_id; + break; + default: + tagName = "input"; + outparam.f_type = button_id; + break; + } + outparam.f_options = ""; + outparam.f_cols = "20"; + outparam.f_rows = "4"; + outparam.f_multiple = "false"; + outparam.f_value = ""; + outparam.f_size = ""; + outparam.f_maxLength = ""; + outparam.f_checked = ""; + outparam.f_src = ""; + outparam.f_onclick = ""; + outparam.f_wrap = ""; + outparam.f_readOnly = "false"; + outparam.f_disabled = "false"; + outparam.f_tabindex = ""; + outparam.f_accesskey = ""; + outparam.f_for = ""; + outparam.f_text = ""; + outparam.f_legend = ""; + }; + editor._popupDialog("plugin://Forms/" + tagName + ".html", function(param) { + if (param) { + if(param["f_cols"]) + if (isNaN(parseInt(param["f_cols"],10)) || parseInt(param["f_cols"],10) <= 0) + param["f_cols"] = ""; + if(param["f_rows"]) + if(isNaN(parseInt(param["f_rows"],10)) || parseInt(param["f_rows"],10) <= 0) + param["f_rows"] = ""; + if(param["f_size"]) + if(isNaN(parseInt(param["f_size"],10)) || parseInt(param["f_size"],10) <= 0) + param["f_size"] = ""; + if(param["f_maxlength"]) + if(isNaN(parseInt(param["f_maxLength"],10)) || parseInt(param["f_maxLength"],10) <= 0) + param["f_maxLength"] = ""; + if(node) { + //prepare existing Element + for (field in param) { + alert(field.substring(2,20) + '=' + param[field]); + if ((field=="f_text") || (field=="f_options") || (field=="f_onclick") || (field=="f_checked"))continue; + if (param[field] != "") + node.setAttribute(field.substring(2,20), param[field]); + else + node.removeAttribute(field.substring(2,20)); + } + if (type == "textarea") { + node.innerHTML = param["f_text"]; + } else if(type == "select") { + node.options.length = 0; + var optionsList = param["f_options"]; + for (i=0; i<= optionsList.length-1; i++) { + node.options[i] = new Option(optionsList[i].text, optionsList[i].value) + } + } else if(type == "label") { + node.innerHTML = param["f_text"]; + } else if(type == "fieldset") { + if(outparam.f_text != "") { + if(node.firstChild.tagName.toLowerCase()=="legend") + node.firstChild.innerHTML = param["f_text"]; + } else {}// not implemented jet + } else if((type == "checkbox") || (type == "radio")) { //input + if(param["f_checked"]!="") + node.checked = true; + else + node.checked = false; + } else { + if(param["f_onclick"]){ + node.onclick = ""; + if(param["f_onclick"]!="") + node.onclick = param["f_onclick"]; + } + } + } else { + //create Element + var text = ""; + for (field in param) { + if (!param[field]) continue; + if ((param[field]=="") || (field=="f_text")|| (field=="f_options"))continue; + text += " " + field.substring(2,20) + '="' + param[field] + '"'; + } + + if(type == "textarea") { + text = '' + param["f_text"] + ''; + } else if(type == "select") { + text = ''; + var optionsList = param["f_options"]; + for (i=0; i<= optionsList.length-1; i++) { + text += ''; + } + text += ''; + } else if(type == "label") { + text = '' + param["f_text"] + ''; + } else if(type == "fieldset") { + text = ''; + if (param["f_legend"] != "") text += '' + param["f_text"] + ''; + text += ''; + } else { + text = ''; + } + editor.insertHTML(text); + } + } + }, outparam); + } +}; diff --git a/xinha/plugins/Forms/img/ed_button.gif b/xinha/plugins/Forms/img/ed_button.gif new file mode 100644 index 0000000..02e00ca Binary files /dev/null and b/xinha/plugins/Forms/img/ed_button.gif differ diff --git a/xinha/plugins/Forms/img/ed_checkbox.gif b/xinha/plugins/Forms/img/ed_checkbox.gif new file mode 100644 index 0000000..64dc609 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_checkbox.gif differ diff --git a/xinha/plugins/Forms/img/ed_fieldset.gif b/xinha/plugins/Forms/img/ed_fieldset.gif new file mode 100644 index 0000000..07e97ac Binary files /dev/null and b/xinha/plugins/Forms/img/ed_fieldset.gif differ diff --git a/xinha/plugins/Forms/img/ed_file.gif b/xinha/plugins/Forms/img/ed_file.gif new file mode 100644 index 0000000..8b55633 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_file.gif differ diff --git a/xinha/plugins/Forms/img/ed_form.gif b/xinha/plugins/Forms/img/ed_form.gif new file mode 100644 index 0000000..56f0df5 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_form.gif differ diff --git a/xinha/plugins/Forms/img/ed_hidden.gif b/xinha/plugins/Forms/img/ed_hidden.gif new file mode 100644 index 0000000..2eaae16 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_hidden.gif differ diff --git a/xinha/plugins/Forms/img/ed_image.gif b/xinha/plugins/Forms/img/ed_image.gif new file mode 100644 index 0000000..b13ec07 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_image.gif differ diff --git a/xinha/plugins/Forms/img/ed_label.gif b/xinha/plugins/Forms/img/ed_label.gif new file mode 100644 index 0000000..11bd44a Binary files /dev/null and b/xinha/plugins/Forms/img/ed_label.gif differ diff --git a/xinha/plugins/Forms/img/ed_password.gif b/xinha/plugins/Forms/img/ed_password.gif new file mode 100644 index 0000000..5bf4bb3 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_password.gif differ diff --git a/xinha/plugins/Forms/img/ed_radio.gif b/xinha/plugins/Forms/img/ed_radio.gif new file mode 100644 index 0000000..d9b546d Binary files /dev/null and b/xinha/plugins/Forms/img/ed_radio.gif differ diff --git a/xinha/plugins/Forms/img/ed_reset.gif b/xinha/plugins/Forms/img/ed_reset.gif new file mode 100644 index 0000000..56b60bf Binary files /dev/null and b/xinha/plugins/Forms/img/ed_reset.gif differ diff --git a/xinha/plugins/Forms/img/ed_select.gif b/xinha/plugins/Forms/img/ed_select.gif new file mode 100644 index 0000000..5cbb75e Binary files /dev/null and b/xinha/plugins/Forms/img/ed_select.gif differ diff --git a/xinha/plugins/Forms/img/ed_submit.gif b/xinha/plugins/Forms/img/ed_submit.gif new file mode 100644 index 0000000..a8f1ccb Binary files /dev/null and b/xinha/plugins/Forms/img/ed_submit.gif differ diff --git a/xinha/plugins/Forms/img/ed_text.gif b/xinha/plugins/Forms/img/ed_text.gif new file mode 100644 index 0000000..922f304 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_text.gif differ diff --git a/xinha/plugins/Forms/img/ed_textarea.gif b/xinha/plugins/Forms/img/ed_textarea.gif new file mode 100644 index 0000000..5309517 Binary files /dev/null and b/xinha/plugins/Forms/img/ed_textarea.gif differ diff --git a/xinha/plugins/Forms/popups/fieldset.html b/xinha/plugins/Forms/popups/fieldset.html new file mode 100644 index 0000000..a691701 --- /dev/null +++ b/xinha/plugins/Forms/popups/fieldset.html @@ -0,0 +1,46 @@ + + + + Insert/Edit Form Element FIELDSET + + + + + + + +
    Form Element: FIELDSET
    + +
    Legend:
    + +

    +

    + + +
    + + + diff --git a/xinha/plugins/Forms/popups/form.html b/xinha/plugins/Forms/popups/form.html new file mode 100644 index 0000000..43377e3 --- /dev/null +++ b/xinha/plugins/Forms/popups/form.html @@ -0,0 +1,90 @@ + + + + Insert/Edit Form + + + + + + + +
    Form
    +
    +
    Form Name:
    + +

    + +

    + Form handler script +
    +
    Action URL:
    + +

    +

    Method:
    + +
    +
    Encoding:
    + +

    +

    Target Frame:
    + +

    +

    + +
    + + +
    +
    + + + diff --git a/xinha/plugins/Forms/popups/input.html b/xinha/plugins/Forms/popups/input.html new file mode 100644 index 0000000..67c8886 --- /dev/null +++ b/xinha/plugins/Forms/popups/input.html @@ -0,0 +1,179 @@ + + + + Insert/Edit Form Element INPUT + + + + + + + + +
    +
    +
    Name/ID:
    + +

    +

    Value:
    + +

    +

    Disabled
    + +

    + +

    +
    Checked
    + +

    +

    + +
    Tab Index:
    + +

    +

    Access Key:
    + +

    + +

    +
    Read Only
    + +

    + +

    + Dimensions +
    +
    Size:
    + +
    +
    Max length:
    + +
    +
    +
    +
    +
    + Button Script +
    +
    'onClick'=
    + +
    +
    +
    +
    +
    + Image source +
    +
    Image URL:
    + +
    +
    +
    +
    + + +
    +
    + + + diff --git a/xinha/plugins/Forms/popups/label.html b/xinha/plugins/Forms/popups/label.html new file mode 100644 index 0000000..61a10dd --- /dev/null +++ b/xinha/plugins/Forms/popups/label.html @@ -0,0 +1,59 @@ + + + + Insert/Edit Form Element LABEL + + + + + + + +
    Form Element: LABEL
    +
    +
    Text:
    + +

    +

    For Control:
    + +

    +

    Access Key:
    + +

    +

    + + +
    +
    + + diff --git a/xinha/plugins/Forms/popups/select.html b/xinha/plugins/Forms/popups/select.html new file mode 100644 index 0000000..9034d3e --- /dev/null +++ b/xinha/plugins/Forms/popups/select.html @@ -0,0 +1,209 @@ + + + + Insert/Edit Form Element SELECT + + + + + + + +
    Form Element: SELECT
    +
    +
    Name/ID:
    + +

    +

    Size:
    + +

    +

    Multiple Select
    + +

    +

    Disabled
    + +

    +

    Tab Index:
    + +

    +

    +
    + Options + + + + + +
    + + +
    +
    + +
    +
    + + + + + + + + +
    Lable:Value:
    +
    +
    + + +
    +
    + + diff --git a/xinha/plugins/Forms/popups/textarea.html b/xinha/plugins/Forms/popups/textarea.html new file mode 100644 index 0000000..90c88ad --- /dev/null +++ b/xinha/plugins/Forms/popups/textarea.html @@ -0,0 +1,113 @@ + + + + Insert/Edit Form Element TEXTAREA + + + + + + + +
    Form Element: TEXTAREA
    +
    +
    Name/ID:
    + +

    +

    + Dimensions +
    Columns:
    + +

    +

    Rows:
    + +

    +

    +
    +
    Wrap Mode:
    + +

    +

    Read Only
    + +

    +

    Disabled
    + +

    +

    Tab Index:
    + +

    +

    Access Key:
    + +

    + +

    Initial Text:
    + +
    + + +
    +
    + + + diff --git a/xinha/plugins/FullPage/full-page.js b/xinha/plugins/FullPage/full-page.js new file mode 100644 index 0000000..f3dd6ca --- /dev/null +++ b/xinha/plugins/FullPage/full-page.js @@ -0,0 +1,208 @@ +// FullPage Plugin for HTMLArea-3.0 +// Implementation by Mihai Bazon. Sponsored by http://thycotic.com +// +// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc. +// This notice MUST stay intact for use (see license.txt). +// +// A free WYSIWYG editor replacement for + +
    +
    Mihai Bazon
    + + +Last modified on Sat Oct 25 01:06:59 2003 + + + + diff --git a/xinha/plugins/FullScreen/full-screen.js b/xinha/plugins/FullScreen/full-screen.js new file mode 100644 index 0000000..b081b04 --- /dev/null +++ b/xinha/plugins/FullScreen/full-screen.js @@ -0,0 +1,203 @@ +function FullScreen(editor, args) +{ + this.editor = editor; + editor._superclean_on = false; + cfg = editor.config; + + cfg.registerButton + ( 'fullscreen', + this._lc("Maximize/Minimize Editor"), + [_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0], true, + function(e, objname, obj) + { + e._fullScreen(); + if(e._isFullScreen) + { + obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',9,0]); + } + else + { + obj.swapImage([_editor_url + cfg.imgURL + 'ed_buttons_main.gif',8,0]); + } + } + ); + + // See if we can find 'popupeditor' and replace it with fullscreen + cfg.addToolbarElement("fullscreen", "popupeditor", 0); +} + +FullScreen._pluginInfo = +{ + name : "FullScreen", + version : "1.0", + developer: "James Sleeman", + developer_url: "http://www.gogo.co.nz/", + c_owner : "Gogo Internet Services", + license : "htmlArea", + sponsor : "Gogo Internet Services", + sponsor_url : "http://www.gogo.co.nz/" +}; + +FullScreen.prototype._lc = function(string) { + return HTMLArea._lc(string, 'FullScreen'); +} + +/** fullScreen makes an editor take up the full window space (and resizes when the browser is resized) + * the principle is the same as the "popupwindow" functionality in the original htmlArea, except + * this one doesn't popup a window (it just uses to positioning hackery) so it's much more reliable + * and much faster to switch between + */ + +HTMLArea.prototype._fullScreen = function() +{ + var e = this; + function sizeItUp() + { + if(!e._isFullScreen || e._sizing) return false; + e._sizing = true; + // Width & Height of window + var x,y; + if (window.innerHeight) // all except Explorer + { + x = window.innerWidth; + y = window.innerHeight; + } + else if (document.documentElement && document.documentElement.clientHeight) + // Explorer 6 Strict Mode + { + x = document.documentElement.clientWidth; + y = document.documentElement.clientHeight; + } + else if (document.body) // other Explorers + { + x = document.body.clientWidth; + y = document.body.clientHeight; + } + + e.sizeEditor(x + 'px',y + 'px',true,true); + e._sizing = false; + } + + function sizeItDown() + { + if(e._isFullScreen || e._sizing) return false; + e._sizing = true; + e.initSize(); + e._sizing = false; + } + + /** It's not possible to reliably get scroll events, particularly when we are hiding the scrollbars + * so we just reset the scroll ever so often while in fullscreen mode + */ + function resetScroll() + { + if(e._isFullScreen) + { + window.scroll(0,0); + window.setTimeout(resetScroll,150); + } + } + + if(typeof this._isFullScreen == 'undefined') + { + this._isFullScreen = false; + if(e.target != e._iframe) + { + HTMLArea._addEvent(window, 'resize', sizeItUp); + } + } + + // Gecko has a bug where if you change position/display on a + // designMode iframe that designMode dies. + if(HTMLArea.is_gecko) + { + this.deactivateEditor(); + } + + if(this._isFullScreen) + { + // Unmaximize + this._htmlArea.style.position = ''; + try + { + if(HTMLArea.is_ie) + { + var bod = document.getElementsByTagName('html'); + } + else + { + var bod = document.getElementsByTagName('body'); + } + bod[0].style.overflow=''; + } + catch(e) + { + // Nutthin + } + this._isFullScreen = false; + sizeItDown(); + + // Restore all ancestor positions + var ancestor = this._htmlArea; + while((ancestor = ancestor.parentNode) && ancestor.style) + { + ancestor.style.position = ancestor._xinha_fullScreenOldPosition; + ancestor._xinha_fullScreenOldPosition = null; + } + + window.scroll(this._unScroll.x, this._unScroll.y); + } + else + { + + // Get the current Scroll Positions + this._unScroll = + { + x:(window.pageXOffset)?(window.pageXOffset):(document.documentElement)?document.documentElement.scrollLeft:document.body.scrollLeft, + y:(window.pageYOffset)?(window.pageYOffset):(document.documentElement)?document.documentElement.scrollTop:document.body.scrollTop + }; + + + // Make all ancestors position = static + var ancestor = this._htmlArea; + while((ancestor = ancestor.parentNode) && ancestor.style) + { + ancestor._xinha_fullScreenOldPosition = ancestor.style.position; + ancestor.style.position = 'static'; + } + + // Maximize + window.scroll(0,0); + this._htmlArea.style.position = 'absolute'; + this._htmlArea.style.zIndex = 999; + this._htmlArea.style.left = 0; + this._htmlArea.style.top = 0; + this._isFullScreen = true; + resetScroll(); + + try + { + if(HTMLArea.is_ie) + { + var bod = document.getElementsByTagName('html'); + } + else + { + var bod = document.getElementsByTagName('body'); + } + bod[0].style.overflow='hidden'; + } + catch(e) + { + // Nutthin + } + + sizeItUp(); + } + + if(HTMLArea.is_gecko) + { + this.activateEditor(); + } + this.focusEditor(); +} \ No newline at end of file diff --git a/xinha/plugins/FullScreen/lang/de.js b/xinha/plugins/FullScreen/lang/de.js new file mode 100644 index 0000000..3637a56 --- /dev/null +++ b/xinha/plugins/FullScreen/lang/de.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Raimund Meyer xinha@ray-of-light.org + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Maximize/Minimize Editor": "Editor maximieren/verkleinern" +} diff --git a/xinha/plugins/FullScreen/lang/fr.js b/xinha/plugins/FullScreen/lang/fr.js new file mode 100644 index 0000000..79f2d4d --- /dev/null +++ b/xinha/plugins/FullScreen/lang/fr.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Maximize/Minimize Editor": "Agrandir/Réduire l'éditeur" +} diff --git a/xinha/plugins/FullScreen/lang/no.js b/xinha/plugins/FullScreen/lang/no.js new file mode 100644 index 0000000..26dbcfb --- /dev/null +++ b/xinha/plugins/FullScreen/lang/no.js @@ -0,0 +1,7 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Maximize/Minimize Editor": "Maksimer/Minimer WYSIWYG vindu" +} \ No newline at end of file diff --git a/xinha/plugins/FullScreen/lang/pl.js b/xinha/plugins/FullScreen/lang/pl.js new file mode 100644 index 0000000..7b5887e --- /dev/null +++ b/xinha/plugins/FullScreen/lang/pl.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, koto1sa@o2.pl, http://www.eskot.krakow.pl/portfolio + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Maximize/Minimize Editor": "Maksymalizuj/minimalizuj edytor" +} diff --git a/xinha/plugins/HtmlTidy/README b/xinha/plugins/HtmlTidy/README new file mode 100644 index 0000000..a3e19f2 --- /dev/null +++ b/xinha/plugins/HtmlTidy/README @@ -0,0 +1,104 @@ +// Plugin for htmlArea to run code through the server's HTML Tidy +// By Adam Wright, for The University of Western Australia +// +// Email: zeno@ucc.gu.uwa.edu.au +// Homepage: http://blog.hipikat.org/ +// +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// Version: 0.5 +// Released to the outside world: 04/03/04 + + +HtmlTidy is a plugin for the popular cross-browser TTY WYSIWYG editor, +htmlArea (http://www.interactivetools.com/products/htmlarea/). HtmlTidy +basically queries HTML Tidy (http://tidy.sourceforge.net/) on the +server side, getting it to make-html-nice, instead of relying on masses +of javascript, which the client would have to download. + +Hi, this is a quick explanation of how to install HtmlTidy. Much better +documentation is probably required, and you're welcome to write it :) + + +* The HtmlTidy directory you should have found this file in should + include the following: + + - README + This file, providing help installing the plugin. + + - html-tidy-config.cfg + This file contains the configuration options HTML Tidy uses to + clean html, and can be modified to suit your organizations + requirements. + + - html-tidy-logic.php + This is the php script, which is queried with dirty html and is + responsible for invoking HTML Tidy, getting nice new html and + returning it to the client. + + - html-tidy.js + The main htmlArea plugin, providing functionality to tidy html + through the htmlArea interface. + + - htmlarea.js.onmode_event.diff + At the time of publishing, an extra event handler was required + inside the main htmlarea.js file. htmlarea.js may be patched + against this file to make the changes reuquired, but be aware + that the event handler may either now be in the core or + htmlarea.js may have changed enough to invalidate the patch. + + UPDATE: now it exists in the official htmlarea.js; applying + this patch is thus no longer necessary. + + - img/html-tidy.gif + The HtmlTidy icon, for the htmlArea toolbar. Created by Dan + Petty for The University of Western Australia. + + - lang/en.js + English language file. Add your own language files here and + please contribute back into the htmlArea community! + + The HtmlArea directory should be extracted to your htmlarea/plugins/ + directory. + + +* Make sure the onMode event handler mentioned above, regarding + htmlarea.js.onmode_event.diff, exists in your htmlarea.js + + +* html-tidy-logic.php should be executable, and your web server should + be configured to execute php scripts in the directory + html-tidy-logic.php exists in. + + +* HTML Tidy needs to be installed on your server, and 'tidy' should be + an alias to it, lying in the PATH known to the user executing such + web scripts. + + +* In your htmlArea configuration, do something like this: + + HTMLArea.loadPlugin("HtmlTidy"); + + editor = new HTMLArea("doc"); + editor.registerPlugin("HtmlTidy"); + + +* Then, in your htmlArea toolbar configuration, use: + + - "HT-html-tidy" + This will create the 'tidy broom' icon on the toolbar, which + will attempt to tidy html source when clicked, and; + + - "HT-auto-tidy" + This will create an "Auto Tidy" / "Don't Tidy" dropdown, to + select whether the source should be tidied automatically when + entering source view. On by default, if you'd like it otherwise + you can do so programatically after generating the toolbar :) + (Or just hack it to be otherwise...) + + +Thank you. + +Any bugs you find can be emailed to zeno@ucc.gu.uwa.edu.au diff --git a/xinha/plugins/HtmlTidy/html-tidy-config.cfg b/xinha/plugins/HtmlTidy/html-tidy-config.cfg new file mode 100644 index 0000000..7616992 --- /dev/null +++ b/xinha/plugins/HtmlTidy/html-tidy-config.cfg @@ -0,0 +1,29 @@ +// Default configuration file for the htmlArea, HtmlTidy plugin +// By Adam Wright, for The University of Western Australia +// +// Evertything you always wanted to know about HTML Tidy * +// can be found at http://tidy.sourceforge.net/, and a +// quick reference to the configuration options exists at +// http://tidy.sourceforge.net/docs/quickref.html +// +// * But were afraid to ask +// +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +word-2000: yes +clean: yes +drop-font-tags: no +doctype: auto +drop-empty-paras: yes +drop-proprietary-attributes: yes +enclose-block-text: yes +enclose-text: yes +escape-cdata: yes +logical-emphasis: yes +indent: auto +indent-spaces: 2 +break-before-br: yes +output-xhtml: yes + +force-output: yes diff --git a/xinha/plugins/HtmlTidy/html-tidy-logic.php b/xinha/plugins/HtmlTidy/html-tidy-logic.php new file mode 100755 index 0000000..b726aa1 --- /dev/null +++ b/xinha/plugins/HtmlTidy/html-tidy-logic.php @@ -0,0 +1,68 @@ + array("pipe", "r"), + 1 => array("pipe", "w") + ); + $process = proc_open("tidy -utf8 -config html-tidy-config.cfg", $descriptorspec, $pipes); + + + // Make sure the program started and we got the hooks... + // Either way, get some source code into $source + if (is_resource($process)) { + + // Feed untidy source into the stdin + fwrite($pipes[0], $source); + fclose($pipes[0]); + + // Read clean source out to the browser + while (!feof($pipes[1])) { + //echo fgets($pipes[1], 1024); + $newsrc .= fgets($pipes[1], 1024); + } + fclose($pipes[1]); + + // Clean up after ourselves + proc_close($process); + + } else { + // Better give them back what they came with, so they don't lose it all... + $newsrc = "\n" .$source. "\n"; + } + + // Split our source into an array by lines + $srcLines = explode("\n",$newsrc); + + // Get only the lines between the body tags + $startLn = 0; + while ( strpos( $srcLines[$startLn++], ' +var ns=""; + +editor.setHTML(ns); + \ No newline at end of file diff --git a/xinha/plugins/HtmlTidy/html-tidy.js b/xinha/plugins/HtmlTidy/html-tidy.js new file mode 100644 index 0000000..1b65e9e --- /dev/null +++ b/xinha/plugins/HtmlTidy/html-tidy.js @@ -0,0 +1,105 @@ +// Plugin for htmlArea to run code through the server's HTML Tidy +// By Adam Wright, for The University of Western Australia +// +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +function HtmlTidy(editor) { + this.editor = editor; + + var cfg = editor.config; + var bl = HtmlTidy.btnList; + var self = this; + + this.onMode = this.__onMode; + + // register the toolbar buttons provided by this plugin + var toolbar = []; + for (var i = 0; i < bl.length; ++i) { + var btn = bl[i]; + if (btn == "html-tidy") { + var id = "HT-html-tidy"; + cfg.registerButton(id, this._lc("HTML Tidy"), editor.imgURL(btn[0] + ".gif", "HtmlTidy"), true, + function(editor, id) { + // dispatch button press event + self.buttonPress(editor, id); + }, btn[1]); + toolbar.push(id); + } else if (btn == "html-auto-tidy") { + var btnTxt = [this._lc("Auto-Tidy"), this._lc("Don't Tidy")]; + var optionItems = new Object(); + optionItems[btnTxt[0]] = "auto"; + optionItems[btnTxt[1]] = "noauto"; + var ht_class = { + id : "HT-auto-tidy", + options : optionItems, + action : function (editor) { self.__onSelect(editor, this); }, + refresh : function (editor) { }, + context : "body" + }; + cfg.registerDropdown(ht_class); + } + } + + for (var i in toolbar) { + cfg.toolbar[0].push(toolbar[i]); + } +}; + +HtmlTidy._pluginInfo = { + name : "HtmlTidy", + version : "1.0", + developer : "Adam Wright", + developer_url : "http://blog.hipikat.org/", + sponsor : "The University of Western Australia", + sponsor_url : "http://www.uwa.edu.au/", + license : "htmlArea" +}; + +HtmlTidy.prototype._lc = function(string) { + return HTMLArea._lc(string, 'HtmlTidy'); +} + +HtmlTidy.prototype.__onSelect = function(editor, obj) { + // Get the toolbar element object + var elem = editor._toolbarObjects[obj.id].element; + + // Set our onMode event appropriately + if (elem.value == "auto") + this.onMode = this.__onMode; + else + this.onMode = null; +}; + +HtmlTidy.prototype.__onMode = function(mode) { + if ( mode == "textmode" ) { + this.buttonPress(this.editor, "HT-html-tidy"); + } +}; + +HtmlTidy.btnList = [ + null, // separator + ["html-tidy"], + ["html-auto-tidy"] +]; + +HtmlTidy.prototype.buttonPress = function(editor, id) { + + switch (id) + { + case "HT-html-tidy": + { + var oldhtml = editor.getHTML(); + if(oldhtml=="") break; //don't clean empty text + // Ask the server for some nice new html, based on the old... + HTMLArea._postback(_editor_url + 'plugins/HtmlTidy/html-tidy-logic.php', {'htisource_name' : oldhtml}, + function(javascriptResponse) { eval(javascriptResponse) }); + } + break; + } +}; + +HtmlTidy.prototype.processTidied = function(newSrc) { + editor = this.editor; + editor.setHTML(newSrc); +}; diff --git a/xinha/plugins/HtmlTidy/img/html-tidy.gif b/xinha/plugins/HtmlTidy/img/html-tidy.gif new file mode 100644 index 0000000..f82d140 Binary files /dev/null and b/xinha/plugins/HtmlTidy/img/html-tidy.gif differ diff --git a/xinha/plugins/HtmlTidy/lang/de.js b/xinha/plugins/HtmlTidy/lang/de.js new file mode 100644 index 0000000..588cdd8 --- /dev/null +++ b/xinha/plugins/HtmlTidy/lang/de.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// Author: Raimund Meyer ray@ray-of-light.org + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "HTML Tidy": "HTML Tidy" +} diff --git a/xinha/plugins/HtmlTidy/lang/fr.js b/xinha/plugins/HtmlTidy/lang/fr.js new file mode 100644 index 0000000..a6a87f8 --- /dev/null +++ b/xinha/plugins/HtmlTidy/lang/fr.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "HTML Tidy": "HTML Tidy" +} diff --git a/xinha/plugins/HtmlTidy/lang/nl.js b/xinha/plugins/HtmlTidy/lang/nl.js new file mode 100644 index 0000000..b6e396b --- /dev/null +++ b/xinha/plugins/HtmlTidy/lang/nl.js @@ -0,0 +1,16 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 + +// FOR TRANSLATORS: +// Nederlands: MadMiner basura@sitter.nl [2/2005] +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "HT-html-tidy": "HTML opschonen" +} \ No newline at end of file diff --git a/xinha/plugins/HtmlTidy/lang/no.js b/xinha/plugins/HtmlTidy/lang/no.js new file mode 100644 index 0000000..df93e5a --- /dev/null +++ b/xinha/plugins/HtmlTidy/lang/no.js @@ -0,0 +1,7 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "HTML Tidy": "HTML Tidy" +} \ No newline at end of file diff --git a/xinha/plugins/InsertAnchor/img/insert-anchor.gif b/xinha/plugins/InsertAnchor/img/insert-anchor.gif new file mode 100755 index 0000000..b6c38e0 Binary files /dev/null and b/xinha/plugins/InsertAnchor/img/insert-anchor.gif differ diff --git a/xinha/plugins/InsertAnchor/img/placeholder.gif b/xinha/plugins/InsertAnchor/img/placeholder.gif new file mode 100755 index 0000000..2c34277 Binary files /dev/null and b/xinha/plugins/InsertAnchor/img/placeholder.gif differ diff --git a/xinha/plugins/InsertAnchor/insert-anchor.css b/xinha/plugins/InsertAnchor/insert-anchor.css new file mode 100755 index 0000000..097d511 --- /dev/null +++ b/xinha/plugins/InsertAnchor/insert-anchor.css @@ -0,0 +1,9 @@ +a.anchor { + width: 18px; + height: 18px; + background-image: url(img/insert-anchor.gif); + background-repeat: no-repeat; + background-position: left top; + padding-left: 19px; + border: 1px dotted blue; +} diff --git a/xinha/plugins/InsertAnchor/insert-anchor.js b/xinha/plugins/InsertAnchor/insert-anchor.js new file mode 100755 index 0000000..58555bb --- /dev/null +++ b/xinha/plugins/InsertAnchor/insert-anchor.js @@ -0,0 +1,97 @@ +function InsertAnchor(editor) { + this.editor = editor; + var cfg = editor.config; + var self = this; + + // register the toolbar buttons provided by this plugin + cfg.registerButton({ + id : "insert-anchor", + tooltip : this._lc("Insert Anchor"), + image : editor.imgURL("insert-anchor.gif", "InsertAnchor"), + textMode : false, + action : function(editor) { + self.buttonPress(editor); + } + }); + cfg.addToolbarElement("insert-anchor", "createlink", 1); +} + +InsertAnchor._pluginInfo = { + name : "InsertAnchor", + origin : "version: 1.0, by Andre Rabold, MR Printware GmbH, http://www.mr-printware.de", + version : "2.0", + developer : "Udo Schmal", + developer_url : "http://www.schaffrath-neuemedien.de", + c_owner : "Udo Schmal", + sponsor : "L.N.Schaffrath NeueMedien", + sponsor_url : "http://www.schaffrath-neuemedien.de", + license : "htmlArea" +}; + +InsertAnchor.prototype._lc = function(string) { + return HTMLArea._lc(string, 'InsertAnchor'); +} + +InsertAnchor.prototype.onGenerate = function() { + var style_id = "IA-style" + var style = this.editor._doc.getElementById(style_id); + if (style == null) { + style = this.editor._doc.createElement("link"); + style.id = style_id; + style.rel = 'stylesheet'; + style.href = _editor_url + 'plugins/InsertAnchor/insert-anchor.css'; + this.editor._doc.getElementsByTagName("HEAD")[0].appendChild(style); + } +} + +InsertAnchor.prototype.buttonPress = function(editor) { + var outparam = null; + var html = editor.getSelectedHTML(); + var sel = editor._getSelection(); + var range = editor._createRange(sel); + var a = editor._activeElement(sel); + if(!(a != null && a.tagName.toLowerCase() == 'a')) { + a = editor._getFirstAncestor(sel, 'a'); + } + if (a != null && a.tagName.toLowerCase() == 'a') + outparam = { name : a.id }; + else + outparam = { name : '' }; + + editor._popupDialog( "plugin://InsertAnchor/insert_anchor", function( param ) { + if ( param ) { + var anchor = param["name"]; + if (anchor == "" || anchor == null) { + if (a) { + var child = a.innerHTML; + a.parentNode.removeChild(a); + editor.insertHTML(child); + } + return; + } + try { + var doc = editor._doc; + if (!a) { +// editor.surroundHTML('', ''); + a = doc.createElement("a"); + a.id = anchor; + a.name = anchor; + a.title = anchor; + a.className = "anchor"; + a.innerHTML = html; + if (HTMLArea.is_ie) { + range.pasteHTML(a.outerHTML); + } else { + editor.insertNodeAtSelection(a); + } + } else { + a.id = anchor; + a.name = anchor; + a.title = anchor; + a.className = "anchor"; + } + } + catch (e) { } + } + }, outparam); +} diff --git a/xinha/plugins/InsertAnchor/lang/de.js b/xinha/plugins/InsertAnchor/lang/de.js new file mode 100755 index 0000000..a6bd568 --- /dev/null +++ b/xinha/plugins/InsertAnchor/lang/de.js @@ -0,0 +1,10 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Raimund Meyer xinha@ray-of-light.org + +{ + "Insert Anchor": "Anker einfügen", + "Anchor name": "Name (ID)", + "Delete": "Löschen" +} diff --git a/xinha/plugins/InsertAnchor/lang/fr.js b/xinha/plugins/InsertAnchor/lang/fr.js new file mode 100644 index 0000000..07ed5f3 --- /dev/null +++ b/xinha/plugins/InsertAnchor/lang/fr.js @@ -0,0 +1,7 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + "Insert Anchor": "Insérer une ancre", + "Anchor name": "Nom de l'ancre", + "Delete": "Supprimer" +} \ No newline at end of file diff --git a/xinha/plugins/InsertAnchor/lang/no.js b/xinha/plugins/InsertAnchor/lang/no.js new file mode 100644 index 0000000..fe3130d --- /dev/null +++ b/xinha/plugins/InsertAnchor/lang/no.js @@ -0,0 +1,8 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Insert Anchor": "Sett inn anker", + "Anchor name": "Anker navn (ID)" +} \ No newline at end of file diff --git a/xinha/plugins/InsertAnchor/popups/insert_anchor.html b/xinha/plugins/InsertAnchor/popups/insert_anchor.html new file mode 100644 index 0000000..6cabf30 --- /dev/null +++ b/xinha/plugins/InsertAnchor/popups/insert_anchor.html @@ -0,0 +1,60 @@ + + + Insert Anchor + + + + + + +
    Insert Anchor
    +
    + + + + + +
    Anchor name
    + +
    + + + +
    +
    + + \ No newline at end of file diff --git a/xinha/plugins/InsertPicture/InsertPicture.php b/xinha/plugins/InsertPicture/InsertPicture.php new file mode 100644 index 0000000..6e25c17 --- /dev/null +++ b/xinha/plugins/InsertPicture/InsertPicture.php @@ -0,0 +1,282 @@ += 1024 && $size < 1024*1024) + return sprintf('%01.2f',$size/1024.0).' Kb'; + else + return sprintf('%01.2f',$size/(1024.0*1024)).' Mb'; + } + + if (isset($_FILES['file'])) { + $file = $_FILES['file']; + $ext = strrchr($file['name'],'.'); + if (!in_array($ext,$limitedext)) { + $message = "The file you are uploading doesn't have the correct extension."; + } else if (file_exists($LocalPicturePath.'\\'.$file['name'])) { + $message = "The file you are uploading already exists."; + } else if ($file['size'] > $limitedsize) { + $message = "The file you are uploading is to big. The max Filesize is ".formatSize($limitedsize)."."; + } else { + copy($file['tmp_name'], $LocalPicturePath.$strPathSeparator.$file['name']); + } + } + +?> + + + + Insert Image + + + + + + + + + + +
    Insert Image
    + + + + + + + +
    Images on the Server:
    + +'; + } else { + echo '
    '; + } +?> +
    +
    + +
    + +
    + Image Preview: +
    + +
    + +
    + + + + + + + + + + + + + +
    Image URL: + +
    Alternate text:
    + +

    + +

    +Layout + +
    + +
    Alignment:
    + + +

    + +

    Border thickness:
    + + +
    + +
    + +
    +Spacing + +
    + +
    Horizontal:
    + + +

    + +

    Vertical:
    + + +
    + +
    +
    + +
    + + +
    +
    + + diff --git a/xinha/plugins/InsertPicture/img/btn_open.gif b/xinha/plugins/InsertPicture/img/btn_open.gif new file mode 100644 index 0000000..3495a7b Binary files /dev/null and b/xinha/plugins/InsertPicture/img/btn_open.gif differ diff --git a/xinha/plugins/InsertPicture/img/nopic.gif b/xinha/plugins/InsertPicture/img/nopic.gif new file mode 100644 index 0000000..3e552f2 Binary files /dev/null and b/xinha/plugins/InsertPicture/img/nopic.gif differ diff --git a/xinha/plugins/InsertPicture/insert-picture.js b/xinha/plugins/InsertPicture/insert-picture.js new file mode 100644 index 0000000..e9d6cbc --- /dev/null +++ b/xinha/plugins/InsertPicture/insert-picture.js @@ -0,0 +1,93 @@ +// Insert Image plugin for HTMLArea +// Original Author - Udo Schmal +// +// (c) www.Schaffrath-NeueMedien.de 2004 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +//Usage: +// if(typeof InsertPicture != 'undefined') +// { InsertPicture.PicturePath = [webpath to imagefolder]; +// InsertPicture.LocalPicturePath = [local server path to imagefolder]; +// } +// for Example: +// if(typeof InsertPicture != 'undefined') +// { InsertPicture.PicturePath = _editor_url + "plugins/insertPicture/demo_pictures/"; +// InsertPicture.LocalPicturePath = "d:\\inetpub\\wwwroot\\xinha\\trunk\\plugins\\insertPicture\\demo_pictures"; +// } + + +function InsertPicture(editor) { +// nothing to do +}; + +InsertPicture._pluginInfo = { + name : "InsertPicture", + version : "1.0.1", + developer : "Udo Schmal", + developer_url : "http://www.Schaffrath-NeueMedien.de/", + sponsor : "L.N.Schaffrath NeueMedien", + sponsor_url : "http://www.schaffrath-neuemedien.de/", + c_owner : "Udo Schmal", + license : "htmlArea" +}; + +HTMLArea.prototype._insertImage = function(image) { + var editor = this; + var outparam = null; + if (typeof image == "undefined") { + image = this.getParentElement(); + if (image && !/^img$/i.test(image.tagName)) + image = null; + } + if (image) outparam = { + f_url : HTMLArea.is_ie ? image.src : image.getAttribute("src"), + f_alt : image.alt, + f_border : image.border, + f_align : image.align, + f_vert : image.vspace, + f_horiz : image.hspace, + f_width : image.width, + f_height : image.height + }; + + var manager = _editor_url + 'plugins/InsertPicture/InsertPicture.php' + + '?picturepath=' + InsertPicture.PicturePath; + + Dialog(manager, function(param) { + if (!param) { // user must have pressed Cancel + return false; + } + if (!image) { + var sel = editor._getSelection(); + var range = editor._createRange(sel); + editor._doc.execCommand("insertimage", false, param.f_url); + if (HTMLArea.is_ie) { + image = range.parentElement(); + // wonder if this works... + if (image.tagName.toLowerCase() != "img") { + image = image.previousSibling; + } + } else { + image = range.startContainer.previousSibling; + } + } else { + image.src = param.f_url; + } + + for (field in param) { + var value = param[field]; + switch (field) { + case "f_alt" : image.alt = value; break; + case "f_border" : image.border = parseInt(value || "0"); break; + case "f_align" : image.align = value; break; + case "f_vert" : image.vspace = parseInt(value || "0"); break; + case "f_horiz" : image.hspace = parseInt(value || "0"); break; + case "f_width" : image.width = parseInt(value || "0"); break; + case "f_height" : image.height = parseInt(value || "0"); break; + } + } + + + }, outparam); +}; \ No newline at end of file diff --git a/xinha/plugins/InsertPicture/lang/de.js b/xinha/plugins/InsertPicture/lang/de.js new file mode 100644 index 0000000..40206a8 --- /dev/null +++ b/xinha/plugins/InsertPicture/lang/de.js @@ -0,0 +1,17 @@ +// LANG: "de", ENCODING: UTF-8 | ISO-8859-1 +// Sponsored by http://www.schaffrath-neuemedien.de +// Author: Udo Schmal (gocher), +// +// (c) Udo Schmal & Schaffrath NeueMedien 2005 +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +{ + "The file you are uploading doesn't have the correct extension.": "Die hochgeladene Datei ist im falschen Format.", + "The file you are uploading already exists.": "Eine Datei mit diesem Namen existiert schon.", + "The file you are uploading is to big. The max Filesize is": "Die hochgeladene Datei ist zu groß. Die maximakle Dateigröße beträgt", + "Images on the Server:": "Bilder auf dem Server:", + "Please select a file to upload.": "Wählen Sie eine Datei zum hochladen aus.", + "Upload file": "Datei hochladen", + "Open file in new window": "Datei in neuen Fenster anzeigen" +}; \ No newline at end of file diff --git a/xinha/plugins/InsertPicture/viewpicture.html b/xinha/plugins/InsertPicture/viewpicture.html new file mode 100644 index 0000000..5b6d64d --- /dev/null +++ b/xinha/plugins/InsertPicture/viewpicture.html @@ -0,0 +1,46 @@ + + + + Preview + + + + + + + + \ No newline at end of file diff --git a/xinha/plugins/InsertWords/insert-words.js b/xinha/plugins/InsertWords/insert-words.js new file mode 100755 index 0000000..a0b440f --- /dev/null +++ b/xinha/plugins/InsertWords/insert-words.js @@ -0,0 +1,71 @@ +// Plugin for htmlArea to insert keywords, when a type of +// keyword is selected from a dropdown list +// By Adam Wright, for The University of Western Australia +// +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). + +function InsertWords(editor, params) { + this.editor = editor; + var cfg = editor.config; + var self = this; + + if(params[0] && params[0].combos) { + //if arguments where passed with registerPlugin use these + var combos = params[0].combos; + } else if (cfg.InsertWords && cfg.InsertWords.combos) { + //if combos is found in config use these + var combos = cfg.InsertWords.combos; + } else { + //no combos found + var combos = []; + } + + // register the toolbar with the keywords dropdown + var first = true; + var toolbar = []; + + for (var i = combos.length; --i >= 0;) { + var combo = combos[i]; + var id = "IW-id" + i; + var iw_class = { + id : id, + options : combo.options, + action : function (editor) { self.onSelect(editor, this, combo.context); }, + refresh : function (editor) { }, + context : combo.context + }; + cfg.registerDropdown(iw_class); + + if (combo.label) + toolbar.push("T[" + combo.label + "]"); + toolbar.push(id); + toolbar.push(first ? "separator" : "space"); + } + + cfg.addToolbarElement(toolbar, "linebreak", 1); + +}; + +InsertWords._pluginInfo = { + name : "InsertWords", + version : "1.0", + developer : "Adam Wright", + developer_url : "http://blog.hipikat.org/", + sponsor : "The University of Western Australia", + sponsor_url : "http://www.uwa.edu.au/", + license : "htmlArea" +}; + +InsertWords.prototype.onSelect = function(editor, obj, context) { + + // Get the toolbar object element + var elem = editor._toolbarObjects[obj.id].element; + + // Insert the keyword value blindly at the selection + editor.insertHTML(elem.value); + + // Reset the dropdown to it's label + elem.selectedIndex = 0; +} + diff --git a/xinha/plugins/Linker/dTree/api.html b/xinha/plugins/Linker/dTree/api.html new file mode 100644 index 0000000..3686a80 --- /dev/null +++ b/xinha/plugins/Linker/dTree/api.html @@ -0,0 +1,252 @@ + + + + + + Destroydrop » Javascripts » Tree » Api + + + + + + + + +
    + +
    + + + + +
    + +
    + + +

    Overview

    +
    +
    + + + +
    + + +

    Functions

    +
    +
    + + +

    add()

    +

    Adds a node to the tree.
    Can only be called before the tree is drawn.

    +

    id, pid and name are required.

    + +

    Parameters

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    idNumberUnique identity number.
    pidNumberNumber refering to the parent node. The value for the root node has to be -1.
    nameStringText label for the node.
    urlStringUrl for the node.
    titleStringTitle for the node.
    targetStringTarget for the node.
    iconStringImage file to use as the icon. Uses default if not specified.
    iconOpenStringImage file to use as the open icon. Uses default if not specified.
    openBooleanIs the node open.
    +
    + + +

    Example

    +

    mytree.add(1, 0, 'My node', 'node.html', 'node title', 'mainframe', 'img/musicfolder.gif');

    +
    + + +

    openAll()

    +

    Opens all the nodes.
    Can be called before and after the tree is drawn.

    +

    Example

    +

    mytree.openAll();

    +
    + + + +

    closeAll()

    +

    Closes all the nodes.
    Can be called before and after the tree is drawn.

    +

    Example

    +

    mytree.closeAll();

    +
    + + + +

    openTo()

    +

    Opens the tree to a certain node and can also select the node.
    + Can only be called after the tree is drawn.

    + +

    Parameters

    + + + + + + + + + + + + + + + + +
    NameTypeDescription
    idNumberIdentity number for the node.
    selectBooleanShould the node be selected.
    + +

    Example

    +

    mytree.openTo(4, true);

    + +
    + + +

    Configuration

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableTypeDefaultDescription
    targetStringtrueTarget for all the nodes.
    folderLinksBooleantrueShould folders be links.
    useSelectionBooleantrueNodes can be selected(highlighted).
    useCookiesBooleantrueThe tree uses cookies to rember it's state.
    useLinesBooleantrueTree is drawn with lines.
    useIconsBooleantrueTree is drawn with icons.
    useStatusTextBooleanfalseDisplays node names in the statusbar instead of the url.
    closeSameLevelBooleanfalseOnly one node within a parent can be expanded at the same time. openAll() and closeAll() functions do not work when this is enabled.
    inOrderBooleanfalseIf parent nodes are always added before children, setting this to true speeds up the tree.
    + +

    Example

    +

    mytree.config.target = "mytarget";

    + +
    + +
    + +
    + + + + +
    + +
    + + + + + \ No newline at end of file diff --git a/xinha/plugins/Linker/dTree/dtree.css b/xinha/plugins/Linker/dTree/dtree.css new file mode 100644 index 0000000..e8e5448 --- /dev/null +++ b/xinha/plugins/Linker/dTree/dtree.css @@ -0,0 +1,39 @@ +/*--------------------------------------------------| +| dTree 2.05 | www.destroydrop.com/javascript/tree/ | +|---------------------------------------------------| +| Copyright (c) 2002-2003 Geir Landr? | +|--------------------------------------------------*/ + +.dtree { + font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; + font-size: 11px; + color: #666; + white-space: nowrap; +} +.dtree img { + border: 0px; + vertical-align: middle; +} +.dtree a { + color: #333; + text-decoration: none; +} +.dtree a.node, .dtree a.nodeSel { + white-space: nowrap; + padding: 1px 2px 1px 2px; + /*padding: 0px 1px 0px 1px;*/ +} +.dtree a.node:hover, .dtree a.nodeSel:hover { + color: #333; + text-decoration: underline; +} +.dtree a.nodeSel { + background-color: #c0d2ec; + /* + -moz-border-radius : 4px; + border:1px dotted #333; + */ +} +.dtree .clip { + overflow: hidden; +} \ No newline at end of file diff --git a/xinha/plugins/Linker/dTree/dtree.js b/xinha/plugins/Linker/dTree/dtree.js new file mode 100644 index 0000000..f2ee303 --- /dev/null +++ b/xinha/plugins/Linker/dTree/dtree.js @@ -0,0 +1,723 @@ +/*--------------------------------------------------| + +| dTree 2.05 | www.destroydrop.com/javascript/tree/ | + +|---------------------------------------------------| + +| Copyright (c) 2002-2003 Geir Landr? | + +| | + +| This script can be used freely as long as all | + +| copyright messages are intact. | + +| | + +| Updated: 17.04.2003 | + +|--------------------------------------------------*/ + + + +// Node object + +function Node(id, pid, name, url, title, target, icon, iconOpen, open) { + + this.id = id; + + this.pid = pid; + + this.name = name; + + this.url = url; + + this.title = title; + + this.target = target; + + this.icon = icon; + + this.iconOpen = iconOpen; + + this._io = open || false; + + this._is = false; + + this._ls = false; + + this._hc = false; + + this._ai = 0; + + this._p; + +}; + + + +// Tree object + +function dTree(objName, baseDir) { + + this.config = { + + target : null, + + folderLinks : true, + + useSelection : true, + + useCookies : true, + + useLines : true, + + useIcons : true, + + useStatusText : false, + + closeSameLevel : false, + + inOrder : false + + } + + this.icon = { + + root : baseDir + 'img/base.gif', + + folder : baseDir + 'img/folder.gif', + + folderOpen : baseDir + 'img/folderopen.gif', + + node : baseDir + 'img/page.gif', + + empty : baseDir + 'img/empty.gif', + + line : baseDir + 'img/line.gif', + + join : baseDir + 'img/join.gif', + + joinBottom : baseDir + 'img/joinbottom.gif', + + plus : baseDir + 'img/plus.gif', + + plusBottom : baseDir + 'img/plusbottom.gif', + + minus : baseDir + 'img/minus.gif', + + minusBottom : baseDir + 'img/minusbottom.gif', + + nlPlus : baseDir + 'img/nolines_plus.gif', + + nlMinus : baseDir + 'img/nolines_minus.gif' + + }; + + this.obj = objName; + + this.aNodes = []; + + this.aIndent = []; + + this.root = new Node(-1); + + this.selectedNode = null; + + this.selectedFound = false; + + this.completed = false; + +}; + + + +// Adds a new node to the node array + +dTree.prototype.add = function(id, pid, name, url, title, target, icon, iconOpen, open) { + + this.aNodes[this.aNodes.length] = new Node(id, pid, name, url, title, target, icon, iconOpen, open); + +}; + + + +// Open/close all nodes + +dTree.prototype.openAll = function() { + + this.oAll(true); + +}; + +dTree.prototype.closeAll = function() { + + this.oAll(false); + +}; + + + +// Outputs the tree to the page + +dTree.prototype.toString = function() { + this.setCS_All(); + var str = '
    \n'; + + if (document.getElementById) { + + if (this.config.useCookies) this.selectedNode = this.getSelected(); + + str += this.addNode(this.root); + + } else str += 'Browser not supported.'; + + str += '
    '; + + if (!this.selectedFound) this.selectedNode = null; + + this.completed = true; + + return str; + +}; + + + +// Creates the tree structure + +dTree.prototype.addNode = function(pNode) { + + var str = ''; + + var n=0; + + if (this.config.inOrder) n = pNode._ai; + + for (n; n'; + + } + + if (node.url) { + + str += ''; + + str += node.name; + + if (node.url || ((!this.config.folderLinks || !node.url) && node._hc)) str += ''; + + str += '
  • '; + + if (node._hc) { + + str += '
    '; + + str += this.addNode(node); + + str += '
    '; + + } + + this.aIndent.pop(); + + return str; + +}; + + + +// Adds the empty and line icons + +dTree.prototype.indent = function(node, nodeId) { + + var str = ''; + + if (this.root.id != node.pid) { + + for (var n=0; n'; + + (node._ls) ? this.aIndent.push(0) : this.aIndent.push(1); + + if (node._hc) { + + str += ''; + + } else str += ''; + + } + + return str; + +}; + + + +// Checks if a node has any children and if it is the last sibling + +dTree.prototype.setCS = function(node) { + + var lastId; + + for (var n=0; n { _hc: haschildren, _ls_is: lastsibling} + + for(var n = 0; n < this.aNodes.length; n++) + { + var node = this.aNodes[n]; + if(!ids[node.pid]) + { + ids[node.pid] = { _hc: true, _ls_is: node.id }; + } + else + { + ids[node.pid]._hc = true; + ids[node.pid]._ls_is = node.id; + } + + if(!ids[node.id]) + { + ids[node.id] = { _hc: false, _ls_is: null } + } + } + + for(var n = 0; n < this.aNodes.length; n++) + { + var node = this.aNodes[n]; + node._ls = ids[node.pid]._ls_is == node.id ? true : false; + node._hc = ids[node.id]._hc; + } +} + +// Returns the selected node + +dTree.prototype.getSelected = function() { + + var sn = this.getCookie('cs' + this.obj); + + return (sn) ? sn : null; + +}; + + + +// Highlights the selected node + +dTree.prototype.s = function(id) { + + if (!this.config.useSelection) return; + + var cn = this.aNodes[id]; + + if (cn._hc && !this.config.folderLinks) return; + + if (this.selectedNode != id) { + + if (this.selectedNode || this.selectedNode==0) { + + eOld = document.getElementById("s" + this.obj + this.selectedNode); + + eOld.className = "node"; + + } + + eNew = document.getElementById("s" + this.obj + id); + + eNew.className = "nodeSel"; + + this.selectedNode = id; + + if (this.config.useCookies) this.setCookie('cs' + this.obj, cn.id); + + } + +}; + + + +// Toggle Open or close + +dTree.prototype.o = function(id) { + + var cn = this.aNodes[id]; + + this.nodeStatus(!cn._io, id, cn._ls); + + cn._io = !cn._io; + + if (this.config.closeSameLevel) this.closeLevel(cn); + + if (this.config.useCookies) this.updateCookie(); + +}; + + + +// Open or close all nodes + +dTree.prototype.oAll = function(status) { + + for (var n=0; n + + + + + Destroydrop » Javascripts » Tree + + + + + + + + +

    Destroydrop » Javascripts » Tree

    + +

    Example

    + +
    + +

    open all | close all

    + + + +
    + +

    ©2002-2003 Geir Landrö

    + + + + \ No newline at end of file diff --git a/xinha/plugins/Linker/dTree/img/base.gif b/xinha/plugins/Linker/dTree/img/base.gif new file mode 100644 index 0000000..9ac0b11 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/base.gif differ diff --git a/xinha/plugins/Linker/dTree/img/cd.gif b/xinha/plugins/Linker/dTree/img/cd.gif new file mode 100644 index 0000000..7503819 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/cd.gif differ diff --git a/xinha/plugins/Linker/dTree/img/copy.gif b/xinha/plugins/Linker/dTree/img/copy.gif new file mode 100644 index 0000000..35ef160 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/copy.gif differ diff --git a/xinha/plugins/Linker/dTree/img/empty.gif b/xinha/plugins/Linker/dTree/img/empty.gif new file mode 100644 index 0000000..b5cf523 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/empty.gif differ diff --git a/xinha/plugins/Linker/dTree/img/folder.gif b/xinha/plugins/Linker/dTree/img/folder.gif new file mode 100644 index 0000000..eb12976 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/folder.gif differ diff --git a/xinha/plugins/Linker/dTree/img/folderopen.gif b/xinha/plugins/Linker/dTree/img/folderopen.gif new file mode 100644 index 0000000..c5c3110 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/folderopen.gif differ diff --git a/xinha/plugins/Linker/dTree/img/globe.gif b/xinha/plugins/Linker/dTree/img/globe.gif new file mode 100644 index 0000000..57123d0 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/globe.gif differ diff --git a/xinha/plugins/Linker/dTree/img/imgfolder.gif b/xinha/plugins/Linker/dTree/img/imgfolder.gif new file mode 100644 index 0000000..e6d8803 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/imgfolder.gif differ diff --git a/xinha/plugins/Linker/dTree/img/join.gif b/xinha/plugins/Linker/dTree/img/join.gif new file mode 100644 index 0000000..34dd476 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/join.gif differ diff --git a/xinha/plugins/Linker/dTree/img/joinbottom.gif b/xinha/plugins/Linker/dTree/img/joinbottom.gif new file mode 100644 index 0000000..48b81c8 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/joinbottom.gif differ diff --git a/xinha/plugins/Linker/dTree/img/line.gif b/xinha/plugins/Linker/dTree/img/line.gif new file mode 100644 index 0000000..1a259ee Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/line.gif differ diff --git a/xinha/plugins/Linker/dTree/img/minus.gif b/xinha/plugins/Linker/dTree/img/minus.gif new file mode 100644 index 0000000..3d212a9 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/minus.gif differ diff --git a/xinha/plugins/Linker/dTree/img/minusbottom.gif b/xinha/plugins/Linker/dTree/img/minusbottom.gif new file mode 100644 index 0000000..dc3198b Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/minusbottom.gif differ diff --git a/xinha/plugins/Linker/dTree/img/move.gif b/xinha/plugins/Linker/dTree/img/move.gif new file mode 100644 index 0000000..59949d5 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/move.gif differ diff --git a/xinha/plugins/Linker/dTree/img/musicfolder.gif b/xinha/plugins/Linker/dTree/img/musicfolder.gif new file mode 100644 index 0000000..f620789 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/musicfolder.gif differ diff --git a/xinha/plugins/Linker/dTree/img/nolines_minus.gif b/xinha/plugins/Linker/dTree/img/nolines_minus.gif new file mode 100644 index 0000000..2592ac2 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/nolines_minus.gif differ diff --git a/xinha/plugins/Linker/dTree/img/nolines_plus.gif b/xinha/plugins/Linker/dTree/img/nolines_plus.gif new file mode 100644 index 0000000..f258ce2 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/nolines_plus.gif differ diff --git a/xinha/plugins/Linker/dTree/img/offline.gif b/xinha/plugins/Linker/dTree/img/offline.gif new file mode 100644 index 0000000..f79b029 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/offline.gif differ diff --git a/xinha/plugins/Linker/dTree/img/offline.png b/xinha/plugins/Linker/dTree/img/offline.png new file mode 100644 index 0000000..bb86270 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/offline.png differ diff --git a/xinha/plugins/Linker/dTree/img/page.gif b/xinha/plugins/Linker/dTree/img/page.gif new file mode 100644 index 0000000..42d7318 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/page.gif differ diff --git a/xinha/plugins/Linker/dTree/img/plus.gif b/xinha/plugins/Linker/dTree/img/plus.gif new file mode 100644 index 0000000..b2c9972 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/plus.gif differ diff --git a/xinha/plugins/Linker/dTree/img/plusbottom.gif b/xinha/plugins/Linker/dTree/img/plusbottom.gif new file mode 100644 index 0000000..b5671d8 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/plusbottom.gif differ diff --git a/xinha/plugins/Linker/dTree/img/question.gif b/xinha/plugins/Linker/dTree/img/question.gif new file mode 100644 index 0000000..dd4e685 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/question.gif differ diff --git a/xinha/plugins/Linker/dTree/img/trash.gif b/xinha/plugins/Linker/dTree/img/trash.gif new file mode 100644 index 0000000..cfa0f00 Binary files /dev/null and b/xinha/plugins/Linker/dTree/img/trash.gif differ diff --git a/xinha/plugins/Linker/dialog.html b/xinha/plugins/Linker/dialog.html new file mode 100644 index 0000000..9ca7d25 --- /dev/null +++ b/xinha/plugins/Linker/dialog.html @@ -0,0 +1,107 @@ +

    Insert/Modify Link

    +
    +
    (the dTree goes in here)
    +
    +
    + + + + + + + + + + +
    Target: +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Size:x (px)
    Name:
    Menu Bar:Toolbar:
    Location Bar:Status Bar:
    Scrollbars:Resizeable:
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + +
    +
    + +
    + + + + + + +
    + +
    +
    + +
    + + + +
    +
    +
    \ No newline at end of file diff --git a/xinha/plugins/Linker/lang/de.js b/xinha/plugins/Linker/lang/de.js new file mode 100644 index 0000000..5bbaf73 --- /dev/null +++ b/xinha/plugins/Linker/lang/de.js @@ -0,0 +1,21 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Udo Schmal +{ + "You must select some text before making a new link.": "Sie müssen einen Text markieren um einen Link zu erstellen", + "Are you sure you wish to remove this link?": "Wollen Sie diesen Link wirklich entfernen?", + "REMOVE LINK": "LINK ENTFERNEN", + "CANCEL": "ABBRECHEN", + "URL Link": "URL Adresse", + "Ordinary Link": "Standard Link", + "Same Window (jump out of frames)": "Selbes Fenster (ganzer Bereich)", + "New Window": "Neues Fenster", + "Popup Window": "Pop-Up Fenster", + "Email Link": "Email Link", + "Email Address:": "Email Adresse", + "Subject:": "Betreff:", + "Message Template:": "Nachrichten Vorlage:", + "Size:": "Größe:", + "Name:": "Name:" +} \ No newline at end of file diff --git a/xinha/plugins/Linker/lang/fr.js b/xinha/plugins/Linker/lang/fr.js new file mode 100644 index 0000000..17f2880 --- /dev/null +++ b/xinha/plugins/Linker/lang/fr.js @@ -0,0 +1,19 @@ +// I18N constants +// LANG: "fr", ENCODING: UTF-8 +{ + "You must select some text before making a new link.": "Vous devez sélectionner un texte avant de créer un nouveau lien", + "Are you sure you wish to remove this link?": "Confirmez-vous la suppression de ce lien ?", + "REMOVE LINK": "Supprimer", + "CANCEL": "Annuler", + "URL Link": "Lien URL", + "Ordinary Link": "Lien standard", + "Same Window (jump out of frames)": "Même fenêtre (sort des frames)", + "New Window": "Nouvelle fenêtre", + "Popup Window": "Fenêtre popup", + "Email Link": "Lien email", + "Email Address:": "Adresse email", + "Subject:": "Sujet", + "Message Template:": "Message", + "Size:": "Taille", + "Name:": "Nom" +} \ No newline at end of file diff --git a/xinha/plugins/Linker/lang/no.js b/xinha/plugins/Linker/lang/no.js new file mode 100644 index 0000000..9cfcb92 --- /dev/null +++ b/xinha/plugins/Linker/lang/no.js @@ -0,0 +1,8 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "You must select some text before making a new link.": "Du må markere tekst eller et bilde før du kan lage en lenke.", + "Are you sure you wish to remove this link?": "Er du sikker på at du vil fjerne lenken?" +} \ No newline at end of file diff --git a/xinha/plugins/Linker/lang/pl.js b/xinha/plugins/Linker/lang/pl.js new file mode 100644 index 0000000..e455f80 --- /dev/null +++ b/xinha/plugins/Linker/lang/pl.js @@ -0,0 +1,20 @@ +// I18N constants +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, http://www.eskot.krakow.pl/portfolio/, koto@webworkers.pl +{ + "You must select some text before making a new link.": "Zaznacz tekst przed dodaniem odnośnika.", + "Are you sure you wish to remove this link?": "Na pewno chcesz usunąć odnośnik?", + "REMOVE LINK": "USUŃ ODNOŚNIK", + "CANCEL": "ANULUJ", + "URL Link": "Adres URL", + "Ordinary Link": "Zwykły odnośnik", + "Same Window (jump out of frames)": "To samo okno (wyskocz z ramek)", + "New Window": "Nowe okno", + "Popup Window": "Okienko pop-up", + "Email Link": "Link do e-maila", + "Email Address:": "Adres e-mail", + "Subject:": "Temat:", + "Message Template:": "Szablon wiadmości:", + "Size:": "Rozmiar:", + "Name:": "Nazwa:" +} \ No newline at end of file diff --git a/xinha/plugins/Linker/linker.js b/xinha/plugins/Linker/linker.js new file mode 100644 index 0000000..5156d94 --- /dev/null +++ b/xinha/plugins/Linker/linker.js @@ -0,0 +1,552 @@ +/** htmlArea - James' Fork - Linker Plugin **/ +Linker._pluginInfo = +{ + name : "Linker", + version : "1.0", + developer: "James Sleeman", + developer_url: "http://www.gogo.co.nz/", + c_owner : "Gogo Internet Services", + license : "htmlArea", + sponsor : "Gogo Internet Services", + sponsor_url : "http://www.gogo.co.nz/" +}; + +HTMLArea.loadStyle('dTree/dtree.css', 'Linker'); + +HTMLArea.Config.prototype.Linker = +{ + 'backend' : _editor_url + 'plugins/Linker/scan.php', + 'files' : null +} + + +function Linker(editor, args) +{ + this.editor = editor; + this.lConfig = editor.config.Linker; + + var linker = this; + if(editor.config.btnList.createlink) + { + editor.config.btnList.createlink[3] + = function(e, objname, obj) { linker._createLink(linker._getSelectedAnchor()); }; + } + else + { + editor.config.registerButton( + 'createlink', 'Insert/Modify Hyperlink', [_editor_url + "images/ed_buttons_main.gif",6,1], false, + function(e, objname, obj) { linker._createLink(linker._getSelectedAnchor()); } + ); + } + + // See if we can find 'createlink' + editor.config.addToolbarElement("createlink", "createlink", 0); +} + +Linker.prototype._lc = function(string) +{ + return HTMLArea._lc(string, 'Linker'); +} + +Linker.prototype._createLink = function(a) +{ + if(!a && this.editor._selectionEmpty(this.editor._getSelection())) + { + alert(this._lc("You must select some text before making a new link.")); + return false; + } + + var inputs = + { + type: 'url', + href: 'http://www.example.com/', + target: '', + p_width: '', + p_height: '', + p_options: ['menubar=no','toolbar=yes','location=no','status=no','scrollbars=yes','resizeable=yes'], + to: 'alice@example.com', + subject: '', + body: '' + } + + if(a && a.tagName.toLowerCase() == 'a') + { + var m = a.href.match(/^mailto:(.*@[^?&]*)(\?(.*))?$/); + var anchor = a.href.match(/^#(.*)$/); + if(m) + { + // Mailto + inputs.type = 'mailto'; + inputs.to = m[1]; + if(m[3]) + { + var args = m[3].split('&'); + for(var x = 0; x]*)(\?[^<]*)?$/i.test(a.innerHTML)) + { + a.innerHTML = RegExp.$1; + } + } + } + } + else + { + if(!atr.href) return true; + + // Insert a link, we let the browser do this, we figure it knows best + var tmp = HTMLArea.uniq('http://www.example.com/Link'); + linker.editor._doc.execCommand('createlink', false, tmp); + + // Fix them up + var anchors = linker.editor._doc.getElementsByTagName('a'); + for(var i = 0; i < anchors.length; i++) + { + var a = anchors[i]; + if(a.href == tmp) + { + // Found one. + for(var i in atr) + { + a.setAttribute(i, atr[i]); + } + } + } + } + } + + this._dialog.show(inputs, doOK); + +} + +Linker.prototype._getSelectedAnchor = function() +{ + var sel = this.editor._getSelection(); + var rng = this.editor._createRange(sel); + var a = this.editor._activeElement(sel); + if(a != null && a.tagName.toLowerCase() == 'a') + { + return a; + } + else + { + a = this.editor._getFirstAncestor(sel, 'a'); + if(a != null) + { + return a; + } + } + return null; +} + +Linker.prototype.onGenerate = function() +{ + this._dialog = new Linker.Dialog(this); +} +// Inline Dialog for Linker + +Linker.Dialog_dTrees = [ ]; + + +Linker.Dialog = function (linker) +{ + var lDialog = this; + this.Dialog_nxtid = 0; + this.linker = linker; + this.id = { }; // This will be filled below with a replace, nifty + + this.ready = false; + this.files = false; + this.html = false; + this.dialog = false; + + // load the dTree script + this._prepareDialog(); + +} + +Linker.Dialog.prototype._prepareDialog = function() +{ + var lDialog = this; + var linker = this.linker; + + // We load some stuff up int he background, recalling this function + // when they have loaded. This is to keep the editor responsive while + // we prepare the dialog. + if(typeof dTree == 'undefined') + { + HTMLArea._loadback(_editor_url + 'plugins/Linker/dTree/dtree.js', + function() {lDialog._prepareDialog(); } + ); + return; + } + + if(this.files == false) + { + if(linker.lConfig.backend) + { + //get files from backend + HTMLArea._getback(linker.lConfig.backend, + function(txt) { + try { + eval('lDialog.files = '+txt); + } catch(Error) { + lDialog.files = [ {url:'',title:Error.toString()} ]; + } + lDialog._prepareDialog(); }); + } + else if(linker.lConfig.files != null) + { + //get files from plugin-config + lDialog.files = linker.lConfig.files; + lDialog._prepareDialog(); + } + return; + } + var files = this.files; + + if(this.html == false) + { + HTMLArea._getback(_editor_url + 'plugins/Linker/dialog.html', function(txt) { lDialog.html = txt; lDialog._prepareDialog(); }); + return; + } + var html = this.html; + + // Now we have everything we need, so we can build the dialog. + var dialog = this.dialog = new HTMLArea.Dialog(linker.editor, this.html, 'Linker'); + var dTreeName = HTMLArea.uniq('dTree_'); + + this.dTree = new dTree(dTreeName, _editor_url + 'plugins/Linker/dTree/'); + eval(dTreeName + ' = this.dTree'); + + this.dTree.add(this.Dialog_nxtid++, -1, document.location.host, null, document.location.host); + this.makeNodes(files, 0); + + // Put it in + var ddTree = this.dialog.getElementById('dTree'); + //ddTree.innerHTML = this.dTree.toString(); + ddTree.innerHTML = ''; + ddTree.style.position = 'absolute'; + ddTree.style.left = 1 + 'px'; + ddTree.style.top = 0 + 'px'; + ddTree.style.overflow = 'auto'; + this.ddTree = ddTree; + this.dTree._linker_premade = this.dTree.toString(); + + var options = this.dialog.getElementById('options'); + options.style.position = 'absolute'; + options.style.top = 0 + 'px'; + options.style.right = 0 + 'px'; + options.style.width = 320 + 'px'; + options.style.overflow = 'auto'; + + // Hookup the resizer + this.dialog.onresize = function() + { + options.style.height = ddTree.style.height = (parseInt(dialog.height) - dialog.getElementById('h1').offsetHeight) + 'px'; + ddTree.style.width = (parseInt(dialog.width) - 322 ) + 'px'; + } + + this.ready = true; +} + +Linker.Dialog.prototype.makeNodes = function(files, parent) +{ + for(var i = 0; i < files.length; i++) + { + if(typeof files[i] == 'string') + { + this.dTree.add(Linker.nxtid++, parent, + files[i].replace(/^.*\//, ''), + 'javascript:document.getElementsByName(\'' + this.dialog.id.href + '\')[0].value=decodeURIComponent(\'' + encodeURIComponent(files[i]) + '\');document.getElementsByName(\'' + this.dialog.id.type + '\')[0].click();document.getElementsByName(\'' + this.dialog.id.href + '\')[0].focus();void(0);', + files[i]); + } + else if(files[i].length) + { + var id = this.Dialog_nxtid++; + this.dTree.add(id, parent, files[i][0].replace(/^.*\//, ''), null, files[i][0]); + this.makeNodes(files[i][1], id); + } + else if(typeof files[i] == 'object') + { + if(files[i].children) { + var id = this.Dialog_nxtid++; + } else { + var id = Linker.nxtid++; + } + + if(files[i].title) var title = files[i].title; + else if(files[i].url) var title = files[i].url.replace(/^.*\//, ''); + else var title = "no title defined"; + if(files[i].url) var link = 'javascript:document.getElementsByName(\'' + this.dialog.id.href + '\')[0].value=decodeURIComponent(\'' + encodeURIComponent(files[i].url) + '\');document.getElementsByName(\'' + this.dialog.id.type + '\')[0].click();document.getElementsByName(\'' + this.dialog.id.href + '\')[0].focus();void(0);'; + else var link = ''; + + this.dTree.add(id, parent, title, link, title); + if(files[i].children) { + this.makeNodes(files[i].children, id); + } + } + } +} + +Linker.Dialog.prototype._lc = Linker.prototype._lc; + +Linker.Dialog.prototype.show = function(inputs, ok, cancel) +{ + if(!this.ready) + { + var lDialog = this; + window.setTimeout(function() {lDialog.show(inputs,ok,cancel);},100); + return; + } + + if(this.ddTree.innerHTML == '') + { + this.ddTree.innerHTML = this.dTree._linker_premade; + } + + if(inputs.type=='url') + { + this.dialog.getElementById('urltable').style.display = ''; + this.dialog.getElementById('mailtable').style.display = 'none'; + this.dialog.getElementById('anchortable').style.display = 'none'; + } + else if(inputs.type=='anchor') + { + this.dialog.getElementById('urltable').style.display = 'none'; + this.dialog.getElementById('mailtable').style.display = 'none'; + this.dialog.getElementById('anchortable').style.display = ''; + } + else + { + this.dialog.getElementById('urltable').style.display = 'none'; + this.dialog.getElementById('mailtable').style.display = ''; + this.dialog.getElementById('anchortable').style.display = 'none'; + } + + if(inputs.target=='popup') + { + this.dialog.getElementById('popuptable').style.display = ''; + } + else + { + this.dialog.getElementById('popuptable').style.display = 'none'; + } + + var anchor = this.dialog.getElementById('anchor'); + for(var i=0;i]+name="([^"]+)"/gi); + if(m) + { + for(i=0;i$url, 'children'=>$subdir); + } + } + elseif(is_file($path)) + { + if(($include && !preg_match($include, $url)) || ($exclude && preg_match($exclude, $url))) continue; + $files[] = array('url'=>$url); + } + + } + } + @closedir($dh); + return dirsort($files); + } + + function dirsort($files) + { + usort($files, 'dircomp'); + return $files; + } + + function dircomp($a, $b) + { + if(is_array($a)) $a = $a[0]; + if(is_array($b)) $b = $b[0]; + return strcmp(strtolower($a), strtolower($b)); + } + + function to_js($var, $tabs = 0) + { + if(is_numeric($var)) + { + return $var; + } + + if(is_string($var)) + { + return "'" . js_encode($var) . "'"; + } + + if(is_array($var)) + { + $useObject = false; + foreach(array_keys($var) as $k) { + if(!is_numeric($k)) $useObject = true; + } + $js = array(); + foreach($var as $k => $v) + { + $i = ""; + if($useObject) { + if(preg_match('#[a-zA-Z]+[a-zA-Z0-9]*#', $k)) { + $i .= "$k: "; + } else { + $i .= "'$k': "; + } + } + $i .= to_js($v, $tabs + 1); + $js[] = $i; + } + if($useObject) { + $ret = "{\n" . tabify(implode(",\n", $js), $tabs) . "\n}"; + } else { + $ret = "[\n" . tabify(implode(",\n", $js), $tabs) . "\n]"; + } + return $ret; + } + + return 'null'; + } + + function tabify($text, $tabs) + { + if($text) + { + return str_repeat(" ", $tabs) . preg_replace('/\n(.)/', "\n" . str_repeat(" ", $tabs) . "\$1", $text); + } + } + + function js_encode($string) + { + static $strings = "\\,\",',%,&,<,>,{,},@,\n,\r"; + + if(!is_array($strings)) + { + $tr = array(); + foreach(explode(',', $strings) as $chr) + { + $tr[$chr] = sprintf('\x%02X', ord($chr)); + } + $strings = $tr; + } + + return strtr($string, $strings); + } + + + echo to_js(scan($dir)); +?> diff --git a/xinha/plugins/ListType/ListType.css b/xinha/plugins/ListType/ListType.css new file mode 100644 index 0000000..8ad84b9 --- /dev/null +++ b/xinha/plugins/ListType/ListType.css @@ -0,0 +1,43 @@ +.ListType { } +.ListType a { + display:block; + float:left; + margin:2px 0 0 5px; + padding:0; + width:50px; + height:40px; + border:1px solid #9c96a5; +} +.ListType a:hover { + border:1px solid #ffd760; +} +.ListType a.active { + border:1px solid #000084; +} +.ListType a.circle { + background:url(img/circle.png); +} +.ListType a.disc { + background:url(img/disc.png); +} +.ListType a.square { + background:url(img/square.png); +} +.ListType a.decimal { + background:url(img/decimal.png); +} +.ListType a.lower-alpha { + background:url(img/lower-alpha.png); +} +.ListType a.upper-alpha { + background:url(img/upper-alpha.png); +} +.ListType a.lower-roman { + background:url(img/lower-roman.png); +} +.ListType a.upper-roman { + background:url(img/upper-roman.png); +} +.ListType a.none { + background:url(img/none.png); +} diff --git a/xinha/plugins/ListType/img/circle.png b/xinha/plugins/ListType/img/circle.png new file mode 100644 index 0000000..e8fd0b6 Binary files /dev/null and b/xinha/plugins/ListType/img/circle.png differ diff --git a/xinha/plugins/ListType/img/decimal.png b/xinha/plugins/ListType/img/decimal.png new file mode 100644 index 0000000..cda7518 Binary files /dev/null and b/xinha/plugins/ListType/img/decimal.png differ diff --git a/xinha/plugins/ListType/img/disc.png b/xinha/plugins/ListType/img/disc.png new file mode 100644 index 0000000..0dd7b62 Binary files /dev/null and b/xinha/plugins/ListType/img/disc.png differ diff --git a/xinha/plugins/ListType/img/lower-alpha.png b/xinha/plugins/ListType/img/lower-alpha.png new file mode 100644 index 0000000..1714b70 Binary files /dev/null and b/xinha/plugins/ListType/img/lower-alpha.png differ diff --git a/xinha/plugins/ListType/img/lower-roman.png b/xinha/plugins/ListType/img/lower-roman.png new file mode 100644 index 0000000..7c934ff Binary files /dev/null and b/xinha/plugins/ListType/img/lower-roman.png differ diff --git a/xinha/plugins/ListType/img/none.png b/xinha/plugins/ListType/img/none.png new file mode 100644 index 0000000..3343f3d Binary files /dev/null and b/xinha/plugins/ListType/img/none.png differ diff --git a/xinha/plugins/ListType/img/square.png b/xinha/plugins/ListType/img/square.png new file mode 100644 index 0000000..884fffc Binary files /dev/null and b/xinha/plugins/ListType/img/square.png differ diff --git a/xinha/plugins/ListType/img/upper-alpha.png b/xinha/plugins/ListType/img/upper-alpha.png new file mode 100644 index 0000000..1654508 Binary files /dev/null and b/xinha/plugins/ListType/img/upper-alpha.png differ diff --git a/xinha/plugins/ListType/img/upper-roman.png b/xinha/plugins/ListType/img/upper-roman.png new file mode 100644 index 0000000..8d08ce5 Binary files /dev/null and b/xinha/plugins/ListType/img/upper-roman.png differ diff --git a/xinha/plugins/ListType/lang/de.js b/xinha/plugins/ListType/lang/de.js new file mode 100644 index 0000000..c86a2fd --- /dev/null +++ b/xinha/plugins/ListType/lang/de.js @@ -0,0 +1,23 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Raimund Meyer xinha@ray-of-light.org + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Decimal numbers": "Zahlen", + "Lower roman numbers": "Römisch klein", + "Upper roman numbers": "Römisch groß", + "Lower latin letters": "Zeichen klein", + "Upper latin letters": "Zeichen groß", + "Lower greek letters": "Griechisch", + "Choose list style type (for ordered lists)": "Wählen Sie einen Typ für die Nummerierung aus" +} diff --git a/xinha/plugins/ListType/lang/fr.js b/xinha/plugins/ListType/lang/fr.js new file mode 100644 index 0000000..d503d00 --- /dev/null +++ b/xinha/plugins/ListType/lang/fr.js @@ -0,0 +1,23 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Decimal numbers": "Nombres décimaux", + "Lower roman numbers": "Nombres romains minuscule", + "Upper roman numbers": "Nombres romains majuscule", + "Lower latin letters": "Lettres latines minuscule", + "Upper latin letters": "Lettres latines majuscule", + "Lower greek letters": "Lettres grecques minuscule", + "Choose list style type (for ordered lists)": "Choisissez le style de liste (pour les listes ordonnées)" +} diff --git a/xinha/plugins/ListType/lang/nl.js b/xinha/plugins/ListType/lang/nl.js new file mode 100644 index 0000000..d7ca4b9 --- /dev/null +++ b/xinha/plugins/ListType/lang/nl.js @@ -0,0 +1,23 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Decimal numbers": "Decimale nummers", + "Lower roman numbers": "Romeinse nummers klein", + "Upper roman numbers": "Romeinse nummers groot", + "Lower latin letters": "Latijnse letters klein", + "Upper latin letters": "Latijnse letters groot", + "Lower greek letters": "Griekse letters", + "Choose list style type (for ordered lists)": "Kies stijl type (voor ordered lists)" +} diff --git a/xinha/plugins/ListType/lang/pl.js b/xinha/plugins/ListType/lang/pl.js new file mode 100644 index 0000000..8179033 --- /dev/null +++ b/xinha/plugins/ListType/lang/pl.js @@ -0,0 +1,23 @@ +// I18N constants + +// LANG: "pl", ENCODING: UTF-8 +// translated: Krzysztof Kotowicz, koto1sa@o2.pl, http://www.eskot.krakow.pl/portfolio + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Decimal numbers": "Cyfry arabskie", + "Lower roman numbers": "Małe rzymskie", + "Upper roman numbers": "Duże rzymskie", + "Lower latin letters": "Małe litery", + "Upper latin letters": "Duże litery", + "Lower greek letters": "Małe litery greckie", + "Choose list style type (for ordered lists)": "Wybierz typ listy numerowanej" +} diff --git a/xinha/plugins/ListType/list-type.js b/xinha/plugins/ListType/list-type.js new file mode 100644 index 0000000..1d3eb68 --- /dev/null +++ b/xinha/plugins/ListType/list-type.js @@ -0,0 +1,191 @@ +// ListType Plugin for Xinha +// Toolbar Implementation by Mihai Bazon, http://dynarch.com/mishoo/ +HTMLArea.loadStyle( 'ListType.css', 'ListType' ); + +function ListType( editor ) +{ + this.editor = editor; + var cfg = editor.config; + var self = this; + + if ( cfg.ListType.mode == 'toolbar' ) + { + var options = {}; + options[HTMLArea._lc( "Decimal numbers", "ListType" )] = "decimal"; + options[HTMLArea._lc( "Lower roman numbers", "ListType" )] = "lower-roman"; + options[HTMLArea._lc( "Upper roman numbers", "ListType" )] = "upper-roman"; + options[HTMLArea._lc( "Lower latin letters", "ListType" )] = "lower-alpha"; + options[HTMLArea._lc( "Upper latin letters", "ListType" )] = "upper-alpha"; + if (!HTMLArea.is_ie) + // IE doesn't support this property; even worse, it complains + // with a gross error message when we tried to select it, + // therefore let's hide it from the damn "browser". + options[HTMLArea._lc( "Lower greek letters", "ListType" )] = "lower-greek"; + var obj = + { + id : "listtype", + tooltip : HTMLArea._lc( "Choose list style type (for ordered lists)", "ListType" ), + options : options, + action : function( editor ) { self.onSelect( editor, this ); }, + refresh : function( editor ) { self.updateValue( editor, this ); }, + context : "ol" + }; + cfg.registerDropdown( obj ); + cfg.addToolbarElement( "listtype", ["insertorderedlist","orderedlist"], 1 ); + } + else + { + editor._ListType = editor.addPanel( 'right' ); + HTMLArea.freeLater( editor, '_ListType' ); + HTMLArea.addClass( editor._ListType, 'ListType' ); + // hurm, ok it's pretty to use the background color for the whole panel, + // but should not it be set by default when creating the panel ? + HTMLArea.addClass( editor._ListType.parentNode, 'dialog' ); + + editor.notifyOn( 'modechange', + function(e,args) + { + if ( args.mode == 'text' ) editor.hidePanel( editor._ListType ); + } + ); + + var elts_ul = ['disc', 'circle', 'square', 'none']; + var elts_ol = ['decimal', 'lower-alpha', 'upper-alpha', 'lower-roman', 'upper-roman', 'none']; + var divglobal = document.createElement( 'div' ); + divglobal.style.height = '90px'; + var div = document.createElement( 'div' ); + div.id = 'LTdivUL'; + div.style.display = 'none'; + for ( var i=0; i + +Quick Tag Editor + + + + + + +
    +
    Quick Tag Editor
    +
    + + + + + + +
    + < + + > +
    +
    +
    +
    + + + +
    +
    +
    +
    + + diff --git a/xinha/plugins/QuickTag/quick-tag.js b/xinha/plugins/QuickTag/quick-tag.js new file mode 100644 index 0000000..2ef6e1a --- /dev/null +++ b/xinha/plugins/QuickTag/quick-tag.js @@ -0,0 +1,53 @@ +/*---------------------------------------*\ + Quick Tag Editor Plugin for HTMLArea-3.0 + ----------------------------------------- + author: Cau guanabara + e-mail: caugb@ibest.com.br +\*---------------------------------------*/ + +function QuickTag(editor) { + var cfg = editor.config; + var self = this; + + cfg.registerButton({ + id : "quickeditor", + tooltip : this._lc("Quick Tag Editor"), + image : editor.imgURL("ed_quicktag.gif", "QuickTag"), + textMode : false, + action : function(editor) { + self.buttonPress(editor); + } + }); + cfg.addToolbarElement("quickeditor", "htmlmode", 1); +}; + +QuickTag.prototype.buttonPress = function(editor) { +var self = this; +var sel = editor.getSelectedHTML().replace(/(<[^>]*>| |\n|\r)/g,""); +var param = new Object(); +param.editor = editor; + + if(/\w/.test(sel)) + editor._popupDialog("plugin://QuickTag/quicktag", function(p) { self.setTag(editor, p); }, param); + else + alert(this._lc('You have to select some text')); +}; + +QuickTag.prototype.setTag = function(editor, param) { +editor.surroundHTML(param.tagopen,param.tagclose); +}; + +QuickTag._pluginInfo = { +name : "QuickTag", +version : "1.0 - beta", +developer : "Cau Guanabara", +developer_url : "mailto:caugb@ibest.com.br", +c_owner : "Cau Guanabara", +sponsor : "Independent production", +sponsor_url : "http://www.netflash.com.br/gb/HA3-rc1/examples/quick-tag.html", +license : "htmlArea" +}; + +QuickTag.prototype._lc = function(string) { + return HTMLArea._lc(string, 'QuickTag'); +} \ No newline at end of file diff --git a/xinha/plugins/QuickTag/tag-lib.js b/xinha/plugins/QuickTag/tag-lib.js new file mode 100644 index 0000000..0f22ad5 --- /dev/null +++ b/xinha/plugins/QuickTag/tag-lib.js @@ -0,0 +1,356 @@ +/* + TAG Library for QuickTag Plugin + ------------------------------- + + allTags = All tags that appears in the first dropdown ('TAGS') {'caption': 'value'} + tagLib = The tags with options (just to check if current TAG have options) {'[TAG]': true} + subTagLib = Complements for some tags that needs it (TABLE) + {'[TAG]': {'op': 'after tag open', 'cl': 'before tag close'}} + opTag_all = Common attributes to all TAGS {'caption': 'value'} + opAtt_all = Options for the common attributes {'attribute': {'caption': 'value'}} + opTag_[TAG] = Attributes for [TAG] {'caption': 'value'} + opAtt_[TAG] = Options for the [TAG] attributes {'attribute': {'caption': 'value'}} + +*/ + +var allTags = { +'a': 'a', +'a (full)': 'a href="" target=""', +'address': 'address', +'b': 'b', +'big': 'big', +'blockquote': 'blockquote', +'code': 'code', +'div': 'div', +'em': 'em', +'fieldset': 'fieldset', +'font': 'font', +'font (full)': 'font face="" size="" color=""', +'h1': 'h1', +'h2': 'h2', +'h3': 'h3', +'h4': 'h4', +'h5': 'h5', +'h6': 'h6', +'i': 'i', +'legend': 'legend', +'li': 'li', +'ol': 'ol', +'ul': 'ul', +'p': 'p', +'pre': 'pre', +'small': 'small', +'span': 'span', +'strong': 'strong', +'sub': 'sub', +'sup': 'sup', +'table': 'table' +}; + +// tags with options +var tagLib = { +'a': true, +'div': true, +'font': true, +'h1': true, +'h2': true, +'h3': true, +'h4': true, +'h5': true, +'h6': true, +'p': true, +'table': true +}; +// tags that needs some complement +var subTagLib = {'table': {'op': '', + 'cl': ''} +}; + +var opTag_a = { +'href': 'href="', +'name': 'name="', +'target': 'target="' +}; +var opAtt_a = { +'href': {'http://': 'http://', + 'https://': 'https://', + 'ftp://': 'ftp://', + 'mailto:': 'mailto:', + '#': '#"'}, +'target': {'_top': '_top"', + '_self': '_self"', + '_parent': '_parent"', + '_blank': '_blank"'} +}; + +var opTag_font = { +'face': 'face="', +'size': 'size="', +'color': 'color="' +}; +var opAtt_font = { +'face': {'Verdana': 'Verdana"', + 'Arial': 'Arial"', + 'Tahoma': 'Tahoma"', + 'Courier New': 'Courier New"', + 'Times New Roman': 'Times New Roman"'}, +'size': {'1': '1"','2': '2"','3': '3"','4': '4"','5': '5"','6': '6"', + '+1': '+1"','+2': '+2"','+3': '+3"','+4': '+4"','+5': '+5"','+6': '+6"', + '-1': '-1"','-2': '-2"','-3': '-3"','-4': '-4"','-5': '-5"','-6': '-6"'} +}; + +var opTag_div = { +'align': 'align="' +}; +var opAtt_div = { +'align': {'center': 'center"', + 'left': 'left"', + 'right': 'right"', + 'justify': 'justify"'} +}; + +var opTag_h = { +'align': 'align="' +}; +var opAtt_h = { +'align': {'center': 'center"', + 'left': 'left"', + 'right': 'right"', + 'justify': 'justify"'} +}; + +var opTag_p = { +'align': 'align="' +}; +var opAtt_p = { +'align': {'center': 'center"', + 'left': 'left"', + 'right': 'right"', + 'justify': 'justify"'} +}; + +var opTag_table = { +'align': 'align="', +'width': 'width="', +'height': 'height="', +'cellpadding': 'cellpadding="', +'cellspacing': 'cellspacing="', +'background': 'background="', +'bgcolor': 'bgcolor="', +'border': 'border="', +'bordercolor': 'bordercolor="', +'bordercolorlight': 'bordercolorlight="', +'bordercolordark': 'bordercolordark="' +}; +var opAtt_table = { +'align': {'center': 'center"', + 'left': 'left"', + 'right': 'right"'} +}; + +// for all tags +var opTag_all = { +'class': 'class="', +'dir': 'dir="', +'id': 'id="', +'lang': 'lang="', +'onFocus': 'onFocus="', +'onBlur': 'onBlur="', +'onClick': 'onClick="', +'onDblClick': 'onDblClick="', +'onMouseDown': 'onMouseDown="', +'onMouseUp': 'onMouseUp="', +'onMouseOver': 'onMouseOver="', +'onMouseMove': 'onMouseMove="', +'onMouseOut': 'onMouseOut="', +'onKeyPress': 'onKeyPress="', +'onKeyDown': 'onKeyDown="', +'onKeyUp': 'onKeyUp="', +'style': 'style="', +'title': 'title="' +}; +var opAtt_all = { +'class': {}, +'dir': {'rtl': 'rtl"','ltr': 'ltr"'}, +'lang': {'Afrikaans ': 'af"', + 'Albanian ': 'sq"', + 'Arabic ': 'ar"', + 'Basque ': 'eu"', + 'Breton ': 'br"', + 'Bulgarian ': 'bg"', + 'Belarusian ': 'be"', + 'Catalan ': 'ca"', + 'Chinese ': 'zh"', + 'Croatian ': 'hr"', + 'Czech ': 'cs"', + 'Danish ': 'da"', + 'Dutch ': 'nl"', + 'English ': 'en"', + 'Estonian ': 'et"', + 'Faeroese ': 'fo"', + 'Farsi ': 'fa"', + 'Finnish ': 'fi"', + 'French ': 'fr"', + 'Gaelic ': 'gd"', + 'German ': 'de"', + 'Greek ': 'el"', + 'Hebrew ': 'he"', + 'Hindi ': 'hi"', + 'Hungarian ': 'hu"', + 'Icelandic ': 'is"', + 'Indonesian ': 'id"', + 'Italian ': 'it"', + 'Japanese ': 'ja"', + 'Korean ': 'ko"', + 'Latvian ': 'lv"', + 'Lithuanian ': 'lt"', + 'Macedonian ': 'mk"', + 'Malaysian ': 'ms"', + 'Maltese ': 'mt"', + 'Norwegian ': 'no"', + 'Polish ': 'pl"', + 'Portuguese ': 'pt"', + 'Rhaeto-Romanic ': 'rm"', + 'Romanian ': 'ro"', + 'Russian ': 'ru"', + 'Sami ': 'sz"', + 'Serbian ': 'sr"', + 'Setswana ': 'tn"', + 'Slovak ': 'sk"', + 'Slovenian ': 'sl"', + 'Spanish ': 'es"', + 'Sutu ': 'sx"', + 'Swedish ': 'sv"', + 'Thai ': 'th"', + 'Tsonga ': 'ts"', + 'Turkish ': 'tr"', + 'Ukrainian ': 'uk"', + 'Urdu ': 'ur"', + 'Vietnamese ': 'vi"', + 'Xhosa ': 'xh"', + 'Yiddish ': 'yi"', + 'Zulu': 'zu"'}, +'style': {'azimuth': 'azimuth: ', + 'background': 'background: ', + 'background-attachment': 'background-attachment: ', + 'background-color': 'background-color: ', + 'background-image': 'background-image: ', + 'background-position': 'background-position: ', + 'background-repeat': 'background-repeat: ', + 'border': 'border: ', + 'border-bottom': 'border-bottom: ', + 'border-left': 'border-left: ', + 'border-right': 'border-right: ', + 'border-top': 'border-top: ', + 'border-bottom-color': 'border-bottom-color: ', + 'border-left-color': 'border-left-color: ', + 'border-right-color': 'border-right-color: ', + 'border-top-color': 'border-top-color: ', + 'border-bottom-style': 'border-bottom-style: ', + 'border-left-style': 'border-left-style: ', + 'border-right-style': 'border-right-style: ', + 'border-top-style': 'border-top-style: ', + 'border-bottom-width': 'border-bottom-width: ', + 'border-left-width': 'border-left-width: ', + 'border-right-width': 'border-right-width: ', + 'border-top-width': 'border-top-width: ', + 'border-collapse': 'border-collapse: ', + 'border-color': 'border-color: ', + 'border-style': 'border-style: ', + 'border-width': 'border-width: ', + 'bottom': 'bottom: ', + 'caption-side': 'caption-side: ', + 'cell-spacing': 'cell-spacing: ', + 'clear': 'clear: ', + 'clip': 'clip: ', + 'color': 'color: ', + 'column-span': 'column-span: ', + 'content': 'content: ', + 'cue': 'cue: ', + 'cue-after': 'cue-after: ', + 'cue-before': 'cue-before: ', + 'cursor': 'cursor: ', + 'direction': 'direction: ', + 'display': 'display: ', + 'elevation': 'elevation: ', + 'filter': 'filter: ', + 'float': 'float: ', + 'font-family': 'font-family: ', + 'font-size': 'font-size: ', + 'font-size-adjust': 'font-size-adjust: ', + 'font-style': 'font-style: ', + 'font-variant': 'font-variant: ', + 'font-weight': 'font-weight: ', + 'height': 'height: ', + '!important': '!important: ', + 'left': 'left: ', + 'letter-spacing': 'letter-spacing: ', + 'line-height': 'line-height: ', + 'list-style': 'list-style: ', + 'list-style-image': 'list-style-image: ', + 'list-style-position': 'list-style-position: ', + 'list-style-type': 'list-style-type: ', + 'margin': 'margin: ', + 'margin-bottom': 'margin-bottom: ', + 'margin-left': 'margin-left: ', + 'margin-right': 'margin-right: ', + 'margin-top': 'margin-top: ', + 'marks': 'marks: ', + 'max-height': 'max-height: ', + 'min-height': 'min-height: ', + 'max-width': 'max-width: ', + 'min-width': 'min-width: ', + 'orphans': 'orphans: ', + 'overflow': 'overflow: ', + 'padding': 'padding: ', + 'padding-bottom': 'padding-bottom: ', + 'padding-left': 'padding-left: ', + 'padding-right': 'padding-right: ', + 'padding-top': 'padding-top: ', + 'page-break-after': 'page-break-after: ', + 'page-break-before': 'page-break-before: ', + 'pause': 'pause: ', + 'pause-after': 'pause-after: ', + 'pause-before': 'pause-before: ', + 'pitch': 'pitch: ', + 'pitch-range': 'pitch-range: ', + 'play-during': 'play-during: ', + 'position': 'position: ', + 'richness': 'richness: ', + 'right': 'right: ', + 'row-span': 'row-span: ', + 'size': 'size: ', + 'speak': 'speak: ', + 'speak-date': 'speak-date: ', + 'speak-header': 'speak-header: ', + 'speak-numeral': 'speak-numeral: ', + 'speak-punctuation': 'speak-punctuation: ', + 'speak-time': 'speak-time: ', + 'speech-rate': 'speech-rate: ', + 'stress': 'stress: ', + 'table-layout': 'table-layout: ', + 'text-align': 'text-align: ', + 'text-decoration': 'text-decoration: ', + 'text-indent': 'text-indent: ', + 'text-shadow': 'text-shadow: ', + 'text-transform': 'text-transform: ', + 'top': 'top: ', + 'vertical-align': 'vertical-align: ', + 'visibility': 'visibility: ', + 'voice-family': 'voice-family: ', + 'volume': 'volume: ', + 'white-space': 'white-space: ', + 'widows': 'widows: ', + 'width': 'width: ', + 'word-spacing': 'word-spacing: ', + 'z-index': 'z-index: ' } +}; + +// add the common items to all objects +for(var i in tagLib) { +i = i.replace(/^h[1-6]$/,"h"); // h1 .. h6 + for(var j in opTag_all) + eval('opTag_'+i+'["'+j+'"] = opTag_all["'+j+'"];'); + for(var j in opAtt_all) + eval('opAtt_'+i+'["'+j+'"] = opAtt_all["'+j+'"];'); +} \ No newline at end of file diff --git a/xinha/plugins/SpellChecker/README b/xinha/plugins/SpellChecker/README new file mode 100644 index 0000000..9b5a2c8 --- /dev/null +++ b/xinha/plugins/SpellChecker/README @@ -0,0 +1,8 @@ +ExecCGI Note: +If you intend to use the perl (.cgi) backend then you will need to have the ExecCGI option enabled for this directory (if you are using Apache), you may be able to do this by adding a file called .htaccess in this directory, with the below contents. + +## EXAMPLE .htaccess +Options +ExecCGI +#################### + +It is however recommended that you use the PHP backend where possible. \ No newline at end of file diff --git a/xinha/plugins/SpellChecker/aspell_setup.php b/xinha/plugins/SpellChecker/aspell_setup.php new file mode 100644 index 0000000..7ea3381 --- /dev/null +++ b/xinha/plugins/SpellChecker/aspell_setup.php @@ -0,0 +1,90 @@ + (int)$aVer[1], 'minor' => (int)$aVer[2], 'release' => (int)$aVer[3]); + if($aVer['major'] >= 0 && $aVer['minor'] >= 60) + { + $aspell_args .= ' -H --encoding=utf-8'; + } + elseif(preg_match('/--encoding/', shell_exec('aspell 2>&1'))) + { + $aspell_args .= ' --mode=none --add-filter=sgml --encoding=utf-8'; + } + else + { + $aspell_args .= ' --mode=none --add-filter=sgml'; + } + + // Personal dictionaries + if(!isset($_REQUEST['p_dicts_path'])) + { + $_REQUEST['p_dicts_path'] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'personal_dicts'; + } + + if(file_exists($_REQUEST['p_dicts_path']) && is_writable($_REQUEST['p_dicts_path'])) + { + if(!isset($_REQUEST['p_dicts_name'])) + { + if(isset($_COOKIE['SpellChecker_p_dicts_name'])) + { + $_REQUEST['p_dicts_name'] = $_COOKIE['SpellChecker_p_dicts_name']; + } + else + { + $_REQUEST['p_dicts_name'] = uniqid('dict'); + setcookie('SpellChecker_p_dicts_name', $_REQUEST['p_dicts_name'], time() + 60*60*24*365*10); + } + } + $p_dict_path = $_REQUEST['p_dicts_path'] . DIRECTORY_SEPARATOR . $_REQUEST['p_dicts_name']; + + if(!file_exists($p_dict_path)) + { + mkdir($p_dict_path); + chmod($p_dict_path, 02770); + } + + if(file_exists($p_dict_path) && is_writable($p_dict_path)) + { + // Good To Go! + $aspell_args .= ' --home-dir=' . $p_dict_path ; + } + } + + $aspelldictionaries = "$aspell dump dicts"; + $aspellcommand = "$aspell $aspell_args < $temptext"; + + +?> \ No newline at end of file diff --git a/xinha/plugins/SpellChecker/img/he-spell-check.gif b/xinha/plugins/SpellChecker/img/he-spell-check.gif new file mode 100644 index 0000000..a9ddac9 Binary files /dev/null and b/xinha/plugins/SpellChecker/img/he-spell-check.gif differ diff --git a/xinha/plugins/SpellChecker/img/spell-check.gif b/xinha/plugins/SpellChecker/img/spell-check.gif new file mode 100644 index 0000000..151bb2b Binary files /dev/null and b/xinha/plugins/SpellChecker/img/spell-check.gif differ diff --git a/xinha/plugins/SpellChecker/lang/cz.js b/xinha/plugins/SpellChecker/lang/cz.js new file mode 100644 index 0000000..e57bca0 --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/cz.js @@ -0,0 +1,37 @@ +// I18N constants + +// LANG: "cz", ENCODING: UTF-8 +// Author: Jiri Löw, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "Prosím potvrÄte otevÅ™ení tohoto odkazu", + "Cancel": "ZruÅ¡it", + "Dictionary": "Slovník", + "Finished list of mispelled words": "DokonÄen seznam chybných slov", + "I will open it in a new page.": "Bude otevÅ™en jej v nové stránce.", + "Ignore all": "Ignorovat vÅ¡e", + "Ignore": "Ignorovat", + "No mispelled words found with the selected dictionary.": "Podle zvoleného slovníku nebyla nalezena žádná chybná slova.", + "Spell check complete, didn't find any mispelled words. Closing now...": "Kontrola správnosti slov dokonÄena, nebyla nalezena žádná chybná slova. UkonÄování ...", + "OK": "OK", + "Original word": "Původní slovo", + "Please wait. Calling spell checker.": "Prosím Äekejte. Komunikuace s kontrolou správnosti slov.", + "Please wait: changing dictionary to": "Prosím Äekejte: zmÄ›na adresáře na", + "This will drop changes and quit spell checker. Please confirm.": "ZmÄ›ny budou zruÅ¡eny a kontrola správnosti slov ukonÄena. Prosím potvrÄte.", + "Re-check": "PÅ™ekontrolovat", + "Replace all": "ZamÄ›nit vÅ¡echno", + "Replace with": "ZamÄ›nit za", + "Replace": "ZamÄ›nit", + "Spell-check": "Kontrola správnosti slov", + "Suggestions": "DoporuÄení", + "One moment...": "strpení prosím ;-)" +} diff --git a/xinha/plugins/SpellChecker/lang/da.js b/xinha/plugins/SpellChecker/lang/da.js new file mode 100644 index 0000000..d27d732 --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/da.js @@ -0,0 +1,36 @@ +// I18N constants + +// LANG: "da", ENCODING: UTF-8 +// Author: Steen SÞnderup, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) +{ + "Please confirm that you want to open this link": "Vil du fÞlge dette link?", + "Cancel": "Anuler", + "Dictionary": "Ordbog", + "Finished list of mispelled words": "Listen med stavefejl er gennemgÃ¥et", + "I will open it in a new page.": "Jeg vil Ã¥bne det i en ny side.", + "Ignore all": "Ignorer alle", + "Ignore": "Ignorer", + "No mispelled words found with the selected dictionary.": "Der blev ikke fundet nogle stavefejl med den valgte ordbog.", + "Spell check complete, didn't find any mispelled words. Closing now...": "Stavekontrollen er gennemfÞrt, der blev ikke fundet nogle stavefejl. Lukker...", + "OK": "OK", + "Original word": "Oprindeligt ord", + "Please wait. Calling spell checker.": "Vent venligst. Henter stavekontrol.", + "Please wait: changing dictionary to": "Vent venligst: skifter ordbog til", + "This will drop changes and quit spell checker. Please confirm.": "Alle dine Êndringer vil gÃ¥ tabt, vil du fortsÊtte?", + "Re-check": "Tjek igen", + "Replace all": "Erstat alle", + "Replace with": "Erstat med", + "Replace": "Erstat", + "Spell-check": "Stavekontrol", + "Suggestions": "Forslag", + "One moment...": "Vent venligst" +} diff --git a/xinha/plugins/SpellChecker/lang/de.js b/xinha/plugins/SpellChecker/lang/de.js new file mode 100644 index 0000000..f554afd --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/de.js @@ -0,0 +1,28 @@ +// I18N constants + +// LANG: "en", ENCODING: UTF-8 +// Author: Broxx, + +{ + "Please confirm that you want to open this link": "Wollen Sie diesen Link oeffnen", + "Cancel": "Abbrechen", + "Dictionary": "Woerterbuch", + "Finished list of mispelled words": "Liste der nicht bekannten Woerter", + "I will open it in a new page.": "Wird auf neuer Seite geoeffnet", + "Ignore all": "Alle ignorieren", + "Ignore": "Ignorieren", + "No mispelled words found with the selected dictionary.": "Keine falschen Woerter mit gewaehlten Woerterbuch gefunden", + "Spell check complete, didn't find any mispelled words. Closing now...": "Rechtsschreibpruefung wurde ohne Fehler fertiggestellt. Wird nun geschlossen...", + "OK": "OK", + "Original word": "Original Wort", + "Please wait. Calling spell checker.": "Bitte warten. Woerterbuch wird durchsucht.", + "Please wait: changing dictionary to": "Bitte warten: Woerterbuch wechseln zu", + "This will drop changes and quit spell checker. Please confirm.": "Aenderungen werden nicht uebernommen. Bitte bestaettigen.", + "Re-check": "Neuueberpruefung", + "Replace all": "Alle ersetzen", + "Replace with": "Ersetzen mit", + "Replace": "Ersetzen", + "Spell-check": "Ueberpruefung", + "Suggestions": "Vorschlag", + "One moment...": "bittsche wartn ;-)" +} diff --git a/xinha/plugins/SpellChecker/lang/fr.js b/xinha/plugins/SpellChecker/lang/fr.js new file mode 100644 index 0000000..3456baf --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/fr.js @@ -0,0 +1,38 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "Veuillez confirmer l'ouverture de ce lien", + "Cancel": "Annuler", + "Dictionary": "Dictionnaire", + "Finished list of mispelled words": "Liste des mots mal orthographiés", + "I will open it in a new page.": "Ouverture dans une nouvelle fenêtre", + "Ignore all": "Tout ignorer", + "Ignore": "Ignorer", + "No mispelled words found with the selected dictionary.": "Aucune erreur orthographique avec le dictionnaire sélectionné.", + "Spell check complete, didn't find any mispelled words. Closing now...": "Vérification terminée, aucune erreur orthographique détectée. Fermeture en cours...", + "OK": "OK", + "Original word": "Mot original", + "Please wait. Calling spell checker.": "Veuillez patienter. Appel du correcteur.", + "Please wait: changing dictionary to": "Veuillez patienter. Changement du dictionnaire vers", + "This will drop changes and quit spell checker. Please confirm.": "Ceci fermera la fenêtre et annulera les modifications. Veuillez confirmer.", + "Re-check": "Vérifier encore", + "Replace all": "Tout remplacer", + "Replace with": "Remplacer par", + "Replace": "Remplacer", + "Revert": "Annuler", + "Spell-check": "Correction", + "Suggestions": "Suggestions", + "One moment...": "Veuillez patienter" +} diff --git a/xinha/plugins/SpellChecker/lang/he.js b/xinha/plugins/SpellChecker/lang/he.js new file mode 100644 index 0000000..8d22315 --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/he.js @@ -0,0 +1,38 @@ +// I18N constants + +// LANG: "en", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "×× × ×שר שברצונך לפתוח קישור ×–×”", + "Cancel": "ביטול", + "Dictionary": "מילון", + "Finished list of mispelled words": "הסתיימה רשימת ×”×ž×™×œ×™× ×”×ž×ויתות ב×ופן שגוי", + "I will open it in a new page.": "×× ×™ ×פתח ×ת ×–×” בחלון חדש.", + "Ignore all": "×”×ª×¢×œ× ×ž×”×›×œ", + "Ignore": "התעל×", + "No mispelled words found with the selected dictionary.": "×œ× × ×ž×¦×ו ×ž×™×œ×™× ×ž×ויתות ב×ופן שגוי ×¢× ×”×ž×™×œ×•×Ÿ הנבחר.", + "Spell check complete, didn't find any mispelled words. Closing now...": "בדיקת ×”×יות נסתיימה, ×œ× × ×ž×¦×ו ×ž×™×œ×™× ×ž×ויתות ב×ופן שגוי. נסגר כעת...", + "OK": "×ישור", + "Original word": "המילה המקורית", + "Please wait. Calling spell checker.": "×× × ×”×ž×ª×Ÿ. ×§×•×¨× ×œ×‘×•×“×§ ×יות.", + "Please wait: changing dictionary to": "×× × ×”×ž×ª×Ÿ: מחליף מילון ל-", + "This will drop changes and quit spell checker. Please confirm.": "×–×” יבטל ×ת ×”×©×™× ×•×™×™× ×•×™×¦× ×ž×‘×•×“×§ ×”×יות. ×× × ×שר.", + "Re-check": "בדוק מחדש", + "Replace all": "החלף הכל", + "Replace with": "החלף ב-", + "Replace": "החלף", + "Revert": "החזר שינויי×", + "Spell-check": "בדיקת ×יות", + "Suggestions": "הצעות", + "One moment...": "×¢× × ×”×ž×˜×Ÿ ;-)" +} diff --git a/xinha/plugins/SpellChecker/lang/hu.js b/xinha/plugins/SpellChecker/lang/hu.js new file mode 100644 index 0000000..dc442ea --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/hu.js @@ -0,0 +1,37 @@ +// I18N constants + +// LANG: "hu", ENCODING: UTF-8 +// Author: Miklós Somogyi, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "MegerÅ‘sítés", + "Cancel": "Mégsem", + "Dictionary": "Szótár", + "Finished list of mispelled words": "A tévesztett szavak listájának vége", + "I will open it in a new page.": "Megnyitás új lapon", + "Ignore all": "Minden elvetése", + "Ignore": "Elvetés", + "No mispelled words found with the selected dictionary.": "A választott szótár szerint nincs tévesztett szó.", + "Spell check complete, didn't find any mispelled words. Closing now...": "A helyesírásellenÅ‘rzés kész, tévesztett szó nem fordult elÅ‘. Bezárás...", + "OK": "Rendben", + "Original word": "Eredeti szó", + "Please wait. Calling spell checker.": "Kis türelmet, a helyesírásellenÅ‘rzÅ‘ hívása folyamatban.", + "Please wait: changing dictionary to": "Kis türelmet, szótár cseréje", + "This will drop changes and quit spell checker. Please confirm.": "Kilépés a változások eldobásával. Jóváhagyja?", + "Re-check": "ÚjraellenÅ‘rzés", + "Replace all": "Mind cseréje", + "Replace with": "Csere a következÅ‘re:", + "Replace": "Csere", + "Spell-check": "HelyesírásellenÅ‘rzés", + "Suggestions": "Tippek", + "One moment...": "Kis türelmet ;-)" +} diff --git a/xinha/plugins/SpellChecker/lang/nl.js b/xinha/plugins/SpellChecker/lang/nl.js new file mode 100644 index 0000000..f2e09ed --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/nl.js @@ -0,0 +1,39 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Author: A.H van den Broek http://www.kontaktfm.nl +// Email : tonbroek@kontaktfm.nl + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "Weet u zeker dat u deze link wilt openen?", + "Cancel": "Annuleer", + "Dictionary": "Woordenboek", + "Finished list of mispelled words": "klaar met de lijst van fouten woorden", + "I will open it in a new page.": "Ik zal het in een nieuwe pagina openen.", + "Ignore all": "alles overslaan", + "Ignore": "Overslaan", + "No mispelled words found with the selected dictionary.": "Geen fouten gevonden met dit woordenboek.", + "Spell check complete, didn't find any mispelled words. Closing now...": "Spell checking is klaar, geen fouten gevonden. spell checking word gesloten...", + "OK": "OK", + "Original word": "Originele woord", + "Please wait. Calling spell checker.": "Even wachten. spell checker wordt geladen.", + "Please wait: changing dictionary to": "even wachten: woordenboek wordt veranderd naar", + "This will drop changes and quit spell checker. Please confirm.": "Dit zal alle veranderingen annuleren en de spell checker sluiten. Weet u het zeker?", + "Re-check": "Opnieuw", + "Replace all": "Alles vervangen", + "Replace with": "Vervangen met", + "Replace": "Vervangen", + "Revert": "Omkeren", + "Spell-check": "Spell-check", + "Suggestions": "Suggestie", + "One moment...": "Even wachten ;-)" +} diff --git a/xinha/plugins/SpellChecker/lang/no.js b/xinha/plugins/SpellChecker/lang/no.js new file mode 100644 index 0000000..8bc229f --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/no.js @@ -0,0 +1,27 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Please confirm that you want to open this link": "Ønsker du Ã¥ Ã¥pne denne lenken", + "Cancel": "Avbryt", + "Dictionary": "Ordliste", + "Finished list of mispelled words": "Ferdig med liste over feilstavede ord", + "I will open it in a new page.": "Ã…pnes i ny side", + "Ignore all": "Ignorer alle", + "Ignore": "Ignorer", + "No mispelled words found with the selected dictionary.": "Ingen feilstavede ord funnet med den valgte ordlisten", + "Spell check complete, didn't find any mispelled words. Closing now...": "Stavekontroll fullført, ingen feilstavede ord ble funnet, stavekontroll avsluttes.", + "OK": "OK", + "Original word": "Opprinnelig ord", + "Please wait. Calling spell checker.": "Vennligst vennt, kaller opp stavekontrollprogrammet", + "Please wait: changing dictionary to": "Vennligst vennt, endrer ordliste til", + "This will drop changes and quit spell checker. Please confirm.": "Dette vil droppe endringene og avbryte stavekontrollen, vennligst bekreft.", + "Re-check": "Kjør stavekontroll pÃ¥ nytt", + "Replace all": "Erstatt alle", + "Replace with": "Erstatt med", + "Replace": "Erstatt", + "Spell-check": "Stavekontroll", + "Suggestions": "Forslag", + "One moment...": "Et øyeblikk..." +} \ No newline at end of file diff --git a/xinha/plugins/SpellChecker/lang/ro.js b/xinha/plugins/SpellChecker/lang/ro.js new file mode 100644 index 0000000..55928a2 --- /dev/null +++ b/xinha/plugins/SpellChecker/lang/ro.js @@ -0,0 +1,37 @@ +// I18N constants + +// LANG: "ro", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Please confirm that you want to open this link": "Vă rog confirmaÅ£i că vreÅ£i să deschideÅ£i acest link", + "Cancel": "Anulează", + "Dictionary": "DicÅ£ionar", + "Finished list of mispelled words": "Am terminat lista de cuvinte greÅŸite", + "I will open it in a new page.": "O voi deschide într-o altă fereastră.", + "Ignore all": "Ignoră toate", + "Ignore": "Ignoră", + "No mispelled words found with the selected dictionary.": "Nu am găsit nici un cuvânt greÅŸit cu acest dicÅ£ionar.", + "Spell check complete, didn't find any mispelled words. Closing now...": "Am terminat, nu am detectat nici o greÅŸeală. Acum închid fereastra...", + "OK": "OK", + "Original word": "Cuvântul original", + "Please wait. Calling spell checker.": "Vă rog aÅŸteptaÅ£i. Apelez spell-checker-ul.", + "Please wait: changing dictionary to": "Vă rog aÅŸteptaÅ£i. Schimb dicÅ£ionarul cu", + "This will drop changes and quit spell checker. Please confirm.": "DoriÅ£i să renunÅ£aÅ£i la modificări ÅŸi să închid spell-checker-ul?", + "Re-check": "Scanează", + "Replace all": "ÃŽnlocuieÅŸte toate", + "Replace with": "ÃŽnlocuieÅŸte cu", + "Replace": "ÃŽnlocuieÅŸte", + "Spell-check": "Detectează greÅŸeli", + "Suggestions": "Sugestii", + "One moment...": "va rog ashteptatzi ;-)" +} diff --git a/xinha/plugins/SpellChecker/readme-tech.html b/xinha/plugins/SpellChecker/readme-tech.html new file mode 100644 index 0000000..1afdf6d --- /dev/null +++ b/xinha/plugins/SpellChecker/readme-tech.html @@ -0,0 +1,114 @@ + + + + HTMLArea Spell Checker + + + +

    HTMLArea Spell Checker

    + +

    The HTMLArea Spell Checker subsystem consists of the following + files:

    + +
      + +
    • spell-checker.js — the spell checker plugin interface for + HTMLArea
    • + +
    • spell-checker-ui.html — the HTML code for the user + interface
    • + +
    • spell-checker-ui.js — functionality of the user + interface
    • + +
    • spell-checker-logic.cgi — Perl CGI script that checks a text + given through POST for spelling errors
    • + +
    • spell-checker-style.css — style for mispelled words
    • + +
    • lang/en.js — main language file (English).
    • + +
    + +

    Process overview

    + +

    + When an end-user clicks the "spell-check" button in the HTMLArea + editor, a new window is opened with the URL of "spell-check-ui.html". + This window initializes itself with the text found in the editor (uses + window.opener.SpellChecker.editor global variable) and it + submits the text to the server-side script "spell-check-logic.cgi". + The target of the FORM is an inline frame which is used both to + display the text and correcting. +

    + +

    + Further, spell-check-logic.cgi calls Aspell for each portion of plain + text found in the given HTML. It rebuilds an HTML file that contains + clear marks of which words are incorrect, along with suggestions for + each of them. This file is then loaded in the inline frame. Upon + loading, a JavaScript function from "spell-check-ui.js" is called. + This function will retrieve all mispelled words from the HTML of the + iframe and will setup the user interface so that it allows correction. +

    + +

    The server-side script (spell-check-logic.cgi)

    + +

    + Unicode safety — the program is + Unicode safe. HTML entities are expanded into their corresponding + Unicode characters. These characters will be matched as part of the + word passed to Aspell. All texts passed to Aspell are in Unicode + (when appropriate). However, Aspell seems to not support Unicode + yet (thread concerning Aspell and Unicode). + This mean that words containing Unicode + characters that are not in 0..255 are likely to be reported as "mispelled" by Aspell. +

    + +

    + Update: though I've never seen it mentioned + anywhere, it looks that Aspell does, in fact, speak + Unicode. Or else, maybe Text::Aspell does + transparent conversion; anyway, this new version of our + SpellChecker plugin is, as tests show so far, fully + Unicode-safe... well, probably the only freeware + Web-based spell-checker which happens to have Unicode support. +

    + +

    + The Perl Unicode manual (man perluniintro) states: +

    + +
    + + Starting from Perl 5.6.0, Perl has had the capacity to handle Unicode + natively. Perl 5.8.0, however, is the first recommended release for + serious Unicode work. The maintenance release 5.6.1 fixed many of the + problems of the initial Unicode implementation, but for example regular + expressions still do not work with Unicode in 5.6.1. + +
    + +

    In other words, do not assume that this script is + Unicode-safe on Perl interpreters older than 5.8.0.

    + +

    The following Perl modules are required:

    + + + +

    Of these, only Text::Aspell might need to be installed manually. The + others are likely to be available by default in most Perl distributions.

    + +
    +
    Mihai Bazon
    + + Last modified: Fri Jan 30 19:14:11 EET 2004 + + + diff --git a/xinha/plugins/SpellChecker/spell-check-logic.cgi b/xinha/plugins/SpellChecker/spell-check-logic.cgi new file mode 100755 index 0000000..0c749c0 --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-logic.cgi @@ -0,0 +1,210 @@ +#! /usr/bin/perl -w + +# Spell Checker Plugin for HTMLArea-3.0 +# Sponsored by www.americanbible.org +# Implementation by Mihai Bazon, http://dynarch.com/mishoo/ +# +# (c) dynarch.com 2003. +# Distributed under the same terms as HTMLArea itself. +# This notice MUST stay intact for use (see license.txt). +# +# $Id$ + +use strict; +use utf8; +use Encode; +use Text::Aspell; +use XML::DOM; +use CGI; + +my $TIMER_start = undef; +eval { + use Time::HiRes qw( gettimeofday tv_interval ); + $TIMER_start = [gettimeofday()]; +}; +# use POSIX qw( locale_h ); + +binmode STDIN, ':utf8'; +binmode STDOUT, ':utf8'; + +my $debug = 0; + +my $speller = new Text::Aspell; +my $cgi = new CGI; + +my $total_words = 0; +my $total_mispelled = 0; +my $total_suggestions = 0; +my $total_words_suggested = 0; + +# FIXME: report a nice error... +die "Can't create speller!" unless $speller; + +my $dict = $cgi->param('dictionary') || $cgi->cookie('dictionary') || 'en'; + +# add configurable option for this +$speller->set_option('lang', $dict); +$speller->set_option('encoding', 'UTF-8'); +#setlocale(LC_CTYPE, $dict); + +# ultra, fast, normal, bad-spellers +# bad-spellers seems to cause segmentation fault +$speller->set_option('sug-mode', 'normal'); + +my %suggested_words = (); +keys %suggested_words = 128; + +my $file_content = decode('UTF-8', $cgi->param('content')); +$file_content = parse_with_dom($file_content); + +my $ck_dictionary = $cgi->cookie(-name => 'dictionary', + -value => $dict, + -expires => '+30d'); + +print $cgi->header(-type => 'text/html; charset: utf-8', + -cookie => $ck_dictionary); + +my $js_suggested_words = make_js_hash(\%suggested_words); +my $js_spellcheck_info = make_js_hash_from_array + ([ + [ 'Total words' , $total_words ], + [ 'Mispelled words' , $total_mispelled . ' in dictionary \"'.$dict.'\"' ], + [ 'Total suggestions' , $total_suggestions ], + [ 'Total words suggested' , $total_words_suggested ], + [ 'Spell-checked in' , defined $TIMER_start ? (tv_interval($TIMER_start) . ' seconds') : 'n/a' ] + ]); + +print qq^ + + + + + + +^; + +print $file_content; +if ($cgi->param('init') eq '1') { + my @dicts = $speller->dictionary_info(); + my $dictionaries = ''; + foreach my $i (@dicts) { + next if $i->{jargon}; + my $name = $i->{name}; + if ($name eq $dict) { + $name = '@'.$name; + } + $dictionaries .= ',' . $name; + } + $dictionaries =~ s/^,//; + print qq^
    $dictionaries
    ^; +} + +print ''; + +# Perl is beautiful. +sub spellcheck { + my $node = shift; + my $doc = $node->getOwnerDocument; + my $check = sub { # called for each word in the text + # input is in UTF-8 + my $word = shift; + my $already_suggested = defined $suggested_words{$word}; + ++$total_words; + if (!$already_suggested && $speller->check($word)) { + return undef; + } else { + # we should have suggestions; give them back to browser in UTF-8 + ++$total_mispelled; + if (!$already_suggested) { + # compute suggestions for this word + my @suggestions = $speller->suggest($word); + my $suggestions = decode($speller->get_option('encoding'), join(',', @suggestions)); + $suggested_words{$word} = $suggestions; + ++$total_suggestions; + $total_words_suggested += scalar @suggestions; + } + # HA-spellcheck-error + my $err = $doc->createElement('span'); + $err->setAttribute('class', 'HA-spellcheck-error'); + my $tmp = $doc->createTextNode; + $tmp->setNodeValue($word); + $err->appendChild($tmp); + return $err; + } + }; + while ($node->getNodeValue =~ /([\p{IsWord}']+)/) { + my $word = $1; + my $before = $`; + my $after = $'; + my $df = &$check($word); + if (!$df) { + $before .= $word; + } + { + my $parent = $node->getParentNode; + my $n1 = $doc->createTextNode; + $n1->setNodeValue($before); + $parent->insertBefore($n1, $node); + $parent->insertBefore($df, $node) if $df; + $node->setNodeValue($after); + } + } +}; + +sub check_inner_text { + my $node = shift; + my $text = ''; + for (my $i = $node->getFirstChild; defined $i; $i = $i->getNextSibling) { + if ($i->getNodeType == TEXT_NODE) { + spellcheck($i); + } + } +}; + +sub parse_with_dom { + my ($text) = @_; + $text = ''.$text.''; + + my $parser = new XML::DOM::Parser; + if ($debug) { + open(FOO, '>:utf8', '/tmp/foo'); + print FOO $text; + close FOO; + } + my $doc = $parser->parse($text); + my $nodes = $doc->getElementsByTagName('*'); + my $n = $nodes->getLength; + + for (my $i = 0; $i < $n; ++$i) { + my $node = $nodes->item($i); + if ($node->getNodeType == ELEMENT_NODE) { + check_inner_text($node); + } + } + + my $ret = $doc->toString; + $ret =~ s{(.*)}{$1}sg; + return $ret; +}; + +sub make_js_hash { + my ($hash) = @_; + my $js_hash = ''; + while (my ($key, $val) = each %$hash) { + $js_hash .= ',' if $js_hash; + $js_hash .= '"'.$key.'":"'.$val.'"'; + } + return $js_hash; +}; + +sub make_js_hash_from_array { + my ($array) = @_; + my $js_hash = ''; + foreach my $i (@$array) { + $js_hash .= ',' if $js_hash; + $js_hash .= '"'.$i->[0].'":"'.$i->[1].'"'; + } + return $js_hash; +}; diff --git a/xinha/plugins/SpellChecker/spell-check-logic.php b/xinha/plugins/SpellChecker/spell-check-logic.php new file mode 100644 index 0000000..af8e882 --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-logic.php @@ -0,0 +1,166 @@ + + + + +'; + +// Lets define some values outside the condition below, in case we have an empty +// document. +$textarray = array(); +$varlines = ''; + +echo ' +'; + +foreach ($textarray as $key=>$value) +{ + echo $value; +} + +$dictionaries = str_replace(chr(10),",", shell_exec($aspelldictionaries)); +if(ereg(",$",$dictionaries)) + $dictionaries = ereg_replace(",$","",$dictionaries); +echo '
    '.$dictionaries.'
    '; + +echo ''; +?> diff --git a/xinha/plugins/SpellChecker/spell-check-savedicts.php b/xinha/plugins/SpellChecker/spell-check-savedicts.php new file mode 100644 index 0000000..cb2d281 --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-savedicts.php @@ -0,0 +1,38 @@ +&1'); + unlink($temptext); + } +?> \ No newline at end of file diff --git a/xinha/plugins/SpellChecker/spell-check-style.css b/xinha/plugins/SpellChecker/spell-check-style.css new file mode 100644 index 0000000..1408ba0 --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-style.css @@ -0,0 +1,10 @@ +.HA-spellcheck-error { border-bottom: 1px dashed #f00; cursor: default; } +.HA-spellcheck-same { background-color: #cef; color: #000; } +.HA-spellcheck-hover { background-color: #433; color: white; } +.HA-spellcheck-fixed { border-bottom: 1px dashed #0b8; } +.HA-spellcheck-current { background-color: #9be; color: #000; } +.HA-spellcheck-suggestions { display: none; } + +#HA-spellcheck-dictionaries { display: none; } + +a:link, a:visited { color: #55e; } diff --git a/xinha/plugins/SpellChecker/spell-check-ui.html b/xinha/plugins/SpellChecker/spell-check-ui.html new file mode 100644 index 0000000..4276221 --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-ui.html @@ -0,0 +1,124 @@ + + + + + Spell Checker + + + + + + + + + +
    + + + + + + + + + + + + + +
    +
    Dictionary + + +
    + Please wait. Calling spell checker. +
    +
    + +
    +
    Original word
    +
    pliz weit ;-)
    +
    + +
    +
    Replace with
    +
    +
    +
    +
    + +
    +
    +
    Suggestions
    +
    + +
    +
    + +
    +
    + + +
    +
    +
    + + + + diff --git a/xinha/plugins/SpellChecker/spell-check-ui.js b/xinha/plugins/SpellChecker/spell-check-ui.js new file mode 100644 index 0000000..ec2cd2d --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-check-ui.js @@ -0,0 +1,445 @@ +// Spell Checker Plugin for HTMLArea-3.0 +// Sponsored by www.americanbible.org +// Implementation by Mihai Bazon, http://dynarch.com/mishoo/ +// +// (c) dynarch.com 2003. +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// $Id$ + +// internationalization file was already loaded in parent ;-) +var SpellChecker = window.opener.SpellChecker; + +var HTMLArea = window.opener.HTMLArea; +var _editor_url = window.opener._editor_url; + +var is_ie = HTMLArea.is_ie; +var editor = SpellChecker.editor; +var frame = null; +var currentElement = null; +var wrongWords = null; +var modified = false; +var allWords = {}; +var fixedWords = []; +var suggested_words = {}; + +var to_p_dict = []; // List of words to add to personal dictionary. +var to_r_list = []; // List of words to add to replacement list. + +function _lc(string) { + return HTMLArea._lc(string, 'SpellChecker'); +} + +function makeCleanDoc(leaveFixed) { + // document.getElementById("status").innerHTML = 'Please wait: rendering valid HTML'; + var words = wrongWords.concat(fixedWords); + for (var i = words.length; --i >= 0;) { + var el = words[i]; + if (!(leaveFixed && /HA-spellcheck-fixed/.test(el.className))) { + el.parentNode.insertBefore(el.firstChild, el); + el.parentNode.removeChild(el); + } else + el.className = "HA-spellcheck-fixed"; + } + // we should use innerHTML here, but IE6's implementation fucks up the + // HTML to such extent that our poor Perl parser doesn't understand it + // anymore. + return window.opener.HTMLArea.getHTML(frame.contentWindow.document.body, false, editor); +}; + +function recheckClicked() { + document.getElementById("status").innerHTML = _lc("Please wait: changing dictionary to") + ': "' + document.getElementById("f_dictionary").value + '".'; + var field = document.getElementById("f_content"); + field.value = makeCleanDoc(true); + field.form.submit(); +}; + +function saveClicked() { + if (modified) { + editor.setHTML(makeCleanDoc(false)); + } + + if(to_p_dict.length || to_r_list.length && editor.config.SpellChecker.backend == 'php') + { + var data = {}; + for(var i = 0;i < to_p_dict.length;i++) + { + data['to_p_dict[' + i + ']'] = to_p_dict[i]; + } + for(var i = 0;i < to_r_list.length;i++) + { + data['to_r_list[' + i + '][0]'] = to_r_list[i][0]; + data['to_r_list[' + i + '][1]'] = to_r_list[i][1]; + } + // var win = window; + window.opener.HTMLArea._postback(_editor_url + '/plugins/SpellChecker/spell-check-savedicts.php', data); + window.close(); + } + else + { + window.close(); + } + return false; +}; + +function cancelClicked() { + var ok = true; + if (modified) { + ok = confirm(_lc("This will drop changes and quit spell checker. Please confirm.")); + } + if (ok) { + window.close(); + } + return false; +}; + +function replaceWord(el) { + var replacement = document.getElementById("v_replacement").value; + var this_word_modified = (el.innerHTML != replacement); + if (this_word_modified) + modified = true; + if (el) { + el.className = el.className.replace(/\s*HA-spellcheck-(hover|fixed)\s*/g, " "); + } + el.className += " HA-spellcheck-fixed"; + el.__msh_fixed = true; + if (!this_word_modified) { + return false; + } + to_r_list.push([el.innerHTML, replacement]); + el.innerHTML = replacement; +}; + +function replaceClicked() { + replaceWord(currentElement); + var start = currentElement.__msh_id; + var index = start; + do { + ++index; + if (index == wrongWords.length) { + index = 0; + } + } while ((index != start) && wrongWords[index].__msh_fixed); + if (index == start) { + index = 0; + alert(_lc("Finished list of mispelled words")); + } + wrongWords[index].__msh_wordClicked(true); + return false; +}; + +function revertClicked() { + document.getElementById("v_replacement").value = currentElement.__msh_origWord; + replaceWord(currentElement); + currentElement.className = "HA-spellcheck-error HA-spellcheck-current"; + return false; +}; + +function replaceAllClicked() { + var replacement = document.getElementById("v_replacement").value; + var ok = true; + var spans = allWords[currentElement.__msh_origWord]; + if (spans.length == 0) { + alert("An impossible condition just happened. Call FBI. ;-)"); + } else if (spans.length == 1) { + replaceClicked(); + return false; + } + /* + var message = "The word \"" + currentElement.__msh_origWord + "\" occurs " + spans.length + " times.\n"; + if (replacement == currentElement.__msh_origWord) { + ok = confirm(message + "Ignore all occurrences?"); + } else { + ok = confirm(message + "Replace all occurrences with \"" + replacement + "\"?"); + } + */ + if (ok) { + for (var i = 0; i < spans.length; ++i) { + if (spans[i] != currentElement) { + replaceWord(spans[i]); + } + } + // replace current element the last, so that we jump to the next word ;-) + replaceClicked(); + } + return false; +}; + +function ignoreClicked() { + document.getElementById("v_replacement").value = currentElement.__msh_origWord; + replaceClicked(); + return false; +}; + +function ignoreAllClicked() { + document.getElementById("v_replacement").value = currentElement.__msh_origWord; + replaceAllClicked(); + return false; +}; + +function learnClicked() { + to_p_dict.push(currentElement.__msh_origWord); + return ignoreAllClicked(); +}; + +function internationalizeWindow() { + var types = ["div", "span", "button"]; + for (var i = 0; i < types.length; ++i) { + var tag = types[i]; + var els = document.getElementsByTagName(tag); + for (var j = els.length; --j >= 0;) { + var el = els[j]; + if (el.childNodes.length == 1 && /\S/.test(el.innerHTML)) { + var txt = el.innerHTML; + el.innerHTML = _lc(txt); + } + } + } +}; + +function initDocument() { + internationalizeWindow(); + modified = false; + frame = document.getElementById("i_framecontent"); + var field = document.getElementById("f_content"); + field.value = HTMLArea.getHTML(editor._doc.body, false, editor); + var dict = document.getElementById("f_dictionary"); + if(typeof editor.config.SpellChecker.defaultDictionary != "undefined" + && editor.config.SpellChecker.defaultDictionary != "") { + dict.value = editor.config.SpellChecker.defaultDictionary; + } else { + dict.value = "en_GB"; + } + if(editor.config.SpellChecker.backend == 'php') + { + field.form.action = _editor_url + '/plugins/SpellChecker/spell-check-logic.php'; + } + + field.form.submit(); + document.getElementById("f_init").value = "0"; + + // assign some global event handlers + + var select = document.getElementById("v_suggestions"); + select.onchange = function() { + document.getElementById("v_replacement").value = this.value; + }; + if (is_ie) { + select.attachEvent("ondblclick", replaceClicked); + } else { + select.addEventListener("dblclick", replaceClicked, true); + } + + document.getElementById("b_replace").onclick = replaceClicked; + if(editor.config.SpellChecker.backend == 'php') + { + document.getElementById("b_learn").onclick = learnClicked; + } + else + { + document.getElementById("b_learn").parent.removeChild(document.getElementById("b_learn")); + } + document.getElementById("b_replall").onclick = replaceAllClicked; + document.getElementById("b_ignore").onclick = ignoreClicked; + document.getElementById("b_ignall").onclick = ignoreAllClicked; + document.getElementById("b_recheck").onclick = recheckClicked; + document.getElementById("b_revert").onclick = revertClicked; + document.getElementById("b_info").onclick = displayInfo; + + document.getElementById("b_ok").onclick = saveClicked; + document.getElementById("b_cancel").onclick = cancelClicked; + + select = document.getElementById("v_dictionaries"); + select.onchange = function() { + document.getElementById("f_dictionary").value = this.value; + }; +}; + +function getAbsolutePos(el) { + var r = { x: el.offsetLeft, y: el.offsetTop }; + if (el.offsetParent) { + var tmp = getAbsolutePos(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; +}; + +function wordClicked(scroll) { + var self = this; + if (scroll) (function() { + var pos = getAbsolutePos(self); + var ws = { x: frame.offsetWidth - 4, + y: frame.offsetHeight - 4 }; + var wp = { x: frame.contentWindow.document.body.scrollLeft, + y: frame.contentWindow.document.body.scrollTop }; + pos.x -= Math.round(ws.x/2); + if (pos.x < 0) pos.x = 0; + pos.y -= Math.round(ws.y/2); + if (pos.y < 0) pos.y = 0; + frame.contentWindow.scrollTo(pos.x, pos.y); + })(); + if (currentElement) { + var a = allWords[currentElement.__msh_origWord]; + currentElement.className = currentElement.className.replace(/\s*HA-spellcheck-current\s*/g, " "); + for (var i = 0; i < a.length; ++i) { + var el = a[i]; + if (el != currentElement) { + el.className = el.className.replace(/\s*HA-spellcheck-same\s*/g, " "); + } + } + } + currentElement = this; + this.className += " HA-spellcheck-current"; + var a = allWords[currentElement.__msh_origWord]; + for (var i = 0; i < a.length; ++i) { + var el = a[i]; + if (el != currentElement) { + el.className += " HA-spellcheck-same"; + } + } + // document.getElementById("b_replall").disabled = (a.length <= 1); + // document.getElementById("b_ignall").disabled = (a.length <= 1); + var txt; + if (a.length == 1) { + txt = "one occurrence"; + } else if (a.length == 2) { + txt = "two occurrences"; + } else { + txt = a.length + " occurrences"; + } + var suggestions = suggested_words[this.__msh_origWord]; + if (suggestions) + suggestions = suggestions.split(/,/); + else + suggestions = []; + var select = document.getElementById("v_suggestions"); + document.getElementById("statusbar").innerHTML = "Found " + txt + + ' for word "' + currentElement.__msh_origWord + '"'; + for (var i = select.length; --i >= 0;) { + select.remove(i); + } + for (var i = 0; i < suggestions.length; ++i) { + var txt = suggestions[i]; + var option = document.createElement("option"); + option.value = txt; + option.appendChild(document.createTextNode(txt)); + select.appendChild(option); + } + document.getElementById("v_currentWord").innerHTML = this.__msh_origWord; + if (suggestions.length > 0) { + select.selectedIndex = 0; + select.onchange(); + } else { + document.getElementById("v_replacement").value = this.innerHTML; + } + select.style.display = "none"; + select.style.display = "block"; + return false; +}; + +function wordMouseOver() { + this.className += " HA-spellcheck-hover"; +}; + +function wordMouseOut() { + this.className = this.className.replace(/\s*HA-spellcheck-hover\s*/g, " "); +}; + +function displayInfo() { + var info = frame.contentWindow.spellcheck_info; + if (!info) + alert("No information available"); + else { + var txt = "** Document information **"; + for (var i in info) { + txt += "\n" + i + " : " + info[i]; + } + alert(txt); + } + return false; +}; + +function finishedSpellChecking() { + // initialization of global variables + currentElement = null; + wrongWords = null; + allWords = {}; + fixedWords = []; + suggested_words = frame.contentWindow.suggested_words; + + document.getElementById("status").innerHTML = "HTMLArea Spell Checker (info)"; + var doc = frame.contentWindow.document; + var spans = doc.getElementsByTagName("span"); + var sps = []; + var id = 0; + for (var i = 0; i < spans.length; ++i) { + var el = spans[i]; + if (/HA-spellcheck-error/.test(el.className)) { + sps.push(el); + el.__msh_wordClicked = wordClicked; + el.onclick = function(ev) { + ev || (ev = window.event); + ev && HTMLArea._stopEvent(ev); + return this.__msh_wordClicked(false); + }; + el.onmouseover = wordMouseOver; + el.onmouseout = wordMouseOut; + el.__msh_id = id++; + var txt = (el.__msh_origWord = el.firstChild.data); + el.__msh_fixed = false; + if (typeof allWords[txt] == "undefined") { + allWords[txt] = [el]; + } else { + allWords[txt].push(el); + } + } else if (/HA-spellcheck-fixed/.test(el.className)) { + fixedWords.push(el); + } + } + + var dicts = doc.getElementById("HA-spellcheck-dictionaries"); + if (dicts) { + dicts.parentNode.removeChild(dicts); + dicts = dicts.innerHTML.split(/,/); + var select = document.getElementById("v_dictionaries"); + for (var i = select.length; --i >= 0;) { + select.remove(i); + } + var activeDictionary = document.getElementById("f_dictionary").value; + for (var i = 0; i < dicts.length; ++i) { + var txt = dicts[i]; + var option = document.createElement("option"); + if(txt == activeDictionary) { + option.selected = true; + } + option.value = txt; + option.appendChild(document.createTextNode(txt)); + select.appendChild(option); + } + } + + wrongWords = sps; + if (sps.length == 0) { + if (!modified) { + alert(_lc("No mispelled words found with the selected dictionary.")); + // window.close(); + } else { + alert(_lc("No mispelled words found with the selected dictionary.")); + } + return false; + } + (currentElement = sps[0]).__msh_wordClicked(true); + var as = doc.getElementsByTagName("a"); + for (var i = as.length; --i >= 0;) { + var a = as[i]; + a.onclick = function() { + if (confirm(_lc("Please confirm that you want to open this link") + ":\n" + + this.href + "\n" + _lc("I will open it in a new page."))) { + window.open(this.href); + } + return false; + }; + } +}; diff --git a/xinha/plugins/SpellChecker/spell-checker.js b/xinha/plugins/SpellChecker/spell-checker.js new file mode 100644 index 0000000..3f8628a --- /dev/null +++ b/xinha/plugins/SpellChecker/spell-checker.js @@ -0,0 +1,73 @@ +// Spell Checker Plugin for HTMLArea-3.0 +// Sponsored by www.americanbible.org +// Implementation by Mihai Bazon, http://dynarch.com/mishoo/ +// +// (c) dynarch.com 2003. +// Distributed under the same terms as HTMLArea itself. +// This notice MUST stay intact for use (see license.txt). +// +// $Id$ + +HTMLArea.Config.prototype.SpellChecker = { 'backend': 'php', 'personalFilesDir' : '', 'defaultDictionary' : 'en_GB' }; + +function SpellChecker(editor) { + this.editor = editor; + + var cfg = editor.config; + var bl = SpellChecker.btnList; + var self = this; + + // see if we can find the mode switch button, insert this before that + var id = "SC-spell-check"; + cfg.registerButton(id, this._lc("Spell-check"), editor.imgURL("spell-check.gif", "SpellChecker"), false, + function(editor, id) { + // dispatch button press event + self.buttonPress(editor, id); + }); + + cfg.addToolbarElement("SC-spell-check", "htmlmode", 1); +}; + +SpellChecker._pluginInfo = { + name : "SpellChecker", + version : "1.0", + developer : "Mihai Bazon", + developer_url : "http://dynarch.com/mishoo/", + c_owner : "Mihai Bazon", + sponsor : "American Bible Society", + sponsor_url : "http://www.americanbible.org", + license : "htmlArea" +}; + +SpellChecker.prototype._lc = function(string) { + return HTMLArea._lc(string, 'SpellChecker'); +} + +SpellChecker.btnList = [ + null, // separator + ["spell-check"] + ]; + +SpellChecker.prototype.buttonPress = function(editor, id) { + switch (id) { + case "SC-spell-check": + SpellChecker.editor = editor; + SpellChecker.init = true; + var uiurl = _editor_url + "plugins/SpellChecker/spell-check-ui.html"; + var win; + if (HTMLArea.is_ie) { + win = window.open(uiurl, "SC_spell_checker", + "toolbar=no,location=no,directories=no,status=no,menubar=no," + + "scrollbars=no,resizable=yes,width=600,height=450"); + } else { + win = window.open(uiurl, "SC_spell_checker", + "toolbar=no,menubar=no,personalbar=no,width=600,height=450," + + "scrollbars=no,resizable=yes"); + } + win.focus(); + break; + } +}; + +// this needs to be global, it's accessed from spell-check-ui.html +SpellChecker.editor = null; diff --git a/xinha/plugins/Stylist/lang/de.js b/xinha/plugins/Stylist/lang/de.js new file mode 100644 index 0000000..6e0a596 --- /dev/null +++ b/xinha/plugins/Stylist/lang/de.js @@ -0,0 +1,17 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Styles": "Stile" +} diff --git a/xinha/plugins/Stylist/lang/no.js b/xinha/plugins/Stylist/lang/no.js new file mode 100644 index 0000000..287214b --- /dev/null +++ b/xinha/plugins/Stylist/lang/no.js @@ -0,0 +1,7 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Styles": "Stiler" +} diff --git a/xinha/plugins/Stylist/stylist.js b/xinha/plugins/Stylist/stylist.js new file mode 100644 index 0000000..91d6d48 --- /dev/null +++ b/xinha/plugins/Stylist/stylist.js @@ -0,0 +1,542 @@ +/** + * Add an empty css_style to Config object's prototype + * the format is { '.className' : 'Description' } + */ + +HTMLArea.Config.prototype.css_style = { }; + +/** + * This method loads an external stylesheet and uses it in the stylist + */ +HTMLArea.Config.prototype.stylistLoadStylesheet = function(url, altnames) +{ + if(!altnames) altnames = { }; + var newStyles = HTMLArea.ripStylesFromCSSFile(url); + for(var i in newStyles) + { + if(altnames[i]) + { + this.css_style[i] = altnames[i]; + } + else + { + this.css_style[i] = newStyles[i]; + } + } + this.pageStyleSheets[this.pageStyleSheets.length] = url; +} + +/** + * This method takes raw style definitions and uses them in the stylist + */ +HTMLArea.Config.prototype.stylistLoadStyles = function(styles, altnames) +{ + if(!altnames) altnames = { }; + var newStyles = HTMLArea.ripStylesFromCSSString(styles); + for(var i in newStyles) + { + if(altnames[i]) + { + this.css_style[i] = altnames[i]; + } + else + { + this.css_style[i] = newStyles[i]; + } + } + this.pageStyle += styles; +} + + + +/** + * Fill the stylist panel with styles that may be applied to the current selection. Styles + * are supplied in the css_style property of the HTMLArea.Config object, which is in the format + * { '.className' : 'Description' } + * classes that are defined on a specific tag (eg 'a.email_link') are only shown in the panel + * when an element of that type is selected. + * classes that are defined with selectors/psuedoclasses (eg 'a.email_link:hover') are never + * shown (if you have an 'a.email_link' without the pseudoclass it will be shown of course) + * multiple classes (eg 'a.email_link.staff_member') are shown as a single class, and applied + * to the element as multiple classes (class="email_link staff_member") + * you may click a class name in the stylist panel to add it, and click again to remove it + * you may add multiple classes to any element + * spans will be added where no single _and_entire_ element is selected + */ +HTMLArea.prototype._fillStylist = function() +{ + if(!this._stylist) return false; + this._stylist.innerHTML = '

    '+HTMLArea._lc('Styles', 'Stylist')+'

    '; + + var may_apply = true; + var sel = this._getSelection(); + + // What is applied + // var applied = this._getAncestorsClassNames(this._getSelection()); + + // Get an active element + var active_elem = this._activeElement(sel); + + for(var x in this.config.css_style) + { + var tag = null; + var className = x.trim(); + var applicable = true; + var apply_to = active_elem; + + if(applicable && /[^a-zA-Z0-9_.-]/.test(className)) + { + applicable = false; // Only basic classes are accepted, no selectors, etc.. presumed + // that if you have a.foo:visited you'll also have a.foo + // alert('complex'); + } + + if(className.indexOf('.') < 0) + { + // No class name, just redefines a tag + applicable = false; + } + + if(applicable && (className.indexOf('.') > 0)) + { + // requires specific html tag + tag = className.substring(0, className.indexOf('.')).toLowerCase(); + className = className.substring(className.indexOf('.'), className.length); + + // To apply we must have an ancestor tag that is the right type + if(active_elem != null && active_elem.tagName.toLowerCase() == tag) + { + applicable = true; + apply_to = active_elem; + } + else + { + if(this._getFirstAncestor(this._getSelection(), [tag]) != null) + { + applicable = true; + apply_to = this._getFirstAncestor(this._getSelection(), [tag]); + } + else + { + // alert (this._getFirstAncestor(this._getSelection(), tag)); + // If we don't have an ancestor, but it's a div/span/p/hx stle, we can make one + if(( tag == 'div' || tag == 'span' || tag == 'p' + || (tag.substr(0,1) == 'h' && tag.length == 2 && tag != 'hr'))) + { + if(!this._selectionEmpty(this._getSelection())) + { + applicable = true; + apply_to = 'new'; + } + else + { + // See if we can get a paragraph or header that can be converted + apply_to = this._getFirstAncestor(sel, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']); + if(apply_to != null) + { + applicable = true; + } + } + } + else + { + applicable = false; + } + } + } + } + + if(applicable) + { + // Remove the first . + className = className.substring(className.indexOf('.'), className.length); + + // Replace any futher ones with spaces (for multiple class definitions) + className = className.replace('.', ' '); + + if(apply_to == null) + { + if(this._selectionEmpty(this._getSelection())) + { + // Get the previous element and apply to that + apply_to = this._getFirstAncestor(this._getSelection(), null); + } + else + { + apply_to = 'new'; + tag = 'span'; + } + } + } + + var applied = (this._ancestorsWithClasses(sel, tag, className).length > 0 ? true : false); + var applied_to = this._ancestorsWithClasses(sel, tag, className); + + if(applicable) + { + var anch = document.createElement('a'); + anch._stylist_className = className.trim(); + anch._stylist_applied = applied; + anch._stylist_appliedTo = applied_to; + anch._stylist_applyTo = apply_to; + anch._stylist_applyTag = tag; + + anch.innerHTML = this.config.css_style[x]; + anch.href = 'javascript:void(0)'; + var editor = this; + anch.onclick = function() + { + if(this._stylist_applied == true) + { + editor._stylistRemoveClasses(this._stylist_className, this._stylist_appliedTo); + } + else + { + editor._stylistAddClasses(this._stylist_applyTo, this._stylist_applyTag, this._stylist_className); + } + return false; + } + + anch.style.display = 'block'; + anch.style.paddingLeft = '3px'; + anch.style.paddingTop = '1px'; + anch.style.paddingBottom = '1px'; + anch.style.textDecoration = 'none'; + + if(applied) + { + anch.style.background = 'Highlight'; + anch.style.color = 'HighlightText'; + } + + this._stylist.appendChild(anch); + } + } +} + + +/** + * Add the given classes (space seperated list) to the currently selected element + * (will add a span if none selected) + */ +HTMLArea.prototype._stylistAddClasses = function(el, tag, classes) + { + if(el == 'new') + { + this.insertHTML('<' + tag + ' class="' + classes + '">' + this.getSelectedHTML() + ''); + } + else + { + if(tag != null && el.tagName.toLowerCase() != tag) + { + // Have to change the tag! + var new_el = this.switchElementTag(el, tag); + + if(typeof el._stylist_usedToBe != 'undefined') + { + new_el._stylist_usedToBe = el._stylist_usedToBe; + new_el._stylist_usedToBe[new_el._stylist_usedToBe.length] = {'tagName' : el.tagName, 'className' : el.getAttribute('class')}; + } + else + { + new_el._stylist_usedToBe = [{'tagName' : el.tagName, 'className' : el.getAttribute('class')}]; + } + + HTMLArea.addClasses(new_el, classes); + } + else + { + HTMLArea._addClasses(el, classes); + } + } + this.focusEditor(); + this.updateToolbar(); + }; + +/** + * Remove the given classes (space seperated list) from the given elements (array of elements) + */ +HTMLArea.prototype._stylistRemoveClasses = function(classes, from) + { + for(var x = 0; x < from.length; x++) + { + this._stylistRemoveClassesFull(from[x], classes); + } + this.focusEditor(); + this.updateToolbar(); + }; + +HTMLArea.prototype._stylistRemoveClassesFull = function(el, classes) +{ + if(el != null) + { + var thiers = el.className.trim().split(' '); + var new_thiers = [ ]; + var ours = classes.split(' '); + for(var x = 0; x < thiers.length; x++) + { + var exists = false; + for(var i = 0; exists == false && i < ours.length; i++) + { + if(ours[i] == thiers[x]) + { + exists = true; + } + } + if(exists == false) + { + new_thiers[new_thiers.length] = thiers[x]; + } + } + + if(new_thiers.length == 0 && el._stylist_usedToBe && el._stylist_usedToBe.length > 0 && el._stylist_usedToBe[el._stylist_usedToBe.length - 1].className != null) + { + // Revert back to what we were IF the classes are identical + var last_el = el._stylist_usedToBe[el._stylist_usedToBe.length - 1]; + var last_classes = HTMLArea.arrayFilter(last_el.className.trim().split(' '), function(c) { if (c == null || c.trim() == '') { return false;} return true; }); + + if( + (new_thiers.length == 0) + || + ( + HTMLArea.arrayContainsArray(new_thiers, last_classes) + && HTMLArea.arrayContainsArray(last_classes, new_thiers) + ) + ) + { + el = this.switchElementTag(el, last_el.tagName); + new_thiers = last_classes; + } + else + { + // We can't rely on the remembered tags any more + el._stylist_usedToBe = [ ]; + } + } + + if( new_thiers.length > 0 + || el.tagName.toLowerCase() != 'span' + || (el.id && el.id != '') + ) + { + el.className = new_thiers.join(' ').trim(); + } + else + { + // Must be a span with no classes and no id, so we can splice it out + var prnt = el.parentNode; + var childs = el.childNodes; + for(var x = 0; x < childs.length; x++) + { + prnt.insertBefore(childs[x], el); + } + prnt.removeChild(el); + } + } +} + +/** + * Change the tag of an element + */ +HTMLArea.prototype.switchElementTag = function(el, tag) +{ + var prnt = el.parentNode; + var new_el = this._doc.createElement(tag); + + if(HTMLArea.is_ie || el.hasAttribute('id')) new_el.setAttribute('id', el.getAttribute('id')); + if(HTMLArea.is_ie || el.hasAttribute('style')) new_el.setAttribute('style', el.getAttribute('style')); + + var childs = el.childNodes; + for(var x = 0; x < childs.length; x++) + { + new_el.appendChild(childs[x].cloneNode(true)); + } + + prnt.insertBefore(new_el, el); + new_el._stylist_usedToBe = [el.tagName]; + prnt.removeChild(el); + this.selectNodeContents(new_el); + return new_el; +} + +HTMLArea.prototype._getAncestorsClassNames = function(sel) +{ + // Scan upwards to find a block level element that we can change or apply to + var prnt = this._activeElement(sel); + if(prnt == null) + { + prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); + } + + var classNames = [ ]; + while(prnt) + { + if(prnt.nodeType == 1) + { + var classes = prnt.className.trim().split(' '); + for(var x = 0; x < classes.length; x++) + { + classNames[classNames.length] = classes[x]; + } + + if(prnt.tagName.toLowerCase() == 'body') break; + if(prnt.tagName.toLowerCase() == 'table' ) break; + } + prnt = prnt.parentNode; + } + + return classNames; +} + +HTMLArea.prototype._ancestorsWithClasses = function(sel, tag, classes) +{ + var ancestors = [ ]; + var prnt = this._activeElement(sel); + if(prnt == null) + { + try + { + prnt = (HTMLArea.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer); + } + catch(e) + { + return ancestors; + } + } + var search_classes = classes.trim().split(' '); + + while(prnt) + { + if(prnt.nodeType == 1) + { + if(tag == null || prnt.tagName.toLowerCase() == tag) + { + var classes = prnt.className.trim().split(' '); + var found_all = true; + for(var i = 0; i < search_classes.length; i++) + { + var found_class = false; + for(var x = 0; x < classes.length; x++) + { + if(search_classes[i] == classes[x]) + { + found_class = true; + break; + } + } + + if(!found_class) + { + found_all = false; + break; + } + } + + if(found_all) ancestors[ancestors.length] = prnt; + } + if(prnt.tagName.toLowerCase() == 'body') break; + if(prnt.tagName.toLowerCase() == 'table' ) break; + } + prnt = prnt.parentNode; + } + + return ancestors; +} + + +HTMLArea.ripStylesFromCSSFile = function(URL) +{ + var css = HTMLArea._geturlcontent(URL); + return HTMLArea.ripStylesFromCSSString(css); +} + +HTMLArea.ripStylesFromCSSString = function(css) +{ + // We are holy interested in the selectors, the rules are not important + // so we'll drop out all coments and rules + RE_comment = /\/\*(.|\r|\n)*?\*\//g; + RE_rule = /\{(.|\r|\n)*?\}/g; + css = css.replace(RE_comment, ''); + css = css.replace(RE_rule, ','); + + // And split on commas + css = css.split(','); + + // And add those into our structure + var selectors = { }; + for(var x = 0; x < css.length; x++) + { + if(css[x].trim()) + { + selectors[css[x].trim()] = css[x].trim(); + } + } + + + return selectors; +} + +// Make our right side panel and insert appropriatly +function Stylist(editor, args) +{ + this.editor = editor; + editor._stylist = null; // This needs to be changes to be Stylist::_stylist sometime + editor._stylist = editor.addPanel('right'); + HTMLArea.addClass(editor._stylist, 'stylist'); + + var stylist = this; + editor.notifyOn('modechange', + function(e,args) + { + switch(args.mode) + { + case 'text': + { + editor.hidePanel(editor._stylist); + break; + } + case 'wysiwyg': + { + editor.showPanel(editor._stylist); + break; + } + } + } + ); +} + +Stylist._pluginInfo = +{ + name : "Stylist", + version : "1.0", + developer: "James Sleeman", + developer_url: "http://www.gogo.co.nz/", + c_owner : "Gogo Internet Services", + license : "htmlArea", + sponsor : "Gogo Internet Services", + sponsor_url : "http://www.gogo.co.nz/" +}; + +Stylist.prototype.onGenerate = function() +{ + var editor = this.editor; + if(typeof editor.config.css_style == 'undefined' || HTMLArea.objectProperties(editor.config.css_style).length == 0) + { + editor.removePanel(editor._stylist); + editor._stylist = null; + } +} + +Stylist.prototype.onUpdateToolbar = function() +{ + if(this.editor._stylist) + { + if(this._timeoutID) + { + window.clearTimeout(this._timeoutID); + } + + var e = this.editor; + this._timeoutID = window.setTimeout(function() { e._fillStylist(); }, 250); + } +} diff --git a/xinha/plugins/SuperClean/dialog.html b/xinha/plugins/SuperClean/dialog.html new file mode 100644 index 0000000..0b863d1 --- /dev/null +++ b/xinha/plugins/SuperClean/dialog.html @@ -0,0 +1,33 @@ +

    Clean up HTML

    +
    + Please select from the following cleaning options... +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    \ No newline at end of file diff --git a/xinha/plugins/SuperClean/img/ed_superclean.gif b/xinha/plugins/SuperClean/img/ed_superclean.gif new file mode 100644 index 0000000..2c6dcc4 Binary files /dev/null and b/xinha/plugins/SuperClean/img/ed_superclean.gif differ diff --git a/xinha/plugins/SuperClean/lang/de.js b/xinha/plugins/SuperClean/lang/de.js new file mode 100644 index 0000000..4da71d3 --- /dev/null +++ b/xinha/plugins/SuperClean/lang/de.js @@ -0,0 +1,27 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Raimund Meyer xinha@ray-of-light.org + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Clean Up HTML": "HTML säubern", + "Please select from the following cleaning options...": "Bitte Optionen auswählen...", + "General tidy up and correction of some problems.": "Allgemeines aufräumen und Korrektur einiger Probleme.", + "Clean bad HTML from Microsoft Word": "Schlechtes HTML aus Microsoft Word aufräumen", + "Remove custom typefaces (font \"styles\").": "Schriftarten entfernen (font face).", + "Remove custom font sizes.": "Schriftgrößen entfernen (font size).", + "Remove custom text colors.": "Schriftfarben entfernen (font color).", + "Go": "Go", + "Cancel": "Abbrechen", + "Tidy failed. Check your HTML for syntax errors.": "Säubern fehlgeschlagen. Überprüfen Sie Ihren Code auf Fehler.", + "You don't have anything to tidy!": "Es gibt nichts zu säubern...!" +} diff --git a/xinha/plugins/SuperClean/lang/fr.js b/xinha/plugins/SuperClean/lang/fr.js new file mode 100644 index 0000000..c6619f3 --- /dev/null +++ b/xinha/plugins/SuperClean/lang/fr.js @@ -0,0 +1,27 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Laurent Vilday, mokhet@mokhet.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Clean Up HTML": "Nettoyer le code HTML", + "Please select from the following cleaning options...": "Veuillez sélectionner une options de nettoyage.", + "General tidy up and correction of some problems.": "Nettoyage générique et correction des problèmes mineurs.", + "Clean bad HTML from Microsoft Word": "Nettoyer les balises HTML de Microsoft Word", + "Remove custom typefaces (font \"styles\").": "Supprimer les polices personalisées (font \"styles\").", + "Remove custom font sizes.": "Supprimer les tailles de polices personnalisées.", + "Remove custom text colors.": "Supprimer les couleurs de texte personalisées.", + "Go": "Commencer", + "Cancel": "Annuler", + "Tidy failed. Check your HTML for syntax errors.": "Tidy a échoué. Vérifier la syntaxe HTML.", + "You don't have anything to tidy!": "Rien à transmettre à tidy !" +} diff --git a/xinha/plugins/SuperClean/lang/no.js b/xinha/plugins/SuperClean/lang/no.js new file mode 100644 index 0000000..81e018c --- /dev/null +++ b/xinha/plugins/SuperClean/lang/no.js @@ -0,0 +1,17 @@ +// I18N constants +// LANG: "no", ENCODING: UTF-8 +// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com + +{ + "Clean Up HTML": "Vask HTML kode", + "Please select from the following cleaning options...": "Vennligst velg blandt de forskjellige mulighetene Ã¥ vaske/ rydde i HTML koden", + "General tidy up and correction of some problems.": "Generell opprydding i HTML koden samt korrigering av typiske feil", + "Clean bad HTML from Microsoft Word": "Vask HTML kode for feil og problemer etter Microsoft Word", + "Remove custom typefaces (font \"styles\").": "Fjerne egendefinerte skrifttyper (font face)", + "Remove custom font sizes.": "Fjerne egendefinerte skriftstørrelser (font size)", + "Remove custom text colors.": "Fjerne egendefinerte skriftfarger (font color)", + "Go": "Utfør", + "Cancel": "Avbryt", + "Tidy failed. Check your HTML for syntax errors.": "Tidy (Programmet som retter HTML koden) feilet. Vennligst se over HTML koden for feil.", + "You don't have anything to tidy!": "Det finnes ingen HTML kode Ã¥ vaske!" +} \ No newline at end of file diff --git a/xinha/plugins/SuperClean/super-clean.js b/xinha/plugins/SuperClean/super-clean.js new file mode 100644 index 0000000..77edd6b --- /dev/null +++ b/xinha/plugins/SuperClean/super-clean.js @@ -0,0 +1,181 @@ +// Make our right side panel and insert appropriatly +function SuperClean(editor, args) +{ + this.editor = editor; + var superclean = this; + editor._superclean_on = false; + editor.config.registerButton('superclean', this._lc("Clean Up HTML"), editor.imgURL('ed_superclean.gif', 'SuperClean'), true, function(e, objname, obj) { superclean._superClean(null, obj); }); + + // See if we can find 'killword' and replace it with superclean + editor.config.addToolbarElement("superclean", "killword", 0); +} + +SuperClean._pluginInfo = +{ + name : "SuperClean", + version : "1.0", + developer: "James Sleeman", + developer_url: "http://www.gogo.co.nz/", + c_owner : "Gogo Internet Services", + license : "htmlArea", + sponsor : "Gogo Internet Services", + sponsor_url : "http://www.gogo.co.nz/" +}; + +SuperClean.prototype._lc = function(string) { + return HTMLArea._lc(string, 'SuperClean'); +} + +/** superClean combines HTMLTidy, Word Cleaning and font stripping into a single function + * it works a bit differently in how it asks for parameters */ + +SuperClean.prototype._superClean = function(opts, obj) +{ + var superclean = this; + + // Do the clean if we got options + var doOK = function() + { + var opts = superclean._dialog.hide(); + var editor = superclean.editor; + + if(opts.word_clean) editor._wordClean(); + var D = editor.getInnerHTML(); + if(opts.faces) + { + D = D.replace(/face="[^"]*"/gi, ''); + // { (stops jedit's fold breaking) + D = D.replace(/font-family:[^;}"']+;?/gi, ''); + } + + if(opts.sizes) + { + D = D.replace(/size="[^"]*"/gi, ''); + // { (stops jedit's fold breaking) + D = D.replace(/font-size:[^;}"']+;?/gi, ''); + } + + if(opts.colors) + { + D = D.replace(/color="[^"]*"/gi, ''); + // { (stops jedit's fold breaking) + D = D.replace(/([^-])color:[^;}"']+;?/gi, '$1'); + } + + D = D.replace(/(style|class)="\s*"/gi, ''); + D = D.replace(/<(font|span)\s*>/gi, ''); + editor.setHTML(D); + + if(editor.config.tidy_handler && opts.tidy) + { + HTMLArea._postback(editor.config.tidy_handler, {'content' : editor.getInnerHTML()}, + function(javascriptResponse) { eval(javascriptResponse) }); + } + return true; + } + var inputs = {}; + this._dialog.show(inputs, doOK); +} + +// set to the URL of a handler for html tidy, this handler +// (see tidy.php for an example) must that a single post variable +// "content" which contains the HTML to tidy, and return javascript like +// editor.setHTML('Tidied Html') +// it's called through XMLHTTPRequest +// +// set to false if you need to disable this. +HTMLArea.Config.prototype.tidy_handler = _editor_url + 'plugins/SuperClean/tidy.php'; + + +SuperClean.prototype.onGenerate = function() +{ + this._dialog = new SuperClean.Dialog(this); +} +// Inline Dialog for SuperClean + + +SuperClean.Dialog = function (SuperClean) +{ + var lDialog = this; + this.Dialog_nxtid = 0; + this.SuperClean = SuperClean; + this.id = { }; // This will be filled below with a replace, nifty + + this.ready = false; + this.files = false; + this.html = false; + this.dialog = false; + + // load the dTree script + this._prepareDialog(); + +} + +SuperClean.Dialog.prototype._prepareDialog = function() +{ + var lDialog = this; + var SuperClean = this.SuperClean; + + if(this.html == false) + { + HTMLArea._getback(_editor_url + 'plugins/SuperClean/dialog.html', function(txt) { lDialog.html = txt; lDialog._prepareDialog(); }); + return; + } + var html = this.html; + + // Now we have everything we need, so we can build the dialog. + var dialog = this.dialog = new HTMLArea.Dialog(SuperClean.editor, this.html, 'SuperClean'); + + this.ready = true; +} + +SuperClean.Dialog.prototype._lc = SuperClean.prototype._lc; + +SuperClean.Dialog.prototype.show = function(inputs, ok, cancel) +{ + if(!this.ready) + { + var lDialog = this; + window.setTimeout(function() {lDialog.show(inputs,ok,cancel);},100); + return; + } + + if(!this.SuperClean.editor.config.tidy_handler) { + this.dialog.getElementById('divTidy').style.display = 'none'; + } + + // Connect the OK and Cancel buttons + var dialog = this.dialog; + var lDialog = this; + if(ok) + { + this.dialog.getElementById('ok').onclick = ok; + } + else + { + this.dialog.getElementById('ok').onclick = function() {lDialog.hide();}; + } + + if(cancel) + { + this.dialog.getElementById('cancel').onclick = cancel; + } + else + { + this.dialog.getElementById('cancel').onclick = function() { lDialog.hide()}; + } + + // Show the dialog + this.SuperClean.editor.disableToolbar(['fullscreen','SuperClean']); + + this.dialog.show(inputs); + + // Init the sizes + this.dialog.onresize(); +} + +SuperClean.Dialog.prototype.hide = function() +{ + this.SuperClean.editor.enableToolbar(); + return this.dialog.hide(); +} diff --git a/xinha/plugins/SuperClean/tidy.php b/xinha/plugins/SuperClean/tidy.php new file mode 100644 index 0000000..678fee2 --- /dev/null +++ b/xinha/plugins/SuperClean/tidy.php @@ -0,0 +1,179 @@ +,{,},@,\n,\r"; + + if(!is_array($strings)) + { + $tr = array(); + foreach(explode(',', $strings) as $chr) + { + $tr[$chr] = sprintf('\x%02X', ord($chr)); + } + $strings = $tr; + } + + return strtr($string, $strings); + } + + // Any errors would screq up our javascript + error_reporting(E_NONE); + ini_set('display_errors', false); + + if(trim(@$_REQUEST['content'])) + { + // PHP's urldecode doesn't understand %uHHHH for unicode + $_REQUEST['content'] = preg_replace('/%u([a-f0-9]{4,4})/ei', 'utf8_chr(0x$1)', $_REQUEST['content']); + function utf8_chr($num) + { + if($num<128)return chr($num); + if($num<1024)return chr(($num>>6)+192).chr(($num&63)+128); + if($num<32768)return chr(($num>>12)+224).chr((($num>>6)&63)+128).chr(($num&63)+128); + if($num<2097152)return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128) .chr(($num&63)+128); + return ''; + } + ob_start(); + passthru("echo " . escapeshellarg($_REQUEST['content']) . " | tidy -q -i -u -wrap 9999 -utf8 -bare -asxhtml 2>/dev/null", $result); + $content = ob_get_contents(); + ob_end_clean(); + + if(!strlen($content)) + { + // Tidy on the local machine failed, try a post + $res_1 + = PostIt( + array + ( + '_function' => 'tidy', + '_html' => $_REQUEST['content'], + 'char-encoding' => 'utf8', + '_output' => 'warn', + 'indent' => 'auto', + 'wrap' => 9999, + 'break-before-br' => 'y', + 'bare' => 'n', + 'word-2000' => 'n', + 'drop-empty-paras' => 'y', + 'drop-font-tags' => 'n', + + ), + 'http://infohound.net/tidy/tidy.pl'); + + if(preg_match('/ diff --git a/xinha/plugins/TableOperations/img/cell-delete.gif b/xinha/plugins/TableOperations/img/cell-delete.gif new file mode 100644 index 0000000..40b2ab1 Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-delete.gif differ diff --git a/xinha/plugins/TableOperations/img/cell-insert-after.gif b/xinha/plugins/TableOperations/img/cell-insert-after.gif new file mode 100644 index 0000000..bea49e9 Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-insert-after.gif differ diff --git a/xinha/plugins/TableOperations/img/cell-insert-before.gif b/xinha/plugins/TableOperations/img/cell-insert-before.gif new file mode 100644 index 0000000..5822174 Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-insert-before.gif differ diff --git a/xinha/plugins/TableOperations/img/cell-merge.gif b/xinha/plugins/TableOperations/img/cell-merge.gif new file mode 100644 index 0000000..4bb9bc3 Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-merge.gif differ diff --git a/xinha/plugins/TableOperations/img/cell-prop.gif b/xinha/plugins/TableOperations/img/cell-prop.gif new file mode 100644 index 0000000..d8bd26e Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-prop.gif differ diff --git a/xinha/plugins/TableOperations/img/cell-split.gif b/xinha/plugins/TableOperations/img/cell-split.gif new file mode 100644 index 0000000..50100d6 Binary files /dev/null and b/xinha/plugins/TableOperations/img/cell-split.gif differ diff --git a/xinha/plugins/TableOperations/img/col-delete.gif b/xinha/plugins/TableOperations/img/col-delete.gif new file mode 100644 index 0000000..aacb0a4 Binary files /dev/null and b/xinha/plugins/TableOperations/img/col-delete.gif differ diff --git a/xinha/plugins/TableOperations/img/col-insert-after.gif b/xinha/plugins/TableOperations/img/col-insert-after.gif new file mode 100644 index 0000000..ca84b49 Binary files /dev/null and b/xinha/plugins/TableOperations/img/col-insert-after.gif differ diff --git a/xinha/plugins/TableOperations/img/col-insert-before.gif b/xinha/plugins/TableOperations/img/col-insert-before.gif new file mode 100644 index 0000000..674210a Binary files /dev/null and b/xinha/plugins/TableOperations/img/col-insert-before.gif differ diff --git a/xinha/plugins/TableOperations/img/col-split.gif b/xinha/plugins/TableOperations/img/col-split.gif new file mode 100644 index 0000000..3e4d59b Binary files /dev/null and b/xinha/plugins/TableOperations/img/col-split.gif differ diff --git a/xinha/plugins/TableOperations/img/row-delete.gif b/xinha/plugins/TableOperations/img/row-delete.gif new file mode 100644 index 0000000..9e88f6f Binary files /dev/null and b/xinha/plugins/TableOperations/img/row-delete.gif differ diff --git a/xinha/plugins/TableOperations/img/row-insert-above.gif b/xinha/plugins/TableOperations/img/row-insert-above.gif new file mode 100644 index 0000000..fc2992c Binary files /dev/null and b/xinha/plugins/TableOperations/img/row-insert-above.gif differ diff --git a/xinha/plugins/TableOperations/img/row-insert-under.gif b/xinha/plugins/TableOperations/img/row-insert-under.gif new file mode 100644 index 0000000..60543ab Binary files /dev/null and b/xinha/plugins/TableOperations/img/row-insert-under.gif differ diff --git a/xinha/plugins/TableOperations/img/row-prop.gif b/xinha/plugins/TableOperations/img/row-prop.gif new file mode 100644 index 0000000..5f3dc93 Binary files /dev/null and b/xinha/plugins/TableOperations/img/row-prop.gif differ diff --git a/xinha/plugins/TableOperations/img/row-split.gif b/xinha/plugins/TableOperations/img/row-split.gif new file mode 100644 index 0000000..926c6a7 Binary files /dev/null and b/xinha/plugins/TableOperations/img/row-split.gif differ diff --git a/xinha/plugins/TableOperations/img/table-prop.gif b/xinha/plugins/TableOperations/img/table-prop.gif new file mode 100644 index 0000000..fbc4d2a Binary files /dev/null and b/xinha/plugins/TableOperations/img/table-prop.gif differ diff --git a/xinha/plugins/TableOperations/lang/cz.js b/xinha/plugins/TableOperations/lang/cz.js new file mode 100644 index 0000000..02ed18e --- /dev/null +++ b/xinha/plugins/TableOperations/lang/cz.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "cz", ENCODING: UTF-8 +// Author: Jiri Löw, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Zarovnání", + "All four sides": "VÅ¡echny ÄtyÅ™i strany", + "Background": "Pozadí", + "Baseline": "Základní linka", + "Border": "Obrys", + "Borders": "Obrysy", + "Bottom": "Dolů", + "Style [CSS]": "Kaskádové styly (CSS)", + "Caption": "Titulek", + "Cell Properties": "Vlastnosti buňky", + "Center": "Na stÅ™ed", + "Char": "Znak", + "Collapsed borders": "StlaÄené okraje", + "Color": "Barva", + "Description": "Popis", + "FG Color": "Barva popÅ™edí", + "Float": "Obtékání", + "Frames": "RámeÄky", + "Height": "Výška", + "How many columns would you like to merge?": "Kolik sloupců si pÅ™ejete spojit?", + "How many rows would you like to merge?": "Kolik řádků si pÅ™ejete spojit?", + "Image URL": "Adresa obrázku", + "Justify": "Do stran", + "Layout": "Rozložení", + "Left": "Vlevo", + "Margin": "Okraj", + "Middle": "Na stÅ™ed", + "No rules": "Žádné Äáry", + "No sides": "Žádné strany", + "None": "Žádné", + "Padding": "Odsazování", + "Please click into some cell": "Prosím kliknÄ›te do nÄ›které buňky", + "Right": "Vpravo", + "Row Properties": "Vlastnosti řádku", + "Rules will appear between all rows and columns": "Čáry mezi vÅ¡emi řádky i sloupci", + "Rules will appear between columns only": "Čáry pouze mezi sloupci", + "Rules will appear between rows only": "Čáry pouze mezi řádky", + "Rules": "Čáry", + "Spacing and padding": "Mezery a odsazování", + "Spacing": "Mezery", + "Summary": "Shrnutí", + "Delete cell": "Smazat buňku", + "Insert cell after": "Vložit buňku za", + "Insert cell before": "Vložit buňku pÅ™ed", + "Merge cells": "Spojit buňky", + "Cell properties": "Vlastnosti buňky", + "Split cell": "RozdÄ›lit buňku", + "Delete column": "Smazat sloupec", + "Insert column after": "Vložit sloupec za", + "Insert column before": "Vložit sloupec pÅ™ed", + "Split column": "RozdÄ›lit sloupec", + "Delete row": "Smazat řádek", + "Insert row before": "Smazat řádek nad", + "Insert row after": "Smazat řádek pod", + "Row properties": "Vlastnosti řádku", + "Split row": "RozdÄ›lit řádek", + "Table properties": "Vlastnosti tabulky", + "Table Properties": "Vlastnosti tabulky", + "Text align": "Zarovnání textu", + "The bottom side only": "Pouze spodní strana", + "The left-hand side only": "Pouze levá strana", + "The right and left sides only": "Pouze levá a pravá strana", + "The right-hand side only": "Pouze pravá strana", + "The top and bottom sides only": "Pouze horní a dolní strana", + "The top side only": "Pouze horní strana", + "Top": "Nahoru", + "Unset color": "ZruÅ¡it barvu", + "Vertical align": "Svislé zarovnání", + "Width": "Šířka", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea zbabÄ›le odmítá smazat poslední buňku v řádku.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea zbabÄ›le odmítá smazat poslední sloupec v tabulce.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea zbabÄ›le odmítá smazat poslední řádek v tabulce.", + "percent": "procent", + "pixels": "pixelů" +} diff --git a/xinha/plugins/TableOperations/lang/da.js b/xinha/plugins/TableOperations/lang/da.js new file mode 100644 index 0000000..066abf8 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/da.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "da", ENCODING: UTF-8 +// Author: Steen Sønderup, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Placer", + "All four sides": "Alle fire sider", + "Background": "Baggrund", + "Baseline": "Bundlinie", + "Border": "Kant", + "Borders": "Kanter", + "Bottom": "Bund", + "Style [CSS]": "Stil [CSS]", + "Caption": "Titel", + "Cell Properties": "Celle egenskaber", + "Center": "Centrer", + "Char": "Plads", + "Collapsed borders": "Sammensmelt rammer", + "Color": "Farve", + "Description": "Beskrivelse", + "FG Color": "Font farve", + "Float": "Justering", + "Frames": "Udvendig", + "Height": "Højde", + "How many columns would you like to merge?": "Hvor mange kollonner vil du samle?", + "How many rows would you like to merge?": "Hvor mange rækker vil du samle?", + "Image URL": "Billede URL", + "Justify": "Lige margener", + "Layout": "Opsætning", + "Left": "Venstre", + "Margin": "Margen", + "Middle": "Centrer", + "No rules": "Ingen rammer", + "No sides": "Ingen sider", + "None": "Ingen", + "Padding": "Margen", + "Please click into some cell": "Klik pÃ¥ en celle", + "Right": "Højre", + "Row Properties": "Række egenskaber", + "Rules will appear between all rows and columns": "Rammer mellem rækker og kolonner", + "Rules will appear between columns only": "Kun rammer mellem kolonner", + "Rules will appear between rows only": "Kun rammer mellem rækker", + "Rules": "Invendig", + "Spacing and padding": "Afstand og margen", + "Spacing": "Afstand", + "Summary": "Beskrivelse", + "Delete cell": "Slet celle", + "Insert cell after": "Indsæt celle efter", + "Insert cell before": "Indsæt celle før", + "Merge cells": "Sammensæt celler", + "Cell properties": "Celle egenskaber", + "Split cell": "Opdel celle", + "Delete column": "Slet kollonne", + "Insert column after": "Indsæt kolonne efter", + "Insert column before": "Indsæt kolonne før", + "Split column": "Opdel kolonne", + "Delete row": "Slet række", + "Insert row before": "Indsæt række før", + "Insert row after": "Indsæt række efter", + "Row properties": "Række egenskaber", + "Split row": "Opdel række", + "Table properties": "Tabel egenskaber", + "Table Properties": "Tabel egenskaber", + "Text align": "Tekst", + "The bottom side only": "Kun i bunden", + "The left-hand side only": "Kun i højre side", + "The right and left sides only": "Kun i siderne", + "The right-hand side only": "Kun i venstre side", + "The top and bottom sides only": "Kun i top og bund", + "The top side only": "Kun i toppen", + "Top": "Top", + "Unset color": "Farve ikke valgt", + "Vertical align": "Vertikal placering", + "Width": "Bredde", + "HTMLArea cowardly refuses to delete the last cell in row.": "Du kan ikke slette den sidste celle i en række.", + "HTMLArea cowardly refuses to delete the last column in table.": "Du kan ikke slette den sidste kolonne i en tabel.", + "HTMLArea cowardly refuses to delete the last row in table.": "Du kan ikke slette den sidste række i en tabel.", + "percent": "procent", + "pixels": "pixel" +} diff --git a/xinha/plugins/TableOperations/lang/de.js b/xinha/plugins/TableOperations/lang/de.js new file mode 100644 index 0000000..7e7b088 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/de.js @@ -0,0 +1,83 @@ +// I18N constants + +// LANG: "de", ENCODING: UTF-8 +// translated: Raimund Meyer xinha@ray-of-light.org + +{ + "Align": "Ausrichtung", + "All four sides": "Alle 4 Seiten", + "Background": "Hintergrund", + "Baseline": "Grundlinie", + "Border": "Rahmen", + "Borders": "Rahmen", + "Bottom": "Unten", + "Style [CSS]": "Style [CSS]", + "Caption": "Überschrift", + "Cell Properties": "Zellenoptionen", + "Center": "Zentriert", + "Char": "Zeichen", + "Collapsed borders": "Rahmen fallen zusammen", + "Color": "Farbe", + "Description": "Beschreibung", + "FG Color": "Vordergrundfarbe", + "Float": "Float", + "Frames": "Rahmen", + "Height": "Höhe", + "How many columns would you like to merge?": "Wieviele Spalten wollen Sie verbinden?", + "How many rows would you like to merge?": "Wieviele Zeilen wollen Sie verbinden?", + "Image URL": "Bild-URL", + "Justify": "Blocksatz", + "Layout": "Layout", + "Left": "Links", + "Margin": "Rand", + "Middle": "Mitte", + "No rules": "Keine Gitterlinien", + "No sides": "Keine Ränder", + "None": "Keine", + "Padding": "Innenabstand", + "Please click into some cell": "Bitte eine Zelle auswählen", + "Right": "Rechts", + "Row Properties": "Zeilenoptionen", + "Rules will appear between all rows and columns": "Linien zwischen Zeilen und Spalten", + "Rules will appear between columns only": "Linien zwischen Spalten", + "Rules will appear between rows only": "Linien zwischen Zeilen", + "Rules": "Linien", + "Spacing and padding": "Abstände", + "Spacing": "Abstand", + "Summary": "Zusammenfassung", + "Delete cell": "Zelle löschen", + "Insert cell after": "Zelle einfügen nach", + "Insert cell before": "Zelle einfügen vor", + "Merge cells": "Zellen zusammenfügen", + "Cell properties": "Zellenoptionen", + "Split cell": "Zellen teilen", + "Delete column": "Spalte löschen", + "Insert column after": "Spalte einfügen nach", + "Insert column before": "Spalte einfügen vor", + "Split column": "Spalte teilen", + "Delete row": "Reihe loeschen", + "Insert row before": "Reihe einfügen vor", + "Insert row after": "Reihe einfügen nach", + "Row properties": "Reiheneinstellungen", + "Split row": "Reihen aufteilen", + "Table properties": "Tabellenoptionen", + "Table Properties": "Tabellenoptionen", + "Text align": "Textausrichtung", + "The bottom side only": "Nur untere Seite", + "The left-hand side only": "Nur linke Seite", + "The right and left sides only": "Nur linke und rechte Seite", + "The right-hand side only": "Nur rechte Seite", + "The top and bottom sides only": "Nur obere und untere Seite", + "The top side only": "Nur obere Seite", + "Top": "Oben", + "Unset color": "Farbe entfernen", + "Vertical align": "Vertikale Ausrichtung", + "Width": "Breite", + "HTMLArea cowardly refuses to delete the last cell in row.": "Letzte Zelle in dieser Zeile kann nicht gelöscht werden", + "HTMLArea cowardly refuses to delete the last column in table.": "Letzte Spalte in dieser Tabelle kann nicht gelöscht werden", + "HTMLArea cowardly refuses to delete the last row in table.": "Letzte Reihe in dieser Tabelle kann nicht gelöscht werden", + "percent": "%", + "pixels": "Pixel", + "OK": "OK", + "Cancel": "Abbrechen" +} diff --git a/xinha/plugins/TableOperations/lang/el.js b/xinha/plugins/TableOperations/lang/el.js new file mode 100644 index 0000000..9916a2c --- /dev/null +++ b/xinha/plugins/TableOperations/lang/el.js @@ -0,0 +1,81 @@ +// I18N constants + +// LANG: "el", ENCODING: UTF-8 +// Author: Dimitris Glezos, dimitris@glezos.com + +{ + "Align": "Στοίχηση", + "All four sides": "Και οι 4 πλευÏές", + "Background": "Φόντο", + "Baseline": "Baseline", + "Border": "ΠεÏίγÏαμμα", + "Borders": "ΠεÏιγÏάμματα", + "Bottom": "Κάτω μέÏος", + "Style [CSS]": "Στυλ [CSS]", + "Caption": "Λεζάντα", + "Cell Properties": "Ιδιότητες ΚελιοÏ", + "Center": "ΚέντÏο", + "Char": "ΧαÏακτήÏας", + "Collapsed borders": "Συμπτυγμένα πεÏιγÏάμματα", + "Color": "ΧÏώμα", + "Description": "ΠεÏιγÏαφή", + "FG Color": "ΧÏώμα αντικειμένων", + "Float": "Float", + "Frames": "Frames", + "Height": "Ύψος", + "How many columns would you like to merge?": "Πόσες στήλες θέλετε να ενώσετε;", + "How many rows would you like to merge?": "Πόσες γÏαμμές θέλετε να ενώσετε;", + "Image URL": "URL εικόνας", + "Justify": "ΠλήÏης στοίχηση", + "Layout": "Διάταξη", + "Left": "ΑÏιστεÏά", + "Margin": "ΠεÏιθώÏιο", + "Middle": "ΚέντÏο", + "No rules": "ΧωÏίς ΓÏαμμές", + "No sides": "No sides", + "None": "Τίποτα", + "Padding": "Εσοχή", + "Please click into some cell": "Κάντε κλικ μέσα σε κάποιο κελί", + "Right": "Δεξιά", + "Row Properties": "Ιδιότητες ΓÏαμμής", + "Rules will appear between all rows and columns": "ΓÏαμμές θα εμφανίζονται Î¼ÎµÏ„Î±Î¾Ï ÏŒÎ»Ï‰Î½ των γÏαμμών και στηλών", + "Rules will appear between columns only": "ΓÏαμμές θα εμφανίζονται μόνο Î¼ÎµÏ„Î±Î¾Ï ÏƒÏ„Î·Î»ÏŽÎ½", + "Rules will appear between rows only": "ΓÏαμμές θα εμφανίζονται μόνο Î¼ÎµÏ„Î±Î¾Ï Î³Ïαμμών", + "Rules": "ΓÏαμμές", + "Spacing and padding": "Αποστάσεις και εσοχές", + "Spacing": "Αποστάσεις", + "Summary": "ΣÏνοψη", + "Delete cell": "ΔιαγÏαφή κελιοÏ", + "Insert cell after": "Εισαγωγή ÎºÎµÎ»Î¹Î¿Ï Î¼ÎµÏ„Î¬", + "Insert cell before": "Εισαγωγή ÎºÎµÎ»Î¹Î¿Ï Ï€Ïιν", + "Merge cells": "Συγχώνευση κελιών", + "Cell properties": "Ιδιότητες κελιοÏ", + "Split cell": "ΔιαίÏεση κελιοÏ", + "Delete column": "ΔιαγÏαφή στήλης", + "Insert column after": "Εισαγωγή στήλης μετά", + "Insert column before": "Εισαγωγή στήλης Ï€Ïιν", + "Split column": "ΔιαίÏεση στήλης", + "Delete row": "ΔιαγÏαφή γÏαμμής", + "Insert row before": "Εισαγωγή γÏαμμής μετά", + "Insert row after": "Εισαγωγή γÏαμμής Ï€Ïιν", + "Row properties": "Ιδιότητες γÏαμμής", + "Split row": "ΔιαίÏεση γÏαμμής", + "Table properties": "Ιδιότητες πίνακα", + "Table Properties": "Ιδιότητες πίνακα", + "Text align": "Στοίχηση κειμένου", + "The bottom side only": "Η κάτω πλευÏά μόνο", + "The left-hand side only": "Η αÏιστεÏή πλευÏά μόνο", + "The right and left sides only": "Οι δεξιές και αÏιστεÏές πλευÏές μόνο", + "The right-hand side only": "Η δεξιά πλευÏά μόνο", + "The top and bottom sides only": "Οι πάνω και κάτω πλευÏές μόνο", + "The top side only": "Η πάνω πλευÏά μόνο", + "Top": "Πάνω", + "Unset color": "ΑναίÏεση χÏώματος", + "Vertical align": "ΚατακόÏυφη στοίχηση", + "Width": "Πλάτος", + "HTMLArea cowardly refuses to delete the last cell in row.": "Δεν μποÏεί να διαγÏαφεί το τελευταίο κελί σε μια γÏαμμή.", + "HTMLArea cowardly refuses to delete the last column in table.": "Δεν μποÏεί να διαγÏαφεί η τελευταία στήλη σε ένα πίνακα.", + "HTMLArea cowardly refuses to delete the last row in table.": "Δεν μποÏεί να διαγÏαφεί η τελευταία γÏαμμή σε ένα πίνακα.", + "percent": "τοις εκατόν", + "pixels": "pixels" +} diff --git a/xinha/plugins/TableOperations/lang/fi.js b/xinha/plugins/TableOperations/lang/fi.js new file mode 100644 index 0000000..e73fd0d --- /dev/null +++ b/xinha/plugins/TableOperations/lang/fi.js @@ -0,0 +1,69 @@ +// I18N constants + +// LANG: "fi", ENCODING: UTF-8 +{ + "Align": "Kohdistus", + "All four sides": "Kaikki neljä sivua", + "Background": "Tausta", + "Baseline": "Takaraja", + "Border": "Reuna", + "Borders": "Reunat", + "Bottom": "Alle", + "Style [CSS]": "Tyyli [CSS]", + "Caption": "Otsikko", + "Cell Properties": "Solun asetukset", + "Center": "Keskelle", + "Char": "Merkki", + "Collapsed borders": "Luhistetut reunat", + "Color": "Väri", + "Description": "Kuvaus", + "FG Color": "FG Väri", + "Frames": "Kehykset", + "Image URL": "Kuvan osoite", + "Layout": "Sommittelu", + "Left": "Vasen", + "Margin": "Marginaali", + "Middle": "Keskelle", + "No rules": "Ei viivoja", + "No sides": "Ei sivuja", + "Padding": "Palstantäyte", + "Right": "Oikea", + "Row Properties": "Rivin asetukset", + "Rules will appear between all rows and columns": "Viivat jokaisen rivin ja sarakkeen välillä", + "Rules will appear between columns only": "Viivat ainoastaan sarakkeiden välillä", + "Rules will appear between rows only": "Viivat ainoastaan rivien välillä", + "Rules": "Viivat", + "Spacing": "Palstatila", + "Summary": "Yhteenveto", + "Delete cell": "Poista solu", + "Insert cell after": "Lisää solu perään", + "Insert cell before": "Lisää solu ennen", + "Merge cells": "Yhdistä solut", + "Cell properties": "Solun asetukset", + "Split cell": "Jaa solu", + "Delete column": "Poista sarake", + "Insert column after": "Lisää sarake perään", + "Insert column before": "Lisää sarake ennen", + "Split column": "Jaa sarake", + "Delete row": "Poista rivi", + "Insert row before": "Lisää rivi yläpuolelle", + "Insert row after": "Lisää rivi alapuolelle", + "Row properties": "Rivin asetukset", + "Split row": "Jaa rivi", + "Table properties": "Taulukon asetukset", + "Top": "Ylös", + "Table Properties": "Taulukon asetukset", + "The bottom side only": "Ainoastaan alapuolelle", + "The left-hand side only": "Ainoastaan vasenreuna", + "The right and left sides only": "Oikea- ja vasenreuna", + "The right-hand side only": "Ainoastaan oikeareuna", + "The top and bottom sides only": "Ylä- ja alapuoli.", + "The top side only": "Ainoastaan yläpuoli", + "Vertical align": "Vertikaali kohdistus", + "Width": "Leveys", + "HTMLArea cowardly refuses to delete the last cell in row.": "Ei voida poistaa viimeistä solua rivistä.", + "HTMLArea cowardly refuses to delete the last column in table.": "Ei voida poistaa viimeistä saraketta taulusta.", + "HTMLArea cowardly refuses to delete the last row in table.": "Ei voida poistaa viimeistä riviä taulusta.", + "percent": "prosenttia", + "pixels": "pikseliä" +} diff --git a/xinha/plugins/TableOperations/lang/fr.js b/xinha/plugins/TableOperations/lang/fr.js new file mode 100644 index 0000000..8dbca95 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/fr.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "fr", ENCODING: UTF-8 +// Author: Cédric Guillemette, http://www.ebdata.com + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Aligner", + "All four sides": "Quatre cotés", + "Background": "Arrière plan", + "Baseline": "Ligne de base", + "Border": "Bordure", + "Borders": "Bordures", + "Bottom": "Bas", + "Style [CSS]": "Style [CSS]", + "Caption": "Étiquette", + "Cell Properties": "Propriétés de cellule", + "Center": "Centre", + "Char": "Charactère", + "Collapsed borders": "Bordure effondrés", + "Color": "Couleur", + "Description": "Description", + "FG Color": "Couleur de face", + "Float": "Flotteur", + "Frames": "Vues", + "Height": "Largeur", + "How many columns would you like to merge?": "Combien de colonnes voulez-vous fusionner?", + "How many rows would you like to merge?": "Combien de rangées voulez-vous fusionner?", + "Image URL": "URL pour l'image", + "Justify": "Justifié", + "Layout": "Arrangement", + "Left": "Gauche", + "Margin": "Marge", + "Middle": "Milieu", + "No rules": "Aucun règlement", + "No sides": "Aucun côtés", + "None": "Aucun", + "Padding": "Remplissage", + "Please click into some cell": "Cliquer sur une cellule", + "Right": "Droit", + "Row Properties": "Propriétés de rangée", + "Rules will appear between all rows and columns": "Les règles vont apparaître entre les rangées et les cellules", + "Rules will appear between columns only": "Les règles vont apparaître entre les colonnes seulement", + "Rules will appear between rows only": "Les règles vont apparaître entre les rangées seulement", + "Rules": "Les règles", + "Spacing and padding": "Espacement et remplissage", + "Spacing": "Espacement", + "Summary": "Sommaire", + "Delete cell": "Supprimer une cellule", + "Insert cell after": "Insérer une cellule après", + "Insert cell before": "Insérer une cellule avant", + "Merge cells": "Fusionner les cellules", + "Cell properties": "Cell properties", + "Split cell": "Diviser la cellule", + "Delete column": "Supprimer la colonne", + "Insert column after": "Insérer une colonne après", + "Insert column before": "Insérer une colonne avant", + "Split column": "Diviser une colonne", + "Delete row": "Supprimer une rangée", + "Insert row before": "Insérer une rangée avant", + "Insert row after": "Insérer une rangée après", + "Row properties": "Propriétés de rangée", + "Split row": "Diviser la rangée", + "Table properties": "Propriétés de table", + "Table Properties": "Propriétés de table", + "Text align": "Aligner le texte", + "The bottom side only": "Côté du bas seulement", + "The left-hand side only": "Côté gauche seulement", + "The right and left sides only": "Côté gauche et droit seulement", + "The right-hand side only": "Côté droit seulement", + "The top and bottom sides only": "Côté haut et bas seulement", + "The top side only": "Côté haut seulement", + "Top": "Haut", + "Unset color": "Enlever la couleur", + "Vertical align": "Alignement vertical", + "Width": "Longeur", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea refuse de supprimer la dernière cellule de la rangée.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea refuse de supprimer la dernière colonne de la table.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea refuse de supprimer la dernière rangée de la table", + "percent": "pourcentage", + "pixels": "pixels" +} diff --git a/xinha/plugins/TableOperations/lang/he.js b/xinha/plugins/TableOperations/lang/he.js new file mode 100644 index 0000000..301a12f --- /dev/null +++ b/xinha/plugins/TableOperations/lang/he.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "he", ENCODING: UTF-8 +// Author: Liron Newman, http://www.eesh.net, + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "ישור", + "All four sides": "כל ×רבעת הצדדי×", + "Background": "רקע", + "Baseline": "קו בסיס", + "Border": "גבול", + "Borders": "גבולות", + "Bottom": "תחתון", + "Style [CSS]": "סגנון [CSS]", + "Caption": "כותרת", + "Cell Properties": "מ×פייני ת×", + "Center": "מרכז", + "Char": "תו", + "Collapsed borders": "גבולות קורסי×", + "Color": "צבע", + "Description": "תי×ור", + "FG Color": "צבע קידמה", + "Float": "מרחף", + "Frames": "מסגרות", + "Height": "גובה", + "How many columns would you like to merge?": "כמה ×˜×•×¨×™× ×‘×¨×¦×•× ×š למזג?", + "How many rows would you like to merge?": "כמה שורות ברצונך למזג?", + "Image URL": "URL התמונה", + "Justify": "ישור", + "Layout": "פריסה", + "Left": "שמ×ל", + "Margin": "שוליי×", + "Middle": "×מצע", + "No rules": "×œ×œ× ×§×•×•×™×", + "No sides": "×œ×œ× ×¦×“×“×™×", + "None": "×ין", + "Padding": "ריווח בשוליי×", + "Please click into some cell": "×× × ×œ×—×¥ על ×ª× ×›×œ×©×”×•", + "Right": "ימין", + "Row Properties": "מ×פייני שורה", + "Rules will appear between all rows and columns": "×§×•×•×™× ×™×•×¤×™×¢×• בין כל השורות והטורי×", + "Rules will appear between columns only": "×§×•×•×™× ×™×•×¤×™×¢×• בין ×˜×•×¨×™× ×‘×œ×‘×“", + "Rules will appear between rows only": "×§×•×•×™× ×™×•×¤×™×¢×• בין שורות בלבד", + "Rules": "קווי×", + "Spacing and padding": "ריווח ושוליי×", + "Spacing": "ריווח", + "Summary": "סיכו×", + "Delete cell": "מחק ת×", + "Insert cell after": "הכנס ×ª× ×חרי", + "Insert cell before": "הכנס ×ª× ×œ×¤× ×™", + "Merge cells": "מזג ת××™×", + "Cell properties": "מ×פייני ת×", + "Split cell": "פצל ת×", + "Delete column": "מחק טור", + "Insert column after": "הכנס טור ×חרי", + "Insert column before": "הכנס טור לפני", + "Split column": "פצל טור", + "Delete row": "מחק שורה", + "Insert row before": "הכנס שורה לפני", + "Insert row after": "הכנס שורה ×חרי", + "Row properties": "מ×פייני שורה", + "Split row": "פצל שורה", + "Table properties": "מ×פייני טבלה", + "Table Properties": "מ×פייני טבלה", + "Text align": "ישור טקסט", + "The bottom side only": "הצד התחתון בלבד", + "The left-hand side only": "הצד השמ×לי בלבד", + "The right and left sides only": "×”×¦×“×“×™× ×”×™×ž× ×™ והשמ×לי בלבד", + "The right-hand side only": "הצד הימני בלבד", + "The top and bottom sides only": "×”×¦×“×“×™× ×”×¢×œ×™×•×Ÿ והתחתון בלבד", + "The top side only": "הצד העליון בלבד", + "Top": "עליון", + "Unset color": "צבע ×œ× × ×‘×—×¨", + "Vertical align": "יישור ×× ×›×™", + "Width": "רוחב", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea מסרב בפחדנות למחוק ×ת ×”×ª× ×”×חרון בשורה.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea מסרב בפחדנות למחוק ×ת הטור ×”×חרון בטבלה.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea מסרב בפחדנות למחוק ×ת השורה ×”×חרונה בטבלה.", + "percent": "×חוז", + "pixels": "פיקסלי×" +} diff --git a/xinha/plugins/TableOperations/lang/it.js b/xinha/plugins/TableOperations/lang/it.js new file mode 100644 index 0000000..7c814b1 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/it.js @@ -0,0 +1,81 @@ +// I18N constants + +// LANG: "it", ENCODING: UTF-8 +// Author: Fabio Rotondo + +{ + "Align": "Allinea", + "All four sides": "Tutti e quattro i lati", + "Background": "Sfondo", + "Baseline": "Allineamento", + "Border": "Bordo", + "Borders": "Bordi", + "Bottom": "Basso", + "Style [CSS]": "Stile [CSS]", + "Caption": "Titolo", + "Cell Properties": "Proprietà della Cella", + "Center": "Centra", + "Char": "Carattere", + "Collapsed borders": "Bordi chiusi", + "Color": "Colore", + "Description": "Descrizione", + "FG Color": "Colore Principale", + "Float": "Fluttuante", + "Frames": "Frames", + "Height": "Altezza", + "How many columns would you like to merge?": "Quante colonne vuoi unire?", + "How many rows would you like to merge?": "Quante righe vuoi unire?", + "Image URL": "URL dell'Immagine", + "Justify": "Justifica", + "Layout": "Layout", + "Left": "Sinistra", + "Margin": "Margine", + "Middle": "Centrale", + "No rules": "Nessun righello", + "No sides": "Nessun lato", + "None": "Nulla", + "Padding": "Padding", + "Please click into some cell": "Per favore, clicca in una cella", + "Right": "Destra", + "Row Properties": "Proprietà della Riga", + "Rules will appear between all rows and columns": "Le linee appariranno tra tutte le righe e colonne", + "Rules will appear between columns only": "Le linee appariranno solo tra le colonne", + "Rules will appear between rows only": "Le linee appariranno solo tra le righe", + "Rules": "Linee", + "Spacing and padding": "Spaziatura e Padding", + "Spacing": "Spaziatura", + "Summary": "Sommario", + "Delete cell": "Cancella cella", + "Insert cell after": "Inserisci cella dopo", + "Insert cell before": "Inserisci cella prima", + "Merge cells": "Unisci celle", + "Cell properties": "Proprietà della cella", + "Split cell": "Dividi cella", + "Delete column": "Cancella colonna", + "Insert column after": "Inserisci colonna dopo", + "Insert column before": "Inserisci colonna prima", + "Split column": "Dividi colonna", + "Delete row": "Cancella riga", + "Insert row before": "Inserisci riga prima", + "Insert row after": "Inserisci riga dopo", + "Row properties": "Proprietà della riga", + "Split row": "Dividi riga", + "Table properties": "Proprietà della Tabella", + "Table Properties": "Proprietà della Tabella", + "Text align": "Allineamento del Testo", + "The bottom side only": "Solo la parte inferiore", + "The left-hand side only": "Solo la parte sinistra", + "The right and left sides only": "Solo destra e sinistra", + "The right-hand side only": "Solo la parte destra", + "The top and bottom sides only": "Solo sopra e sotto", + "The top side only": "Solo la parte sopra", + "Top": "Alto", + "Unset color": "Rimuovi colore", + "Vertical align": "Allineamento verticale", + "Width": "Larghezza", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea si rifiuta codardamente di cancellare l'ultima cella nella riga.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea si rifiuta codardamente di cancellare l'ultima colonna nella tabella.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea si rifiuta codardamente di cancellare l'ultima riga nella tabella.", + "percent": "percento", + "pixels": "pixels" +} diff --git a/xinha/plugins/TableOperations/lang/nl.js b/xinha/plugins/TableOperations/lang/nl.js new file mode 100644 index 0000000..4a44d26 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/nl.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "nl", ENCODING: UTF-8 +// Author: Michel Weegeerink (info@mmc-shop.nl), http://mmc-shop.nl + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Uitlijning", + "All four sides": "Alle 4 zijden", + "Background": "Achtergrond", + "Baseline": "Basis", + "Border": "Rand", + "Borders": "Randen", + "Bottom": "Onder", + "Style [CSS]": "CSS Style", + "Caption": "Opmerking", + "Cell Properties": "Celeigenschappen", + "Center": "Centreren", + "Char": "Karakter", + "Collapsed borders": "Geen randen", + "Color": "Kleur", + "Description": "Omschrijving", + "FG Color": "Voorgrond", + "Float": "Zwevend", + "Frames": "Frames", + "Height": "Hoogte", + "How many columns would you like to merge?": "Hoeveel kolommen wilt u samenvoegen?", + "How many rows would you like to merge?": "Hoeveel rijen wilt u samenvoegen?", + "Image URL": "Afbeelding URL", + "Justify": "Uitvullen", + "Layout": "Opmaak", + "Left": "Links", + "Margin": "Marge", + "Middle": "Midden", + "No rules": "Geen regels", + "No sides": "Geen zijlijnen", + "None": "Geen", + "Padding": "Celmarge", + "Please click into some cell": "Klik in een cel a.u.b.", + "Right": "Rechts", + "Row Properties": "Rijeigenschappen", + "Rules will appear between all rows and columns": "Regels verschijnen tussen alle rijen en kolommen", + "Rules will appear between columns only": "Regels verschijnen enkel tussen de kolommen", + "Rules will appear between rows only": "Regels verschijnen enkel tussen de rijen", + "Rules": "Regels", + "Spacing and padding": "Celmarge en afstand tussen cellen", + "Spacing": "marge", + "Summary": "Overzicht", + "Delete cell": "Cel verwijderen", + "Insert cell after": "Voeg cel toe achter", + "Insert cell before": "Voeg cel toe voor", + "Merge cells": "Cellen samenvoegen", + "Cell properties": "Celeigenschappen", + "Split cell": "Cel splitsen", + "Delete column": "Kolom verwijderen", + "Insert column after": "Kolom invoegen achter", + "Insert column before": "Kolom invoegen voor", + "Split column": "Kolom splitsen", + "Delete row": "Rij verwijderen", + "Insert row before": "Rij invoegen boven", + "Insert row after": "Rij invoegen onder", + "Row properties": "Rij eigenschappen", + "Split row": "Rij splitsen", + "Table properties": "Tabel eigenschappen", + "Table Properties": "Tabel eigenschappen", + "Text align": "Text uitlijning", + "The bottom side only": "Enkel aan de onderkant", + "The left-hand side only": "Enkel aan de linkerkant", + "The right and left sides only": "Enkel aan de linker en rechterkant", + "The right-hand side only": "Enkel aan de rechterkant", + "The top and bottom sides only": "Enkel aan de bovenen onderkant", + "The top side only": "Enkel aan de bovenkant", + "Top": "Boven", + "Unset color": "Wis kleur", + "Vertical align": "Vertikale uitlijning", + "Width": "Breedte", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea kan de laatste cel in deze tabel niet verwijderen.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea kan de laatste kolom in deze tabel niet verwijderen.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea kan de laatste rij in deze tabel niet verwijderen.", + "percent": "procent", + "pixels": "pixels" +} diff --git a/xinha/plugins/TableOperations/lang/no.js b/xinha/plugins/TableOperations/lang/no.js new file mode 100644 index 0000000..c145edc --- /dev/null +++ b/xinha/plugins/TableOperations/lang/no.js @@ -0,0 +1,91 @@ +// I18N constants + +// LANG: "no", ENCODING: UTF-8 +// Author: Mihai Bazon, +// translated into Norwegian: ses@online.no 11.11.03 + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Juster", + "All four sides": "Alle fire sider", + "Background": "Bakgrund", + "Baseline": "Grunnlinje", + "Border": "Kantlinje", + "Borders": "Kantlinjer", + "Bottom": "Bunn", + "Style [CSS]": "Stil [CSS]", + "Caption": "Overskrift", + "Cell Properties": "Celleegenskaper", + "Center": "Sentrer", + "Char": "Tegn", + "Collapsed borders": "Fjern kantlinjer", + "Color": "Farge", + "Description": "Beskrivelse", + "FG Color": "FG farge", + "Float": "Flytende", + "Frames": "rammer", + "Height": "Høyde", + "How many columns would you like to merge?": "Hvor mange kolonner vil du slÃ¥ sammen?", + "How many rows would you like to merge?": "Hvor mange rader vil du slÃ¥ sammen?", + "Image URL": "Bildets URL", + "Justify": "Juster", + "Layout": "Layout", + "Left": "Venstre", + "Margin": "Marg", + "Middle": "Midten", + "No rules": "Ingen linjal", + "No sides": "Ingen sider", + "None": "Ingen", + "Padding": "Luft", + "Please click into some cell": "Klikk i en eller annen celle", + "Right": "Høyre", + "Row Properties": "Egenskaper for rad", + "Rules will appear between all rows and columns": "Linjer vil synes mellom alle rader og kolonner", + "Rules will appear between columns only": "Linjer vil synes kun mellom kolonner", + "Rules will appear between rows only": "Linjer vil synes kun mellom rader", + "Rules": "Linjer", + "Spacing and padding": "Luft", + "Spacing": "Luft", + "Summary": "Sammendrag", + "Delete cell": "Slett celle", + "Insert cell after": "Sett inn celle etter", + "Insert cell before": "Sett inn celle foran", + "Merge cells": "SlÃ¥ sammen celler", + "Cell properties": "Egenskaper for celle", + "Split cell": "Del celle", + "Delete column": "Slett kolonne", + "Insert column after": "Skyt inn kolonne etter", + "Insert column before": "Skyt inn kolonne før", + "Split column": "Del kolonne", + "Delete row": "Slett rad", + "Insert row before": "Skyt inn rad foran", + "Insert row after": "Skyt inn rad etter", + "Row properties": "Egenskaper for rad", + "Split row": "Del rad", + "Table properties": "Tabellegenskaper", + "Table Properties": "Tabellegenskaper", + "Text align": "Juster tekst", + "The bottom side only": "Bunnen kun", + "The left-hand side only": "Venstresiden kun", + "The right and left sides only": "Høyre- og venstresiden kun", + "The right-hand side only": "Høyresiden kun", + "The top and bottom sides only": "The top and bottom sides only", + "The top side only": "Overkanten kun", + "Top": "Overkant", + "Unset color": "Ikke-bestemt farge", + "Vertical align": "Vertikal justering", + "Width": "Bredde", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea nekter Ã¥ slette siste cellen i tabellen.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea nekter Ã¥ slette siste kolonnen i tabellen.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea nekter Ã¥ slette siste raden i tabellen.", + "percent": "prosent", + "pixels": "billedpunkter" +} diff --git a/xinha/plugins/TableOperations/lang/ro.js b/xinha/plugins/TableOperations/lang/ro.js new file mode 100644 index 0000000..2fade84 --- /dev/null +++ b/xinha/plugins/TableOperations/lang/ro.js @@ -0,0 +1,90 @@ +// I18N constants + +// LANG: "ro", ENCODING: UTF-8 +// Author: Mihai Bazon, http://dynarch.com/mishoo + +// FOR TRANSLATORS: +// +// 1. PLEASE PUT YOUR CONTACT INFO IN THE ABOVE LINE +// (at least a valid email address) +// +// 2. PLEASE TRY TO USE UTF-8 FOR ENCODING; +// (if this is not possible, please include a comment +// that states what encoding is necessary.) + +{ + "Align": "Aliniere", + "All four sides": "Toate părÅ£ile", + "Background": "Fundal", + "Baseline": "Baseline", + "Border": "Chenar", + "Borders": "Chenare", + "Bottom": "Jos", + "Style [CSS]": "Stil [CSS]", + "Caption": "Titlu de tabel", + "Cell Properties": "Proprietăţile celulei", + "Center": "Centru", + "Char": "Caracter", + "Collapsed borders": "Chenare asimilate", + "Color": "Culoare", + "Description": "Descriere", + "FG Color": "Culoare text", + "Float": "PoziÅ£ie", + "Frames": "Chenare", + "Height": "ÃŽnălÅ£imea", + "How many columns would you like to merge?": "Câte coloane vrei să uneÅŸti?", + "How many rows would you like to merge?": "Câte linii vrei să uneÅŸti?", + "Image URL": "URL-ul imaginii", + "Justify": "Justify", + "Layout": "Aranjament", + "Left": "Stânga", + "Margin": "Margine", + "Middle": "Mijloc", + "No rules": "Fără linii", + "No sides": "Fără părÅ£i", + "None": "Nimic", + "Padding": "SpaÅ£iere", + "Please click into some cell": "Vă rog să daÅ£i click într-o celulă", + "Right": "Dreapta", + "Row Properties": "Proprietăţile liniei", + "Rules will appear between all rows and columns": "Vor apărea linii între toate rândurile ÅŸi coloanele", + "Rules will appear between columns only": "Vor apărea doar linii verticale", + "Rules will appear between rows only": "Vor apărea doar linii orizontale", + "Rules": "Linii", + "Spacing and padding": "SpaÅ£ierea", + "Spacing": "ÃŽntre celule", + "Summary": "Sumar", + "Delete cell": "Åžterge celula", + "Insert cell after": "Inserează o celulă la dreapta", + "Insert cell before": "Inserează o celulă la stânga", + "Merge cells": "UneÅŸte celulele", + "Cell properties": "Proprietăţile celulei", + "Split cell": "ÃŽmparte celula", + "Delete column": "Åžterge coloana", + "Insert column after": "Inserează o coloană la dreapta", + "Insert column before": "Inserează o coloană la stânga", + "Split column": "ÃŽmparte coloana", + "Delete row": "Åžterge rândul", + "Insert row before": "Inserează un rând înainte", + "Insert row after": "Inserează un rând după", + "Row properties": "Proprietăţile rândului", + "Split row": "ÃŽmparte rândul", + "Table properties": "Proprietăţile tabelei", + "Table Properties": "Proprietăţile tabelei", + "Text align": "Aliniere", + "The bottom side only": "Doar partea de jos", + "The left-hand side only": "Doar partea din stânga", + "The right and left sides only": "Partea din stânga ÅŸi cea din dreapta", + "The right-hand side only": "Doar partea din dreapta", + "The top and bottom sides only": "Partea de sus si cea de jos", + "The top side only": "Doar partea de sus", + "Top": "Sus", + "Unset color": "Dezactivează culoarea", + "Vertical align": "Aliniere pe verticală", + "Width": "Lăţime", + "HTMLArea cowardly refuses to delete the last cell in row.": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultima celulă din rând.", + "HTMLArea cowardly refuses to delete the last column in table.": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultima coloamă din tabela.", + "HTMLArea cowardly refuses to delete the last row in table.": "HTMLArea refuză cu laÅŸitate să ÅŸteargă ultimul rând din tabela.", + "percent": "procente", + "pixels": "pixeli" +} diff --git a/xinha/plugins/TableOperations/table-operations.js b/xinha/plugins/TableOperations/table-operations.js new file mode 100644 index 0000000..8d84e78 --- /dev/null +++ b/xinha/plugins/TableOperations/table-operations.js @@ -0,0 +1,1170 @@ +// Table Operations Plugin for HTMLArea-3.0 +// Implementation by Mihai Bazon. Sponsored by http://www.bloki.com +// +// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc. +// This notice MUST stay intact for use (see license.txt). +// +// A free WYSIWYG editor replacement for