I have coded a browser helper object in C# for IE, and would like to wrap up that code to implement a chrome/firefox extension. My research led me to Firebreath. I am now loading a content_script file which will fire an onSubmit event and send a message to backgound.htm,js files which handles my firebreath plugin. However, sure enough, m_host now points to the background htm file rather than the original website (from which the user pressed submit button). I tried replacing the html code form the native plugin, but it is not working..
test setup:
content_script:
document.addEventListener('DOMContentLoaded', function () {
alert(document.forms.length);
for (var i = 0; i < document.forms.length; i++) {
document.forms[i].addEventListener("submit", function () {
var documentHTML = "<html>" + document.documentElement.innerHTML + "</html>";
chrome.runtime.sendMessage({ inputElement: documentHTML }, function (response) { }); }); } });
background.js:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
document.getElementById('plugin0').sethtml(request.inputElement); });
firebreath code:
void coolnewtestpluginAPI::setInnerHTML(const FB::variant& innerHTML)
{
m_host->getDOMDocument()->setInnerHTML(innerHTML.convert_cast<std::string>());
}
The native plugin is being called, and I can debug through it. "setInnerHTML()" returns successfully without any errors, but the html code is not being updated, and refers to the original background.htm file. Any ideas?
PS: I'm not that fluent in javascript, so I'd rather offload as much as possible to c# / c++
The only way to put an NPAPI/FireBreath plugin into the actual page is to inject the object tag into that page using javascript from the extension. Otherwise the plugin will know nothing about that page.
Related
I am very new to programming and I am trying to make a Chrome extension that searches for a given string of text on the webpage where the extension is loaded and do some stuff.
In my popup.js file I tried with a function like this:
function findtext() {
if (document.body.innerHTML.search("String I am looking for") != -1) {
//do stuff
} else {
alert("Nope");
}
}
However, when I launch my extension from a page that clearly includes the text "String I am looking for", I get the control alert "Nope".
I don't really understand why this does not work.
UPDATE: I kind of solved this through a code.js file injection, as shown here.
I'm new to Chrome extensions. I know there's lots of similar questions and info out there, but none of it seems to address this problem.
I need my content script to execute on every page that matches *://*.youtube.com/watch?v=*.
I've tried using the above value and *://*.youtube.com/* as the match property, but neither works supposedly due to the way YouTube handles requests. I've also tried using the onhashchange event, but of course YouTube doesn't use anchors in their URLs. I've read about webRequest, but I don't need the function to be called when somebody is scrolling through the comments and the page loads more comments.
All I need is a way to call my content script when the URL changes. How exactly can I accomplish this?
Additionally, I cannot load the content script at document_start because the extension scrapes the HTML and parses it.
I had the same issue and this is what I did. I added a background script to listen to all changes
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.url) {
chrome.tabs.sendMessage(tabId, {
message: 'hello',
url: changeInfo.url
});
}
});
Then in my content script, I listen to it and reload the URL
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === 'hello') {
const { url } = request;
chrome.location.replace(url);
}
});
I am trying to inject a javascript namespace with function from App to Android WebView
NOTE: I do not have any control on the actual source being loaded on WebView apart from the below script. I am working in Xamarin so the Android code is C#
So there are two major components that I am using:
(function() {
console.log("Loading JS Bindings");
function addOnClickHandler () {
$(document).ready(function () {
if (window.InjectedNamespace) { // check InjectedNamespace namespace exists
var onClickHandler = window.InjectedNamespace.handleOnClick;
if (typeof onClickHandler === 'function') {
$(":button, a").each(function (idx) {
$(this).click(function() {
onClickHandler("click!");
});
});
} else {
console.error('missing onclick handler');
}
} else {
console.error('missing InjectedNamespace namespace');
}
});
}
})();
Above script which will be added by the third-party, which will attach click function to all <button> and <a> tags.
Below namespace will be injected from the App side
var InjectedNamespace={handleOnClick:function(a){Internal.handleOnClickEvent(a)}};
On App side I have this Javascript interface object
class JSInterfaceObject : Java.Lang.Object
{
readonly CustomWebView View;
string Data;
public JSInterfaceObject(CustomWebView view)
{
View = view;
}
[Export]
[JavascriptInterface]
// only methods exposed with annotation [JavascriptInterface] are exposed to javascript
public void handleOnClickEvent(string data)
{
Log.ForContext("TAG", TAG).Debug("handleOnClickEvent: " + data);
if(View.OnClick != null)
{
View.OnClick(data);
}
}
}
And this interface is added to webview using
AddJavascriptInterface(new JSInterfaceObject(this), "Internal");
And in OnPageStarted I am injecting the javascript using
webview.LoadUrl("javascript:"+"var IM={handleOnClick:function(a){Internal.handleOnClickEvent(a)}};");
This setup work fine for Android SDK < 24. But for Webview in SDK >=24 the script always errors out with missing InjectedNamespace namespace, which implies the LoadUrl in OnPageStarted failed!
This check is done in $(document).ready in the script.
I found this note in "Android 7.0 for Developers" which says
"Starting with apps targeting Android 7.0, the Javascript context will
be reset when a new page is loaded. Currently, the context is carried
over for the first page loaded in a new WebView instance.
Developers looking to inject Javascript into the WebView should
execute the script after the page has started to load."
So tried to add the javascript injection code after the page started loading but got the same error. Also tried using the WebView.EvaluateJavascript() but error persists.
The error disappers if I change my TargetSDK to <=23.
I would like to be able to edit and save text files in javascript, like the code below, but I have to be able to do it without using system.io, as this is a chrome app. Is there any way to be able to do this?
import System.IO;
var filePath = "data.txt";
function Start() {
if (!File.Exists(filePath)) {
CreateFile();
}
}
function CreateFile() {
var sw: StreamWriter = new StreamWriter(filePath);
sw.WriteLine("Hello World")
sw.Flush();
sw.Close();
print("Done");
}
While you are creating a chrome app, you can use chrome.fileSystem.
This snippet comes from the chrome app samples:
https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples/text-editor
function openFile() {
chrome.fileSystem.chooseEntry(function (entry) {
if (chrome.runtime.lastError) {
showError(chrome.runtime.lastError.message);
return;
}
clearError();
setEntry(entry, false);
replaceDocContentsFromFileEntry();
});
}
For security reasons, JavaScript has no access to local files. It can only access the HTML document. To access external files, such as text files, you must use VBScript. Note that VBScript only works on IE and Edge browsers, and only when they are enabled in the browser's settings.
(I have already read this and it didn't work, and I've done a lot of searching and experimentation to no avail.)
I am writing a Chrome extension (BigConsole) with the goal of building a better Console tab for the Chrome developer tools. This means I would like to execute user-input code in the context of the page with access to the DOM and other variables on the page. To do this, the communication is structured as follows:
devtools creates a panel where the user writes code
When the user wants to execute code from the panel, the panel sends a message to a background script with the code
The background script receives the message/code from panel and passes it on to the content script which is injected into the page
The content script receives the message/code from the background script and injects a script element into the page which then runs the code
The result of the script on the page is then posted back to the content script with window.postMessage
The content script listens for the message/result from the page and passes it on to the background script
The background script receives the message/result from the content script and passes it on to the panel
The panel receives the message/result from the background script and inserts it into the log of results
Whew.
Right now, when the user tries to run the code, nothing happens. I put a bunch of console.log()s into the code but nothing appears in the console. My main question is, what have I done wrong here with the message passing that results in nothing happening? Alternatively, I would love to be told that I am making this way too complicated and there is a better way of doing things. Simplified code below...
panel.js:
window.onload = function() {
var port = chrome.runtime.connect({name: "Eval in context"});
// Add the eval'd response to the console when the background page sends it back
port.onMessage.addListener(function (msg) {
addToConsole(msg, false);
});
document.getElementById('run').addEventListener('click', function() {
var s = document.getElementById('console').value;
try {
// Ask the background page to ask the content script to inject a script
// into the DOM that can finally eval `s` in the right context.
port.postMessage(s);
// Outputting `s` to the log in the panel works here,
// but console.log() does nothing, and I can't observe any
// results of port.postMessage
}
catch(e) {}
});
};
background.js:
chrome.runtime.onConnect.addListener(function (port) {
// Listen for message from the panel and pass it on to the content
port.onMessage.addListener(function (message) {
// Request a tab for sending needed information
chrome.tabs.query({'active': true,'currentWindow': true}, function (tabs) {
// Send message to content script
if (tab) {
chrome.tabs.sendMessage(tabs[0].id, message);
}
});
});
// Post back to Devtools from content
chrome.runtime.onMessage.addListener(function (message, sender) {
port.postMessage(message);
});
});
content.js:
// Listen for the content to eval from the panel via the background page
chrome.runtime.onMessage.addListener(function (message, sender) {
executeScriptInPageContext(message);
});
function executeScriptInPageContext(m) { alert(m); }
As pointed out by Alex, here's a typo in your code which prevents it from working.
Drop your current code and use chrome.devtools.inspectedWindow.eval to directly run the code and parse the results. This simplifies your complicated logic to:
devtools creates a panel where the user writes code
devtools runs code
devtools handles result
PS. There is a way to manipulate the existing console, but I recommend against using it, unless it's for personal use. Two different ways to do this are shown in this answer.