Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make word count warnings work with leatest TinyMCE editor. #4271

Merged
merged 2 commits into from
Dec 13, 2024

Conversation

frjo
Copy link
Member

@frjo frjo commented Dec 9, 2024

Fixes #4270

Test Steps

  • Confirm that the word count warnings on rich text fields on applications forms are working.

@frjo frjo added Type: Bug Bugs! Things that are broken :-/ Type: Patch Mini change, used in release drafter Status: Needs testing Tickets that need testing/qa Status: Needs dev testing 🧑‍💻 Tasks that should be tested by the dev team labels Dec 9, 2024
@theskumar theskumar changed the title Make work count warnings work with leatest TinyMCE editor. Make word count warnings work with leatest TinyMCE editor. Dec 10, 2024
@theskumar
Copy link
Member

Works great in my testing.

If you are up for it, probably also update the js file with a more readable and easy to understand version

(function() {
    let wordCountInterval;

    const WARNING_THRESHOLD = 0.8;

    /**
     * Count words and manage warning states for an element
     * @param {HTMLElement} element - Target element to process
     */
     function updateWordCount(element) {
        const currentCount = parseInt(element.innerText.match(/\d+/)?.[0], 10) || 0;
        const limit = parseInt(element.closest("div[data-word-limit]").dataset.wordLimit, 10);
        const warningThreshold = limit * WARNING_THRESHOLD;

        /**
        * Clear warning states and classes
        */
        function clearWarnings() {
            delete element.dataset.afterWordCount;
            element.classList.remove("word-count-warning", "word-count-warning-2");
        }

        if (element.textContent.includes("characters")) {
            clearWarnings();
            return;
        }

        element.dataset.afterWordCount = ` out of ${limit}`;

        if (currentCount <= warningThreshold) {
            clearWarnings();
        } else if (currentCount <= limit) {
            element.dataset.afterWordCount += " (Close to the limit)";
            element.classList.remove("word-count-warning-2");
            element.classList.add("word-count-warning");
        } else {
            element.dataset.afterWordCount += " (Over the limit)";
            element.classList.add("word-count-warning-2");
        }
    }

    const observer = new MutationObserver(mutations =>
        mutations.forEach(mutation => updateWordCount(mutation.target))
    );

    /**
     * Initialize word count tracking for matching elements
     */
    function initializeWordCount() {
        const elements = document.querySelectorAll(".tox-statusbar__wordcount");

        if (elements.length) {
            clearInterval(wordCountInterval);
            elements.forEach(element => {
                updateWordCount(element);
                observer.observe(element, {
                    childList: true
                });
            });
        }
    }

    wordCountInterval = setInterval(initializeWordCount, 300);
})();

@theskumar
Copy link
Member

theskumar commented Dec 10, 2024

I didn't quite understand the logic behind wordCountInterval = setInterval(initializeWordCount, 300);, is it doing polling until a matching word count instance is found?

Will there be a situation when, after going into a loop, if js is included but no .tox-statusbar__wordcount is present in the DOM.

@frjo
Copy link
Member Author

frjo commented Dec 10, 2024

@theskumar Added your version of the script, definitely more readable.

If the only rich text field is in a field group it can be hidden. That might be the reason for using "setInterval". It was I who added this, but it was five years ago.

@theskumar
Copy link
Member

If the only rich text field is in a field group it can be hidden. That might be the reason for using "setInterval". It was I who added this, but it was five years ago.

OK. Makes sense. If it’s hidden, the querySelector should still be able to pick it up. I think you should try using setTimeout to initialize it after, say, 300ms of page load, and see if it still works. We could try finding some better trigger, but to me it feels like it was added because the TinyMCE takes a while to initialize itself and this code just checks for it until it's ready.

@wes-otf wes-otf added Status: Tested - approved for live ✅ and removed Status: Needs testing Tickets that need testing/qa Status: Needs dev testing 🧑‍💻 Tasks that should be tested by the dev team labels Dec 13, 2024
@frjo frjo merged commit b1bece9 into main Dec 13, 2024
7 checks passed
@theskumar theskumar deleted the fix/make-word-count-warnings-work-with-latest-tinymce branch March 11, 2025 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Tested - approved for live ✅ Type: Bug Bugs! Things that are broken :-/ Type: Patch Mini change, used in release drafter
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Word count warnings not working after TinyMCE update
3 participants