/* * FCKeditor - The text editor for Internet - http://www.fckeditor.net * Copyright (C) 2003-2007 Frederico Caldeira Knabben * * == BEGIN LICENSE == * * Licensed under the terms of any of the following licenses at your * choice: * * - GNU General Public License Version 2 or later (the "GPL") * http://www.gnu.org/licenses/gpl.html * * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") * http://www.gnu.org/licenses/lgpl.html * * - Mozilla Public License Version 1.1 or later (the "MPL") * http://www.mozilla.org/MPL/MPL-1.1.html * * == END LICENSE == * * Utility functions. */ var FCKTools = new Object() ; FCKTools.CreateBogusBR = function( targetDocument ) { var eBR = targetDocument.createElement( 'br' ) ; // eBR.setAttribute( '_moz_editor_bogus_node', 'TRUE' ) ; eBR.setAttribute( 'type', '_moz' ) ; return eBR ; } // Returns a reference to the appended style sheet or an array with all the appended references FCKTools.AppendStyleSheet = function( documentElement, cssFileUrlOrArray ) { if ( typeof( cssFileUrlOrArray ) == 'string' ) return this._AppendStyleSheet( documentElement, cssFileUrlOrArray ) ; else { var aStyleSheeArray = new Array() ; for ( var i = 0 ; i < cssFileUrlOrArray.length ; i++ ) aStyleSheeArray.push(this._AppendStyleSheet( documentElement, cssFileUrlOrArray[i] ) ) ; return aStyleSheeArray ; } } FCKTools.AppendStyleString = function ( documentElement, cssStyles ) { this._AppendStyleString( documentElement, cssStyles ) ; } FCKTools.GetElementDocument = function ( element ) { return element.ownerDocument || element.document ; } // Get the window object where the element is placed in. FCKTools.GetElementWindow = function( element ) { return this.GetDocumentWindow( this.GetElementDocument( element ) ) ; } FCKTools.GetDocumentWindow = function( document ) { // With Safari, there is not way to retrieve the window from the document, so we must fix it. if ( FCKBrowserInfo.IsSafari && !document.parentWindow ) this.FixDocumentParentWindow( window.top ) ; return document.parentWindow || document.defaultView ; } /* This is a Safari specific function that fix the reference to the parent window from the document object. */ FCKTools.FixDocumentParentWindow = function( targetWindow ) { targetWindow.document.parentWindow = targetWindow ; for ( var i = 0 ; i < targetWindow.frames.length ; i++ ) FCKTools.FixDocumentParentWindow( targetWindow.frames[i] ) ; } FCKTools.HTMLEncode = function( text ) { if ( !text ) return '' ; text = text.replace( /&/g, '&' ) ; text = text.replace( //g, '>' ) ; return text ; } FCKTools.HTMLDecode = function( text ) { if ( !text ) return '' ; text = text.replace( />/g, '>' ) ; text = text.replace( /</g, '<' ) ; text = text.replace( /&/g, '&' ) ; return text ; } FCKTools._ProcessLineBreaksForPMode = function( oEditor, text, liState, node, strArray ) { var closeState = 0 ; var blockStartTag = "

" ; var blockEndTag = "

" ; var lineBreakTag = "
" ; if ( liState ) { blockStartTag = "
  • " ; blockEndTag = "
  • " ; closeState = 1 ; } // Are we currently inside a

    tag now? // If yes, close it at the next double line break. while ( node && node != oEditor.FCK.EditorDocument.body ) { if ( node.tagName.toLowerCase() == 'p' ) { closeState = 1 ; break; } node = node.parentNode ; } for ( var i = 0 ; i < text.length ; i++ ) { var c = text.charAt( i ) ; if ( c == '\r' ) continue ; if ( c != '\n' ) { strArray.push( c ) ; continue ; } // Now we have encountered a line break. // Check if the next character is also a line break. var n = text.charAt( i + 1 ) ; if ( n == '\r' ) { i++ ; n = text.charAt( i + 1 ) ; } if ( n == '\n' ) { i++ ; // ignore next character - we have already processed it. if ( closeState ) strArray.push( blockEndTag ) ; strArray.push( blockStartTag ) ; closeState = 1 ; } else strArray.push( lineBreakTag ) ; } } FCKTools._ProcessLineBreaksForDivMode = function( oEditor, text, liState, node, strArray ) { var closeState = 0 ; var blockStartTag = "

    " ; var blockEndTag = "
    " ; if ( liState ) { blockStartTag = "
  • " ; blockEndTag = "
  • " ; closeState = 1 ; } // Are we currently inside a
    tag now? // If yes, close it at the next double line break. while ( node && node != oEditor.FCK.EditorDocument.body ) { if ( node.tagName.toLowerCase() == 'div' ) { closeState = 1 ; break ; } node = node.parentNode ; } for ( var i = 0 ; i < text.length ; i++ ) { var c = text.charAt( i ) ; if ( c == '\r' ) continue ; if ( c != '\n' ) { strArray.push( c ) ; continue ; } if ( closeState ) { if ( strArray[ strArray.length - 1 ] == blockStartTag ) { // A div tag must have some contents inside for it to be visible. strArray.push( " " ) ; } strArray.push( blockEndTag ) ; } strArray.push( blockStartTag ) ; closeState = 1 ; } if ( closeState ) strArray.push( blockEndTag ) ; } FCKTools._ProcessLineBreaksForBrMode = function( oEditor, text, liState, node, strArray ) { var closeState = 0 ; var blockStartTag = "
    " ; var blockEndTag = "" ; if ( liState ) { blockStartTag = "
  • " ; blockEndTag = "
  • " ; closeState = 1 ; } for ( var i = 0 ; i < text.length ; i++ ) { var c = text.charAt( i ) ; if ( c == '\r' ) continue ; if ( c != '\n' ) { strArray.push( c ) ; continue ; } if ( closeState && blockEndTag.length ) strArray.push ( blockEndTag ) ; strArray.push( blockStartTag ) ; closeState = 1 ; } } FCKTools.ProcessLineBreaks = function( oEditor, oConfig, text ) { var enterMode = oConfig.EnterMode.toLowerCase() ; var strArray = [] ; // Is the caret or selection inside an
  • tag now? var liState = 0 ; var range = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ; range.MoveToSelection() ; var node = range._Range.startContainer ; while ( node && node.nodeType != 1 ) node = node.parentNode ; if ( node && node.tagName.toLowerCase() == 'li' ) liState = 1 ; if ( enterMode == 'p' ) this._ProcessLineBreaksForPMode( oEditor, text, liState, node, strArray ) ; else if ( enterMode == 'div' ) this._ProcessLineBreaksForDivMode( oEditor, text, liState, node, strArray ) ; else if ( enterMode == 'br' ) this._ProcessLineBreaksForBrMode( oEditor, text, liState, node, strArray ) ; return strArray.join( "" ) ; } /** * Adds an option to a SELECT element. */ FCKTools.AddSelectOption = function( selectElement, optionText, optionValue ) { var oOption = FCKTools.GetElementDocument( selectElement ).createElement( "OPTION" ) ; oOption.text = optionText ; oOption.value = optionValue ; selectElement.options.add(oOption) ; return oOption ; } FCKTools.RunFunction = function( func, thisObject, paramsArray, timerWindow ) { if ( func ) this.SetTimeout( func, 0, thisObject, paramsArray, timerWindow ) ; } FCKTools.SetTimeout = function( func, milliseconds, thisObject, paramsArray, timerWindow ) { return ( timerWindow || window ).setTimeout( function() { if ( paramsArray ) func.apply( thisObject, [].concat( paramsArray ) ) ; else func.apply( thisObject ) ; }, milliseconds ) ; } FCKTools.SetInterval = function( func, milliseconds, thisObject, paramsArray, timerWindow ) { return ( timerWindow || window ).setInterval( function() { func.apply( thisObject, paramsArray || [] ) ; }, milliseconds ) ; } FCKTools.ConvertStyleSizeToHtml = function( size ) { return size.EndsWith( '%' ) ? size : parseInt( size, 10 ) ; } FCKTools.ConvertHtmlSizeToStyle = function( size ) { return size.EndsWith( '%' ) ? size : ( size + 'px' ) ; } // START iCM MODIFICATIONS // Amended to accept a list of one or more ascensor tag names // Amended to check the element itself before working back up through the parent hierarchy FCKTools.GetElementAscensor = function( element, ascensorTagNames ) { // var e = element.parentNode ; var e = element ; var lstTags = "," + ascensorTagNames.toUpperCase() + "," ; while ( e ) { if ( lstTags.indexOf( "," + e.nodeName.toUpperCase() + "," ) != -1 ) return e ; e = e.parentNode ; } return null ; } // END iCM MODIFICATIONS FCKTools.CreateEventListener = function( func, params ) { var f = function() { var aAllParams = [] ; for ( var i = 0 ; i < arguments.length ; i++ ) aAllParams.push( arguments[i] ) ; func.apply( this, aAllParams.concat( params ) ) ; } return f ; } FCKTools.IsStrictMode = function( document ) { // There is no compatMode in Safari, but it seams that it always behave as // CSS1Compat, so let's assume it as the default. return ( 'CSS1Compat' == ( document.compatMode || 'CSS1Compat' ) ) ; } // Transforms a "arguments" object to an array. FCKTools.ArgumentsToArray = function( args, startIndex, maxLength ) { startIndex = startIndex || 0 ; maxLength = maxLength || args.length ; var argsArray = new Array() ; for ( var i = startIndex ; i < startIndex + maxLength && i < args.length ; i++ ) argsArray.push( args[i] ) ; return argsArray ; } FCKTools.CloneObject = function( sourceObject ) { var fCloneCreator = function() {} ; fCloneCreator.prototype = sourceObject ; return new fCloneCreator ; } // Appends a bogus
    at the end of the element, if not yet available. FCKTools.AppendBogusBr = function( element ) { if ( !element ) return ; var eLastChild = this.GetLastItem( element.getElementsByTagName('br') ) ; if ( !eLastChild || ( eLastChild.getAttribute( 'type', 2 ) != '_moz' && eLastChild.getAttribute( '_moz_dirty' ) == null ) ) { var doc = this.GetElementDocument( element ) ; if ( FCKBrowserInfo.IsOpera ) element.appendChild( doc.createTextNode('') ) ; else element.appendChild( this.CreateBogusBR( doc ) ) ; } } FCKTools.GetLastItem = function( list ) { if ( list.length > 0 ) return list[ list.length - 1 ] ; return null ; } FCKTools.GetDocumentPosition = function( w, node ) { var x = 0 ; var y = 0 ; var curNode = node ; while ( curNode && curNode != w.document.body ) { x += curNode.offsetLeft - curNode.scrollLeft ; y += curNode.offsetTop - curNode.scrollTop ; curNode = curNode.offsetParent ; } return { "x" : x, "y" : y } ; } FCKTools.GetWindowPosition = function( w, node ) { var pos = this.GetDocumentPosition( w, node ) ; var scroll = FCKTools.GetScrollPosition( w ) ; pos.x -= scroll.X ; pos.y -= scroll.Y ; return pos ; } FCKTools.ProtectFormStyles = function( formNode ) { if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' ) return [] ; var hijackRecord = [] ; var hijackNames = [ 'style', 'className' ] ; for ( var i = 0 ; i < hijackNames.length ; i++ ) { var name = hijackNames[i] ; if ( formNode.elements.namedItem( name ) ) { var hijackNode = formNode.elements.namedItem( name ) ; hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] ) ; formNode.removeChild( hijackNode ) ; } } return hijackRecord ; } FCKTools.RestoreFormStyles = function( formNode, hijackRecord ) { if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' ) return ; if ( hijackRecord.length > 0 ) { for ( var i = hijackRecord.length - 1 ; i >= 0 ; i-- ) { var node = hijackRecord[i][0] ; var sibling = hijackRecord[i][1] ; if ( sibling ) formNode.insertBefore( node, sibling ) ; else formNode.appendChild( node ) ; } } } // Perform a one-step DFS walk. FCKTools.GetNextNode = function( node, limitNode ) { if ( node.firstChild ) return node.firstChild ; else if ( node.nextSibling ) return node.nextSibling ; else { var ancestor = node.parentNode ; while ( ancestor ) { if ( ancestor == limitNode ) return null ; if ( ancestor.nextSibling ) return ancestor.nextSibling ; else ancestor = ancestor.parentNode ; } } return null ; } FCKTools.GetNextTextNode = function( textnode, limitNode, checkStop ) { node = this.GetNextNode( textnode, limitNode ) ; if ( checkStop && node && checkStop( node ) ) return null ; while ( node && node.nodeType != 3 ) { node = this.GetNextNode( node, limitNode ) ; if ( checkStop && node && checkStop( node ) ) return null ; } return node ; } /** * Merge all objects passed by argument into a single object. */ FCKTools.Merge = function() { var args = arguments ; var o = args[0] ; for ( var i = 1 ; i < args.length ; i++ ) { var arg = args[i] ; for ( var p in arg ) o[p] = arg[p] ; } return o ; } /** * Check if the passed argument is a real Array. It may not working when * calling it cross windows. */ FCKTools.IsArray = function( it ) { return ( it instanceof Array ) ; } /** * Appends a "length" property to an object, containing the number of * properties available on it, excluded the append property itself. */ FCKTools.AppendLengthProperty = function( targetObject, propertyName ) { var counter = 0 ; for ( var n in targetObject ) counter++ ; return targetObject[ propertyName || 'length' ] = counter ; } /** * Gets the browser parsed version of a css text (style attribute value). On * some cases, the browser makes changes to the css text, returning a different * value. For example, hexadecimal colors get transformed to rgb(). */ FCKTools.NormalizeCssText = function( unparsedCssText ) { // Injects the style in a temporary span object, so the browser parses it, // retrieving its final format. var tempSpan = document.createElement( 'span' ) ; tempSpan.style.cssText = unparsedCssText ; return tempSpan.style.cssText ; } /** * Utility function to wrap a call to an object's method, * so it can be passed for example to an event handler, * and then it will be executed with 'this' being the object. */ FCKTools.Hitch = function( obj, methodName ) { return function() { obj[methodName].apply(obj, arguments); } ; }