I'm currently writing a Chrome Extension that takes user selected data and passes it to another window. Aside from the manifest.json files, I have a background.js and index.php file.
The background.js file successfully grabs the user selected data, opens a new broswer window, and then passes the user selected data to the index.php file located on a server via $_GET. This works great until you exceed a certain character limit in which case you get an error saying the url is too long. I was wondering if there was anyway to send the data from the background.js file to the new window using $_POST or any other method that would allow larger data selections? Or could I just pass the user selected data to the new window first, and then have that window access the server?
background.js
function getClickHandler() {
return function(info, tab) {
var tx = info.selectionText;
tx = encodeURIComponent(tx);
// Create a new window to the info page.
var url = 'http://192.168.0.22?tx=' + tx;
chrome.windows.create({url: url, width: 500, height: 760 });
};
};
chrome.contextMenus.create({
"title" : "Store",
"type" : "normal",
"contexts" : ["selection"],
"onclick" : getClickHandler()
});
index.php
<?php
$text = $_GET['tx'];
print ($text);
?>
Potentially you could create a form dynamically and then set an input to the value you're trying to send as a query-string-parameter.
Something like:
var $form = $('<form action="' + url + '" method="POST" target="_blank" />'),
$input = $('<input name="tx" type="text" />').val(tx);
$form.append($input).trigger("submit");
Without running the code I'm not sure if the submit will function without adding the form to the DOM, if not then you'll need to append the form to the DOM and then trigger submit, after which you probably want to remove the form from the DOM.
I say potentially because I'm not familiar with writing Chrome Extensions but I've done this as part of a normal web-app before and it worked.
Related
Let say I have a database with several products. I'm making a page to create printable export of that database. On the page the user can setup the export depending on his needs. For example, choosing what categories of products he want to exclude from it, how he want it to be sorted and so on.
He then click on a button making an ajax call with the chosen settings to a php script making the sql request and everything.
From there I would like to generate a temporary html page to visualize the result and open it in a new tab to be printed. But once it is done, I don't need it anymore. I could write the html file from my php script and make my ajax call to open the new file on another tab but that would create a new file everytime and take a lot of space.
What is the best way to achieve that ? The main problem is that my php script result in a very long string that can't be send in the url. tmpfile() don't allow me to open the created file in a new tab as it is deleted at the end of the script.
I tried using tempnam() like this :
$tmpfname = tempnam("../tmp/",$_SESSION['loggedUser']);
$handle = fopen($tmpfname, "w");
fwrite($handle, "long string being my html code");
fclose($handle);
$success = true;
$return_arr = array($success,$tmpfname);
And my ajax call :
$.post('../php/export_script.php',{:settings},function(data){
response = JSON.parse(data);
if (response[0] == true) {
var win = window.open('../landing.php?file='+response[1], '_blank');
if (win) {
win.focus();
} else {
alert("Browser blocked the opening of the file.");
}
}else{
alert(response[1]);
}
});
So that open the landing.php page that is like so :
<div id="content">
<?php
$handle = $_GET['handle'];
$fileData = #file_get_contents($handle);
echo $fileData
?>
</div>
But that open the new tab with the clear path of the file in the url like this
"https://mywebsite.com/landing.php?file=/home/myserver/myproject/tmp/userV4rIkE"
That looks unsafe to me, showing some clear server infos to the user. Is there a better way to achieve this ? I though about just creating a normal file in my tmp folder generating a random name with timestamp + user session code and setting up a way for my server to empty that folder every once in a while.
In the parent page, you can use javascript to create a new page, which gives you a way to write data into that new page - so just write the HTML from the parent into the new page. It does not need any URL at all (about:blank) should work fine.
const handle = window.open();
if (handle) {
// write HTML to child.
}
I wrote an chrome extension, which saves user input to the local storage via chrome.storage.sync.set/get... and sends this data via chrome.tabs.sendMessage to a content script, which listens via chrome.runtime.onMessage.addListener. This whole load and send process is triggered, when the user opens the extension per mouse click and presses a button. Before this happens the content script has not the needed data to do its task and is waiting.
Concrete requirements / questions:
I want, that the local storage data gets loaded (and sent to the content script) automatically on every page load without any user interaction needed.
Which callback do I have to implement or where do I have to put my code in order to achieve this?
The whole code looks like this (Tag and Pass are the mentioned user data):
function clickHandler(e) {
var tag = document.getElementById(DOM_TAG).value, pass = document.getElementById(DOM_PASS).value;
// ...query for the active tab...
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {
from: 'popup',
subject: 'init',
tag: tag,
pass: pass
});
});
// Save data to local storage.
chrome.storage.sync.set({DOM_TAG: tag, DOM_PASS: pass}, function() {
// Notify that we saved.
});
}
// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function() {
// Load data from local storage.
chrome.storage.sync.get({DOM_TAG: 'defaultTag', DOM_PASS: 'defaultPass'}, function(items) {
document.getElementById(DOM_TAG).value = items.DOM_TAG;
document.getElementById(DOM_PASS).value = items.DOM_PASS;
});
document.querySelector('button').addEventListener('click', clickHandler);
});
What I already tried:
Of course I tried to start the process inside the callback function for DOMContentLoaded, but that is not working since this event only gets fired when the user manually opens the extensions by clicking on it. Thats not what I want.
I also tried to put the specific lines of code into a BackgroundScript, with no success.
You do not need to pass data from extension to content script. You can access it directly in content script. i.e: chrome.storage.local and chrome.storage.sync are available to content scripts.
Your extension's content scripts can directly access user data without the need for a background page.
storage docs
I want to open webpage and automatically fill in login information. My main.js addon code is given below. I have uname and upass variable. I want to fill in the login form using those when addon opens the tab.
var uname="username";
var upass="password";
tabs.open({
url: "https://www.facebook.com",
onReady:runScript
});
function runScript(tab) {
tab.attach({
contentScriptFile: data.url("mody.js")
});
I put this code in my mody.js file:
document.getElementById("email").value=uname; // uname undefined
document.getElementById("pass").value=upass; // upass undefined
But I can't access these variables from mody.js. Is there any way to pass this variable to the login page?
Use the contentScriptOptions for this.
The contentScriptOptions is a JSON object that is exposed to content
scripts as a read-only value under the self.options property:
For current non-IE browsers (Chrome, Firefox, Opera, Safari), I would like to send a PDF document to the printer given a URL to that PDF.
To avoid superfluous windows popping up, I am presently doing this with an <iframe> but I would like to close the iframe after the printing is completed, otherwise some browsers will pop up a dialog when one tries to leave the page.
Here is what I have come up with so far (using lodash and jQuery for simplicity):
var _print_url, _remove_iframe, _set_print;
_print_url = function(src_url) {
$("<iframe src='" + src_url + "' type='application/pdf'>").css({
visibility: 'hidden',
position: 'fixed',
right: '0',
bottom: '0'
}).on('load', _set_print).appendTo(document.body);
};
_remove_iframe = function(iframe) {
return $(iframe).parent().find(iframe).detach();
};
_set_print = function() {
this.contentWindow.print();
/*
* Where we could do #contentWindow.close() with a window, we must remove the
* print iframe from the DOM. We have to engage in some async madness
* it seems, for no apparent reason other than this won't work
* synchronously (#cw.print above must be async, it seems) - even though
* window.close() appears to work synchronously.
*/
_.delay(_.partial(_remove_iframe, this), 100);
};
Sometimes it seems with Google Chrome the print-dialog ends up showing the PDF correctly, but when one selects the printer and confirms the intention to print it will actually send the contents of the frame's parent page to the printer instead of the PDF itself.
There is a link suggestions on the Mozilla page but this document seems obsolete at the moment. The best example I could find was by reverse-engineering the Amazon Web Services print dialog for invoices, but that opens a window.
One alternative I have considered is Google Cloud Print, but obviously this requires the installation of extra software or configuration of a Google Account, neither of which I would wish to impose on users unless necessary.
Are there other examples of how one might print a PDF given a URL, particularly with Javascript and without otherwise superfluous additional browser add-ons or artefacts such as windows popping up?
-- NOTE whit this approach you will never see the popup blocker --
I run in a similar problem wiht an ajax application a couple month ago, the problem was I faced was I need to create the pdf file and store before to send it to print, what I did is the following:
I didnt use iframes. This application works with php TCPDF for creating the pdf and jquery and underscore for the templating system.
you can see the demo video at http://www.screenr.com/Ur07 (2:18 min)
Send the information via JSON (ajax) To achieve this because I faced the problem that everything was in ajax, so I couldn't make post with the information, so what I did is to append a hidden form to the DOM and then with the target="_blank" make the post to a new window (which you will close a the end of the process).
HTML hidden virtual form
<form method='<%= method %>'
action="<%= action %>"
name="<%= name %>"
id="<%= id %>"
target="_blank">
<input type='hidden' name='json' id='<%= valueId %>' />
</form>
Javascript
function makePost(){
var _t = _.template(_JS_Templates["print.form.hidden"]); //this the html of the form
var o = {
method : "POST",
action : js_WEB_ + "/print.php",
name : "print_virtual_form",
id : "print_virtual_form_id",
valueId : "print_virtual_value"
}
var form = _t(o);
$(".warp").append(form); //appending the form to the dom
var json = {
data : data // some data
}
$("#print_virtual_value").val(JSON.stringify(json)); //assing to the hidden input the value and stringify the json
$("#print_virtual_form_id").submit(); //make the post submmitting the form
$("#print_virtual_form_id").remove(); //removing the "virtual hidden form"
}
2.- when you receive the json in my case was using php you create whatever you have to create, I did it in this way you can see the php code in this example (is my answer)
Generate PDF using TCPDF on ajax call
3.- And finally in this is where the cool parts come is the response, in this part, I use the php file to write a javascript code saying that have to close the parent windows and report the json answer to an specific function, is kind of callback.
switch($_SERVER['REQUEST_METHOD']){
case "GET":
echo "Denied";
break;
case "POST":
if(isset($_POST["json"])){
if(!empty($_POST["json"])){
$json = $_POST["json"];
$hash = PDF::makePDF($json);
echo "<script>
function init() {
//calling callback
//returning control to the previous browser
window.opener.someclass.finish('".$hash."');
window.close();
}
window.onload = init;
</script>";
}else{
echo "not json detected";
}
}else{
echo "not json detected";
}
break;
4.- and for the end with the control in you window browser you can do.
var someobject = (function(name){
//private
var finish(data){
//do whatever you want with the json data
}
//public
var $r = {};
$r.finish = function(data){
finish(data); //you will pass the data to the finish function and that is..!! voila!!
}
return $r;
})("someobject");
I know is not exactly what you ask but is another approach to the same problem while I think this is little more complex, I can guarantee works in a lot of browser and the users will love the way you do it. They will never see what is happening and they will download the file just how the expect to do it, clicking a link and the saving the file.
Just my two cents and happy coding.
This is similar to: How to open a file using JavaScript?
Goal: to retrieve/open a file on an image's double click
function getFile(filename){
// setting mime this way is for example only
var mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
jQuery.ajax({ url : 'get_file.pl',
data : {filename:filename},
success : function(data){
var win = window.open('','title');
win.document.open(mime);
win.document.write(data);
win.document.close();
}
});
}
jQuery('#imgID').dblclick(function(){
getFile('someFile.docx');
});
I'm doing this off the top of my head, but I think the above would work for text files, but not binary. Is there a plugin that does this properly? The ideal would be to open the file in the browser (or application), rather than download, but I doubt that is a dream. If the file must be downloaded with the save/open dialog, that's fine.
Edit:
One piece of information that I forgot to mention is that I'd like this to be a POST request. This is partly why I was looking at AJAX to begin with. I've seen workarounds that have created forms/iframes to do something similar, but I was looking for a better handler of the returned info.
Seems to me there's no reason to do this via AJAX. Just open the new window to get_file.pl?filename=... and let the browser handle it. If the user has a plugin capable of handling the Content-Type sent by get_file.pl, the file will display; otherwise, it should download like any other file.
function getFile(filename) {
window.open('get_file.pl?filename=' + filename,'title');
}
jQuery('#imgID').dblclick(function() {
getFile('someFile.docx');
});
Edit: If you want to POST to your script, you can do it with some <form> hackery:
function getFile(filename) {
var win = 'w' + Math.floor(Math.random() * 10000000000000);
window.open('', win,'width=250,height=100');
var f = $('<form></form>')
.attr({target: win, method:'post', action: 'get_file.pl'})
.appendTo(document.body);
var i = $('<input>')
.attr({type:'hidden',name:'filename',value:filename})
.appendTo(f);
f[0].submit();
f.remove();
}
Of course, this is somewhat silly since it is impossible to hide your data from "prying eyes" with developer tools. If your filename really is sensitive, issue access tokens to the client, and look up the data in your sever script.