Remove oscpu property from from window.navigator - firefox

If you are using FireFox, navigator has a property oscpu.
The property can be easily changed by appending general.oscpu.override value in about:config.
But, this option is present only in FireFox and does not exist in any other browser. This allows a 100% certainty to determine the type of browser.
Conventional means can not remove it. Whatever happened that ( oscpu in navigator) would return false.
All this does not work:
delete navigator.oscpu;
'oscpu' in navigator; // true
navigator.oscpu = null;
'serviceWorker' in navigator; // true
navigator.oscpu === null; // false
Object.defineProperty(navigator, "oscpu", {
configurable: true,
value: undefined
});
'oscpu' in navigator; // true
navigator.oscpu === undefined; // true
Are there ways to remove this property from navigator? And indeed any other parameter. I am writing a Firefox Add-on SDK extension.

There are potential side effects of doing what you are wanting to accomplish. It would be helpful to know what your goals are in order to determine a good way to accomplish what you desire.
However, for what you have specifically requested, removing navigator.oscpu in the current scope, the following works:
//This specific code relies on navigator referring to the object which you want to
// modify. In an Add-on SDK extension, if navigator is _actually_ the object you need
// to modify to accomplish what you desire will depend on the scope you are in and
// what object you have set the variable navigator to refer to.
delete navigator.__proto__.oscpu;
console.log(navigator.oscpu); // undefined
'oscpu' in navigator // false
Note that you will need to do this within every context/scope in which you desire for it to have effect. In general, this means that you will need to inject a content script into every page and frame in which you wish this to be the case. It also means that you should take care to only do it in the context/scopes in which you are wanting it to be seen by whatever JavaScript you are attempting to spoof (i.e. within the scope of page scripts, not in the scope of code running with Chrome privileges.).

Related

history.replaceState() not working with history.scrollRestoration = 'auto' in Svelte/Sapper

I am using history.replaceState() to update the query params of my page without causing a page reload as suggested in this SO answer.
function setQueryParam ({ name, value }) {
const params = new URLSearchParams(window.location.search)
params.set(name, value)
history.replaceState({}, '', decodeURIComponent(`${window.location.pathname}?${params}`))
}
I am also storing the scroll position of the user with the following line:
history.scrollRestoration = 'auto'
When navigating from one page to another, scrollRestoration works fine - the scroll position is maintained between pages. However, after I change the query params with my setQueryParam function, scroll restoration no longer works.
Why is this happening?
Note: the same code works fine outside of Svelte/Sapper, using HTML and JavaScript only.
As a client-side router, Sapper has to hijack scroll management & restoration a good deal to emulate the behaviour you normally get when you fully reload the browser on each page change.
To do that, it uses history's state to know the scroll position to restore.
When you're using history.replaceState, you're changing the state (it's the first argument you place to replaceState). And so, Sapper don't find its restore scroll data when you later pop the state.
You can try to manually preserve the history state like this:
// notice the first argument
history.replaceState(history.state, '', decodeURIComponent(`${window.location.pathname}?${params}`))
I don't think history.scrollRestoration actually has any effect in Sapper.

create and show one use only dialog, constructed based on global state.

I have a plugin which need to show a (Modal) dialog each time the user double click on a word.
Detecting double click is no problem, but the exact fields/values in the dialog depends on exactly which word the user clicked on, and some mutable global state. So I can't create the dialog until the moment before I need to show it. And here is the problem: How do I do that?
Right now I use this code:
var dialogName="uniqueDialog" + counter++;
CKEDITOR.dialog.add(dialogName,function(editor) {
// Creating dialog here.
});
CKEDITOR.instances.editor.openDialog(dialogName);
This works, but having to add a uniquely named dialog, just to show it once and then newer use it again seems really really wrong. Also I fear this will keep using resources since the dialogs are newer removed(I could not find any remove method).
So my question is: Is there a better way to dynamical create and show a "one use" dialog?
Update:
If bootstrap is not allowed then maybe an addFrame version of the dialog is acceptable. This could then refer to a html file that can load from parameters.
NB: The plunkr only works, if you fork and edit it, otherwise it will give you a 404 for the template.
Here is a quick plunkr:
plunky
And here is the plugin in question:
CKEDITOR.plugins.add( 'insertVariable', {
requires: ['iframedialog'],
icons: 'insertvariable',
init: function( editor ) {
editor.addCommand( 'varDialog', new CKEDITOR.dialogCommand( 'varDialog' ) );
CKEDITOR.dialog.addIframe('varDialog','varDialog','sample.html?var='+item,500,400);
editor.ui.addButton( 'insertVariable', {
label: 'Insert Variable',
command: 'varDialog',
icon: this.path + '<insert gif>'
});
}
});
Obviously you are not creating dialogs anymore with different content, but you are referring to another piece of html, that can change. I've kept the bootstrap thing in there as well for reference.
I made one final edit, that will show the current contents. So I think that is roughly what you want. Check it out.
Previous Answer
If you are prepared to use bootstrap, then you can do no worse than check out their modal dialog, which can be just be shown and hidden at will.
http://getbootstrap.com/javascript/#modals
It's simple and cuts down any need to keep creating your own dialog. The dialog won't be one use type, but you will set the defaults as necessary. The varying content link is here:
http://getbootstrap.com/javascript/#modals-related-target
That would be the quickest way to get this going. It all depends on whether you want to use this framework. As CKEDITOR is already using JQuery it is an option worth considering.

Firefox extension: share state

I have a Firefox overlay extension with a tree in a sidebar.
How can I keep the tree state synchronized in several windows?
For example in first window added new item in tree, how update tree in other windows?
If somebody can show minimal code for it (with use code modules, observers, broadcasters or something else), please help.
I read similar question, but it did not help:
Firefox extension - Share common state between two or more windows
The answer in the question you reference is good, but short on explanation. You should read the references to which it links. I have duplicated those links here.
One way to keep state information outside of a window context is to use JavaScript code modules (JSM). The section Sharing objects using code modules talks briefly about doing this. Once you have set up your JSM to share the data, it is merely a matter of informing each window that a change has been made and it should update the displayed state. This is easily accomplished by using an event which you define. All of the sidebars listen for a particular event in their window. Then there is one function in the JSM which runs through all the windows signalling them that they need to update.
The code to signal could look something like:
Components.utils.import("resource://gre/modules/Services.jsm");
function forEachOpenWindow(todo) {
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}
}
function signalUpdateNeeded(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
}
function sendUpdateAvailableToAllWindows(){
forEachOpenWindow(signalUpdateNeeded);
}
Then in the code for the sidebar:
//This imports your JSM, it does not need the .jsm extension, you can use
// whatever extension you want.
Components.utils.import("chrome://MyExtension/content/moduleName.jsm");
window.addEventListener("myExtensionName-UpdateAvailable",
updateDataFromModule, false);
//Instead you may need the following (or another way to get to the
// top window). What is actually needed will depend on the context in
// which your sidebar code is running. You should see below for code to
// access the main browser window from within a sidebar.
//window.top.addEventListener("myExtensionName-UpdateAvailable",
// updateDataFromModule, false);
function updateDataFromModule(){
//Whatever it is you need to do here.
mylocalVariable = myExtensionModule.dataStructure.whatever;
}
Refactoring the first code section above so that it looks like it is in a module that uses one variable to reduce namespace clutter. The code for the module could be something like:
var EXPORTED_SYMBOLS = [ "myExtensionModule" ];
Components.utils.import("resource://gre/modules/Services.jsm");
var myExtensionModule = {
dataStructure: {
whatever: true,
you: 1,
want: ["here.", "It", "is", "your", "data."]
};
forEachOpenWindow: function(todo){
// Apply a function to all open browser windows
var windows = Services.wm.getEnumerator("navigator:browser");
while (windows.hasMoreElements()) {
todo(windows.getNext()
.QueryInterface(Components.interfaces.nsIDOMWindow));
}
},
signalUpdateNeeded: function(window){
let event = window.document.createEvent("Event");
event.initEvent("myExtensionName-UpdateAvailable",false,false);
window.dispatchEvent(event);
},
sendUpdateAvailableToAllWindows: function(){
this.forEachOpenWindow(this.signalUpdateNeeded);
}
}
I have not actually tested this, so there may be some errors.
Having either your sidebar code access the main browser window, or the JSM code find which sidebar your code is in (in order to send or listen fro events) may be a bit more complicated than you think. You should see Working with windows in chrome code. Specifically, Accessing the elements of the top-level document from a child window. That section provides the following code to access the main browser window from within a sidebar:
var mainWindow = window
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
An alternative is for your JSM to keep a reference to an object in the data structure on which all of the sidebars place listeners. This could be an object which it creates. If you do use this method and choose to use a window, then you need to make sure that handle releasing the reference if the window is closed. If you don't you could end up with a memory leak.

How to access the content of a webpage displayed in a tab from a Firefox addon

In a Firefox extension, I am attempting to add a form into the web page by inserting DOM elements, and then process any data that the user enters in the form.
I have tried several methods, but have been unable to get my form inserted into the webpage's document. I tried using the different types of add-ons, Overlay (XUL) and the Add-on SDK, but I have not been able to get it to work.
Overlay/XUL: I investigated and found nothing that specifically showed me how to change the contents of a web page.
Using the Addons SDK: The only working code which I found was the demo code in "Modifying Web Pages Based on URL" which appeared to give:
var html = sth;
$("body").html(html);
I tried:
$('.id_of_ele').html('I want to show');
It doesn't work.
So far the only thing which has gotten me close is to use unsafeWindow.document, but I believe that is a really a bad idea, and the code looks really bad.
How do I access the the document of a webpage from a Firefox extension?
If you are looking for examples of known working code, you can always download one or more extensions from Mozilla Add-ons which do something close to what you want to accomplish and look at how they do it. Obviously, you should look at the license (linked on each extensions page) to see what the legal status of the code it. There are literally thousands of working examples there. The vast majority of which have code which is licensed in a way which permits you to re-use it.
The jQuery accesses which you are trying to use rely on the document variable pointing to the document which you are wanting to modify. In the context in which you are running, a Firefox add-on, the document variable may, by default, point to a document which is an ancestor of the webpage you are interested in or not be defined at all. What document actually is will depend on the context from which your add-on code was invoked. In a Firefox add-on, the document variable will almost never, by default, point to the content of a web page. You have to remember that you are writing code that is intended to run in a context that is much larger (entire browser/user agent) than that which is used for content scripts on a webpage (context within the browser is restricted to only the content of the webpage from which the script was run, or data which is obtained from references originating from within the page).
Gaining access to the document for the currently selected tab:
Changing the content document is very easy. You can change it just like you would from any JavaScript. The issue that you may find frustrating is obtaining a reference to the document.
Firefox overlay and restartless/bootstrapped have a great amount of power over the entire browser. However, the context, and what window points to, or even if it is defined, depends greatly on how the JavaScript was invoked. This can be both confusing and frustrating. On MDN, there is a document "Working with windows in chrome code" which describes many of the issues.
From extensions you have access to all windows and tabs. However, what you probably want is just some code that works to get you access to the current selected document.
This should work from all contexts to get you a reference to the document for the currently selected tab:
var selectedTabWindow = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
var selectedTabDocument = selectedTabWindow.content.document;
If you have code which you are converting from a content script which just expects to find window and document objects, you could write something like:
if (typeof window === "undefined") {
var window;
} else {
//Keep a reference to whatever was defined as window.
var originalWindow = window;
}
//Get the window from the most recently selected tab.
window = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow("navigator:browser");
//Now that we have a window for the most recently selected tab,
// get the document for it.
if (typeof document === "undefined") {
var document;
} else {
//Keep a reference to whatever was defined as document.
var originalDocument = document;
}
document = window.content.document;
//Now that we have a window for the most recently selected tab,
// get the gBrowser for it.
if (typeof gBrowser === "undefined") {
var gBrowser;
} else {
//Keep a reference to whatever was defined as gBrowser.
var originalGBrowser = gBrowser;
}
gBrowser = window.gBrowser;
The above will, obviously, overwrite any currently variables currently defined as window, document and gBrowser. Depending on the context in which you are running, and the scope in which you define these this could be either a good thing, or it might be a bad idea to change that reference. For example, if the code is running in a popup window then window is a reference to window of the popup. In that case, you can get a reference to the window from which the popup was opened with:
var windowWhichOpendedThisOne = window.opener;
var documentForWindowWhichOpendedThisOne = window.opener.content.document;
If you are in an event handler, then you can get the window for the target of the event from:
var windowInWhichEventTargetExists = event.view;
Choosing what to do based on the URL:
Once you have the correct document it should be quite easy to choose what to do based on the document's URL:
var currentUrl = document.location.href;

Accessing global variables in Firefox extensions

I'm writing a Firefox extension which takes a custom switch from the command line and sets a variable inside my cmdline.js in the components directory, we'll call the variable switchDetected which is a boolean. Now based upon this variable I want actions to be carried out in my overlay.js file in the chrome/content directory.
The problem I'm having is I can't seem to be able to access the variable switchDetected that is declared in components/cmdline.js from within chrome/contents/overlay.js.
I've tried numerous ways of doing this but nothing seems to work. So I'm just wondering if anyone knows how this can be achieved.
A script loaded in an overlay runs in the context of the browser window - its global variables are stored as properties of the window object corresponding with the browser. If you open a second browser window the same script will load a second time and run in the context of the new browser window - it will have different global variables. The scripts containing XPCOM components on the other hand only load once and they have their independent context that isn't bound to a window. So their global variables cannot be accessed from a browser window directly, just like two browser windows cannot access each others global variables directly.
Instead the browser window should communicate with the XPCOM component using the usual approach: get a component instance and call its method. If you don't want to define your own interface for that (you probably don't) you can use a trick, something like this:
CommandLineHandler.prototype = {
handle: function(commandLine) {...},
get helpInfo() {...},
isSwitchDetected: function()
{
return switchDetected;
},
get wrappedJSObject()
{
return this;
},
QueryInterface: XPCOMUtils.generateQI(["nsICommandLineHandler"]);
};
The wrappedJSObject property makes sure that your component can be unwrapped - all its methods and properties will become accessible then and not just the ones defined in the interface. So your overlay script needs to do the following:
var cmdLineHandler = Components.classes["#myself.com/my-command-line-handler;1"]
.getService()
.wrappedJSObject;
var switchDetected = cmdLineHandler.isSwitchDetected();

Resources