1/* 2 * FCKeditor - The text editor for Internet - http://www.fckeditor.net 3 * Copyright (C) 2003-2009 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 * 21 * Useful functions used by almost all dialog window pages. 22 * Dialogs should link to this file as the very first script on the page. 23 */ 24 25// Automatically detect the correct document.domain (#123). 26(function() 27{ 28 var d = document.domain ; 29 30 while ( true ) 31 { 32 // Test if we can access a parent property. 33 try 34 { 35 var test = window.parent.document.domain ; 36 break ; 37 } 38 catch( e ) {} 39 40 // Remove a domain part: www.mytest.example.com => mytest.example.com => example.com ... 41 d = d.replace( /.*?(?:\.|$)/, '' ) ; 42 43 if ( d.length == 0 ) 44 break ; // It was not able to detect the domain. 45 46 try 47 { 48 document.domain = d ; 49 } 50 catch (e) 51 { 52 break ; 53 } 54 } 55})() ; 56 57// Attention: FCKConfig must be available in the page. 58function GetCommonDialogCss( prefix ) 59{ 60 // CSS minified by http://iceyboard.no-ip.org/projects/css_compressor (see _dev/css_compression.txt). 61 return FCKConfig.BasePath + 'dialog/common/' + '|.ImagePreviewArea{border:#000 1px solid;overflow:auto;width:100%;height:170px;background-color:#fff}.FlashPreviewArea{border:#000 1px solid;padding:5px;overflow:auto;width:100%;height:170px;background-color:#fff}.BtnReset{float:left;background-position:center center;background-image:url(images/reset.gif);width:16px;height:16px;background-repeat:no-repeat;border:1px none;font-size:1px}.BtnLocked,.BtnUnlocked{float:left;background-position:center center;background-image:url(images/locked.gif);width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.BtnUnlocked{background-image:url(images/unlocked.gif)}.BtnOver{border:outset 1px;cursor:pointer;cursor:hand}' ; 62} 63 64// Gets a element by its Id. Used for shorter coding. 65function GetE( elementId ) 66{ 67 return document.getElementById( elementId ) ; 68} 69 70function ShowE( element, isVisible ) 71{ 72 if ( typeof( element ) == 'string' ) 73 element = GetE( element ) ; 74 element.style.display = isVisible ? '' : 'none' ; 75} 76 77function SetAttribute( element, attName, attValue ) 78{ 79 if ( attValue == null || attValue.length == 0 ) 80 element.removeAttribute( attName, 0 ) ; // 0 : Case Insensitive 81 else 82 element.setAttribute( attName, attValue, 0 ) ; // 0 : Case Insensitive 83} 84 85function GetAttribute( element, attName, valueIfNull ) 86{ 87 var oAtt = element.attributes[attName] ; 88 89 if ( oAtt == null || !oAtt.specified ) 90 return valueIfNull ? valueIfNull : '' ; 91 92 var oValue = element.getAttribute( attName, 2 ) ; 93 94 if ( oValue == null ) 95 oValue = oAtt.nodeValue ; 96 97 return ( oValue == null ? valueIfNull : oValue ) ; 98} 99 100function SelectField( elementId ) 101{ 102 var element = GetE( elementId ) ; 103 element.focus() ; 104 105 // element.select may not be available for some fields (like <select>). 106 if ( element.select ) 107 element.select() ; 108} 109 110// Functions used by text fields to accept numbers only. 111var IsDigit = ( function() 112 { 113 var KeyIdentifierMap = 114 { 115 End : 35, 116 Home : 36, 117 Left : 37, 118 Right : 39, 119 'U+00007F' : 46 // Delete 120 } ; 121 122 return function ( e ) 123 { 124 if ( !e ) 125 e = event ; 126 127 var iCode = ( e.keyCode || e.charCode ) ; 128 129 if ( !iCode && e.keyIdentifier && ( e.keyIdentifier in KeyIdentifierMap ) ) 130 iCode = KeyIdentifierMap[ e.keyIdentifier ] ; 131 132 return ( 133 ( iCode >= 48 && iCode <= 57 ) // Numbers 134 || (iCode >= 35 && iCode <= 40) // Arrows, Home, End 135 || iCode == 8 // Backspace 136 || iCode == 46 // Delete 137 || iCode == 9 // Tab 138 ) ; 139 } 140 } )() ; 141 142String.prototype.Trim = function() 143{ 144 return this.replace( /(^\s*)|(\s*$)/g, '' ) ; 145} 146 147String.prototype.StartsWith = function( value ) 148{ 149 return ( this.substr( 0, value.length ) == value ) ; 150} 151 152String.prototype.Remove = function( start, length ) 153{ 154 var s = '' ; 155 156 if ( start > 0 ) 157 s = this.substring( 0, start ) ; 158 159 if ( start + length < this.length ) 160 s += this.substring( start + length , this.length ) ; 161 162 return s ; 163} 164 165String.prototype.ReplaceAll = function( searchArray, replaceArray ) 166{ 167 var replaced = this ; 168 169 for ( var i = 0 ; i < searchArray.length ; i++ ) 170 { 171 replaced = replaced.replace( searchArray[i], replaceArray[i] ) ; 172 } 173 174 return replaced ; 175} 176 177function OpenFileBrowser( url, width, height ) 178{ 179 // oEditor must be defined. 180 181 var iLeft = ( oEditor.FCKConfig.ScreenWidth - width ) / 2 ; 182 var iTop = ( oEditor.FCKConfig.ScreenHeight - height ) / 2 ; 183 184 var sOptions = "toolbar=no,status=no,resizable=yes,dependent=yes,scrollbars=yes" ; 185 sOptions += ",width=" + width ; 186 sOptions += ",height=" + height ; 187 sOptions += ",left=" + iLeft ; 188 sOptions += ",top=" + iTop ; 189 190 window.open( url, 'FCKBrowseWindow', sOptions ) ; 191} 192 193/** 194 Utility function to create/update an element with a name attribute in IE, so it behaves properly when moved around 195 It also allows to change the name or other special attributes in an existing node 196 oEditor : instance of FCKeditor where the element will be created 197 oOriginal : current element being edited or null if it has to be created 198 nodeName : string with the name of the element to create 199 oAttributes : Hash object with the attributes that must be set at creation time in IE 200 Those attributes will be set also after the element has been 201 created for any other browser to avoid redudant code 202*/ 203function CreateNamedElement( oEditor, oOriginal, nodeName, oAttributes ) 204{ 205 var oNewNode ; 206 207 // IE doesn't allow easily to change properties of an existing object, 208 // so remove the old and force the creation of a new one. 209 var oldNode = null ; 210 if ( oOriginal && oEditor.FCKBrowserInfo.IsIE ) 211 { 212 // Force the creation only if some of the special attributes have changed: 213 var bChanged = false; 214 for( var attName in oAttributes ) 215 bChanged |= ( oOriginal.getAttribute( attName, 2) != oAttributes[attName] ) ; 216 217 if ( bChanged ) 218 { 219 oldNode = oOriginal ; 220 oOriginal = null ; 221 } 222 } 223 224 // If the node existed (and it's not IE), then we just have to update its attributes 225 if ( oOriginal ) 226 { 227 oNewNode = oOriginal ; 228 } 229 else 230 { 231 // #676, IE doesn't play nice with the name or type attribute 232 if ( oEditor.FCKBrowserInfo.IsIE ) 233 { 234 var sbHTML = [] ; 235 sbHTML.push( '<' + nodeName ) ; 236 for( var prop in oAttributes ) 237 { 238 sbHTML.push( ' ' + prop + '="' + oAttributes[prop] + '"' ) ; 239 } 240 sbHTML.push( '>' ) ; 241 if ( !oEditor.FCKListsLib.EmptyElements[nodeName.toLowerCase()] ) 242 sbHTML.push( '</' + nodeName + '>' ) ; 243 244 oNewNode = oEditor.FCK.EditorDocument.createElement( sbHTML.join('') ) ; 245 // Check if we are just changing the properties of an existing node: copy its properties 246 if ( oldNode ) 247 { 248 CopyAttributes( oldNode, oNewNode, oAttributes ) ; 249 oEditor.FCKDomTools.MoveChildren( oldNode, oNewNode ) ; 250 oldNode.parentNode.removeChild( oldNode ) ; 251 oldNode = null ; 252 253 if ( oEditor.FCK.Selection.SelectionData ) 254 { 255 // Trick to refresh the selection object and avoid error in 256 // fckdialog.html Selection.EnsureSelection 257 var oSel = oEditor.FCK.EditorDocument.selection ; 258 oEditor.FCK.Selection.SelectionData = oSel.createRange() ; // Now oSel.type will be 'None' reflecting the real situation 259 } 260 } 261 oNewNode = oEditor.FCK.InsertElement( oNewNode ) ; 262 263 // FCK.Selection.SelectionData is broken by now since we've 264 // deleted the previously selected element. So we need to reassign it. 265 if ( oEditor.FCK.Selection.SelectionData ) 266 { 267 var range = oEditor.FCK.EditorDocument.body.createControlRange() ; 268 range.add( oNewNode ) ; 269 oEditor.FCK.Selection.SelectionData = range ; 270 } 271 } 272 else 273 { 274 oNewNode = oEditor.FCK.InsertElement( nodeName ) ; 275 } 276 } 277 278 // Set the basic attributes 279 for( var attName in oAttributes ) 280 oNewNode.setAttribute( attName, oAttributes[attName], 0 ) ; // 0 : Case Insensitive 281 282 return oNewNode ; 283} 284 285// Copy all the attributes from one node to the other, kinda like a clone 286// But oSkipAttributes is an object with the attributes that must NOT be copied 287function CopyAttributes( oSource, oDest, oSkipAttributes ) 288{ 289 var aAttributes = oSource.attributes ; 290 291 for ( var n = 0 ; n < aAttributes.length ; n++ ) 292 { 293 var oAttribute = aAttributes[n] ; 294 295 if ( oAttribute.specified ) 296 { 297 var sAttName = oAttribute.nodeName ; 298 // We can set the type only once, so do it with the proper value, not copying it. 299 if ( sAttName in oSkipAttributes ) 300 continue ; 301 302 var sAttValue = oSource.getAttribute( sAttName, 2 ) ; 303 if ( sAttValue == null ) 304 sAttValue = oAttribute.nodeValue ; 305 306 oDest.setAttribute( sAttName, sAttValue, 0 ) ; // 0 : Case Insensitive 307 } 308 } 309 // The style: 310 if ( oSource.style.cssText !== '' ) 311 oDest.style.cssText = oSource.style.cssText ; 312} 313 314/** 315* Replaces a tag with another one, keeping its contents: 316* for example TD --> TH, and TH --> TD. 317* input: the original node, and the new tag name 318* http://www.w3.org/TR/DOM-Level-3-Core/core.html#Document3-renameNode 319*/ 320function RenameNode( oNode , newTag ) 321{ 322 // TODO: if the browser natively supports document.renameNode call it. 323 // does any browser currently support it in order to test? 324 325 // Only rename element nodes. 326 if ( oNode.nodeType != 1 ) 327 return null ; 328 329 // If it's already correct exit here. 330 if ( oNode.nodeName == newTag ) 331 return oNode ; 332 333 var oDoc = oNode.ownerDocument ; 334 // Create the new node 335 var newNode = oDoc.createElement( newTag ) ; 336 337 // Copy all attributes 338 CopyAttributes( oNode, newNode, {} ) ; 339 340 // Move children to the new node 341 FCKDomTools.MoveChildren( oNode, newNode ) ; 342 343 // Finally replace the node and return the new one 344 oNode.parentNode.replaceChild( newNode, oNode ) ; 345 346 return newNode ; 347} 348