I'm trying to figure out exactly how Content Scripts work.
I'm writing an extension with a context menu that, once the option is clicked, the next click will result in an alert dialog with information about the page the element is on and the id and name of the element clicked.
I think my problem is including the name of the content script file somewhere on my manifest, since I am using executeScript to use it instead of having it injected on every single web page but I cannot figure out where to put it.
Please let me know if I can provide more helpful information.
Here are copies of my manifest, the main script I use and the script that I am trying to insert.
Manifest.json
{
"name": "Omnixx Page Object Builder",
"description": "Finds information about an element clicked, started with a context menu",
"version": "0.3",
"permissions": ["tabs", "contextMenus", "activeTab"],
"background": {
"persistent": false,
"scripts": ["menuBuilder.js"]
},
"manifest_version": 2
}
menuBuilder.js
function onClickHandler(info, tab) {
if (info.menuItemId == "start") {
console.log("Started trying to find elements");
chrome.tabs.executeScript(null, {file:"elementTracker.js"});
console.log("Started listening...");
}
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({"title": "Find element information", "id": "start", "contexts":["all", "page", "frame", "selection", "link", "editable", "image","video", "audio"], });
});
elementTracker.js
function click(event) {
// Begin building the message
var msgToWrite = "";
var curscreen = window.HIDEFRAME.document.getElementsByName("curscreen")[1].value;
msgToWrite += "curscreen: '" + curscreen + "'\n";
var url = content.document.URL;
msgToWrite += "URL: " + url + "\n";
// A try-catch block is necessary for finding the frame; otherwise the code
// will fail for pages without frames
try {
var frame = event.originalTarget.ownerDocument.defaultView.frameElement;
var frameName = frame.getAttribute("name");
if (frameName != null) {
msgToWrite += "Frame: '" + frameName + "'\n";
} else {
msgToWrite += "No frame found\n";
}
} catch (e) {
msgToWrite += "No frame found\n";
}
// Get the element's ID
var elemID = event.target.getAttribute("id");
if (elemID != null) {
msgToWrite += "ID: '" + elemID + "'\n";
} else {
msgToWrite += "No ID found\n";
}
// Get the element's name
var elemName = event.target.getAttribute("name");
if (elemName != null) {
msgToWrite += "Name: '" + elemName + "'";
} else {
msgToWrite += "No name found";
}
// Create a pop-up message
alert(msgToWrite);
}
document.addEventListener('click', click);
What I think is happening is that you're trying to call another event listener at the end of your elementTracker.js file. You don't need that because you're initializing the script from the context menu call.
Change the last line in that script to click(event). The script will be injected to the page from the context menu.
Related
I'm building an extension. When I click on the extension's icon, a UI is being loaded, from which I click a button, and a screenshot is performed.
For now, what's happening is that i'm using html2canvas, and in order to screenshot the current active tab, I need to pass that tab's HTML Source ( for now i'm capturing my own extension's window -_- ).
I was attempting on following the answer [here][1], but without success. That means, I was attempting to retrieve in the content_script.js the current page's HTML, and send it via sendMessage:
function DOMtoString(document_root) {
var html = "",
node = document_root.firstChild;
while (node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
html += node.outerHTML;
break;
case Node.TEXT_NODE:
html += node.nodeValue;
break;
case Node.CDATA_SECTION_NODE:
html += "<![CDATA[" + node.nodeValue + "]]>";
break;
case Node.COMMENT_NODE:
html += "<!--" + node.nodeValue + "-->";
break;
case Node.DOCUMENT_TYPE_NODE:
// (X)HTML documents are identified by public identifiers
html +=
"<!DOCTYPE " +
node.name +
(node.publicId ? ' PUBLIC "' + node.publicId + '"' : "") +
(!node.publicId && node.systemId ? " SYSTEM" : "") +
(node.systemId ? ' "' + node.systemId + '"' : "") +
">\n";
break;
}
node = node.nextSibling;
}
return html;
}
chrome.runtime.sendMessage({
action: "getSource",
source: DOMtoString(document),
});
then, in a file which popup is mounting, I have done the following, in order to attempt and grab that message (important to state - i was also trying the following code in background.js, same result):
chrome.runtime.onMessage.addListener(function (request, sender) {
console.log("IN THE LISTENER backfgroundE - " + message);
if (request.action == "getSource") {
message.innerText = request.source;
}
});
but for some odd reason the message is not even arriving to neither my mounted-by-popup.html file, nor in my background.js file.
Any ideas?
Manifest file:
{
"name": "Chrome plugin for Juno issues report",
"description": "A issues report tool as a Chrome plugin",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_title": "Juno issue report"
},
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "index.html"
},
"icons": {
"16": "juno-icon.png",
"48": "juno-icon.png",
"128": "juno-icon.png"
},
"permissions": ["desktopCapture", "tabs", "downloads", "<all_urls>"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content_script.js"]
}
]
}
I'll just add that the names of the files are aligned with the names mentioned in the manifest file.
Image of my files tree can be seen here:
[![enter image description here][2]][2]
Regards!
[1]: Getting the source HTML of the current page from chrome extension
[2]: https://i.stack.imgur.com/jh3Gf.png
I have written code for a small Chrome Extension that scrapes content based on selectors. Once I have the content I need, I push it to my PHP server in order to store it in a database. The code works well except when content is loaded dynamically, I can only see what is visible the source code from the browser.
I thought I could solve the issue by waiting until the page was fully loaded (setInterval) but even when I see that the content is loaded, the source code I'm getting is still the initial one.
I use the following code to create a tab and retrieve the source code:
function CreateTab (createProperties)
{
chrome.tabs.create(createProperties, tab =>
{
if (chrome.runtime.lastError)
{
console.log(chrome.runtime.lastError);
}
else
{
container = "h2";
var i = 0;
var checkClass = setInterval (function()
{
if (i<=3)
{
console.log('Iteration :'+i);
chrome.tabs.executeScript(tab.id,
{
file: 'GetSource.js',
}, async function(results)
{
let e = chrome.runtime.lastError;
if(e !== undefined)
{
console.log(tab.id, e);
}
// GETTING HTML
parser = new DOMParser();
content = parser.parseFromString(results, "text/html");
console.log(content);
// CAPTURE TITLES
try
{
datatable = content.querySelectorAll(container);
}
catch(err)
{
console.log('Iteration '+i+' table not found');
datatable = "";
}
if (datatable.length>0)
{
clearInterval(checkClass);
removeTab(tab.id,3)
// DATA FOUND!
i=10;
}
});
i++;
}
else
{
clearInterval(checkClass);
console.log('Container not found');
removeTab(tab.id,5)
}
},10000);
}
});
}
The script I'm calling to get the source is the following (GetSource.js)
function DOMtoString(document_root) {
var html = '',
node = document_root.firstChild;
while (node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
html += node.outerHTML;
break;
case Node.TEXT_NODE:
html += node.nodeValue;
break;
case Node.CDATA_SECTION_NODE:
html += '<![CDATA[' + node.nodeValue + ']]>';
break;
case Node.COMMENT_NODE:
html += '<!--' + node.nodeValue + '-->';
break;
case Node.DOCUMENT_TYPE_NODE:
// (X)HTML documents are identified by public identifiers
html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
break;
}
node = node.nextSibling;
}
return html;
}
sourcecode = DOMtoString (document);
sourcecode
How can I make sure that the GetSource.js script is getting the final rendered source code? There are more and more sites using dynamic content loaded after the initial load and with this script I'm stuck on those sites.
There are ready to use scrapers in the Chrome store that can get dynamic content so there must be a solution for my script too. I don't want to use to solutions as I need to retrieve the selectors I want to catch from my server and once the scraping is done pushing them back to the server.
Do you have any idea of how I could achieve this?
Thanks
I have a problem in browser with sent file links:
file:/// instead of file:// and i would like to create a zimlet which is check links in mail and if it is a file link then change file:/// to file:// and start on click.
Or start external program if it is a file link. I created the link reader program but i don't know how to start it or implement to a zimlet.
Do you have any idea?
thanks in advance for any help.
My example for link correction in .net but how it looks like in java ajax:
foreach (string b in args)
{
// Console.WriteLine(b);
if (b.Contains("file:F"))
{
string d = b.Replace(#"file:F", #"F");
System.Diagnostics.Process.Start(d);
}
else if (b.Contains("file:///F:"))
{
string d = b.Replace(#"file:///F:", #"F:");
System.Diagnostics.Process.Start(d);
}
}
Here the string is readed and checked and replaced with good starting chars.
I think it have to work in java too but i am not good in java.
Please Help!
I tried with converter: But it not works:
try
{
for (String b : args)
{
// Console.WriteLine(b);
if (b.contains("file:F"))
{
String d = b.replace("file:F", "F");
System.Diagnostics.Process.Start(d);
}
else if (b.contains("file:///F:"))
{
String d = b.replace("file:///F:", "F:");
System.Diagnostics.Process.Start(d);
}
else
{
System.out.println("File Not Contain Valid File Link!");
System.out.println("Or File Missing!");
Console.ReadKey();
}
// Console.WriteLine(d);
// Console.ReadKey();
// System.Diagnostics.Process.Start(d);
}
}
catch (RuntimeException e)
{
System.out.println("File Not Contain Valid File Link!");
System.out.println("Or File Missing!");
Console.ReadKey();
}
I have a new idea!
How can i run links automatically in new tab?
Like if i click on a link than automatically open new tab and copy url to there and run. It have to be an right-click menu i think. It should work.
UPDATE:
Now i using an example: for right click menu now it is working on click pop up message:
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The onClicked callback function.
function onClickHandler(info, tab) {
if (info.menuItemId == "radio1" || info.menuItemId == "radio2") {
console.log("radio item " + info.menuItemId +
" was clicked (previous checked state was " +
info.wasChecked + ")");
} else if (info.menuItemId == "checkbox1" || info.menuItemId == "checkbox2") {
console.log(JSON.stringify(info));
console.log("checkbox item " + info.menuItemId +
" was clicked, state is now: " + info.checked +
" (previous state was " + info.wasChecked + ")");
} else {
console.log("item " + info.menuItemId + " was clicked");
console.log("info: " + JSON.stringify(info));
console.log("tab: " + JSON.stringify(tab));
}
Pop-up message is here
alert("I am an alert box!");
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
// Set up context menu tree at install time.
chrome.runtime.onInstalled.addListener(function() {
// Create one test item for each context type.
var contexts = ["page","selection","link","editable","image","video",
"audio"];
for (var i = 0; i < contexts.length; i++) {
var context = contexts[i];
var title = "Test '" + context + "' menu item";
var id = chrome.contextMenus.create({"title": title, "contexts":[context],
"id": "context" + context});
console.log("'" + context + "' item:" + id);
}
// Create a parent item and two children.
chrome.contextMenus.create({"title": "Test parent item", "id": "parent"});
chrome.contextMenus.create(
{"title": "Child 1", "parentId": "parent", "id": "child1"});
chrome.contextMenus.create(
{"title": "Child 2", "parentId": "parent", "id": "child2"});
console.log("parent child1 child2");
// Create some radio items.
chrome.contextMenus.create({"title": "Radio 1", "type": "radio",
"id": "radio1"});
chrome.contextMenus.create({"title": "Radio 2", "type": "radio",
"id": "radio2"});
console.log("radio1 radio2");
// Create some checkbox items.
chrome.contextMenus.create(
{"title": "Checkbox1", "type": "checkbox", "id": "checkbox1"});
chrome.contextMenus.create(
{"title": "Checkbox2", "type": "checkbox", "id": "checkbox2"});
console.log("checkbox1 checkbox2");
// Intentionally create an invalid item, to show off error checking in the
// create callback.
console.log("About to try creating an invalid item - an error about " +
"duplicate item child1 should show up");
chrome.contextMenus.create({"title": "Oops", "id": "child1"}, function() {
if (chrome.extension.lastError) {
console.log("Got expected error: " + chrome.extension.lastError.message);
}
});
});
And i created a hta file which is running my exe:
<script type="text/javascript" language="javascript">
var oShell = new ActiveXObject("Shell.Application");
var commandtoRun = "F:\\ABLAGE\\link_reader_ip.exe";
oShell.ShellExecute(commandtoRun,"","","open","1");
</script>
New problems:
1. How to start on click hta file:
function callShellApplication(){
var objShell = new ActiveXObject("WScript.shell");
objShell.Run('"d:\\test.hta"');
}
no error , but the test.hta file wont start.
if the hta run my file it opens an extra window but i wont.
Please someone help me.
im having issue with the below code not showing up with selection is detected on the webpage.
Currently when i am selecting text the context menu is not showing up.
Code
function getword(info,tab) {
if (info.menuItemId == "google") {
console.log("Google" + info.selectionText + " was clicked.");
chrome.tabs.create({
url: "http://www.google.com/search?q=" + info.selectionText,
})
} else {
console.log("Bing" + info.selectionText + " was clicked.");
chrome.tabs.create({
url: "http://www.bing.com/search?q=" + info.selectionText,
})
}
};
chrome.contextMenus.onClicked.addListener(getword);
chrome.runtime.onInstalled.addListener(function() {
var contexts = ["page","selection","link","editable"];
for (var i = 0; i < contexts.length; i++) {
var context = contexts[i];
var title = "Google Search";
var id = chrome.contextMenus.create({"title": title, "contexts":[context],
"id": "google"});
console.log("'" + context + "' item:" + id);
}
chrome.contextMenus.create({"title": "Bing Search", "id": "child1"});
});
The value of the "id" property needs to be unique. You will see the following error if you view the console of your background page:
contextMenus.create: Cannot create item with duplicate id google
at chrome-extension://ghbcieomgcdedebllbpimfgakljlleeb/background.js:23:34
Do not call chrome.contextMenus.create for each context, but assign the list of contexts to the contexts key:
chrome.runtime.onInstalled.addListener(function() {
var contexts = ["page","selection","link","editable"];
var title = "Google Search";
chrome.contextMenus.create({
"title": title,
"contexts": contexts,
"id": "google"
});
// ...
});
I'm new to this so please bear with me. I am trying to write a chrome extension that does the following:
Detect www.website.com/anypage.html. If this website is detected, then do the following.
Don't load the URL.
Instead, write a blank document with a hyperlink to www.website.com/anypage.html?ie=UTF8
The script is set to run at document start (in the manifest).
Here is my code:
Detect URL:
var regExp = /website.com/gi;
var match = 0;
testString = window.location.href.toString();
if(regExp.test(testString) {
match = 1;
Write blank document with link to the URL with the UTF8 encoding tag:
document.write("<a href=" + window.location.href + "?ie=UTF8>Title of Link</a>");
This doesn't work as expected, and just shows a blank page. Anyone have any ideas?
Thanks!
EDIT: Here is the full code:
checklink(); // If there is a match, then checklink will return a 1. If it's already tagged, it will return a 5.
var matchLink = null;
if (checklink() === 1) {
matchLink = window.location.href.toString();
if (checklink() != 1) {
matchLink = null;
function checklink() { //checks to see if the current URL matches website.com
var regExp = /website.com/gi,
testString = window.location.href.toString(),
match = 0,
tagged = 0;
if (regExp.test(testString)) { //if there is a match, returns 1
match = 1;
var regExp2 = /UTF8/gi;
if (regExp2.test(testString)) { //if UTF8 is found, then it returns 5
tagged = 5;
return(match + tagged);
function tagUTF() {
if (matchLink) {
var newLink = matchLink + "?ie=UTF8";
document.write("Link");
if (matchLink) {
tagUTF();
}
The chrome content script has access to the DOM, so you could just replace the contents of the body element of the current page with a new node that has your anchor tag either using dom manipulation methods or innerHTML:
document.body.innerHTML = "<a href=" + window.location.href + "?ie=UTF8>Title of Link</a>";
Please note, this assumes that the JavaScript that is doing the DOM manipulation was properly added for your Chrome extension as a "content script":
http://code.google.com/chrome/extensions/content_scripts.html
EDIT:
Here is the code I used to make it work for me locally:
manifest.json
{
"name": "Test",
"version": "1.0",
"description": "Test",
"permissions": [
"<all_urls>"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"run_at": "document_end"
}
]
}
content-script.js
document.body.innerHTML = "<a href='test'>test</a>";