Glyphicon's boostrap 3 not working in chrome extensions? - javascript

I'm start learning create an extension in chrome. I had a problem that Chrome does not accept any glyphicon icon using in boostrap version 3, like this:
<span class="glyphicon glyphicon-arrow-right"></span>
I tried config bootstrap in content.js file or call it in html's file but it still didn't work. Here are some in my mini project:
Chrome does not recognize icon.
.
In my source code manifest.json, I have configured chrome to receive bootstrap:
"web_accessible_resources": [
"/assets/*",
"/css/*",
"/js/DomAnalys/*"
],
"content_scripts": [
{
"matches": [
"https://*/*",
"http://*/*"
],
"all_frames": true,
"js": [
"/assets/js/jquery-3.4.1.min.js",
"/assets/js/bootstrap-3.4.1.min.js",
"/js/content.js"
],
"css": []
}
]
I also configured embedded boostrap directly into the js file. But
nothing happened. Here is my content.js file, i attached boostrap to
shadow dom:
const urlCssContent = chrome.extension.getURL("/css/content-script.css");
const urlCssBoostrap = chrome.extension.getURL("/assets/css/bootstrap.min.css");
const shadow = document.querySelector('#popup-modal-transl').attachShadow({
mode: 'open'
});
const importCss = `<style>
#import "${urlCssContent}";
#import "${urlCssBoostrap}";
</style>`;
shadow.innerHTML = `${importCss}${content}`;

Related

Overwrite native JS function with Chrome Extension (manifest V3)

my aim is to override the default setInterval JS function in all pages with a browser extension (by injecting my javascript code just at the beginning of pages). This script should run before any other script, jQuery included. My latest attempt (not working) is this:
manifest.js
...
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start",
"all_frames": true
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"scripting"
],
"host_permissions": ["<all_urls>"],
...
content.js
function do_newInterval() {
window.setInterval = function setInterval() {console.log('hello')}
};
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.type === 'newInterval') { do_newInterval(); }
});
background.js
chrome.tabs.onUpdated.addListener(async () => {
let activeTab=await chrome.tabs.query({ active: true,
lastFocusedWindow: true })
chrome.tabs.sendMessage(activeTab[0].id, { type: "newInterval"
});
})
Unfortunately the code to replace the setInterval function is run after other page scripts are executed!
Could you please show me the right way to make my JS run as first?
Thank you!

Programmatically determine which content script to run

I'm attempting to build a browser extension that changes the CSS of a website (among other things).
In the manifest.json file, one is able to specify a "matches" key to limit which sites the extension has permission to modify via the content script. Right now, I'm trying to present multiple different theme options, and each has its own CSS file.
Let's say I have three themes: theme1.css, theme2.css, and theme3.css
This is my save function, simply for reference.
function save(theme) {
chrome.storage.sync.set({"theme": theme}, function() {
console.log('Set the theme to ' + theme)
main()
})
}
Currently, I have this in my manifest.json:
"content_scripts": [{
"css": ["style.css"],
"js": ["content.js"],
"matches": ["https://*.example.com/*"]
}]
How can I check the stored theme to determine which one has been selected by the user, and then apply the corresponding CSS file if the URL is, let's say, https://example.com/?
Edit: I've since tried Declarative Content, this is what I've gotten. The Javascript is being injected but the CSS does not appear to be working.
var theme1 = {
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostEquals: 'example.com', schemes: ['https'] }
})
],
actions: [
new chrome.declarativeContent.RequestContentScript({
js: [
"content.js"
],
css: [
"css/theme1.css"
]
})
]
};
if (theme === "theme1") {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([theme1])
console.log("Set theme to theme1")
})
}

Override Element.prototype.attachShadow using Chrome Extension

I need to access the DOM of a web component that has a closed Shadow DOM for some Selenium testing. I've read in several references that you can override Element.prototype.attachShadow on the document startup in order to change the Shadow from closed to open. In order to do this, I created a Chrome Extension. Below is my manifest.json:
{
"name": "SeleniumTesting",
"description": "Extension to open closed Shadow DOM for selenium testing",
"version": "1",
"author": "SeleniumTesting",
"manifest_version": 2,
"permissions": ["downloads", "<all_urls>"],
"content_scripts": [{
"matches": ["http://localhost:5000/*"],
"run_at": "document_start",
"all_frames": true,
"js": ["shadowInject.js"]
}]
}
And my shadowInject.js
console.log('test');
Element.prototype._attachShadow = Element.prototype.attachShadow;
Element.prototype.attachShadow = function () {
console.log('attachShadow');
return this._attachShadow( { mode: "open" } );
};
In order to test it, I created my component in an ASPNetCore MVC project. Below is my javascript that creates the custom component:
customElements.define('x-element', class extends HTMLElement {
constructor() {
super();
this._shadowRoot = this.attachShadow({
mode: 'closed'
});
this._shadowRoot.innerHTML = `<div class="wrapper">
<a href="download/File.pdf" download>
<button id="download">Download File</button>
</a>
<p>Link para download</p>
</div>`;
}
});
And my HTML file that uses it:
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<script src='~/js/componente.js'></script>
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
<x-element id='comp'></x-element>
</div>
I load my extension into Chrome, and I run the page. I get the console log Test, but the attachShadow method is never called, and I still cannot access the closed shadow DOM
I would really appreciate some help on what I`m doing wrong. Thank you very much.
FINAL SOLUTION
After applying the changes in the answer, I need to make some adjustments to the manifest.json. Below is the final version:
{
"name": "SeleniumTesting",
"description": "Extension to open closed Shadow DOM for selenium testing",
"version": "1",
"author": "SeleniumTesting",
"manifest_version": 2,
"permissions": ["downloads", "<all_urls>"],
"content_scripts": [{
"matches": ["http://localhost:5000/*"],
"run_at": "document_start",
"all_frames": true,
"js": ["shadowInject.js"]
}],
"web_accessible_resources": ["injected.js"]
}
Now it worked, and the Shadow DOM changed to open
You should not put the code in content_scripts because content_scripts is not the same as the current page context.
You try to change the shadowInject.js code to:
const injectedScript = document.createElement('script');
injectedScript.src = chrome.extension.getURL('injected.js');
(document.head || document.documentElement).appendChild(injectedScript);
Then create a injected.js file in the same directory:
The file content is:
console.log('test');
Element.prototype._attachShadow = Element.prototype.attachShadow;
Element.prototype.attachShadow = function () {
console.log('attachShadow');
return this._attachShadow( { mode: "open" } );
};
You can try it. If there is any problem, please let me know
As mentioned in Black-Hole's answer, content scripts have their own versions of the DOM objects so you'll have to inject an additional script to run in the real DOM.
If you want to touch the page as little as possible and keep shadows closed to the rest of the page you can use this script:
{
const shadows = new WeakMap();
const original = Element.prototype.attachShadow;
Element.prototype.attachShadow = function() {
const shadow = original.apply(this, arguments);
shadows.set(this, shadow);
return shadow;
};
// Later...
shadows.get(document.querySelector("x-element"));
}

Export as Excel file not working for HTML table in Chrome Extension

I am currently developing an chrome extension for my university and there is a problem i am facing, the 'Export as Excel' does not show up after i add jquery code in manifest.json as well as in timetable.js (Look below for more info)
Here is my code :
Manifest.json
{
"name": "VIT Academics Enhancement Suite",
"version": "0.1",
"author": "Rahul Kapoor",
"description": "Extension to help you improve your experience on VIT Academics",
"permissions": ["*://academics.vit.ac.in/*"],
"content_scripts": [
{
"matches": ["*://academics.vit.ac.in/parent/parent_login.asp","*://academics.vit.ac.in/student/stud_login.asp","*://academics.vit.ac.in/parent/","*://academics.vit.ac.in/student/","*://27.251.102.132/parent/parent_login.asp","*://27.251.102.132/student/stud_login.asp","*://27.251.102.132/parent/","*://27.251.102.132/student/"],
"js": ["captcha.js"]
},
{
"matches": ["*://academics.vit.ac.in/student/timetable_ws.asp"],
"all_frames": true,
"js": ["timetable.js"],
"js": ["jquery.js"]
},
{
"matches": ["*://academics.vit.ac.in/*/attn_report.asp*","*://academics.vit.ac.in/student/attn_report_details.asp","*://27.251.102.132/*/attn_report.asp*"],
"all_frames": true,
"js": ["attendance.js"],
"css": ["home.css"]
}
],
"manifest_version": 2
}
Timetable.js
var textbox = document.getElementsByName('regular')[0];
console.log(textbox);
var para = document.createElement("input");
var t = document.createTextNode("Show Password");
para.setAttribute("type", "button");
para.setAttribute("id", "btnExport");
para.setAttribute("value","Export Table data into Excel");
textbox.parentElement.appendChild(para);
$("#btnExport").click(function (e) {
window.open('data:application/vnd.ms-excel,' + $('table:nth-child(1)').html());
e.preventDefault();
});
The table HTML code has no id or class so i am targeting it using nth-child but as soon i add jquery.js in manifest which as CDN library code then the button 'Export as Excel' disappears.
Am i doing it right or is it something else i need to do, Please help.
Your problem is in the way you specify multiple script dependencies in the manifest:
"js": ["timetable.js"],
"js": ["jquery.js"]
In JSON, the latter entry will simply overwrite the former, so now you no longer reference timetable.js
The value for the "js" key is already an array (as denoted by the [ ]), so you just add your dependencies to that array:
"js": ["timetable.js", "jquery.js"]
I'm not sure in what order the scripts are injected, you might need to switch them around.

chrome.tabs.executeScript: How to get access to variable from content script in background script?

How to get access to variable app from content script app.js in background script background.js?
Here is how I try it (background.js):
chrome.tabs.executeScript(null, { file: "app.js" }, function() {
app.getSettings('authorizeInProgress'); //...
});
Here is what I get:
Here is manifest.json:
{
"name": "ctrl-vk",
"version": "0.1.3",
"manifest_version": 2,
"description": "Chrome extension for ctrl+v insertion of images to vk.com",
"content_scripts": [{
"matches": [
"http://*/*",
"https://*/*"
],
"js": ["jquery-1.9.1.min.js"
],
"run_at": "document_end"
}],
"web_accessible_resources": [
"jquery-1.9.1.min.js"
],
"permissions" : [
"tabs",
"http://*/*",
"https://*/*"
],
"background": {
"persistent": false,
"scripts": ["background.js"]
}
}
Full code for instance, at github
https://github.com/MaxLord/ctrl-vk/tree/with_bug
To avoid above error use following code
if (tab.url.indexOf("chrome-devtools://") == -1) {
chrome.tabs.executeScript(tabId, {
file: "app.js"
}, function () {
if (app.getSettings('authorizeInProgress')) {
alert('my tab');
REDIRECT_URI = app.getSettings('REDIRECT_URI');
if (tab.url.indexOf(REDIRECT_URI + "#access_token") >= 0) {
app.setSettings('authorize_in_progress', false);
chrome.tabs.remove(tabId);
return app.finishAuthorize(tab.url);
}
} else {
alert('not my');
}
});
}
instead of
chrome.tabs.executeScript(null, {
file: "app.js"
}, function () {
if (app.getSettings('authorizeInProgress')) {
alert('my tab');
REDIRECT_URI = app.getSettings('REDIRECT_URI');
if (tab.url.indexOf(REDIRECT_URI + "#access_token") >= 0) {
app.setSettings('authorize_in_progress', false);
chrome.tabs.remove(tabId);
return app.finishAuthorize(tab.url);
}
} else {
alert('not my');
}
});
Explanation
chrome://extensions/ page also fires chrome.tabs.onUpdated event, to avoid it we have to add a filter to skip all dev-tool pages.
(Would've submitted this as comment to the accepted answer but still lack the required reputation)
You should also give the tabId to chrome.tabs.executeScript as first argument when you have it. Otherwise you risk user switching windows/tabs right after requesting a URL and background.js doing executeScript against wrong page.
While fairly obvious on hindsight it threw me for a loop when I got that same error message "Cannot access contents of url "chrome-devtools://.." even though my chrome.tabs.onUpdated eventhandler was checking that the page user requested had some specific domain name just before doing the executeScript call.
So keep in mind, chrome.tabs.executeScript(null,..) runs the script in active window, even if the active window might be developer tools inspector.
We should notice that, in the manifest cofigļ¼š
"content_scripts": [{
"matches": [
"http://*/*",
"https://*/*"
],
"js": ["jquery-1.9.1.min.js"
],
in the "matches" part, only http, https are matched, so if you load your extension in page like: 'chrome://extensions/', or 'file:///D:xxx', that error will occur.
You may load your extension in the page with the url 'http://'; or add more rules in your 'matches' array.

Categories