home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 139 / dpcs0999.iso / Web / CFserver / data1.cab / JavaScript / scripts / wddx.js
Encoding:
JavaScript  |  1999-04-12  |  16.1 KB  |  619 lines

  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. //    Filename:        wddx.js
  4. //
  5. //    Authors:        Simeon Simeonov (simeons@allaire.com)
  6. //                    Nate Weiss (nweiss@icesinc.com)
  7. //
  8. //    Last Modified:    March 5, 1999
  9. //
  10. ///////////////////////////////////////////////////////////////////////////
  11.  
  12.  
  13. ///////////////////////////////////////////////////////////////////////////
  14. //
  15. //    WddxSerializer
  16. //
  17. ///////////////////////////////////////////////////////////////////////////
  18.  
  19.  
  20. ///////////////////////////////////////////////////////////////////////////
  21. //     serializeValue() serializes any value that can be serialized
  22. //    returns true/false
  23. function wddxSerializer_serializeValue(obj)
  24. {
  25.     var bSuccess = true;
  26.  
  27.     if (typeof(obj) == "string")
  28.     {
  29.         // String value
  30.         this.serializeString(obj);
  31.     }
  32.     else if (typeof(obj) == "number")
  33.     {
  34.         // Number value
  35.         this.write("<number>" + obj + "</number>");
  36.     }
  37.     else if (typeof(obj) == "boolean")
  38.     {
  39.         // Boolean value
  40.         this.write("<boolean value='" + obj + "'/>");
  41.     }
  42.     else if (typeof(obj) == "object")
  43.     {
  44.         if (obj == null)
  45.         {
  46.             // Null values become empty strings
  47.             this.write("<string></string>");
  48.         }
  49.         else if (typeof(obj.wddxSerialize) == "function")
  50.         {
  51.             // Object knows how to serialize itself
  52.             bSuccess = obj.wddxSerialize(this);
  53.         }
  54.         else if (
  55.             typeof(obj.join) == "function" &&
  56.             typeof(obj.reverse) == "function" &&
  57.             typeof(obj.sort) == "function" &&
  58.             typeof(obj.length) == "number")
  59.         {
  60.             this.write("<array length='" + obj.length + "'>");
  61.             for (var i = 0; bSuccess && i < obj.length; ++i)
  62.             {
  63.                 bSuccess = this.serializeValue(obj[i]);
  64.             }
  65.             this.write("</array>");
  66.         }
  67.         else if (
  68.             typeof(obj.getTimezoneOffset) == "function" &&
  69.             typeof(obj.toGMTString) == "function")
  70.         {
  71.             // Possible Date
  72.             this.write(    "<dateTime>" + 
  73.                 (obj.getYear() < 100 ? 1900+obj.getYear() : obj.getYear()) + "-" + (obj.getMonth() + 1) + "-" + obj.getDate() +
  74.                 "T" + obj.getHours() + ":" + obj.getMinutes() + ":" + obj.getSeconds());
  75.             if (this.useTimezoneInfo)
  76.             {
  77.                 this.write(this.timezoneString);
  78.             }
  79.             this.write("</dateTime>");
  80.         }
  81.         else
  82.         {
  83.             // Some generic object; treat it as a structure
  84.             // Use the wddxSerializationType property as a guide as to its type
  85.             
  86.             if (typeof(obj.wddxSerializationType) == 'string')
  87.             {              
  88.                 this.write('<struct type="'+ obj.wddxSerializationType +'">')
  89.             }  
  90.             else
  91.             {                                                       
  92.                 this.write("<struct>");
  93.             }
  94.                         
  95.             for (var prop in obj)
  96.             {  
  97.                 if (prop != 'wddxSerializationType')
  98.                 {                          
  99.                     bSuccess = this.serializeVariable(prop, obj[prop]);
  100.                     if (! bSuccess)
  101.                     {
  102.                         break;
  103.                     }
  104.                 }
  105.             }
  106.             
  107.             this.write("</struct>");
  108.         }
  109.     }
  110.     else
  111.     {
  112.         // Error: undefined values or functions
  113.         bSuccess = false;
  114.     }
  115.  
  116.     // Successful serialization
  117.     return bSuccess;
  118. }
  119.  
  120.  
  121. ///////////////////////////////////////////////////////////////////////////
  122. //     serializeString() serializes a string using JavaScript functionality
  123. //    available in NS 3.0 and above
  124. function wddxSerializer_serializeString(s)
  125. {
  126.     this.write("<string>");
  127.     for (var i = 0; i < s.length; ++i)
  128.     {
  129.         this.write(this.et[s.charAt(i)]);
  130.     }
  131.     this.write("</string>");
  132. }
  133.  
  134.  
  135. ///////////////////////////////////////////////////////////////////////////
  136. //     serializeStringOld() serializes a string using JavaScript functionality
  137. //    available in IE 3.0
  138. function wddxSerializer_serializeStringOld(s)
  139. {
  140.     this.write("<string><![CDATA[");
  141.     
  142.     pos = s.indexOf("]]>");
  143.     if (pos != -1)
  144.     {
  145.         startPos = 0;
  146.         while (pos != -1)
  147.         {
  148.             this.write(s.substring(startPos, pos) + "]]>]]><![CDATA[");
  149.             
  150.             startPos = pos + 3;
  151.             if (startPos < s.length)
  152.             {
  153.                 pos = s.indexOf("]]>", startPos);
  154.             }
  155.             else
  156.             {
  157.                 // Work around bug in indexOf()
  158.                 // "" will be returned instead of -1 if startPos > length
  159.                 pos = -1;
  160.             }                               
  161.         }
  162.         this.write(s.substring(startPos, s.length));
  163.     }
  164.     else
  165.     {
  166.         this.write(s);
  167.     }
  168.             
  169.     this.write("]]></string>");
  170. }
  171.  
  172.  
  173. ///////////////////////////////////////////////////////////////////////////
  174. //     serializeVariable() serializes a property of a structure
  175. //    returns true/false
  176. function wddxSerializer_serializeVariable(name, obj)
  177. {
  178.     var bSuccess = true;
  179.     
  180.     if (typeof(obj) != "function")
  181.     {
  182.         this.write("<var name='" + (this.preserveVarCase ? name : name.toLowerCase()) + "'>");
  183.         bSuccess = this.serializeValue(obj);
  184.         this.write("</var>");
  185.     }
  186.  
  187.     return bSuccess;
  188. }
  189.  
  190.  
  191. ///////////////////////////////////////////////////////////////////////////
  192. //    write() appends text to the wddxPacket buffer
  193. function wddxSerializer_write(str)
  194. {
  195.     this.wddxPacket += str;
  196. }
  197.  
  198.  
  199. ///////////////////////////////////////////////////////////////////////////
  200. //    serialize() creates a WDDX packet for a given object
  201. //    returns the packet on success or null on failure
  202. function wddxSerializer_serialize(rootObj)
  203. {
  204.     this.wddxPacket = "";
  205.  
  206.     this.write("<wddxPacket version='0.9'><header/><data>");
  207.     var bSuccess = this.serializeValue(rootObj);
  208.     this.write("</data></wddxPacket>");
  209.  
  210.     if (bSuccess)
  211.     {
  212.         return this.wddxPacket;
  213.     }
  214.     else
  215.     {    
  216.         return null;
  217.     }
  218. }
  219.  
  220.  
  221. ///////////////////////////////////////////////////////////////////////////
  222. // WddxSerializer() binds the function properties of the object
  223. function WddxSerializer()
  224. {
  225.     // Compatibility section
  226.     if (navigator.appVersion != "" && navigator.appVersion.indexOf("MSIE 3.") == -1)
  227.     {
  228.         // Character encoding table
  229.         
  230.         // Encoding table    
  231.         var et = new Array();
  232.     
  233.         // Numbers to characters table and 
  234.         // characters to numbers table
  235.         var n2c = new Array();
  236.         var c2n = new Array();
  237.     
  238.         for (var i = 0; i < 256; ++i)
  239.         {
  240.             // Build a character from octal code
  241.             var d1 = Math.floor(i/64);
  242.             var d2 = Math.floor((i%64)/8);
  243.             var d3 = i%8;
  244.             var c = eval("\"\\" + d1.toString(10) + d2.toString(10) + d3.toString(10) + "\"");
  245.     
  246.             // Modify character-code conversion tables        
  247.             n2c[i] = c;
  248.             c2n[c] = i; 
  249.             
  250.             // Modify encoding table
  251.             if (i < 32 && i != 9 && i != 10 && i != 13)
  252.             {
  253.                 // Control characters that are not tabs, newlines, and carriage returns
  254.                 
  255.                 // Create a two-character hex code representation
  256.                 var hex = i.toString(16);
  257.                 if (hex.length == 1)
  258.                 {
  259.                     hex = "0" + hex;
  260.                 }
  261.                 
  262.                 et[n2c[i]] = "<char code='" + hex + "'/>";
  263.             }
  264.             else if (i < 128)
  265.             {
  266.                 // Low characters that are not special control characters
  267.                 et[n2c[i]] = n2c[i];
  268.             }
  269.             else
  270.             {
  271.                 // High characters
  272.                 et[n2c[i]] = "&#x" + i.toString(16) + ";";
  273.             }
  274.         }    
  275.     
  276.         // Special escapes
  277.         et["<"] = "<";
  278.         et[">"] = ">";
  279.         et["&"] = "&";
  280.         
  281.         // Store tables
  282.         this.n2c = n2c;
  283.         this.c2n = c2n;
  284.         this.et = et;    
  285.         
  286.            // The browser is not MSIE 3.x
  287.         this.serializeString = wddxSerializer_serializeString;
  288.     }
  289.     else
  290.     {
  291.         // The browser is most likely MSIE 3.x, it is NS 2.0 compatible
  292.         this.serializeString = wddxSerializer_serializeStringOld;
  293.     }
  294.     
  295.     // Setup timezone information
  296.     
  297.     var tzOffset = (new Date()).getTimezoneOffset();
  298.  
  299.     // Invert timezone offset to convert local time to UTC time
  300.     if (tzOffset >= 0)
  301.     {
  302.         this.timezoneString = '-';
  303.     }
  304.     else
  305.     {
  306.         this.timezoneString = '+';
  307.     }
  308.     this.timezoneString += Math.floor(Math.abs(tzOffset) / 60) + ":" + (Math.abs(tzOffset) % 60);
  309.     
  310.     // Common properties
  311.     this.preserveVarCase = false;
  312.     this.useTimezoneInfo = true;
  313.  
  314.     // Common functions
  315.     this.serialize = wddxSerializer_serialize;
  316.     this.serializeValue = wddxSerializer_serializeValue;
  317.     this.serializeVariable = wddxSerializer_serializeVariable;
  318.     this.write = wddxSerializer_write;
  319. }
  320.  
  321.  
  322. ///////////////////////////////////////////////////////////////////////////
  323. //
  324. //    WddxRecordset
  325. //
  326. ///////////////////////////////////////////////////////////////////////////
  327.  
  328.  
  329. ///////////////////////////////////////////////////////////////////////////
  330. //     getRowCount() returns the number of rows in the recordset
  331. function wddxRecordset_getRowCount()
  332. {
  333.     var nRowCount = 0;
  334.     for (var col in this)
  335.     {
  336.         if (typeof(this[col]) == "object")
  337.         {
  338.             nRowCount = this[col].length;
  339.             break;
  340.         }
  341.     }
  342.     return nRowCount;
  343. }
  344.  
  345.  
  346. ///////////////////////////////////////////////////////////////////////////
  347. //     addColumn(name) adds a column with that name and length == getRowCount()
  348. function wddxRecordset_addColumn(name)
  349. {
  350.     var nLen = this.getRowCount();
  351.     var colValue = new Array(nLen);
  352.     for (var i = 0; i < nLen; ++i)
  353.     {
  354.         colValue[i] = null;
  355.     }
  356.     this[this.preserveFieldCase ? name : name.toLowerCase()] = colValue;
  357. }
  358.  
  359.  
  360. ///////////////////////////////////////////////////////////////////////////
  361. //     addRows() adds n rows to all columns of the recordset
  362. function wddxRecordset_addRows(n)
  363. {
  364.     for (var col in this)
  365.     {
  366.         var nLen = this[col].length;
  367.         for (var i = nLen; i < nLen + n; ++i)
  368.         {
  369.             this[col][i] = null;
  370.         }
  371.     }
  372. }
  373.  
  374.  
  375. ///////////////////////////////////////////////////////////////////////////
  376. //     getField() returns the element in a given (row, col) position
  377. function wddxRecordset_getField(row, col)
  378. {
  379.     return this[this.preserveFieldCase ? col : col.toLowerCase()][row];
  380. }
  381.  
  382.  
  383. ///////////////////////////////////////////////////////////////////////////
  384. //     setField() sets the element in a given (row, col) position to value
  385. function wddxRecordset_setField(row, col, value)
  386. {
  387.     this[this.preserveFieldCase ? col : col.toLowerCase()][row] = value;
  388. }
  389.  
  390.  
  391. ///////////////////////////////////////////////////////////////////////////
  392. //     wddxSerialize() serializes a recordset
  393. //    returns true/false
  394. function wddxRecordset_wddxSerialize(serializer)
  395. {
  396.     // Create an array and a list of column names
  397.     var colNamesList = "";
  398.     var colNames = new Array();
  399.     var i = 0;
  400.     for (var col in this)
  401.     {
  402.         if (typeof(this[col]) == "object")
  403.         {
  404.             colNames[i++] = col;
  405.  
  406.             if (colNamesList.length > 0)
  407.             {
  408.                 colNamesList += ",";
  409.             }
  410.             colNamesList += col;            
  411.         }
  412.     }
  413.     
  414.     var nRows = this.getRowCount();
  415.     
  416.     serializer.write("<recordset rowCount='" + nRows + "' fieldNames='" + colNamesList + "'>");
  417.     
  418.     var bSuccess = true;
  419.     for (i = 0; bSuccess && i < colNames.length; i++)
  420.     {
  421.         var name = colNames[i];
  422.         serializer.write("<field name='" + name + "'>");
  423.         
  424.         for (var row = 0; bSuccess && row < nRows; row++)
  425.         {
  426.             bSuccess = serializer.serializeValue(this[name][row]);
  427.         }
  428.         
  429.         serializer.write("</field>");
  430.     }
  431.     
  432.     serializer.write("</recordset>");
  433.     
  434.     return bSuccess;
  435. }
  436.  
  437.  
  438. ///////////////////////////////////////////////////////////////////////////
  439. //     dump(escapeStrings) returns an HTML table with the recordset data
  440. //    It is a convenient routine for debugging and testing recordsets
  441. //    The boolean parameter escapeStrings determines whether the <>& 
  442. //    characters in string values are escaped as <>&
  443. function wddxRecordset_dump(escapeStrings)
  444. {
  445.     // Get row count
  446.     var nRows = this.getRowCount();
  447.     
  448.     // Determine column names
  449.     var colNames = new Array();
  450.     var i = 0;
  451.     for (var col in this)
  452.     {
  453.         if (typeof(this[col]) == "object")
  454.         {
  455.             colNames[i++] = col;
  456.         }
  457.     }
  458.  
  459.     // Build table headers    
  460.     var o = "<table border=1><tr><td><b>RowNumber</b></td>";
  461.     for (i = 0; i < colNames.length; ++i)
  462.     {
  463.         o += "<td><b>" + colNames[i] + "</b></td>";
  464.     }
  465.     o += "</tr>";
  466.     
  467.     // Build data cells
  468.     for (var row = 0; row < nRows; ++row)
  469.     {
  470.         o += "<tr><td>" + row + "</td>";
  471.         for (i = 0; i < colNames.length; ++i)
  472.         {
  473.             var elem = this.getField(row, colNames[i]);
  474.             if (escapeStrings && typeof(elem) == "string")
  475.             {
  476.                 var str = "";
  477.                 for (var j = 0; j < elem.length; ++j)
  478.                 {
  479.                     var ch = elem.charAt(j);
  480.                     if (ch == '<')
  481.                     {
  482.                         str += "<";
  483.                     }
  484.                     else if (ch == '>')
  485.                     {
  486.                         str += ">";
  487.                     }
  488.                     else if (ch == '&')
  489.                     {
  490.                         str += "&";
  491.                     }
  492.                     else
  493.                     {
  494.                         str += ch;
  495.                     }
  496.                 }            
  497.                 o += ("<td>" + str + "</td>");
  498.             }
  499.             else
  500.             {
  501.                 o += ("<td>" + elem + "</td>");
  502.             }
  503.         }
  504.         o += "</tr>";
  505.     }
  506.  
  507.     // Close table
  508.     o += "</table>";
  509.  
  510.     // Return HTML recordset dump
  511.     return o;    
  512. }
  513.  
  514.  
  515. ///////////////////////////////////////////////////////////////////////////
  516. // WddxRecordset() creates an empty recordset
  517. // WddxRecordset(columns) creates a recordset with these columns
  518. // WddxRecordset(columns, rows) creates a recordset with these columns and some number of rows
  519. function WddxRecordset()
  520. {
  521.     // Add default properties
  522.     this.preserveFieldCase = false;
  523.     
  524.     // Add extensions
  525.     if (typeof(wddxRecordsetExtensions) == "object")
  526.     {
  527.         for (var prop in wddxRecordsetExtensions)
  528.         {
  529.             // Hook-up method to WddxRecordset object
  530.             this[prop] = wddxRecordsetExtensions[prop]
  531.         }
  532.     }
  533.  
  534.     // Add built-in methods
  535.     this.getRowCount = wddxRecordset_getRowCount;
  536.     this.addColumn = wddxRecordset_addColumn;
  537.     this.addRows = wddxRecordset_addRows;
  538.     this.getField = wddxRecordset_getField;
  539.     this.setField = wddxRecordset_setField;
  540.     this.wddxSerialize = wddxRecordset_wddxSerialize;
  541.     this.dump = wddxRecordset_dump;
  542.     
  543.     // Perfom any needed initialization
  544.     if (WddxRecordset.arguments.length > 0)
  545.     {
  546.         var cols = WddxRecordset.arguments[0];
  547.         var nLen = WddxRecordset.arguments.length > 1 ? WddxRecordset.arguments[1] : 0;
  548.         
  549.         for (var i = 0; i < cols.length; ++i)
  550.         {
  551.              var colValue = new Array(nLen);
  552.             for (var j = 0; j < nLen; ++j)
  553.             {
  554.                 colValue[j] = null;
  555.             }
  556.         
  557.             this[cols[i]] = colValue;
  558.         }        
  559.     }
  560. }
  561.  
  562.  
  563. ///////////////////////////////////////////////////////////////////////////
  564. //
  565. //    WddxRecordset extensions
  566. //
  567. //    The WddxRecordset class has been designed with extensibility in mind.
  568. //    Developers can create new methods for the class outside this file as
  569. //    long as they make a call to registerWddxRecordsetExtension() with the
  570. //    name of the method and the function object that implements the method.
  571. //    The WddxRecordset constructor will automatically register all these
  572. //    methods with instances of the class.
  573. //
  574. //    Example:
  575. //
  576. //    If I want to add a new WddxRecordset method called addOneRow() I can
  577. //    do the following:
  578. //
  579. //    - create the method implementation
  580. //
  581. //    function wddxRecordset_addOneRow()
  582. //    {
  583. //        this.addRows(1);
  584. //    }
  585. //
  586. //    - call registerWddxRecordsetExtension() 
  587. //
  588. //    registerWddxRecordsetExtension("addOneRow", wddxRecordset_addOneRow);
  589. //
  590. //    - use the new function
  591. //
  592. //    rs = new WddxRecordset();
  593. //    rs.addOneRow();
  594. //
  595. ///////////////////////////////////////////////////////////////////////////
  596.  
  597.  
  598. ///////////////////////////////////////////////////////////////////////////
  599. //    registerWddxRecordsetExtension(name, func) can be used to extend 
  600. //    functionality by registering functions that should be added as methods 
  601. //    to WddxRecordset instances.
  602. function registerWddxRecordsetExtension(name, func)
  603. {
  604.     // Perform simple validation of arguments
  605.     if (typeof(name) == "string" && typeof(func) == "function")
  606.     {
  607.         // Guarantee existence of wddxRecordsetExtensions object
  608.         if (typeof(wddxRecordsetExtensions) != "object")
  609.         {
  610.             // Create wddxRecordsetExtensions instance
  611.             wddxRecordsetExtensions = new Object();
  612.         }
  613.         
  614.         // Register extension; override an existing one
  615.         wddxRecordsetExtensions[name] = func;
  616.     }
  617. }
  618.  
  619.