Note: last update at the end of POST
I am developing an extension for community users.
Introduction:
The extension is under development on this github: https://github.com/IcarosNetSA/atsu
and these are its future planned features:
- Rich automatic comments and suggestion (customisable).
- Detection of native language equal to that of the site (customisable).
- Posts highlighting Color: unvisited, visited, and closed (customisable).
- Possibly in the future the synchronization of data between devices and the persistence of data will be added through a google chrome account.
Illustrative images:
Color Highlighter Related Video:
https://i.sstatic.net/5dBd9.jpg
Problem that I have encountered that does not allow me to continue:
In my document.js
file (It runs in the website tab) I am trying to implement the insertion of new DOM elements to HTML (example the comment and help button); which I have effectively achieved; but I'm trying to give this button an interaction with the user; where I seek to inject a modal and that by clicking the button I can open this modal.
The main idea is to be able to use the scripts that are already running on the site (avoid reloading the CSS and JS scripts) from the document.js
file; but I can't. and it gives me an undefined funsion error.
I have already reviewed the documentation of stack design product and it does not say anything about how to implement it as a chrome extension, even the idea may be to inject it using the manifest configuration but it would then be loading the library 2 times, since if I am working with the site of the network stack exchange this library is part of the page, but I can not get access to these methods.
I have three doubts:
I know, it's what I'm trying to solve: on the one hand, I can't get access to the javascript to what already exists on the page; and if I try to inject the library again from the context of the extension it would not be appropriate because I would be duplicating the library ...
- I am correctly implementing the button's html and the CSS modal.
- What am I doing wrong in the deployment of the javascript to open the modal and how can I solve it.
- Exist any way to add tabs to the Modal Opened? I am thinking of implementing a tab for the quick selection of comments and another to edit, remove or add new comments.
I'm using the V3 manifest suggested by Chrome Extension and it looks like this:
manifest.json
{
"name": "sadfgdsg",
"version": "1.0",
"description": "dsfgsdgfsd",
"manifest_version": 3,
"author": [
{
"author1": {
"name": "dsfgsdgfsd",
"email": "[email protected]",
"secction": "dsfgsdgfsd"
},
"author2": {
"name": "dsfgsdgfsd",
"email": "[email protected]",
"secction": "dsfgsdgfsd"
}
}
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "src/html/popup.html",
"default_title": "dsfgsdgfsd",
"default_icon": {
"32": "src/img/32.png",
"48": "src/img/48.png",
"64": "src/img/64.png",
"128": "src/img/128.png"
}
},
"icons": {
"32": "src/img/32.png",
"48": "src/img/48.png",
"64": "src/img/64.png",
"128": "src/img/128.png"
},
"content_scripts": [
{
"matches": [
"https://*.com/*"
],
"js": [
"src/js/document.js"
]
}
],
"permissions": [
"history",
"tabs",
"activeTab",
"bookmarks",
"unlimitedStorage",
"storage",
"cookies"
],
"host_permissions": [
"*://*/*"
]
}
this is my javascript file that wants to do the magic:
document.js
function isNumeric(str) {
if (typeof str != "string") return false // we only process strings!
return !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
!isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail
}
var post_url_data = window.location.href.split('/');
var post_id = post_url_data[4];
if (typeof post_id !== 'undefined') {
if (isNumeric(post_id)) {
var post_tittle = post_url_data[5].replaceAll('-', ' ');
console.log('ATSU is Working in POST: ' + post_id + ' ' + post_tittle);
// Select the node that will be observed for mutations
const targetNode = document.getElementById('add-comment-' + post_id);
// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };
console.log(targetNode, config);
// Callback function to execute when mutations are observed
const callback = function (mutationsList, observer) {
// Use traditional 'for loops' for IE 11
for (const mutation of mutationsList) {
if ('s-btn s-btn__primary' == mutation.target.className) {
console.log(mutation.target.className);
let list = document.getElementsByClassName('js-comment-help-link s-btn s-btn__link ta-left px2');
console.log(list, list[0], mutation);
//I dont know if i am injecting the righ HTML button and modal
let atsu_btn = `<button
type="button"
class="s-btn js-modal-open"
id="atsu-post-comment"
data-togle="s-modal"
data-target="#atsu-modal"
style="margin-top:5px; border: 3px solid rgb(246, 178, 107); color: rgb(194, 123, 160); font-style: italic;">
Auto Com. & Help
</button>
<div data-controller="s-modal" data-s-modal-return-element="#atsu-post-comment">
<aside class="s-modal" id="atsu-modal" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-describedby="modal-description" aria-hidden="true" data-controller="s-modal" data-s-modal-target="modal" data-s-modal-return-element=".js-modal-open[data-target='#atsu-modal']" data-s-modal-remove-when-hidden="false">
<div class="s-modal--dialog" role="document">
<h1 class="s-modal--header" id="modal-title">Example title</h1>
<p class="s-modal--body" id="modal-description">Nullam ornare lectus vitae lacus sagittis, at sodales leo viverra. Suspendisse nec nulla dignissim elit varius tempus. Cras viverra neque at imperdiet vehicula. Curabitur condimentum id dolor vitae ultrices. Pellentesque scelerisque nunc sit amet leo fringilla bibendum. Etiam feugiat imperdiet mi, eu blandit arcu cursus a. Pellentesque cursus massa id dolor ullamcorper, at condimentum nunc ultrices.</p>
<div class="d-flex gs8 gsx s-modal--footer">
<button class="flex--item s-btn s-btn__primary" type="button">Save changes</button>
<button class="flex--item s-btn" type="button" data-action="s-modal#hide">Cancel</button>
</div>
<button class="s-modal--close s-btn s-btn__muted js-modal-close" type="button" aria-label="Close" data-action="s-modal#hide">
<svg aria-hidden="true" class="svg-icon iconClearSm" width="14" height="14" viewBox="0 0 14 14"><path d="M12 3.41 10.59 2 7 5.59 3.41 2 2 3.41 5.59 7 2 10.59 3.41 12 7 8.41 10.59 12 12 10.59 8.41 7 12 3.41Z"></path></svg>
</button>
</div>
</aside>
<aside class="s-modal" id="atsu-modal" tabindex="-1" role="dialog" aria-labelledby="modal-title" aria-describedby="modal-description" aria-hidden="true" data-controller="s-modal" data-s-modal-target="modal" data-s-modal-return-element=".js-modal-open[data-target='#atsu-modal']" data-s-modal-remove-when-hidden="false">
<div class="s-modal--dialog" role="document">
<h1 class="s-modal--header" id="modal-title">Example title</h1>
<p class="s-modal--body" id="modal-description">Nullam ornare lectus vitae lacus sagittis, at sodales leo viverra. Suspendisse nec nulla dignissim elit varius tempus. Cras viverra neque at imperdiet vehicula. Curabitur condimentum id dolor vitae ultrices. Pellentesque scelerisque nunc sit amet leo fringilla bibendum. Etiam feugiat imperdiet mi, eu blandit arcu cursus a. Pellentesque cursus massa id dolor ullamcorper, at condimentum nunc ultrices.</p>
<div class="d-flex gs8 gsx s-modal--footer">
<button class="flex--item s-btn s-btn__primary" type="button">Save changes</button>
<button class="flex--item s-btn" type="button" data-action="s-modal#hide">Cancel</button>
</div>
<button class="s-modal--close s-btn s-btn__muted js-modal-close" type="button" aria-label="Close" data-action="s-modal#hide">
<svg aria-hidden="true" class="svg-icon iconClearSm" width="14" height="14" viewBox="0 0 14 14"><path d="M12 3.41 10.59 2 7 5.59 3.41 2 2 3.41 5.59 7 2 10.59 3.41 12 7 8.41 10.59 12 12 10.59 8.41 7 12 3.41Z"></path></svg>
</button>
</div>
</aside>
</div>
`;
mutation.target.insertAdjacentHTML('afterend', atsu_btn);
let help = document.getElementsByClassName('js-comment-help-link');
help[0].style.display = "none";
help[0].style.visibility = "hidden";
let comment_input = document.getElementsByClassName('s-textarea js-comment-text-input');
comment_input[0].rows = "5";
document.querySelector("#atsu-post-comment").addEventListener("click", function (e) {
Stacks.showModal(document.querySelector("#atsu-modal")); //this function trow the error.
});
this.disconnect();
}
}
};
if(targetNode instanceof HTMLElement){
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
}
}
}
Update #1: i have try to implement this solution from SO but i am getting other error (I imagine it is related to the differences between manifests V2 and V3; and different privacy policies or features):
Update #2: I have opted for the script implementation:
chrome.scripting.executeScript({
target: { tabId: tabId, allFrames: true },
files: ['src/js/stacks.min.js'],
});
now the problem is that there is a collision of the original script of the web pages of SE sites; and the file that I am injecting. then all the effects and events created by the original script have stopped working; only those that I initialize in the extension work.
Project in: https://github.com/arcanisgk/atsu
Stacks
variable is not directly available from the content script context. Even if it was available, you should never run page code in the content script context, as that has substantial security issues. You will need to use one of a variety of methods to execute code in the page context.