0

We are using CrossRider to develop an extension for Internet Explorer. We also have extensions for Chrome, Firefox and Safari, but we didn't use CrossRider for these extensions. I would like to know how we can inject a script to specific tabs in CrossRider? And after we do it, will it be injected also to tabs which will be opened later? And if yes, how do we remove the script so it will not be injected to any more tabs?

Here is the script, we have to add a case to CrossRider. Only in Safari we also remove the script, because in Chrome and Firefox it's not added to tabs which will be opened later. If it does in CrossRider then we have to remove it in CrossRider too.

Controller.showNotification = function() {
    var possibleURLs = /(mail\.google\.com|mail\.yahoo\.com|mail\.live\.com|mail\.aol\.com|mail\.rambler\.ru)/gi;
    var possibleURLsArray = ["http://mail.google.com/*", "https://mail.google.com/*", "http://*.mail.yahoo.com/neo/*", "https://*.mail.yahoo.com/neo/*", "http://*.mail.yahoo.com/mc/*", "https://*.mail.yahoo.com/mc/*", "http://*.mail.yahoo.com/dc/*", "https://*.mail.yahoo.com/dc/*", "http://*.mail.live.com/*", "https://*.mail.live.com/*", "http://*.webmail.aol.com/*/Suite.aspx", "http://*.webmail.aol.com/*/suite.aspx", "http://*.mail.aol.com/*/suite.aspx", "http://*.mail.aol.com/*/Suite.aspx", "http://mail.aol.com/*/suite.aspx", "http://mail.aol.com/*/Suite.aspx", "https://*.webmail.aol.com/*/Suite.aspx", "https://*.webmail.aol.com/*/suite.aspx", "https://*.mail.aol.com/*/suite.aspx", "https://*.mail.aol.com/*/Suite.aspx", "https://mail.aol.com/*/suite.aspx", "https://mail.aol.com/*/Suite.aspx", "http://mail.rambler.ru/mail/compose.cgi*"];
    var possibleURLsScriptURL = Utils.getUrl("content/src/common/show_notification_script.js");
    var possibleURLsScriptRelativeURL = Utils.getRelativeUrl("content/src/common/show_notification_script.js");
    switch (Sys.platform) {
        case 'chrome':
            chrome.tabs.query({}, function(tabs) {
                for (var i in tabs) {
                    if (tabs[i].url.match(possibleURLs) !== null) {
                        chrome.tabs.executeScript(tabs[i].id, {
                            file: possibleURLsScriptRelativeURL
                        });
                    }
                }
            });
            break;

        case 'safari':
            safari.extension.addContentScriptFromURL(possibleURLsScriptURL, possibleURLsArray, [], true);
            break;

        case 'mozilla':
            for (var i in tabs) {
                if (tabs[i].url.match(possibleURLs) !== null) {
                    tabs[i].attach({
                        contentScriptFile: possibleURLsScriptURL
                    });
                }
            }
            break;

        case 'crossrider':
            appAPI.dom.onDocumentStart.addJS({
                resourcePath: possibleURLsScriptRelativeURL,
                whitelistUrls: possibleURLs
            });
            break;
    }
};

Controller.disableShowNotification = function() {
    var possibleURLsScriptURL = Utils.getUrl("content/src/common/show_notification_script.js");
    switch (Sys.platform) {
        case 'safari':
            safari.extension.removeContentScript(possibleURLsScriptURL);
            break;
    }
};

Utils.getUrl = function(filename, preferSecure) {
    return WS.getURL(filename, preferSecure);
};

Utils.getRelativeUrl = function(filename) {
    return WS.getRelativeUrl(filename);
};

/* Function to retrieve the relative URL/URI of a file in the platform's file system. */
WS.getURL = function(filename, preferSecure) {
    if (typeof filename !== "string") {
        filename = "";
    } else if (filename.substr(0, 1) === "/") { /* Remove forward slash if it's the first character, so it matches with the base URLs of the APIs below. */
        filename = filename.substr(1);
    }

    switch (Sys.platform) {
        case 'mozilla':
            if (typeof exports === 'undefined') { // Means we're in a content script.
                return  self.options.extensionURL + filename;
            }
            return require("sdk/self").data.url("../lib/"+filename);

        case 'chrome':
            return chrome.extension.getURL(filename);

        case 'safari':
            return safari.extension.baseURI + filename;

        case 'web':
        case 'conduit':
            if (preferSecure && 'remote_secure' in WS.config.URLs.APIs) {
                return WS.config.URLs.APIs.remote_secure + filename;
            }

            return WS.config.URLs.APIs.remote + filename;

        case 'crossrider':
            filename = filename.substr("content/".length);
            if (filename.indexOf('png') !== -1) {
                return appAPI.resources.getImage(filename);
            }

            return "resource://" + filename;

        default:
            return '../' + filename; /* Added temporarily as a fix for Node.js compatibility */
    }
};

/* Function to retrieve the relative URL/URI of a file in the platform's file system. */
/* Currently this function is only defined for chrome and crossrider. */
WS.getRelativeUrl = function(filename) {
    if (typeof filename !== "string") {
        filename = "";
    } else if (filename.substr(0, 1) === "/") { /* Remove forward slash if it's the first character, so it matches with the base URLs of the APIs below. */
        filename = filename.substr(1);
    }

    switch (Sys.platform) {
        case 'chrome':
            return "/" + filename;

        case 'crossrider':
            filename = filename.substr("content/".length);
            return filename;
    }
};

And how do we reload specific tabs in CrossRider? Do we have to send a message to the tab which will reload itself? Or is it possible to reload tabs from the background?

Controller.reloadAllEmailTabs = function() {
    var possibleURLs = /(mail\.google\.com|mail\.yahoo\.com|mail\.live\.com|mail\.aol\.com|mail\.rambler\.ru)/gi;
    switch (Sys.platform) {
        case 'chrome':
            chrome.tabs.query({}, function(tabs) {
                for (var i in tabs) {
                    if (tabs[i].url.match(possibleURLs) !== null) {
                        chrome.tabs.reload(tabs[i].id);
                    }
                }
            });
            break;

        case 'mozilla':
            for (var i in tabs) {
                if (tabs[i].url.match(possibleURLs) !== null) {
                    tabs[i].reload();
                }
            }
            break;

        case 'safari':
            var browserWindows = safari.application.browserWindows;
            for (var i = 0; i < browserWindows.length; i++) {
                var safari_tabs = browserWindows[i].tabs;
                for (var j = 0; j < safari_tabs.length; j++) {
                    if (safari_tabs[j].url.match(possibleURLs) !== null) {
                        safari_tabs[j].url = safari_tabs[j].url;
                    }
                }
            }
            break;

        case 'crossrider':
            appAPI.tabs.getAllTabs(function(tabs) {
                for (var i = 0; i < tabs.length; i++) {
                    if (tabs[i].tabUrl.match(possibleURLs) !== null) {
                        appAPI.tabs.reload(tabs[i].tabId);
                    }
                }
            });
            break;
    }
};

Our Extension ID is 43889. I'm using Internet Explorer 11 but this extension should work on all versions of Internet Explorer.

Update: I added cases for CrossRider from Shlomo's answer, but they don't work (they don't do anything in CrossRider).

Uri
  • 2,992
  • 8
  • 43
  • 86

2 Answers2

2

If I understand your requirements correctly, they can be summarized as follows:

  1. How to inject a script to specific tabs?
  2. How to inject a script to new tabs?
  3. How to remove a script from injecting into any more tabs?
  4. How to reload a specific tab from the background?

Questions 1&2 can be handled using appAPI.dom.onDocumentStart.addJS specifying the whitelistUrls property as your possibleURLs, whilst 4 can be achieved using a combination of appAPI.tabs.getAllTabs, and appAPI.tabs.reloadTab.

As to question 3, I'm not quite clear as to why you would want to add and then remove a script as you have done for Safari, but if the intention is to simply prevent the script from running on Safari, you can specify condition using appAPI.platform around the code injection (see example).

As you will note, all this is achieved in the background scope as you require. If I have not understood correctly, please clarify each question and I will try to help.

[Disclosure: I am a Crossrider employee]

background.js:

appAPI.ready(function($) {
  // get's all open tabs
  appAPI.tabs.getAllTabs(function(tabs) {
    for (var i=0; i<tabs.length; i++) {
      // For tabs with matching URLs
      if (tabs[i].tabUrl.match(possibleURLs) !== null) {
        // Reload the tab
        appAPI.tabs.reloadTab(tabs[i].tabId);
      }
    };
  });

  // For browsers other than Safari
  if (appAPI.platform !== 'SF') {
    // Inject script on tabs with matching URLs
    appAPI.dom.onDocumentStart.addJS({
      js: "alert('hello world!');",
      whitelistUrls: possibleURLs
    });
  }
})
Community
  • 1
  • 1
Shlomo
  • 3,763
  • 11
  • 16
  • We only use CrossRider with `appAPI.platform === 'IE'`. If we inject the script using `appAPI.dom.onDocumentStart.addJS`, will it be injected to tabs that will be opened later and match the whitelistUrls? If not then everything is OK, but if yes, then how do we remove it from being injected to any more tabs? We only implemented it in Safari because we didn't find a way to inject JavaScript to only current tabs in Safari. – Uri Nov 24 '14 at 08:11
  • `appAPI.tabs.getAllTabs` returns tabs of length 0. – Uri Nov 24 '14 at 09:31
  • I also didn't find documentation for `appAPI.tabs.reload`, only `appAPI.tabs.reloadTab`. – Uri Nov 24 '14 at 09:47
  • Apologies, I was in Chrome/Firefox mode when providing the example snippet, however getAllTabs is not supported in IE. If I understand your scenario correctly, you are using getAllTabs to inject your code on existing pages (by reloading the page) when the extension first runs after installation (in subsequent runs code is injected automatically by onDocument.addJS code) but unfortunately, due to IE architecture, this is not possible in IE. Also, thanks for the typo correction for reloadTab (code snippet updated to reflect). – Shlomo Nov 24 '14 at 12:07
  • Shlomo, so how do we implement reloading specific tabs and injecting scripts in IE? I updated my code with your answer (you can see my updated question) but both don't work in IE with CrossRider. – Uri Nov 24 '14 at 12:37
  • Also, I didn't find anything on http://docs.crossrider.com/#!/api/appAPI.tabs about `appAPI.tabs.getAllTabs` not being supported in IE. – Uri Nov 24 '14 at 12:39
  • In the docs, by each method, there is a table indicating the supported scopes and browsers. – Shlomo Nov 24 '14 at 13:17
  • Regarding reloading tabs, you can use the appAPI.tabs.reloadTab method which is supported in IE. However, that does not overcome the core issue of getAllTabs which, as previously mentioned, is not possible in IE on first run after install. If your scenario is not on first run after install, you can create the list manually by [sending a message to all tabs](http://docs.crossrider.com/#!/api/appAPI.message-method-toAllTabs) and collating the responses. – Shlomo Nov 24 '14 at 13:26
0

Regarding appAPI.dom.onDocumentStart.addJS, this indeed injects the script on all pages that match whitelistUrls when they load and cannot be removed. If you need greater control over when to inject the script, you can use appAPI.tabs.executeScript in conjuction with appAPI.tabs.onTabUpdated and add a condition before injecting the script, something like:

var DoNotLoad = false; // Your condition for not injecting script
appAPI.tabs.onTabUpdated(function(tabInfo) {
    if (tabInfo.tabUrl.match(possibleURLs) !== null && !DoNotLoad) {
        appAPI.tabs.executeScript({
            tabId: tabInfo.tabId,
            code: 'alert("Running script");'
        });
    }
});
Shlomo
  • 3,763
  • 11
  • 16