Google Chrome Extension: How to use an external script - javascript

I am trying to make a markdown preview tab for a forum I often use that uses markdown in it's formatting but currently does not have any way to preview what that markdown will look like.
I want to use the page down markdown converter however I don't know how to use the files inside the content script
here is my manifest.json
{
"name": "Forum Post Previewer",
"version": "0.1",
"manifest_version":2,
"description":"Adds a preview tab on the post editor",
"permissions": [
"activeTab",
"*://*/*"
],
"content_scripts": [
{
"js": ["previewtab.js"]
}
],
}
and here is the previewtab.js
// Adding the preview tab
var tabs = document.getElementsByClassName("nav nav-tabs");
var list = document.createElement("li");
var tab = document.createElement("a");
tab.innerHTML = "Preview";
tab.setAttribute("data-toggle", "tab");
tab.setAttribute("href", "#tab3");
list.appendChild(tab);
document.getElementById("post-editor").parentElement.firstElementChild.appendChild(list);
var content = document.createElement("div");
content.setAttribute("class", "tab-pane");
content.setAttribute("id", "tab3");
var bar = document.createElement("div");
bar.setAttribute("id", "wmd-button-bar");
var textarea = document.createElement("textarea");
textarea.setAttribute("id", "wmd-input");
textarea.setAttribute("class", "wmd-input");
var preview = document.createElement("div");
preview.setAttribute("id", "wmd-preview");
preview.setAttribute("class", "wmd-panel wmd-preview");
content.appendChild(bar);
content.appendChild(textarea);
content.appendChild(preview);
document.getElementById("post-editor").appendChild(content);
// Using the converter
var converter = Markdown.getSanitizingConverter();
var editor = new Markdown.Editor(converter);
editor.run();
right now I get errors when using the converter because it does not know where Markdown has come from.
Can you help me to find out how to use this external script in a chrome extension
Thanks

Just add the .js files to your extension and include them as content scripts before yours, like this:
"content_scripts": [
{
"js": ["Markdown.Converter", "Markdown.Editor", "Markdown.Sanitizer", "previewtab.js"]
}
],

Related

Chrome Extension Content Script - Inject Javascript before page code

I am trying to make a Chrome extension with a content script to inject a script into a webpage before all other scripts in the page. (I am using the xhook library to intercept XHR requests, which overwrites the XHR class. I need to do this because it is currently impossible to modify responses using Chrome extension APIs.) The "document_start" event is executed before any of the DOM is written, so I manually create the body element with the content script. However, this creates 2 body tags in the HTML, which appears to make variables defined within the injected script tag inaccessible to the code in the main page.
How should I do this?
I have simplified version of my code below:
manifest.json
{
// Required
"manifest_version": 2,
"name": "My Extension",
"version": "0.1",
"description": "My Description",
"author": "Me",
"permissions": ["https://example.com/*"],
"content_scripts": [{
"matches": ["https://example.com/*"],
"js": ["xhook.js"],
"run_at": "document_start",
"all_frames": true
}
]
}
xhook.js
var script_tag = document.createElement('script');
script_tag.type = 'text/javascript';
holder = document.createTextNode(`
//Xhook library code
// XHook - v1.4.9 - https://github.com/jpillora/xhook
//...
//Now to use the library
console.log('loading extension');
xhook.after(function (request, response) {
//console.log(request.url);
if (request.url.startsWith("https://example.com/")) {
var urlParams = new URLSearchParams(window.location.search);
fetch('https://example.com/robots.txt')
.then(
function (apiresponse) {
if (apiresponse.status == 200) {
response.text = apiresponse.text();
return;
};
if (apiresponse.status !== 200) {
console.log('File not found. Status Code: ' +
apiresponse.status);
return;
};
});
};
});
xhook.enable();`);
script_tag.appendChild(holder);
document.body = document.createElement("body");
document.head.appendChild(script_tag);
Thanks!
If the extension is loaded at document_start, document.head = null. Hence, to overcome this, do - document.lastChild.appendChild(script_tag);. This creates a script tag in your <html> hierarchy. Hope this helps.
Also, Could you please tell why are you doing the following statement
document.body = document.createElement("body"); I believe this is not required.

Content JavaScript Not Executing in Content Script

My Chrome extension has a Content Script that adds a DIV with a button. The OnClick JS function defined for the button, however, never executes (defined in the same Content Script), so the button does nothing. Why is that?
contentscript.js
var msg = "Click this button <button onclick='test()'>Test</button>";
var div = document.createElement( 'div' );
div.id = 'testDiv';
document.body.appendChild( div );
document.getElementById('testDiv').innerHTML = msg;
function test()
{
alert('in test()'); // Never gets here
}
manifest.json
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"css": ["contentstyle.css"],
"js": ["jquery-1.11.2.min.js", "contentscript.js"]
Look at the official docs regarding policies. Inline javascript is strictly prohibited. The docs explain how to do it. https://developer.chrome.com/extensions/contentSecurityPolicy

Element created by Content script on page creating issue with Gmail,Facebook,stackoverflow etc

I am developing a Chrome extension and my requirement is to create element(button) on page for each tab open and wants to show simple alert message on clicking button..it works properly for all but it always creating issue with Gmail,Facebook and Stackoverflow..please help me to resolve this issue.
I am having the code of adding button to a web page in my Content script.
manifest.json
....
....
"content_scripts": [
{
"matches":["http://*/*", "https://*/*"],
"css": [ "style.css" ],
"js":["contentScript.js"],
"all_frames": false,
"run_at": "document_idle"
}
]
....
....
contentScript.js
....
....
function addButton() {
document.body.innerHTML += '<button id="my_button" class="buttonCss">Show Button</button>';
var button = document.getElementById("my_button");
button.addEventListener("click", function () {
alert("hello");
}, false);
}
.....
.....
....
I think some Gmail security features is creating the issue.
document.body.innerHTML += /* ... */
I think this is your issue right there. It forces Chrome to re-create the entire DOM of body, losing attached events/data.
The proper way would be to construct and append a DOM node:
var button = document.createElement("button");
button.id = "my_button";
button.className = "buttonCss";
button.textContent = "Show Button";
document.body.appendChild(button);

Create sidebar by manipulating the DOM of the loaded webpage

My simple Chrome extension is injecting a DIV at the top of document.body, then you can drag text from your page into the extension. The problem is that I want the extension DIV not to be located at top, but instead be something like a side bar to the left.
In other words I need to know how to programatically rearrange already loaded DOM structure so that all content is moved to the right and horizontally compressed and then the left area is accessible to further manipulations.
One option I was considering was to do this:
tmp = document.body.innerHTML
document.body.innerHTML = '<table><tr><td id=sidebar></td><td>'
+ tmp + '</td></tr></table>'
But this will be inneficient, will cause rerender and may have other undesired side effects.
By the way current version of the extension will inject every page "on load", but this is just a temporary solution, the side bar must be displayed when the extension button is clicked. This is not part of this question, I know how to do that. Just to let you know that the sidebar creation could be done at any time when user chooses to click the button. That's why using innerHTML is not a good option.
pageload.js
function allowDrop(ev) {ev.preventDefault()}
function drop(ev) {
ev.preventDefault();
var t = 'text', T = Array.prototype.slice.apply(ev.dataTransfer.types)
if (T.indexOf('text/html') >= 0)
t = "text/html"
console.log('text type:', t)
d1.innerHTML += '<div style="display:inline;border:2px solid #000000;">'+ev.dataTransfer.getData(t)+'</div> '
}
function createDragbar(id) {
var n = document.createElement('div')
// n.style.position = "absolute";
n.setAttribute('id', id)
n.style.border = '1px solid #aaaaaa'
n.style.height = 532
n.style.background = "teal"
n.innerHTML = "Drop your text here "
n.ondrop = drop
n.ondragover = allowDrop
document.body.insertBefore(n, document.body.firstChild)
}
createDragbar('d1')
manifest.json
{
"name": "Yakov's Demo Extension",
"description": "Just a demo",
"version": "0.1",
"permissions": [
"activeTab"
],
"content_scripts": [{
"matches": ["http://*/*", "https://*/*", "file://*/*"],
"js": ["pageload.js"]
}],
"manifest_version": 2
}
What about element.insertAdjacentHTML(position, text)?
https://developer.mozilla.org/en-US/docs/Web/API/Element.insertAdjacentHTML

Apply Angular.js to new DOM Element in Chrome Extension Content Script

Okay, so I've been at this for a while.
In the red box, I want to have some angular functionality (ng-repeats, data binding, etc...) This red box appears when text on any webpage is double clicked. However, I can't seem to find out how to actually get angular wired/hooked up to the text box example in the red popup.
It seems fairly trivial to use angular in a badge popup in chrome, as well as on options pages, etc...but I can't seem to get it working in this instance.
inject.js (which is included as a content script in manifest, below)
var displayPopup = function(event) {
var mydiv = document.createElement('div');
var $div = $('#divid').closest('.sentence');
mydiv.innerHTML = getSelectionText();
mydiv.innerHTML += currentSentence.innerHTML;
//Next line is where I want to apply some angular functionality
mydiv.innerHTML += '<div ng-app="myApp" scroll-to-me><input type="text" ng-model="data.test"><div ng-model="data.test">{{data.test}}</div></div>';
mydiv.id = "popup";
mydiv.style.position = "fixed";
mydiv.style.top = event.clientY + "px";
mydiv.style.left = event.clientX + "px";
mydiv.style.border = "4px solid #d00";
mydiv.style.background = "#fcc";
$("body").append(mydiv);
$.getJSON('http://local.wordly.com:3000/words/definitions/test', function(data) {
console.log(data);
});
}
and my manifest.json content script array looks like:
"content_scripts": [
{
"matches": [
"https://www.google.com/*"
],
"css": [
"src/inject/inject.css"
]
},
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"js/angular/angular.js", "app.js", "js/jquery/jquery.js", "src/inject/inject.js"
]
}
]
and app.js, also included in manifest, for just some skeletal app to get up and running.
var myApp = angular.module("myApp", []);
myApp.factory('Data', function(){
//return {message: "I'm data from a service"};
});
myApp.controller("SecondCtrl", function($scope, $http){
});
You need to bootstrap manually if you’re injecting the markup after the page loads. Angular will only run ng-app if it’s present when the document is loaded. Afterwards, you pass the module name to angular.bootstrap:
angular.bootstrap(mydiv, ['myApp'])
Example.

Categories