~justinmcp/unity-chromium-extension/native-messaging-base

« back to all changes in this revision

Viewing changes to chromium-extension/unity-webapps-binding.js

  • Committer: Tarmac
  • Author(s): Alexandre Abreu
  • Date: 2013-09-16 21:39:13 UTC
  • mfrom: (228.1.1 revert)
  • Revision ID: tarmac-20130916213913-63a50kn45ddqom1j
Revert revision 228: deprecate tab integration.

Approved by Robert Bruce Park, PS Jenkins bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Chromium Unity integration extension
 
2
 * 
 
3
 *   Copyright 2012 Canonical Ltd.
 
4
 *
 
5
 *   This program is free software: you can redistribute it and/or modify it 
 
6
 *   under the terms of the GNU General Public License version 3, as published 
 
7
 *   by the Free Software Foundation.
 
8
 *
 
9
 *  This program is distributed in the hope that it will be useful, but 
 
10
 *   WITHOUT ANY WARRANTY; without even the implied warranties of 
 
11
 *   MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
 
12
 *   PURPOSE.  See the GNU General Public License for more details.
 
13
 *
 
14
 *   You should have received a copy of the GNU General Public License along 
 
15
 *   with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 **/
 
17
 
 
18
// TODO just there for convenience, will probably reuse those from FF but w/ a better
 
19
//  module mecanism (dunno what is used by FF)
 
20
 
 
21
// FF specific
 
22
// TODO should be properly injected
 
23
var unsafeWindow = window;
 
24
 
 
25
var UnityPopupManager = (
 
26
  function () {
 
27
    UnityPopupManager = {
 
28
      requestIntegration: function (name, domain, integrateCallback, dontAskActionCallback) {
 
29
        var message = chrome.i18n.getMessage("integration_copy", [name, domain]);
 
30
        var details = "";
 
31
        
 
32
        var isconfirmed = function (response) {
 
33
          return response && response.integrate;
 
34
        };
 
35
        UnityContentScriptApi.requestUnityIntegration (message,
 
36
                                                       details,
 
37
                                                       function(response) {
 
38
                                                         if (isconfirmed (response)) {
 
39
                                                           integrateCallback ();
 
40
                                                         }
 
41
                                                         else {
 
42
                                                           dontAskActionCallback ();
 
43
                                                         }
 
44
                                                       });
 
45
      }
 
46
    };
 
47
    
 
48
    return UnityPopupManager;
 
49
  }                                                
 
50
)();
 
51
 
 
52
var UnityFaviconUtils = (
 
53
  function () {
 
54
    function findFaviconLink (document){
 
55
      var linkElements = document.getElementsByTagName("link");
 
56
      var i = 0;
 
57
      
 
58
      for (i = 0; i < linkElements.length; i++){
 
59
        var element = linkElements[i];
 
60
        
 
61
        if (element.hasAttribute("rel") &&
 
62
            (element.rel == "shortcut icon")) {
 
63
          var link = element.href;
 
64
          
 
65
          if (link[0] == "/") {
 
66
            return document.location + link;
 
67
          } else {
 
68
            return link;
 
69
          }
 
70
        }
 
71
      }
 
72
      
 
73
      return null;
 
74
    }
 
75
    
 
76
    UnityFaviconUtils = {
 
77
      getFaviconForDocument: function (document) {
 
78
        var favIcon = findFaviconLink (document);
 
79
        
 
80
        if (favIcon == null) {
 
81
          favIcon = "http://" + document.domain + "/favicon.ico";
 
82
        }
 
83
        
 
84
        return favIcon;
 
85
      }
 
86
    };
 
87
 
 
88
    return UnityFaviconUtils;
 
89
  }
 
90
) ();
 
91
 
 
92
 
 
93
var UnityWindowHelper = (
 
94
  function () {
 
95
    function UnityWindowHelper (aWindow) {
 
96
      this.window = aWindow;
 
97
    };
 
98
 
 
99
    UnityWindowHelper.prototype.FindToplevelContentWindow = function (aWindow) {
 
100
      var toplevelContentWindow = aWindow;
 
101
      
 
102
      while (toplevelContentWindow.parent != toplevelContentWindow){
 
103
        toplevelContentWindow = toplevelContentWindow.parent;
 
104
      }
 
105
      return toplevelContentWindow;
 
106
    };
 
107
 
 
108
    return UnityWindowHelper;
 
109
  }
 
110
) ();
 
111
 
 
112
 
 
113
var UnityPreviewUtils = (
 
114
  function () {
 
115
    UnityPreviewUtils = {
 
116
      getPreviewForWindow: function (window, callback) {
 
117
        
 
118
        UnityContentScriptApi.takeSnapshot (function (dataURL) {
 
119
                                              callback (dataURL);
 
120
                                            });
 
121
      }
 
122
    };
 
123
 
 
124
    return UnityPreviewUtils;
 
125
  }
 
126
)();
 
127
 
 
128
 
 
129
UnityGlobalPropertyInitializer = {
 
130
  makeCallback: function (get_uwa, service, logger) {
 
131
    function callback(aWindow) {
 
132
      var _global = {
 
133
        context: null
 
134
      };
 
135
      var _uwa = get_uwa();
 
136
 
 
137
      // TODO fix, improper "form"
 
138
      var PopupManager = UnityPopupManager;
 
139
      var WindowHelper = new UnityWindowHelper (window);
 
140
      
 
141
      var doListenToTabChanges = function () {
 
142
        // open communication link w/ background page to be informed of everything that happens w/
 
143
        //  the page itself
 
144
        
 
145
        // TODO mmh all tabs userscript will receive this, so it might trigger duplicate is_active(0) calls
 
146
        //  for already unactive tabs
 
147
        chrome.runtime.onMessage.addListener (
 
148
          function (request, sender, response) {
 
149
            if (request && request.method && request.method === 'on_tab_active_changed') {
 
150
              UnityContentScriptApi.getTabInfo (
 
151
                function (response) {
 
152
                  var uwa = get_uwa();
 
153
                  if (request.tabId === response.tabId) {
 
154
                    logger ('Activating context corresponding to tab ' + request.tabId);
 
155
                    uwa.context_set_view_is_active (_global.context, 1);
 
156
                  }
 
157
                  else {
 
158
                    uwa.context_set_view_is_active (_global.context, 0);
 
159
                  }
 
160
                });
 
161
            }
 
162
          });
 
163
      };
 
164
 
 
165
      window.addEventListener("pagehide"
 
166
                              , function(event) {
 
167
                                var uwa = get_uwa();
 
168
                                if (_global.context == null) {return;}
 
169
                                uwa.context_destroy (_global.context, 0);
 
170
                                _global.context = null;
 
171
                              }, false);
 
172
      _global.onInitCallbacks = [];
 
173
      
 
174
      function doInitializeContextWithName (name, service, domain, iconUrl, oninit, homepage, login, mimeTypes, environmentInfos, firstTime) {
 
175
        // If we are adding the site for the first time and there is no homepage, store the point of integration.
 
176
        if (firstTime && homepage == undefined) {
 
177
          homepage = WindowHelper.FindToplevelContentWindow (window).document.location.toString();
 
178
        }
 
179
        
 
180
        var appRaiseCallback = function (context, file, userdata) {
 
181
          UnityContentScriptApi.getTabInfo (
 
182
            function (response) {
 
183
              UnityContentScriptApi.raiseTabWithId({tabId: response.tabId, windowId: response.windowId});
 
184
 
 
185
              if (file !== null) {
 
186
                if (_global.acceptDataCallback) {
 
187
                  try {
 
188
                    _global.acceptDataCallback (file);
 
189
                  }
 
190
                  catch(e) {
 
191
                    console.log ("Error: " + e);
 
192
                  }  
 
193
                }
 
194
              }
 
195
            });
 
196
        };
 
197
        var appCloseCallback = function (context, userdata) {
 
198
          UnityContentScriptApi.getTabInfo (
 
199
            function (response) {
 
200
              UnityContentScriptApi.killTabWithId({tabId: response.tabId, windowId: response.windowId});
 
201
            });
 
202
        };
 
203
        
 
204
        var contextPrepared = function () {
 
205
 
 
206
          var uwa = get_uwa();
 
207
 
 
208
          if (login) {
 
209
            logger("Notifying parent extension of login info");
 
210
            chrome.runtime.sendMessage ({
 
211
                action: "loginEvent",
 
212
                login: login,
 
213
                domain: domain
 
214
            });
 
215
          }
 
216
 
 
217
          // preview request is asynchronous & only for visible tab, so we
 
218
          // take a guess a take a snapshot in the current tab's state
 
219
          // 
 
220
          // TODO make sure that we are still in the same tab (vs visible one).
 
221
          var _previewData = '\0';
 
222
          UnityPreviewUtils.getPreviewForWindow (window, function (dataURL) { _previewData = dataURL; });
 
223
          
 
224
          var previewRequestedCallback = function (context, user_data) {
 
225
            var content = null;
 
226
            
 
227
            try {           
 
228
              content = _previewData + '\0';
 
229
            } catch (e) {
 
230
              logger ("Unity Preview Error: " + e.toString());
 
231
            }
 
232
            
 
233
            return content;
 
234
          };
 
235
          
 
236
          logger ('Got a context for domain '
 
237
                  + domain
 
238
                  + ', service: '
 
239
                  + service
 
240
                  + ', name: '
 
241
                  + name
 
242
                  + ", homepage: "
 
243
                  + homepage
 
244
                  + ', context: '
 
245
                  + _global.context);
 
246
          
 
247
          _global.contextReady = true;
 
248
          
 
249
          uwa.context_add_icon (_global.context
 
250
                                 , UnityFaviconUtils.getFaviconForDocument (document)
 
251
                                 , 16);
 
252
          
 
253
          uwa.context_on_raise_callback (_global.context, appRaiseCallback, null);
 
254
          uwa.context_on_close_callback (_global.context, appCloseCallback, null);
 
255
          uwa.context_set_preview_requested_callback (_global.context, previewRequestedCallback, null);
 
256
          
 
257
          if ((homepage != undefined) && (homepage != null)) {
 
258
            uwa.context_set_homepage (_global.context, homepage);
 
259
          }
 
260
          
 
261
          for (var c in _global.onInitCallbacks) {
 
262
            var callback = _global.onInitCallbacks[c];
 
263
            
 
264
            if (callback != null) {
 
265
              try {
 
266
                logger ('Calling an initialization callback');
 
267
                
 
268
                callback();
 
269
                
 
270
              } catch (e) {
 
271
                logger ("Unity Extension, error calling onInit callback: " + e.toString());
 
272
              }
 
273
            }
 
274
          }
 
275
          
 
276
          doListenToTabChanges ();
 
277
 
 
278
          uwa.context_set_view_is_active (_global.context, 1);
 
279
 
 
280
          uwa.context_set_view_location (_global.context, document.location.toString());
 
281
          uwa.service_set_xid_for_browser_window_id (service
 
282
                                                      , _global.context
 
283
                                                      , environmentInfos.windowId);
 
284
          
 
285
          var context_name = uwa.context_get_name(_global.context);
 
286
          var domain_name = uwa.context_get_domain(_global.context) || domain;
 
287
          var interest_id = uwa.context_get_interest_id(_global.context);
 
288
          UnityContentScriptApi.addIntegrationScriptForTab(context_name
 
289
                                                           , domain_name
 
290
                                                           , interest_id);
 
291
        };
 
292
        
 
293
        if (_global.context != null) {
 
294
          if (_global.contextReady && oninit != null) {
 
295
            
 
296
            try {
 
297
              logger ("Calling integration script's initialization function");
 
298
              
 
299
              oninit();
 
300
              
 
301
            } catch (e) {
 
302
              logger ("Unity Extension, exception calling onInit callback: " + e.toString());
 
303
            }
 
304
          } else if (_global.contextReady == false) {
 
305
            
 
306
            _global.onInitCallbacks.push (oninit);
 
307
          }
 
308
          return;
 
309
        }
 
310
        
 
311
        _global.context = _uwa.context_new_lazy (service, name, domain, iconUrl, mimeTypes);
 
312
        
 
313
        _global.contextReady = false;
 
314
        
 
315
        _global.onInitCallbacks.push (oninit);
 
316
        
 
317
        logger ("Preparing Unity context");
 
318
        
 
319
        _uwa.context_prepare (_global.context, contextPrepared, null);
 
320
      }; // function doInitializeContextWithName
 
321
      
 
322
      function unityInit (options, environmentInfos) {
 
323
        
 
324
        var name = options.name || "Undefined name";
 
325
        var integrationScriptInitCallback = options.onInit || function () { logger ("Default onInit called for '" + name + "'"); };
 
326
        var iconUrl = options.iconUrl;
 
327
        var homepage = options.homepage;
 
328
        var domain = options.domain;
 
329
        var login = options.login;
 
330
        var mimeTypes = options.mimeTypes;
 
331
        
 
332
        var unityInitWithDomain = function (domain) {
 
333
          if (!_uwa.permissions_is_integration_allowed()) {
 
334
            logger ("Unity integration disabled (by user settings).");
 
335
            return;
 
336
          }
 
337
          function integrateActionCallback() {
 
338
            _uwa.permissions_allow_domain (domain);
 
339
 
 
340
            doInitializeContextWithName (name
 
341
                                         , service
 
342
                                         , domain
 
343
                                         , iconUrl
 
344
                                         , integrationScriptInitCallback
 
345
                                         , homepage
 
346
                                         , login
 
347
                                         , mimeTypes
 
348
                                         , environmentInfos
 
349
                                         , true);
 
350
          }
 
351
 
 
352
          function dontAskActionCallback() {
 
353
            _uwa.permissions_dontask_domain (domain);
 
354
          }
 
355
          logger ("Initializing Unity for domain: " + domain);
 
356
 
 
357
          if (_uwa.permissions_get_domain_dontask (domain)) {
 
358
            logger ("Domain has been 'blacklisted'");
 
359
            return;
 
360
          }
 
361
 
 
362
          if (domain == "" || _uwa.permissions_get_domain_allowed (domain)) {
 
363
            logger ("Domain has been 'whilelisted' - skipping the integration step");
 
364
            try {
 
365
              doInitializeContextWithName (name
 
366
                                           , service
 
367
                                           , domain
 
368
                                           , iconUrl
 
369
                                           , integrationScriptInitCallback
 
370
                                           , homepage
 
371
                                           , login
 
372
                                           , mimeTypes
 
373
                                           , environmentInfos
 
374
                                           , false);
 
375
            }
 
376
            catch (e) {
 
377
              logger ("Unity Extension: Error initializing context (" + e.toString() + e.line + e + ")");
 
378
            }
 
379
            return;
 
380
          }
 
381
          logger ('Requesting Unity integration to user');
 
382
 
 
383
          PopupManager.requestIntegration(name
 
384
                                          , domain
 
385
                                          , integrateActionCallback
 
386
                                          , dontAskActionCallback);
 
387
        }; // function unityInitWithDomain
 
388
 
 
389
        if (!mimeTypes) {
 
390
          mimeTypes = null;
 
391
        }
 
392
        if (!iconUrl) {
 
393
          iconUrl = null;
 
394
        }
 
395
 
 
396
        if (domain == undefined) {
 
397
          domain = document.domain;
 
398
 
 
399
          unityInitWithDomain (domain);
 
400
        } else {
 
401
          UnityContentScriptApi.getBaseDomain (document.location.href
 
402
                                               , function (currentBaseDomain) {
 
403
                                                 if ((domain.indexOf(currentBaseDomain,
 
404
                                                                     domain.length-currentBaseDomain.length) == -1)) {
 
405
                                                   throw Error("invalid supplied domain "
 
406
                                                               + domain
 
407
                                                               + " does not have base suffix ("
 
408
                                                               + currentBaseDomain + ")");
 
409
                                                 }
 
410
                                                 unityInitWithDomain (domain);
 
411
                                               });
 
412
        }
 
413
      }; // function unityInit
 
414
 
 
415
      function unityPrepareEnvironment (options) {
 
416
        UnityContentScriptApi.getTabInfo (function (environmentInfos) {
 
417
                                            logger ('Environment informations: '
 
418
                                                    + environmentInfos.windowId
 
419
                                                    + ', tabId: '
 
420
                                                    + environmentInfos.tabId);
 
421
                                            unityInit (options, environmentInfos);
 
422
                                          });
 
423
      };
 
424
 
 
425
      var CallbackManager = {
 
426
        releaseCallback: function (type) {
 
427
        },
 
428
        makeCallback: function (type, callback) {
 
429
          return callback;
 
430
        }
 
431
      };
 
432
 
 
433
      function acceptData(context, mimes, func) {
 
434
        var uwa = get_uwa();
 
435
        uwa.context_set_application_accept_data(_global.context, mimes);
 
436
        _global.acceptDataCallback = func;
 
437
      }
 
438
 
 
439
      function contextAddApplicationActions(actions) {
 
440
        var uwa = get_uwa();
 
441
        var appActions = [];
 
442
        for (var i = 0; i < actions.length; i++) {
 
443
          appActions.push({
 
444
                            path: actions[i].name
 
445
                            , callback: actions[i].callback
 
446
                          });
 
447
        }
 
448
        uwa.context_add_application_actions(_global.context, appActions, actions.length);
 
449
        actions = [];
 
450
      }
 
451
 
 
452
      return makeAPI (setTimeout
 
453
                      , contextAddApplicationActions
 
454
                      , unityPrepareEnvironment
 
455
                      , UnityContentScriptApi.toDataURL
 
456
                      , logger
 
457
                      , get_uwa
 
458
                      , _global
 
459
                      , CallbackManager
 
460
                      , acceptData);
 
461
      
 
462
    } // function callback
 
463
    
 
464
    return callback;
 
465
    
 
466
  } // makeCallback: function
 
467
};
 
468