JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.3.2
[ckeditor.git] / ckeditor.asp
1 <%\r
2  '\r
3  ' Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
4  ' For licensing, see LICENSE.html or http://ckeditor.com/license\r
5 \r
6 ' Shared variable for all instances ("static")\r
7 dim CKEDITOR_initComplete\r
8 dim CKEDITOR_returnedEvents\r
9 \r
10  ''\r
11  ' \brief CKEditor class that can be used to create editor\r
12  ' instances in ASP pages on server side.\r
13  ' @see http://ckeditor.com\r
14  '\r
15  ' Sample usage:\r
16  ' @code\r
17  ' editor = new CKEditor\r
18  ' editor.editor "editor1", "<p>Initial value.</p>", empty, empty\r
19  ' @endcode\r
20 \r
21 Class CKEditor\r
22 \r
23         ''\r
24         ' The version of %CKEditor.\r
25         private version\r
26 \r
27         ''\r
28         ' A constant string unique for each release of %CKEditor.\r
29         private mTimeStamp\r
30 \r
31         ''\r
32         ' URL to the %CKEditor installation directory (absolute or relative to document root).\r
33         ' If not set, CKEditor will try to guess it's path.\r
34         '\r
35         ' Example usage:\r
36         ' @code\r
37         ' editor.basePath = "/ckeditor/"\r
38         ' @endcode\r
39         Public basePath\r
40 \r
41         ''\r
42         ' A boolean variable indicating whether CKEditor has been initialized.\r
43         ' Set it to true only if you have already included\r
44         ' &lt;script&gt; tag loading ckeditor.js in your website.\r
45         Public initialized\r
46 \r
47         ''\r
48         ' Boolean variable indicating whether created code should be printed out or returned by a function.\r
49         '\r
50         ' Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function.\r
51         ' @code\r
52         ' editor = new CKEditor\r
53         ' editor.returnOutput = true\r
54         ' code = editor.editor("editor1", "<p>Initial value.</p>", empty, empty)\r
55         ' response.write "<p>Editor 1:</p>"\r
56         ' response.write code\r
57         ' @endcode\r
58         Public returnOutput\r
59 \r
60         ''\r
61         ' A Dictionary with textarea attributes.\r
62         '\r
63         ' When %CKEditor is created with the editor() method, a HTML &lt;textarea&gt; element is created,\r
64         ' it will be displayed to anyone with JavaScript disabled or with incompatible browser.\r
65         public textareaAttributes\r
66 \r
67         ''\r
68         ' A string indicating the creation date of %CKEditor.\r
69         ' Do not change it unless you want to force browsers to not use previously cached version of %CKEditor.\r
70         public timestamp\r
71 \r
72         ''\r
73         ' A dictionary that holds the instance configuration.\r
74         private oInstanceConfig\r
75 \r
76         ''\r
77         ' A dictionary that holds the configuration for all the instances.\r
78         private oAllInstancesConfig\r
79 \r
80         ''\r
81         ' A dictionary that holds event listeners for the instance.\r
82         private oInstanceEvents\r
83 \r
84         ''\r
85         ' A dictionary that holds event listeners for all the instances.\r
86         private oAllInstancesEvents\r
87 \r
88         ''\r
89         ' A Dictionary that holds global event listeners (CKEDITOR object)\r
90         private oGlobalEvents\r
91 \r
92 \r
93         Private Sub Class_Initialize()\r
94                 version = "3.3.2"\r
95                 timeStamp = "A73H4H9"\r
96                 mTimeStamp = "A73H4H9"\r
97 \r
98                 Set oInstanceConfig = CreateObject("Scripting.Dictionary")\r
99                 Set oAllInstancesConfig = CreateObject("Scripting.Dictionary")\r
100 \r
101                 Set oInstanceEvents = CreateObject("Scripting.Dictionary")\r
102                 Set oAllInstancesEvents = CreateObject("Scripting.Dictionary")\r
103                 Set oGlobalEvents = CreateObject("Scripting.Dictionary")\r
104 \r
105                 Set textareaAttributes = CreateObject("Scripting.Dictionary")\r
106                 textareaAttributes.Add "rows", 8\r
107                 textareaAttributes.Add "cols", 60\r
108         End Sub\r
109 \r
110         ''\r
111          ' Creates a %CKEditor instance.\r
112          ' In incompatible browsers %CKEditor will downgrade to plain HTML &lt;textarea&gt; element.\r
113          '\r
114          ' @param name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element).\r
115          ' @param value (string) Initial value.\r
116          '\r
117          ' Example usage:\r
118          ' @code\r
119          ' set editor = New CKEditor\r
120          ' editor.editor "field1", "<p>Initial value.</p>"\r
121          ' @endcode\r
122          '\r
123          ' Advanced example:\r
124          ' @code\r
125          ' set editor = new CKEditor\r
126          ' set config = CreateObject("Scripting.Dictionary")\r
127          ' config.Add "toolbar", Array( _\r
128          '      Array( "Source", "-", "Bold", "Italic", "Underline", "Strike" ), _\r
129          '      Array( "Image", "Link", "Unlink", "Anchor" ) _\r
130          ' )\r
131          ' set events = CreateObject("Scripting.Dictionary")\r
132          ' events.Add "instanceReady", "function (evt) { alert('Loaded second editor: ' + evt.editor.name );}"\r
133 \r
134          ' editor.editor "field1", "<p>Initial value.</p>", config, events\r
135          ' @endcode\r
136          '\r
137         public function editor(name, value)\r
138                 dim attr, out, js, customConfig, extraConfig\r
139                 dim attribute\r
140 \r
141                 attr = ""\r
142 \r
143                 for each attribute in textareaAttributes\r
144                         attr = attr & " " &  attribute & "=""" & replace( textareaAttributes( attribute ), """", "&quot" ) & """"\r
145                 next\r
146 \r
147                 out = "<textarea name=""" & name & """" & attr & ">" & Server.HtmlEncode(value) & "</textarea>" & vbcrlf\r
148 \r
149                 if not(initialized) then\r
150                         out = out & init()\r
151                 end if\r
152 \r
153                 set customConfig = configSettings()\r
154                 js = returnGlobalEvents()\r
155 \r
156                 extraConfig = (new JSON)( empty, customConfig, false )\r
157                 if extraConfig<>"" then extraConfig = ", " & extraConfig\r
158                 js = js & "CKEDITOR.replace('" & name & "'" & extraConfig & ");"\r
159 \r
160                 out = out & script(js)\r
161 \r
162                 if not(returnOutput) then\r
163                         response.write out\r
164                         out = ""\r
165                 end if\r
166 \r
167                 editor = out\r
168 \r
169                 oInstanceConfig.RemoveAll\r
170                 oInstanceEvents.RemoveAll\r
171         end function\r
172 \r
173         ''\r
174          ' Replaces a &lt;textarea&gt; with a %CKEditor instance.\r
175          '\r
176          ' @param id (string) The id or name of textarea element.\r
177          '\r
178          ' Example 1: adding %CKEditor to &lt;textarea name="article"&gt;&lt;/textarea&gt; element:\r
179          ' @code\r
180          ' set editor = New CKEditor\r
181          ' editor.replace "article"\r
182          ' @endcode\r
183          '\r
184         public function replaceInstance(id)\r
185                 dim out, js, customConfig, extraConfig\r
186 \r
187                 out = ""\r
188                 if not(initialized) then\r
189                         out = out & init()\r
190                 end if\r
191 \r
192                 set customConfig = configSettings()\r
193                 js = returnGlobalEvents()\r
194 \r
195                 extraConfig = (new JSON)( empty, customConfig, false )\r
196                 if extraConfig<>"" then extraConfig = ", " & extraConfig\r
197                 js = js & "CKEDITOR.replace('" & id & "'" & extraConfig & ");"\r
198 \r
199                 out = out & script(js)\r
200 \r
201                 if not(returnOutput) then\r
202                         response.write out\r
203                         out = ""\r
204                 end if\r
205 \r
206                 replaceInstance = out\r
207 \r
208                 oInstanceConfig.RemoveAll\r
209                 oInstanceEvents.RemoveAll\r
210         end function\r
211 \r
212         ''\r
213          ' Replace all &lt;textarea&gt; elements available in the document with editor instances.\r
214          '\r
215          ' @param className (string) If set, replace all textareas with class className in the page.\r
216          '\r
217          ' Example 1: replace all &lt;textarea&gt; elements in the page.\r
218          ' @code\r
219          ' editor = new CKEditor\r
220          ' editor.replaceAll empty\r
221          ' @endcode\r
222          '\r
223          ' Example 2: replace all &lt;textarea class="myClassName"&gt; elements in the page.\r
224          ' @code\r
225          ' editor = new CKEditor\r
226          ' editor.replaceAll 'myClassName'\r
227          ' @endcode\r
228          '\r
229         function replaceAll(className)\r
230                 dim out, js, customConfig\r
231 \r
232                 out = ""\r
233                 if not(initialized) then\r
234                         out = out & init()\r
235                 end if\r
236 \r
237                 set customConfig = configSettings()\r
238                 js = returnGlobalEvents()\r
239 \r
240                 if (customConfig.Count=0) then\r
241                         if (isEmpty(className)) then\r
242                                 js = js & "CKEDITOR.replaceAll();"\r
243                         else\r
244                                 js = js & "CKEDITOR.replaceAll('" & className & "');"\r
245                         end if\r
246                 else\r
247                         js = js & "CKEDITOR.replaceAll( function(textarea, config) {\n"\r
248                         if not(isEmpty(className)) then\r
249                                 js = js & "     var classRegex = new RegExp('(?:^| )' + '" & className & "' + '(?:$| )');\n"\r
250                                 js = js & "     if (!classRegex.test(textarea.className))\n"\r
251                                 js = js & "             return false;\n"\r
252                         end if\r
253                         js = js & "     CKEDITOR.tools.extend(config, " & (new JSON)( empty, customConfig, false ) & ", true);"\r
254                         js = js & "} );"\r
255                 end if\r
256 \r
257                 out = out & script(js)\r
258 \r
259                 if not(returnOutput) then\r
260                         response.write out\r
261                         out = ""\r
262                 end if\r
263 \r
264                 replaceAll = out\r
265 \r
266                 oInstanceConfig.RemoveAll\r
267                 oInstanceEvents.RemoveAll\r
268         end function\r
269 \r
270 \r
271         ''\r
272         ' A Dictionary that holds the %CKEditor configuration for all instances\r
273         ' For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html\r
274         '\r
275         ' Example usage:\r
276         ' @code\r
277         ' editor.config("height") = 400\r
278         ' // Use @@ at the beggining of a string to ouput it without surrounding quotes.\r
279         ' editor.config("width") = "@@screen.width * 0.8"\r
280         ' @endcode\r
281         Public Property Let Config( configKey, configValue )\r
282                 oAllInstancesConfig.Add configKey, configValue\r
283         End Property\r
284 \r
285         ''\r
286         ' Configuration options for the next instance\r
287         '\r
288         Public Property Let instanceConfig( configKey, configValue )\r
289                 oInstanceConfig.Add configKey, configValue\r
290         End Property\r
291 \r
292         ''\r
293          ' Adds event listener.\r
294          ' Events are fired by %CKEditor in various situations.\r
295          '\r
296          ' @param eventName (string) Event name.\r
297          ' @param javascriptCode (string) Javascript anonymous function or function name.\r
298          '\r
299          ' Example usage:\r
300          ' @code\r
301          ' editor.addEventHandler  "instanceReady", "function (ev) { " & _\r
302          '    " alert('Loaded: ' + ev.editor.name); " & _\r
303          ' "}"\r
304          ' @endcode\r
305          '\r
306         public sub addEventHandler(eventName, javascriptCode)\r
307                 if not(oAllInstancesEvents.Exists( eventName ) ) then\r
308                         oAllInstancesEvents.Add eventName, Array()\r
309                 end if\r
310 \r
311                 dim listeners, size\r
312                 listeners = oAllInstancesEvents( eventName )\r
313                 size = ubound(listeners) + 1\r
314                 redim preserve listeners(size)\r
315                 listeners(size) = javascriptCode\r
316 \r
317                 oAllInstancesEvents( eventName ) = listeners\r
318 '               '' Avoid duplicates. fixme...\r
319 '               if (!in_array($javascriptCode, $this->_events[$event])) {\r
320 '                       $this->_events[$event][] = $javascriptCode;\r
321 '               }\r
322         end sub\r
323 \r
324         ''\r
325          ' Clear registered event handlers.\r
326          ' Note: this function will have no effect on already created editor instances.\r
327          '\r
328          ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed.\r
329          '\r
330         public sub clearEventHandlers( eventName )\r
331                 if not(isEmpty( eventName )) then\r
332                         oAllInstancesEvents.Remove eventName\r
333                 else\r
334                         oAllInstancesEvents.RemoveAll\r
335                 end if\r
336         end sub\r
337 \r
338 \r
339         ''\r
340          ' Adds event listener only for the next instance.\r
341          ' Events are fired by %CKEditor in various situations.\r
342          '\r
343          ' @param eventName (string) Event name.\r
344          ' @param javascriptCode (string) Javascript anonymous function or function name.\r
345          '\r
346          ' Example usage:\r
347          ' @code\r
348          ' editor.addInstanceEventHandler  "instanceReady", "function (ev) { " & _\r
349          '    " alert('Loaded: ' + ev.editor.name); " & _\r
350          ' "}"\r
351          ' @endcode\r
352          '\r
353         public sub addInstanceEventHandler(eventName, javascriptCode)\r
354                 if not(oInstanceEvents.Exists( eventName ) ) then\r
355                         oInstanceEvents.Add eventName, Array()\r
356                 end if\r
357 \r
358                 dim listeners, size\r
359                 listeners = oInstanceEvents( eventName )\r
360                 size = ubound(listeners) + 1\r
361                 redim preserve listeners(size)\r
362                 listeners(size) = javascriptCode\r
363 \r
364                 oInstanceEvents( eventName ) = listeners\r
365 '               '' Avoid duplicates. fixme...\r
366 '               if (!in_array($javascriptCode, $this->_events[$event])) {\r
367 '                       $this->_events[$event][] = $javascriptCode;\r
368 '               }\r
369         end sub\r
370 \r
371         ''\r
372          ' Clear registered event handlers.\r
373          ' Note: this function will have no effect on already created editor instances.\r
374          '\r
375          ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed.\r
376          '\r
377         public sub clearInstanceEventHandlers( eventName )\r
378                 if not(isEmpty( eventName )) then\r
379                         oInstanceEvents.Remove eventName\r
380                 else\r
381                         oInstanceEvents.RemoveAll\r
382                 end if\r
383         end sub\r
384 \r
385         ''\r
386          ' Adds global event listener.\r
387          '\r
388          ' @param event (string) Event name.\r
389          ' @param javascriptCode (string) Javascript anonymous function or function name.\r
390          '\r
391          ' Example usage:\r
392          ' @code\r
393          ' editor.addGlobalEventHandler "dialogDefinition", "function (ev) { " & _\r
394          '   "  alert('Loading dialog: ' + ev.data.name); " & _\r
395          ' "}"\r
396          ' @endcode\r
397          '\r
398         public sub addGlobalEventHandler( eventName, javascriptCode)\r
399                 if not(oGlobalEvents.Exists( eventName ) ) then\r
400                         oGlobalEvents.Add eventName, Array()\r
401                 end if\r
402 \r
403                 dim listeners, size\r
404                 listeners = oGlobalEvents( eventName )\r
405                 size = ubound(listeners) + 1\r
406                 redim preserve listeners(size)\r
407                 listeners(size) = javascriptCode\r
408 \r
409                 oGlobalEvents( eventName ) = listeners\r
410 \r
411 '               // Avoid duplicates.\r
412 '               if (!in_array($javascriptCode, $this->_globalEvents[$event])) {\r
413 '                       $this->_globalEvents[$event][] = $javascriptCode;\r
414 '               }\r
415         end sub\r
416 \r
417         ''\r
418          ' Clear registered global event handlers.\r
419          ' Note: this function will have no effect if the event handler has been already printed/returned.\r
420          '\r
421          ' @param eventName (string) Event name, if set to 'empty' all event handlers will be removed .\r
422          '\r
423         public sub clearGlobalEventHandlers( eventName )\r
424                 if not(isEmpty( eventName )) then\r
425                         oGlobalEvents.Remove eventName\r
426                 else\r
427                         oGlobalEvents.RemoveAll\r
428                 end if\r
429         end sub\r
430 \r
431         ''\r
432          ' Prints javascript code.\r
433          '\r
434          ' @param string js\r
435          '\r
436         private function script(js)\r
437                 script = "<script type=""text/javascript"">" & _\r
438                         "//<![CDATA[" & vbcrlf & _\r
439                         js & vbcrlf & _\r
440                         "//]]>" & _\r
441                         "</script>" & vbcrlf\r
442         end function\r
443 \r
444         ''\r
445          ' Returns the configuration array (global and instance specific settings are merged into one array).\r
446          '\r
447          ' @param instanceConfig (Dictionary) The specific configurations to apply to editor instance.\r
448          ' @param instanceEvents (Dictionary) Event listeners for editor instance.\r
449          '\r
450         private function configSettings()\r
451                 dim mergedConfig, mergedEvents\r
452                 set mergedConfig = cloneDictionary(oAllInstancesConfig)\r
453                 set mergedEvents = cloneDictionary(oAllInstancesEvents)\r
454 \r
455                 if not(isEmpty(oInstanceConfig)) then\r
456                         set mergedConfig = mergeDictionary(mergedConfig, oInstanceConfig)\r
457                 end if\r
458 \r
459                 if not(isEmpty(oInstanceEvents)) then\r
460                         for each eventName in oInstanceEvents\r
461                                 code = oInstanceEvents( eventName )\r
462 \r
463                                 if not(mergedEvents.Exists( eventName)) then\r
464                                         mergedEvents.Add eventName, code\r
465                                 else\r
466 \r
467                                         dim listeners, size\r
468                                         listeners = mergedEvents( eventName )\r
469                                         size = ubound(listeners)\r
470                                         if isArray( code ) then\r
471                                                 addedCount = ubound(code)\r
472                                                 redim preserve listeners( size + addedCount + 1 )\r
473                                                 for i = 0 to addedCount\r
474                                                         listeners(size + i + 1) = code (i)\r
475                                                 next\r
476                                         else\r
477                                                 size = size + 1\r
478                                                 redim preserve listeners(size)\r
479                                                 listeners(size) = code\r
480                                         end if\r
481 \r
482                                         mergedEvents( eventName ) = listeners\r
483                                 end if\r
484                         next\r
485 \r
486                 end if\r
487 \r
488                 dim i, eventName, handlers, configON, ub, code\r
489 \r
490                 if mergedEvents.Count>0 then\r
491                         if mergedConfig.Exists( "on" ) then\r
492                                 set configON = mergedConfig.items( "on" )\r
493                         else\r
494                                 set configON = CreateObject("Scripting.Dictionary")\r
495                                 mergedConfig.Add "on", configOn\r
496                         end if\r
497 \r
498                         for each eventName in mergedEvents\r
499                                 handlers = mergedEvents( eventName )\r
500                                 code = ""\r
501 \r
502                                 if isArray(handlers) then\r
503                                         uB = ubound(handlers)\r
504                                         if (uB = 0) then\r
505                                                 code = handlers(0)\r
506                                         else\r
507                                                 code = "function (ev) {"\r
508                                                 for i=0 to uB\r
509                                                         code = code & "(" & handlers(i) & ")(ev);"\r
510                                                 next\r
511                                                 code = code & "}"\r
512                                         end if\r
513                                 else\r
514                                         code = handlers\r
515                                 end if\r
516                                 ' Using @@ at the beggining to signal JSON that we don't want this quoted.\r
517                                 configON.Add eventName, "@@" & code\r
518                         next\r
519 \r
520 '                       set mergedConfig.Item("on") = configOn\r
521                 end if\r
522 \r
523                 set configSettings = mergedConfig\r
524         end function\r
525 \r
526          ''\r
527                 ' Returns a copy of a scripting.dictionary object\r
528                 '\r
529         private function cloneDictionary( base )\r
530                 dim newOne, tmpKey\r
531 \r
532                 Set newOne = CreateObject("Scripting.Dictionary")\r
533                 for each tmpKey in base\r
534                         newOne.Add tmpKey , base( tmpKey )\r
535                 next\r
536 \r
537                 set cloneDictionary = newOne\r
538         end function\r
539 \r
540          ''\r
541                 ' Combines two scripting.dictionary objects\r
542                 ' The base object isn't modified, and extra gets all the properties in base\r
543                 '\r
544         private function mergeDictionary(base, extra)\r
545                 dim newOne, tmpKey\r
546 \r
547                 for each tmpKey in base\r
548                         if not(extra.Exists( tmpKey )) then\r
549                                 extra.Add tmpKey, base( tmpKey )\r
550                         end if\r
551                 next\r
552 \r
553                 set mergeDictionary = extra\r
554         end function\r
555 \r
556         ''\r
557          ' Return global event handlers.\r
558          '\r
559         private function returnGlobalEvents()\r
560                 dim out, eventName, handlers\r
561                 dim handlersForEvent, handler, code, i\r
562                 out = ""\r
563 \r
564                 if (isempty(CKEDITOR_returnedEvents)) then\r
565                         set CKEDITOR_returnedEvents = CreateObject("Scripting.Dictionary")\r
566                 end if\r
567 \r
568                 for each eventName in oGlobalEvents\r
569                         handlers = oGlobalEvents( eventName )\r
570 \r
571                         if not(CKEDITOR_returnedEvents.Exists(eventName)) then\r
572                                 CKEDITOR_returnedEvents.Add eventName, CreateObject("Scripting.Dictionary")\r
573                         end if\r
574 \r
575                                 set handlersForEvent = CKEDITOR_returnedEvents.Item( eventName )\r
576 \r
577                                 ' handlersForEvent is another dictionary\r
578                                 ' and handlers is an array\r
579 \r
580                                 for i = 0 to ubound(handlers)\r
581                                         code = handlers( i )\r
582 \r
583                                         ' Return only new events\r
584                                         if not(handlersForEvent.Exists( code )) then\r
585                                                 if (out <> "") then out = out & vbcrlf\r
586                                                 out = out & "CKEDITOR.on('" &  eventName & "', " & code & ");"\r
587                                                 handlersForEvent.Add code, code\r
588                                         end if\r
589                                 next\r
590                 next\r
591 \r
592                 returnGlobalEvents = out\r
593         end function\r
594 \r
595         ''\r
596          ' Initializes CKEditor (executed only once).\r
597          '\r
598         private function init()\r
599                 dim out, args, path, extraCode, file\r
600                 out = ""\r
601 \r
602                 if (CKEDITOR_initComplete) then\r
603                         init = ""\r
604                         exit function\r
605                 end if\r
606 \r
607                 if (initialized) then\r
608                         CKEDITOR_initComplete = true\r
609                         init = ""\r
610                         exit function\r
611                 end if\r
612 \r
613                 args = ""\r
614                 path = ckeditorPath()\r
615 \r
616                 if (timestamp <> "") and (timestamp <> "%" & "TIMESTAMP%") then\r
617                         args = "?t=" & timestamp\r
618                 end if\r
619 \r
620                 ' Skip relative paths...\r
621                 if (instr(path, "..") <> 0) then\r
622                         out = out & script("window.CKEDITOR_BASEPATH='" &  path  & "';")\r
623                 end if\r
624 \r
625                 out = out & "<scr" & "ipt type=""text/javascript"" src=""" & path & ckeditorFileName() & args & """></scr" & "ipt>" & vbcrlf\r
626 \r
627                 extraCode = ""\r
628                 if (timestamp <> mTimeStamp) then\r
629                         extraCode = extraCode & "CKEDITOR.timestamp = '" & timestamp & "';"\r
630                 end if\r
631                 if (extraCode <> "") then\r
632                         out = out & script(extraCode)\r
633                 end if\r
634 \r
635                 CKEDITOR_initComplete = true\r
636                 initialized = true\r
637 \r
638                 init = out\r
639         end function\r
640 \r
641         private function ckeditorFileName()\r
642                 ckeditorFileName = "ckeditor.js"\r
643         end function\r
644 \r
645         ''\r
646          ' Return path to ckeditor.js.\r
647          '\r
648         private function ckeditorPath()\r
649                 if (basePath <> "") then\r
650                         ckeditorPath = basePath\r
651                 else\r
652                         ' In classic ASP we can't get the location of this included script\r
653                         ckeditorPath = "/ckeditor/"\r
654                 end if\r
655 \r
656                 ' Try to check if that folder contains the CKEditor files:\r
657                 ' If it's a full URL avoid checking it as it might point to an external server.\r
658                 if (instr(ckeditorPath, "://") <> 0) then exit function\r
659 \r
660                 dim filename, oFSO, exists\r
661                 filename = server.mapPath(basePath & ckeditorFileName())\r
662                 set oFSO = Server.CreateObject("Scripting.FileSystemObject")\r
663                 exists = oFSO.FileExists(filename)\r
664                 set oFSO = nothing\r
665 \r
666                 if not(exists) then\r
667                         response.clear\r
668                         response.write "<h1>CKEditor path validation failed</h1>"\r
669                         response.write "<p>The path &quot;" & ckeditorPath & "&quot; doesn't include the CKEditor main file (" & ckeditorFileName() & ")</p>"\r
670                         response.write "<p>Please, verify that you have set it correctly and/or adjust the 'basePath' property</p>"\r
671                         response.write "<p>Checked for physical file: &quot;" & filename & "&quot;</p>"\r
672                         response.end\r
673                 end if\r
674         end function\r
675 \r
676 End Class\r
677 \r
678 \r
679 \r
680 ' URL: http://www.webdevbros.net/2007/04/26/generate-json-from-asp-datatypes/\r
681 '**************************************************************************************************************\r
682 '' @CLASSTITLE:         JSON\r
683 '' @CREATOR:            Michal Gabrukiewicz (gabru at grafix.at), Michael Rebec\r
684 '' @CONTRIBUTORS:       - Cliff Pruitt (opensource at crayoncowboy.com)\r
685 ''                                      - Sylvain Lafontaine\r
686 ''                                      - Jef Housein\r
687 ''                                      - Jeremy Brown\r
688 '' @CREATEDON:          2007-04-26 12:46\r
689 '' @CDESCRIPTION:       Comes up with functionality for JSON (http://json.org) to use within ASP.\r
690 ''                                      Correct escaping of characters, generating JSON Grammer out of ASP datatypes and structures\r
691 ''                                      Some examples (all use the <em>toJSON()</em> method but as it is the class' default method it can be left out):\r
692 ''                                      <code>\r
693 ''                                      <%\r
694 ''                                      'simple number\r
695 ''                                      output = (new JSON)("myNum", 2, false)\r
696 ''                                      'generates {"myNum": 2}\r
697 ''\r
698 ''                                      'array with different datatypes\r
699 ''                                      output = (new JSON)("anArray", array(2, "x", null), true)\r
700 ''                                      'generates "anArray": [2, "x", null]\r
701 ''                                      '(note: the last parameter was true, thus no surrounding brackets in the result)\r
702 ''                                      % >\r
703 ''                                      </code>\r
704 '' @REQUIRES:           -\r
705 '' @OPTIONEXPLICIT:     yes\r
706 '' @VERSION:            1.5.1\r
707 \r
708 '**************************************************************************************************************\r
709 class JSON\r
710 \r
711         'private members\r
712         private output, innerCall\r
713 \r
714         '**********************************************************************************************************\r
715         '* constructor\r
716         '**********************************************************************************************************\r
717         public sub class_initialize()\r
718                 newGeneration()\r
719         end sub\r
720 \r
721         '******************************************************************************************\r
722         '' @SDESCRIPTION:       STATIC! takes a given string and makes it JSON valid\r
723         '' @DESCRIPTION:        all characters which needs to be escaped are beeing replaced by their\r
724         ''                                      unicode representation according to the\r
725         ''                                      RFC4627#2.5 - http://www.ietf.org/rfc/rfc4627.txt?number=4627\r
726         '' @PARAM:                      val [string]: value which should be escaped\r
727         '' @RETURN:                     [string] JSON valid string\r
728         '******************************************************************************************\r
729         public function escape(val)\r
730                 dim cDoubleQuote, cRevSolidus, cSolidus\r
731                 cDoubleQuote = &h22\r
732                 cRevSolidus = &h5C\r
733                 cSolidus = &h2F\r
734                 dim i, currentDigit\r
735                 for i = 1 to (len(val))\r
736                         currentDigit = mid(val, i, 1)\r
737                         if ascw(currentDigit) > &h00 and ascw(currentDigit) < &h1F then\r
738                                 currentDigit = escapequence(currentDigit)\r
739                         elseif ascw(currentDigit) >= &hC280 and ascw(currentDigit) <= &hC2BF then\r
740                                 currentDigit = "\u00" + right(padLeft(hex(ascw(currentDigit) - &hC200), 2, 0), 2)\r
741                         elseif ascw(currentDigit) >= &hC380 and ascw(currentDigit) <= &hC3BF then\r
742                                 currentDigit = "\u00" + right(padLeft(hex(ascw(currentDigit) - &hC2C0), 2, 0), 2)\r
743                         else\r
744                                 select case ascw(currentDigit)\r
745                                         case cDoubleQuote: currentDigit = escapequence(currentDigit)\r
746                                         case cRevSolidus: currentDigit = escapequence(currentDigit)\r
747                                         case cSolidus: currentDigit = escapequence(currentDigit)\r
748                                 end select\r
749                         end if\r
750                         escape = escape & currentDigit\r
751                 next\r
752         end function\r
753 \r
754         '******************************************************************************************************************\r
755         '' @SDESCRIPTION:       generates a representation of a name value pair in JSON grammer\r
756         '' @DESCRIPTION:        It generates a name value pair which is represented as <em>{"name": value}</em> in JSON.\r
757         ''                                      the generation is fully recursive. Thus the value can also be a complex datatype (array in dictionary, etc.) e.g.\r
758         ''                                      <code>\r
759         ''                                      <%\r
760         ''                                      set j = new JSON\r
761         ''                                      j.toJSON "n", array(RS, dict, false), false\r
762         ''                                      j.toJSON "n", array(array(), 2, true), false\r
763         ''                                      % >\r
764         ''                                      </code>\r
765         '' @PARAM:                      name [string]: name of the value (accessible with javascript afterwards). leave empty to get just the value\r
766         '' @PARAM:                      val [variant], [int], [float], [array], [object], [dictionary]: value which needs\r
767         ''                                      to be generated. Conversation of the data types is as follows:<br>\r
768         ''                                      - <strong>ASP datatype -> JavaScript datatype</strong>\r
769         ''                                      - NOTHING, NULL -> null\r
770         ''                                      - INT, DOUBLE -> number\r
771         ''                                      - STRING -> string\r
772         ''                                      - BOOLEAN -> bool\r
773         ''                                      - ARRAY -> array\r
774         ''                                      - DICTIONARY -> Represents it as name value pairs. Each key is accessible as property afterwards. json will look like <code>"name": {"key1": "some value", "key2": "other value"}</code>\r
775         ''                                      - <em>multidimensional array</em> -> Generates a 1-dimensional array (flat) with all values of the multidimensional array\r
776         ''                                      - <em>request</em> 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 <strong>lowercase</strong>. e.g. <em>servervariables</em>.\r
777         ''                                      - OBJECT -> name of the type (if unknown type) or all its properties (if class implements <em>reflect()</em> method)\r
778         ''                                      Implement a <strong>reflect()</strong> function if you want your custom classes to be recognized. The function must return\r
779         ''                                      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\r
780         ''                                      <code>\r
781         ''                                      <%\r
782         ''                                      function reflect()\r
783         ''                                      .       set reflect = server.createObject("scripting.dictionary")\r
784         ''                                      .       reflect.add "firstname", firstname\r
785         ''                                      .       reflect.add "lastname", lastname\r
786         ''                                      end function\r
787         ''                                      % >\r
788         ''                                      </code>\r
789         ''                                      Example of how to generate a JSON representation of the asp request object and access the <em>HTTP_HOST</em> server variable in JavaScript:\r
790         ''                                      <code>\r
791         ''                                      <script>alert(<%= (new JSON)(empty, request, false) % >.servervariables.HTTP_HOST);</script>\r
792         ''                                      </code>\r
793         '' @PARAM:                      nested [bool]: indicates if the name value pair is already nested within another? if yes then the <em>{}</em> are left out.\r
794         '' @RETURN:                     [string] returns a JSON representation of the given name value pair\r
795         '******************************************************************************************************************\r
796         public default function toJSON(name, val, nested)\r
797                 if not nested and not isEmpty(name) then write("{")\r
798                 if not isEmpty(name) then write("""" & escape(name) & """: ")\r
799                 generateValue(val)\r
800                 if not nested and not isEmpty(name) then write("}")\r
801                 toJSON = output\r
802 \r
803                 if innerCall = 0 then newGeneration()\r
804         end function\r
805 \r
806         '******************************************************************************************************************\r
807         '* generate\r
808         '******************************************************************************************************************\r
809         private function generateValue(val)\r
810                 if isNull(val) then\r
811                         write("null")\r
812                 elseif isArray(val) then\r
813                         generateArray(val)\r
814                 elseif isObject(val) then\r
815                         dim tName : tName = typename(val)\r
816                         if val is nothing then\r
817                                 write("null")\r
818                         elseif tName = "Dictionary" or tName = "IRequestDictionary" then\r
819                                 generateDictionary(val)\r
820                         elseif tName = "IRequest" then\r
821                                 set req = server.createObject("scripting.dictionary")\r
822                                 req.add "clientcertificate", val.ClientCertificate\r
823                                 req.add "cookies", val.cookies\r
824                                 req.add "form", val.form\r
825                                 req.add "querystring", val.queryString\r
826                                 req.add "servervariables", val.serverVariables\r
827                                 req.add "totalbytes", val.totalBytes\r
828                                 generateDictionary(req)\r
829                         elseif tName = "IStringList" then\r
830                                 if val.count = 1 then\r
831                                         toJSON empty, val(1), true\r
832                                 else\r
833                                         generateArray(val)\r
834                                 end if\r
835                         else\r
836                                 generateObject(val)\r
837                         end if\r
838                 else\r
839                         'bool\r
840                         dim varTyp\r
841                         varTyp = varType(val)\r
842                         if varTyp = 11 then\r
843                                 if val then write("true") else write("false")\r
844                         'int, long, byte\r
845                         elseif varTyp = 2 or varTyp = 3 or varTyp = 17 or varTyp = 19 then\r
846                                 write(cLng(val))\r
847                         'single, double, currency\r
848                         elseif varTyp = 4 or varTyp = 5 or varTyp = 6 or varTyp = 14 then\r
849                                 write(replace(cDbl(val), ",", "."))\r
850                         else\r
851                                 ' Using @@ at the beggining to signal JSON that we don't want this quoted.\r
852                                 if left(val, 2) = "@@" then\r
853                                         write( mid( val, 3 ) )\r
854                                 else\r
855                                         write("""" & escape(val & "") & """")\r
856                                 end if\r
857                         end if\r
858                 end if\r
859                 generateValue = output\r
860         end function\r
861 \r
862         '******************************************************************************************************************\r
863         '* generateArray\r
864         '******************************************************************************************************************\r
865         private sub generateArray(val)\r
866                 dim item, i\r
867                 write("[")\r
868                 i = 0\r
869                 'the for each allows us to support also multi dimensional arrays\r
870                 for each item in val\r
871                         if i > 0 then write(",")\r
872                         generateValue(item)\r
873                         i = i + 1\r
874                 next\r
875                 write("]")\r
876         end sub\r
877 \r
878         '******************************************************************************************************************\r
879         '* generateDictionary\r
880         '******************************************************************************************************************\r
881         private sub generateDictionary(val)\r
882                 innerCall = innerCall + 1\r
883                 if val.count = 0 then\r
884                         toJSON empty, null, true\r
885                         exit sub\r
886                 end if\r
887                 dim key, i\r
888                 write("{")\r
889                 i = 0\r
890                 for each key in val\r
891                         if i > 0 then write(",")\r
892                         toJSON key, val(key), true\r
893                         i = i + 1\r
894                 next\r
895                 write("}")\r
896                 innerCall = innerCall - 1\r
897         end sub\r
898 \r
899         '******************************************************************************************************************\r
900         '* generateObject\r
901         '******************************************************************************************************************\r
902         private sub generateObject(val)\r
903                 dim props\r
904                 on error resume next\r
905                 set props = val.reflect()\r
906                 if err = 0 then\r
907                         on error goto 0\r
908                         innerCall = innerCall + 1\r
909                         toJSON empty, props, true\r
910                         innerCall = innerCall - 1\r
911                 else\r
912                         on error goto 0\r
913                         write("""" & escape(typename(val)) & """")\r
914                 end if\r
915         end sub\r
916 \r
917         '******************************************************************************************************************\r
918         '* newGeneration\r
919         '******************************************************************************************************************\r
920         private sub newGeneration()\r
921                 output = empty\r
922                 innerCall = 0\r
923         end sub\r
924 \r
925         '******************************************************************************************\r
926         '* JsonEscapeSquence\r
927         '******************************************************************************************\r
928         private function escapequence(digit)\r
929                 escapequence = "\u00" + right(padLeft(hex(ascw(digit)), 2, 0), 2)\r
930         end function\r
931 \r
932         '******************************************************************************************\r
933         '* padLeft\r
934         '******************************************************************************************\r
935         private function padLeft(value, totalLength, paddingChar)\r
936                 padLeft = right(clone(paddingChar, totalLength) & value, totalLength)\r
937         end function\r
938 \r
939         '******************************************************************************************\r
940         '* clone\r
941         '******************************************************************************************\r
942         private function clone(byVal str, n)\r
943                 dim i\r
944                 for i = 1 to n : clone = clone & str : next\r
945         end function\r
946 \r
947         '******************************************************************************************\r
948         '* write\r
949         '******************************************************************************************\r
950         private sub write(val)\r
951                 output = output & val\r
952         end sub\r
953 \r
954 end class\r
955 %>\r