Register for InstructureCon25 • Passes include access to all sessions, the expo hall, entertainment and networking events, meals, and extraterrestrial encounters.
Found this content helpful? Log in or sign up to leave a like!
Hello everyone,
This is my first time learning about MutationObservers and I saw there was a feature request for a word count in SpeedGrader. So for a weekend project, I decided to give it an initial attempt. I know the code can be cleaned up more, but this is an initial prototype. Please let me know your thoughts about the code and if you notice any errors.
Since I didn't find a way currently to access the iFrame content when a document preview is loaded, I would especially appreciate any feedback if someone knows a way to get access. Unfortunately, the preview is loaded from a CanvasDocs domain so my code isn't permitted to access that.
Current Design:
Here is the JavaScript code I used:
$(document).ready(function() {
if (/^\/courses\/[0-9]+\/gradebook\/speed_grader/.test(window.location.pathname)) {
addWordCountToRightSideOfSpeedGrader();
let internalFrameHolder = document.getElementById("iframe_holder");
const internalFrameHolderObserver = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if(mutation.addedNodes) {
mutation.addedNodes.forEach(node => {
if(node.nodeName === "IFRAME") {
node.addEventListener("load", addWordCountToIFrameContent);
node.addEventListener("change", addWordCountToIFrameContent);
}
});
}
});
});
internalFrameHolderObserver.observe(internalFrameHolder, {
childList: true
});
}
});
function countWordsInTextArea() {
let textareaElem = document.getElementById("word-count-textarea");
let resultElem = document.getElementById("word-count-total");
let count = 0;
let words = (textareaElem.value.split("\n").join(" ").split(" ")).filter(word => word != "");
if(words.length > 4 && words[0] == "Page" && words[2] == "of") {
count = words.length - 4;
}
else {
count = words.length;
}
resultElem.innerHTML = count;
}
function addWordCountToRightSideOfSpeedGrader() {
const wordCountDiv = document.createElement("div");
wordCountDiv.id = "word-count-div";
wordCountDiv.classList.add("content_box");
const wordCountHeading = document.createElement("h2");
const wordCountHeadingText = document.createTextNode("Word Count Input");
wordCountHeading.appendChild(wordCountHeadingText);
wordCountDiv.appendChild(wordCountHeading);
const wordCountTextArea = document.createElement("textarea");
wordCountTextArea.id = "word-count-textarea";
wordCountTextArea.placeholder = "Add text here to count the words"
wordCountTextArea.style.overflowY = "hidden";
wordCountTextArea.style.height = "5rem";
wordCountTextArea.style.width = "95%";
wordCountDiv.appendChild(wordCountTextArea);
const wordCountResults = document.createElement("p");
const wordCountText = document.createTextNode("Word Count: ");
wordCountResults.appendChild(wordCountText);
const wordCountTotal = document.createElement("span");
wordCountTotal.id = "word-count-total";
const wordCountValue = document.createTextNode("0");
wordCountTotal.appendChild(wordCountValue);
wordCountResults.appendChild(wordCountTotal);
wordCountDiv.appendChild(wordCountResults);
document.getElementById("rightside_inner").appendChild(wordCountDiv);
wordCountTextArea.addEventListener("input", countWordsInTextArea);
}
function addWordCountToIFrameContent() {
let internalFrame = document.getElementById("speedgrader_iframe");
if (internalFrame && /\/courses\/[0-9]+\/assignments\/[0-9]+\/submissions/.test(internalFrame.src)) {
let posts = internalFrame.contentWindow.document.getElementsByClassName("message_html");
if (posts.length > 0) {
let postsArray = Array.from(posts);
postsArray = postsArray.map(post => post.defaultValue);
postsArray = postsArray.map(post => post.replace(/<.+?>/g, ""));
postsArray = postsArray.map(post => post.replaceAll(" ", " "));
postsArray = postsArray.map(post => post.replaceAll("\n", " ").trim());
postsArray = postsArray.map(post => post.split(" "));
postsArray = postsArray.map(post => post.filter(word => word != "" && word != " "));
postsArray = postsArray.map(post => post.length);
for (let i = 0; i < postsArray.length; i++) {
let count = postsArray[i];
if (count > 0) {
let countDiv = document.createElement("div");
countDiv.style.borderStyle = "solid";
let countPost = document.createTextNode("Word Count: " + count);
countDiv.appendChild(countPost);
posts[i].parentNode.appendChild(countDiv);
}
}
}
else {
let textSubmission = internalFrame.contentWindow.document.getElementById("submission_preview");
if (textSubmission) {
let text = textSubmission.innerHTML;
text = text.replace(/<span class="screenreader-only".+?<\/span>/g, "");
text = text.replace(/<.+?>/g, "");
text = text.replaceAll(" ", " ");
text = text.replaceAll("\n", " ").trim();
let count = text.split(" ").filter(word => word != "" && word != " ").length;
let countDiv = document.createElement("div");
countDiv.style.borderStyle = "solid";
let countPost = document.createTextNode("Word Count: " + count);
countDiv.appendChild(countPost);
textSubmission.parentNode.appendChild(countDiv);
}
}
}
}
We noticed that the PDF word count is currently not accurate @Ventura College.
Matt
To interact with Panda Bot in the Instructure Community, you need to sign up or log in:
Sign In