Podświetlanie składni w edytorze XML dzięki editArea. Closes #17. Niestety dla tekstó...
[redakcja.git] / project / static / js / edit_area.js
diff --git a/project/static/js/edit_area.js b/project/static/js/edit_area.js
new file mode 100755 (executable)
index 0000000..27674f6
--- /dev/null
@@ -0,0 +1,525 @@
+/******\r
+ *\r
+ *     EditArea \r
+ *     Developped by Christophe Dolivet\r
+ *     Released under LGPL, Apache and BSD licenses (use the one you want)\r
+ *\r
+******/\r
+\r
+       function EditArea(){\r
+               var t=this;\r
+               t.error= false; // to know if load is interrrupt\r
+               \r
+               t.inlinePopup= [{popup_id: "area_search_replace", icon_id: "search"},\r
+                                                                       {popup_id: "edit_area_help", icon_id: "help"}];\r
+               t.plugins= {};\r
+       \r
+               t.line_number=0;\r
+               \r
+               parent.editAreaLoader.set_browser_infos(t);     // navigator identification\r
+               // fix IE8 detection as we run in IE7 emulate mode through X-UA <meta> tag\r
+               if( t.isIE >= 8 )\r
+                       t.isIE  = 7;\r
+               \r
+               t.last_selection={};            \r
+               t.last_text_to_highlight="";\r
+               t.last_hightlighted_text= "";\r
+               t.syntax_list= [];\r
+               t.allready_used_syntax= {};\r
+               t.check_line_selection_timer= 50;       // the timer delay for modification and/or selection change detection\r
+               \r
+               t.textareaFocused= false;\r
+               t.highlight_selection_line= null;\r
+               t.previous= [];\r
+               t.next= [];\r
+               t.last_undo="";\r
+               t.files= {};\r
+               t.filesIdAssoc= {};\r
+               t.curr_file= '';\r
+               //t.loaded= false;\r
+               t.assocBracket={};\r
+               t.revertAssocBracket= {};               \r
+               // bracket selection init \r
+               t.assocBracket["("]=")";\r
+               t.assocBracket["{"]="}";\r
+               t.assocBracket["["]="]";                \r
+               for(var index in t.assocBracket){\r
+                       t.revertAssocBracket[t.assocBracket[index]]=index;\r
+               }\r
+               t.is_editable= true;\r
+               \r
+               \r
+               /*t.textarea="";        \r
+               \r
+               t.state="declare";\r
+               t.code = []; // store highlight syntax for languagues*/\r
+               // font datas\r
+               t.lineHeight= 16;\r
+               /*t.default_font_family= "monospace";\r
+               t.default_font_size= 10;*/\r
+               t.tab_nb_char= 8;       //nb of white spaces corresponding to a tabulation\r
+               if(t.isOpera)\r
+                       t.tab_nb_char= 6;\r
+\r
+               t.is_tabbing= false;\r
+               \r
+               t.fullscreen= {'isFull': false};\r
+               \r
+               t.isResizing=false;     // resize var\r
+               \r
+               // init with settings and ID (area_id is a global var defined by editAreaLoader on iframe creation\r
+               t.id= area_id;\r
+               t.settings= editAreas[t.id]["settings"];\r
+               \r
+               if((""+t.settings['replace_tab_by_spaces']).match(/^[0-9]+$/))\r
+               {\r
+                       t.tab_nb_char= t.settings['replace_tab_by_spaces'];\r
+                       t.tabulation="";\r
+                       for(var i=0; i<t.tab_nb_char; i++)\r
+                               t.tabulation+=" ";\r
+               }else{\r
+                       t.tabulation="\t";\r
+               }\r
+                       \r
+               // retrieve the init parameter for syntax\r
+               if(t.settings["syntax_selection_allow"] && t.settings["syntax_selection_allow"].length>0)\r
+                       t.syntax_list= t.settings["syntax_selection_allow"].replace(/ /g,"").split(",");\r
+               \r
+               if(t.settings['syntax'])\r
+                       t.allready_used_syntax[t.settings['syntax']]=true;\r
+               \r
+               \r
+       };\r
+       EditArea.prototype.init= function(){\r
+               var t=this, a, s=t.settings;\r
+               t.textarea                      = _$("textarea");\r
+               t.container                     = _$("container");\r
+               t.result                        = _$("result");\r
+               t.content_highlight     = _$("content_highlight");\r
+               t.selection_field       = _$("selection_field");\r
+               t.selection_field_text= _$("selection_field_text");\r
+               t.processing_screen     = _$("processing");\r
+               t.editor_area           = _$("editor");\r
+               t.tab_browsing_area     = _$("tab_browsing_area");\r
+               t.test_font_size        = _$("test_font_size");\r
+               a = t.textarea;\r
+               \r
+               if(!s['is_editable'])\r
+                       t.set_editable(false);\r
+               \r
+               t.set_show_line_colors( s['show_line_colors'] );\r
+               \r
+               if(syntax_selec= _$("syntax_selection"))\r
+               {\r
+                       // set up syntax selection lsit in the toolbar\r
+                       for(var i=0; i<t.syntax_list.length; i++) {\r
+                               var syntax= t.syntax_list[i];\r
+                               var option= document.createElement("option");\r
+                               option.value= syntax;\r
+                               if(syntax==s['syntax'])\r
+                                       option.selected= "selected";\r
+                               option.innerHTML= t.get_translation("syntax_" + syntax, "word");\r
+                               syntax_selec.appendChild(option);\r
+                       }\r
+               }\r
+               \r
+               // add plugins buttons in the toolbar\r
+               spans= parent.getChildren(_$("toolbar_1"), "span", "", "", "all", -1);\r
+               \r
+               for(var i=0; i<spans.length; i++){\r
+               \r
+                       id=spans[i].id.replace(/tmp_tool_(.*)/, "$1");\r
+                       if(id!= spans[i].id){\r
+                               for(var j in t.plugins){\r
+                                       if(typeof(t.plugins[j].get_control_html)=="function" ){\r
+                                               html=t.plugins[j].get_control_html(id);\r
+                                               if(html!=false){\r
+                                                       html= t.get_translation(html, "template");\r
+                                                       var new_span= document.createElement("span");\r
+                                                       new_span.innerHTML= html;                               \r
+                                                       var father= spans[i].parentNode;\r
+                                                       spans[i].parentNode.replaceChild(new_span, spans[i]);   \r
+                                                       break; // exit the for loop                                     \r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               // init datas\r
+               //a.value       = 'a';//editAreas[t.id]["textarea"].value;\r
+       \r
+               if(s["debug"])\r
+               {\r
+                       t.debug=parent.document.getElementById("edit_area_debug_"+t.id);\r
+               }\r
+               // init size            \r
+               //this.update_size();\r
+               \r
+               if(_$("redo") != null)\r
+                       t.switchClassSticky(_$("redo"), 'editAreaButtonDisabled', true);\r
+               \r
+               // insert css rules for highlight mode          \r
+               if(typeof(parent.editAreaLoader.syntax[s["syntax"]])!="undefined"){\r
+                       for(var i in parent.editAreaLoader.syntax){\r
+                               if (typeof(parent.editAreaLoader.syntax[i]["styles"]) != "undefined"){\r
+                                       t.add_style(parent.editAreaLoader.syntax[i]["styles"]);\r
+                               }\r
+                       }\r
+               }\r
+       \r
+               // init key events\r
+               if(t.isOpera)\r
+                       _$("editor").onkeypress = keyDown;\r
+               else\r
+                       _$("editor").onkeydown  = keyDown;\r
+\r
+               for(var i=0; i<t.inlinePopup.length; i++){\r
+                       if(t.isOpera)\r
+                               _$(t.inlinePopup[i]["popup_id"]).onkeypress     = keyDown;\r
+                       else\r
+                               _$(t.inlinePopup[i]["popup_id"]).onkeydown      = keyDown;\r
+               }\r
+               \r
+               if(s["allow_resize"]=="both" || s["allow_resize"]=="x" || s["allow_resize"]=="y")\r
+                       t.allow_resize(true);\r
+               \r
+               parent.editAreaLoader.toggle(t.id, "on");\r
+               //a.focus();\r
+               // line selection init\r
+               t.change_smooth_selection_mode(editArea.smooth_selection);\r
+               // highlight\r
+               t.execCommand("change_highlight", s["start_highlight"]);\r
+       \r
+               // get font size datas          \r
+               t.set_font(editArea.settings["font_family"], editArea.settings["font_size"]);\r
+               \r
+               // set unselectable text\r
+               children= parent.getChildren(document.body, "", "selec", "none", "all", -1);\r
+               for(var i=0; i<children.length; i++){\r
+                       if(t.isIE)\r
+                               children[i].unselectable = true; // IE\r
+                       else\r
+                               children[i].onmousedown= function(){return false};\r
+               /*      children[i].style.MozUserSelect = "none"; // Moz\r
+                       children[i].style.KhtmlUserSelect = "none";  // Konqueror/Safari*/\r
+               }\r
+               \r
+               a.spellcheck= s["gecko_spellcheck"];\r
+       \r
+               /** Browser specific style fixes **/\r
+               \r
+               // fix rendering bug for highlighted lines beginning with no tabs\r
+               if( t.isFirefox >= '3' ) {\r
+                       t.content_highlight.style.paddingLeft= "1px";\r
+                       t.selection_field.style.paddingLeft= "1px";\r
+                       t.selection_field_text.style.paddingLeft= "1px";\r
+               }\r
+               \r
+               if(t.isIE && t.isIE < 8 ){\r
+                       a.style.marginTop= "-1px";\r
+               }\r
+               /*\r
+               if(t.isOpera){\r
+                       t.editor_area.style.position= "absolute";\r
+               }*/\r
+               \r
+               if( t.isSafari ){\r
+                       t.editor_area.style.position    = "absolute";\r
+                       a.style.marginLeft              ="-3px";\r
+                       if( t.isSafari < 3.2 ) // Safari 3.0 (3.1?)\r
+                               a.style.marginTop       ="1px";\r
+               }\r
+               \r
+               // si le textarea n'est pas grand, un click sous le textarea doit provoquer un focus sur le textarea\r
+               parent.editAreaLoader.add_event(t.result, "click", function(e){ if((e.target || e.srcElement)==editArea.result) { editArea.area_select(editArea.textarea.value.length, 0);}  });\r
+               \r
+               if(s['is_multi_files']!=false)\r
+                       t.open_file({'id': t.curr_file, 'text': ''});\r
+       \r
+               t.set_word_wrap( s['word_wrap'] );\r
+               \r
+               setTimeout("editArea.focus();editArea.manage_size();editArea.execCommand('EA_load');", 10);             \r
+               //start checkup routine\r
+               t.check_undo();\r
+               t.check_line_selection(true);\r
+               t.scroll_to_view();\r
+               \r
+               for(var i in t.plugins){\r
+                       if(typeof(t.plugins[i].onload)=="function")\r
+                               t.plugins[i].onload();\r
+               }\r
+               if(s['fullscreen']==true)\r
+                       t.toggle_full_screen(true);\r
+       \r
+               parent.editAreaLoader.add_event(window, "resize", editArea.update_size);\r
+               parent.editAreaLoader.add_event(parent.window, "resize", editArea.update_size);\r
+               parent.editAreaLoader.add_event(top.window, "resize", editArea.update_size);\r
+               parent.editAreaLoader.add_event(window, "unload", function(){\r
+                       // in case where editAreaLoader have been already cleaned\r
+                       if( parent.editAreaLoader )\r
+                       {\r
+                               parent.editAreaLoader.remove_event(parent.window, "resize", editArea.update_size);\r
+                               parent.editAreaLoader.remove_event(top.window, "resize", editArea.update_size);\r
+                       }\r
+                       if(editAreas[editArea.id] && editAreas[editArea.id]["displayed"]){\r
+                               editArea.execCommand("EA_unload");\r
+                       }\r
+               });\r
+               \r
+               \r
+               /*date= new Date();\r
+               alert(date.getTime()- parent.editAreaLoader.start_time);*/\r
+       };\r
+       \r
+       \r
+       \r
+       //called by the toggle_on\r
+       EditArea.prototype.update_size= function(){\r
+               var d=document,pd=parent.document,height,width,popup,maxLeft,maxTop;\r
+               \r
+               if( typeof editAreas != 'undefined' && editAreas[editArea.id] && editAreas[editArea.id]["displayed"]==true){\r
+                       if(editArea.fullscreen['isFull']){      \r
+                               pd.getElementById("frame_"+editArea.id).style.width             = pd.getElementsByTagName("html")[0].clientWidth + "px";\r
+                               pd.getElementById("frame_"+editArea.id).style.height    = pd.getElementsByTagName("html")[0].clientHeight + "px";\r
+                       }\r
+                       \r
+                       if(editArea.tab_browsing_area.style.display=='block' && ( !editArea.isIE || editArea.isIE >= 8 ) )\r
+                       {\r
+                               editArea.tab_browsing_area.style.height = "0px";\r
+                               editArea.tab_browsing_area.style.height = (editArea.result.offsetTop - editArea.tab_browsing_area.offsetTop -1)+"px";\r
+                       }\r
+                       \r
+                       height  = d.body.offsetHeight - editArea.get_all_toolbar_height() - 4;\r
+                       editArea.result.style.height    = height +"px";\r
+                       \r
+                       width   = d.body.offsetWidth -2;\r
+                       editArea.result.style.width             = width+"px";\r
+                       //alert("result h: "+ height+" w: "+width+"\ntoolbar h: "+this.get_all_toolbar_height()+"\nbody_h: "+document.body.offsetHeight);\r
+                       \r
+                       // check that the popups don't get out of the screen\r
+                       for( i=0; i < editArea.inlinePopup.length; i++ )\r
+                       {\r
+                               popup   = _$(editArea.inlinePopup[i]["popup_id"]);\r
+                               maxLeft = d.body.offsetWidth - popup.offsetWidth;\r
+                               maxTop  = d.body.offsetHeight - popup.offsetHeight;\r
+                               if( popup.offsetTop > maxTop )\r
+                                       popup.style.top         = maxTop+"px";\r
+                               if( popup.offsetLeft > maxLeft )\r
+                                       popup.style.left        = maxLeft+"px";\r
+                       }\r
+                       \r
+                       editArea.manage_size( true );\r
+                       editArea.fixLinesHeight( editArea.textarea.value, 0,-1);\r
+               }               \r
+       };\r
+       \r
+       \r
+       EditArea.prototype.manage_size= function(onlyOneTime){\r
+               if(!editAreas[this.id])\r
+                       return false;\r
+                       \r
+               if(editAreas[this.id]["displayed"]==true && this.textareaFocused)\r
+               {\r
+                       var area_height,resized= false;\r
+                       \r
+                       //1) Manage display width\r
+                       //1.1) Calc the new width to use for display\r
+                       if( !this.settings['word_wrap'] )\r
+                       {\r
+                               var area_width= this.textarea.scrollWidth;\r
+                               area_height= this.textarea.scrollHeight;\r
+                               // bug on old opera versions\r
+                               if(this.isOpera && this.isOpera < 9.6 ){\r
+                                       area_width=10000;                                                               \r
+                               }\r
+                               //1.2) the width is not the same, we must resize elements\r
+                               if(this.textarea.previous_scrollWidth!=area_width)\r
+                               {       \r
+                                       this.container.style.width= area_width+"px";\r
+                                       this.textarea.style.width= area_width+"px";\r
+                                       this.content_highlight.style.width= area_width+"px";    \r
+                                       this.textarea.previous_scrollWidth=area_width;\r
+                                       resized=true;\r
+                               }\r
+                       }\r
+                       // manage wrap width\r
+                       if( this.settings['word_wrap'] )\r
+                       {\r
+                               newW=this.textarea.offsetWidth;\r
+                               if( this.isFirefox || this.isIE )\r
+                                       newW-=2;\r
+                               if( this.isSafari )\r
+                                       newW-=6;\r
+                               this.content_highlight.style.width=this.selection_field_text.style.width=this.selection_field.style.width=this.test_font_size.style.width=newW+"px";\r
+                       }\r
+                       \r
+                       //2) Manage display height\r
+                       //2.1) Calc the new height to use for display\r
+                       if( this.isOpera || this.isFirefox || this.isSafari ) { \r
+                               area_height= this.getLinePosTop( this.last_selection["nb_line"] + 1 );\r
+                       } else {\r
+                               area_height = this.textarea.scrollHeight;\r
+                       }       \r
+                       //2.2) the width is not the same, we must resize elements \r
+                       if(this.textarea.previous_scrollHeight!=area_height)    \r
+                       {       \r
+                               this.container.style.height= (area_height+2)+"px";\r
+                               this.textarea.style.height= area_height+"px";\r
+                               this.content_highlight.style.height= area_height+"px";  \r
+                               this.textarea.previous_scrollHeight= area_height;\r
+                               resized=true;\r
+                       }\r
+               \r
+                       //3) if there is new lines, we add new line numbers in the line numeration area\r
+                       if(this.last_selection["nb_line"] >= this.line_number)\r
+                       {\r
+                               var newLines= '', destDiv=_$("line_number"), start=this.line_number, end=this.last_selection["nb_line"]+100;\r
+                               for( i = start+1; i < end; i++ )\r
+                               {\r
+                                       newLines+='<div id="line_'+ i +'">'+i+"</div>";\r
+                                       this.line_number++;\r
+                               }\r
+                               destDiv.innerHTML= destDiv.innerHTML + newLines;\r
+                               \r
+                               this.fixLinesHeight( this.textarea.value, start, -1 );\r
+                       }\r
+               \r
+                       //4) be sure the text is well displayed\r
+                       this.textarea.scrollTop="0px";\r
+                       this.textarea.scrollLeft="0px";\r
+                       if(resized==true){\r
+                               this.scroll_to_view();\r
+                       }\r
+               }\r
+               \r
+               if(!onlyOneTime)\r
+                       setTimeout("editArea.manage_size();", 100);\r
+       };\r
+       \r
+       EditArea.prototype.execCommand= function(cmd, param){\r
+               \r
+               for(var i in this.plugins){\r
+                       if(typeof(this.plugins[i].execCommand)=="function"){\r
+                               if(!this.plugins[i].execCommand(cmd, param))\r
+                                       return;\r
+                       }\r
+               }\r
+               switch(cmd){\r
+                       case "save":\r
+                               if(this.settings["save_callback"].length>0)\r
+                                       eval("parent."+this.settings["save_callback"]+"('"+ this.id +"', editArea.textarea.value);");\r
+                               break;\r
+                       case "load":\r
+                               if(this.settings["load_callback"].length>0)\r
+                                       eval("parent."+this.settings["load_callback"]+"('"+ this.id +"');");\r
+                               break;\r
+                       case "onchange":\r
+                               if(this.settings["change_callback"].length>0)\r
+                                       eval("parent."+this.settings["change_callback"]+"('"+ this.id +"');");\r
+                               break;          \r
+                       case "EA_load":\r
+                               if(this.settings["EA_load_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_load_callback"]+"('"+ this.id +"');");\r
+                               break;\r
+                       case "EA_unload":\r
+                               if(this.settings["EA_unload_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_unload_callback"]+"('"+ this.id +"');");\r
+                               break;\r
+                       case "toggle_on":\r
+                               if(this.settings["EA_toggle_on_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_toggle_on_callback"]+"('"+ this.id +"');");\r
+                               break;\r
+                       case "toggle_off":\r
+                               if(this.settings["EA_toggle_off_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_toggle_off_callback"]+"('"+ this.id +"');");\r
+                               break;\r
+                       case "re_sync":\r
+                               if(!this.do_highlight)\r
+                                       break;\r
+                       case "file_switch_on":\r
+                               if(this.settings["EA_file_switch_on_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_file_switch_on_callback"]+"(param);");\r
+                               break;\r
+                       case "file_switch_off":\r
+                               if(this.settings["EA_file_switch_off_callback"].length>0)\r
+                                       eval("parent."+this.settings["EA_file_switch_off_callback"]+"(param);");\r
+                               break;\r
+                       case "file_close":\r
+                               if(this.settings["EA_file_close_callback"].length>0)\r
+                                       return eval("parent."+this.settings["EA_file_close_callback"]+"(param);");\r
+                               break;\r
+                       \r
+                       default:\r
+                               if(typeof(eval("editArea."+cmd))=="function")\r
+                               {\r
+                                       if(this.settings["debug"])\r
+                                               eval("editArea."+ cmd +"(param);");\r
+                                       else\r
+                                               try{eval("editArea."+ cmd +"(param);");}catch(e){};\r
+                               }\r
+               }\r
+       };\r
+       \r
+       EditArea.prototype.get_translation= function(word, mode){\r
+               if(mode=="template")\r
+                       return parent.editAreaLoader.translate(word, this.settings["language"], mode);\r
+               else\r
+                       return parent.editAreaLoader.get_word_translation(word, this.settings["language"]);\r
+       };\r
+       \r
+       EditArea.prototype.add_plugin= function(plug_name, plug_obj){\r
+               for(var i=0; i<this.settings["plugins"].length; i++){\r
+                       if(this.settings["plugins"][i]==plug_name){\r
+                               this.plugins[plug_name]=plug_obj;\r
+                               plug_obj.baseURL=parent.editAreaLoader.baseURL + "plugins/" + plug_name + "/";\r
+                               if( typeof(plug_obj.init)=="function" )\r
+                                       plug_obj.init();\r
+                       }\r
+               }\r
+       };\r
+       \r
+       EditArea.prototype.load_css= function(url){\r
+               try{\r
+                       link = document.createElement("link");\r
+                       link.type = "text/css";\r
+                       link.rel= "stylesheet";\r
+                       link.media="all";\r
+                       link.href = url;\r
+                       head = document.getElementsByTagName("head");\r
+                       head[0].appendChild(link);\r
+               }catch(e){\r
+                       document.write("<link href='"+ url +"' rel='stylesheet' type='text/css' />");\r
+               }\r
+       };\r
+       \r
+       EditArea.prototype.load_script= function(url){\r
+               try{\r
+                       script = document.createElement("script");\r
+                       script.type = "text/javascript";\r
+                       script.src  = url;\r
+                       script.charset= "UTF-8";\r
+                       head = document.getElementsByTagName("head");\r
+                       head[0].appendChild(script);\r
+               }catch(e){\r
+                       document.write("<script type='text/javascript' src='" + url + "' charset=\"UTF-8\"><"+"/script>");\r
+               }\r
+       };\r
+       \r
+       // add plugin translation to language translation array\r
+       EditArea.prototype.add_lang= function(language, values){\r
+               if(!parent.editAreaLoader.lang[language])\r
+                       parent.editAreaLoader.lang[language]={};\r
+               for(var i in values)\r
+                       parent.editAreaLoader.lang[language][i]= values[i];\r
+       };\r
+       \r
+       // short cut for document.getElementById()\r
+       function _$(id){return document.getElementById( id );};\r
+\r
+       var editArea = new EditArea();  \r
+       parent.editAreaLoader.add_event(window, "load", init);\r
+       \r
+       function init(){                \r
+               setTimeout("editArea.init();  ", 10);\r
+       };\r