Chrome extension: missing class instances in background page - javascript

I'm trying to build a "complex" extension for google chrome, in fact the extension is actually build (JSLoader), and the structure used in the extension worked a few months ago. Now I want to update it but none of my pop-up's are showing due to some strange behavior of chrome.runtime.getBackgroundPage(). I have several "modules" declared in manifest.json as follows:
"background": {
"scripts": [
"dependencies/dep1.js",
" ... ",
"bg/module1.js",
"bg/module2.js",
" ... "
"bg/background.js"
]
},
Then in my background page I do instantiate each of the modules the following way:
this.module1 = new Module1(this);
this.module2 = new Module2(this);
Where module1 and module2 defines the functions (or old style classes) Module1 and Module2 respectively. Then from my pop-up's, concretelly from page action and options page of the extension I'm doing:
chrome.runtime.getBackgroundPage(page => {
...
/* this fails and says that module1 is not defined */
page.module1.callSomeFunctionOnModule1()
...
})
As said above this used to work some months ago, and I don't know why my instances are not defined anymore, actually none of the functions defined in the background page are available. Is there any reason I can not do this anymore? What will be the way to call functions on the background from the page actions and option page?
I don't know what to try ... my functions are not defined in the foreground anymore.. I tried to call chrome.extension.getBackgroundPage instead of chrome.runtime.getBackgroundPage with no luck.
You can find the complete extension at https://github.com/szz-dvl/JSLoader/tree/chrome
I do expect to be able to access my background functions from my foreground pages (both page action and options page.)
Thanks in advance!

Related

Replicate chrome://offline-internals/ functionality - chrome.send is not a function

I am trying to build a chrome://offline-internals/ functionality. The chrome://offline-internals/ shows among many things, the pages which are stored for offline viewing, and this feature are only available in mobile chrome browser.
The page at chrome://offline-internals/ basically has a HTML page which I found using view-source:chrome://offline-internals/. I the HTML a javascript is referenced (offline_internals.js), which in turn has nested javascript referenced. I downloaded all referenced javascript in my local folder since chrome doesn't allow access to chrome://resources/js for referencing js pages.
After downloading, I tried to open HTML page and I got an error as below
cr.m.js:107 Uncaught TypeError: chrome.send is not a function
at sendWithPromise (cr.m.js:107)
at OfflineInternalsBrowserProxyImpl.getStoredPages (offline_internals_browser_proxy.js:30)
at refreshAll (offline_internals.js:64)
at HTMLDocument.initialize (offline_internals.js:248)
This basically comes in a file called cr.m.js in the below function
export function sendWithPromise(methodName, var_args) {
const args = Array.prototype.slice.call(arguments, 1);
const promiseResolver = new PromiseResolver();
const id = methodName + '_' + createUid();
chromeSendResolverMap[id] = promiseResolver;
chrome.send(methodName, [id].concat(args)); <-- Error
return promiseResolver.promise;
}
I tried to open chrome://offline-internals/ and set my breakpoint at the above function and that time chrome.send was found to be a function and when I ran my custom HTML page having same source and references, it says chrome.send is not a function.
Probably, the chrome instance given to my script vis-a-vis the one given to chrome://offline-internals/ is a different one.
What can I do to resolve this issue ?
P.S.: This link chrome://offline-internals/ will open in your mobile chrome browser only.
P.S.: All downloaded files are present at this path, in case you wish to see:
https://easyupload.io/9x332s

Running client side javascript without loading a new (blank) view on Odoo 8

I need to run some client-side javascript from a button in a form view in Odoo 8. This button runs a python method which returns this dictionary:
{"type": "ir.actions.client",
"tag": "my_module.do_something",}
do_something is defined in a .js file as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.Action");
instance.my_module.Action = instance.web.Widget.extend({
init: function() {
// Do a lot of nice things here
}
});
};
Now, the javascript is loaded and executed properly, but even before launching the init function, Odoo loads a brand new, blank view, and once the javascript is over I can't get browse any other menu entry. In fact, wherever I click I get this error:
Uncaught TypeError: Cannot read property 'callbackList' of undefined
What I need instead is to run the javascript from the form view where the button belongs, without loading a new view, so both getting the javascript stuff done and leaving all callbacks and the whole environment in a good state. My gut feeling is that I shouldn't override the init funcion (or maybe the whole thing is broken, I'm quite new to Odoo client-side js) , but I couldn't find docs neither a good example to call js the way I want. Any idea to get that?
Sorry, I don't work on v8 since a lot of time and I don't remember how to add that, but this might help you: https://github.com/odoo/odoo/blob/8.0/doc/howtos/web.rst
Plus, if you search into v8 code base you can find some occurence of client actions in web module docs https://github.com/odoo/odoo/search?utf8=%E2%9C%93&q=instance.web.client_actions.add
Thanks to the pointers simahawk posted in another answer, I have been able to fix my js, which is now doing exactly what I needed. For your reference, the code is as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.action");
instance.my_module.action = function (parent, action) {
// Do a lot of nice things here
}
};

In newer versions of Firefox, is it still possible to override a web page's JS function?

I am writing an extension to override a web page's JS function, and started from this question, but the answer does not appear to work in Firefox 42 on Linux.
Next, I tried to use exportFunction as described in the documentation, but that also silently failed.
Inside package.json, I have added the following sesction.
"permissions": {
"unsafe-content-script": true
}
Here is my index.js file.
var self = require('sdk/self');
require("sdk/tabs").on("ready", fixGoogle);
function fixGoogle(tab) {
if (tab.url.indexOf("google.com") > -1) {
tab.attach({
contentScriptFile: self.data.url("google-script.js")
});
}
}
Here is my current data/google-script.js.
unsafeWindow.rwt=function(){};
Note that manually typing in rwt=function(){}; to the browser's console achieves the desired effect, as does using a bookmarklet (which requires clicking) but I am writing the plugin to get this automatically every time I use Google.
Is it possible to override the rwt page function using a Firefox extension? If so, what is the correct API to use?
read the documentation you've linked to, specifically the chapter titled Expose functions to page scripts - which links to exportFunction
function blah() {}
exportFunction(blah, unsafeWindow, {defineAs: 'rwt'});
It turns out that the issue is that the redefinition of the function rwt is racing against the original definition and winning. The original runs after and overrides the function I defined, thereby making it look like my redefinition had silently failed.
Once I realized that this was the problem, the easiest hack around it was to add a timeout to the redefinition inside data/google-script.js.
setTimeout(function() {
unsafeWindow.rwt=function(){};
}, 1000);
Thus, the orignal answer is still correct but simply failed to address the race condition.
Even though content scripts share the DOM, they are otherwise isolated from page scripts. As you correctly surmised, one can use unsafeWindow in Firefox to bypass this isolation.
Personally, I don't like the name of unsafeWindow for some reason ;)
Therefore I propose another way to do this: make use of the thing that's shared between these scopes, i. e. DOM.
You can create a page script from a content script:
var script = 'rwt=function()();';
document.addEventListener('DOMContentLoaded', function() {
var scriptEl = document.createElement('script');
scriptEl.textContent = script;
document.head.appendChild(scriptEl);
});
The benefit of this approach is that you can use it in environments without unsafeWindow, e. g. chrome extensions.

Javascript Runtime Error: 'Application is undefined'

I need to know if this is correct. I'm just beginning in app development using WinJS. I've identified the source of the problem and got rid of it but I don't know if that's the correct method.Please help!
// Optimize the load of the application and while the splash screen is
// shown, execute high priority scheduled work.
ui.disableAnimations();
var p = ui.processAll().then(function () {
//return nav.navigate(nav.location || Application.navigator.home, nav.state);
return nav.navigate(nav.location || app.local, nav.state)
}).then(function () {
return sched.requestDrain(sched.Priority.aboveNormal + 1);
}).then(function () {
ui.enableAnimations();
});
The problem is in the first .then(). The commented line was the default line, I've changed it for the app to work.I've absolutely no idea what it is.Please tell me what it means and what is changed. By the way, 'app' is WinJS.Application and Application is a WinJS namespace in navigator.js where the home property is located.
This error would suggest that navigator.js isn't being loaded by the time this code is executed. The Application namespace, which is entirely arbitrary and unrelated to WinJS.Application, is defined only in navigator.js, so if that file isn't loaded that namespace won't exist.
A WinJS namespace, by the way, is just a formalization of a module pattern in JavaScript that helps you keep the global namespace from getting cluttered. Declaring a namespace like navigator.js does it:
WinJS.Namespace.define("Application", {
PageControlNavigator: WinJS.Class.define(
just creates a single object in the global namespace called "Application" and then defines members for it. (You can change "Application" to anything you want, by the way. Nothing else in navigator.js relies on it, and navigator.js is something that comes from the app templates in Visual Studio and isn't part of WinJS itself.)
So again, my suspicion is that you don't have (or whatever the proper path is) in your default.html, the path to it isn't correct, or that perhaps it's being loaded after the other code is trying to execute. Try setting breakpoints on WinJS.Namespace.define and see if that file is loaded and the breakpoint gets hit.

error with google swiffy calling runtime.js multiple times in the same page

I have converted multiple swf files using google swiffy v5.2 and will have my new animations displayed on many different pages, most of which I do not have control of or access to. In order for the animation to work it needs the swiffy's runtime.js file, which might look something like this on the page:
<script src="https://www.gstatic.com/swiffy/v5.2/runtime.js"></script>
The problem arises when I either have multiple instances of the animation on the same page or a client has this runtime.js file included on their own. When checking the javascript console I get this error:
Uncaught TypeError: Cannot redefine property: __swiffy_override - runtime.js:186
If i was only worried about the conflict with myself I could possibly keep track of a variable or check if the script src existed already, however I do not have this luxury when a client's page may have renamed or changed the source to this file.
Is there a way to prevent the swiffy runtime.js from redefining this property when there are multiple instances of the same javascript file being included on the page?
I imagine you are seeing this problem happen when using AS3 swfs, which have Document classes applied to them. For example, say you have animationAS3.swf, which uses AnimationBaseClass.as. When it is "compiled" by Google Swiffy service the resultant JSON data will contain
{"internedStrings":["...", "AnimationBaseClass", "..."] ....}
The Google Swiffy runtime applies JavaScript's defineProperties() or perhaps defineProperty() to seal an "AnimationBaseClass" object it creates. So, when another instance of the data is loaded the Swiffy runtime attempts to do the same thing again, and the JavaScript interpreter says "Hey, I've already defined that object, I won't redefine it."
The solution I've found, which I believe is inefficient, is to rename the class before giving the data to the Swiffy runtime. Like this:
var classEnumerator = 0;
$.getJSON('animationAS3.json', function(data) {
// Due to "TypeError: Cannot redefine property: AnimationBaseClass",
// we need to enumerate the name of the class. I have no idea about
// the impact on resource usage when doing this.
var classNameIndex;
var i = data.internedStrings.length;
while(i--) {
if (data.internedStrings[i].indexOf("AnimationBaseClass") > -1) {
classNameIndex = i;
}
}
data.internedStrings[classNameIndex] = "AnimationBaseClass_" + (classEnumerator++));
}

Categories

Resources