1
/* Chromium Unity integration extension
3
* Copyright 2012 Canonical Ltd.
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.
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.
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/>.
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)
22
// TODO should be properly injected
23
var unsafeWindow = window;
25
var UnityPopupManager = (
28
requestIntegration: function (name, domain, integrateCallback, dontAskActionCallback) {
29
var message = chrome.i18n.getMessage("integration_copy", [name, domain]);
32
var isconfirmed = function (response) {
33
return response && response.integrate;
35
UnityContentScriptApi.requestUnityIntegration (message,
38
if (isconfirmed (response)) {
42
dontAskActionCallback ();
48
return UnityPopupManager;
52
var UnityFaviconUtils = (
54
function findFaviconLink (document){
55
var linkElements = document.getElementsByTagName("link");
58
for (i = 0; i < linkElements.length; i++){
59
var element = linkElements[i];
61
if (element.hasAttribute("rel") &&
62
(element.rel == "shortcut icon")) {
63
var link = element.href;
66
return document.location + link;
77
getFaviconForDocument: function (document) {
78
var favIcon = findFaviconLink (document);
80
if (favIcon == null) {
81
favIcon = "http://" + document.domain + "/favicon.ico";
88
return UnityFaviconUtils;
93
var UnityWindowHelper = (
95
function UnityWindowHelper (aWindow) {
96
this.window = aWindow;
99
UnityWindowHelper.prototype.FindToplevelContentWindow = function (aWindow) {
100
var toplevelContentWindow = aWindow;
102
while (toplevelContentWindow.parent != toplevelContentWindow){
103
toplevelContentWindow = toplevelContentWindow.parent;
105
return toplevelContentWindow;
108
return UnityWindowHelper;
113
var UnityPreviewUtils = (
115
UnityPreviewUtils = {
116
getPreviewForWindow: function (window, callback) {
118
UnityContentScriptApi.takeSnapshot (function (dataURL) {
124
return UnityPreviewUtils;
129
UnityGlobalPropertyInitializer = {
130
makeCallback: function (get_uwa, service, logger) {
131
function callback(aWindow) {
135
var _uwa = get_uwa();
137
// TODO fix, improper "form"
138
var PopupManager = UnityPopupManager;
139
var WindowHelper = new UnityWindowHelper (window);
141
var doListenToTabChanges = function () {
142
// open communication link w/ background page to be informed of everything that happens w/
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) {
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);
158
uwa.context_set_view_is_active (_global.context, 0);
165
window.addEventListener("pagehide"
168
if (_global.context == null) {return;}
169
uwa.context_destroy (_global.context, 0);
170
_global.context = null;
172
_global.onInitCallbacks = [];
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();
180
var appRaiseCallback = function (context, file, userdata) {
181
UnityContentScriptApi.getTabInfo (
182
function (response) {
183
UnityContentScriptApi.raiseTabWithId({tabId: response.tabId, windowId: response.windowId});
186
if (_global.acceptDataCallback) {
188
_global.acceptDataCallback (file);
191
console.log ("Error: " + e);
197
var appCloseCallback = function (context, userdata) {
198
UnityContentScriptApi.getTabInfo (
199
function (response) {
200
UnityContentScriptApi.killTabWithId({tabId: response.tabId, windowId: response.windowId});
204
var contextPrepared = function () {
209
logger("Notifying parent extension of login info");
210
chrome.runtime.sendMessage ({
211
action: "loginEvent",
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
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; });
224
var previewRequestedCallback = function (context, user_data) {
228
content = _previewData + '\0';
230
logger ("Unity Preview Error: " + e.toString());
236
logger ('Got a context for domain '
247
_global.contextReady = true;
249
uwa.context_add_icon (_global.context
250
, UnityFaviconUtils.getFaviconForDocument (document)
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);
257
if ((homepage != undefined) && (homepage != null)) {
258
uwa.context_set_homepage (_global.context, homepage);
261
for (var c in _global.onInitCallbacks) {
262
var callback = _global.onInitCallbacks[c];
264
if (callback != null) {
266
logger ('Calling an initialization callback');
271
logger ("Unity Extension, error calling onInit callback: " + e.toString());
276
doListenToTabChanges ();
278
uwa.context_set_view_is_active (_global.context, 1);
280
uwa.context_set_view_location (_global.context, document.location.toString());
281
uwa.service_set_xid_for_browser_window_id (service
283
, environmentInfos.windowId);
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
293
if (_global.context != null) {
294
if (_global.contextReady && oninit != null) {
297
logger ("Calling integration script's initialization function");
302
logger ("Unity Extension, exception calling onInit callback: " + e.toString());
304
} else if (_global.contextReady == false) {
306
_global.onInitCallbacks.push (oninit);
311
_global.context = _uwa.context_new_lazy (service, name, domain, iconUrl, mimeTypes);
313
_global.contextReady = false;
315
_global.onInitCallbacks.push (oninit);
317
logger ("Preparing Unity context");
319
_uwa.context_prepare (_global.context, contextPrepared, null);
320
}; // function doInitializeContextWithName
322
function unityInit (options, environmentInfos) {
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;
332
var unityInitWithDomain = function (domain) {
333
if (!_uwa.permissions_is_integration_allowed()) {
334
logger ("Unity integration disabled (by user settings).");
337
function integrateActionCallback() {
338
_uwa.permissions_allow_domain (domain);
340
doInitializeContextWithName (name
344
, integrationScriptInitCallback
352
function dontAskActionCallback() {
353
_uwa.permissions_dontask_domain (domain);
355
logger ("Initializing Unity for domain: " + domain);
357
if (_uwa.permissions_get_domain_dontask (domain)) {
358
logger ("Domain has been 'blacklisted'");
362
if (domain == "" || _uwa.permissions_get_domain_allowed (domain)) {
363
logger ("Domain has been 'whilelisted' - skipping the integration step");
365
doInitializeContextWithName (name
369
, integrationScriptInitCallback
377
logger ("Unity Extension: Error initializing context (" + e.toString() + e.line + e + ")");
381
logger ('Requesting Unity integration to user');
383
PopupManager.requestIntegration(name
385
, integrateActionCallback
386
, dontAskActionCallback);
387
}; // function unityInitWithDomain
396
if (domain == undefined) {
397
domain = document.domain;
399
unityInitWithDomain (domain);
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 "
407
+ " does not have base suffix ("
408
+ currentBaseDomain + ")");
410
unityInitWithDomain (domain);
413
}; // function unityInit
415
function unityPrepareEnvironment (options) {
416
UnityContentScriptApi.getTabInfo (function (environmentInfos) {
417
logger ('Environment informations: '
418
+ environmentInfos.windowId
420
+ environmentInfos.tabId);
421
unityInit (options, environmentInfos);
425
var CallbackManager = {
426
releaseCallback: function (type) {
428
makeCallback: function (type, callback) {
433
function acceptData(context, mimes, func) {
435
uwa.context_set_application_accept_data(_global.context, mimes);
436
_global.acceptDataCallback = func;
439
function contextAddApplicationActions(actions) {
442
for (var i = 0; i < actions.length; i++) {
444
path: actions[i].name
445
, callback: actions[i].callback
448
uwa.context_add_application_actions(_global.context, appActions, actions.length);
452
return makeAPI (setTimeout
453
, contextAddApplicationActions
454
, unityPrepareEnvironment
455
, UnityContentScriptApi.toDataURL
462
} // function callback
466
} // makeCallback: function