Firefox Add-on: get document from a tab - javascript

I was just trying to get the document of a tab and read information from it, but if I try to read the information on the Add-on-side I get an error "doc.getElementById is not a function". In the content-script it works fine. So is there a problem with passing whole objects through self.port?
var tabs = require('sdk/tabs');
var myTab;
var myScript = "self.port.on('getDocument', function() {" +
" var doc = window.document;" +
" console.log(doc.getElementById('lga').style.height);" +
" self.port.emit('answer', doc);" +
"})";
for each (var tab in tabs) {
if (tab.url == "https://www.google.com/") {
myTab = tab;
}
}
worker = myTab.attach({
contentScript: myScript
});
worker.port.emit("getDocument");
worker.port.on("answer", function(doc) {
console.log(doc.getElementById('lga').style.height);
});

You can only pass values via a message that could be serialized to JSON. doc, being a document, cannot be passed.
In your message, you could pass the actual value of the style instead:
self.port.emit('answer', doc.getElementById('lga').style.height);

Rather than try to import the document into main.js, create a new Javascript file in the data folder, ContentScript.js. Inject it with contentScriptFile into the page like so:
worker = myTab.attach({
contentScriptFile: require('sdk/self').data.url('ContentScript.js')
});
Meanwhile, in ContentScript.js
var doc = window.document;
//Now have your way with the document
Then if you ever need any variables in main.js, do what #nmaier said.
I realize that this may be obvious, but this is the intended behaviour, and it means you don't have to write a script as a string and provides more detailed logging.

Related

web workers inline instead of fetching another page

I would like to create web workers in line instead of referencing an external script (so that I can deploy a single HTML page instead of an HTML file and a JS file). I found a cool method online using Blobs here, but for some reason I cannot get it to work. I noticed mixed results in the comments section of that article too.
I am getting an error: Failed to load resource: the server responded with a status of 404 (Not Found) which errors on line: localhost:63342/[object%20Worker]:1
I'm guessing that the web worker isn't really the issue, it's in creating the temporary url resource? If so what am I missing still?
Here's my code, in the script tag in the HTML file:
function createWorker(fn) {
var blob = new Blob(['self.onmessage = ', fn.toString()], { type: 'text/javascript' });
var url = window.URL.createObjectURL(blob);
return new Worker(url);
}
var generic = function(e) {
self.postMessage('in line web worker code');
};
var worker = createWorker(generic);
if (window.Worker) {
var getEquipmentW = new Worker(worker);
getEquipmentW.postMessage({
msg: 'hi'
});
getEquipmentW.onmessage = function (e) {
console.log(e.data);
};
}
I'll answer my own question, you can include a Web Worker in a separate script tag. I believe the script type isn't an official one, so the code in this tag is not evaluated until later. It'll look something like this:
<script id="myWorkerCode" type="javascript/worker">
self.onmessage = function(e) {
const data = e.data
self.postMessage('received some data in worker thread');
};
</script>
then, in the script where you need the worker, create a Blob and assign the content to be the "javascript" type. make that Blob be a URL that you can feed into the Worker constructor:
if(window.Worker)
{
//# select the ID of the SCRIPT that contains your worker code
const blob = new Blob([
document.getElementById('myWorkerCode').textContent
], {type: "text/javascript"});
//# Note: window.webkitURL.createObjectURL() in Chrome 10+.
const worker = new Worker(window.URL.createObjectURL(blob));
worker.onMessage = (e) =>
{
console.log('received data in main thread : ')
console.log( e.data );
};
}
It's more of a "in-a-line-above" than "inline", but it allows web workers to be composed and used in the same file. The trick is using script tags and converting unevaluated javascript by assigning the script tags to the given types in the code above. Still not the most elegant solution, but very handy when pushing processes to another thread.
You function createWorker already returns a worker, so you can replace:
var worker = createWorker(generic);
var getEquipmentW = new Worker(worker);
With this:
var getEquipmentW = createWorker(generic);

Running Javascript in new window.open

I'm running this function to open a new window.
function htmlNewWindow(id) {
var html = $(id).html();
var newWindow = window.open('');
newWindow.document.body.innerHTML = '<html><head><title>Hi</title> <script src="js/myScript.js"></script> </head>' + html;
}
This successfully creates a new window with the HTML in it. I have a bunch of HTML tags which when clicked run a function called Foo1. I've tried printing the entire function of Foo1 to the new HTML document, and tried putting Foo1 inside myScript.js. I see both Foo1 inside a script tag in the new window, and but neither are loaded since they are just written to the new page as HTML.
Scripts added with .innerHTML aren't executed. You need to create a script node and append it to the window's DOM.
$("#button").click(newWindow);
function newWindow(id) {
var html = $(id).html();
var win = window.open('');
win.document.head.innerHTML = '<title>Hi</title></head>';
win.document.body.innerHTML = '<body>' + html + '</body>';
var script = document.createElement('script');
script.src = 'js/myScript.js';
win.document.head.appendChild(script);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">Click me</button>
This doesn't run in Stack Snippet's sandbox, here's a working jsfiddle.
Try this:
var newWindow = window.open('');
newWindow.document.createElement('script');
script.src = 'js/myScript.js';
newWindow.document.head.appendChild(script);
Just in case someone has this to be done in a link. Do the following:
Link
This opens a new window with that URL, it set the focus to that windows, and as soon as the 'load' event is triggered, it executes the code in the function. It only works with a page in the same domain.
Hope this helps ⬆✌.
Cheers 👍
Here's how you create, and then append a script file within a new window:
var fileref = document.createElement('script');
//creates script in current document
fileref.setAttribute("type", "text/javascript")
//set it to JS by "type"
fileref.setAttribute("src", filename)
//set your "src=yourFile_href_Here.js"
//Then create your newWindow as you did above, but slightly updated
//Create your function which will consume the "fileref" argument
function htmlNewWindow(fileref) {
var newWindow = window.open('');
newWindow.document.getElementsByTagName("head")[0].appendChild(fileref);
}; //right now the function is made but you still have to execute it
//Execute your function, and pass it the variable "fileref" that you set above.
htmlNewWindow(fileref);
//Within this edit you will append the head element
//with your newly created script(or any other parameterized argument)
/* Replace your filename to pass any other script */
NOTE - Opening a page residing on a different domain, if not specifically allowed, will reject instances of this due to CORS(https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
It's not a safe practice to be sending your scripts into other people's pages or allowing them in your own if your domain hasn't sent them. Also, depending on your server/technology stack you may need to configure your *-origin settings within your backend stack. See here: (https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)

Change html page content

I am creating Firefox addon using the Add-on SDK. I want to get data from remote url and inject it in current html. As of now i m able to fetch data using request module of Firefox addon sdk but m not able to inject it in current page.
for example : i am fetching response from website "abc.com".after fetching response i will augment current page with response
// main.js
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");
var Request = require("sdk/request").Request;
//create addon widget
var widget = widgets.Widget({
id: "div-show",
label: "Show divs",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function() {
//initializing request module to fetch content
quijote.get();
}
});
//fetch content of requested page
var quijote = Request({
url: "http://localhost/abc/",
overrideMimeType: "text/plain; charset=latin1",
onComplete: function (response) {
//check if content is fetched successfully
addContent(response);
}
});
//try and modify current page
function addContent(response){
//initialize page modification module
var pageMod = require("sdk/page-mod");
tabs.activeTab.attach({
contentScript: 'document.body.innerHTML = ' + ' "<h1>'+response.text+'</h1>";'
});
}
Is their any way in which i can augment my current page???
Your code will bitterly fail e.g. when response.text includes a double quote.
Then your code would be (assume it is world):
document.body.innerHTML = "<h1>world</h1>";
This is obviously invalid code.
Your code basically constructs a dynamic script from unsanitized data, which is a bad idea because (other than the escaping problem above)
you'll be running an unsanitized content script if that code is even valid and
if that would succeed, the page might run unsanitized code as well.
This is the web equivalent to SQL injection attacks....
First, lets tackle 1.) with messaging (more):
var worker = tabs.activeTab.attach({
contentScript: 'self.port.on("setdom", function(data) { ' +
+ 'document.body.innerHTML = data; /* still a security issue! */'
+ '});'
});
worker.port.emit("setdom", response.text);
This guarantees that the content script will be valid (can even run) and does not run arbitrary code.
However 2.) is still a problem. Read DOM Building and HTML insertion.

Is it possible to access java script data from the code behind in a different page?

I am trying to export some data that I have in some Backbone collections to a csv file.
So far I am opening a new export page using java script like so
var href = [];
href.push('ExportAnalysis.aspx?');
href.push('ParamSet=' + this.document.analysisParameterSetView.selectedParamSet + '&');
href.push('Start=' + start
Date + '&');
href.push('Finish=' + endDate + '&');
frames["exportIFrame"].location.href = href.join('');
And then in the code behind of exportAalysis.aspx, i am grabing the variables from the query string getting the data, building up the csv file and return the file like so.
// Get the export parmaters from the query string
var paramSet = Request["ParamSet"];
var startUnix = int.Parse(Request["Start"]);
var finishUnix = int.Parse(Request["Finish"]);
var start = DateTime.Parse("1970-01-01").AddSeconds(startUnix);
var finish = DateTime.Parse("1970-01-01").AddSeconds(finishUnix);
// GET DATA using Parameters
var filename = "analysisExport";
var content = "1,2";
Response.Clear();
Response.ContentType = "application/x-unknown";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
Response.Write(content);
Response.End();
}
This works OK, but it seems a little inefficient, as I am having to get the data I need twice. Once for the main page and again for the export page.
Its a bit of a long shot But is it possible to get the data from the first page from the code behind of the export page? If it was all client side I could use window.opener.document to get the opener page, Can I do something similar in asp.net
Or am I completely off track, and there is a much better way to achieve this.
This only works if the protocol and domain match between the iframe and the main window.
All code is javascript
Iframe to the parent:
var pDoc = window.parent.document;
var pWin = window.parent.window;
Document to iframe:
var cDoc = document.getElementById("exportIFrame").contentDocument;
var cWin = document.getElementById("exportIFrame").contentWindow;
To call scripts on a parent:
pWin.yourFunction("parameter");
To call scripts in an iframe:
cWin.yourFunction("parameter");

Add content to a new open window

I don't know how to solve this issue, I've trying reading many post but no one answer to it.
I need to open a new window with a page already coded (inside the same domain) and add some content.
The problem is that if I use OpenWindow.write() the page is not loaded yet or it overrides everything and only the code added through write appears.
var OpenWindow = window.open('mypage.html','_blank','width=335,height=330,resizable=1');
OpenWindow.document.write(output);
output is the code I need to append.
I need it to work at least on Firefox, IE and GC.
It is not a problem if I need to use JQuery.
When You want to open new tab/window (depends on Your browser configuration defaults):
output = 'Hello, World!';
window.open().document.write(output);
When output is an Object and You want get JSON, for example (also can generate any type of document, even image encoded in Base64)
output = ({a:1,b:'2'});
window.open('data:application/json;' + (window.btoa?'base64,'+btoa(JSON.stringify(output)):JSON.stringify(output)));
Update
Google Chrome (60.0.3112.90) block this code:
Not allowed to navigate top frame to data URL: data:application/json;base64,eyJhIjoxLCJiIjoiMiJ9
When You want to append some data to existing page
output = '<h1>Hello, World!</h1>';
window.open('output.html').document.body.innerHTML += output;
output = 'Hello, World!';
window.open('about:blank').document.body.innerText += output;
in parent.html:
<script type="text/javascript">
$(document).ready(function () {
var output = "data";
var OpenWindow = window.open("child.html", "mywin", '');
OpenWindow.dataFromParent = output; // dataFromParent is a variable in child.html
OpenWindow.init();
});
</script>
in child.html:
<script type="text/javascript">
var dataFromParent;
function init() {
document.write(dataFromParent);
}
</script>
Here is what you can try
Write a function say init() inside mypage.html that do the html thing ( append or what ever)
instead of OpenWindow.document.write(output); call OpenWindow.init() when the dom is ready
So the parent window will have
OpenWindow.onload = function(){
OpenWindow.init('test');
}
and in the child
function init(txt){
$('#test').text(txt);
}
When you call document.write after a page has loaded it will eliminate all content and replace it with the parameter you provide. Instead use DOM methods to add content, for example:
var OpenWindow = window.open('mypage.html','_blank','width=335,height=330,resizable=1');
var text = document.createTextNode('hi');
OpenWindow.document.body.appendChild(text);
If you want to use jQuery you get some better APIs to deal with. For example:
var OpenWindow = window.open('mypage.html','_blank','width=335,height=330,resizable=1');
$(OpenWindow.document.body).append('<p>hi</p>');
If you need the code to run after the new window's DOM is ready try:
var OpenWindow = window.open('mypage.html','_blank','width=335,height=330,resizable=1');
$(OpenWindow.document.body).ready(function() {
$(OpenWindow.document.body).append('<p>hi</p>');
});
If you want to open a page or window with sending data POST or GET method you can use a code like this:
$.ajax({
type: "get", // or post method, your choice
url: yourFileForInclude.php, // any url in same origin
data: data, // data if you need send some data to page
success: function(msg){
console.log(msg); // for checking
window.open('about:blank').document.body.innerHTML = msg;
}
});
it is even more simple!
Just put the code below in between the <head> </head> of your code and all of your links will open in a new window:
<base target="_blank">

Categories

Resources