source: sandbox/2.3-MailArchiver/expressoMail1_2/spell_checker/cpaint/cpaint2.inc.js @ 6779

Revision 6779, 38.1 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado Expresso(branch 2.3) integrado ao MailArchiver?.

Line 
1/**
2* CPAINT - Cross-Platform Asynchronous INterface Toolkit
3*
4* http://sf.net/projects/cpaint
5*
6* released under the terms of the LGPL
7* see http://www.fsf.org/licensing/licenses/lgpl.txt for details
8*
9* @package      CPAINT
10* @access       public
11* @copyright    Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint
12* @author       Paul Sullivan <wiley14@gmail.com>
13* @author       Dominique Stender <dstender@st-webdevelopment.de>
14* @author               Stephan Tijink <stijink@googlemail.com>
15* @version      $Id$
16*/
17function cpaint() {
18   
19  /**
20  * CPAINT version
21  *
22  * @access     protected
23  * @var        string      version
24  */
25  this.version = '2.0.2';
26 
27  /**
28  * configuration options both for this class but also for  the cpaint_call() objects.
29  *
30  * @access     protected
31  * @var        array       config
32  */
33  var config                      = new Array();
34  config['debugging']             = -1;
35  config['proxy_url']             = '';
36  config['transfer_mode']         = 'GET';
37  config['async']                 = true;
38  config['response_type']         = 'OBJECT';
39  config['persistent_connection'] = false;
40  config['use_cpaint_api']        = true;
41 
42  /**
43  * maintains the next free index in the stack
44  *
45  * @access   protected
46  * @var      integer   stack_count
47  */
48  var stack_count = 0;
49
50  /**
51  * property returns whether or not the browser is AJAX capable
52  *
53  * @access             public
54  * @return             boolean
55  */
56  this.capable = test_ajax_capability();
57 
58  /**
59  * switches debug mode on/off.
60  *
61  * @access   public
62  * @param    boolean    debug    debug flag
63  * @return   void
64  */
65  this.set_debug = function() {
66   
67    if (typeof arguments[0] == 'boolean') {
68      if (arguments[0] === true) {
69        config['debugging'] = 1;
70
71      } else {
72        config['debugging'] = 0;
73      }
74     
75    } else if (typeof arguments[0] == 'number') {
76      config['debugging'] = Math.round(arguments[0]);
77    }
78  }
79
80  /**
81  * defines the URL of the proxy script.
82  *
83  * @access   public
84  * @param    string    proxy_url    URL of the proxyscript to connect
85  * @return   void
86  */
87  this.set_proxy_url = function() {
88   
89    if (typeof arguments[0] == 'string') {
90
91      config['proxy_url'] = arguments[0];
92    }
93  }
94
95  /**
96  * sets the transfer_mode (GET|POST).
97  *
98  * @access   public
99  * @param    string    transfer_mode    transfer_mode
100  * @return   void
101  */
102  this.set_transfer_mode = function() {
103   
104    if (arguments[0].toUpperCase() == 'GET'
105      || arguments[0].toUpperCase() == 'POST') {
106
107      config['transfer_mode'] = arguments[0].toUpperCase();
108    }
109  }
110
111  /**
112  * sets the flag whether or not to use asynchronous calls.
113  *
114  * @access   public
115  * @param    boolean    async    syncronization flag
116  * @return   void
117  */
118  this.set_async = function() {
119   
120    if (typeof arguments[0] == 'boolean') {
121      config['async'] = arguments[0];
122    }
123  }
124
125  /**
126  * defines the response type.
127  *
128  * allowed values are:
129  *   TEXT    = raw text response
130  *   XML     = raw XMLHttpObject
131  *   OBJECT  = parsed JavaScript object structure from XMLHttpObject
132  *
133  * the default is OBJECT.
134  *
135  * @access   public
136  * @param    string    response_type    response type
137  * @return   void
138  */
139  this.set_response_type = function() {
140   
141    if (arguments[0].toUpperCase() == 'TEXT'
142      || arguments[0].toUpperCase() == 'XML'
143      || arguments[0].toUpperCase() == 'OBJECT'
144      || arguments[0].toUpperCase() == 'E4X'
145      || arguments[0].toUpperCase() == 'JSON') {
146
147      config['response_type'] = arguments[0].toUpperCase();
148    }
149  }
150
151  /**
152  * sets the flag whether or not to use a persistent connection.
153  *
154  * @access   public
155  * @param    boolean    persistent_connection    persistance flag
156  * @return   void
157  */
158  this.set_persistent_connection = function() {
159   
160    if (typeof arguments[0] == 'boolean') {
161      config['persistent_connection'] = arguments[0];
162    }
163  }
164 
165 
166  /**
167  * sets the flag whether or not to use the cpaint api on the backend.
168  *
169  * @access    public
170  * @param     boolean    cpaint_api      api_flag
171  * @return    void
172  */
173  this.set_use_cpaint_api = function() {
174    if (typeof arguments[0] == 'boolean') {
175      config['use_cpaint_api'] = arguments[0];
176    }
177  }
178 
179  /**
180  * tests whether one of the necessary implementations
181  * of the XMLHttpRequest class are available
182  *
183  * @access     protected
184  * @return     boolean
185  */
186  function test_ajax_capability() {
187    var cpc = new cpaint_call(0, config, this.version);
188    return cpc.test_ajax_capability();
189  }
190
191  /**
192  * takes the arguments supplied and triggers a call to the CPAINT backend
193  * based on the settings.
194  *
195  * upon response cpaint_call.callback() will automatically be called
196  * to perform post-processing operations.
197  *
198  * @access   public
199  * @param    string    url                 remote URL to call
200  * @param    string    remote_method       remote method to call
201  * @param    object    client_callback     client side callback method to deliver the remote response to. do NOT supply a string!
202  * @param    mixed     argN                remote parameters from now on
203  * @return   void
204  */
205  this.call = function() {
206    var use_stack = -1;
207   
208    if (config['persistent_connection'] == true
209      && __cpaint_stack[0] != null) {
210
211      switch (__cpaint_stack[0].get_http_state()) {
212        case -1:
213          // no XMLHttpObject object has already been instanciated
214          // create new object and configure it
215          use_stack = 0;
216          debug('no XMLHttpObject object to re-use for persistence, creating new one later', 2);
217          break;
218         
219        case 4:
220          // object is ready for a new request, no need to do anything
221          use_stack = 0
222          debug('re-using the persistent connection', 2);
223          break;
224         
225        default:
226          // connection is currently in use, don't do anything
227          debug('the persistent connection is in use - skipping this request', 2);
228      }
229     
230    } else if (config['persistent_connection'] == true) {
231      // persistent connection is active, but no object has been instanciated
232      use_stack = 0;
233      __cpaint_stack[use_stack] = new cpaint_call(use_stack, config, this.version);
234      debug('no cpaint_call object available for re-use, created new one', 2);
235   
236    } else {
237      // no connection persistance
238      use_stack = stack_count;
239      __cpaint_stack[use_stack] = new cpaint_call(use_stack, config, this.version);
240      debug('no cpaint_call object created new one', 2);
241    }
242
243    // configure cpaint_call if allowed to
244    if (use_stack != -1) {
245      __cpaint_stack[use_stack].set_client_callback(arguments[2]);
246     
247      // distribute according to proxy use
248      if (config['proxy_url'] != '') {
249        __cpaint_stack[use_stack].call_proxy(arguments);
250     
251      } else {
252        __cpaint_stack[use_stack].call_direct(arguments);
253      }
254
255      // increase stack counter
256      stack_count++;
257      debug('stack size: ' + __cpaint_stack.length, 2);
258    }
259  }
260
261  /**
262  * debug method
263  *
264  * @access  protected
265  * @param   string       message         the message to debug
266  * @param   integer      debug_level     debug level at which the message appears
267  * @return  void
268  */
269  var debug  = function(message, debug_level) {
270    var prefix = '[CPAINT Debug] ';
271   
272    if (debug_level < 1) {
273      prefix = '[CPAINT Error] ';
274    }
275   
276    if (config['debugging'] >= debug_level) {
277      alert(prefix + message);
278    }
279  }
280}
281
282/**
283* internal FIFO stack of cpaint_call() objects.
284*
285* @access   protected
286* @var      array    __cpaint_stack
287*/
288var __cpaint_stack = new Array();
289
290/**
291* local instance of cpaint_transformer
292* MSIE is unable to handle static classes... sheesh.
293*
294* @access   public
295* @var      object    __cpaint_transformer
296*/
297var __cpaint_transformer = new cpaint_transformer();
298
299/**
300* transport agent class
301*
302* creates the request object, takes care of the response, handles the
303* client callback. Is configured by the cpaint() object.
304*
305* @package      CPAINT
306* @access       public
307* @copyright    Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint
308* @author       Dominique Stender <dstender@st-webdevelopment.de>
309* @author       Paul Sullivan <wiley14@gmail.com>
310* @param        integer     stack_id      stack Id in cpaint
311* @param        array       config        configuration array for this call
312* @param        string      version       CPAINT API version
313*/
314function cpaint_call() {
315  /**
316  * CPAINT version
317  *
318  * @access     protected
319  * @var        string      version
320  */
321  var version = arguments[2];
322 
323  /**
324  * configuration options both for this class objects.
325  *
326  * @access     protected
327  * @var        array       config
328  */
329  var config                      = new Array();
330  config['debugging']             = arguments[1]['debugging'];
331  config['proxy_url']             = arguments[1]['proxy_url'];
332  config['transfer_mode']         = arguments[1]['transfer_mode'];
333  config['async']                 = arguments[1]['async'];
334  config['response_type']         = arguments[1]['response_type'];
335  config['persistent_connection'] = arguments[1]['persistent_connection'];
336  config['use_cpaint_api']        = arguments[1]['use_cpaint_api'];
337
338  /**
339  * XMLHttpObject used for this request.
340  *
341  * @access   protected
342  * @var      object     httpobj
343  */
344  var httpobj    = false;
345
346  /**
347  * client callback function.
348  *
349  * @access   public
350  * @var      function    client_callback
351  */
352  var client_callback;
353
354  /**
355  * stores the stack Id within the cpaint object
356  *
357  * @access   protected
358  * @var      stack_id
359  */
360  var stack_id = arguments[0];
361 
362  /**
363  * sets the client callback function.
364  *
365  * @access   public
366  * @param    function    client_callback     the client callback function
367  * @return   void
368  */
369  this.set_client_callback = function() {
370   
371    if (typeof arguments[0] == 'function') {
372      client_callback = arguments[0];
373    }
374  }
375
376  /**
377  * returns the ready state of the internal XMLHttpObject
378  *
379  * if no such object was set up already, -1 is returned
380  *
381  * @access     public
382  * @return     integer
383  */
384  this.get_http_state = function() {
385    var return_value = -1;
386   
387    if (typeof httpobj == 'object') {
388      return_value = httpobj.readyState;
389    }
390   
391    return return_value;
392  }
393 
394  /**
395  * internal method for remote calls to the local server without use of the proxy script.
396  *
397  * @access   public
398  * @param    array    call_arguments    array of arguments initially passed to cpaint.call()
399  * @return   void
400  */
401  this.call_direct = function(call_arguments) {
402    var url             = call_arguments[0];
403    var remote_method   = call_arguments[1];
404    var querystring     = '';
405    var i               = 0;
406   
407    // correct link to self
408    if (url == 'SELF') {
409      url = document.location.href;
410    }
411 
412    if (config['use_cpaint_api'] == true) {
413      // backend uses cpaint api
414      // pass parameters to remote method
415      for (i = 3; i < call_arguments.length; i++) {
416
417        if ((typeof call_arguments[i] == 'string'
418              && call_arguments[i] != ''
419              && call_arguments[i].search(/^\s+$/g) == -1)
420          && !isNaN(call_arguments[i])
421          && isFinite(call_arguments[i])) {
422          // numerical value, convert it first
423          querystring += '&cpaint_argument[]=' + encodeURIComponent(JSON.stringify(Number(call_arguments[i])));
424       
425        } else {
426          querystring += '&cpaint_argument[]=' + encodeURIComponent(JSON.stringify(call_arguments[i]));
427        }
428      }
429   
430      // add response type to querystring
431      querystring += '&cpaint_response_type=' + config['response_type'];
432   
433      // build header
434      if (config['transfer_mode'] == 'GET') {
435                               
436        if(url.indexOf('?') != -1) {
437                                        url = url + '&cpaint_function=' + remote_method +       querystring;
438                               
439        } else {
440                                        url = url + '?cpaint_function=' + remote_method +       querystring;
441                                }
442     
443      } else {
444        querystring = 'cpaint_function=' + remote_method + querystring;
445      }
446     
447    } else {
448      // backend does not use cpaint api
449      // pass parameters to remote method
450      for (i = 3; i < call_arguments.length; i++) {
451       
452        if (i == 3) {
453          querystring += encodeURIComponent(call_arguments[i]);
454       
455        } else {
456          querystring += '&' + encodeURIComponent(call_arguments[i]);
457        }
458      }
459   
460      // build header
461      if (config['transfer_mode'] == 'GET') {
462        url = url + querystring;
463      }
464    }
465 
466    // open connection
467    get_connection_object();
468
469    // open connection to remote target
470    debug('opening connection to "' + url + '"', 1);
471    httpobj.open(config['transfer_mode'], url, config['async']);
472
473    // send "urlencoded" header if necessary (if POST)
474    if (config['transfer_mode'] == 'POST') {
475
476      try {
477        httpobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
478
479      } catch (cp_err) {
480        debug('POST cannot be completed due to incompatible browser.  Use GET as your request method.', 0);
481      }
482    }
483
484    // make ourselves known
485    httpobj.setRequestHeader('X-Powered-By', 'CPAINT v' + version + ' :: http://sf.net/projects/cpaint');
486
487    // callback handling for asynchronous calls
488    httpobj.onreadystatechange = callback;
489
490    // send content
491    if (config['transfer_mode'] == 'GET') {
492      httpobj.send(null);
493
494    } else {
495      debug('sending query: ' + querystring, 1);
496      httpobj.send(querystring);
497    }
498
499    if (config['async'] == true) {
500      // manual callback handling for synchronized calls
501      callback();
502    }
503  }
504   
505  /**
506  * internal method for calls to remote servers through the proxy script.
507  *
508  * @access   public
509  * @param    array    call_arguments    array of arguments passed to cpaint.call()
510  * @return   void
511  */
512  this.call_proxy = function(call_arguments) {
513    var proxyscript     = config['proxy_url'];
514    var url             = call_arguments[0];
515    var remote_method   = call_arguments[1];
516    var querystring     = '';
517    var i               = 0;
518   
519    var querystring_argument_prefix = 'cpaint_argument[]=';
520
521    // pass parameters to remote method
522    if (config['use_cpaint_api'] == false) {
523      // when not talking to a CPAINT backend, don't prefix arguments
524      querystring_argument_prefix = '';
525    }
526
527    for (i = 3; i < call_arguments.length; i++) {
528
529      if (config['use_cpaint_api'] == true) {
530     
531        if ((typeof call_arguments[i] == 'string'
532              && call_arguments[i] != ''
533              && call_arguments[i].search(/^\s+$/g) == -1)
534          && !isNaN(call_arguments[i])
535          && isFinite(call_arguments[i])) {
536          // numerical value, convert it first
537          querystring += encodeURIComponent(querystring_argument_prefix + JSON.stringify(Number(call_arguments[i])) + '&');
538
539        } else {
540          querystring += encodeURIComponent(querystring_argument_prefix + JSON.stringify(call_arguments[i]) + '&');
541        }
542       
543      } else {
544        // no CPAINT in the backend
545        querystring += encodeURIComponent(querystring_argument_prefix + call_arguments[i] + '&');
546      }
547    }
548
549    if (config['use_cpaint_api'] == true) {
550      // add remote function name to querystring
551      querystring += encodeURIComponent('&cpaint_function=' + remote_method);
552 
553      // add response type to querystring
554      querystring += encodeURIComponent('&cpaint_responsetype=' + config['response_type']);
555    }
556   
557    // build header
558    if (config['transfer_mode'] == 'GET') {
559      proxyscript += '?cpaint_remote_url=' + encodeURIComponent(url)
560        + '&cpaint_remote_query=' + querystring
561        + '&cpaint_remote_method=' + config['transfer_mode']
562        + '&cpaint_response_type=' + config['response_type'];
563
564    } else {
565      querystring = 'cpaint_remote_url=' + encodeURIComponent(url)
566        + '&cpaint_remote_query=' + querystring
567        + '&cpaint_remote_method=' + config['transfer_mode']
568        + '&cpaint_response_type=' + config['response_type'];
569    }
570
571    // open connection
572    get_connection_object();
573
574    // open connection to remote target
575    debug('opening connection to proxy "' + proxyscript + '"', 1);
576    httpobj.open(config['transfer_mode'], proxyscript, config['async']);
577
578    // send "urlencoded" header if necessary (if POST)
579    if (config['transfer_mode'] == 'POST') {
580
581      try {
582        httpobj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
583
584      } catch (cp_err) {
585        debug('POST cannot be completed due to incompatible browser.  Use GET as your request method.', 0);
586      }
587    }
588
589    httpobj.setRequestHeader('X-Powered-By', 'CPAINT v' + version);
590
591    // callback handling for asynchronous calls
592    httpobj.onreadystatechange = callback;
593
594    // send content
595    if (config['transfer_mode'] == 'GET') {
596      httpobj.send(null);
597
598    } else {
599      debug('sending query: ' + querystring, 1);
600      httpobj.send(querystring);
601    }
602
603    if (config['async'] == false) {
604      // manual callback handling for synchronized calls
605      callback();
606    }
607  }
608
609  this.test_ajax_capability = function() {
610    return get_connection_object();
611  }
612 
613  /**
614  * creates a new connection object.
615  *
616  * @access   protected
617  * @return   boolean
618  */
619  var get_connection_object = function() {
620    var return_value    = false;
621    var new_connection  = false;
622
623    // open new connection only if necessary
624    if (config['persistent_connection'] == false) {
625      // no persistance, create a new object every time
626      debug('Using new connection object', 1);
627      new_connection = true;
628
629    } else {
630      // persistent connection object, only open one if no object exists
631      debug('Using shared connection object.', 1);
632
633      if (typeof httpobj != 'object') {
634        debug('Getting new persistent connection object.', 1);
635        new_connection = true;
636      }
637    }
638
639    if (new_connection == true) {
640      try {
641        httpobj = new ActiveXObject('Msxml2.XMLHTTP');
642 
643      } catch (e) {
644       
645        try { 
646          httpobj = new ActiveXObject('Microsoft.XMLHTTP');
647 
648        } catch (oc) {
649          httpobj = null;
650        }
651      }
652 
653      if (!httpobj && typeof XMLHttpRequest != 'undefined') {
654        httpobj = new XMLHttpRequest();
655      }
656 
657      if (!httpobj) {
658        debug('Could not create connection object', 0);
659     
660      } else {
661        return_value = true;
662      }
663    }
664
665    if (httpobj.readyState != 4) {
666      httpobj.abort();
667    }
668
669    return return_value;
670  }
671
672  /**
673  * internal callback function.
674  *
675  * will perform some consistency checks (response code, NULL value testing)
676  * and if response_type = 'OBJECT' it will automatically call
677  * cpaint_call.parse_ajax_xml() to have a JavaScript object structure generated.
678  *
679  * after all that is done the client side callback function will be called
680  * with the generated response as single value.
681  *
682  * @access   protected
683  * @return   void
684  */
685  var callback = function() {
686    var response = null;
687
688    if (httpobj.readyState == 4
689      && httpobj.status == 200) {
690     
691      debug(httpobj.responseText, 1);
692      debug('using response type ' + config['response_type'], 2);
693     
694      // fetch correct response
695      switch (config['response_type']) {
696        case 'XML':
697          debug(httpobj.responseXML, 2);
698          response = __cpaint_transformer.xml_conversion(httpobj.responseXML);
699          break;
700         
701        case 'OBJECT':
702          response = __cpaint_transformer.object_conversion(httpobj.responseXML);
703          break;
704       
705        case 'TEXT':
706          response = __cpaint_transformer.text_conversion(httpobj.responseText);
707          break;
708         
709        case 'E4X':
710          response = __cpaint_transformer.e4x_conversion(httpobj.responseText);
711          break;
712         
713        case 'JSON':
714          response = __cpaint_transformer.json_conversion(httpobj.responseText);
715          break;
716         
717        default:
718          debug('invalid response type \'' + response_type + '\'', 0);
719      }
720     
721      // call client side callback
722      if (response != null
723        && typeof client_callback == 'function') {
724        client_callback(response, httpobj.responseText);
725      }
726     
727      // remove ourselves from the stack
728      remove_from_stack();
729   
730    } else if (httpobj.readyState == 4
731      && httpobj.status != 200) {
732      // HTTP error of some kind
733      debug('invalid HTTP response code \'' + Number(httpobj.status) + '\'', 0);
734    }
735  }
736
737  /**
738  * removes an entry from the stack
739  *
740  * @access     protected
741  * @return     void
742  */
743  var remove_from_stack = function() {
744    // remove only if everything is okay and we're not configured as persistent connection
745    if (typeof stack_id == 'number'
746      && __cpaint_stack[stack_id]
747      && config['persistent_connection'] == false) {
748     
749      __cpaint_stack[stack_id] = null;
750    }
751  }
752
753  /**
754  * debug method
755  *
756  * @access  protected
757  * @param   string       message         the message to debug
758  * @param   integer      debug_level     debug level at which the message appears
759  * @return  void
760  */
761  var debug  = function(message, debug_level) {
762    var prefix = '[CPAINT Debug] ';
763   
764    if (config['debugging'] < 1) {
765      prefix = '[CPAINT Error] ';
766    }
767   
768    if (config['debugging'] >= debug_level) {
769      alert(prefix + message);
770    }
771  }
772}
773
774/**
775* CPAINT transformation object
776*
777* @package      CPAINT
778* @access       public
779* @copyright    Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint
780* @author       Paul Sullivan <wiley14@gmail.com>
781* @author       Dominique Stender <dstender@st-webdevelopment.de>
782*/
783function cpaint_transformer() {
784
785  /**
786  * will take a XMLHttpObject and generate a JavaScript
787  * object structure from it.
788  *
789  * is internally called by cpaint_call.callback() if necessary.
790  * will call cpaint_call.create_object_structure() to create nested object structures.
791  *
792  * @access   public
793  * @param    object    xml_document  a XMLHttpObject
794  * @return   object
795  */
796  this.object_conversion = function(xml_document) {
797    var return_value  = new cpaint_result_object();
798    var i             = 0;
799    var firstNodeName = '';
800   
801    if (typeof xml_document == 'object'
802      && xml_document != null) {
803
804      // find the first element node - for MSIE the <?xml?> node is the very first...
805      for (i = 0; i < xml_document.childNodes.length; i++) {
806
807        if (xml_document.childNodes[i].nodeType == 1) {
808          firstNodeName = xml_document.childNodes[i].nodeName;
809          break;
810        }
811      }
812     
813      var ajax_response = xml_document.getElementsByTagName(firstNodeName);
814
815      return_value[firstNodeName] = new Array();
816   
817      for (i = 0; i < ajax_response.length; i++) {
818        var tmp_node = create_object_structure(ajax_response[i]);
819        tmp_node.id  = ajax_response[i].getAttribute('id')
820        return_value[firstNodeName].push(tmp_node);
821      }
822
823    } else {
824      debug('received invalid XML response', 0);
825    }
826
827    return return_value;
828  }
829
830  /**
831  * performs the necessary conversions for the XML response type
832  *
833  * @access   public
834  * @param    object    xml_document  a XMLHttpObject
835  * @return   object
836  */
837  this.xml_conversion = function(xml_document) {
838    return xml_document;
839  }
840 
841  /**
842  * performs the necessary conversions for the TEXT response type
843  *
844  * @access   public
845  * @param    string    text  the response text
846  * @return   string
847  */
848  this.text_conversion = function(text) {
849    return decode(text);
850  }
851 
852  /**
853  * performs the necessary conversions for the E4X response type
854  *
855  * @access   public
856  * @param    string    text  the response text
857  * @return   string
858  */
859  this.e4x_conversion = function(text) {
860    // remove <?xml ?>tag
861    text = text.replace(/^\<\?xml[^>]+\>/, '');
862    return new XML(text);
863  }
864 
865  /**
866  * performs the necessary conversions for the JSON response type
867  *
868  * @access   public
869  * @param    string    text  the response text
870  * @return   string
871  */
872  this.json_conversion = function(text) {
873    return JSON.parse(text);
874  }
875 
876  /**
877  * this method takes a HTML / XML node object and creates a
878  * JavaScript object structure from it.
879  *
880  * @access   public
881  * @param    object    stream    a node in the XML structure
882  * @return   object
883  */
884  var create_object_structure = function(stream) {
885    var return_value = new cpaint_result_object();
886    var node_name = '';
887    var i         = 0;
888    var attrib    = 0;
889   
890    if (stream.hasChildNodes() == true) {
891      for (i = 0; i < stream.childNodes.length; i++) {
892 
893        node_name = stream.childNodes[i].nodeName;
894        node_name = node_name.replace(/[^a-zA-Z0-9_]*/g, '');
895       
896        // reset / create subnode
897        if (typeof return_value[node_name] != 'object') {
898          return_value[node_name] = new Array();
899        }
900       
901        if (stream.childNodes[i].nodeType == 1) {
902          var tmp_node  = create_object_structure(stream.childNodes[i]);
903
904          for (attrib = 0; attrib < stream.childNodes[i].attributes.length; attrib++) {
905            tmp_node.set_attribute(stream.childNodes[i].attributes[attrib].nodeName, stream.childNodes[i].attributes[attrib].nodeValue);
906          }
907         
908          return_value[node_name].push(tmp_node);
909       
910        } else if (stream.childNodes[i].nodeType == 3) {
911          return_value.data  = decode(String(stream.firstChild.data));
912        }
913      }
914    }
915   
916    return return_value;
917  }
918
919  /**
920  * converts an encoded text back to viewable characters.
921  *
922  * @access     public
923  * @param      string      rawtext     raw text as provided by the backend
924  * @return     mixed
925  */
926  var decode = function(rawtext) {
927    var plaintext = '';
928    var i         = 0;
929    var c1        = 0;
930    var c2        = 0;
931    var c3        = 0;
932    var u         = 0;
933    var t         = 0;
934
935    // remove special JavaScript encoded non-printable characters
936    while (i < rawtext.length) {
937      if (rawtext.charAt(i) == '\\'
938        && rawtext.charAt(i + 1) == 'u') {
939       
940        u = 0;
941       
942        for (j = 2; j < 6; j += 1) {
943          t = parseInt(rawtext.charAt(i + j), 16);
944         
945          if (!isFinite(t)) {
946            break;
947          }
948          u = u * 16 + t;
949        }
950
951        plaintext += String.fromCharCode(u);
952        i       += 6;
953     
954      } else {
955        plaintext += rawtext.charAt(i);
956        i++;
957      }
958    }
959
960    // convert numeric data to number type
961    if (plaintext != ''
962      && plaintext.search(/^\s+$/g) == -1
963      && !isNaN(plaintext)
964      && isFinite(plaintext)) {
965     
966      plaintext = Number(plaintext);
967    }
968 
969    return plaintext;
970  }
971}
972
973/**
974* this is the basic prototype for a cpaint node object
975* as used in cpaint_call.parse_ajax_xml()
976*
977* @package      CPAINT
978* @access       public
979* @copyright    Copyright (c) 2005-2006 Paul Sullivan, Dominique Stender - http://sf.net/projects/cpaint
980* @author       Paul Sullivan <wiley14@gmail.com>
981* @author       Dominique Stender <dstender@st-webdevelopment.de>
982*/
983function cpaint_result_object() {
984  this.id           = 0;
985  this.data         = '';
986  var __attributes  = new Array();
987 
988  /**
989  * Returns a subnode with the given type and id.
990  *
991  * @access     public
992  * @param      string    type    The type of the subnode. Equivalent to the XML tag name.
993  * @param      string    id      The id of the subnode. Equivalent to the XML tag names id attribute.
994  * @return     object
995  */
996  this.find_item_by_id = function() {
997    var return_value  = null;
998    var type    = arguments[0];
999    var id      = arguments[1];
1000    var i       = 0;
1001   
1002    if (this[type]) {
1003
1004      for (i = 0; i < this[type].length; i++) {
1005
1006        if (this[type][i].get_attribute('id') == id) {
1007          return_value = this[type][i];
1008          break;
1009        }
1010      }
1011    }
1012
1013    return return_value;
1014  }
1015 
1016  /**
1017  * retrieves the value of an attribute.
1018  *
1019  * @access   public
1020  * @param    string    name    name of the attribute
1021  * @return   mixed
1022  */
1023  this.get_attribute = function() {
1024    var return_value  = null;
1025    var id            = arguments[0];
1026   
1027    if (typeof __attributes[id] != 'undefined') {
1028      return_value = __attributes[id];
1029    }
1030   
1031    return return_value;
1032  }
1033 
1034  /**
1035  * assigns a value to an attribute.
1036  *
1037  * if that attribute does not exist it will be created.
1038  *
1039  * @access     public
1040  * @param      string    name    name of the attribute
1041  * @param      string    value   value of the attribute
1042  * @return     void
1043  */
1044  this.set_attribute = function() {
1045    __attributes[arguments[0]] = arguments[1];
1046  }
1047}
1048
1049
1050/*
1051Copyright (c) 2005 JSON.org
1052
1053Permission is hereby granted, free of charge, to any person obtaining a copy
1054of this software and associated documentation files (the "Software"), to deal
1055in the Software without restriction, including without limitation the rights
1056to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1057copies of the Software, and to permit persons to whom the Software is
1058furnished to do so, subject to the following conditions:
1059
1060The Software shall be used for Good, not Evil.
1061
1062THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1063IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1064FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1065AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1066LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1067OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1068SOFTWARE.
1069*/
1070
1071//Array.prototype.______array = '______array';
1072
1073var JSON = {
1074  org: 'http://www.JSON.org',
1075  copyright: '(c)2005 JSON.org',
1076  license: 'http://www.crockford.com/JSON/license.html',
1077
1078  stringify: function (arg) {
1079    var c, i, l, s = '', v;
1080    var numeric = true;
1081   
1082    switch (typeof arg) {
1083    case 'object':
1084      if (arg) {
1085        if (arg.______array == '______array') {
1086          // do a test whether all array keys are numeric
1087          for (i in arg) {
1088            if (i != '______array'
1089              && (isNaN(i)
1090                || !isFinite(i))) {
1091              numeric = false;
1092              break;
1093            }
1094          }
1095         
1096          if (numeric == true) {
1097            for (i = 0; i < arg.length; ++i) {
1098              if (typeof arg[i] != 'undefined') {
1099                v = this.stringify(arg[i]);
1100                if (s) {
1101                  s += ',';
1102                }
1103                s += v;
1104              } else {
1105                s += ',null';
1106              }
1107            }
1108            return '[' + s + ']';
1109          } else {
1110            for (i in arg) {
1111              if (i != '______array') {
1112                v = arg[i];
1113                if (typeof v != 'undefined' && typeof v != 'function') {
1114                  v = this.stringify(v);
1115                  if (s) {
1116                    s += ',';
1117                  }
1118                  s += this.stringify(i) + ':' + v;
1119                }
1120              }
1121            }
1122            // return as object
1123            return '{' + s + '}';
1124          }
1125        } else if (typeof arg.toString != 'undefined') {
1126          for (i in arg) {
1127            v = arg[i];
1128            if (typeof v != 'undefined' && typeof v != 'function') {
1129              v = this.stringify(v);
1130              if (s) {
1131                s += ',';
1132              }
1133              s += this.stringify(i) + ':' + v;
1134            }
1135          }
1136          return '{' + s + '}';
1137        }
1138      }
1139      return 'null';
1140    case 'number':
1141      return isFinite(arg) ? String(arg) : 'null';
1142    case 'string':
1143      l = arg.length;
1144      s = '"';
1145      for (i = 0; i < l; i += 1) {
1146        c = arg.charAt(i);
1147        if (c >= ' ') {
1148          if (c == '\\' || c == '"') {
1149            s += '\\';
1150          }
1151          s += c;
1152        } else {
1153          switch (c) {
1154            case '\b':
1155              s += '\\b';
1156              break;
1157            case '\f':
1158              s += '\\f';
1159              break;
1160            case '\n':
1161              s += '\\n';
1162              break;
1163            case '\r':
1164              s += '\\r';
1165              break;
1166            case '\t':
1167              s += '\\t';
1168              break;
1169            default:
1170              c = c.charCodeAt();
1171              s += '\\u00' + Math.floor(c / 16).toString(16) +
1172                (c % 16).toString(16);
1173          }
1174        }
1175      }
1176      return s + '"';
1177    case 'boolean':
1178      return String(arg);
1179    default:
1180      return 'null';
1181    }
1182  },
1183  parse: function (text) {
1184    var at = 0;
1185    var ch = ' ';
1186
1187    function error(m) {
1188      throw {
1189        name: 'JSONError',
1190        message: m,
1191        at: at - 1,
1192        text: text
1193      };
1194    }
1195
1196    function next() {
1197      ch = text.charAt(at);
1198      at += 1;
1199      return ch;
1200    }
1201
1202    function white() {
1203      while (ch != '' && ch <= ' ') {
1204        next();
1205      }
1206    }
1207
1208    function str() {
1209      var i, s = '', t, u;
1210
1211      if (ch == '"') {
1212outer:      while (next()) {
1213          if (ch == '"') {
1214            next();
1215            return s;
1216          } else if (ch == '\\') {
1217            switch (next()) {
1218            case 'b':
1219              s += '\b';
1220              break;
1221            case 'f':
1222              s += '\f';
1223              break;
1224            case 'n':
1225              s += '\n';
1226              break;
1227            case 'r':
1228              s += '\r';
1229              break;
1230            case 't':
1231              s += '\t';
1232              break;
1233            case 'u':
1234              u = 0;
1235              for (i = 0; i < 4; i += 1) {
1236                t = parseInt(next(), 16);
1237                if (!isFinite(t)) {
1238                  break outer;
1239                }
1240                u = u * 16 + t;
1241              }
1242              s += String.fromCharCode(u);
1243              break;
1244            default:
1245              s += ch;
1246            }
1247          } else {
1248            s += ch;
1249          }
1250        }
1251      }
1252      error("Bad string");
1253    }
1254
1255    function arr() {
1256      var a = [];
1257
1258      if (ch == '[') {
1259        next();
1260        white();
1261        if (ch == ']') {
1262          next();
1263          return a;
1264        }
1265        while (ch) {
1266          a.push(val());
1267          white();
1268          if (ch == ']') {
1269            next();
1270            return a;
1271          } else if (ch != ',') {
1272            break;
1273          }
1274          next();
1275          white();
1276        }
1277      }
1278      error("Bad array");
1279    }
1280
1281    function obj() {
1282      var k, o = {};
1283
1284      if (ch == '{') {
1285        next();
1286        white();
1287        if (ch == '}') {
1288          next();
1289          return o;
1290        }
1291        while (ch) {
1292          k = str();
1293          white();
1294          if (ch != ':') {
1295            break;
1296          }
1297          next();
1298          o[k] = val();
1299          white();
1300          if (ch == '}') {
1301            next();
1302            return o;
1303          } else if (ch != ',') {
1304            break;
1305          }
1306          next();
1307          white();
1308        }
1309      }
1310      error("Bad object");
1311    }
1312
1313    function assoc() {
1314      var k, a = [];
1315
1316      if (ch == '<') {
1317        next();
1318        white();
1319        if (ch == '>') {
1320          next();
1321          return a;
1322        }
1323        while (ch) {
1324          k = str();
1325          white();
1326          if (ch != ':') {
1327            break;
1328          }
1329          next();
1330          a[k] = val();
1331          white();
1332          if (ch == '>') {
1333            next();
1334            return a;
1335          } else if (ch != ',') {
1336            break;
1337          }
1338          next();
1339          white();
1340        }
1341      }
1342      error("Bad associative array");
1343    }
1344
1345    function num() {
1346      var n = '', v;
1347      if (ch == '-') {
1348        n = '-';
1349        next();
1350      }
1351      while (ch >= '0' && ch <= '9') {
1352        n += ch;
1353        next();
1354      }
1355      if (ch == '.') {
1356        n += '.';
1357        while (next() && ch >= '0' && ch <= '9') {
1358          n += ch;
1359        }
1360      }
1361      if (ch == 'e' || ch == 'E') {
1362        n += 'e';
1363        next();
1364        if (ch == '-' || ch == '+') {
1365          n += ch;
1366          next();
1367        }
1368        while (ch >= '0' && ch <= '9') {
1369          n += ch;
1370          next();
1371        }
1372      }
1373      v = +n;
1374      if (!isFinite(v)) {
1375        error("Bad number");
1376      } else {
1377        return v;
1378      }
1379    }
1380
1381    function word() {
1382      switch (ch) {
1383        case 't':
1384          if (next() == 'r' && next() == 'u' && next() == 'e') {
1385            next();
1386            return true;
1387          }
1388          break;
1389        case 'f':
1390          if (next() == 'a' && next() == 'l' && next() == 's' &&
1391              next() == 'e') {
1392            next();
1393            return false;
1394          }
1395          break;
1396        case 'n':
1397          if (next() == 'u' && next() == 'l' && next() == 'l') {
1398            next();
1399            return null;
1400          }
1401          break;
1402      }
1403      error("Syntax error");
1404    }
1405
1406    function val() {
1407      white();
1408      switch (ch) {
1409        case '{':
1410          return obj();
1411        case '[':
1412          return arr();
1413        case '<':
1414          return assoc();
1415        case '"':
1416          return str();
1417        case '-':
1418          return num();
1419        default:
1420          return ch >= '0' && ch <= '9' ? num() : word();
1421      }
1422    }
1423
1424    return val();
1425  }
1426};
Note: See TracBrowser for help on using the repository browser.