Firefox plugin that ask for some input at startup - firefox

I would like to know how to implement a dialog that show up when you first start Firefox to ask the user to enter some input. This input will be stored somewhere temporarily, and should be used later on by the plugin when required.
I have full understand of how to implement firefox plugin (this includes understanding of XUL and Javascript), so no need for full plugin example. The specific question is how to show a dialog when firefox start that ask for input, and how to store the input in a temporary storage.
Any help would be appreciated.

Add an event listener to your overlay.xul:
<window>
<script type="text/javascript">
var your_func = function (e) {
var pref = window.prompt ("Your name:","");
}
window.addEventListener ("load", your_func, false);
</script>
</window>
The your_func() will be called, whenever a new window (not a new tab) is loaded. If it should only be on start-up, you'll have to make an additional test. You find details here: developer.mozilla.org
For persistence you could store the found value as a preference: Preference Code Snippets. It would be useful then, to check in your_func, if such a preference exists, before opening the prompt.
Instead of a plain prompt, you could do the following:
window.open ("chrome://my-plugin/content/prompt.xul", "MyWindow", "chrome,modal,alwaysRaised,centerscreen");
The magic lies in the "modal" value in the third parameter.
Cheers,

Related

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.

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;

workaround to firefox creating new history after each document.write()

in Firefox after each document.write() new history entrie is made, so if document.write() is called on page load when user presses back button to go back in history firefox takes him to the current page which runs document.write() again and creates another history so even another back button pressing won't help and take him where he wants
simple workaround is:
function onbeforeunload(e)
{
setTimeout(function() { window.history.go(-2); }, 0);
}
window.addEventListener("beforeunload", onbeforeunload, true);
but then it won't let user go any link or type any address into addressbar and go there, so is there another way to fix firefox?
a better way would be to use onpopstate event instead but it does not work in firefox after document.write()
and no, document.write() must be used here.
Use document.open("text/html", "replace") instead of just document.open().
Works like a charm.
Interesting to note that other workarounds did NOT work - such as $('html').replaceWith(pageContent) or manipulating the history if the browser is Firefox...
Use document.open to run document.write while keeping the history unchanged:
<script>
document.open("text/html",document.write("foo") );
</script>
References
DOM document.open

chrome-app won't recognize id's that work fine when run by the chrome browser

I'm converting a standard browser based app that's working fine to a chrome-app.
Once the page loads up, it has already hit an error - Uncaught TypeError: Cannot call method 'appendChild' of null. This occurs after several hundred lines of JS have done their job but its the first time the code makes a reference to the document object, specifically document.getElementById('mainDiv').appendChild(...).
I can clearly see the div with the id="mainDiv" in the debuggers elements tab. Yet, document.getElementById('mainDiv') must be returning a null. Any attempt at putting in breakpoints fails as they are ignored. I've added them to the line that fails as well as to lines that lead up to it and breakpoints are never triggered. I've read some of the threads on SO and I'm certain the breakpoints issue is just a bug in the debugger, but not recognizing an id when I can clearly see it and the code when run in the browser works fine leaves me wondering what's going on. Is document in the browser different from document in the app version?
Any ideas?
If I choose "inspect background page", the breakpoints work but it still fails but in a different way. The elements tab does NOT show my html page, but the pseudo generated background one and I can't get the debugger to show my page at all.
Any enlightenment would be appreciated. I've searched and read what I could find, but much of the docs are clearly out of date.
You seem to be accessing the document object of the background page, instead of that of your POS.html file.
Try this:
chrome.app.window.create('POS.html',{
'bounds': {
'width': screen.availWidth,
'height': screen.availHeight
}
}, function(appWin) {
var pageWindow = appWin.contentWindow;
var pageDocument = pageWindow.document;
pageWindow.addEventListener('load',function() {
// now use
pageDocument.getElementById('yourid');
// instead of
document.getElementById('yourid');
},false);
});
Also to inspect elements in your page right-click anywhere in the app window and select Inspect Element (this works only when the app was loaded as an 'unpacked extension')
Alternatively you can navigate to chrome://extensions and click the page link next to your app entry.
As lostsource mentioned, you're probably accessing the wrong DOM's document. You should think about the javascript in your app running in different global contexts, one for each page. There is (at a minimum) a page for the background page, and a page for each window.
Each of these pages runs in its own global context. This means global variables like document and window are different.
In the background page will be scripts which you load via the background manifest tag. When you open a window, it can also load its own script via script tags (make sure you do not use inline or block script tags, but use script src="foo.js". See http://developer.chrome.com/apps/contentSecurityPolicy.html).
The code that runs in the callback to chrome.app.window.create runs in the background page's context, so its document variable is for the background page's DOM, which is usually empty. Instead you can make it refer to the window's DOM using win.contentWindow as lostsource suggested, or add a page.js file with the script in it, and include it from the page via a script src='page.js' tag.
Is your call occurring after the load event, e.g. the JS called in a function set on window.onload?

Save drop-down history in a Firefox Toolbar

I'm doing some testing on Firefox toolbars for the sake of learning and I can't find out any information on how to store the contents of a "search" drop-down inside the user's profile.
Is there any tutorial on how to sort this out?
Since it's taking quite a bit to get an answer I went and investigate it myself.
Here is what I've got now. Not all is clear to me but it works.
Let's assume you have a <textbox> like this, on your .xul:
<textbox id="search_with_history" />
You now have to add some other attributes to enable history.
<textbox id="search_with_history" type="autocomplete"
autocompletesearch="form-history"
autocompletesearchparam="Search-History-Name"
ontextentered="Search_Change(param);"
enablehistory="true"
/>
This gives you the minimum to enable a history on that textbox.
For some reason, and here is where my ignorance shows, the onTextEntered event function has to have the param to it called "param". I tried "event" and it didn't work.
But that alone will not do work by itself. One has to add some Javascript to help with the job.
// This is the interface to store the history
const HistoryObject = Components.classes["#mozilla.org/satchel/form-history;1"]
.getService(
Components.interfaces.nsIFormHistory2 || Components.interfaces.nsIFormHistory
);
// The above line was broken into 4 for clearness.
// If you encounter problems please use only one line.
// This function is the one called upon the event of pressing <enter>
// on the text box
function Search_Change(event) {
var terms = document.getElementById('search_with_history').value;
HistoryObject.addEntry('Search-History-Name', terms);
}
This is the absolute minimum to get a history going on.
Gustavo,
I wanted to do the same thing - I found an answer here on the Mozilla support forums. (Edit: I wanted to save my search history out of interest, not because I wanted to learn how the Firefox toolbars work, as you said.)
Basically, that data is stored in a sqlite database file called formhistory.sqlite (in your Firefox profile directory). You can use the Firefox extension SQLite Manager to retrieve and export the data: https://addons.mozilla.org/firefox/addon/5817
You can export it as a CSV (comma- separated values) file and open it with Excel or other software.
This has the added benefit of also saving the history of data you've entered into other forms/fields on sites, such as the Search field on Google, etc, if this data is of interest to you.
Gustavo's solution is good, but document.getElemenById('search_with_history').value; is missing a 't' in getElementById

Resources