X-Git-Url: https://scm.cri.ensmp.fr/git/ckeditor.git/blobdiff_plain/256592bf803e851aa7fc953e08a6e9e58d970f8c..871bad8291b6dbc29d489d95d185458caab25158:/skins/ckeditor/ckeditor.asp diff --git a/skins/ckeditor/ckeditor.asp b/skins/ckeditor/ckeditor.asp new file mode 100644 index 0000000..33b9f55 --- /dev/null +++ b/skins/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.1" + timeStamp = "B5GJ5GG" + mTimeStamp = "B5GJ5GG" + + 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 & "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:"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
+%>