push 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2463 @@
1
+ (function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {
2
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
3
+ /*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */
4
+ //
5
+ // easyXDM
6
+ // http://easyxdm.net/
7
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
8
+ //
9
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ // of this software and associated documentation files (the "Software"), to deal
11
+ // in the Software without restriction, including without limitation the rights
12
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ // copies of the Software, and to permit persons to whom the Software is
14
+ // furnished to do so, subject to the following conditions:
15
+ //
16
+ // The above copyright notice and this permission notice shall be included in
17
+ // all copies or substantial portions of the Software.
18
+ //
19
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ // THE SOFTWARE.
26
+ //
27
+
28
+ var global = this;
29
+ var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded
30
+ var emptyFn = Function.prototype;
31
+ var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4)
32
+ var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression
33
+ var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol
34
+ var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)
35
+ var easyXDM = {};
36
+ var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite
37
+ var IFRAME_PREFIX = "easyXDM_";
38
+ var HAS_NAME_PROPERTY_BUG;
39
+ var useHash = false; // whether to use the hash over the query
40
+
41
+
42
+ // http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
43
+ function isHostMethod(object, property){
44
+ var t = typeof object[property];
45
+ return t == 'function' ||
46
+ (!!(t == 'object' && object[property])) ||
47
+ t == 'unknown';
48
+ }
49
+
50
+ function isHostObject(object, property){
51
+ return !!(typeof(object[property]) == 'object' && object[property]);
52
+ }
53
+
54
+ // end
55
+
56
+ // http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
57
+ function isArray(o){
58
+ return Object.prototype.toString.call(o) === '[object Array]';
59
+ }
60
+
61
+ // end
62
+
63
+ function hasActiveX(name){
64
+ try {
65
+ var activeX = new ActiveXObject(name);
66
+ activeX = null;
67
+ return true;
68
+ }
69
+ catch (notSupportedException) {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ /*
75
+ * Cross Browser implementation for adding and removing event listeners.
76
+ */
77
+ var on, un;
78
+ if (isHostMethod(window, "addEventListener")) {
79
+ on = function(target, type, listener){
80
+ target.addEventListener(type, listener, false);
81
+ };
82
+ un = function(target, type, listener){
83
+ target.removeEventListener(type, listener, false);
84
+ };
85
+ }
86
+ else if (isHostMethod(window, "attachEvent")) {
87
+ on = function(object, sEvent, fpNotify){
88
+ object.attachEvent("on" + sEvent, fpNotify);
89
+ };
90
+ un = function(object, sEvent, fpNotify){
91
+ object.detachEvent("on" + sEvent, fpNotify);
92
+ };
93
+ }
94
+ else {
95
+ throw new Error("Browser not supported");
96
+ }
97
+
98
+ /*
99
+ * Cross Browser implementation of DOMContentLoaded.
100
+ */
101
+ var domIsReady = false, domReadyQueue = [], readyState;
102
+ if ("readyState" in document) {
103
+ // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and
104
+ // 'interactive' (HTML5 specs, recent WebKit builds) states.
105
+ // https://bugs.webkit.org/show_bug.cgi?id=45119
106
+ readyState = document.readyState;
107
+ domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));
108
+ }
109
+ else {
110
+ // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately
111
+ // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.
112
+ // We only need a body to add elements to, so the existence of document.body is enough for us.
113
+ domIsReady = !!document.body;
114
+ }
115
+
116
+ function dom_onReady(){
117
+ if (domIsReady) {
118
+ return;
119
+ }
120
+ domIsReady = true;
121
+ for (var i = 0; i < domReadyQueue.length; i++) {
122
+ domReadyQueue[i]();
123
+ }
124
+ domReadyQueue.length = 0;
125
+ }
126
+
127
+
128
+ if (!domIsReady) {
129
+ if (isHostMethod(window, "addEventListener")) {
130
+ on(document, "DOMContentLoaded", dom_onReady);
131
+ }
132
+ else {
133
+ on(document, "readystatechange", function(){
134
+ if (document.readyState == "complete") {
135
+ dom_onReady();
136
+ }
137
+ });
138
+ if (document.documentElement.doScroll && window === top) {
139
+ (function doScrollCheck(){
140
+ if (domIsReady) {
141
+ return;
142
+ }
143
+ // http://javascript.nwbox.com/IEContentLoaded/
144
+ try {
145
+ document.documentElement.doScroll("left");
146
+ }
147
+ catch (e) {
148
+ setTimeout(doScrollCheck, 1);
149
+ return;
150
+ }
151
+ dom_onReady();
152
+ }());
153
+ }
154
+ }
155
+
156
+ // A fallback to window.onload, that will always work
157
+ on(window, "load", dom_onReady);
158
+ }
159
+ /**
160
+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.
161
+ * If functions are added after this event then they will be executed immediately.
162
+ * @param {function} fn The function to add
163
+ * @param {Object} scope An optional scope for the function to be called with.
164
+ */
165
+ function whenReady(fn, scope){
166
+ if (domIsReady) {
167
+ fn.call(scope);
168
+ return;
169
+ }
170
+ domReadyQueue.push(function(){
171
+ fn.call(scope);
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Returns an instance of easyXDM from the parent window with
177
+ * respect to the namespace.
178
+ *
179
+ * @return An instance of easyXDM (in the parent window)
180
+ */
181
+ function getParentObject(){
182
+ var obj = parent;
183
+ if (namespace !== "") {
184
+ for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {
185
+ obj = obj[ii[i]];
186
+ }
187
+ }
188
+ return obj.easyXDM;
189
+ }
190
+
191
+ /**
192
+ * Removes easyXDM variable from the global scope. It also returns control
193
+ * of the easyXDM variable to whatever code used it before.
194
+ *
195
+ * @param {String} ns A string representation of an object that will hold
196
+ * an instance of easyXDM.
197
+ * @return An instance of easyXDM
198
+ */
199
+ function noConflict(ns){
200
+
201
+ window.easyXDM = _easyXDM;
202
+ namespace = ns;
203
+ if (namespace) {
204
+ IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";
205
+ }
206
+ return easyXDM;
207
+ }
208
+
209
+ /*
210
+ * Methods for working with URLs
211
+ */
212
+ /**
213
+ * Get the domain name from a url.
214
+ * @param {String} url The url to extract the domain from.
215
+ * @return The domain part of the url.
216
+ * @type {String}
217
+ */
218
+ function getDomainName(url){
219
+ return url.match(reURI)[3];
220
+ }
221
+
222
+ /**
223
+ * Get the port for a given URL, or "" if none
224
+ * @param {String} url The url to extract the port from.
225
+ * @return The port part of the url.
226
+ * @type {String}
227
+ */
228
+ function getPort(url){
229
+ return url.match(reURI)[4] || "";
230
+ }
231
+
232
+ /**
233
+ * Returns a string containing the schema, domain and if present the port
234
+ * @param {String} url The url to extract the location from
235
+ * @return {String} The location part of the url
236
+ */
237
+ function getLocation(url){
238
+ var m = url.match(reURI);
239
+ var proto = m[2], domain = m[3], port = m[4] || "";
240
+ if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {
241
+ port = "";
242
+ }
243
+ return proto + "//" + domain + port;
244
+ }
245
+
246
+ /**
247
+ * Resolves a relative url into an absolute one.
248
+ * @param {String} url The path to resolve.
249
+ * @return {String} The resolved url.
250
+ */
251
+ function resolveUrl(url){
252
+
253
+ // replace all // except the one in proto with /
254
+ url = url.replace(reDoubleSlash, "$1/");
255
+
256
+ // If the url is a valid url we do nothing
257
+ if (!url.match(/^(http||https):\/\//)) {
258
+ // If this is a relative path
259
+ var path = (url.substring(0, 1) === "/") ? "" : location.pathname;
260
+ if (path.substring(path.length - 1) !== "/") {
261
+ path = path.substring(0, path.lastIndexOf("/") + 1);
262
+ }
263
+
264
+ url = location.protocol + "//" + location.host + path + url;
265
+ }
266
+
267
+ // reduce all 'xyz/../' to just ''
268
+ while (reParent.test(url)) {
269
+ url = url.replace(reParent, "");
270
+ }
271
+
272
+ return url;
273
+ }
274
+
275
+ /**
276
+ * Appends the parameters to the given url.<br/>
277
+ * The base url can contain existing query parameters.
278
+ * @param {String} url The base url.
279
+ * @param {Object} parameters The parameters to add.
280
+ * @return {String} A new valid url with the parameters appended.
281
+ */
282
+ function appendQueryParameters(url, parameters){
283
+
284
+ var hash = "", indexOf = url.indexOf("#");
285
+ if (indexOf !== -1) {
286
+ hash = url.substring(indexOf);
287
+ url = url.substring(0, indexOf);
288
+ }
289
+ var q = [];
290
+ for (var key in parameters) {
291
+ if (parameters.hasOwnProperty(key)) {
292
+ q.push(key + "=" + encodeURIComponent(parameters[key]));
293
+ }
294
+ }
295
+ return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;
296
+ }
297
+
298
+
299
+ // build the query object either from location.query, if it contains the xdm_e argument, or from location.hash
300
+ var query = (function(input){
301
+ input = input.substring(1).split("&");
302
+ var data = {}, pair, i = input.length;
303
+ while (i--) {
304
+ pair = input[i].split("=");
305
+ data[pair[0]] = decodeURIComponent(pair[1]);
306
+ }
307
+ return data;
308
+ }(/xdm_e=/.test(location.search) ? location.search : location.hash));
309
+
310
+ /*
311
+ * Helper methods
312
+ */
313
+ /**
314
+ * Helper for checking if a variable/property is undefined
315
+ * @param {Object} v The variable to test
316
+ * @return {Boolean} True if the passed variable is undefined
317
+ */
318
+ function undef(v){
319
+ return typeof v === "undefined";
320
+ }
321
+
322
+ /**
323
+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.
324
+ * @return {JSON} A valid JSON conforming object, or null if not found.
325
+ */
326
+ var getJSON = function(){
327
+ var cached = {};
328
+ var obj = {
329
+ a: [1, 2, 3]
330
+ }, json = "{\"a\":[1,2,3]}";
331
+
332
+ if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {
333
+ // this is a working JSON instance
334
+ return JSON;
335
+ }
336
+ if (Object.toJSON) {
337
+ if (Object.toJSON(obj).replace((/\s/g), "") === json) {
338
+ // this is a working stringify method
339
+ cached.stringify = Object.toJSON;
340
+ }
341
+ }
342
+
343
+ if (typeof String.prototype.evalJSON === "function") {
344
+ obj = json.evalJSON();
345
+ if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {
346
+ // this is a working parse method
347
+ cached.parse = function(str){
348
+ return str.evalJSON();
349
+ };
350
+ }
351
+ }
352
+
353
+ if (cached.stringify && cached.parse) {
354
+ // Only memoize the result if we have valid instance
355
+ getJSON = function(){
356
+ return cached;
357
+ };
358
+ return cached;
359
+ }
360
+ return null;
361
+ };
362
+
363
+ /**
364
+ * Applies properties from the source object to the target object.<br/>
365
+ * @param {Object} target The target of the properties.
366
+ * @param {Object} source The source of the properties.
367
+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.
368
+ */
369
+ function apply(destination, source, noOverwrite){
370
+ var member;
371
+ for (var prop in source) {
372
+ if (source.hasOwnProperty(prop)) {
373
+ if (prop in destination) {
374
+ member = source[prop];
375
+ if (typeof member === "object") {
376
+ apply(destination[prop], member, noOverwrite);
377
+ }
378
+ else if (!noOverwrite) {
379
+ destination[prop] = source[prop];
380
+ }
381
+ }
382
+ else {
383
+ destination[prop] = source[prop];
384
+ }
385
+ }
386
+ }
387
+ return destination;
388
+ }
389
+
390
+ // This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].
391
+ function testForNamePropertyBug(){
392
+ var el = document.createElement("iframe");
393
+ el.name = IFRAME_PREFIX + "TEST";
394
+ apply(el.style, {
395
+ position: "absolute",
396
+ left: "-2000px",
397
+ top: "0px"
398
+ });
399
+ document.body.appendChild(el);
400
+ HAS_NAME_PROPERTY_BUG = el.contentWindow !== window.frames[el.name];
401
+ document.body.removeChild(el);
402
+ }
403
+
404
+ /**
405
+ * Creates a frame and appends it to the DOM.
406
+ * @param config {object} This object can have the following properties
407
+ * <ul>
408
+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>
409
+ * <li> {object} attr The attributes that should be set on the frame.</li>
410
+ * <li> {DOMElement} container Its parent element (Optional).</li>
411
+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>
412
+ * </ul>
413
+ * @return The frames DOMElement
414
+ * @type DOMElement
415
+ */
416
+ function createFrame(config){
417
+ if (undef(HAS_NAME_PROPERTY_BUG)) {
418
+ testForNamePropertyBug();
419
+ }
420
+ var frame;
421
+ // This is to work around the problems in IE6/7 with setting the name property.
422
+ // Internally this is set as 'submitName' instead when using 'iframe.name = ...'
423
+ // This is not required by easyXDM itself, but is to facilitate other use cases
424
+ if (HAS_NAME_PROPERTY_BUG) {
425
+ frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");
426
+ }
427
+ else {
428
+ frame = document.createElement("IFRAME");
429
+ frame.name = config.props.name;
430
+ }
431
+
432
+ frame.id = frame.name = config.props.name;
433
+ delete config.props.name;
434
+
435
+ if (config.onLoad) {
436
+ on(frame, "load", config.onLoad);
437
+ }
438
+
439
+ if (typeof config.container == "string") {
440
+ config.container = document.getElementById(config.container);
441
+ }
442
+
443
+ if (!config.container) {
444
+ // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.
445
+ frame.style.position = "absolute";
446
+ frame.style.top = "-2000px";
447
+ config.container = document.body;
448
+ }
449
+
450
+ // HACK for some reason, IE needs the source set
451
+ // after the frame has been appended into the DOM
452
+ // so remove the src, and set it afterwards
453
+ var src = config.props.src;
454
+ delete config.props.src;
455
+
456
+ // transfer properties to the frame
457
+ apply(frame, config.props);
458
+
459
+ frame.border = frame.frameBorder = 0;
460
+ config.container.appendChild(frame);
461
+
462
+ // HACK see above
463
+ frame.src = src;
464
+ config.props.src = src;
465
+
466
+ return frame;
467
+ }
468
+
469
+ /**
470
+ * Check whether a domain is allowed using an Access Control List.
471
+ * The ACL can contain * and ? as wildcards, or can be regular expressions.
472
+ * If regular expressions they need to begin with ^ and end with $.
473
+ * @param {Array/String} acl The list of allowed domains
474
+ * @param {String} domain The domain to test.
475
+ * @return {Boolean} True if the domain is allowed, false if not.
476
+ */
477
+ function checkAcl(acl, domain){
478
+ // normalize into an array
479
+ if (typeof acl == "string") {
480
+ acl = [acl];
481
+ }
482
+ var re, i = acl.length;
483
+ while (i--) {
484
+ re = acl[i];
485
+ re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));
486
+ if (re.test(domain)) {
487
+ return true;
488
+ }
489
+ }
490
+ return false;
491
+ }
492
+
493
+ /*
494
+ * Functions related to stacks
495
+ */
496
+ /**
497
+ * Prepares an array of stack-elements suitable for the current configuration
498
+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.
499
+ * @return {Array} An array of stack-elements with the TransportElement at index 0.
500
+ */
501
+ function prepareTransportStack(config){
502
+ var protocol = config.protocol, stackEls;
503
+ config.isHost = config.isHost || undef(query.xdm_p);
504
+ useHash = config.hash || false;
505
+
506
+ if (!config.props) {
507
+ config.props = {};
508
+ }
509
+ if (!config.isHost) {
510
+ config.channel = query.xdm_c;
511
+ config.secret = query.xdm_s;
512
+ config.remote = query.xdm_e;
513
+ protocol = query.xdm_p;
514
+ if (config.acl && !checkAcl(config.acl, config.remote)) {
515
+ throw new Error("Access denied for " + config.remote);
516
+ }
517
+ }
518
+ else {
519
+ config.remote = resolveUrl(config.remote);
520
+ config.channel = config.channel || "default" + channelId++;
521
+ config.secret = Math.random().toString(16).substring(2);
522
+ if (undef(protocol)) {
523
+ if (getLocation(location.href) == getLocation(config.remote)) {
524
+ /*
525
+ * Both documents has the same origin, lets use direct access.
526
+ */
527
+ protocol = "4";
528
+ }
529
+ else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {
530
+ /*
531
+ * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+
532
+ */
533
+ protocol = "1";
534
+ }
535
+ else if (isHostMethod(window, "ActiveXObject") && hasActiveX("ShockwaveFlash.ShockwaveFlash")) {
536
+ /*
537
+ * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS
538
+ */
539
+ protocol = "6";
540
+ }
541
+ else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {
542
+ /*
543
+ * This is supported in Gecko (Firefox 1+)
544
+ */
545
+ protocol = "5";
546
+ }
547
+ else if (config.remoteHelper) {
548
+ /*
549
+ * This is supported in all browsers that retains the value of window.name when
550
+ * navigating from one domain to another, and where parent.frames[foo] can be used
551
+ * to get access to a frame from the same domain
552
+ */
553
+ config.remoteHelper = resolveUrl(config.remoteHelper);
554
+ protocol = "2";
555
+ }
556
+ else {
557
+ /*
558
+ * This is supported in all browsers where [window].location is writable for all
559
+ * The resize event will be used if resize is supported and the iframe is not put
560
+ * into a container, else polling will be used.
561
+ */
562
+ protocol = "0";
563
+ }
564
+ }
565
+ }
566
+
567
+ switch (protocol) {
568
+ case "0":// 0 = HashTransport
569
+ apply(config, {
570
+ interval: 100,
571
+ delay: 2000,
572
+ useResize: true,
573
+ useParent: false,
574
+ usePolling: false
575
+ }, true);
576
+ if (config.isHost) {
577
+ if (!config.local) {
578
+ // If no local is set then we need to find an image hosted on the current domain
579
+ var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;
580
+ var i = images.length;
581
+ while (i--) {
582
+ image = images[i];
583
+ if (image.src.substring(0, domain.length) === domain) {
584
+ config.local = image.src;
585
+ break;
586
+ }
587
+ }
588
+ if (!config.local) {
589
+ // If no local was set, and we are unable to find a suitable file, then we resort to using the current window
590
+ config.local = window;
591
+ }
592
+ }
593
+
594
+ var parameters = {
595
+ xdm_c: config.channel,
596
+ xdm_p: 0
597
+ };
598
+
599
+ if (config.local === window) {
600
+ // We are using the current window to listen to
601
+ config.usePolling = true;
602
+ config.useParent = true;
603
+ config.local = location.protocol + "//" + location.host + location.pathname + location.search;
604
+ parameters.xdm_e = config.local;
605
+ parameters.xdm_pa = 1; // use parent
606
+ }
607
+ else {
608
+ parameters.xdm_e = resolveUrl(config.local);
609
+ }
610
+
611
+ if (config.container) {
612
+ config.useResize = false;
613
+ parameters.xdm_po = 1; // use polling
614
+ }
615
+ config.remote = appendQueryParameters(config.remote, parameters);
616
+ }
617
+ else {
618
+ apply(config, {
619
+ channel: query.xdm_c,
620
+ remote: query.xdm_e,
621
+ useParent: !undef(query.xdm_pa),
622
+ usePolling: !undef(query.xdm_po),
623
+ useResize: config.useParent ? false : config.useResize
624
+ });
625
+ }
626
+ stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({
627
+ encode: true,
628
+ maxLength: 4000 - config.remote.length
629
+ }), new easyXDM.stack.VerifyBehavior({
630
+ initiate: config.isHost
631
+ })];
632
+ break;
633
+ case "1":
634
+ stackEls = [new easyXDM.stack.PostMessageTransport(config)];
635
+ break;
636
+ case "2":
637
+ stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({
638
+ initiate: config.isHost
639
+ })];
640
+ break;
641
+ case "3":
642
+ stackEls = [new easyXDM.stack.NixTransport(config)];
643
+ break;
644
+ case "4":
645
+ stackEls = [new easyXDM.stack.SameOriginTransport(config)];
646
+ break;
647
+ case "5":
648
+ stackEls = [new easyXDM.stack.FrameElementTransport(config)];
649
+ break;
650
+ case "6":
651
+ if (!config.swf) {
652
+ config.swf = "../../tools/easyxdm.swf";
653
+ }
654
+ stackEls = [new easyXDM.stack.FlashTransport(config)];
655
+ break;
656
+ }
657
+ // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization
658
+ stackEls.push(new easyXDM.stack.QueueBehavior({
659
+ lazy: config.lazy,
660
+ remove: true
661
+ }));
662
+ return stackEls;
663
+ }
664
+
665
+ /**
666
+ * Chains all the separate stack elements into a single usable stack.<br/>
667
+ * If an element is missing a necessary method then it will have a pass-through method applied.
668
+ * @param {Array} stackElements An array of stack elements to be linked.
669
+ * @return {easyXDM.stack.StackElement} The last element in the chain.
670
+ */
671
+ function chainStack(stackElements){
672
+ var stackEl, defaults = {
673
+ incoming: function(message, origin){
674
+ this.up.incoming(message, origin);
675
+ },
676
+ outgoing: function(message, recipient){
677
+ this.down.outgoing(message, recipient);
678
+ },
679
+ callback: function(success){
680
+ this.up.callback(success);
681
+ },
682
+ init: function(){
683
+ this.down.init();
684
+ },
685
+ destroy: function(){
686
+ this.down.destroy();
687
+ }
688
+ };
689
+ for (var i = 0, len = stackElements.length; i < len; i++) {
690
+ stackEl = stackElements[i];
691
+ apply(stackEl, defaults, true);
692
+ if (i !== 0) {
693
+ stackEl.down = stackElements[i - 1];
694
+ }
695
+ if (i !== len - 1) {
696
+ stackEl.up = stackElements[i + 1];
697
+ }
698
+ }
699
+ return stackEl;
700
+ }
701
+
702
+ /**
703
+ * This will remove a stackelement from its stack while leaving the stack functional.
704
+ * @param {Object} element The elment to remove from the stack.
705
+ */
706
+ function removeFromStack(element){
707
+ element.up.down = element.down;
708
+ element.down.up = element.up;
709
+ element.up = element.down = null;
710
+ }
711
+
712
+ /*
713
+ * Export the main object and any other methods applicable
714
+ */
715
+ /**
716
+ * @class easyXDM
717
+ * A javascript library providing cross-browser, cross-domain messaging/RPC.
718
+ * @version 2.4.13.0
719
+ * @singleton
720
+ */
721
+ apply(easyXDM, {
722
+ /**
723
+ * The version of the library
724
+ * @type {string}
725
+ */
726
+ version: "2.4.13.0",
727
+ /**
728
+ * This is a map containing all the query parameters passed to the document.
729
+ * All the values has been decoded using decodeURIComponent.
730
+ * @type {object}
731
+ */
732
+ query: query,
733
+ /**
734
+ * @private
735
+ */
736
+ stack: {},
737
+ /**
738
+ * Applies properties from the source object to the target object.<br/>
739
+ * @param {object} target The target of the properties.
740
+ * @param {object} source The source of the properties.
741
+ * @param {boolean} noOverwrite Set to True to only set non-existing properties.
742
+ */
743
+ apply: apply,
744
+
745
+ /**
746
+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.
747
+ * @return {JSON} A valid JSON conforming object, or null if not found.
748
+ */
749
+ getJSONObject: getJSON,
750
+ /**
751
+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.
752
+ * If functions are added after this event then they will be executed immediately.
753
+ * @param {function} fn The function to add
754
+ * @param {object} scope An optional scope for the function to be called with.
755
+ */
756
+ whenReady: whenReady,
757
+ /**
758
+ * Removes easyXDM variable from the global scope. It also returns control
759
+ * of the easyXDM variable to whatever code used it before.
760
+ *
761
+ * @param {String} ns A string representation of an object that will hold
762
+ * an instance of easyXDM.
763
+ * @return An instance of easyXDM
764
+ */
765
+ noConflict: noConflict
766
+ });
767
+
768
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
769
+ /*global console, _FirebugCommandLine, easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */
770
+ //
771
+ // easyXDM
772
+ // http://easyxdm.net/
773
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
774
+ //
775
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
776
+ // of this software and associated documentation files (the "Software"), to deal
777
+ // in the Software without restriction, including without limitation the rights
778
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
779
+ // copies of the Software, and to permit persons to whom the Software is
780
+ // furnished to do so, subject to the following conditions:
781
+ //
782
+ // The above copyright notice and this permission notice shall be included in
783
+ // all copies or substantial portions of the Software.
784
+ //
785
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
786
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
787
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
788
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
789
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
790
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
791
+ // THE SOFTWARE.
792
+ //
793
+
794
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
795
+ /*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */
796
+ //
797
+ // easyXDM
798
+ // http://easyxdm.net/
799
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
800
+ //
801
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
802
+ // of this software and associated documentation files (the "Software"), to deal
803
+ // in the Software without restriction, including without limitation the rights
804
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
805
+ // copies of the Software, and to permit persons to whom the Software is
806
+ // furnished to do so, subject to the following conditions:
807
+ //
808
+ // The above copyright notice and this permission notice shall be included in
809
+ // all copies or substantial portions of the Software.
810
+ //
811
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
812
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
813
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
814
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
815
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
816
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
817
+ // THE SOFTWARE.
818
+ //
819
+
820
+ /**
821
+ * @class easyXDM.DomHelper
822
+ * Contains methods for dealing with the DOM
823
+ * @singleton
824
+ */
825
+ easyXDM.DomHelper = {
826
+ /**
827
+ * Provides a consistent interface for adding eventhandlers
828
+ * @param {Object} target The target to add the event to
829
+ * @param {String} type The name of the event
830
+ * @param {Function} listener The listener
831
+ */
832
+ on: on,
833
+ /**
834
+ * Provides a consistent interface for removing eventhandlers
835
+ * @param {Object} target The target to remove the event from
836
+ * @param {String} type The name of the event
837
+ * @param {Function} listener The listener
838
+ */
839
+ un: un,
840
+ /**
841
+ * Checks for the presence of the JSON object.
842
+ * If it is not present it will use the supplied path to load the JSON2 library.
843
+ * This should be called in the documents head right after the easyXDM script tag.
844
+ * http://json.org/json2.js
845
+ * @param {String} path A valid path to json2.js
846
+ */
847
+ requiresJSON: function(path){
848
+ if (!isHostObject(window, "JSON")) {
849
+ // we need to encode the < in order to avoid an illegal token error
850
+ // when the script is inlined in a document.
851
+ document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');
852
+ }
853
+ }
854
+ };
855
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
856
+ /*global easyXDM, window, escape, unescape, debug */
857
+ //
858
+ // easyXDM
859
+ // http://easyxdm.net/
860
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
861
+ //
862
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
863
+ // of this software and associated documentation files (the "Software"), to deal
864
+ // in the Software without restriction, including without limitation the rights
865
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
866
+ // copies of the Software, and to permit persons to whom the Software is
867
+ // furnished to do so, subject to the following conditions:
868
+ //
869
+ // The above copyright notice and this permission notice shall be included in
870
+ // all copies or substantial portions of the Software.
871
+ //
872
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
873
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
874
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
875
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
876
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
877
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
878
+ // THE SOFTWARE.
879
+ //
880
+
881
+ (function(){
882
+ // The map containing the stored functions
883
+ var _map = {};
884
+
885
+ /**
886
+ * @class easyXDM.Fn
887
+ * This contains methods related to function handling, such as storing callbacks.
888
+ * @singleton
889
+ * @namespace easyXDM
890
+ */
891
+ easyXDM.Fn = {
892
+ /**
893
+ * Stores a function using the given name for reference
894
+ * @param {String} name The name that the function should be referred by
895
+ * @param {Function} fn The function to store
896
+ * @namespace easyXDM.fn
897
+ */
898
+ set: function(name, fn){
899
+ _map[name] = fn;
900
+ },
901
+ /**
902
+ * Retrieves the function referred to by the given name
903
+ * @param {String} name The name of the function to retrieve
904
+ * @param {Boolean} del If the function should be deleted after retrieval
905
+ * @return {Function} The stored function
906
+ * @namespace easyXDM.fn
907
+ */
908
+ get: function(name, del){
909
+ var fn = _map[name];
910
+
911
+ if (del) {
912
+ delete _map[name];
913
+ }
914
+ return fn;
915
+ }
916
+ };
917
+
918
+ }());
919
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
920
+ /*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */
921
+ //
922
+ // easyXDM
923
+ // http://easyxdm.net/
924
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
925
+ //
926
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
927
+ // of this software and associated documentation files (the "Software"), to deal
928
+ // in the Software without restriction, including without limitation the rights
929
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
930
+ // copies of the Software, and to permit persons to whom the Software is
931
+ // furnished to do so, subject to the following conditions:
932
+ //
933
+ // The above copyright notice and this permission notice shall be included in
934
+ // all copies or substantial portions of the Software.
935
+ //
936
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
937
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
938
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
939
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
940
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
941
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
942
+ // THE SOFTWARE.
943
+ //
944
+
945
+ /**
946
+ * @class easyXDM.Socket
947
+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>
948
+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>
949
+ * Internally different stacks will be used depending on the browsers features and the available parameters.
950
+ * <h2>How to set up</h2>
951
+ * Setting up the provider:
952
+ * <pre><code>
953
+ * var socket = new easyXDM.Socket({
954
+ * &nbsp; local: "name.html",
955
+ * &nbsp; onReady: function(){
956
+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket
957
+ * &nbsp; &nbsp; socket.postMessage("foo-message");
958
+ * &nbsp; },
959
+ * &nbsp; onMessage: function(message, origin) {
960
+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);
961
+ * &nbsp; }
962
+ * });
963
+ * </code></pre>
964
+ * Setting up the consumer:
965
+ * <pre><code>
966
+ * var socket = new easyXDM.Socket({
967
+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",
968
+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",
969
+ * &nbsp; onReady: function(){
970
+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket
971
+ * &nbsp; &nbsp; socket.postMessage("foo-message");
972
+ * &nbsp; },
973
+ * &nbsp; onMessage: function(message, origin) {
974
+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);
975
+ * &nbsp; }
976
+ * });
977
+ * </code></pre>
978
+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property
979
+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.
980
+ * @namespace easyXDM
981
+ * @constructor
982
+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.
983
+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed.
984
+ * @cfg {String} remote (Consumer only) The url to the providers document.
985
+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.
986
+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window. Optional, defaults to 2000.
987
+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.
988
+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.
989
+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.
990
+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.
991
+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.
992
+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>
993
+ * This can contain the wildcards ? and *. Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.
994
+ * If none of the patterns match an Error will be thrown.
995
+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>.
996
+ * Properties such as 'name' and 'src' will be overrided. Optional.
997
+ */
998
+ easyXDM.Socket = function(config){
999
+
1000
+ // create the stack
1001
+ var stack = chainStack(prepareTransportStack(config).concat([{
1002
+ incoming: function(message, origin){
1003
+ config.onMessage(message, origin);
1004
+ },
1005
+ callback: function(success){
1006
+ if (config.onReady) {
1007
+ config.onReady(success);
1008
+ }
1009
+ }
1010
+ }])), recipient = getLocation(config.remote);
1011
+
1012
+ // set the origin
1013
+ this.origin = getLocation(config.remote);
1014
+
1015
+ /**
1016
+ * Initiates the destruction of the stack.
1017
+ */
1018
+ this.destroy = function(){
1019
+ stack.destroy();
1020
+ };
1021
+
1022
+ /**
1023
+ * Posts a message to the remote end of the channel
1024
+ * @param {String} message The message to send
1025
+ */
1026
+ this.postMessage = function(message){
1027
+ stack.outgoing(message, recipient);
1028
+ };
1029
+
1030
+ stack.init();
1031
+ };
1032
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1033
+ /*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */
1034
+ //
1035
+ // easyXDM
1036
+ // http://easyxdm.net/
1037
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1038
+ //
1039
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1040
+ // of this software and associated documentation files (the "Software"), to deal
1041
+ // in the Software without restriction, including without limitation the rights
1042
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1043
+ // copies of the Software, and to permit persons to whom the Software is
1044
+ // furnished to do so, subject to the following conditions:
1045
+ //
1046
+ // The above copyright notice and this permission notice shall be included in
1047
+ // all copies or substantial portions of the Software.
1048
+ //
1049
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1050
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1051
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1052
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1053
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1054
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1055
+ // THE SOFTWARE.
1056
+ //
1057
+
1058
+ /**
1059
+ * @class easyXDM.Rpc
1060
+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation
1061
+ * of methods to be called from the remote end.<br/>
1062
+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>
1063
+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.
1064
+ * <h2>How to set up</h2>
1065
+ * <pre><code>
1066
+ * var rpc = new easyXDM.Rpc({
1067
+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.
1068
+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",
1069
+ * &nbsp; onReady: function(){
1070
+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy
1071
+ * &nbsp; &nbsp; rpc.foo(...
1072
+ * &nbsp; }
1073
+ * },{
1074
+ * &nbsp; local: {..},
1075
+ * &nbsp; remote: {..}
1076
+ * });
1077
+ * </code></pre>
1078
+ *
1079
+ * <h2>Exposing functions (procedures)</h2>
1080
+ * <pre><code>
1081
+ * var rpc = new easyXDM.Rpc({
1082
+ * &nbsp; ...
1083
+ * },{
1084
+ * &nbsp; local: {
1085
+ * &nbsp; &nbsp; nameOfMethod: {
1086
+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){
1087
+ * &nbsp; &nbsp; &nbsp; &nbsp; ...
1088
+ * &nbsp; &nbsp; &nbsp; }
1089
+ * &nbsp; &nbsp; },
1090
+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation
1091
+ * &nbsp; &nbsp; nameOfAnotherMethod: function(arg1, arg2, success, error){
1092
+ * &nbsp; &nbsp; }
1093
+ * &nbsp; },
1094
+ * &nbsp; remote: {...}
1095
+ * });
1096
+ * </code></pre>
1097
+
1098
+ * The function referenced by [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>
1099
+ * To send a successfull result back you can use
1100
+ * <pre><code>
1101
+ * return foo;
1102
+ * </pre></code>
1103
+ * or
1104
+ * <pre><code>
1105
+ * success(foo);
1106
+ * </pre></code>
1107
+ * To return an error you can use
1108
+ * <pre><code>
1109
+ * throw new Error("foo error");
1110
+ * </code></pre>
1111
+ * or
1112
+ * <pre><code>
1113
+ * error("foo error");
1114
+ * </code></pre>
1115
+ *
1116
+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>
1117
+ * The definition of the remote end is quite similar:
1118
+ * <pre><code>
1119
+ * var rpc = new easyXDM.Rpc({
1120
+ * &nbsp; ...
1121
+ * },{
1122
+ * &nbsp; local: {...},
1123
+ * &nbsp; remote: {
1124
+ * &nbsp; &nbsp; nameOfMethod: {}
1125
+ * &nbsp; }
1126
+ * });
1127
+ * </code></pre>
1128
+ * To call a remote method use
1129
+ * <pre><code>
1130
+ * rpc.nameOfMethod("arg1", "arg2", function(value) {
1131
+ * &nbsp; alert("success: " + value);
1132
+ * }, function(message) {
1133
+ * &nbsp; alert("error: " + message + );
1134
+ * });
1135
+ * </code></pre>
1136
+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>
1137
+ * When called with no callback a JSON-RPC 2.0 notification will be executed.
1138
+ * Be aware that you will not be notified of any errors with this method.
1139
+ * <br/>
1140
+ * <h2>Specifying a custom serializer</h2>
1141
+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library
1142
+ * then you can specify a custom serializer using <code>serializer: foo</code>
1143
+ * <pre><code>
1144
+ * var rpc = new easyXDM.Rpc({
1145
+ * &nbsp; ...
1146
+ * },{
1147
+ * &nbsp; local: {...},
1148
+ * &nbsp; remote: {...},
1149
+ * &nbsp; serializer : {
1150
+ * &nbsp; &nbsp; parse: function(string){ ... },
1151
+ * &nbsp; &nbsp; stringify: function(object) {...}
1152
+ * &nbsp; }
1153
+ * });
1154
+ * </code></pre>
1155
+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.
1156
+ * @namespace easyXDM
1157
+ * @constructor
1158
+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.
1159
+ * @param {Object} jsonRpcConfig The description of the interface to implement.
1160
+ */
1161
+ easyXDM.Rpc = function(config, jsonRpcConfig){
1162
+
1163
+ // expand shorthand notation
1164
+ if (jsonRpcConfig.local) {
1165
+ for (var method in jsonRpcConfig.local) {
1166
+ if (jsonRpcConfig.local.hasOwnProperty(method)) {
1167
+ var member = jsonRpcConfig.local[method];
1168
+ if (typeof member === "function") {
1169
+ jsonRpcConfig.local[method] = {
1170
+ method: member
1171
+ };
1172
+ }
1173
+ }
1174
+ }
1175
+ }
1176
+
1177
+ // create the stack
1178
+ var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {
1179
+ callback: function(success){
1180
+ if (config.onReady) {
1181
+ config.onReady(success);
1182
+ }
1183
+ }
1184
+ }]));
1185
+
1186
+ // set the origin
1187
+ this.origin = getLocation(config.remote);
1188
+
1189
+
1190
+ /**
1191
+ * Initiates the destruction of the stack.
1192
+ */
1193
+ this.destroy = function(){
1194
+ stack.destroy();
1195
+ };
1196
+
1197
+ stack.init();
1198
+ };
1199
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1200
+ /*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/
1201
+ //
1202
+ // easyXDM
1203
+ // http://easyxdm.net/
1204
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1205
+ //
1206
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1207
+ // of this software and associated documentation files (the "Software"), to deal
1208
+ // in the Software without restriction, including without limitation the rights
1209
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1210
+ // copies of the Software, and to permit persons to whom the Software is
1211
+ // furnished to do so, subject to the following conditions:
1212
+ //
1213
+ // The above copyright notice and this permission notice shall be included in
1214
+ // all copies or substantial portions of the Software.
1215
+ //
1216
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1217
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1218
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1219
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1220
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1221
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1222
+ // THE SOFTWARE.
1223
+ //
1224
+
1225
+ /**
1226
+ * @class easyXDM.stack.SameOriginTransport
1227
+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>
1228
+ * This can be useful for testing and for when the main application supports both internal and external sources.
1229
+ * @namespace easyXDM.stack
1230
+ * @constructor
1231
+ * @param {Object} config The transports configuration.
1232
+ * @cfg {String} remote The remote document to communicate with.
1233
+ */
1234
+ easyXDM.stack.SameOriginTransport = function(config){
1235
+ var pub, frame, send, targetOrigin;
1236
+
1237
+ return (pub = {
1238
+ outgoing: function(message, domain, fn){
1239
+ send(message);
1240
+ if (fn) {
1241
+ fn();
1242
+ }
1243
+ },
1244
+ destroy: function(){
1245
+ if (frame) {
1246
+ frame.parentNode.removeChild(frame);
1247
+ frame = null;
1248
+ }
1249
+ },
1250
+ onDOMReady: function(){
1251
+ targetOrigin = getLocation(config.remote);
1252
+
1253
+ if (config.isHost) {
1254
+ // set up the iframe
1255
+ apply(config.props, {
1256
+ src: appendQueryParameters(config.remote, {
1257
+ xdm_e: location.protocol + "//" + location.host + location.pathname,
1258
+ xdm_c: config.channel,
1259
+ xdm_p: 4 // 4 = SameOriginTransport
1260
+ }),
1261
+ name: IFRAME_PREFIX + config.channel + "_provider"
1262
+ });
1263
+ frame = createFrame(config);
1264
+ easyXDM.Fn.set(config.channel, function(sendFn){
1265
+ send = sendFn;
1266
+ setTimeout(function(){
1267
+ pub.up.callback(true);
1268
+ }, 0);
1269
+ return function(msg){
1270
+ pub.up.incoming(msg, targetOrigin);
1271
+ };
1272
+ });
1273
+ }
1274
+ else {
1275
+ send = getParentObject().Fn.get(config.channel, true)(function(msg){
1276
+ pub.up.incoming(msg, targetOrigin);
1277
+ });
1278
+ setTimeout(function(){
1279
+ pub.up.callback(true);
1280
+ }, 0);
1281
+ }
1282
+ },
1283
+ init: function(){
1284
+ whenReady(pub.onDOMReady, pub);
1285
+ }
1286
+ });
1287
+ };
1288
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1289
+ /*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, getDomainName,, getPort, query*/
1290
+ //
1291
+ // easyXDM
1292
+ // http://easyxdm.net/
1293
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1294
+ //
1295
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1296
+ // of this software and associated documentation files (the "Software"), to deal
1297
+ // in the Software without restriction, including without limitation the rights
1298
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1299
+ // copies of the Software, and to permit persons to whom the Software is
1300
+ // furnished to do so, subject to the following conditions:
1301
+ //
1302
+ // The above copyright notice and this permission notice shall be included in
1303
+ // all copies or substantial portions of the Software.
1304
+ //
1305
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1306
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1307
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1308
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1309
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1310
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1311
+ // THE SOFTWARE.
1312
+ //
1313
+
1314
+ /**
1315
+ * @class easyXDM.stack.FlashTransport
1316
+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.
1317
+ * @namespace easyXDM.stack
1318
+ * @constructor
1319
+ * @param {Object} config The transports configuration.
1320
+ * @cfg {String} remote The remote domain to communicate with.
1321
+ * @cfg {String} secret the pre-shared secret used to secure the communication.
1322
+ * @cfg {String} swf The path to the swf file
1323
+ */
1324
+ easyXDM.stack.FlashTransport = function(config){
1325
+ var pub, // the public interface
1326
+ frame, send, targetOrigin, swf, swfContainer;
1327
+
1328
+ function onMessage(message, origin){
1329
+ setTimeout(function(){
1330
+ pub.up.incoming(message, targetOrigin);
1331
+ }, 0);
1332
+ }
1333
+
1334
+ /**
1335
+ * This method adds the SWF to the DOM and prepares the initialization of the channel
1336
+ */
1337
+ function addSwf(callback){
1338
+ // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.
1339
+ var url = config.swf + "?host=" + config.isHost;
1340
+ var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);
1341
+
1342
+ // prepare the init function that will fire once the swf is ready
1343
+ easyXDM.Fn.set("flash_loaded", function(){
1344
+ easyXDM.stack.FlashTransport.__swf = swf = swfContainer.firstChild;
1345
+ callback();
1346
+ });
1347
+
1348
+ // create the container that will hold the swf
1349
+ swfContainer = document.createElement('div');
1350
+ apply(swfContainer.style, {
1351
+ height: "1px",
1352
+ width: "1px",
1353
+ position: "absolute",
1354
+ left: 0,
1355
+ top: 0
1356
+ });
1357
+ document.body.appendChild(swfContainer);
1358
+
1359
+ // create the object/embed
1360
+ var flashVars = "proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;
1361
+ swfContainer.innerHTML = "<object height='1' width='1' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +
1362
+ "<param name='allowScriptAccess' value='always'></param>" +
1363
+ "<param name='wmode' value='transparent'>" +
1364
+ "<param name='movie' value='" +
1365
+ url +
1366
+ "'></param>" +
1367
+ "<param name='flashvars' value='" +
1368
+ flashVars +
1369
+ "'></param>" +
1370
+ "<embed type='application/x-shockwave-flash' FlashVars='" +
1371
+ flashVars +
1372
+ "' allowScriptAccess='always' wmode='transparent' src='" +
1373
+ url +
1374
+ "' height='1' width='1'></embed>" +
1375
+ "</object>";
1376
+ }
1377
+
1378
+ return (pub = {
1379
+ outgoing: function(message, domain, fn){
1380
+ swf.postMessage(config.channel, message.toString());
1381
+ if (fn) {
1382
+ fn();
1383
+ }
1384
+ },
1385
+ destroy: function(){
1386
+ try {
1387
+ swf.destroyChannel(config.channel);
1388
+ }
1389
+ catch (e) {
1390
+ }
1391
+ swf = null;
1392
+ if (frame) {
1393
+ frame.parentNode.removeChild(frame);
1394
+ frame = null;
1395
+ }
1396
+ },
1397
+ onDOMReady: function(){
1398
+
1399
+ targetOrigin = config.remote;
1400
+ swf = easyXDM.stack.FlashTransport.__swf;
1401
+
1402
+ /**
1403
+ * Prepare the code that will be run after the swf has been intialized
1404
+ */
1405
+ easyXDM.Fn.set("flash_" + config.channel + "_init", function(){
1406
+ setTimeout(function(){
1407
+ pub.up.callback(true);
1408
+ });
1409
+ });
1410
+
1411
+ // set up the omMessage handler
1412
+ easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);
1413
+
1414
+ var fn = function(){
1415
+ // create the channel
1416
+ swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);
1417
+
1418
+ if (config.isHost) {
1419
+ // set up the iframe
1420
+ apply(config.props, {
1421
+ src: appendQueryParameters(config.remote, {
1422
+ xdm_e: getLocation(location.href),
1423
+ xdm_c: config.channel,
1424
+ xdm_p: 6, // 6 = FlashTransport
1425
+ xdm_s: config.secret
1426
+ }),
1427
+ name: IFRAME_PREFIX + config.channel + "_provider"
1428
+ });
1429
+ frame = createFrame(config);
1430
+ }
1431
+ };
1432
+
1433
+ if (swf) {
1434
+ // if the swf is in place and we are the consumer
1435
+ fn();
1436
+ }
1437
+ else {
1438
+ // if the swf does not yet exist
1439
+ addSwf(fn);
1440
+ }
1441
+ },
1442
+ init: function(){
1443
+ whenReady(pub.onDOMReady, pub);
1444
+ }
1445
+ });
1446
+ };
1447
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1448
+ /*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/
1449
+ //
1450
+ // easyXDM
1451
+ // http://easyxdm.net/
1452
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1453
+ //
1454
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1455
+ // of this software and associated documentation files (the "Software"), to deal
1456
+ // in the Software without restriction, including without limitation the rights
1457
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1458
+ // copies of the Software, and to permit persons to whom the Software is
1459
+ // furnished to do so, subject to the following conditions:
1460
+ //
1461
+ // The above copyright notice and this permission notice shall be included in
1462
+ // all copies or substantial portions of the Software.
1463
+ //
1464
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1465
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1466
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1467
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1468
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1469
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1470
+ // THE SOFTWARE.
1471
+ //
1472
+
1473
+ /**
1474
+ * @class easyXDM.stack.PostMessageTransport
1475
+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>
1476
+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>
1477
+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>
1478
+ * @namespace easyXDM.stack
1479
+ * @constructor
1480
+ * @param {Object} config The transports configuration.
1481
+ * @cfg {String} remote The remote domain to communicate with.
1482
+ */
1483
+ easyXDM.stack.PostMessageTransport = function(config){
1484
+ var pub, // the public interface
1485
+ frame, // the remote frame, if any
1486
+ callerWindow, // the window that we will call with
1487
+ targetOrigin; // the domain to communicate with
1488
+ /**
1489
+ * Resolves the origin from the event object
1490
+ * @private
1491
+ * @param {Object} event The messageevent
1492
+ * @return {String} The scheme, host and port of the origin
1493
+ */
1494
+ function _getOrigin(event){
1495
+ if (event.origin) {
1496
+ // This is the HTML5 property
1497
+ return getLocation(event.origin);
1498
+ }
1499
+ if (event.uri) {
1500
+ // From earlier implementations
1501
+ return getLocation(event.uri);
1502
+ }
1503
+ if (event.domain) {
1504
+ // This is the last option and will fail if the
1505
+ // origin is not using the same schema as we are
1506
+ return location.protocol + "//" + event.domain;
1507
+ }
1508
+ throw "Unable to retrieve the origin of the event";
1509
+ }
1510
+
1511
+ /**
1512
+ * This is the main implementation for the onMessage event.<br/>
1513
+ * It checks the validity of the origin and passes the message on if appropriate.
1514
+ * @private
1515
+ * @param {Object} event The messageevent
1516
+ */
1517
+ function _window_onMessage(event){
1518
+ var origin = _getOrigin(event);
1519
+ if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {
1520
+ pub.up.incoming(event.data.substring(config.channel.length + 1), origin);
1521
+ }
1522
+ }
1523
+
1524
+ return (pub = {
1525
+ outgoing: function(message, domain, fn){
1526
+ callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);
1527
+ if (fn) {
1528
+ fn();
1529
+ }
1530
+ },
1531
+ destroy: function(){
1532
+ un(window, "message", _window_onMessage);
1533
+ if (frame) {
1534
+ callerWindow = null;
1535
+ frame.parentNode.removeChild(frame);
1536
+ frame = null;
1537
+ }
1538
+ },
1539
+ onDOMReady: function(){
1540
+ targetOrigin = getLocation(config.remote);
1541
+ if (config.isHost) {
1542
+ // add the event handler for listening
1543
+ var waitForReady = function(event){
1544
+ if (event.data == config.channel + "-ready") {
1545
+ // replace the eventlistener
1546
+ callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;
1547
+ un(window, "message", waitForReady);
1548
+ on(window, "message", _window_onMessage);
1549
+ setTimeout(function(){
1550
+ pub.up.callback(true);
1551
+ }, 0);
1552
+ }
1553
+ };
1554
+ on(window, "message", waitForReady);
1555
+
1556
+ // set up the iframe
1557
+ apply(config.props, {
1558
+ src: appendQueryParameters(config.remote, {
1559
+ xdm_e: getLocation(location.href),
1560
+ xdm_c: config.channel,
1561
+ xdm_p: 1 // 1 = PostMessage
1562
+ }),
1563
+ name: IFRAME_PREFIX + config.channel + "_provider"
1564
+ });
1565
+ frame = createFrame(config);
1566
+ }
1567
+ else {
1568
+ // add the event handler for listening
1569
+ on(window, "message", _window_onMessage);
1570
+ callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;
1571
+ callerWindow.postMessage(config.channel + "-ready", targetOrigin);
1572
+
1573
+ setTimeout(function(){
1574
+ pub.up.callback(true);
1575
+ }, 0);
1576
+ }
1577
+ },
1578
+ init: function(){
1579
+ whenReady(pub.onDOMReady, pub);
1580
+ }
1581
+ });
1582
+ };
1583
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1584
+ /*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/
1585
+ //
1586
+ // easyXDM
1587
+ // http://easyxdm.net/
1588
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1589
+ //
1590
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1591
+ // of this software and associated documentation files (the "Software"), to deal
1592
+ // in the Software without restriction, including without limitation the rights
1593
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1594
+ // copies of the Software, and to permit persons to whom the Software is
1595
+ // furnished to do so, subject to the following conditions:
1596
+ //
1597
+ // The above copyright notice and this permission notice shall be included in
1598
+ // all copies or substantial portions of the Software.
1599
+ //
1600
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1602
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1603
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1604
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1605
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1606
+ // THE SOFTWARE.
1607
+ //
1608
+
1609
+ /**
1610
+ * @class easyXDM.stack.FrameElementTransport
1611
+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>
1612
+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.
1613
+ * @namespace easyXDM.stack
1614
+ * @constructor
1615
+ * @param {Object} config The transports configuration.
1616
+ * @cfg {String} remote The remote document to communicate with.
1617
+ */
1618
+ easyXDM.stack.FrameElementTransport = function(config){
1619
+ var pub, frame, send, targetOrigin;
1620
+
1621
+ return (pub = {
1622
+ outgoing: function(message, domain, fn){
1623
+ send.call(this, message);
1624
+ if (fn) {
1625
+ fn();
1626
+ }
1627
+ },
1628
+ destroy: function(){
1629
+ if (frame) {
1630
+ frame.parentNode.removeChild(frame);
1631
+ frame = null;
1632
+ }
1633
+ },
1634
+ onDOMReady: function(){
1635
+ targetOrigin = getLocation(config.remote);
1636
+
1637
+ if (config.isHost) {
1638
+ // set up the iframe
1639
+ apply(config.props, {
1640
+ src: appendQueryParameters(config.remote, {
1641
+ xdm_e: getLocation(location.href),
1642
+ xdm_c: config.channel,
1643
+ xdm_p: 5 // 5 = FrameElementTransport
1644
+ }),
1645
+ name: IFRAME_PREFIX + config.channel + "_provider"
1646
+ });
1647
+ frame = createFrame(config);
1648
+ frame.fn = function(sendFn){
1649
+ delete frame.fn;
1650
+ send = sendFn;
1651
+ setTimeout(function(){
1652
+ pub.up.callback(true);
1653
+ }, 0);
1654
+ // remove the function so that it cannot be used to overwrite the send function later on
1655
+ return function(msg){
1656
+ pub.up.incoming(msg, targetOrigin);
1657
+ };
1658
+ };
1659
+ }
1660
+ else {
1661
+ // This is to mitigate origin-spoofing
1662
+ if (document.referrer && getLocation(document.referrer) != query.xdm_e) {
1663
+ window.top.location = query.xdm_e;
1664
+ }
1665
+ send = window.frameElement.fn(function(msg){
1666
+ pub.up.incoming(msg, targetOrigin);
1667
+ });
1668
+ pub.up.callback(true);
1669
+ }
1670
+ },
1671
+ init: function(){
1672
+ whenReady(pub.onDOMReady, pub);
1673
+ }
1674
+ });
1675
+ };
1676
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1677
+ /*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/
1678
+ //
1679
+ // easyXDM
1680
+ // http://easyxdm.net/
1681
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1682
+ //
1683
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1684
+ // of this software and associated documentation files (the "Software"), to deal
1685
+ // in the Software without restriction, including without limitation the rights
1686
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1687
+ // copies of the Software, and to permit persons to whom the Software is
1688
+ // furnished to do so, subject to the following conditions:
1689
+ //
1690
+ // The above copyright notice and this permission notice shall be included in
1691
+ // all copies or substantial portions of the Software.
1692
+ //
1693
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1694
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1695
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1696
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1697
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1698
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1699
+ // THE SOFTWARE.
1700
+ //
1701
+
1702
+ /**
1703
+ * @class easyXDM.stack.NameTransport
1704
+ * NameTransport uses the window.name property to relay data.
1705
+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>
1706
+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.
1707
+ * @constructor
1708
+ * @param {Object} config The transports configuration.
1709
+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.
1710
+ * @namespace easyXDM.stack
1711
+ */
1712
+ easyXDM.stack.NameTransport = function(config){
1713
+
1714
+ var pub; // the public interface
1715
+ var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;
1716
+
1717
+ function _sendMessage(message){
1718
+ var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;
1719
+ callerWindow.contentWindow.sendMessage(message, url);
1720
+ }
1721
+
1722
+ function _onReady(){
1723
+ if (isHost) {
1724
+ if (++readyCount === 2 || !isHost) {
1725
+ pub.up.callback(true);
1726
+ }
1727
+ }
1728
+ else {
1729
+ _sendMessage("ready");
1730
+ pub.up.callback(true);
1731
+ }
1732
+ }
1733
+
1734
+ function _onMessage(message){
1735
+ pub.up.incoming(message, remoteOrigin);
1736
+ }
1737
+
1738
+ function _onLoad(){
1739
+ if (callback) {
1740
+ setTimeout(function(){
1741
+ callback(true);
1742
+ }, 0);
1743
+ }
1744
+ }
1745
+
1746
+ return (pub = {
1747
+ outgoing: function(message, domain, fn){
1748
+ callback = fn;
1749
+ _sendMessage(message);
1750
+ },
1751
+ destroy: function(){
1752
+ callerWindow.parentNode.removeChild(callerWindow);
1753
+ callerWindow = null;
1754
+ if (isHost) {
1755
+ remoteWindow.parentNode.removeChild(remoteWindow);
1756
+ remoteWindow = null;
1757
+ }
1758
+ },
1759
+ onDOMReady: function(){
1760
+ isHost = config.isHost;
1761
+ readyCount = 0;
1762
+ remoteOrigin = getLocation(config.remote);
1763
+ config.local = resolveUrl(config.local);
1764
+
1765
+ if (isHost) {
1766
+ // Register the callback
1767
+ easyXDM.Fn.set(config.channel, function(message){
1768
+ if (isHost && message === "ready") {
1769
+ // Replace the handler
1770
+ easyXDM.Fn.set(config.channel, _onMessage);
1771
+ _onReady();
1772
+ }
1773
+ });
1774
+
1775
+ // Set up the frame that points to the remote instance
1776
+ remoteUrl = appendQueryParameters(config.remote, {
1777
+ xdm_e: config.local,
1778
+ xdm_c: config.channel,
1779
+ xdm_p: 2
1780
+ });
1781
+ apply(config.props, {
1782
+ src: remoteUrl + '#' + config.channel,
1783
+ name: IFRAME_PREFIX + config.channel + "_provider"
1784
+ });
1785
+ remoteWindow = createFrame(config);
1786
+ }
1787
+ else {
1788
+ config.remoteHelper = config.remote;
1789
+ easyXDM.Fn.set(config.channel, _onMessage);
1790
+ }
1791
+ // Set up the iframe that will be used for the transport
1792
+
1793
+ callerWindow = createFrame({
1794
+ props: {
1795
+ src: config.local + "#_4" + config.channel
1796
+ },
1797
+ onLoad: function onLoad(){
1798
+ // Remove the handler
1799
+ var w = callerWindow || this;
1800
+ un(w, "load", onLoad);
1801
+ easyXDM.Fn.set(config.channel + "_load", _onLoad);
1802
+ (function test(){
1803
+ if (typeof w.contentWindow.sendMessage == "function") {
1804
+ _onReady();
1805
+ }
1806
+ else {
1807
+ setTimeout(test, 50);
1808
+ }
1809
+ }());
1810
+ }
1811
+ });
1812
+ },
1813
+ init: function(){
1814
+ whenReady(pub.onDOMReady, pub);
1815
+ }
1816
+ });
1817
+ };
1818
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1819
+ /*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/
1820
+ //
1821
+ // easyXDM
1822
+ // http://easyxdm.net/
1823
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1824
+ //
1825
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1826
+ // of this software and associated documentation files (the "Software"), to deal
1827
+ // in the Software without restriction, including without limitation the rights
1828
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1829
+ // copies of the Software, and to permit persons to whom the Software is
1830
+ // furnished to do so, subject to the following conditions:
1831
+ //
1832
+ // The above copyright notice and this permission notice shall be included in
1833
+ // all copies or substantial portions of the Software.
1834
+ //
1835
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1836
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1837
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1838
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1839
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1840
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1841
+ // THE SOFTWARE.
1842
+ //
1843
+
1844
+ /**
1845
+ * @class easyXDM.stack.HashTransport
1846
+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>
1847
+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>
1848
+ * @namespace easyXDM.stack
1849
+ * @constructor
1850
+ * @param {Object} config The transports configuration.
1851
+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.
1852
+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.
1853
+ * @cfg {Number} interval The interval used when polling for messages.
1854
+ */
1855
+ easyXDM.stack.HashTransport = function(config){
1856
+ var pub;
1857
+ var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;
1858
+ var useParent, _remoteOrigin;
1859
+
1860
+ function _sendMessage(message){
1861
+ if (!_callerWindow) {
1862
+ return;
1863
+ }
1864
+ var url = config.remote + "#" + (_msgNr++) + "_" + message;
1865
+ ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;
1866
+ }
1867
+
1868
+ function _handleHash(hash){
1869
+ _lastMsg = hash;
1870
+ pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);
1871
+ }
1872
+
1873
+ /**
1874
+ * Checks location.hash for a new message and relays this to the receiver.
1875
+ * @private
1876
+ */
1877
+ function _pollHash(){
1878
+ if (!_listenerWindow) {
1879
+ return;
1880
+ }
1881
+ var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");
1882
+ if (indexOf != -1) {
1883
+ hash = href.substring(indexOf);
1884
+ }
1885
+ if (hash && hash != _lastMsg) {
1886
+ _handleHash(hash);
1887
+ }
1888
+ }
1889
+
1890
+ function _attachListeners(){
1891
+ _timer = setInterval(_pollHash, pollInterval);
1892
+ }
1893
+
1894
+ return (pub = {
1895
+ outgoing: function(message, domain){
1896
+ _sendMessage(message);
1897
+ },
1898
+ destroy: function(){
1899
+ window.clearInterval(_timer);
1900
+ if (isHost || !useParent) {
1901
+ _callerWindow.parentNode.removeChild(_callerWindow);
1902
+ }
1903
+ _callerWindow = null;
1904
+ },
1905
+ onDOMReady: function(){
1906
+ isHost = config.isHost;
1907
+ pollInterval = config.interval;
1908
+ _lastMsg = "#" + config.channel;
1909
+ _msgNr = 0;
1910
+ useParent = config.useParent;
1911
+ _remoteOrigin = getLocation(config.remote);
1912
+ if (isHost) {
1913
+ config.props = {
1914
+ src: config.remote,
1915
+ name: IFRAME_PREFIX + config.channel + "_provider"
1916
+ };
1917
+ if (useParent) {
1918
+ config.onLoad = function(){
1919
+ _listenerWindow = window;
1920
+ _attachListeners();
1921
+ pub.up.callback(true);
1922
+ };
1923
+ }
1924
+ else {
1925
+ var tries = 0, max = config.delay / 50;
1926
+ (function getRef(){
1927
+ if (++tries > max) {
1928
+ throw new Error("Unable to reference listenerwindow");
1929
+ }
1930
+ try {
1931
+ _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];
1932
+ }
1933
+ catch (ex) {
1934
+ }
1935
+ if (_listenerWindow) {
1936
+ _attachListeners();
1937
+ pub.up.callback(true);
1938
+ }
1939
+ else {
1940
+ setTimeout(getRef, 50);
1941
+ }
1942
+ }());
1943
+ }
1944
+ _callerWindow = createFrame(config);
1945
+ }
1946
+ else {
1947
+ _listenerWindow = window;
1948
+ _attachListeners();
1949
+ if (useParent) {
1950
+ _callerWindow = parent;
1951
+ pub.up.callback(true);
1952
+ }
1953
+ else {
1954
+ apply(config, {
1955
+ props: {
1956
+ src: config.remote + "#" + config.channel + new Date(),
1957
+ name: IFRAME_PREFIX + config.channel + "_consumer"
1958
+ },
1959
+ onLoad: function(){
1960
+ pub.up.callback(true);
1961
+ }
1962
+ });
1963
+ _callerWindow = createFrame(config);
1964
+ }
1965
+ }
1966
+ },
1967
+ init: function(){
1968
+ whenReady(pub.onDOMReady, pub);
1969
+ }
1970
+ });
1971
+ };
1972
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
1973
+ /*global easyXDM, window, escape, unescape, debug */
1974
+ //
1975
+ // easyXDM
1976
+ // http://easyxdm.net/
1977
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
1978
+ //
1979
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1980
+ // of this software and associated documentation files (the "Software"), to deal
1981
+ // in the Software without restriction, including without limitation the rights
1982
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1983
+ // copies of the Software, and to permit persons to whom the Software is
1984
+ // furnished to do so, subject to the following conditions:
1985
+ //
1986
+ // The above copyright notice and this permission notice shall be included in
1987
+ // all copies or substantial portions of the Software.
1988
+ //
1989
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1990
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1991
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1992
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1993
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1994
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1995
+ // THE SOFTWARE.
1996
+ //
1997
+
1998
+ /**
1999
+ * @class easyXDM.stack.ReliableBehavior
2000
+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.
2001
+ * @namespace easyXDM.stack
2002
+ * @constructor
2003
+ * @param {Object} config The behaviors configuration.
2004
+ */
2005
+ easyXDM.stack.ReliableBehavior = function(config){
2006
+ var pub, // the public interface
2007
+ callback; // the callback to execute when we have a confirmed success/failure
2008
+ var idOut = 0, idIn = 0, currentMessage = "";
2009
+
2010
+ return (pub = {
2011
+ incoming: function(message, origin){
2012
+ var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");
2013
+ message = message.substring(indexOf + 1);
2014
+
2015
+ if (ack[0] == idOut) {
2016
+ currentMessage = "";
2017
+ if (callback) {
2018
+ callback(true);
2019
+ }
2020
+ }
2021
+ if (message.length > 0) {
2022
+ pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);
2023
+ if (idIn != ack[1]) {
2024
+ idIn = ack[1];
2025
+ pub.up.incoming(message, origin);
2026
+ }
2027
+ }
2028
+
2029
+ },
2030
+ outgoing: function(message, origin, fn){
2031
+ currentMessage = message;
2032
+ callback = fn;
2033
+ pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);
2034
+ }
2035
+ });
2036
+ };
2037
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
2038
+ /*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/
2039
+ //
2040
+ // easyXDM
2041
+ // http://easyxdm.net/
2042
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
2043
+ //
2044
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2045
+ // of this software and associated documentation files (the "Software"), to deal
2046
+ // in the Software without restriction, including without limitation the rights
2047
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2048
+ // copies of the Software, and to permit persons to whom the Software is
2049
+ // furnished to do so, subject to the following conditions:
2050
+ //
2051
+ // The above copyright notice and this permission notice shall be included in
2052
+ // all copies or substantial portions of the Software.
2053
+ //
2054
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2055
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2056
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2057
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2058
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2059
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2060
+ // THE SOFTWARE.
2061
+ //
2062
+
2063
+ /**
2064
+ * @class easyXDM.stack.QueueBehavior
2065
+ * This is a behavior that enables queueing of messages. <br/>
2066
+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.
2067
+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the
2068
+ * set length.
2069
+ * @namespace easyXDM.stack
2070
+ * @constructor
2071
+ * @param {Object} config The behaviors configuration. Optional.
2072
+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.
2073
+ */
2074
+ easyXDM.stack.QueueBehavior = function(config){
2075
+ var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;
2076
+
2077
+ function dispatch(){
2078
+ if (config.remove && queue.length === 0) {
2079
+ removeFromStack(pub);
2080
+ return;
2081
+ }
2082
+ if (waiting || queue.length === 0 || destroying) {
2083
+ return;
2084
+ }
2085
+ waiting = true;
2086
+ var message = queue.shift();
2087
+
2088
+ pub.down.outgoing(message.data, message.origin, function(success){
2089
+ waiting = false;
2090
+ if (message.callback) {
2091
+ setTimeout(function(){
2092
+ message.callback(success);
2093
+ }, 0);
2094
+ }
2095
+ dispatch();
2096
+ });
2097
+ }
2098
+ return (pub = {
2099
+ init: function(){
2100
+ if (undef(config)) {
2101
+ config = {};
2102
+ }
2103
+ if (config.maxLength) {
2104
+ maxLength = config.maxLength;
2105
+ doFragment = true;
2106
+ }
2107
+ if (config.lazy) {
2108
+ lazy = true;
2109
+ }
2110
+ else {
2111
+ pub.down.init();
2112
+ }
2113
+ },
2114
+ callback: function(success){
2115
+ waiting = false;
2116
+ var up = pub.up; // in case dispatch calls removeFromStack
2117
+ dispatch();
2118
+ up.callback(success);
2119
+ },
2120
+ incoming: function(message, origin){
2121
+ if (doFragment) {
2122
+ var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);
2123
+ incoming += message.substring(indexOf + 1);
2124
+ if (seq === 0) {
2125
+ if (config.encode) {
2126
+ incoming = decodeURIComponent(incoming);
2127
+ }
2128
+ pub.up.incoming(incoming, origin);
2129
+ incoming = "";
2130
+ }
2131
+ }
2132
+ else {
2133
+ pub.up.incoming(message, origin);
2134
+ }
2135
+ },
2136
+ outgoing: function(message, origin, fn){
2137
+ if (config.encode) {
2138
+ message = encodeURIComponent(message);
2139
+ }
2140
+ var fragments = [], fragment;
2141
+ if (doFragment) {
2142
+ // fragment into chunks
2143
+ while (message.length !== 0) {
2144
+ fragment = message.substring(0, maxLength);
2145
+ message = message.substring(fragment.length);
2146
+ fragments.push(fragment);
2147
+ }
2148
+ // enqueue the chunks
2149
+ while ((fragment = fragments.shift())) {
2150
+ queue.push({
2151
+ data: fragments.length + "_" + fragment,
2152
+ origin: origin,
2153
+ callback: fragments.length === 0 ? fn : null
2154
+ });
2155
+ }
2156
+ }
2157
+ else {
2158
+ queue.push({
2159
+ data: message,
2160
+ origin: origin,
2161
+ callback: fn
2162
+ });
2163
+ }
2164
+ if (lazy) {
2165
+ pub.down.init();
2166
+ }
2167
+ else {
2168
+ dispatch();
2169
+ }
2170
+ },
2171
+ destroy: function(){
2172
+ destroying = true;
2173
+ pub.down.destroy();
2174
+ }
2175
+ });
2176
+ };
2177
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
2178
+ /*global easyXDM, window, escape, unescape, undef, debug */
2179
+ //
2180
+ // easyXDM
2181
+ // http://easyxdm.net/
2182
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
2183
+ //
2184
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2185
+ // of this software and associated documentation files (the "Software"), to deal
2186
+ // in the Software without restriction, including without limitation the rights
2187
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2188
+ // copies of the Software, and to permit persons to whom the Software is
2189
+ // furnished to do so, subject to the following conditions:
2190
+ //
2191
+ // The above copyright notice and this permission notice shall be included in
2192
+ // all copies or substantial portions of the Software.
2193
+ //
2194
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2195
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2196
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2197
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2198
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2199
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2200
+ // THE SOFTWARE.
2201
+ //
2202
+
2203
+ /**
2204
+ * @class easyXDM.stack.VerifyBehavior
2205
+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,
2206
+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.
2207
+ * @namespace easyXDM.stack
2208
+ * @constructor
2209
+ * @param {Object} config The behaviors configuration.
2210
+ * @cfg {Boolean} initiate If the verification should be initiated from this end.
2211
+ */
2212
+ easyXDM.stack.VerifyBehavior = function(config){
2213
+ var pub, mySecret, theirSecret, verified = false;
2214
+
2215
+ function startVerification(){
2216
+ mySecret = Math.random().toString(16).substring(2);
2217
+ pub.down.outgoing(mySecret);
2218
+ }
2219
+
2220
+ return (pub = {
2221
+ incoming: function(message, origin){
2222
+ var indexOf = message.indexOf("_");
2223
+ if (indexOf === -1) {
2224
+ if (message === mySecret) {
2225
+ pub.up.callback(true);
2226
+ }
2227
+ else if (!theirSecret) {
2228
+ theirSecret = message;
2229
+ if (!config.initiate) {
2230
+ startVerification();
2231
+ }
2232
+ pub.down.outgoing(message);
2233
+ }
2234
+ }
2235
+ else {
2236
+ if (message.substring(0, indexOf) === theirSecret) {
2237
+ pub.up.incoming(message.substring(indexOf + 1), origin);
2238
+ }
2239
+ }
2240
+ },
2241
+ outgoing: function(message, origin, fn){
2242
+ pub.down.outgoing(mySecret + "_" + message, origin, fn);
2243
+ },
2244
+ callback: function(success){
2245
+ if (config.initiate) {
2246
+ startVerification();
2247
+ }
2248
+ }
2249
+ });
2250
+ };
2251
+ /*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/
2252
+ /*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */
2253
+ //
2254
+ // easyXDM
2255
+ // http://easyxdm.net/
2256
+ // Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
2257
+ //
2258
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
2259
+ // of this software and associated documentation files (the "Software"), to deal
2260
+ // in the Software without restriction, including without limitation the rights
2261
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2262
+ // copies of the Software, and to permit persons to whom the Software is
2263
+ // furnished to do so, subject to the following conditions:
2264
+ //
2265
+ // The above copyright notice and this permission notice shall be included in
2266
+ // all copies or substantial portions of the Software.
2267
+ //
2268
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2269
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2270
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2271
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2272
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2273
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2274
+ // THE SOFTWARE.
2275
+ //
2276
+
2277
+ /**
2278
+ * @class easyXDM.stack.RpcBehavior
2279
+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>
2280
+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.
2281
+ * @namespace easyXDM.stack
2282
+ * @constructor
2283
+ * @param {Object} proxy The object to apply the methods to.
2284
+ * @param {Object} config The definition of the local and remote interface to implement.
2285
+ * @cfg {Object} local The local interface to expose.
2286
+ * @cfg {Object} remote The remote methods to expose through the proxy.
2287
+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.
2288
+ */
2289
+ easyXDM.stack.RpcBehavior = function(proxy, config){
2290
+ var pub, serializer = config.serializer || getJSON();
2291
+ var _callbackCounter = 0, _callbacks = {};
2292
+
2293
+ /**
2294
+ * Serializes and sends the message
2295
+ * @private
2296
+ * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.
2297
+ */
2298
+ function _send(data){
2299
+ data.jsonrpc = "2.0";
2300
+ pub.down.outgoing(serializer.stringify(data));
2301
+ }
2302
+
2303
+ /**
2304
+ * Creates a method that implements the given definition
2305
+ * @private
2306
+ * @param {Object} The method configuration
2307
+ * @param {String} method The name of the method
2308
+ * @return {Function} A stub capable of proxying the requested method call
2309
+ */
2310
+ function _createMethod(definition, method){
2311
+ var slice = Array.prototype.slice;
2312
+
2313
+ return function(){
2314
+ var l = arguments.length, callback, message = {
2315
+ method: method
2316
+ };
2317
+
2318
+ if (l > 0 && typeof arguments[l - 1] === "function") {
2319
+ //with callback, procedure
2320
+ if (l > 1 && typeof arguments[l - 2] === "function") {
2321
+ // two callbacks, success and error
2322
+ callback = {
2323
+ success: arguments[l - 2],
2324
+ error: arguments[l - 1]
2325
+ };
2326
+ message.params = slice.call(arguments, 0, l - 2);
2327
+ }
2328
+ else {
2329
+ // single callback, success
2330
+ callback = {
2331
+ success: arguments[l - 1]
2332
+ };
2333
+ message.params = slice.call(arguments, 0, l - 1);
2334
+ }
2335
+ _callbacks["" + (++_callbackCounter)] = callback;
2336
+ message.id = _callbackCounter;
2337
+ }
2338
+ else {
2339
+ // no callbacks, a notification
2340
+ message.params = slice.call(arguments, 0);
2341
+ }
2342
+ if (definition.namedParams && message.params.length === 1) {
2343
+ message.params = message.params[0];
2344
+ }
2345
+ // Send the method request
2346
+ _send(message);
2347
+ };
2348
+ }
2349
+
2350
+ /**
2351
+ * Executes the exposed method
2352
+ * @private
2353
+ * @param {String} method The name of the method
2354
+ * @param {Number} id The callback id to use
2355
+ * @param {Function} method The exposed implementation
2356
+ * @param {Array} params The parameters supplied by the remote end
2357
+ */
2358
+ function _executeMethod(method, id, fn, params){
2359
+ if (!fn) {
2360
+ if (id) {
2361
+ _send({
2362
+ id: id,
2363
+ error: {
2364
+ code: -32601,
2365
+ message: "Procedure not found."
2366
+ }
2367
+ });
2368
+ }
2369
+ return;
2370
+ }
2371
+
2372
+ var success, error;
2373
+ if (id) {
2374
+ success = function(result){
2375
+ success = emptyFn;
2376
+ _send({
2377
+ id: id,
2378
+ result: result
2379
+ });
2380
+ };
2381
+ error = function(message, data){
2382
+ error = emptyFn;
2383
+ var msg = {
2384
+ id: id,
2385
+ error: {
2386
+ code: -32099,
2387
+ message: message
2388
+ }
2389
+ };
2390
+ if (data) {
2391
+ msg.error.data = data;
2392
+ }
2393
+ _send(msg);
2394
+ };
2395
+ }
2396
+ else {
2397
+ success = error = emptyFn;
2398
+ }
2399
+ // Call local method
2400
+ if (!isArray(params)) {
2401
+ params = [params];
2402
+ }
2403
+ try {
2404
+ var result = fn.method.apply(fn.scope, params.concat([success, error]));
2405
+ if (!undef(result)) {
2406
+ success(result);
2407
+ }
2408
+ }
2409
+ catch (ex1) {
2410
+ error(ex1.message);
2411
+ }
2412
+ }
2413
+
2414
+ return (pub = {
2415
+ incoming: function(message, origin){
2416
+ var data = serializer.parse(message);
2417
+ if (data.method) {
2418
+ // A method call from the remote end
2419
+ if (config.handle) {
2420
+ config.handle(data, _send);
2421
+ }
2422
+ else {
2423
+ _executeMethod(data.method, data.id, config.local[data.method], data.params);
2424
+ }
2425
+ }
2426
+ else {
2427
+ // A method response from the other end
2428
+ var callback = _callbacks[data.id];
2429
+
2430
+ if (data.error) {
2431
+ if (callback.error) {
2432
+ callback.error(data.error);
2433
+ }
2434
+ }
2435
+ else if (callback.success) {
2436
+ callback.success(data.result);
2437
+ }
2438
+ delete _callbacks[data.id];
2439
+ }
2440
+ },
2441
+ init: function(){
2442
+ if (config.remote) {
2443
+ // Implement the remote sides exposed methods
2444
+ for (var method in config.remote) {
2445
+ if (config.remote.hasOwnProperty(method)) {
2446
+ proxy[method] = _createMethod(config.remote[method], method);
2447
+ }
2448
+ }
2449
+ }
2450
+ pub.down.init();
2451
+ },
2452
+ destroy: function(){
2453
+ for (var method in config.remote) {
2454
+ if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {
2455
+ delete proxy[method];
2456
+ }
2457
+ }
2458
+ pub.down.destroy();
2459
+ }
2460
+ });
2461
+ };
2462
+ global.easyXDM = easyXDM;
2463
+ })(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);