| 1 | /* | |
| 2 | * FCKeditor - The text editor for Internet - http://www.fckeditor.net | |
| 3 | * Copyright (C) 2003-2007 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 | * This is the integration file for JavaScript. | |
| 22 | * | |
| 23 | * It defines the FCKeditor class that can be used to create editor | |
| 24 | * instances in a HTML page in the client side. For server side | |
| 25 | * operations, use the specific integration system. | |
| 26 | */ | |
| 27 | ||
| 28 | // FCKeditor Class | |
| 29 | var FCKeditor = function( instanceName, width, height, toolbarSet, value ) | |
| 30 | { | |
| 31 | // Properties | |
| 32 | this.InstanceName = instanceName ; | |
| 33 | this.Width = width || '100%' ; | |
| 34 | this.Height = height || '200' ; | |
| 35 | this.ToolbarSet = toolbarSet || 'Default' ; | |
| 36 | this.Value = value || '' ; | |
| 37 | this.BasePath = '/fckeditor/' ; | |
| 38 | this.CheckBrowser = true ; | |
| 39 | this.DisplayErrors = true ; | |
| 40 | ||
| 41 | this.Config = new Object() ; | |
| 42 | ||
| 43 | // Events | |
| 44 | this.OnError = null ; // function( source, errorNumber, errorDescription ) | |
| 45 | } | |
| 46 | ||
| 47 | FCKeditor.prototype.Version = '2.5' ; | |
| 48 | FCKeditor.prototype.VersionBuild = '17352' ; | |
| 49 | ||
| 50 | FCKeditor.prototype.Create = function() | |
| 51 | { | |
| 52 | document.write( this.CreateHtml() ) ; | |
| 53 | } | |
| 54 | ||
| 55 | FCKeditor.prototype.CreateHtml = function() | |
| 56 | { | |
| 57 | // Check for errors | |
| 58 | if ( !this.InstanceName || this.InstanceName.length == 0 ) | |
| 59 | { | |
| 60 | this._ThrowError( 701, 'You must specify an instance name.' ) ; | |
| 61 | return '' ; | |
| 62 | } | |
| 63 | ||
| 64 | var sHtml = '<div>' ; | |
| 65 | ||
| 66 | if ( !this.CheckBrowser || this._IsCompatibleBrowser() ) | |
| 67 | { | |
| 68 | sHtml += '<input type="hidden" id="' + this.InstanceName + '" name="' + this.InstanceName + '" value="' + this._HTMLEncode( this.Value ) + '" style="display:none" />' ; | |
| 69 | sHtml += this._GetConfigHtml() ; | |
| 70 | sHtml += this._GetIFrameHtml() ; | |
| 71 | } | |
| 72 | else | |
| 73 | { | |
| 74 | var sWidth = this.Width.toString().indexOf('%') > 0 ? this.Width : this.Width + 'px' ; | |
| 75 | var sHeight = this.Height.toString().indexOf('%') > 0 ? this.Height : this.Height + 'px' ; | |
| 76 | sHtml += '<textarea name="' + this.InstanceName + '" rows="4" cols="40" style="width:' + sWidth + ';height:' + sHeight + '">' + this._HTMLEncode( this.Value ) + '<\/textarea>' ; | |
| 77 | } | |
| 78 | ||
| 79 | sHtml += '</div>' ; | |
| 80 | ||
| 81 | return sHtml ; | |
| 82 | } | |
| 83 | ||
| 84 | FCKeditor.prototype.ReplaceTextarea = function() | |
| 85 | { | |
| 86 | if ( !this.CheckBrowser || this._IsCompatibleBrowser() ) | |
| 87 | { | |
| 88 | // We must check the elements firstly using the Id and then the name. | |
| 89 | var oTextarea = document.getElementById( this.InstanceName ) ; | |
| 90 | var colElementsByName = document.getElementsByName( this.InstanceName ) ; | |
| 91 | var i = 0; | |
| 92 | while ( oTextarea || i == 0 ) | |
| 93 | { | |
| 94 | if ( oTextarea && oTextarea.tagName.toLowerCase() == 'textarea' ) | |
| 95 | break ; | |
| 96 | oTextarea = colElementsByName[i++] ; | |
| 97 | } | |
| 98 | ||
| 99 | if ( !oTextarea ) | |
| 100 | { | |
| 101 | alert( 'Error: The TEXTAREA with id or name set to "' + this.InstanceName + '" was not found' ) ; | |
| 102 | return ; | |
| 103 | } | |
| 104 | ||
| 105 | oTextarea.style.display = 'none' ; | |
| 106 | this._InsertHtmlBefore( this._GetConfigHtml(), oTextarea ) ; | |
| 107 | this._InsertHtmlBefore( this._GetIFrameHtml(), oTextarea ) ; | |
| 108 | } | |
| 109 | } | |
| 110 | ||
| 111 | FCKeditor.prototype._InsertHtmlBefore = function( html, element ) | |
| 112 | { | |
| 113 | if ( element.insertAdjacentHTML ) // IE | |
| 114 | element.insertAdjacentHTML( 'beforeBegin', html ) ; | |
| 115 | else // Gecko | |
| 116 | { | |
| 117 | var oRange = document.createRange() ; | |
| 118 | oRange.setStartBefore( element ) ; | |
| 119 | var oFragment = oRange.createContextualFragment( html ); | |
| 120 | element.parentNode.insertBefore( oFragment, element ) ; | |
| 121 | } | |
| 122 | } | |
| 123 | ||
| 124 | FCKeditor.prototype._GetConfigHtml = function() | |
| 125 | { | |
| 126 | var sConfig = '' ; | |
| 127 | for ( var o in this.Config ) | |
| 128 | { | |
| 129 | if ( sConfig.length > 0 ) sConfig += '&' ; | |
| 130 | sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.Config[o] ) ; | |
| 131 | } | |
| 132 | ||
| 133 | return '<input type="hidden" id="' + this.InstanceName + '___Config" value="' + sConfig + '" style="display:none" />' ; | |
| 134 | } | |
| 135 | ||
| 136 | FCKeditor.prototype._GetIFrameHtml = function() | |
| 137 | { | |
| 138 | var sFile = 'fckeditor.html' ; | |
| 139 | ||
| 140 | try | |
| 141 | { | |
| 142 | if ( (/fcksource=true/i).test( window.top.location.search ) ) | |
| 143 | sFile = 'fckeditor.original.html' ; | |
| 144 | } | |
| 145 | catch (e) { /* Ignore it. Much probably we are inside a FRAME where the "top" is in another domain (security error). */ } | |
| 146 | ||
| 147 | var sLink = this.BasePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.InstanceName ) ; | |
| 148 | if (this.ToolbarSet) sLink += '&Toolbar=' + this.ToolbarSet ; | |
| 149 | ||
| 150 | return '<iframe id="' + this.InstanceName + '___Frame" src="' + sLink + '" width="' + this.Width + '" height="' + this.Height + '" frameborder="0" scrolling="no"></iframe>' ; | |
| 151 | } | |
| 152 | ||
| 153 | FCKeditor.prototype._IsCompatibleBrowser = function() | |
| 154 | { | |
| 155 | return FCKeditor_IsCompatibleBrowser() ; | |
| 156 | } | |
| 157 | ||
| 158 | FCKeditor.prototype._ThrowError = function( errorNumber, errorDescription ) | |
| 159 | { | |
| 160 | this.ErrorNumber = errorNumber ; | |
| 161 | this.ErrorDescription = errorDescription ; | |
| 162 | ||
| 163 | if ( this.DisplayErrors ) | |
| 164 | { | |
| 165 | document.write( '<div style="COLOR: #ff0000">' ) ; | |
| 166 | document.write( '[ FCKeditor Error ' + this.ErrorNumber + ': ' + this.ErrorDescription + ' ]' ) ; | |
| 167 | document.write( '</div>' ) ; | |
| 168 | } | |
| 169 | ||
| 170 | if ( typeof( this.OnError ) == 'function' ) | |
| 171 | this.OnError( this, errorNumber, errorDescription ) ; | |
| 172 | } | |
| 173 | ||
| 174 | FCKeditor.prototype._HTMLEncode = function( text ) | |
| 175 | { | |
| 176 | if ( typeof( text ) != "string" ) | |
| 177 | text = text.toString() ; | |
| 178 | ||
| 179 | text = text.replace( | |
| 180 | /&/g, "&").replace( | |
| 181 | /"/g, """).replace( | |
| 182 | /</g, "<").replace( | |
| 183 | />/g, ">") ; | |
| 184 | ||
| 185 | return text ; | |
| 186 | } | |
| 187 | ||
| 188 | function FCKeditor_IsCompatibleBrowser() | |
| 189 | { | |
| 190 | var sAgent = navigator.userAgent.toLowerCase() ; | |
| 191 | ||
| 192 | // Internet Explorer 5.5+ | |
| 193 | if ( /*@cc_on!@*/false && sAgent.indexOf("mac") == -1 ) | |
| 194 | { | |
| 195 | var sBrowserVersion = navigator.appVersion.match(/MSIE (.\..)/)[1] ; | |
| 196 | return ( sBrowserVersion >= 5.5 ) ; | |
| 197 | } | |
| 198 | ||
| 199 | // Gecko (Opera 9 tries to behave like Gecko at this point). | |
| 200 | if ( navigator.product == "Gecko" && navigator.productSub >= 20030210 && !( typeof(opera) == 'object' && opera.postError ) ) | |
| 201 | return true ; | |
| 202 | ||
| 203 | // Opera 9.50+ | |
| 204 | if ( window.opera && window.opera.version && parseFloat( window.opera.version() ) >= 9.5 ) | |
| 205 | return true ; | |
| 206 | ||
| 207 | // Safari 3+ | |
| 208 | if ( sAgent.indexOf( ' applewebkit/' ) != -1 ) | |
| 209 | return ( sAgent.match( / applewebkit\/(\d+)/ )[1] >= 522 ) ; // Build must be at least 522 (v3) | |
| 210 | ||
| 211 | return false ; | |
| 212 | } |