Skip to content

Instantly share code, notes, and snippets.

@jrr6
Last active May 21, 2021 13:23
Show Gist options
  • Select an option

  • Save jrr6/5f7961a3e3a1b582fae94a92ee712250 to your computer and use it in GitHub Desktop.

Select an option

Save jrr6/5f7961a3e3a1b582fae94a92ee712250 to your computer and use it in GitHub Desktop.
A userscript that adds a card showing undone work to the Google Classroom Classes page.
// ==UserScript==
// @name Classroom Work Card
// @version 0.1.8
// @description Adds a card showing undone work to the Google Classroom Classes page.
// @author jrr6
// @downloadURL https://gist.github.com/jrr6/5f7961a3e3a1b582fae94a92ee712250/raw/ClassroomWorkCard.user.js
// @updateURL https://gist.github.com/jrr6/5f7961a3e3a1b582fae94a92ee712250/raw/ClassroomWorkCard.user.js
// @match https://classroom.google.com/*
// @grant GM_addStyle
// ==/UserScript==
function addCard () {
var css = document.createElement('style')
css.type = 'text/css'
var styles = `
#work-spot {
width: 27.5rem;
height: 20.5em;
overflow: scroll;
margin-bottom: 2rem;
text-align: center;
margin-right: 2.5rem;
box-shadow: 0 0.1rem 0.2rem rgba(0,0,0,0.12), 0 0 0.1rem rgba(0,0,0,0.12);
padding: 1em;
background: #fff;
}
#work-spot:hover {
box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 2px rgba(0,0,0,0.12), 0 5px 5px -3px rgba(0,0,0,0.2);
}
#work-spot h1 {
font-size: 2rem;
font-weight: 500;
line-height: 2.8rem;
}
.work-item h3 {
font-weight: bold;
}
#work-spot h2 {
color: gray;
font-weight: bold;
}
.work-item {
border: 1px solid black;
margin-bottom: 1em;
padding: 0.5em;
}
`
if (css.styleSheet) {
css.styleSheet.cssText = styles
} else {
css.appendChild(document.createTextNode(styles))
}
document.getElementsByTagName('head')[0].appendChild(css)
var workSpot = document.createElement('div')
workSpot.setAttribute('id', 'work-spot')
var h1 = document.createElement('h1')
h1.textContent = 'Undone Work'
workSpot.appendChild(h1)
document.querySelector('.JwPp0e').prepend(workSpot)
// script
var dates = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
var todayIdx = (new Date()).getDay()
dates = dates.splice(todayIdx).concat(dates)
var asgns = []
document.querySelectorAll('div.kdAl3b div[jscontroller="x4VfFc"]').forEach(e => {
let assignmentGroups = Array.from(e.children).filter(e => e.classList.contains('hrUpcomingAssignmentGroup'))
assignmentGroups.forEach(e => {
let dueDate = e.previousSibling.textContent.slice(4)
let className = e.parentElement.parentElement.parentElement.children[0].children[2].children[0].children[0].children[0].children[0].textContent
for (let child of e.children) {
let asgnName = child
asgns.push({date: dueDate, classN: className, nameNode: asgnName})
}
})
})
asgns.sort((a, b) => {
let aIdx = dates.indexOf(a.date)
let bIdx = dates.indexOf(b.date)
// special cases
if (a.date === 'today' && b.date === 'today') {
return 0
} else if (a.date === 'today') {
return -1
} else if (b.date === 'today') {
return 1
}
if (a.date === 'tomorrow' && b.date === 'tomorrow') {
return 0
} else if (a.date === 'tomorrow') {
return -1
} else if (b.date === 'tomorrow') {
return 1
}
if (aIdx === -1 && bIdx === -1) {
return 0
} else if (aIdx === -1) {
return 1
} else if (bIdx === -1) {
return -1
}
return aIdx > bIdx ? 1 : aIdx === bIdx ? 0 : -1
})
var wList = document.getElementById('work-spot')
if (asgns.length === 0) {
wList.textContent = 'No more work!'
} else {
for (let i = 0; i < asgns.length; ++i) {
let box = document.createElement('div')
box.classList.add('work-item')
if (i > 0) {
if (asgns[i - 1].date !== asgns[i].date) {
let date = document.createElement('h2')
date.textContent = `Due ${asgns[i].date}`
wList.appendChild(date)
}
} else {
let date = document.createElement('h2')
date.textContent = `Due ${asgns[i].date}`
wList.appendChild(date)
}
let classN = document.createElement('h3')
classN.textContent = asgns[i].classN
box.appendChild(classN)
box.appendChild(asgns[i].nameNode.cloneNode(true))
wList.appendChild(box)
}
}
}
function rafAsync () {
return new Promise(resolve => {
requestAnimationFrame(resolve)
})
}
function checkElements (selector) {
if (document.querySelector(selector) === null) {
return rafAsync().then(() => checkElements(selector))
} else {
return Promise.resolve(true)
}
}
var mo = new MutationObserver(function () {
if (document.querySelector('.JwPp0e') !== null) {
checkElements('.gHz6xd.yckQJf.lziZub.k6fwTc').then(setTimeout(addCard, 3000))
mo.disconnect()
}
})
mo.observe(document.body, {attributes: false, childList: true, subtree: true})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment