Is there a reliable way to access the client machine's clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use Flash?
My primary target is IE8, but would like to support FF and Chrome also.
I have seen the technique to do this using Flash, but am looking for a pure js route:
Clipboard access using Flash
Since this is a big security risk, all browsers that care about safety don't allow JS to access the clipboard.
The main reason is that many people put their passwords into a text file and then use cut&paste to login. Crackers could then collect the password (and possibly other private information like the word document which you just copied) from the clipboard by cracking a popular site and installing some JS that sends them the content of the clipboard.
Which is why I have flash disabled all the time.
No, not in FF and Chrome. It works in IE (not sure about 7 and 8, but definitively 6), and from Flash. That is why Flash is always used.
Forget pure JS.
There is no standard API for accessing the clipboard, and few browsers implement a propriety method.
Flash is the 'standard' method.
You're looking for the execCommand function, at least the best I can tell. Here are some resources:
Insert text in Javascript contenteditable div
http://www.java2s.com/Code/JavaScriptReference/Javascript-Methods/execCommandisappliedto.htm
Unfortunately, this runs into the same security loophole that Flash sealed in Flash 9. Since people were spamming the clipboard, the clipboard is now only accessible through direct user interaction, and honestly, it is better that way. And I'll wager that most browsers have similar (if not stricter policies).
In IE, to do this is pretty painless. For Firefox, you need to update users.js and/or prefs.js (you can google for Clipboard access in Firefox). For Chrome, you need to write an extension.
In you extension background_page, have a place holder (an IFrame)
in your webpage, have buttons or links like 'cut', 'copy' and 'paste'. also have a hidden iframe paste_holder on your page to get back the text read by the background_page of your extension. In your extension's manifest file, have code like below:
manifest.json
"background_page": "mypaste_helper.html",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["mypaste_helper.js"],
"all_frames": true
}
],
"permissions": [
"clipboardRead",
"clipboardWrite",
"tabs"
]
mypaste_helper.js
get references to your cut, copy and copy buttons on the page
cutButton.addEventListener("click", function()
{
get selected content using window.getSelection()
pass that text to handleCut function in mypaste_helper.html
}, false);
copyButton.addEventListener("click", function()
{
get selected content using window.getSelection()
pass that text to handleCopy function in mypaste_helper.html
}, false);
pasteButton.addEventListener("click", function()
{
get content from handlePaste function in mypaste_helper.html
}, false);
in the callback function
get the contents sent by background_page function
set innerHTML of paste_holder frame's document.body with received text.
mypaste_helper.html
handleCopy and handleCut are identical
get reference to your iframe document.body as clipboardholder
set innerHTML of the clipboardholder.contentDocument.body with the data passed by mypaste_helper.js
capture selection through window.getSelection()
selection.selectAllChildren(clipboardholder);
document.execCommand('copy')
read contents of the clipboardholder
pass the text back to callback in mypaste_helper.js
handlePaste
get reference to your iframe document.body as clipboardholder
you may want to clear the contents of clipboardholder.contentDocument.body
capture selection through window.getSelection()
selection.selectAllChildren(clipboardholder);
document.execCommand('paste')
read contents of the clipboardholder
pass the text back to callback in mypaste_helper.js
http://www.rodsdot.com/ee/cross_browser_clipboard_copy_with_pop_over_message.asp implements the ZeroClipboard flash object correctly and is cross browser. It also discusses the potential problems with ZeroClipboard and possible work-arounds. Also compatible with Flash 10+.
Here's a pure JS implementation that lets you paste image data which works in Google Chrome: http://strd6.com/2011/09/html5-javascript-pasting-image-data-in-chrome/
It was clear this issue, but I still have doubts because there is the option to do this in javascript and another thing is for windows forms it is totally possible to do using the command
Clipboard.Clear()
Ref: System.Windows.Forms
Any malicious software that can do well.
Related
chrome.tabs returns undefined despite the fact I set tabs in the permissions block.
"permissions": [
"tabs",
"http://*/*",
"https://*/*"
],
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"js/myScript.js"
],
"all_frames": true
}
],
But in myScript.js the following returns undefined.
chrome.tabs
As content script has its own limitations,
chrome.tabs is only available in background scripts and popup scripts.
If you wanna to use chrome.tabs then pass message from content_script to background script and play with chrome.tabs.
Content scripts have only limited access to Chrome APIs. This access does not include the API you are trying to use (e.g. chrome.tabs). If you need to use that API, you will have to do so in a background script1.
As listed in Chrome's content scripts documentation, the APIs available to a content script are [I have placed deprecated methods in strikethrough format]:
extension ( getURL , inIncognitoContext , lastError , onRequest , sendRequest )
i18n
runtime ( connect , getManifest , getURL , id , onConnect , onMessage , sendMessage )
storage
A couple of the listed APIs are deprecated and have been for some time. Those that are deprecated have moved to different locations (also listed above):
extension.onRequest ➞ runtime.onMessage
extension.sendRequest ➞ runtime.sendMessage
While not officially deprecated, extension.lastError is also available as runtime.lastError. At this point, it is usually referred to at that location:
extension.lastError ➞ runtime.lastError
Partition your extension into background scripts and content scripts
You are going to need to separate your code into what needs to be in a background script and what needs to be in content scripts, based on the capabilities available to each type of script. Content scripts have access to the DOM of the web page into which they are injected, but limited access to extension APIs. Background scripts have full access to the extension APIs, but no access to web page content. You should read the Chrome extension overview, and the pages linked from there, to get a feel for what functionality should be located in which type of script.
It is common to need to communicate between your content scripts and background scripts. To do so you can use message passing. This allows you to communicate information between the two scripts to accomplish things which are not possible using only one type of script.
For instance, in your content script, you may need information which is only available from one of the other Chrome APIs, or you need something to happen which can most appropriately (or only) be done through one of the other Chrome extension APIs. In these cases, you will need to send a message to your background script, using chrome.runtime.sendMessage(), to tell it what needs to be done, while providing enough informaiton for it to be able to do so. Your background script can then return the desired information, if any, to your content script. Alternately, you will have times when the processing will primarily be done in the background script. The background script may inject a content script, or just message an already injected script, to obtain information from a page, or make changes to the web page.
Background script means any script that is in the background context. In addition to actual background scripts, this includes popups and options pages, etc. However, the only page that you can be sure to have consistently available to receive messages from a content script are your actual background scripts defined in manifest.json. Other pages may be available at some times as a result of the user's interaction with the browser, but they are not available consistently.
This answer was moved from a duplicate question, and then modified.
https://developer.chrome.com/extensions/tabs#method-getSelected shows
getSelected
chrome.tabs.getSelected(integer windowId, function
callback)
Deprecated since Chrome 33. Please use tabs.query {active: true}.
Gets the tab that is selected in the specified window.
Maybe, you should use chrome.tabs.query in popup.js like this
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
console.log(tabs[0].url);
});
, reload your extension and check the result in the inspect element of your extension.
result image
code image
https://developer.chrome.com/extensions/tabs#type-Tab shows that
The URL the tab is displaying. This property is only present if the extension's manifest includes the "tabs" permission.(Just for remind someone forgot. I was forgot it when I just test it.)
Check this answer also https://stackoverflow.com/a/6718277/449345
This one worked for me
chrome.tabs.getSelected(null, function(tab){
console.log(tab);
});
For my JavaScript project I need to detect if the clipboard is reachable. Because in Firefox you need to configure an access for every site which needs it, otherwise some functions (like the execCommand with cut, copy or paste attribute) can't be executed and I need to know that.
You could try saving something into the clipboard. If it fails, you know it is not accessible.
try
{
// Use some library to save some data into the clipboard.
}
catch (ex)
{
alert("Your browser seems to block access to the clipboard.");
}
Access to the clipboard is disallowed in Chrome and Firefox per default. With pure javascript it can't be done in other browsers than Internet Explorer. You will need a Flash-shim.
You can find an article about how to achieve that crossbrowser-compatibly here.
A good library for this is Zeroclipboard.
I work on a javascript library that customers include on their site to embed a UI widget. I want a way to test dev versions of the library live on the customer's site without requiring them to make any changes to their code. This would make it easy to debug issues and test new versions.
To do this I need to change the script include to point to my dev server, and then override the load() method that's called in the page to add an extra parameter to tell it what server to point to when making remote calls.
It looks like I can add JS to the page using a chrome extension, but I don't see any way to modify the page before it's loaded. Is there something I'm missing, or are chrome extensions not allowed to do this kind of thing?
I've done a fair amount of Chrome extension development, and I don't think there's any way to edit a page source before it's rendered by the browser. The two closest options are:
Content scripts allow you to toss in extra JavaScript and CSS files. You might be able to use these scripts to rewrite existing script tags in the page, but I'm not sure it would work out, since any script tags visible to your script through the DOM are already loaded or are being loaded.
WebRequest allows you to hijack HTTP requests, so you could have an extension reroute a request for library.js to library_dev.js.
Assuming your site is www.mysite.com and you keep your scripts in the /js directory:
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if( details.url == "http://www.mysite.com/js/library.js" )
return {redirectUrl: "http://www.mysite.com/js/library_dev.js" };
},
{urls: ["*://www.mysite.com/*.js"]},
["blocking"]);
The HTML source will look the same, but the document pulled in by <script src="library.js"></script> will now be a different file. This should achieve what you want.
Here's a way to modify content before it is loaded on the page using the WebRequest API. This requires the content to be loaded into a string variable before the onBeforeRequest listener returns. This example is for javascript, but it should work equally well for other types of content.
chrome.webRequest.onBeforeRequest.addListener(
function (details) {
var javascriptCode = loadSynchronously(details.url);
// modify javascriptCode here
return { redirectUrl: "data:text/javascript,"
+ encodeURIComponent(javascriptCode) };
},
{ urls: ["*://*.example.com/*.js"] },
["blocking"]);
loadSynchronously() can be implemented with a regular XMLHttpRequest. Synchronous loading will block the event loop and is deprecated in XMLHttpRequest, but it is unfortunately hard to avoid with this solution.
You might be interested in the hooks available in the Opera browser. Opera used to have* very powerful hooks, available both to User JavaScript files (single-file things, very easy to write and deploy) and Extensions. Some of these are:
BeforeExternalScript:
This event is fired when a script element with a src attribute is encountered. You may examine the element, including its src attribute, change it, add more specific event listeners to it, or cancel its loading altogether.
One nice trick is to cancel its loading, load the external script in an AJAX call, perform text replacement on it, and then re-inject it into the webpage as a script tag, or using eval.
window.opera.defineMagicVariable:
This method can be used by User JavaScripts to override global variables defined by regular scripts. Any reference to the global name being overridden will call the provided getter and setter functions.
window.opera.defineMagicFunction:
This method can be used by User JavaScripts to override global functions defined by regular scripts. Any invocation of the global name being overridden will call the provided implementation.
*: Opera recently switched over to the Webkit engine, and it seems they have removed some of these hooks. You can still find Opera 12 for download on their website, though.
I had an idea, but I didn't try it, but it worked in theory.
Run content_script that was executed before the document was loaded, and register a ServiceWorker to replace page's requested file content in real time. (ServiceWorker can intercept all requests in the page, including those initiated directly through the dom)
Chrome extension (manifest v3) allow us to add rules for declarativeNetRequest:
chrome.declarativeNetRequest.updateDynamicRules({
addRules: [
{
"id": 1002,
"priority": 1,
"action": {
"type": "redirect",
"redirect": {
"url": "https://example.com/script.js"
}
},
"condition": {
"urlFilter": 'https://www.replaceme.com/js/some_script_to_replace.js',
"resourceTypes": [
'csp_report',
'font',
'image',
'main_frame',
'media',
'object',
'other',
'ping',
'script',
'stylesheet',
'sub_frame',
'webbundle',
'websocket',
'webtransport',
'xmlhttprequest'
]
}
},
],
removeRuleIds: [1002]
});
and debug it by adding listener:
chrome.declarativeNetRequest.onRuleMatchedDebug.addListener(
c => console.log('onRuleMatchedDebug', c)
)
It's not a Chrome extension, but Fiddler can change the script to point to your development server (see this answer for setup instructions from the author of Fiddler). Also, with Fiddler you can setup a search and replace to add that extra parameter that you need.
Is it possible to download the entire HTML of a webpage using JavaScript given the URL? What I want to do is to develop a Firefox add-on to download the content of all the links found in the source of current page of browser.
update: the URLs reside in the same domain
It should be possible to do using jQuery ajax. Javascript in a Firefox extension is not subject to the cross-origin restriction. Here are some tips for using jQuery in a Firefox extension:
Add the jQuery library to your extension's chrome/content/ directory.
Load jQuery in the window load event callback rather than including it in your browser overlay XUL. Otherwise it can cause conflicts (e.g. clobbers a user's customized toolbar).
(function(loader){
loader.loadSubScript("chrome://ryebox/content/jquery-1.6.2.min.js"); })
(Components.classes["#mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader));
Use "jQuery" instead of "$". I experienced weird behavior when using $ instead of jQuery (a conflict of some kind I suppose)
Use jQuery(content.document) instead of jQuery(document) to access a page's DOM. In a Firefox extension "document" refers to the browser's XUL whereas "content.document" refers to the page's DOM.
I wrote a Firefox extension for getting bookmarks from my friend's bookmark site. It uses jQuery to fetch my bookmarks in a JSON response from his service, then creates a menu of those bookmarks so that I can easily access them. You can browse the source at https://github.com/erturne/ryebox
You can do XmlHttpRequests (XHR`s) if the combination scheme://domain:port is the same for the page hosting the JavaScript that should fetch the HTML.
Many JS-frameworks gives you easy XHR-support, Jquery, Dojo, etc. Example using DOJO:
function getText() {
dojo.xhrGet({
url: "test/someHtml.html",
load: function(response, ioArgs){
//The repsone is the HTML
return response;
},
error: function(response, ioArgs){
return response;
},
handleAs: "text"
});
}
If you prefer writing your own XMLHttpRequest-handler, take a look here: http://www.w3schools.com/xml/xml_http.asp
For JavaScript in general, the short answer is no, not unless all pages are within the same domain. JavaScript is limited by the same-origin policy, so for security reasons, you cannot do cross-domain requests like that.
However, as pointed out by Max and erturne in the comments, when JavaScript is written as part of an extension/add-on to the browser, the regular rules about same origin policy and cross-domain requests does not seem to apply - at least not for Firefox and Chrome. Therefor, using JavaScript to download the pages should be possible using a XMLHttpRequest, or using some of the wrapper methods included in your favorite JS-library.
If you like me prefer jQuery, you can have a look at jQuery's .load() method, that loads HTML from a given resource, and inject it into an element that you specify.
Edit:
Made some updates to my answer based on the comments about cross-domain requests made by add-ons.
if you only write a text web page downloader with your mind,and you only know html and javascript, you can write a downloader name "download.hta" with html and javascript to control Msxml2.ServerXMLHTTP.6.0 and FSO
My Google Chome extension makes use of a content script declared in its manifest via:
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/jquery-1.6.1.min.js", "js/content.js"]
}
],
It also comes with a localization-related resource bundle in _locales/en.
Looking up a key using chrome.i18n.getMessage(...) works flawlessly from general extension code (i.e., in options.html), but it fails (i.e., does not return anything) when executed from js/content.js while that script is being run in the context of the regular web page.
Is this a general limitation (this Chrome bug may be related) or did someone manage to get this working?
You should be able to use chrome.i18n.getMessage(...) from content scripts. Try restarting the whole browser.
Currently running: Version 24.0.1297.0 dev-m
I was hit by this as well. I'm not sure about the original poster's scenario, but my problems were caused by the bug (http://code.google.com/p/chromium/issues/detail?id=53628), which was referenced in a reply in Thilo's bug report. The bug is that the reloading of messages.json is unreliable when reloading your extension from the Extensions manager page. I originally started with an empty messages.json and then added to it as I tried to make use of chrome.i18n.getMessage. I too received no errors, but didn't get my message as expected. As illogical as it sounds and being new to development in general, I thought this might be one of those APIs that can't run from content scripts. Luckily that wasn't the case.
I would say a bug report needs to be created.
It doesn't say anywhere that it is supposed to work, but it doesn't throw an error that chrome.i18n.getMessage isn't accessible from a content scripts either, as all other API calls do. So that's a bug already.
It would be a nice feature to have. I think they started implementing it but either forget or left it for better times. A bug report would be a good reminder.
Meanwhile, you can get localization strings from a background page through messaging. Perhaps send one request at the beginning of a content script requesting an array of all strings you will need.
The strings only get loaded once, when activating the extension.
When the function returns "" this just means, that the index wasn't found.
One just needs to go to "Chrome Extensions" disable and re-enable the extension.
Then the function returns the localized strings - just as expected # Chromium 31.