Podświetlanie składni w edytorze XML dzięki editArea. Closes #17. Niestety dla tekstó...
[redakcja.git] / project / static / js / elements_functions.js
diff --git a/project/static/js/elements_functions.js b/project/static/js/elements_functions.js
new file mode 100755 (executable)
index 0000000..3426fd1
--- /dev/null
@@ -0,0 +1,333 @@
+/****\r
+ * This page contains some general usefull functions for javascript\r
+ *\r
+ ****/  \r
+       \r
+       \r
+       // need to redefine this functiondue to IE problem\r
+       function getAttribute( elm, aName ) {\r
+               var aValue,taName,i;\r
+               try{\r
+                       aValue = elm.getAttribute( aName );\r
+               }catch(exept){}\r
+               \r
+               if( ! aValue ){\r
+                       for( i = 0; i < elm.attributes.length; i ++ ) {\r
+                               taName = elm.attributes[i] .name.toLowerCase();\r
+                               if( taName == aName ) {\r
+                                       aValue = elm.attributes[i] .value;\r
+                                       return aValue;\r
+                               }\r
+                       }\r
+               }\r
+               return aValue;\r
+       };\r
+       \r
+       // need to redefine this function due to IE problem\r
+       function setAttribute( elm, attr, val ) {\r
+               if(attr=="class"){\r
+                       elm.setAttribute("className", val);\r
+                       elm.setAttribute("class", val);\r
+               }else{\r
+                       elm.setAttribute(attr, val);\r
+               }\r
+       };\r
+       \r
+       /* return a child element\r
+               elem: element we are searching in\r
+               elem_type: type of the eleemnt we are searching (DIV, A, etc...)\r
+               elem_attribute: attribute of the searched element that must match\r
+               elem_attribute_match: value that elem_attribute must match\r
+               option: "all" if must return an array of all children, otherwise return the first match element\r
+               depth: depth of search (-1 or no set => unlimited)\r
+       */\r
+       function getChildren(elem, elem_type, elem_attribute, elem_attribute_match, option, depth)\r
+       {           \r
+               if(!option)\r
+                       var option="single";\r
+               if(!depth)\r
+                       var depth=-1;\r
+               if(elem){\r
+                       var children= elem.childNodes;\r
+                       var result=null;\r
+                       var results= [];\r
+                       for (var x=0;x<children.length;x++) {\r
+                               strTagName = new String(children[x].tagName);\r
+                               children_class="?";\r
+                               if(strTagName!= "undefined"){\r
+                                       child_attribute= getAttribute(children[x],elem_attribute);\r
+                                       if((strTagName.toLowerCase()==elem_type.toLowerCase() || elem_type=="") && (elem_attribute=="" || child_attribute==elem_attribute_match)){\r
+                                               if(option=="all"){\r
+                                                       results.push(children[x]);\r
+                                               }else{\r
+                                                       return children[x];\r
+                                               }\r
+                                       }\r
+                                       if(depth!=0){\r
+                                               result=getChildren(children[x], elem_type, elem_attribute, elem_attribute_match, option, depth-1);\r
+                                               if(option=="all"){\r
+                                                       if(result.length>0){\r
+                                                               results= results.concat(result);\r
+                                                       }\r
+                                               }else if(result!=null){                                                                          \r
+                                                       return result;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+                       if(option=="all")\r
+                          return results;\r
+               }\r
+               return null;\r
+       };       \r
+       \r
+       function isChildOf(elem, parent){\r
+               if(elem){\r
+                       if(elem==parent)\r
+                               return true;\r
+                       while(elem.parentNode != 'undefined'){\r
+                               return isChildOf(elem.parentNode, parent);\r
+                       }\r
+               }\r
+               return false;\r
+       };\r
+       \r
+       function getMouseX(e){\r
+\r
+               if(e!=null && typeof(e.pageX)!="undefined"){\r
+                       return e.pageX;\r
+               }else{\r
+                       return (e!=null?e.x:event.x)+ document.documentElement.scrollLeft;\r
+               }\r
+       };\r
+       \r
+       function getMouseY(e){\r
+               if(e!=null && typeof(e.pageY)!="undefined"){\r
+                       return e.pageY;\r
+               }else{\r
+                       return (e!=null?e.y:event.y)+ document.documentElement.scrollTop;\r
+               }\r
+       };\r
+       \r
+       function calculeOffsetLeft(r){\r
+               return calculeOffset(r,"offsetLeft")\r
+       };\r
+       \r
+       function calculeOffsetTop(r){\r
+               return calculeOffset(r,"offsetTop")\r
+       };\r
+       \r
+       function calculeOffset(element,attr){\r
+               var offset=0;\r
+               while(element){\r
+                       offset+=element[attr];\r
+                       element=element.offsetParent\r
+               }\r
+               return offset;\r
+       };\r
+       \r
+       /** return the computed style\r
+        *      @param: elem: the reference to the element\r
+        *      @param: prop: the name of the css property       \r
+        */\r
+       function get_css_property(elem, prop)\r
+       {\r
+               if(document.defaultView)\r
+               {\r
+                       return document.defaultView.getComputedStyle(elem, null).getPropertyValue(prop);\r
+               }\r
+               else if(elem.currentStyle)\r
+               {\r
+                       var prop = prop.replace(/-\D/gi, function(sMatch)\r
+                       {\r
+                               return sMatch.charAt(sMatch.length - 1).toUpperCase();\r
+                       });\r
+                       return elem.currentStyle[prop];\r
+               }\r
+               else return null;\r
+       }\r
+       \r
+/****\r
+ * Moving an element \r
+ ***/  \r
+       \r
+       var _mCE;       // currently moving element\r
+       \r
+       /* allow to move an element in a window\r
+               e: the event\r
+               id: the id of the element\r
+               frame: the frame of the element \r
+               ex of use:\r
+                       in html:        <img id='move_area_search_replace' onmousedown='return parent.start_move_element(event,"area_search_replace", parent.frames["this_frame_id"]);' .../>  \r
+               or\r
+                       in javascript: document.getElementById("my_div").onmousedown= start_move_element\r
+       */\r
+       function start_move_element(e, id, frame){\r
+               var elem_id=(e.target || e.srcElement).id;\r
+               if(id)\r
+                       elem_id=id;             \r
+               if(!frame)\r
+                       frame=window;\r
+               if(frame.event)\r
+                       e=frame.event;\r
+                       \r
+               _mCE= frame.document.getElementById(elem_id);\r
+               _mCE.frame=frame;\r
+               frame.document.onmousemove= move_element;\r
+               frame.document.onmouseup= end_move_element;\r
+               /*_mCE.onmousemove= move_element;\r
+               _mCE.onmouseup= end_move_element;*/\r
+               \r
+               //alert(_mCE.frame.document.body.offsetHeight);\r
+               \r
+               mouse_x= getMouseX(e);\r
+               mouse_y= getMouseY(e);\r
+               //window.status=frame+ " elem: "+elem_id+" elem: "+ _mCE + " mouse_x: "+mouse_x;\r
+               _mCE.start_pos_x = mouse_x - (_mCE.style.left.replace("px","") || calculeOffsetLeft(_mCE));\r
+               _mCE.start_pos_y = mouse_y - (_mCE.style.top.replace("px","") || calculeOffsetTop(_mCE));\r
+               return false;\r
+       };\r
+       \r
+       function end_move_element(e){\r
+               _mCE.frame.document.onmousemove= "";\r
+               _mCE.frame.document.onmouseup= "";              \r
+               _mCE=null;\r
+       };\r
+       \r
+       function move_element(e){\r
+               var newTop,newLeft,maxLeft;\r
+\r
+               if( _mCE.frame && _mCE.frame.event )\r
+                       e=_mCE.frame.event;\r
+               newTop  = getMouseY(e) - _mCE.start_pos_y;\r
+               newLeft = getMouseX(e) - _mCE.start_pos_x;\r
+               \r
+               maxLeft = _mCE.frame.document.body.offsetWidth- _mCE.offsetWidth;\r
+               max_top = _mCE.frame.document.body.offsetHeight- _mCE.offsetHeight;\r
+               newTop  = Math.min(Math.max(0, newTop), max_top);\r
+               newLeft = Math.min(Math.max(0, newLeft), maxLeft);\r
+               \r
+               _mCE.style.top  = newTop+"px";\r
+               _mCE.style.left = newLeft+"px";         \r
+               return false;\r
+       };\r
+       \r
+/***\r
+ * Managing a textarea (this part need the navigator infos from editAreaLoader\r
+ ***/ \r
+       \r
+       var nav= editAreaLoader.nav;\r
+       \r
+       // allow to get infos on the selection: array(start, end)\r
+       function getSelectionRange(textarea){\r
+               return {"start": textarea.selectionStart, "end": textarea.selectionEnd};\r
+       };\r
+       \r
+       // allow to set the selection\r
+       function setSelectionRange(t, start, end){\r
+               t.focus();\r
+               \r
+               start   = Math.max(0, Math.min(t.value.length, start));\r
+               end             = Math.max(start, Math.min(t.value.length, end));\r
+       \r
+               if( this.isOpera && this.isOpera < 9.6 ){       // Opera bug when moving selection start and selection end\r
+                       t.selectionEnd = 1;     \r
+                       t.selectionStart = 0;                   \r
+                       t.selectionEnd = 1;     \r
+                       t.selectionStart = 0;           \r
+               }\r
+               t.selectionStart        = start;\r
+               t.selectionEnd          = end;          \r
+               //textarea.setSelectionRange(start, end);\r
+               \r
+               if(isIE)\r
+                       set_IE_selection(t);\r
+       };\r
+\r
+       \r
+       // set IE position in Firefox mode (textarea.selectionStart and textarea.selectionEnd). should work as a repeated task\r
+       function get_IE_selection(t){\r
+               var d=document,div,range,stored_range,elem,scrollTop,relative_top,line_start,line_nb,range_start,range_end,tab;\r
+               if(t && t.focused)\r
+               {       \r
+                       if(!t.ea_line_height)\r
+                       {       // calculate the lineHeight\r
+                               div= d.createElement("div");\r
+                               div.style.fontFamily= get_css_property(t, "font-family");\r
+                               div.style.fontSize= get_css_property(t, "font-size");\r
+                               div.style.visibility= "hidden";                 \r
+                               div.innerHTML="0";\r
+                               d.body.appendChild(div);\r
+                               t.ea_line_height= div.offsetHeight;\r
+                               d.body.removeChild(div);\r
+                       }\r
+                       //t.focus();\r
+                       range = d.selection.createRange();\r
+                       try\r
+                       {\r
+                               stored_range = range.duplicate();\r
+                               stored_range.moveToElementText( t );\r
+                               stored_range.setEndPoint( 'EndToEnd', range );\r
+                               if(stored_range.parentElement() == t){\r
+                                       // the range don't take care of empty lines in the end of the selection\r
+                                       elem            = t;\r
+                                       scrollTop       = 0;\r
+                                       while(elem.parentNode){\r
+                                               scrollTop+= elem.scrollTop;\r
+                                               elem    = elem.parentNode;\r
+                                       }\r
+                               \r
+                               //      var scrollTop= t.scrollTop + document.body.scrollTop;\r
+                                       \r
+                               //      var relative_top= range.offsetTop - calculeOffsetTop(t) + scrollTop;\r
+                                       relative_top= range.offsetTop - calculeOffsetTop(t)+ scrollTop;\r
+                               //      alert("rangeoffset: "+ range.offsetTop +"\ncalcoffsetTop: "+ calculeOffsetTop(t) +"\nrelativeTop: "+ relative_top);\r
+                                       line_start      = Math.round((relative_top / t.ea_line_height) +1);\r
+                                       \r
+                                       line_nb         = Math.round(range.boundingHeight / t.ea_line_height);\r
+                                       \r
+                                       range_start     = stored_range.text.length - range.text.length;\r
+                                       tab     = t.value.substr(0, range_start).split("\n");                   \r
+                                       range_start     += (line_start - tab.length)*2;         // add missing empty lines to the selection\r
+                                       t.selectionStart = range_start;\r
+                                       \r
+                                       range_end       = t.selectionStart + range.text.length;\r
+                                       tab     = t.value.substr(0, range_start + range.text.length).split("\n");                       \r
+                                       range_end       += (line_start + line_nb - 1 - tab.length)*2;\r
+                                       t.selectionEnd = range_end;\r
+                               }\r
+                       }\r
+                       catch(e){}\r
+               }\r
+               setTimeout("get_IE_selection(document.getElementById('"+ t.id +"'));", 50);\r
+       };\r
+       \r
+       function IE_textarea_focus(){\r
+               event.srcElement.focused= true;\r
+       }\r
+       \r
+       function IE_textarea_blur(){\r
+               event.srcElement.focused= false;\r
+       }\r
+       \r
+       // select the text for IE (take into account the \r difference)\r
+       function set_IE_selection( t ){\r
+               var nbLineStart,nbLineStart,nbLineEnd,range;\r
+               if(!window.closed){ \r
+                       nbLineStart=t.value.substr(0, t.selectionStart).split("\n").length - 1;\r
+                       nbLineEnd=t.value.substr(0, t.selectionEnd).split("\n").length - 1;\r
+                       try\r
+                       {\r
+                               range = document.selection.createRange();\r
+                               range.moveToElementText( t );\r
+                               range.setEndPoint( 'EndToStart', range );\r
+                               range.moveStart('character', t.selectionStart - nbLineStart);\r
+                               range.moveEnd('character', t.selectionEnd - nbLineEnd - (t.selectionStart - nbLineStart)  );\r
+                               range.select();\r
+                       }\r
+                       catch(e){}\r
+               }\r
+       };\r
+       \r
+       \r
+       editAreaLoader.waiting_loading["elements_functions.js"]= "loaded";\r