Difficulties in correctly adding external JavaScript

Hopefully this isn’t too much of a necrobump.

I have the script working on initial page load.

Customization code

<script>
	var refTagger = {
		settings: {
			bibleVersion: "NKJV",
			convertHyperlinks: true,		
			roundCorners: true,
			socialSharing: [],
			tagChapters: true
		}
	};
</script>

<script>
    function downloadJSAtOnload() {
        var element = document.createElement("script");
        element.src = "https://api.reftagger.com/v2/RefTagger.js";
        document.body.appendChild(element);
    }
    
    window.addEventListener("load", downloadJSAtOnload, false);
</script>

Working screenshot

Problems

The problem with this is that it only works when visiting a URL directly. Visiting a page from another page on the Discourse site or having more posts load from scrolling down are both situations in which the verse-tagging script does not work.

I’ve done some more reading (A tour of how the Widget (Virtual DOM) code in Discourse works), and am pretty sure that these problems are related to the tagging script not having access to memory objects in the virtual DOM:

This will work if you want something done when topic pages are opened:

const TopicRoute = require("discourse/routes/topic").default;
TopicRoute.reopen({
	activate: function() {
		this._super();
		Em.run.next(function() {
			// do stuff here when a topic page is opend
		});
	}
});

And you can do stuff HOWEVER, you wont be able to modify the contents of the topic because they are in virtual dom and that’s why jQuery was not able to modify the topic contents while it was able to do stuff like console.log and modify parts of the pre-existing actual dom…

My understanding is that the script I wish to use goes through the DOM while regex matching on Bible verses, creates links to a specific site for things it matches, and adds a particular class to these links. The reason why the script is not working on page change or when more posts are loaded is because the changes in content are not propagating to the actual HTML in the DOM, but are in memory in the virtual DOM.

This explains why I have had no luck with api.onPageChange() – calling the script again when the content changed would work fine if the new content actually showed up in the DOM. Since it does not, it makes sense that this call doesn’t make the script work on with content introduced with a page change or when more posts are loaded, since such content is in the virtual DOM

Moving forward

I feel like I understand the problem more now, but I think I’m now batting above my level. It seems like what I have to do would be to translate the JavaScript code that adds links of a specific class to Bible verses into something using the plugin API that operates on widgets, as described in Developer’s guide to Discourse Themes - decorateCooked().

The problem is, the JavaScript for the library is minified and obfuscated. For example, the first major function in the script, after being beautified, looks like

        function s(e, t) {
            var o, n, r, s, i, a, l, c, d, h, u, f = t && t.split("/"),
                p = T.map,
                g = p && p["*"] || {};
            if (e && "." === e.charAt(0))
                if (t) {
                    for (f = f.slice(0, f.length - 1), e = e.split("/"), i = e.length - 1, T.nodeIdCompat && x.test(e[i]) && (e[i] = e[i].replace(x, "")), e = f.concat(e), d = 0; d < e.length; d += 1)
                        if (u = e[d], "." === u) e.splice(d, 1), d -= 1;
                        else if (".." === u) {
                        if (1 === d && (".." === e[2] || ".." === e[0])) break;
                        d > 0 && (e.splice(d - 1, 2), d -= 2)
                    }
                    e = e.join("/")
                } else 0 === e.indexOf("./") && (e = e.substring(2));
            if ((f || g) && p) {
                for (o = e.split("/"), d = o.length; d > 0; d -= 1) {
                    if (n = o.slice(0, d).join("/"), f)
                        for (h = f.length; h > 0; h -= 1)
                            if (r = p[f.slice(0, h).join("/")], r && (r = r[n])) {
                                s = r, a = d;
                                break
                            } if (s) break;
                    !l && g && g[n] && (l = g[n], c = d)
                }!s && l && (s = l, a = c), s && (o.splice(0, a, s), e = o.join("/"))
            }
            return e
        }

If I could invoke the JavaScript on individual elements (like a <p> tag within a post) that might work too – but that’s not how the script is set up initially. (It targets the whole document).


Hopefully I’ve explained myself clearly. @Johani – your posts keep coming up in my search. Does what I’m writing seem to make sense? Suggestions?

4 Likes