Can a jQuery Script Be Added to a Dataviewjs Snippet to Change Progress Bar Appearance?

I am running a dataviewjs snippet in a markdown file, specifically Obsidian, but I am not happy with the progess bar appearance, which uses green for 'barely started or bad' and red for 'finished or good'. I'd like to reverse that. I found a jQuery script that I think would help, but I can't make it work (extreme js rookie, here).

Here is the dataviewjs snippet:

const createProgressBar = (char_count, char_goal, words_count, words_goal) => {
        let percents = 0
        if (char_goal != undefined) {
            percents = Math.round(char_count / char_goal * 100)
            else if (words_goal != undefined) {
                percents = Math.round(words_count / words_goal * 100)
            }
            dv.paragraph("<progress max=100 value=" + percents + "> </progress> " + percents + "%")
        }


        const getFirstSplit = (split) => {
                if (split.type == "tabs") {
                    return split
                    else if (split.type == "split") {
                        return getFirstSplit(split.children[0])
                    }
                }

                let firstSplit = getFirstSplit(app.workspace.rootSplit)

                let current = firstSplit.children[firstSplit.currentTab].view.file

                if (current != null) {
                    let page = dv.page(current.path)

                    if (page != undefined) {
                        let char_goal = page.char_goal
                        let words_goal = page.words_goal
                        let synopsis = page.synopsis
                        let POV = page.pov
                        let location = page.location
                        let characters = page.characters
                        let tags = page.tags
                        let project = page.project
                        let highlights


                        if (project != undefined) {
                            dv.header(4, "[[" + project + "]]")
                        }


                        if (synopsis != undefined) {
                            dv.span("***")
                            dv.header(5, "Synopsis")
                            dv.span(synopsis)
                        }


                        if (POV != undefined) {
                            dv.span("***")
                            dv.header(5, "POV")
                            dv.span(POV)
                        }


                        if (page.type == "writing scene") {


                            let content = await dv.io.load(current.path)
                            highlights = content.match(/==.*?==/g)
                            content = content.replace(/^---\n.*?\n---/ms, "").trim().replaceAll("—", "").replaceAll(/[\n]+/mg, " ").replaceAll(/[ ]+/mg, " ").replaceAll("==", "").replaceAll("*", "").replaceAll("#", "")
                            let words = content.split(" ")

                            dv.span("***")
                            dv.header(5, "Scene progress")


                            if (words_goal != undefined) {
                                dv.paragraph(words.length + " / " + words_goal + " words")
                            }

                            if (char_goal != undefined) {
                                dv.paragraph(content.length + " / " + char_goal + " characters")
                            }

                            createProgressBar(content.length, char_goal, words.length, words_goal)
                        }




                        if (page.type == "writing project") {
                            let path = '"' + page.file.folder + '"'
                            let scenePages = dv.pages(path).filter(p => p.type == "writing scene")
                            let words_count = 0
                            let char_count = 0

                            let scenesData = []

                            for (let scene of scenePages) {
                                let sceneContent = await dv.io.load(scene.file.path)
                                sceneContent = sceneContent.replace(/^---\n.*?\n---/ms, "").trim().replaceAll("—", "").replaceAll(/[\n]+/mg, " ").replaceAll(/[ ]+/mg, " ").replaceAll("==", "").replaceAll("*", "").replaceAll("#", "")
                                let sceneWords = sceneContent.split(" ")
                                words_count = words_count + sceneWords.length
                                char_count = char_count + sceneContent.length
                                scenesData.push({
                                    words_count: sceneWords.length,
                                    char_count: sceneContent.length,
                                    link: scene.file.link,
                                    words_goal: scene.words_goal,
                                    char_goal: scene.char_goal
                                })
                            }

                            dv.span("***")
                            dv.header(5, "Novel progress")

                            if (words_goal != undefined) {
                                dv.paragraph(words_count + " / " + words_goal + " words")
                            }
                            if (char_goal != undefined) {
                                dv.paragraph(char_count + " / " + char_goal + " characters")
                            }
                            createProgressBar(char_count, char_goal, words_count, words_goal)

                            dv.span("***")
                            dv.header(5, "Scenes progress")

                            scenesData.forEach(scene => {
                                dv.span(scene.link)
                                createProgressBar(scene.char_count, scene.char_goal, scene.words_count, scene.words_goal)
                            })
                        }



                        if (location != undefined) {
                            dv.span("***")
                            dv.header(5, "Location")
                            dv.span(location.map(c => " [[" + c + "]]") + "")
                        }

                        if (characters != undefined) {
                            dv.span("***")
                            dv.header(5, "Characters")
                            dv.span(characters.map(c => " [[" + c + "]]") + "")
                        }

                        if (tags != undefined) {
                            dv.span("***")
                            dv.header(5, "Tags")
                            dv.span(tags.map(c => " #" + c) + "")
                        }

                        if (highlights != undefined) {
                            highlights = highlights.map(h => h.replaceAll("==", ""))
                            dv.span("***")
                            dv.header(5, "Highlights")
                            dv.paragraph(highlights)
                        }
                    }
                }

Here is the jQuery script:

$(document).ready(function() {
            const show_percent = true;
            var progressBars = $(".progress-bar");
            for (i = 0; i < progressBars.length; i++) {
                var progress = $(progressBars[i]).attr("aria-valuenow");
                $(progressBars[i]).width(progress + "%");
                if (show_percent) {
                    $(progressBars[i]).text(progress + "%");
                }
                if (progress >= "90") {
                    //90 and above
                    $(progressBars[i]).addClass("bg-success");
                    else if (progress >= "30" && progress < "45") {
                        $(progressBars[i]).addClass("bg-warning"); //From 30 to 44
                        else if (progress >= "45" && progress < "90") {
                            $(progressBars[i]).addClass("bg-info"); //From 45 to 89
                            else {
                                //29 and under
                                $(progressBars[i]).addClass("bg-danger");
                            }
                        }
                    });

Is it possible to add the jquery to the dataview snippet, and if so, where and how would I do so?

I tried using the jQuery script with the attribute changed to match my dataviewjs parameters, but I got the following error message:

Evaluation Error: TypeError: Cannot set properties of undefined (setting '__k')
    at S$1 (plugin:dataview:14624:8423)
    at q$1 (plugin:dataview:14624:8598)
    at $ (plugin:dataview:14628:5017)
    at eval (eval at <anonymous> (plugin:dataview), <anonymous>:1:39)
    at DataviewInlineApi.eval (plugin:dataview:18404:16)
    at evalInContext (plugin:dataview:18405:7)
    at asyncEvalInContext (plugin:dataview:18415:32)
    at DataviewJSRenderer.render (plugin:dataview:18436:19)
    at DataviewJSRenderer.onload (plugin:dataview:18020:14)
    at e.load (app://)

1 Answer

I do NOT think jQuery is supported in Obsidian.

As an alternative, you can add the following CSS snippet

.progress-red::-webkit-progress-value {
  background-color: red !important;
}

.progress-orange::-webkit-progress-value {
    background-color: orange !important;
  }

.progress-greenyellow::-webkit-progress-value {
background-color: greenyellow !important;
}

And also tweak your JS createProgressBar as follows

const createProgressBar = (char_count, char_goal, words_count, words_goal) => {
    let percents = 0
    if (char_goal != undefined) {
        percents = Math.round(char_count / char_goal * 100)
    }
    else if (words_goal != undefined) {
        percents = Math.round(words_count / words_goal * 100)
    }
    let color='red';
    if(percents >=75)

        color = 'greenyellow';
    else if(percents >=50)
            color = 'orange';

    dv.paragraph(`<progress class="progress-${color}" max=100 value=${percents}></progress> ${percents}% `)
}

createProgressBar(12, undefined, 30.8, 100)
createProgressBar(400, 500, 30.8, 100)
createProgressBar(400, undefined, 234, 423)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Alexander Ross

Alexander Ross

Gaming, Esports & Interactive Media Writer

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.

Share this article
Twitter Facebook Pinterest