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