1

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:

enter image description here

enter image description here

Color Highlighter Related Video:

https://imgur.com/a/c6cd9rM


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.

enter image description here

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 ...

  1. I am correctly implementing the button's html and the CSS modal.
  2. What am I doing wrong in the deployment of the javascript to open the modal and how can I solve it.
  3. 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": "dsfgsdgfsd@gmail.com",
        "secction": "dsfgsdgfsd"
      },
      "author2": {
        "name": "dsfgsdgfsd",
        "email": "dsfgsdgfsd@gmail.com",
        "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. &amp; 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):

enter image description here

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.

13
  • 1
    It looks like you don't have Stacks loaded. Assuming that is the Stack Design component you need somehow include that. See stackoverflow.design/product/guidelines/javascript for your options.
    – rene
    Oct 26 at 17:51
  • @rene thanks for commnet, I'm trying to inject it that way; If I'm working with an extension, I should be able to access the site's javascript. If I insert it into manifest I would be loading the same library twice, right? Oct 26 at 17:54
  • the stack design product documentation doesn't say anything about how to implement it as a chrome extension ... Oct 26 at 17:55
  • You appear to be assuming that your content script is running in the page context (the JavaScript context in which all the scripts from the page run), which is definitely not the case. The 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.
    – Makyen
    Oct 26 at 18:01
  • @Makyen Let's see if I understand: it does not run in the same context / scope; that makes sense of the error; and you suggest not to implement it, because being able to do so would be a security problem; So how can I get access to the modal's display methods, which are already inserted in the DOM of the site without incurring in what you describe. Oct 26 at 18:06
  • My personal preference of how to do this is described in my answer to: "Calling webpage JavaScript methods from browser extension".
    – Makyen
    Oct 26 at 18:14
  • 1
    I doubt this is a problem specific to Stack Exchange or the API. I guess this should put you on the right track: stackoverflow.com/questions/53029697/…
    – rene
    Oct 26 at 18:14
  • ok let me see this ok, Oct 26 at 18:15
  • ok @Makyen i try that you describe with updateTask function but get error to try inline inject script ... i think that is a policy feature of V3 manifest ... and your example is runing v2 Oct 26 at 18:16
  • 1
    @rene SE's code should not be included in an extension. At a minimum, it's a significant security issue. In addition, it's quite likely to cause operational conflicts with the code which is already running in the page. SE's code is definitely not designed to have multiple copies running in different contexts.
    – Makyen
    Oct 26 at 18:19
  • @Makyen 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 ... Oct 26 at 18:22
  • @Makyen this is that i get when try to implement your solution: i.imgur.com/dSWXNUg.png Oct 26 at 18:28
  • @rene thanks for your contribution; that solves the problem when you want to implement a library that does not already exist in the context of the page, and you want to use it in the extension to manipulate the page; But it is not the current case, if I do this I would be duplicating the script, although they are different contexts, it is not appropriate. good is what I have understood. Oct 26 at 18:31

You must log in to answer this question.

Browse other questions tagged .