easyxdm-rails 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module EasyxdmRails
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,214 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>easyXDM cross-domain XHMLHttpRequest provider</title>
5
+ <script type="text/javascript" src="../easyXDM.debug.js">
6
+ // This should be changed so that it points to the minified version before use in production.
7
+ </script>
8
+ <script type="text/javascript">
9
+ // Update to point to your copy
10
+ easyXDM.DomHelper.requiresJSON("../json2.js");
11
+ </script>
12
+ <script type="text/javascript">
13
+
14
+ /*
15
+ * This is a CORS (Cross-Origin Resource Sharing) and AJAX enabled endpoint for easyXDM.
16
+ * The ACL code is adapted from pmxdr (http://github.com/eligrey/pmxdr/) by Eli Grey (http://eligrey.com/)
17
+ *
18
+ */
19
+ // From 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
+ /**
28
+ * Creates a cross-browser XMLHttpRequest object
29
+ * @return {XMLHttpRequest} A XMLHttpRequest object.
30
+ */
31
+ var getXhr = (function(){
32
+ if (isHostMethod(window, "XMLHttpRequest")) {
33
+ return function(){
34
+ return new XMLHttpRequest();
35
+ };
36
+ }
37
+ else {
38
+ var item = (function(){
39
+ var list = ["Microsoft", "Msxml2", "Msxml3"], i = list.length;
40
+ while (i--) {
41
+ try {
42
+ item = list[i] + ".XMLHTTP";
43
+ var obj = new ActiveXObject(item);
44
+ return item;
45
+ }
46
+ catch (e) {
47
+ }
48
+ }
49
+ }());
50
+ return function(){
51
+ return new ActiveXObject(item);
52
+ };
53
+ }
54
+ }());
55
+
56
+ // this file is by default set up to use Access Control - this means that it will use the headers set by the server to decide whether or not to allow the call to return
57
+ var useAccessControl = true;
58
+ // always trusted origins, can be exact strings or regular expressions
59
+ var alwaysTrustedOrigins = [(/\.?easyxdm\.net/), (/xdm1/)];
60
+
61
+ // instantiate a new easyXDM object which will handle the request
62
+ var remote = new easyXDM.Rpc({
63
+ local: "../name.html",
64
+ swf: "../easyxdm.swf"
65
+ }, {
66
+ local: {
67
+ // define the exposed method
68
+ request: function(config, success, error){
69
+
70
+ // apply default values if not set
71
+ easyXDM.apply(config, {
72
+ method: "POST",
73
+ headers: {
74
+ "Content-Type": "application/x-www-form-urlencoded",
75
+ "X-Requested-With": "XMLHttpRequest"
76
+ },
77
+ success: Function.prototype,
78
+ error: function(msg){
79
+ throw new Error(msg);
80
+ },
81
+ data: {},
82
+ timeout: 10 * 1000
83
+ }, true);
84
+
85
+ // set the CORS request header
86
+ // only if there is no XHR2 features
87
+ if (!window.XMLHttpRequest || !('withCredentials' in (new XMLHttpRequest))) {
88
+ config.headers.Origin = remote.origin;
89
+ }
90
+
91
+ var isPOST = config.method == "POST";
92
+
93
+ // convert the data into a format we can send to the server
94
+ var pairs = [];
95
+ for (var key in config.data) {
96
+ if (config.data.hasOwnProperty(key)) {
97
+ pairs.push(encodeURIComponent(key) + "=" + encodeURIComponent(config.data[key]));
98
+ }
99
+ }
100
+ var data = pairs.join("&");
101
+
102
+ // create the XMLHttpRequest object
103
+ var req = getXhr();
104
+ var url = !isPOST && data
105
+ ? config.url + (~config.url.indexOf('?') ? '&' : '?') + data
106
+ : config.url;
107
+ req.open(config.method, url, true);
108
+
109
+ // apply the request headers
110
+ for (var prop in config.headers) {
111
+ if (config.headers.hasOwnProperty(prop) && config.headers[prop]) {
112
+ req.setRequestHeader(prop, config.headers[prop]);
113
+ }
114
+ }
115
+
116
+ // set a timeout
117
+ var timeout;
118
+ timeout = setTimeout(function(){
119
+ // reset the handler
120
+ req.onreadystatechange = Function.prototype;
121
+ req.abort();
122
+ req = null;
123
+ error({
124
+ message: "timeout after " + config.timeout + " second",
125
+ status: 0,
126
+ data: null,
127
+ toString: function(){
128
+ return this.message + " Status: " + this.status;
129
+ }
130
+ }, null);
131
+ }, config.timeout);
132
+
133
+ // check if this origin should always be trusted
134
+ var alwaysTrusted = false, i = alwaysTrustedOrigins.length;
135
+ while (i-- && !alwaysTrusted) {
136
+ if (alwaysTrustedOrigins[i] instanceof RegExp) {
137
+ alwaysTrusted = alwaysTrustedOrigins[i].test(remote.origin);
138
+ }
139
+ else if (typeof alwaysTrustedOrigins[i] == "string") {
140
+ alwaysTrusted = (remote.origin === alwaysTrustedOrigins[i]);
141
+ }
142
+ }
143
+
144
+
145
+ // define the onreadystate handler
146
+ req.onreadystatechange = function(){
147
+ if (req.readyState == 4) {
148
+ clearTimeout(timeout);
149
+
150
+ // parse the response headers
151
+ var rawHeaders = req.getAllResponseHeaders(), headers = {}, headers_lowercase = {}, reHeader = /([\w-_]+):\s+(.*)$/gm, m;
152
+ while ((m = reHeader.exec(rawHeaders))) {
153
+ headers_lowercase[m[1].toLowerCase()] = headers[m[1]] = m[2];
154
+ }
155
+
156
+ if (req.status < 200 || req.status >= 300) {
157
+ if (useAccessControl) {
158
+ error("INVALID_STATUS_CODE");
159
+ }
160
+ else {
161
+ error("INVALID_STATUS_CODE", {
162
+ status: req.status,
163
+ data: req.responseText
164
+ });
165
+ }
166
+ }
167
+ else {
168
+
169
+ var errorMessage;
170
+ if (useAccessControl) {
171
+ // normalize the valuse access controls
172
+ var aclAllowedOrigin = (headers_lowercase["access-control-allow-origin"] || "").replace(/\s/g, "");
173
+ var aclAllowedMethods = (headers_lowercase["access-control-allow-methods"] || "").replace(/\s/g, "");
174
+
175
+ // determine if origin is trusted
176
+ if (alwaysTrusted || aclAllowedOrigin == "*" || aclAllowedOrigin.indexOf(remote.origin) != -1) {
177
+ // determine if the request method was allowed
178
+ if (aclAllowedMethods && aclAllowedMethods != "*" && aclAllowedMethods.indexOf(config.method) == -1) {
179
+ errorMessage = "DISALLOWED_REQUEST_METHOD";
180
+ }
181
+ }
182
+ else {
183
+ errorMessage = "DISALLOWED_ORIGIN";
184
+ }
185
+
186
+ }
187
+
188
+ if (errorMessage) {
189
+ error(errorMessage);
190
+ }
191
+ else {
192
+ success({
193
+ data: req.responseText,
194
+ status: req.status,
195
+ headers: headers
196
+ });
197
+ }
198
+ }
199
+ // reset the handler
200
+ req.onreadystatechange = Function.prototype;
201
+ req = null;
202
+ }
203
+ };
204
+
205
+ // issue the request
206
+ req.send(isPOST ? data : "");
207
+ }
208
+ }
209
+ });
210
+ </script>
211
+ </head>
212
+ <body>
213
+ </body>
214
+ </html>
@@ -0,0 +1,333 @@
1
+ /**
2
+ * easyXDM
3
+ * http://easyxdm.net/
4
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ * THE SOFTWARE.
23
+ */
24
+ /*jslint browser: true, immed: true, passfail: true, undef: true, newcap: true*/
25
+ /*global easyXDM, window */
26
+ /**
27
+ * easyXDM
28
+ * http://easyxdm.net/
29
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
30
+ *
31
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
32
+ * of this software and associated documentation files (the "Software"), to deal
33
+ * in the Software without restriction, including without limitation the rights
34
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
+ * copies of the Software, and to permit persons to whom the Software is
36
+ * furnished to do so, subject to the following conditions:
37
+ *
38
+ * The above copyright notice and this permission notice shall be included in
39
+ * all copies or substantial portions of the Software.
40
+ *
41
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
+ * THE SOFTWARE.
48
+ */
49
+ /**
50
+ * @class easyXDM.WidgetManager
51
+ * A class for managing widgets.<br/>
52
+ * Handles initializing widgets, and does all of the message distribution.
53
+ <pre><code>
54
+ _widgetManager = new easyXDM.WidgetManager({
55
+ local: "../hash.html",
56
+ container: document.getElementById("defaultcontainer")
57
+ },function(){
58
+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{});
59
+ });
60
+ </code></pre>
61
+ * Widgets can by dynamically added using the addWidget method
62
+ <pre><code>
63
+ _widgetManager.addWidget("http://provider.easyxdm.net/example/widget.html",{
64
+ container document.getElementById("widgetcontainer")
65
+ });
66
+ </code></pre>
67
+ * @constructor
68
+ * @param {Object} config The WidgetManagers configuration
69
+ * @namespace easyXDM
70
+ */
71
+ easyXDM.WidgetManager = function(config){
72
+ var WidgetManager = this, _hashUrl = config.local, _channelNr = 0;
73
+ var Events = {
74
+ WidgetInitialized: "widgetinitialized",
75
+ WidgetFailed: "widgetfailed"
76
+ };
77
+ var _widgets = {}, _subscribers = {};
78
+ var _widgetSettings = {
79
+ hosturl: location.href
80
+ };
81
+ easyXDM.apply(_widgetSettings, config.widgetSettings);
82
+ var _container = config.container || document.body;
83
+
84
+ /**
85
+ * @private
86
+ * Raises the specified event
87
+ * @param {String} event The raised event
88
+ * @param {Object} arg
89
+ */
90
+ function _raiseEvent(event, arg){
91
+ if (config.listeners && config.listeners[event]) {
92
+ config.listeners[event](WidgetManager, arg);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * @private
98
+ * Adds the widghet to the list of subscribers for the given topic
99
+ * @param {String} url The widgets url
100
+ * @param {String} topic The topic to subscribe to
101
+ */
102
+ function _subscribe(url, topic){
103
+ if (!(topic in _subscribers)) {
104
+ _subscribers[topic] = [];
105
+ }
106
+ _subscribers[topic].push(url);
107
+ }
108
+
109
+ /**
110
+ * @private
111
+ * Initialized the widget.<br/>
112
+ * This is called after the widget has notified that it is ready.
113
+ * @param {Object} widget The widget
114
+ * @param {String} url The widgets url
115
+ * @param {Object} widgetConfig The widgets configuration
116
+ */
117
+ function _initializeWidget(widget, url, widgetConfig){
118
+ widget.initialize(_widgetSettings, function(response){
119
+ if (response.isInitialized) {
120
+ _widgets[url] = widget;
121
+ var i = response.subscriptions.length;
122
+ while (i--) {
123
+ _subscribe(url, response.subscriptions[i]);
124
+ }
125
+ _raiseEvent(Events.WidgetInitialized, {
126
+ url: url
127
+ });
128
+ }
129
+ else {
130
+ widget.destroy();
131
+ _raiseEvent(Events.WidgetFailed, {
132
+ url: url
133
+ });
134
+ }
135
+ });
136
+ }
137
+
138
+ /**
139
+ * @private
140
+ * Publishes the data to the topics subscribers
141
+ * @param {String} url The senders url
142
+ * @param {String} topic The datas topic
143
+ * @param {Object} data The data to publish
144
+ */
145
+ function _publish(url, topic, data){
146
+ var subscribers = _subscribers[topic];
147
+ if (subscribers) {
148
+ var i = subscribers.length, widgetUrl;
149
+ while (i--) {
150
+ widgetUrl = subscribers[i];
151
+ if (widgetUrl !== url) {
152
+ _widgets[widgetUrl].send(url, topic, data);
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ /**
159
+ * @private
160
+ * Sets up a new widget
161
+ * @param {String} url The widgets url
162
+ * @param {Object} widgetConfig The widgets configuration
163
+ */
164
+ function _setUpWidget(url, widgetConfig){
165
+ var widget = new easyXDM.Rpc({
166
+ channel: "widget" + _channelNr++,
167
+ local: _hashUrl,
168
+ remote: url,
169
+ container: widgetConfig.container || _container,
170
+ swf: config.swf,
171
+ onReady: function(){
172
+ _initializeWidget(widget, url, widgetConfig);
173
+ }
174
+ }, {
175
+ local: {
176
+ subscribe: {
177
+ isVoid: true,
178
+ method: function(topic){
179
+ _subscribe(url, topic);
180
+ }
181
+ },
182
+ publish: {
183
+ isVoid: true,
184
+ method: function(topic, data){
185
+ _publish(url, topic, data);
186
+ }
187
+ }
188
+ },
189
+ remote: {
190
+ initialize: {},
191
+ send: {
192
+ isVoid: true
193
+ }
194
+ }
195
+ });
196
+ }
197
+
198
+ /**
199
+ * Adds a widget to the collection
200
+ * @param {String} url The url to load the widget from
201
+ * @param {Object} widgetConfig The widgets url
202
+ */
203
+ this.addWidget = function(url, widgetConfig){
204
+ if (url in _widgets) {
205
+ throw new Error("A widget with this url has already been initialized");
206
+ }
207
+ _setUpWidget(url, widgetConfig);
208
+ };
209
+
210
+ /**
211
+ * Removes the widget
212
+ * @param {Object} url
213
+ */
214
+ this.removeWidget = function(url){
215
+ if (url in _widgets) {
216
+ for (var topic in _subscribers) {
217
+ if (_subscribers.hasOwnProperty(topic)) {
218
+ var subscribers = _subscribers[topic], i = subscribers.length;
219
+ while (i--) {
220
+ if (subscribers[i] === url) {
221
+ subscribers.splice(i, 1);
222
+ break;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ _widgets[url].destroy();
228
+ delete _widgets[url];
229
+ }
230
+ };
231
+
232
+ /**
233
+ * Publish data to a topics subscribers
234
+ * @param {String} topic The topic to publish to
235
+ * @param {Object} data The data to publish
236
+ */
237
+ this.publish = function(topic, data){
238
+ _publish("", topic, data);
239
+ };
240
+
241
+ /**
242
+ * Broadcasts data to all the widgets
243
+ * @param {Object} data The data to broadcast
244
+ */
245
+ this.broadcast = function(data){
246
+ for (var url in _widgets) {
247
+ if (_widgets.hasOwnPropert(url)) {
248
+ _widgets[url].send({
249
+ url: "",
250
+ topic: "broadcast",
251
+ data: data
252
+ });
253
+ }
254
+ }
255
+ };
256
+ };
257
+
258
+ /**
259
+ * @class easyXDM.Widget
260
+ * The base framework for creating widgets
261
+ * @constructor
262
+ * @param {Object} config The widgets configuration
263
+ * @param {Function} onReady A method to run after the widget has been initialized.
264
+ * @namespace easyXDM
265
+ */
266
+ easyXDM.Widget = function(config){
267
+ var _widget = this;
268
+ var _incomingMessageHandler;
269
+ var _widgetHost = new easyXDM.Rpc({
270
+ swf: config.swf
271
+ }, {
272
+ remote: {
273
+ subscribe: {
274
+ isVoid: true
275
+ },
276
+ publish: {
277
+ isVoid: true
278
+ }
279
+ },
280
+ local: {
281
+ initialize: {
282
+ method: function(settings){
283
+ config.initialized(_widget, _widgetHost);
284
+ return {
285
+ isInitialized: true,
286
+ subscriptions: config.subscriptions
287
+ };
288
+ }
289
+ },
290
+ send: {
291
+ isVoid: true,
292
+ method: function(url, topic, data){
293
+ _incomingMessageHandler(url, topic, data);
294
+ }
295
+ }
296
+ }
297
+ });
298
+
299
+ /**
300
+ * @private
301
+ * Destroy the interface on unload
302
+ */
303
+ window.onunload = function(){
304
+ _widgetHost.destroy();
305
+ };
306
+
307
+ /**
308
+ * Publish data to subscribers to a topic
309
+ * @param {String} topic The topic to publish to
310
+ * @param {Object} data The data to publish
311
+ */
312
+ this.publish = function(topic, data){
313
+ _widgetHost.publish(topic, data);
314
+ };
315
+
316
+ /**
317
+ * Subscribe to a topic
318
+ * @param {String} topic The topic to subscribe to
319
+ */
320
+ this.subscribe = function(topic){
321
+ _widgetHost.subscribe(topic);
322
+ };
323
+
324
+ /**
325
+ * Register the method that will handle incoming messages
326
+ * @param {Function} fn The handler
327
+ */
328
+ this.registerMessageHandler = function(fn){
329
+ _incomingMessageHandler = fn;
330
+ };
331
+
332
+ config.initialize(this, _widgetHost);
333
+ };