Guest User

Cyril

a guest
Mar 29th, 2009
809
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /* ============ DEFERRED OBJECT ===========
  2.    used by Requester */
  3. var Deferred = function()
  4. {
  5.     this.cbh_ = [];
  6.     this.ebh_ = [];
  7.     this.fired_ = false;
  8. }
  9. Deferred.prototype = {
  10.     callback: function(data) {
  11.         return this.fire(true, data);
  12.     },
  13.     errback: function(data) {
  14.         return this.fire(false, data);
  15.     },
  16.     fire: function(status, result) {
  17.         if (this.fired_) return false;
  18.         this.fired_ = true;
  19.         this.status_ = status;
  20.         this.result_ = result;
  21.         this.broadcast_();
  22.         return true;
  23.     },
  24.     fired: function() {
  25.         return this.fired_;
  26.     },
  27.     addCallback: function(fn) {
  28.         this.cbh_.push(fn);
  29.         this.broadcast_();
  30.         return this;
  31.     },
  32.     addErrback: function(fn) {
  33.         this.ebh_.push(fn);
  34.         this.broadcast_();
  35.         return this;
  36.     },
  37.     broadcast_: function() {
  38.         if (!this.fired_) return;
  39.         this.broadcast_impl_(this.status_ ? this.cbh_ : this.ebh_, this.result_);
  40.         this.cbh_ = [];
  41.         this.ebh_ = [];
  42.     },
  43.     broadcast_impl_: function(list, arg) { // called only from 'broadcast_'
  44.         for(var cb = 0; cb < list.length; ++cb) {
  45.             list[cb].call(this, arg);
  46.         }
  47.     }
  48. };
  49.  
  50. /* ============ REQUESTER OBJECT ===========
  51.    Incapsulates cross-domain http async requests in userjs.
  52.    The data is passed through window.name varible. */
  53.  
  54. var serializeData = function(a) {
  55.     if (!(a instanceof Array)) a = [a];
  56.     var r = '[ ';
  57.     for(var i = 0; i < a.length; ++i) {
  58. //      r += "'" + a[i].toString().replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/'/g, "\\'") + "', ";
  59. // UNCOMMENT THIS
  60.     }
  61.     return (r += ']');
  62. }
  63. var unserializeData = function(s) {
  64.     return eval(s); // Mind security!
  65. }
  66.  
  67. var explode = function(s, delim, n) {
  68.     var p = 0;
  69.     var g = [];
  70.     for(var i = 0; n == undefined || i < n-1; ++i) {
  71.         var index = s.indexOf(delim, p);
  72.         if (index == -1) break;
  73.         g[i] = s.slice(p, index);
  74.         p = index+1;
  75.     }
  76.     if (n != undefined || i < n-1) {
  77.         g[i] = s.slice(p);
  78.     }
  79.     return g;
  80. }
  81.    
  82. /**
  83.  * Cross domain requests from Opera UserJS. Singleton.
  84.  * A  user-js handler at requested page must exist to prepare and return data to requesting page.
  85.  *
  86.  * Usage: let A is requesting page. B is a page at the remote domain to request from,
  87.  * A.domain, B.domain are the domains of A and B.
  88.  * Create a UserJS at A calling Requester.request, passing to B, and url of a page at A.domain.
  89.  * The latter page is called a stub and is used to exchange data with original requesting window.
  90.  * It must be an arbitrary page at original domain, better small-sized.
  91.  * Then create a UserJS handler for B. Get passed arguments by calling Requester.getArguments(),
  92.  * make proper preparations and requests (e.g. XMLHttpRequests to B.domain webservice), and return
  93.  * resulting array by calling Requester.returnData().
  94.  */
  95. Requester = {
  96.     default_timeout: 15000,
  97.     token: 'XDR1',
  98.  
  99.     /**
  100.      * Make cross-domain request.
  101.      *
  102.      * @param request_url URL to load
  103.      * @param stub_url any URL at requesting domain used to exchange data with original Requester
  104.      * @param data an array of strings to pass to handler script at 'request_url'
  105.      * @param timeout generate timeout error after 'timeout' msec
  106.      * @return deferred object receiving events
  107.      */
  108.     request: function (request_url, stub_url, data, timeout)
  109.     {
  110.         if (timeout == undefined) timeout = this.default_timeout;
  111.         var req_id = 'request'+(new Date()).getTime();
  112.        
  113.         var iframe = document.createElement('iframe');
  114.         document.body.appendChild(iframe);
  115.         iframe.setAttribute('src', request_url);
  116.         iframe.setAttribute('style', 'display: none;');
  117.         iframe.contentWindow.name = this.token + '#' + req_id + '#' + stub_url + '#' + serializeData(data);
  118.        
  119.         var deferred = new Deferred();
  120.         deferred.iframe = iframe;
  121.         deferred.req_id = req_id;
  122.         window[req_id] = deferred;
  123.        
  124.         setTimeout(function() {
  125.             if (!deferred.fired()) {
  126.                 deferred.errback(-1);
  127.             }
  128.         }, timeout);
  129.         deferred.addCallback(this.disposeFrame);
  130.         deferred.addErrback(this.disposeFrame);
  131.        
  132.         return deferred;
  133.     },
  134.    
  135.     /**
  136.      * Get rid of a deferred object and frame having been used. Used internally
  137.      */
  138.     /* private */ disposeFrame: function() {
  139.         this.iframe.parentNode.removeChild(this.iframe);
  140.         delete(window[this.req_id]);
  141.     },
  142.    
  143.     /**
  144.      * UserJS handler at requested url calls it to get the array of data passed by requesting script.
  145.      *
  146.      * @see Requester#request
  147.      * @returns array of data, or false if nothing requested by this requester
  148.      */
  149.     getArguments: function() {
  150.         var args = explode(window.name, '#', 4);
  151.         if (args[0] != this.token)
  152.             return false;
  153.         return unserializeData(args[3]);
  154.     },
  155.    
  156.     /**
  157.      * Pass an array of data to requesting page as a result.
  158.      * Deferred callback will be called with this array as an argument.
  159.      */
  160.     returnData: function(data) {
  161.         var args = explode(window.name, '#', 4);
  162.         var req_id = args[1];
  163.         var stub_url = args[2];
  164.         window.name = this.token + '#' + req_id + '#' + stub_url + '#' + serializeData(data);
  165.         location.replace(stub_url);
  166.     },
  167.    
  168.     /**
  169.      * Check if we are in stub.
  170.      *
  171.      * @return true if location.href is the stub page. False otherwise.
  172.      */
  173.     inStub: function() {
  174.         var args = explode(window.name, '#', 4);
  175.         var token = args[0];
  176.         var stub_url = args[2];
  177.         return token == this.token && location.href == stub_url;
  178.     },
  179.    
  180.     /**
  181.      * Pass the collected result to original requesting page.
  182.      */
  183.     runStub: function() {
  184.         var args = explode(window.name, '#', 4);
  185.         window.name = '';  
  186.         var req_id = args[1];
  187.         var data = args[3];
  188.        
  189.         if (!window.parent[req_id]) {  
  190.             log_("Requester: Deferred object disappeared.");
  191.             return;
  192.         }
  193.         deferred = window.parent[req_id];
  194.         window.parent.setTimeout(function() { // run in parent window thread
  195.             deferred.callback(unserializeData(data));
  196.         }, 0);
  197.     },
  198. };
  199. if (Requester.inStub())
  200. {
  201.     Requester.runStub();
  202. }
RAW Paste Data