Ticket #21: wym.js

File wym.js, 23.2 kB (added by Moxide, 3 years ago)
Line 
1/*
2 * WYMeditor : what you see is What You Mean web-based editor
3 * Copyright (C) 2006 H.O.net - http://www.honet.be/
4 * Dual licensed under the MIT (MIT-license.txt)
5 * and GPL (GPL-license.txt) licenses.
6 *
7 * For further information visit:
8 *              http://www.wymeditor.org/
9 *
10 * File Name:
11 *              wym.js
12 *              Main javascript functions.
13 *              See the documentation for more info.
14 *
15 * File Authors:
16 *              Jean-François Hovinne (jf.hovinne@wymeditor.org)
17*/
18
19//global vars
20var selectedElement=null;
21var bCleanPaste=true;
22
23//called at body.onload
24function init()
25{
26        getHTML(); //populate the textarea
27        setImgEvent(); //add mouse events on images
28        displayPasteCleanup(true); //paste cleanup is on or off
29       
30        if(moz)
31        {
32                //get the content from parent
33                ed=iframe().contentWindow.parent.document.getElementById('editor');
34                if(ed!=null)iframe().contentDocument.body.innerHTML=ed.innerHTML;
35
36                getHTML();
37               
38                //editable
39                iframe().contentDocument.designMode="on";
40               
41                //handles (un)necessary nodes
42                handleNodes(editor());
43               
44                //add key and mouse events listeners
45                iframe().contentDocument.addEventListener('keydown',iframe_keydown_handler,false);
46                iframe().contentDocument.addEventListener('keyup',iframe_keyup_handler,false);
47                iframe().contentDocument.addEventListener('mouseup',iframe_mouseup_handler,false);
48                iframe().contentDocument.addEventListener('blur',function(evt){bCleanPaste=false;displayPasteCleanup(true);},false);
49               
50                //disable inline styles
51                execCom("styleWithCSS",false);
52        }
53}
54
55//these functions return base objects
56function editor()
57{
58        if(ie) return(document.getElementById('editor'));
59        else if(moz) return(iframe().contentDocument.body);
60}
61function txthtml()
62{
63        return(document.getElementById('txthtml'));
64}
65function container()
66{
67        return(getSelectedContainer());
68}
69function classespanel()
70{
71        return(document.getElementById('m_class'));
72}
73//returns selected image
74function selected()
75{
76  return(selectedElement);
77}
78function selectedId()
79{
80        if(selectedElement!=null)return(selectedElement.id);
81        else return(null);
82}
83
84function iframe()
85{
86        return(document.getElementById('iframe_editor'));
87}
88
89//we 'release' the image selection
90function release()
91{
92        selectedElement=null;
93}
94
95//used to get the cursor position
96function saveCaret()
97{
98    editor().caretPos=document.selection.createRange();
99}
100
101//little hack to get the current cursor position
102function getCaretPos()
103{
104    var bookmark="~caret~pos~";
105    var orig=editor().innerHTML;
106    var caretPos=editor().caretPos;
107    if(caretPos!=null)
108    {
109        caretPos.text=bookmark;
110        var i=editor().innerHTML.search(bookmark);
111        editor().innerHTML=orig;
112
113        var hid=document.getElementById('caretpos');
114        hid.value=i;
115    }
116    return(i);
117}
118
119//insert HTML at cursor pos
120function insertAtCursor(sHtml)
121{
122        if(ie)
123        {
124                var pos=getCaretPos();
125                if(pos>-1)
126                {
127                        var html=editor().innerHTML;
128                        editor().innerHTML=insertAt(html,sHtml,pos);
129                }
130        }
131        else if(moz)
132        {
133                execCom("inserthtml",sHtml);
134        }
135}
136
137//insert an HTML element *after* the current one
138function insertAfter(elem,currentElem)
139{
140        if(currentElem.nextSibling!=null)editor().insertBefore(elem,currentElem.nextSibling);
141        else editor().appendChild(elem);
142}
143
144//put editor value in txthtml
145function getHTML()
146{
147        if(ie)
148        {
149                txthtml().innerText="";
150                txthtml().innerText=editor().innerHTML;
151        }
152        else if(moz)
153        {
154                txthtml().value="";
155                txthtml().value=editor().innerHTML;
156        }
157}
158
159//put cleaned editor value in txthtml
160function getCleanHTML()
161{
162        if(ie)
163        {
164                txthtml().innerText="";
165                txthtml().innerText=cleanupHTML_ie(editor().innerHTML);
166        }
167        else if(moz)
168        {
169                txthtml().value="";
170               
171                //various cleanups, see util.js
172                handleNodes(editor());
173                txthtml().value=cleanupHTML_moz(editor().innerHTML);
174        }
175}
176
177//put txthtml value in editor
178function setHTML()
179{
180        if(ie) editor().innerHTML=txthtml().innerText;
181        else if(moz)editor().innerHTML=txthtml().value;
182}
183
184//set txthtml (in)visible
185function htmlVisible()
186{
187        if(txthtml().style.display!="none")txthtml().style.display="none";
188        else txthtml().style.display="inline";
189}
190
191//buttons events
192function execCom(cmd,opt)
193{
194        if(moz)
195        {
196                //well, moz sets <b><strong>#text</strong></b> or <i><em>#text</em></i>
197                //in this case, we don't use execCommand: we replace the <strong> or <em> nodes by a textNode
198
199                //nested lists (indent and outdent): moz creates blockquotes around lists, so we (try to) prevent this
200                switch(cmd.toLowerCase())
201                {
202                        case "bold":
203                                container=getSelectedContainer();
204                                if(container.tagName.toLowerCase()=="strong")
205                                {
206                                        ntext=iframe().contentDocument.createTextNode(container.innerHTML);
207                                        container.parentNode.replaceChild(ntext,container);
208                                }
209                                else iframe().contentDocument.execCommand(cmd,'',opt);
210                                break;
211                        case "italic":
212                                container=getSelectedContainer();
213                                if(container.tagName.toLowerCase()=="em")
214                                {
215                                        ntext=iframe().contentDocument.createTextNode(container.innerHTML);
216                                        container.parentNode.replaceChild(ntext,container);
217                                }
218                                else iframe().contentDocument.execCommand(cmd,'',opt);
219                                break;
220                        case "indent": case "outdent":
221                                var focusNode=getSelectedNode("focus");
222                                var anchorNode=getSelectedNode("anchor");
223                               
224                                focusNode=getFirstBlockParent(focusNode);
225                                anchorNode=getFirstBlockParent(anchorNode);
226
227                                if(focusNode!=null && focusNode==anchorNode && focusNode.tagName.toLowerCase()=="li")
228                                {
229                                        var ancestor=focusNode.parentNode.parentNode;
230                                        if(focusNode.parentNode.childNodes.length>1
231                                                || ancestor.tagName.toLowerCase()=="ol"
232                                                || ancestor.tagName.toLowerCase()=="ul")
233                                       
234                                                iframe().contentDocument.execCommand(cmd,'',opt);
235                                }
236                                break;
237                        default:
238                                iframe().contentDocument.execCommand(cmd,'',opt);
239                                break;
240                }
241        }
242        else if(ie)
243        {
244                switch(cmd.toLowerCase())
245                {
246                        case "indent": case "outdent":
247                                container=getSelectedContainer();
248                                if(container.tagName.toLowerCase()=="li") document.execCommand(cmd);
249                                break;
250                        default:
251                                document.execCommand(cmd);
252                                break;
253                }
254        }
255}
256
257//main function to get the current selected container
258function getSelectedContainer()
259{
260        if(selectedElement==null)
261        {
262                if(ie)
263                {
264                        var caretPos=editor().caretPos;
265                        if(caretPos!=null)
266                        {
267                                if(caretPos.parentElement!=undefined)return(caretPos.parentElement());
268                        }
269                }
270                else if(moz)
271                {
272                        var sel=iframe().contentWindow.getSelection();
273                        var node=sel.focusNode;
274                        if(node.nodeName=="#text")return(node.parentNode);
275                        else return(node);
276                }
277        }
278        else return(selectedElement);
279}
280
281//returns the selected anchor or focus node
282function getSelectedNode(sType)
283{
284        if(moz)
285        {
286                var sel=iframe().contentWindow.getSelection();
287                if(sType=="focus") node=sel.focusNode;
288                else if(sType=="anchor") node=sel.anchorNode;
289                if(node.nodeName=="#text")return(node.parentNode);
290                else return(node);
291        }
292}
293//get the top container (the first editor's child which contains the element)
294function getMainContainer(elem)
295{
296        if(ie)
297        {
298                nodes=editor().children;
299                for(var x=0;x<nodes.length;x++)
300                {
301                        if(nodes.item(x).contains(elem)) //not supported by Mozilla
302                        {
303                                container=nodes.item(x);
304                                break;
305                        }
306                }
307                return(container);
308        }
309        else if(moz)
310        {
311                nodes=editor().childNodes;
312                for(var y=0;y<nodes.length;y++)
313                {
314                        if(nodeContains(nodes.item(y),elem) || nodes.item(y)==elem)
315                        {
316                                container=nodes.item(y);
317                                break;
318                        }
319                }
320                return(container);
321        }
322}
323
324//Moz only: Mozilla doesn't support node.contains()
325function nodeContains(node,elem)
326{
327        parent=elem.parentNode;
328        if(parent.tagName.toLowerCase()=="body" || parent.tagName.toLowerCase()=="html")return(false);
329        else if(parent==node)return(true);
330        else return(nodeContains(node,parent));
331}
332
333//recursive function which returns the first block-level element's parent
334function getFirstBlockParent(elem)
335{
336        if(elem!=null && elem.id!="editor")
337        {
338                var tagName=elem.tagName.toLowerCase();
339                switch(tagName)
340                {
341                        case "address":
342                        case "blockquote":
343                        case "div":
344                        case "dl":
345                        case "fieldset":
346                        case "form":
347                        case "h1": case "h2": case "h3": case "h4": case "h5": case "h6":
348                        case "hr":
349                        case "noscript":
350                        case "ol":
351                        case "p":
352                        case "pre":
353                        case "table":
354                        case "ul":
355                        case "dd":
356                        case "dt":
357                        case "li":
358                        case "tbody":
359                        case "td":
360                        case "tfoot":
361                        case "th":
362                        case "thead":
363                        case "tr":
364                                return(elem);
365                                break;
366                        default:
367                                elem=elem.parentNode;
368                                return(getFirstBlockParent(elem));
369                                break;
370                }
371        }
372        else return(null);     
373}
374
375//recursive function which returns the element's parent having a particular type
376
377//we get the element's parent
378//if its type (tagname) isn't sContainerType, we get its parent
379//and so on ...
380function getContainerOfType(elem,sContainerType)
381{
382        if(elem!=null && elem.id!="editor")
383        {
384                if(elem.tagName!=sContainerType)
385                {
386                        elem=elem.parentNode;
387                        return(getContainerOfType(elem,sContainerType));
388                }
389                else return(elem);
390        }
391        else return(null);
392}
393
394//the same as getContainerOfType, but we use an array of possible types
395function getContainerOfTypeArray(elem,aContainerTypes)
396{
397        var bFound=false;
398        if(elem!=null && elem.id!="editor")
399        {
400                for(i=0;i<aContainerTypes.length;i++)
401                {
402                        if(elem.tagName==aContainerTypes[i])
403                        {
404                                bFound=true;
405                                break;
406                        }
407                }
408                if(!bFound)
409                {
410                        elem=elem.parentNode;
411                        return(getContainerOfTypeArray(elem,aContainerTypes));
412                }
413                else return(elem);
414        }
415        else return(null);
416}
417
418//check if we can apply the class to the container
419// '*' = all containers allowed
420function getAllowedContainer(container,aAllowedContainers)
421{
422        if(container!=null && container.id!="editor")
423        {
424                var bAllowed=false;
425                for(i=0;i<aAllowedContainers.length;i++)
426                {
427                        if(aAllowedContainers[i]==container.tagName || aAllowedContainers[i]=="*")
428                        {
429                                bAllowed=true;
430                                break;
431                        }
432                }
433                if(bAllowed)return(container);
434                else return(getAllowedContainer(container.parentNode,aAllowedContainers));
435        }
436        else return(null);
437}
438
439//switch the container to a new one with another type
440function setContainer(sType)
441{
442        container=getSelectedContainer();
443        if(container!=null)
444        {
445                switch(container.tagName)
446                {
447                        case "P":
448                        case "H1":
449                        case "H2":
450                        case "H3":
451                        case "H4":
452                        case "H5":
453                        case "H6":
454                        case "PRE":
455                        case "BLOCKQUOTE":
456                                break;
457                        default:
458                                var aTypes=new Array("P","H1","H2","H3","H4","H5","H6","PRE","BLOCKQUOTE");
459                                container=getContainerOfTypeArray(container,aTypes);
460                                break;
461                }
462       
463                if(container!=null)
464                {
465                        var newNode=null;
466
467                        //blockquotes must contain a block level element
468                        if(sType.toLowerCase()=="blockquote")
469                        {
470                                var blockquote=getContainerOfType(container,"BLOCKQUOTE");
471                                if(blockquote==null)
472                                {
473                                        newNode=document.createElement(sType);
474                                        container.parentNode.insertBefore(newNode,container);
475                                        newNode.appendChild(container);
476          setFocusToNode(newNode.firstChild);
477                                }
478                                else
479                                {
480                                        var nodes=blockquote.childNodes;
481                                        var lgt=nodes.length;
482          var firstNode = nodes.item(0);
483          for(var x=0;x<lgt;x++)
484                                        {
485                                                blockquote.parentNode.insertBefore(nodes.item(0),blockquote);
486                                        }
487          blockquote.parentNode.removeChild(blockquote);
488          setFocusToNode(firstNode);
489                                }
490                        }
491                        else
492                        {
493                                newNode=document.createElement(sType);
494                                var html=container.innerHTML;
495                                if(ie)container.replaceNode(newNode);
496                                else if(moz)container.parentNode.replaceChild(newNode,container);
497                                newNode.innerHTML=html;
498        setFocusToNode(newNode);
499                        }
500                }
501        }
502}
503
504//converts a TD to a TH and vice-versa
505function switchCellType()
506{
507        container=getSelectedContainer();
508        if(container!=null)
509        {
510                switch(container.tagName)
511                {
512                        case "TD": case "TH":
513                                break;
514                        default:
515                                var aTypes=new Array("TD","TH");
516                                container=getContainerOfTypeArray(container,aTypes);
517                                break;
518                }
519       
520                if(container!=null)
521                {
522                        var sType=(container.tagName=="TD")? "TH": "TD";
523                        var html=container.innerHTML;
524                        var newNode=document.createElement(sType);
525                        if(ie)container.replaceNode(newNode);
526                        else if(moz)container.parentNode.replaceChild(newNode,container);
527                        newNode.innerHTML=html;
528      setFocusToNode(newNode);
529                }
530        }
531}
532
533//set the class to the container
534function setClass(sValue,sAllowedContainers,sConflictingClasses,sAllowedClasses)
535{
536        var bConflictFound=false;
537        var bAllowedFound=(sAllowedClasses=="" || sAllowedClasses==null);
538        var container=null;
539        var attrClass;
540        var sClasses="";
541       
542        if(sConflictingClasses==null)sConflictingClasses="";
543        if(sAllowedClasses==null)sAllowedClasses="";
544
545        //sAllowedContainers : string e.g. "P,DIV,SPAN"
546        // '*' = all containers allowed
547        var aCt=sAllowedContainers.split(",");
548
549        //find the container (from cursor pos or selected element)
550        container=getSelectedContainer();
551       
552        if(ie) sClasses=container.className;
553        if(moz) attrClass=container.attributes.getNamedItem("class");
554        if(attrClass!=null) sClasses=attrClass.value;
555
556        //find allowed container
557        //if current container isn't allowed, take the parent, and so on ...
558        if(container!=null)container=getAllowedContainer(container,aCt);
559       
560        if(container!=null)
561        {
562                //check if there isn't a conflict with existent classes
563                var aClE=sClasses.split(" ");                                                   //array of classes already applied to the container
564                var aClC=sConflictingClasses.split(",");                                        //array of conflicting classes
565                var aClA=sAllowedClasses.split(",");                                            //array of compatible classes
566               
567                if(sClasses=="")bAllowedFound=true;                                             //if no classes already applied, every class is allowed
568
569                for(var i=0;i<aClE.length;i++)
570                {
571                        for(var j=0;j<aClC.length;j++)
572                        {
573                                if((aClC[j]==aClE[i] && aClC[j]!="") || (aClC[j]=="*" && aClE[i]!="" && aClE[i]!=sValue))
574                                {
575                                        bConflictFound=true;
576                                        break;
577                                }
578                        }
579                        if(bConflictFound)break;
580                       
581                        if(!bAllowedFound)
582                        {
583                                for(var k=0;k<aClA.length;k++)
584                                {
585                                        if((aClA[k]==aClE[i] && aClA[k]!="") || (aClA[k]=="*" && aClE[i]!="") || (aClE[i]==sValue))
586                                        {
587                                                bAllowedFound=true;
588                                                break; 
589                                        }
590                                }
591                                if(bAllowedFound)break;
592                        }
593                }
594
595                //apply or remove it if no conflict
596                if(!bConflictFound && bAllowedFound)
597                {
598                        if(sClasses==sValue || sClasses.indexOf(sValue+" ")>-1 || sClasses.indexOf(" "+sValue)>-1)
599                        {
600                                sClasses=sClasses.replace(sValue,"");
601                                sClasses=sClasses.replace("  "," ");
602                                sValue=sClasses;
603                        }
604                        else
605                        {
606                                if(sClasses=="")sClasses=sValue;
607                                else sValue=sClasses+" "+sValue;
608                        }
609
610                        sValue=sTrim(sValue);
611                        if(sValue=="")
612                        {
613                                if(ie)container.removeAttribute("className");
614                                else if(moz)container.attributes.removeNamedItem("class");
615                        }
616                        else
617                        {
618                                if(ie)container.setAttribute("className",sValue,0);
619                                else if(moz)container.setAttribute("class",sValue);
620                        }
621                        displayClasses();
622                }
623    iframe().contentWindow.focus();
624        }
625}
626
627//highlight the container's classes
628function displayClasses()
629{
630        var container=getSelectedContainer();
631        var nodes=document.getElementById('m_class').getElementsByTagName("A"); //get the buttons from the panel
632        for(var i=0;i<nodes.length;i++)
633        {
634                //clearing
635                if(ie)nodes.item(i).setAttribute("className","",0);
636                else if(moz)
637                {
638                        if(nodes.item(i).attributes.getNamedItem("class")!=null)
639                                nodes.item(i).attributes.removeNamedItem("class");
640                }
641        }
642       
643        if(container==null)container=selected(); //an image ?
644        if(container!=null)
645        {
646                var sClasses="";
647                var attrClass=container.attributes.getNamedItem("class");
648                if(attrClass!=null)sClasses=attrClass.value;
649               
650                var aClE=sClasses.split(" "); //get the classes names
651                for(i=0;i<aClE.length;i++)
652                {
653                        if(aClE[i]!="")
654                        {
655                                for(var j=0;j<nodes.length;j++)
656                                {
657                                        if(nodes.item(j).name==aClE[i])
658                                        {
659                                                if(ie)nodes.item(j).setAttribute("className","active",0); //set the 'active' class
660                                                else if(moz)nodes.item(j).setAttribute("class","active",0);
661                                                break;
662                                        }
663                                }
664                        }
665                }
666        }
667}
668
669//remove the class attribute
670function removeClassAttr()
671{
672        var container=getSelectedContainer();
673        if(container!=null)
674        {
675                if(ie) container.removeAttribute("className",false);
676                else if(moz) container.removeAttribute("class",false);
677        }
678}
679
680// !! remove all attributes
681function removeAttrs()
682{
683var container=getSelectedContainer();
684        if(container!=null)
685        {
686                container.clearAttributes();
687        }
688}
689
690//open a dialog
691function openDialog(sDialogType)
692{
693        var sUrl=dialogs["base"]+dialogs[sDialogType];
694        var dialog=window.open(sUrl,"dialog",dialogs_features);
695}
696
697//open the preview
698function openPreview()
699{
700        var dialog=window.open(preview_url,"preview",preview_features);
701}
702
703//set a unique id to images (when needed)
704function setImgIds()
705{
706        var img=editor().getElementsByTagName("img");
707        for(var i=0;i<img.length;i++)
708        {
709                if(img.id==undefined || img.id==null || img.id=="")img.id=getUniqueId();
710        }
711}
712
713//handles click events on images
714//so we can modify images
715function setImgEvent()
716{
717        var img=editor().getElementsByTagName("img");
718        for(var i=0;i<img.length;i++)
719        {
720                if(ie)
721                {
722                        img[i].onmousedown=function()
723                        {
724                                img_mousedown_handler(this);
725                        }
726                        img[i].ondblclick=function()
727                        {
728                                img_dblclick_handler(this);
729                        }
730                }
731                else if(moz)
732                {
733                        img.item(i).addEventListener("mousedown",img_mousedown_handler_moz,false);
734                        img.item(i).addEventListener("dblclick",img_dblclick_handler_moz,false);
735                }
736        }
737}
738
739function img_mousedown_handler(img)
740{
741        if(img.id==undefined || img.id==null || img.id=="")img.id=getUniqueId();
742        selectedElement=img;
743        displayClasses();
744}
745
746function img_mousedown_handler_moz()
747{
748        if(this.id==undefined || this.id==null || this.id=="")this.id=getUniqueId();
749        selectedElement=this;
750        displayClasses();
751}
752
753function img_dblclick_handler(img)
754{
755        if(img.id==undefined || img.id==null || img.id=="")img.id=getUniqueId();
756        selectedElement=img;
757        openDialog("image");
758}
759
760function img_dblclick_handler_moz()
761{
762        if(this.id==undefined || this.id==null || this.id=="")this.id=getUniqueId();
763        selectedElement=this;
764        openDialog("image");
765}
766
767//IE specific - Gecko has nested buttons for row and cells creation/removing
768//insert a row or column
769//sObjectType values : "ROW","COL"
770//bBefore : boolean (true : inserts before selected, false : inserts after selected object)
771function table_insertObject(sObjectType,bBefore)
772{
773        var pos=0;
774        if(!bBefore)pos=1;
775
776        var container=getSelectedContainer();
777        if(container!=null)
778        {
779                //find the table element
780                var table=getContainerOfType(container,"TABLE");
781                if(table!=null)
782                {
783                        //find the selected td / tr
784                        var aTypes=new Array("TD","TH");
785                        var td=getContainerOfTypeArray(container,aTypes);
786                        var tr=getContainerOfType(container,"TR");
787
788                        if(tr!=null && td!=null)
789                        {
790                                var tdindex=td.cellIndex;
791                                switch(sObjectType)
792                                {
793                                        //insert a new row and create cols in it
794                                        case "ROW":
795                                                var newRow=table.insertRow(tr.rowIndex+pos);
796                                               
797                                                for(x=0;x<tr.cells.length;x++)
798                                                {
799                                                        newRow.insertCell();
800                                                }
801                                                break;
802                                        //insert a new column in each row
803                                        case "COL":
804                                                for(x=0;x<table.rows.length;x++)
805                                                {
806                                                        table.rows[x].insertCell(tdindex+pos);
807                                                }
808                                                break;
809                                        default:
810                                                break;
811                                }
812                        }
813                }
814        }
815}
816
817//delete a row or column
818//sObjectType values : "ROW","COL"
819function table_deleteObject(sObjectType)
820{
821        var container=getSelectedContainer();
822        if(container!=null)
823        {
824                var table=getContainerOfType(container,"TABLE");
825                if(table!=null)
826                {
827                        var aTypes=new Array("TD","TH");
828                        var td=getContainerOfTypeArray(container,aTypes);
829                        var tr=getContainerOfType(container,"TR");
830
831                        if(tr!=null && td!=null)
832                        {
833                                var tdindex=td.cellIndex;
834                                switch(sObjectType)
835                                {
836                                        //delete the row
837                                        case "ROW":
838                                                if(table.rows.length>1)table.deleteRow(tr.rowIndex);
839                                                break;
840                                        //delete each coll at tdindex
841                                        case "COL":
842                                                if(tr.cells.length>1)
843                                                {
844                                                        for(x=0;x<table.rows.length;x++)
845                                                        {
846                                                                table.rows[x].deleteCell(tdindex);
847                                                        }
848                                                }
849                                                break;
850                                        default:
851                                                break;
852                                }
853                        }
854                }
855        }
856}
857
858//display a visual feedback while copying-cutting-pasting
859function displayPasteCleanup(bln)
860{
861        var elem_on=document.getElementById('m_paste_cleanup_flag_on');
862        var elem_off=document.getElementById('m_paste_cleanup_flag_off');
863       
864        if(bln)
865        {
866                elem_on.style.display="inline";
867                elem_off.style.display="none";
868        }
869        else
870        {
871                elem_on.style.display="none";
872                elem_off.style.display="inline";
873        }
874}
875
876//paste data from any application
877//onbeforepaste and onpaste events
878function pasteData(sData)
879{
880        if(!bCleanPaste || sData!=null)
881        {
882                //cancel the default behavior
883                if(ie) event.returnValue=false;
884
885                var parent;
886                var newNode;
887                var sTmp;
888                var tmpContainer=null;
889                var sPasted=sData;
890               
891                var container=getSelectedContainer();
892               
893                //get the data as raw text (no markup)
894                if(ie) sPasted=window.clipboardData.getData("Text");
895               
896                //if we are in a P,heading,..., we get the parentNode
897                //if we are in a TD, we add a temporary P, to keep the following code simple
898                //(it will be eventually removed)
899                switch(container.tagName)
900                {
901                        case "BODY":
902                                parent=container;
903                                break;
904                        case "P":
905                        case "H1":
906                        case "H2":
907                        case "H3":
908                        case "H4":
909                        case "H5":
910                        case "H6":
911                        case "PRE":
912                        case "BLOCKQUOTE":
913                                parent=container.parentNode;
914                                break;
915                        case "TD":
916                                parent=container;
917                                tmpContainer=document.createElement("P");
918                                container.appendChild(tmpContainer);
919                                container=tmpContainer;
920                                break;
921                        default:
922                                parent=getMainContainer(container).parentNode;
923                                break;
924                }
925               
926                //we have the parent node
927                //let's add the data
928                if(parent!=null)
929                {
930                        //split the data, using double newlines as the separator
931                        var aP;
932                        if(ie) aP=sPasted.split("\r\n\r\n");
933                        else if(moz) aP=sPasted.split("\n\n");
934       
935                        //add a P for each item
936                        for(x=0;x<aP.length;x++)
937                        {
938                                newNode=document.createElement("P");
939                               
940                                if(container.nextSibling!=null)parent.insertBefore(newNode,container.nextSibling);
941                                else parent.appendChild(newNode);
942       
943                                sTmp=aP[x];
944                               
945                                //simple newlines are replaced by a break
946                                //maybe we need a trim("\r\n")
947                                sTmp=sTmp.replace(/\r\n/g,"<br />");
948                                newNode.innerHTML=sTmp;
949                               
950                                //switch the container to add the next P at the good position
951                                container=newNode;
952                        }
953                       
954                        //remove the temp container (if in a TD)
955                        if(tmpContainer!=null)tmpContainer.removeNode();
956
957                        //remove remaining BR (moz only)
958                        if(moz && editor().childNodes[1]!=null && editor().childNodes[1].tagName=="BR")
959                                editor().removeChild(editor().childNodes[1]);
960                       
961                        getCleanHTML();
962                }
963        }
964}
965
966
967//GECKO
968
969//keydown & keyup handlers, mainly used for cleanups
970
971function iframe_keydown_handler(evt)
972{
973        if(evt.keyCode==86 && evt.ctrlKey) //CTRL+V -> PASTE
974        {       
975                //prevent CTRL+V
976                if(moz_prevent_copy) evt.preventDefault();
977        }
978}
979
980function iframe_keyup_handler(evt)
981{       
982        if(evt.keyCode==13 && !evt.shiftKey) //RETURN key
983        {
984                //cleanup <br><br> between paragraphs
985               
986                nodes=editor().childNodes;
987
988                for(var x=0;x<nodes.length;x++)
989                {
990                        if(nodes.item(x).nodeName.toLowerCase()=="br") editor().removeChild(nodes.item(x));
991                }
992        }
993       
994        else if(evt.keyCode!=8 && evt.keyCode!=46 && evt.keyCode!=17 && !evt.ctrlKey) //NOT BACKSPACE, NOT DELETE, NOT CTRL
995        {
996                //text nodes replaced by P
997                container=getSelectedContainer();
998                name=container.tagName.toLowerCase();
999
1000                //fix forbidden main containers
1001                if(
1002                        name=="strong" ||
1003                        name=="b" ||
1004                        name=="em" ||
1005                        name=="i" ||
1006                        name=="sub" ||
1007                        name=="sup" ||
1008                        name=="a"
1009
1010                ) name=container.parentNode.tagName.toLowerCase();
1011
1012                if(name=="body") execCom("formatblock","P");
1013        }
1014       
1015        displayClasses();
1016}
1017
1018function iframe_mouseup_handler(evt)
1019{
1020        if(evt.target.nodeName.toLowerCase()!="img")
1021        {
1022                setImgEvent();
1023                release();
1024        }
1025        displayClasses();
1026}
1027
1028function setFocusToNode(node) {
1029  if (moz) {
1030    r=document.createRange();
1031    r.selectNode(node);
1032    sel=iframe().contentWindow.getSelection();
1033    sel.addRange(r);
1034    sel.collapse(node,0);
1035    iframe().contentWindow.focus();
1036  }
1037}