Firefox Add-on SDK context-menu communicate with a content script loaded by page-mod - firefox

I'm creating a Firefox add-on with the Firefox Add-on SDK. This add-on does two things:
Inject a content script into every page with sdk/page-mod.
Add a context menu item using sdk/context-menu.
I want that when user clicks the context menu item, the add-on will call functions in the content script which was loaded by PageMod().

Unless your page-mod script is doing other things, it sounds like it might be more appropriate to load it using the context-menu contentScript or contentScriptFile properties. Alternately, load the portions of it that are needed by the context menu using this methodology. How best to split the script you are using depends on what you are actually doing. Without more information from you it is difficult to provide specific recommendations.
Communicating between content scripts loaded at different times or by different methods:
There is no method of directly doing what you desire. Content scripts that are not loaded at the same time by the same methodology are loaded into different contexts. They are unable to directly call functions between them. Multiple content scripts which are loaded at the same time and the same methodology share the same context/scope and can directly call functions between them.
However, you can communicate between content scripts. If they are not loaded into the same page, then you will need to communicate from one content script to another by using your main add-on script to first receive a message from one content script. Then, your main add-on script will need to send a second message (potentially containing exactly the same data) to the second content script. In other words, your main add-on code would need to relay the message between the two content scripts.
For content scripts that are loaded into the same page via different methods (e.g. one with page-mod and another as a context menu item – the situation in which you are interested), you can communicate directly between them using the DOM postMessage() API or a CustomEvent. Either can be used to send whatever JSON serializable data you desire between the two scripts. The DOM postMessage() API provides for more security, but is a bit more complex. With it you must also filter out any other "message" events that are sent on it by random code. It should probably be used if you are going to have code in a released add-on execute functions based on the content of the messages. This is a security issue which will depend on exactly what you are doing with the messages.
Example:
The following code will load a page-mod script into every page that matches "*.mozilla.org". It also creates a context menu item in those same pages which is displayed on links. Clicking on the context menu item will send an event from the context-menu content script with data containing the URL for which the context menu was displayed. The custom event will be received by the page-mod script. The page-mod script will then issue an alert with the URL for the link.
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "*.mozilla.org",
contentScript: 'function contextMenuAlert(href) {'
+ ' window.alert("The context menu click on a link with URL:\\n" + href);'
+ '};'
+ 'window.addEventListener("myAddonId-contextMenu-clicked",'
+ ' function(event){contextMenuAlert(event.detail);});'
});
//Context menu
let cm = require("sdk/context-menu");
cm.Item({
label: "Alert link URL",
context: [
cm.URLContext(["*.mozilla.org"]),
cm.SelectorContext("a[href]")
],
contentScript: 'self.on("click", function (node, data) {'
+ ' var event = new CustomEvent("myAddonId-contextMenu-clicked",'
+ ' {detail:node.href});'
+ ' window.dispatchEvent(event);'
+ '});'
});
The above code produces a context menu that looks like:
When clicked on, the page-mod added content script initiates the following alert:
Using the message sent to choose from multiple different functions:
The information passed through the event can be expanded to allow multiple different functions to be called depending on the content. One method of doing this is to send an object as the message. One property of the object can be the function desired and another can be data to use in that function. My answers to the following questions contain examples of doing this:
Add menu item created with the sdk/context-menu API to the top of the context menu: This answer has code which uses the same passed message to indicate that either a click was made on a context menu item and pass the URL on which the context menu item was clicked, or to tell the main script that the context menu is about to be displayed so it can be modified.
How to console.log from ChromeWorker (alternative to dump): This answer shows sending a message that will result in a call to one of a variety of different functions and pass data to the function which was called. It was implemented as a way of using console methods from a worker with just console.log("message"). I'd code this one a bit differently were I doing it today, but it works and demonstrates the concept.
Because the documentation on MDN (here and here) was not very clear on content script to content script communication, I have updated the pages I found on which it was discussed. I have also added the above code as an example.

Related

xamarin forms webview.eval return type is voide . How to retrieve user input data?

I am working on xamarin.forms. I have a content page which contains one webview which load 3rd party url(www.xyz.com) site and one button in shell.
On button click event I am trying to get user input data using
webview.eval(javascript: var data = document.getElementById('first-name').value;alert(data)).
It works fine but due to void return type I could not store data in local variable and I have a customrender(webviewrender) but don't know on shell button click event how can I get userinput data from webview
Please suggest me how do I achieve this functionality.I do not want XLab-Hybridwebview.
You'll probably need to have the JavaScript code call out to the external code when the result is available. You could then wrap that whole process in a TaskCompletionSource to make everything nice and easy to use.

Firefox addon sdk tab script talk to page mod script

In main.js I am opening a tab and attaching a script with page-mod. The html file that is being opened it has a bunch of regular includes.
Sort of have two issues.
The script from page mod does not get attached until after those other scripts are loaded, and also
the regular scripts can't access variables defined in the script that is attached with page mod.
You have to send messages.
Directly
In your page-mod, send a message:
page-mod.js
window.postMessage(projectUniqueId + '|' + message, domain);
If your page needs to work with all domains (being a plug-in), you might need '*' as a domain.
tab-attach.js
window.addEventListener('message',function(event){
var words = event.data.split('|');
if (words[0] == projectUniqueId){
handle(words[1]);
}
});
The script from page mod does not get attached until after those other scripts are loaded,
Specifying contentScriptWhen: 'ready' in the page-mod constructor should "[l]oad content scripts once DOM content has been loaded, corresponding to the DOMContentLoaded event"
the regular scripts can't access variables defined in the script that is attached with page mod.
Have a look at Expose objects to page scripts. You need to use
var contentScriptObject = {"greeting" : "hello from add-on"};
unsafeWindow.clonedContentScriptObject = cloneInto(contentScriptObject, unsafeWindow);
in the content script to make the object accessible.

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?

wp7 open another web browser control inside web broser control

I have web browser control which contains many links and data. All these data are coming from web service.
Now i want open another web browser control when i click on first web broser link.
so how it can be done?
my first web broser code is :
webBrowser1.NavigateToString(htmlCode);
You could have another webBrowser hidden under webBrowser1. Lets call it webBrowser2. Now when a user hits a link on webBrowser1, capture it a string lets say link. Now you can navigate to link using webBrowser2.Navigate(new Uri(link,UriKind.Absolute));. Do not forget to make webBrowser1 hidden and webBrowser2 visible.
If i understand you, you want to intercept the onClick event in your first WB control (call this WB1), and open that page up (when the hyperlink is clicked) in another WB control (call this WB2)?
There are several ways you can do this, is this link set to open up in a new window? If so, you can intercept the NewWindow2 event is WB1 and run the following code in the NewWindow2 event of WB1...
Set pDisp = WB2.object
(it may be ppDisp instead of pDisp, but it will show up when your event is auto generated, choose whichever object name shows up in your arguments list).
Otherwise, you can intercept this request during BeforeNavigate2 event of the WB1 event, check the URL property if it is the link you're interested in, and if so, cancel the current request and reissue a new one as below... (in the WB1 BN2 event)...
Cancel = True ' This cancels the request
WB2.Navigate2 URL, , "YourWB2sDocumentNameOrTargetFrameNameGoesHere"
Second line of code just reissues the request.
Of course, the YourWB2sDocumentNameOrTargetFrameNameGoesHere is the TargetFrameName (or the frame or document name of the top level document, or any iframe, in your WB2 control/window). This can usually be found in the BODY tags name= property, but you don't even need to do this if all you want is to load it as the top level document in WB2... if you just want to load it as the parent top level document in WB2, just do this...
Cancel = True
WB2.Navigate2 URL
By referencing WB2 it will just send the same URL request to WB2 window after cancelling WB1 request.
Let me know if you need more help and let me know how you get along.

Can I delay loading of some controls on an xPage to after page loaded

is it possible to delay loading of some controls on an xpage?
This is the problem: let's say you have a control that does a fultextsearch and displays the result in a repeat control. this ft search might take a long time and will hold the webpage loading in a waiting state until the search result is ready.
I want my page to load most of the data initally, and some "time consuming" controls should be loaded in to the page as a sperate request after the inital load.
this way the user will immediatly see the webpage, but some of the data on the page will load a little bit later without holding the webpage in a waiting state from the server.
possible?
The downside to using rendered is that all the value bindings will still evaluate, even if the corresponding markup isn't sent to the page. So the trick here is making sure the components don't even exist until you want them to.
Every component has a getChildren() method. This returns a mutable List of components, which has a add() method. This allows you to add components to the page on the fly, either while the page is loading, or later during an event. For the purposes of what you're trying to do, you would want to defer adding the "expensive" components until a subsequent event.
Create an event handler attached directly to the view root (), give it a unique ID (e.g. "loadExpensiveComponentsEvent", set its refresh mode to partial, set a refresh ID to whatever div or panel will contain the search results, and set its event name to an arbitrary event (e.g. "loadExpensiveComponents"). This prevents your event from being triggered by actual user behavior. Set the event's code to SSJS that will inject your components.
Then add a script block () to trigger the event after the page has loaded:
XSP.addOnLoad(function(){
XSP.firePartial(null, "#{id:loadExpensiveComponentsEvent}");
});
Your page will load without the search result components. Once the page has fully loaded, it will trigger the component injection event automatically.
For guidance on how to code the injection event, open the Java file that has been generated from your existing page to see what components need to be injected and what to set their values to.
You can pack them into a panel and set their rendered status to rendered=#{viewScope.pageFullyLoaded}. Then in the onLoad event have a XSP. partialRefresh request where you set viewScope.pageFullyLoaded=true
A little ugly but doable. Now you can wrap that code into your own custom control, so you could have a "lazyGrid", "lazyPanel" etc.
Not sure why I did not think of this before. the dynamic content control in extlib actually solves this problem. the dcc can be triggered onClientLoad both using javascript and ssjs afer the page has loaded.
one problem I am facing now is that I am already using the dcc on my site so I need to put another dcc within my dcc. and this seem to be a bit buggy. I have reported it to the extlib team on openNTF.

Resources