diff --git a/lib/ckeditor/ckeditor.asp b/lib/ckeditor/ckeditor.asp new file mode 100644 index 00000000..f9bf274e --- /dev/null +++ b/lib/ckeditor/ckeditor.asp @@ -0,0 +1,955 @@ +<% + ' + ' Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. + ' For licensing, see LICENSE.html or http://ckeditor.com/license + +' Shared variable for all instances ("static") +dim CKEDITOR_initComplete +dim CKEDITOR_returnedEvents + + '' + ' \brief CKEditor class that can be used to create editor + ' instances in ASP pages on server side. + ' @see http://ckeditor.com + ' + ' Sample usage: + ' @code + ' editor = new CKEditor + ' editor.editor "editor1", "

Initial value.

", empty, empty + ' @endcode + +Class CKEditor + + '' + ' The version of %CKEditor. + private version + + '' + ' A constant string unique for each release of %CKEditor. + private mTimeStamp + + '' + ' URL to the %CKEditor installation directory (absolute or relative to document root). + ' If not set, CKEditor will try to guess it's path. + ' + ' Example usage: + ' @code + ' editor.basePath = "/ckeditor/" + ' @endcode + Public basePath + + '' + ' A boolean variable indicating whether CKEditor has been initialized. + ' Set it to true only if you have already included + ' <script> tag loading ckeditor.js in your website. + Public initialized + + '' + ' Boolean variable indicating whether created code should be printed out or returned by a function. + ' + ' Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + ' @code + ' editor = new CKEditor + ' editor.returnOutput = true + ' code = editor.editor("editor1", "

Initial value.

", empty, empty) + ' response.write "

Editor 1:

" + ' response.write code + ' @endcode + Public returnOutput + + '' + ' A Dictionary with textarea attributes. + ' + ' When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + ' it will be displayed to anyone with JavaScript disabled or with incompatible browser. + public textareaAttributes + + '' + ' A string indicating the creation date of %CKEditor. + ' Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + public timestamp + + '' + ' A dictionary that holds the instance configuration. + private oInstanceConfig + + '' + ' A dictionary that holds the configuration for all the instances. + private oAllInstancesConfig + + '' + ' A dictionary that holds event listeners for the instance. + private oInstanceEvents + + '' + ' A dictionary that holds event listeners for all the instances. + private oAllInstancesEvents + + '' + ' A Dictionary that holds global event listeners (CKEDITOR object) + private oGlobalEvents + + + Private Sub Class_Initialize() + version = "3.6.2" + timeStamp = "B8DJ5M3" + mTimeStamp = "B8DJ5M3" + + Set oInstanceConfig = CreateObject("Scripting.Dictionary") + Set oAllInstancesConfig = CreateObject("Scripting.Dictionary") + + Set oInstanceEvents = CreateObject("Scripting.Dictionary") + Set oAllInstancesEvents = CreateObject("Scripting.Dictionary") + Set oGlobalEvents = CreateObject("Scripting.Dictionary") + + Set textareaAttributes = CreateObject("Scripting.Dictionary") + textareaAttributes.Add "rows", 8 + textareaAttributes.Add "cols", 60 + End Sub + + '' + ' Creates a %CKEditor instance. + ' In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + ' + ' @param name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + ' @param value (string) Initial value. + ' + ' Example usage: + ' @code + ' set editor = New CKEditor + ' editor.editor "field1", "

Initial value.

" + ' @endcode + ' + ' Advanced example: + ' @code + ' set editor = new CKEditor + ' set config = CreateObject("Scripting.Dictionary") + ' config.Add "toolbar", Array( _ + ' Array( "Source", "-", "Bold", "Italic", "Underline", "Strike" ), _ + ' Array( "Image", "Link", "Unlink", "Anchor" ) _ + ' ) + ' set events = CreateObject("Scripting.Dictionary") + ' events.Add "instanceReady", "function (evt) { alert('Loaded second editor: ' + evt.editor.name );}" + + ' editor.editor "field1", "

Initial value.

", config, events + ' @endcode + ' + public function editor(name, value) + dim attr, out, js, customConfig, extraConfig + dim attribute + + attr = "" + + for each attribute in textareaAttributes + attr = attr & " " & attribute & "=""" & replace( textareaAttributes( attribute ), """", """ ) & """" + next + + out = "" & vbcrlf + + if not(initialized) then + out = out & init() + end if + + set customConfig = configSettings() + js = returnGlobalEvents() + + extraConfig = (new JSON)( empty, customConfig, false ) + if extraConfig<>"" then extraConfig = ", " & extraConfig + js = js & "CKEDITOR.replace('" & name & "'" & extraConfig & ");" + + out = out & script(js) + + if not(returnOutput) then + response.write out + out = "" + end if + + editor = out + + oInstanceConfig.RemoveAll + oInstanceEvents.RemoveAll + end function + + '' + ' Replaces a <textarea> with a %CKEditor instance. + ' + ' @param id (string) The id or name of textarea element. + ' + ' Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + ' @code + ' set editor = New CKEditor + ' editor.replace "article" + ' @endcode + ' + public function replaceInstance(id) + dim out, js, customConfig, extraConfig + + out = "" + if not(initialized) then + out = out & init() + end if + + set customConfig = configSettings() + js = returnGlobalEvents() + + extraConfig = (new JSON)( empty, customConfig, false ) + if extraConfig<>"" then extraConfig = ", " & extraConfig + js = js & "CKEDITOR.replace('" & id & "'" & extraConfig & ");" + + out = out & script(js) + + if not(returnOutput) then + response.write out + out = "" + end if + + replaceInstance = out + + oInstanceConfig.RemoveAll + oInstanceEvents.RemoveAll + end function + + '' + ' Replace all <textarea> elements available in the document with editor instances. + ' + ' @param className (string) If set, replace all textareas with class className in the page. + ' + ' Example 1: replace all <textarea> elements in the page. + ' @code + ' editor = new CKEditor + ' editor.replaceAll empty + ' @endcode + ' + ' Example 2: replace all <textarea class="myClassName"> elements in the page. + ' @code + ' editor = new CKEditor + ' editor.replaceAll 'myClassName' + ' @endcode + ' + function replaceAll(className) + dim out, js, customConfig + + out = "" + if not(initialized) then + out = out & init() + end if + + set customConfig = configSettings() + js = returnGlobalEvents() + + if (customConfig.Count=0) then + if (isEmpty(className)) then + js = js & "CKEDITOR.replaceAll();" + else + js = js & "CKEDITOR.replaceAll('" & className & "');" + end if + else + js = js & "CKEDITOR.replaceAll( function(textarea, config) {\n" + if not(isEmpty(className)) then + js = js & " var classRegex = new RegExp('(?:^| )' + '" & className & "' + '(?:$| )');\n" + js = js & " if (!classRegex.test(textarea.className))\n" + js = js & " return false;\n" + end if + js = js & " CKEDITOR.tools.extend(config, " & (new JSON)( empty, customConfig, false ) & ", true);" + js = js & "} );" + end if + + out = out & script(js) + + if not(returnOutput) then + response.write out + out = "" + end if + + replaceAll = out + + oInstanceConfig.RemoveAll + oInstanceEvents.RemoveAll + end function + + + '' + ' A Dictionary that holds the %CKEditor configuration for all instances + ' For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + ' + ' Example usage: + ' @code + ' editor.config("height") = 400 + ' // Use @@ at the beggining of a string to ouput it without surrounding quotes. + ' editor.config("width") = "@@screen.width * 0.8" + ' @endcode + Public Property Let Config( configKey, configValue ) + oAllInstancesConfig.Add configKey, configValue + End Property + + '' + ' Configuration options for the next instance + ' + Public Property Let instanceConfig( configKey, configValue ) + oInstanceConfig.Add configKey, configValue + End Property + + '' + ' Adds event listener. + ' Events are fired by %CKEditor in various situations. + ' + ' @param eventName (string) Event name. + ' @param javascriptCode (string) Javascript anonymous function or function name. + ' + ' Example usage: + ' @code + ' editor.addEventHandler "instanceReady", "function (ev) { " & _ + ' " alert('Loaded: ' + ev.editor.name); " & _ + ' "}" + ' @endcode + ' + public sub addEventHandler(eventName, javascriptCode) + if not(oAllInstancesEvents.Exists( eventName ) ) then + oAllInstancesEvents.Add eventName, Array() + end if + + dim listeners, size + listeners = oAllInstancesEvents( eventName ) + size = ubound(listeners) + 1 + redim preserve listeners(size) + listeners(size) = javascriptCode + + oAllInstancesEvents( eventName ) = listeners +' '' Avoid duplicates. fixme... +' if (!in_array($javascriptCode, $this->_events[$event])) { +' $this->_events[$event][] = $javascriptCode; +' } + end sub + + '' + ' Clear registered event handlers. + ' Note: this function will have no effect on already created editor instances. + ' + ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed. + ' + public sub clearEventHandlers( eventName ) + if not(isEmpty( eventName )) then + oAllInstancesEvents.Remove eventName + else + oAllInstancesEvents.RemoveAll + end if + end sub + + + '' + ' Adds event listener only for the next instance. + ' Events are fired by %CKEditor in various situations. + ' + ' @param eventName (string) Event name. + ' @param javascriptCode (string) Javascript anonymous function or function name. + ' + ' Example usage: + ' @code + ' editor.addInstanceEventHandler "instanceReady", "function (ev) { " & _ + ' " alert('Loaded: ' + ev.editor.name); " & _ + ' "}" + ' @endcode + ' + public sub addInstanceEventHandler(eventName, javascriptCode) + if not(oInstanceEvents.Exists( eventName ) ) then + oInstanceEvents.Add eventName, Array() + end if + + dim listeners, size + listeners = oInstanceEvents( eventName ) + size = ubound(listeners) + 1 + redim preserve listeners(size) + listeners(size) = javascriptCode + + oInstanceEvents( eventName ) = listeners +' '' Avoid duplicates. fixme... +' if (!in_array($javascriptCode, $this->_events[$event])) { +' $this->_events[$event][] = $javascriptCode; +' } + end sub + + '' + ' Clear registered event handlers. + ' Note: this function will have no effect on already created editor instances. + ' + ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed. + ' + public sub clearInstanceEventHandlers( eventName ) + if not(isEmpty( eventName )) then + oInstanceEvents.Remove eventName + else + oInstanceEvents.RemoveAll + end if + end sub + + '' + ' Adds global event listener. + ' + ' @param event (string) Event name. + ' @param javascriptCode (string) Javascript anonymous function or function name. + ' + ' Example usage: + ' @code + ' editor.addGlobalEventHandler "dialogDefinition", "function (ev) { " & _ + ' " alert('Loading dialog: ' + ev.data.name); " & _ + ' "}" + ' @endcode + ' + public sub addGlobalEventHandler( eventName, javascriptCode) + if not(oGlobalEvents.Exists( eventName ) ) then + oGlobalEvents.Add eventName, Array() + end if + + dim listeners, size + listeners = oGlobalEvents( eventName ) + size = ubound(listeners) + 1 + redim preserve listeners(size) + listeners(size) = javascriptCode + + oGlobalEvents( eventName ) = listeners + +' // Avoid duplicates. +' if (!in_array($javascriptCode, $this->_globalEvents[$event])) { +' $this->_globalEvents[$event][] = $javascriptCode; +' } + end sub + + '' + ' Clear registered global event handlers. + ' Note: this function will have no effect if the event handler has been already printed/returned. + ' + ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed . + ' + public sub clearGlobalEventHandlers( eventName ) + if not(isEmpty( eventName )) then + oGlobalEvents.Remove eventName + else + oGlobalEvents.RemoveAll + end if + end sub + + '' + ' Prints javascript code. + ' + ' @param string js + ' + private function script(js) + script = "" & vbcrlf + end function + + '' + ' Returns the configuration array (global and instance specific settings are merged into one array). + ' + ' @param instanceConfig (Dictionary) The specific configurations to apply to editor instance. + ' @param instanceEvents (Dictionary) Event listeners for editor instance. + ' + private function configSettings() + dim mergedConfig, mergedEvents + set mergedConfig = cloneDictionary(oAllInstancesConfig) + set mergedEvents = cloneDictionary(oAllInstancesEvents) + + if not(isEmpty(oInstanceConfig)) then + set mergedConfig = mergeDictionary(mergedConfig, oInstanceConfig) + end if + + if not(isEmpty(oInstanceEvents)) then + for each eventName in oInstanceEvents + code = oInstanceEvents( eventName ) + + if not(mergedEvents.Exists( eventName)) then + mergedEvents.Add eventName, code + else + + dim listeners, size + listeners = mergedEvents( eventName ) + size = ubound(listeners) + if isArray( code ) then + addedCount = ubound(code) + redim preserve listeners( size + addedCount + 1 ) + for i = 0 to addedCount + listeners(size + i + 1) = code (i) + next + else + size = size + 1 + redim preserve listeners(size) + listeners(size) = code + end if + + mergedEvents( eventName ) = listeners + end if + next + + end if + + dim i, eventName, handlers, configON, ub, code + + if mergedEvents.Count>0 then + if mergedConfig.Exists( "on" ) then + set configON = mergedConfig.items( "on" ) + else + set configON = CreateObject("Scripting.Dictionary") + mergedConfig.Add "on", configOn + end if + + for each eventName in mergedEvents + handlers = mergedEvents( eventName ) + code = "" + + if isArray(handlers) then + uB = ubound(handlers) + if (uB = 0) then + code = handlers(0) + else + code = "function (ev) {" + for i=0 to uB + code = code & "(" & handlers(i) & ")(ev);" + next + code = code & "}" + end if + else + code = handlers + end if + ' Using @@ at the beggining to signal JSON that we don't want this quoted. + configON.Add eventName, "@@" & code + next + +' set mergedConfig.Item("on") = configOn + end if + + set configSettings = mergedConfig + end function + + '' + ' Returns a copy of a scripting.dictionary object + ' + private function cloneDictionary( base ) + dim newOne, tmpKey + + Set newOne = CreateObject("Scripting.Dictionary") + for each tmpKey in base + newOne.Add tmpKey , base( tmpKey ) + next + + set cloneDictionary = newOne + end function + + '' + ' Combines two scripting.dictionary objects + ' The base object isn't modified, and extra gets all the properties in base + ' + private function mergeDictionary(base, extra) + dim newOne, tmpKey + + for each tmpKey in base + if not(extra.Exists( tmpKey )) then + extra.Add tmpKey, base( tmpKey ) + end if + next + + set mergeDictionary = extra + end function + + '' + ' Return global event handlers. + ' + private function returnGlobalEvents() + dim out, eventName, handlers + dim handlersForEvent, handler, code, i + out = "" + + if (isempty(CKEDITOR_returnedEvents)) then + set CKEDITOR_returnedEvents = CreateObject("Scripting.Dictionary") + end if + + for each eventName in oGlobalEvents + handlers = oGlobalEvents( eventName ) + + if not(CKEDITOR_returnedEvents.Exists(eventName)) then + CKEDITOR_returnedEvents.Add eventName, CreateObject("Scripting.Dictionary") + end if + + set handlersForEvent = CKEDITOR_returnedEvents.Item( eventName ) + + ' handlersForEvent is another dictionary + ' and handlers is an array + + for i = 0 to ubound(handlers) + code = handlers( i ) + + ' Return only new events + if not(handlersForEvent.Exists( code )) then + if (out <> "") then out = out & vbcrlf + out = out & "CKEDITOR.on('" & eventName & "', " & code & ");" + handlersForEvent.Add code, code + end if + next + next + + returnGlobalEvents = out + end function + + '' + ' Initializes CKEditor (executed only once). + ' + private function init() + dim out, args, path, extraCode, file + out = "" + + if (CKEDITOR_initComplete) then + init = "" + exit function + end if + + if (initialized) then + CKEDITOR_initComplete = true + init = "" + exit function + end if + + args = "" + path = ckeditorPath() + + if (timestamp <> "") and (timestamp <> "%" & "TIMESTAMP%") then + args = "?t=" & timestamp + end if + + ' Skip relative paths... + if (instr(path, "..") <> 0) then + out = out & script("window.CKEDITOR_BASEPATH='" & path & "';") + end if + + out = out & "" & vbcrlf + + extraCode = "" + if (timestamp <> mTimeStamp) then + extraCode = extraCode & "CKEDITOR.timestamp = '" & timestamp & "';" + end if + if (extraCode <> "") then + out = out & script(extraCode) + end if + + CKEDITOR_initComplete = true + initialized = true + + init = out + end function + + private function ckeditorFileName() + ckeditorFileName = "ckeditor.js" + end function + + '' + ' Return path to ckeditor.js. + ' + private function ckeditorPath() + if (basePath <> "") then + ckeditorPath = basePath + else + ' In classic ASP we can't get the location of this included script + ckeditorPath = "/ckeditor/" + end if + + ' Try to check if that folder contains the CKEditor files: + ' If it's a full URL avoid checking it as it might point to an external server. + if (instr(ckeditorPath, "://") <> 0) then exit function + + dim filename, oFSO, exists + filename = server.mapPath(basePath & ckeditorFileName()) + set oFSO = Server.CreateObject("Scripting.FileSystemObject") + exists = oFSO.FileExists(filename) + set oFSO = nothing + + if not(exists) then + response.clear + response.write "

CKEditor path validation failed

" + response.write "

The path "" & ckeditorPath & "" doesn't include the CKEditor main file (" & ckeditorFileName() & ")

" + response.write "

Please, verify that you have set it correctly and/or adjust the 'basePath' property

" + response.write "

Checked for physical file: "" & filename & ""

" + response.end + end if + end function + +End Class + + + +' URL: http://www.webdevbros.net/2007/04/26/generate-json-from-asp-datatypes/ +'************************************************************************************************************** +'' @CLASSTITLE: JSON +'' @CREATOR: Michal Gabrukiewicz (gabru at grafix.at), Michael Rebec +'' @CONTRIBUTORS: - Cliff Pruitt (opensource at crayoncowboy.com) +'' - Sylvain Lafontaine +'' - Jef Housein +'' - Jeremy Brown +'' @CREATEDON: 2007-04-26 12:46 +'' @CDESCRIPTION: Comes up with functionality for JSON (http://json.org) to use within ASP. +'' Correct escaping of characters, generating JSON Grammer out of ASP datatypes and structures +'' Some examples (all use the toJSON() method but as it is the class' default method it can be left out): +'' +'' <% +'' 'simple number +'' output = (new JSON)("myNum", 2, false) +'' 'generates {"myNum": 2} +'' +'' 'array with different datatypes +'' output = (new JSON)("anArray", array(2, "x", null), true) +'' 'generates "anArray": [2, "x", null] +'' '(note: the last parameter was true, thus no surrounding brackets in the result) +'' % > +'' +'' @REQUIRES: - +'' @OPTIONEXPLICIT: yes +'' @VERSION: 1.5.1 + +'************************************************************************************************************** +class JSON + + 'private members + private output, innerCall + + '********************************************************************************************************** + '* constructor + '********************************************************************************************************** + public sub class_initialize() + newGeneration() + end sub + + '****************************************************************************************** + '' @SDESCRIPTION: STATIC! takes a given string and makes it JSON valid + '' @DESCRIPTION: all characters which needs to be escaped are beeing replaced by their + '' unicode representation according to the + '' RFC4627#2.5 - http://www.ietf.org/rfc/rfc4627.txt?number=4627 + '' @PARAM: val [string]: value which should be escaped + '' @RETURN: [string] JSON valid string + '****************************************************************************************** + public function escape(val) + dim cDoubleQuote, cRevSolidus, cSolidus + cDoubleQuote = &h22 + cRevSolidus = &h5C + cSolidus = &h2F + dim i, currentDigit + for i = 1 to (len(val)) + currentDigit = mid(val, i, 1) + if ascw(currentDigit) > &h00 and ascw(currentDigit) < &h1F then + currentDigit = escapequence(currentDigit) + elseif ascw(currentDigit) >= &hC280 and ascw(currentDigit) <= &hC2BF then + currentDigit = "\u00" + right(padLeft(hex(ascw(currentDigit) - &hC200), 2, 0), 2) + elseif ascw(currentDigit) >= &hC380 and ascw(currentDigit) <= &hC3BF then + currentDigit = "\u00" + right(padLeft(hex(ascw(currentDigit) - &hC2C0), 2, 0), 2) + else + select case ascw(currentDigit) + case cDoubleQuote: currentDigit = escapequence(currentDigit) + case cRevSolidus: currentDigit = escapequence(currentDigit) + case cSolidus: currentDigit = escapequence(currentDigit) + end select + end if + escape = escape & currentDigit + next + end function + + '****************************************************************************************************************** + '' @SDESCRIPTION: generates a representation of a name value pair in JSON grammer + '' @DESCRIPTION: It generates a name value pair which is represented as {"name": value} in JSON. + '' the generation is fully recursive. Thus the value can also be a complex datatype (array in dictionary, etc.) e.g. + '' + '' <% + '' set j = new JSON + '' j.toJSON "n", array(RS, dict, false), false + '' j.toJSON "n", array(array(), 2, true), false + '' % > + '' + '' @PARAM: name [string]: name of the value (accessible with javascript afterwards). leave empty to get just the value + '' @PARAM: val [variant], [int], [float], [array], [object], [dictionary]: value which needs + '' to be generated. Conversation of the data types is as follows:
+ '' - ASP datatype -> JavaScript datatype + '' - NOTHING, NULL -> null + '' - INT, DOUBLE -> number + '' - STRING -> string + '' - BOOLEAN -> bool + '' - ARRAY -> array + '' - DICTIONARY -> Represents it as name value pairs. Each key is accessible as property afterwards. json will look like "name": {"key1": "some value", "key2": "other value"} + '' - multidimensional array -> Generates a 1-dimensional array (flat) with all values of the multidimensional array + '' - request object -> every property and collection (cookies, form, querystring, etc) of the asp request object is exposed as an item of a dictionary. Property names are lowercase. e.g. servervariables. + '' - OBJECT -> name of the type (if unknown type) or all its properties (if class implements reflect() method) + '' Implement a reflect() function if you want your custom classes to be recognized. The function must return + '' a dictionary where the key holds the property name and the value its value. Example of a reflect function within a User class which has firstname and lastname properties + '' + '' <% + '' function reflect() + '' . set reflect = server.createObject("scripting.dictionary") + '' . reflect.add "firstname", firstname + '' . reflect.add "lastname", lastname + '' end function + '' % > + '' + '' Example of how to generate a JSON representation of the asp request object and access the HTTP_HOST server variable in JavaScript: + '' + '' + '' + '' @PARAM: nested [bool]: indicates if the name value pair is already nested within another? if yes then the {} are left out. + '' @RETURN: [string] returns a JSON representation of the given name value pair + '****************************************************************************************************************** + public default function toJSON(name, val, nested) + if not nested and not isEmpty(name) then write("{") + if not isEmpty(name) then write("""" & escape(name) & """: ") + generateValue(val) + if not nested and not isEmpty(name) then write("}") + toJSON = output + + if innerCall = 0 then newGeneration() + end function + + '****************************************************************************************************************** + '* generate + '****************************************************************************************************************** + private function generateValue(val) + if isNull(val) then + write("null") + elseif isArray(val) then + generateArray(val) + elseif isObject(val) then + dim tName : tName = typename(val) + if val is nothing then + write("null") + elseif tName = "Dictionary" or tName = "IRequestDictionary" then + generateDictionary(val) + elseif tName = "IRequest" then + set req = server.createObject("scripting.dictionary") + req.add "clientcertificate", val.ClientCertificate + req.add "cookies", val.cookies + req.add "form", val.form + req.add "querystring", val.queryString + req.add "servervariables", val.serverVariables + req.add "totalbytes", val.totalBytes + generateDictionary(req) + elseif tName = "IStringList" then + if val.count = 1 then + toJSON empty, val(1), true + else + generateArray(val) + end if + else + generateObject(val) + end if + else + 'bool + dim varTyp + varTyp = varType(val) + if varTyp = 11 then + if val then write("true") else write("false") + 'int, long, byte + elseif varTyp = 2 or varTyp = 3 or varTyp = 17 or varTyp = 19 then + write(cLng(val)) + 'single, double, currency + elseif varTyp = 4 or varTyp = 5 or varTyp = 6 or varTyp = 14 then + write(replace(cDbl(val), ",", ".")) + else + ' Using @@ at the beggining to signal JSON that we don't want this quoted. + if left(val, 2) = "@@" then + write( mid( val, 3 ) ) + else + write("""" & escape(val & "") & """") + end if + end if + end if + generateValue = output + end function + + '****************************************************************************************************************** + '* generateArray + '****************************************************************************************************************** + private sub generateArray(val) + dim item, i + write("[") + i = 0 + 'the for each allows us to support also multi dimensional arrays + for each item in val + if i > 0 then write(",") + generateValue(item) + i = i + 1 + next + write("]") + end sub + + '****************************************************************************************************************** + '* generateDictionary + '****************************************************************************************************************** + private sub generateDictionary(val) + innerCall = innerCall + 1 + if val.count = 0 then + toJSON empty, null, true + exit sub + end if + dim key, i + write("{") + i = 0 + for each key in val + if i > 0 then write(",") + toJSON key, val(key), true + i = i + 1 + next + write("}") + innerCall = innerCall - 1 + end sub + + '****************************************************************************************************************** + '* generateObject + '****************************************************************************************************************** + private sub generateObject(val) + dim props + on error resume next + set props = val.reflect() + if err = 0 then + on error goto 0 + innerCall = innerCall + 1 + toJSON empty, props, true + innerCall = innerCall - 1 + else + on error goto 0 + write("""" & escape(typename(val)) & """") + end if + end sub + + '****************************************************************************************************************** + '* newGeneration + '****************************************************************************************************************** + private sub newGeneration() + output = empty + innerCall = 0 + end sub + + '****************************************************************************************** + '* JsonEscapeSquence + '****************************************************************************************** + private function escapequence(digit) + escapequence = "\u00" + right(padLeft(hex(ascw(digit)), 2, 0), 2) + end function + + '****************************************************************************************** + '* padLeft + '****************************************************************************************** + private function padLeft(value, totalLength, paddingChar) + padLeft = right(clone(paddingChar, totalLength) & value, totalLength) + end function + + '****************************************************************************************** + '* clone + '****************************************************************************************** + private function clone(byVal str, n) + dim i + for i = 1 to n : clone = clone & str : next + end function + + '****************************************************************************************** + '* write + '****************************************************************************************** + private sub write(val) + output = output & val + end sub + +end class +%> diff --git a/lib/ckeditor/ckeditor.php b/lib/ckeditor/ckeditor.php new file mode 100644 index 00000000..ee899736 --- /dev/null +++ b/lib/ckeditor/ckeditor.php @@ -0,0 +1,29 @@ +CKEditor web site to find more information about the editor. + * \section install_sec Installation + * \subsection step1 Include ckeditor.php in your PHP web site. + * @code + * + * @endcode + * \subsection step2 Create CKEditor class instance and use one of available methods to insert CKEditor. + * @code + * textarea("field1", "

Initial value.

"); + * ?> + * @endcode + */ + +if ( !function_exists('version_compare') || version_compare( phpversion(), '5', '<' ) ) + include_once( 'ckeditor_php4.php' ) ; +else + include_once( 'ckeditor_php5.php' ) ; diff --git a/lib/ckeditor/ckeditor_php4.php b/lib/ckeditor/ckeditor_php4.php new file mode 100644 index 00000000..14ea9548 --- /dev/null +++ b/lib/ckeditor/ckeditor_php4.php @@ -0,0 +1,566 @@ +editor("editor1", "

Initial value.

"); + * @endcode + */ +class CKEditor +{ + /** + * The version of %CKEditor. + * \private + */ + var $version = '3.6.2'; + /** + * A constant string unique for each release of %CKEditor. + * \private + */ + var $_timestamp = 'B8DJ5M3'; + + /** + * URL to the %CKEditor installation directory (absolute or relative to document root). + * If not set, CKEditor will try to guess it's path. + * + * Example usage: + * @code + * $CKEditor->basePath = '/ckeditor/'; + * @endcode + */ + var $basePath; + /** + * An array that holds the global %CKEditor configuration. + * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + * + * Example usage: + * @code + * $CKEditor->config['height'] = 400; + * // Use @@ at the beggining of a string to ouput it without surrounding quotes. + * $CKEditor->config['width'] = '@@screen.width * 0.8'; + * @endcode + */ + var $config = array(); + /** + * A boolean variable indicating whether CKEditor has been initialized. + * Set it to true only if you have already included + * <script> tag loading ckeditor.js in your website. + */ + var $initialized = false; + /** + * Boolean variable indicating whether created code should be printed out or returned by a function. + * + * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->returnOutput = true; + * $code = $CKEditor->editor("editor1", "

Initial value.

"); + * echo "

Editor 1:

"; + * echo $code; + * @endcode + */ + var $returnOutput = false; + /** + * An array with textarea attributes. + * + * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + * it will be displayed to anyone with JavaScript disabled or with incompatible browser. + */ + var $textareaAttributes = array( "rows" => 8, "cols" => 60 ); + /** + * A string indicating the creation date of %CKEditor. + * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + */ + var $timestamp = "B8DJ5M3"; + /** + * An array that holds event listeners. + * \private + */ + var $_events = array(); + /** + * An array that holds global event listeners. + * \private + */ + var $_globalEvents = array(); + + /** + * Main Constructor. + * + * @param $basePath (string) URL to the %CKEditor installation directory (optional). + */ + function CKEditor($basePath = null) { + if (!empty($basePath)) { + $this->basePath = $basePath; + } + } + + /** + * Creates a %CKEditor instance. + * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + * + * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + * @param $value (string) Initial value (optional). + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example usage: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->editor("field1", "

Initial value.

"); + * @endcode + * + * Advanced example: + * @code + * $CKEditor = new CKEditor(); + * $config = array(); + * $config['toolbar'] = array( + * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), + * array( 'Image', 'Link', 'Unlink', 'Anchor' ) + * ); + * $events['instanceReady'] = 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'; + * $CKEditor->editor("field1", "

Initial value.

", $config, $events); + * @endcode + */ + function editor($name, $value = "", $config = array(), $events = array()) + { + $attr = ""; + foreach ($this->textareaAttributes as $key => $val) { + $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; + } + $out = "\n"; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) + $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; + else + $js .= "CKEDITOR.replace('".$name."');"; + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replaces a <textarea> with a %CKEditor instance. + * + * @param $id (string) The id or name of textarea element. + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replace("article"); + * @endcode + */ + function replace($id, $config = array(), $events = array()) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) { + $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; + } + else { + $js .= "CKEDITOR.replace('".$id."');"; + } + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replace all <textarea> elements available in the document with editor instances. + * + * @param $className (string) If set, replace all textareas with class className in the page. + * + * Example 1: replace all <textarea> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll(); + * @endcode + * + * Example 2: replace all <textarea class="myClassName"> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll( 'myClassName' ); + * @endcode + */ + function replaceAll($className = null) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings(); + + $js = $this->returnGlobalEvents(); + if (empty($_config)) { + if (empty($className)) { + $js .= "CKEDITOR.replaceAll();"; + } + else { + $js .= "CKEDITOR.replaceAll('".$className."');"; + } + } + else { + $classDetection = ""; + $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; + if (!empty($className)) { + $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; + $js .= " if (!classRegex.test(textarea.className))\n"; + $js .= " return false;\n"; + } + $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; + $js .= "} );"; + + } + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Adds event listener. + * Events are fired by %CKEditor in various situations. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addEventHandler('instanceReady', 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'); + * @endcode + */ + function addEventHandler($event, $javascriptCode) + { + if (!isset($this->_events[$event])) { + $this->_events[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->_events[$event])) { + $this->_events[$event][] = $javascriptCode; + } + } + + /** + * Clear registered event handlers. + * Note: this function will have no effect on already created editor instances. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + function clearEventHandlers($event = null) + { + if (!empty($event)) { + $this->_events[$event] = array(); + } + else { + $this->_events = array(); + } + } + + /** + * Adds global event listener. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { + * alert("Loading dialog: " + ev.data.name); + * }'); + * @endcode + */ + function addGlobalEventHandler($event, $javascriptCode) + { + if (!isset($this->_globalEvents[$event])) { + $this->_globalEvents[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->_globalEvents[$event])) { + $this->_globalEvents[$event][] = $javascriptCode; + } + } + + /** + * Clear registered global event handlers. + * Note: this function will have no effect if the event handler has been already printed/returned. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + function clearGlobalEventHandlers($event = null) + { + if (!empty($event)) { + $this->_globalEvents[$event] = array(); + } + else { + $this->_globalEvents = array(); + } + } + + /** + * Prints javascript code. + * \private + * + * @param string $js + */ + function script($js) + { + $out = "\n"; + + return $out; + } + + /** + * Returns the configuration array (global and instance specific settings are merged into one array). + * \private + * + * @param $config (array) The specific configurations to apply to editor instance. + * @param $events (array) Event listeners for editor instance. + */ + function configSettings($config = array(), $events = array()) + { + $_config = $this->config; + $_events = $this->_events; + + if (is_array($config) && !empty($config)) { + $_config = array_merge($_config, $config); + } + + if (is_array($events) && !empty($events)) { + foreach ($events as $eventName => $code) { + if (!isset($_events[$eventName])) { + $_events[$eventName] = array(); + } + if (!in_array($code, $_events[$eventName])) { + $_events[$eventName][] = $code; + } + } + } + + if (!empty($_events)) { + foreach($_events as $eventName => $handlers) { + if (empty($handlers)) { + continue; + } + else if (count($handlers) == 1) { + $_config['on'][$eventName] = '@@'.$handlers[0]; + } + else { + $_config['on'][$eventName] = '@@function (ev){'; + foreach ($handlers as $handler => $code) { + $_config['on'][$eventName] .= '('.$code.')(ev);'; + } + $_config['on'][$eventName] .= '}'; + } + } + } + + return $_config; + } + + /** + * Return global event handlers. + * \private + */ + function returnGlobalEvents() + { + static $returnedEvents; + $out = ""; + + if (!isset($returnedEvents)) { + $returnedEvents = array(); + } + + if (!empty($this->_globalEvents)) { + foreach ($this->_globalEvents as $eventName => $handlers) { + foreach ($handlers as $handler => $code) { + if (!isset($returnedEvents[$eventName])) { + $returnedEvents[$eventName] = array(); + } + // Return only new events + if (!in_array($code, $returnedEvents[$eventName])) { + $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; + $returnedEvents[$eventName][] = $code; + } + } + } + } + + return $out; + } + + /** + * Initializes CKEditor (executed only once). + * \private + */ + function init() + { + static $initComplete; + $out = ""; + + if (!empty($initComplete)) { + return ""; + } + + if ($this->initialized) { + $initComplete = true; + return ""; + } + + $args = ""; + $ckeditorPath = $this->ckeditorPath(); + + if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { + $args = '?t=' . $this->timestamp; + } + + // Skip relative paths... + if (strpos($ckeditorPath, '..') !== 0) { + $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); + } + + $out .= "\n"; + + $extraCode = ""; + if ($this->timestamp != $this->_timestamp) { + $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; + } + if ($extraCode) { + $out .= $this->script($extraCode); + } + + $initComplete = $this->initialized = true; + + return $out; + } + + /** + * Return path to ckeditor.js. + * \private + */ + function ckeditorPath() + { + if (!empty($this->basePath)) { + return $this->basePath; + } + + /** + * The absolute pathname of the currently executing script. + * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, + * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. + */ + if (isset($_SERVER['SCRIPT_FILENAME'])) { + $realPath = dirname($_SERVER['SCRIPT_FILENAME']); + } + else { + /** + * realpath - Returns canonicalized absolute pathname + */ + $realPath = realpath( './' ) ; + } + + /** + * The filename of the currently executing script, relative to the document root. + * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar + * would be /test.php/foo.bar. + */ + $selfPath = dirname($_SERVER['PHP_SELF']); + $file = str_replace("\\", "/", __FILE__); + + if (!$selfPath || !$realPath || !$file) { + return "/ckeditor/"; + } + + $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); + $fileUrl = substr($file, strlen($documentRoot)); + $ckeditorUrl = str_replace("ckeditor_php4.php", "", $fileUrl); + + return $ckeditorUrl; + } + + /** + * This little function provides a basic JSON support. + * \private + * + * @param mixed $val + * @return string + */ + function jsEncode($val) + { + if (is_null($val)) { + return 'null'; + } + if (is_bool($val)) { + return $val ? 'true' : 'false'; + } + if (is_int($val)) { + return $val; + } + if (is_float($val)) { + return str_replace(',', '.', $val); + } + if (is_array($val) || is_object($val)) { + if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { + return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; + } + $temp = array(); + foreach ($val as $k => $v){ + $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); + } + return '{' . implode(',', $temp) . '}'; + } + // String otherwise + if (strpos($val, '@@') === 0) + return substr($val, 2); + if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') + return $val; + + return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; + } +} diff --git a/lib/ckeditor/ckeditor_php5.php b/lib/ckeditor/ckeditor_php5.php new file mode 100644 index 00000000..2b72cf19 --- /dev/null +++ b/lib/ckeditor/ckeditor_php5.php @@ -0,0 +1,556 @@ +editor("editor1", "

Initial value.

"); + * @endcode + */ +class CKEditor +{ + /** + * The version of %CKEditor. + */ + const version = '3.6.2'; + /** + * A constant string unique for each release of %CKEditor. + */ + const timestamp = 'B8DJ5M3'; + + /** + * URL to the %CKEditor installation directory (absolute or relative to document root). + * If not set, CKEditor will try to guess it's path. + * + * Example usage: + * @code + * $CKEditor->basePath = '/ckeditor/'; + * @endcode + */ + public $basePath; + /** + * An array that holds the global %CKEditor configuration. + * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + * + * Example usage: + * @code + * $CKEditor->config['height'] = 400; + * // Use @@ at the beggining of a string to ouput it without surrounding quotes. + * $CKEditor->config['width'] = '@@screen.width * 0.8'; + * @endcode + */ + public $config = array(); + /** + * A boolean variable indicating whether CKEditor has been initialized. + * Set it to true only if you have already included + * <script> tag loading ckeditor.js in your website. + */ + public $initialized = false; + /** + * Boolean variable indicating whether created code should be printed out or returned by a function. + * + * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->returnOutput = true; + * $code = $CKEditor->editor("editor1", "

Initial value.

"); + * echo "

Editor 1:

"; + * echo $code; + * @endcode + */ + public $returnOutput = false; + /** + * An array with textarea attributes. + * + * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + * it will be displayed to anyone with JavaScript disabled or with incompatible browser. + */ + public $textareaAttributes = array( "rows" => 8, "cols" => 60 ); + /** + * A string indicating the creation date of %CKEditor. + * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + */ + public $timestamp = "B8DJ5M3"; + /** + * An array that holds event listeners. + */ + private $events = array(); + /** + * An array that holds global event listeners. + */ + private $globalEvents = array(); + + /** + * Main Constructor. + * + * @param $basePath (string) URL to the %CKEditor installation directory (optional). + */ + function __construct($basePath = null) { + if (!empty($basePath)) { + $this->basePath = $basePath; + } + } + + /** + * Creates a %CKEditor instance. + * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + * + * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + * @param $value (string) Initial value (optional). + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example usage: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->editor("field1", "

Initial value.

"); + * @endcode + * + * Advanced example: + * @code + * $CKEditor = new CKEditor(); + * $config = array(); + * $config['toolbar'] = array( + * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), + * array( 'Image', 'Link', 'Unlink', 'Anchor' ) + * ); + * $events['instanceReady'] = 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'; + * $CKEditor->editor("field1", "

Initial value.

", $config, $events); + * @endcode + */ + public function editor($name, $value = "", $config = array(), $events = array()) + { + $attr = ""; + foreach ($this->textareaAttributes as $key => $val) { + $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; + } + $out = "\n"; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) + $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; + else + $js .= "CKEDITOR.replace('".$name."');"; + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replaces a <textarea> with a %CKEditor instance. + * + * @param $id (string) The id or name of textarea element. + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replace("article"); + * @endcode + */ + public function replace($id, $config = array(), $events = array()) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) { + $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; + } + else { + $js .= "CKEDITOR.replace('".$id."');"; + } + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replace all <textarea> elements available in the document with editor instances. + * + * @param $className (string) If set, replace all textareas with class className in the page. + * + * Example 1: replace all <textarea> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll(); + * @endcode + * + * Example 2: replace all <textarea class="myClassName"> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll( 'myClassName' ); + * @endcode + */ + public function replaceAll($className = null) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings(); + + $js = $this->returnGlobalEvents(); + if (empty($_config)) { + if (empty($className)) { + $js .= "CKEDITOR.replaceAll();"; + } + else { + $js .= "CKEDITOR.replaceAll('".$className."');"; + } + } + else { + $classDetection = ""; + $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; + if (!empty($className)) { + $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; + $js .= " if (!classRegex.test(textarea.className))\n"; + $js .= " return false;\n"; + } + $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; + $js .= "} );"; + + } + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Adds event listener. + * Events are fired by %CKEditor in various situations. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addEventHandler('instanceReady', 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'); + * @endcode + */ + public function addEventHandler($event, $javascriptCode) + { + if (!isset($this->events[$event])) { + $this->events[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->events[$event])) { + $this->events[$event][] = $javascriptCode; + } + } + + /** + * Clear registered event handlers. + * Note: this function will have no effect on already created editor instances. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearEventHandlers($event = null) + { + if (!empty($event)) { + $this->events[$event] = array(); + } + else { + $this->events = array(); + } + } + + /** + * Adds global event listener. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { + * alert("Loading dialog: " + ev.data.name); + * }'); + * @endcode + */ + public function addGlobalEventHandler($event, $javascriptCode) + { + if (!isset($this->globalEvents[$event])) { + $this->globalEvents[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->globalEvents[$event])) { + $this->globalEvents[$event][] = $javascriptCode; + } + } + + /** + * Clear registered global event handlers. + * Note: this function will have no effect if the event handler has been already printed/returned. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearGlobalEventHandlers($event = null) + { + if (!empty($event)) { + $this->globalEvents[$event] = array(); + } + else { + $this->globalEvents = array(); + } + } + + /** + * Prints javascript code. + * + * @param string $js + */ + private function script($js) + { + $out = "\n"; + + return $out; + } + + /** + * Returns the configuration array (global and instance specific settings are merged into one array). + * + * @param $config (array) The specific configurations to apply to editor instance. + * @param $events (array) Event listeners for editor instance. + */ + private function configSettings($config = array(), $events = array()) + { + $_config = $this->config; + $_events = $this->events; + + if (is_array($config) && !empty($config)) { + $_config = array_merge($_config, $config); + } + + if (is_array($events) && !empty($events)) { + foreach ($events as $eventName => $code) { + if (!isset($_events[$eventName])) { + $_events[$eventName] = array(); + } + if (!in_array($code, $_events[$eventName])) { + $_events[$eventName][] = $code; + } + } + } + + if (!empty($_events)) { + foreach($_events as $eventName => $handlers) { + if (empty($handlers)) { + continue; + } + else if (count($handlers) == 1) { + $_config['on'][$eventName] = '@@'.$handlers[0]; + } + else { + $_config['on'][$eventName] = '@@function (ev){'; + foreach ($handlers as $handler => $code) { + $_config['on'][$eventName] .= '('.$code.')(ev);'; + } + $_config['on'][$eventName] .= '}'; + } + } + } + + return $_config; + } + + /** + * Return global event handlers. + */ + private function returnGlobalEvents() + { + static $returnedEvents; + $out = ""; + + if (!isset($returnedEvents)) { + $returnedEvents = array(); + } + + if (!empty($this->globalEvents)) { + foreach ($this->globalEvents as $eventName => $handlers) { + foreach ($handlers as $handler => $code) { + if (!isset($returnedEvents[$eventName])) { + $returnedEvents[$eventName] = array(); + } + // Return only new events + if (!in_array($code, $returnedEvents[$eventName])) { + $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; + $returnedEvents[$eventName][] = $code; + } + } + } + } + + return $out; + } + + /** + * Initializes CKEditor (executed only once). + */ + private function init() + { + static $initComplete; + $out = ""; + + if (!empty($initComplete)) { + return ""; + } + + if ($this->initialized) { + $initComplete = true; + return ""; + } + + $args = ""; + $ckeditorPath = $this->ckeditorPath(); + + if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") { + $args = '?t=' . $this->timestamp; + } + + // Skip relative paths... + if (strpos($ckeditorPath, '..') !== 0) { + $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); + } + + $out .= "\n"; + + $extraCode = ""; + if ($this->timestamp != self::timestamp) { + $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; + } + if ($extraCode) { + $out .= $this->script($extraCode); + } + + $initComplete = $this->initialized = true; + + return $out; + } + + /** + * Return path to ckeditor.js. + */ + private function ckeditorPath() + { + if (!empty($this->basePath)) { + return $this->basePath; + } + + /** + * The absolute pathname of the currently executing script. + * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, + * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. + */ + if (isset($_SERVER['SCRIPT_FILENAME'])) { + $realPath = dirname($_SERVER['SCRIPT_FILENAME']); + } + else { + /** + * realpath - Returns canonicalized absolute pathname + */ + $realPath = realpath( './' ) ; + } + + /** + * The filename of the currently executing script, relative to the document root. + * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar + * would be /test.php/foo.bar. + */ + $selfPath = dirname($_SERVER['PHP_SELF']); + $file = str_replace("\\", "/", __FILE__); + + if (!$selfPath || !$realPath || !$file) { + return "/ckeditor/"; + } + + $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); + $fileUrl = substr($file, strlen($documentRoot)); + $ckeditorUrl = str_replace("ckeditor_php5.php", "", $fileUrl); + + return $ckeditorUrl; + } + + /** + * This little function provides a basic JSON support. + * + * @param mixed $val + * @return string + */ + private function jsEncode($val) + { + if (is_null($val)) { + return 'null'; + } + if (is_bool($val)) { + return $val ? 'true' : 'false'; + } + if (is_int($val)) { + return $val; + } + if (is_float($val)) { + return str_replace(',', '.', $val); + } + if (is_array($val) || is_object($val)) { + if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { + return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; + } + $temp = array(); + foreach ($val as $k => $v){ + $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); + } + return '{' . implode(',', $temp) . '}'; + } + // String otherwise + if (strpos($val, '@@') === 0) + return substr($val, 2); + if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') + return $val; + + return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; + } +}