cobot_client 1.2.4 → 1.3.0

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