This userscript allows HKU students to show your current courses (in a semester) in a separate entry in HKU Moodle. By: Andrew Z, converted to userscript by q234rty
当前为
// ==UserScript==
// @name HKU moodle helper
// @include http://moodle.hku.hk/*
// @include https://moodle.hku.hk/*
// @version 1.4.5
// @description This userscript allows HKU students to show your current courses (in a semester) in a separate entry in HKU Moodle. By: Andrew Z, converted to userscript by q234rty
// @author AENeuro, q234rty
// @resource mystyle https://cdn.jsdelivr.net/gh/AENeuro/HKU-Moodle-Helper@2d0a17a/myStyle.css
// @license CC BY-NC 4.0
// @grant GM_getResourceText
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @namespace https://greasyfork.org/users/78076
// ==/UserScript==
globalThis.addFeedbackBox = function() {
function showTextArea() {
document.getElementById("helperFeedbackForm").classList.add("helper-shown")
document.getElementById("helperFeedbackButton").insertAdjacentHTML("beforebegin", `
<p id="helperFeedbackButton2" style="color: #AAAAAA;">You can also submit an issue or PR on
<a href="https://github.com/AENeuro/HKU-Moodle-Helper" target="_blank">
<span style="color: #AAAAAA;"><u>Github</u></span>
</a>
</p>
`)
document.getElementById("helperFeedbackButton").remove()
}
async function sendFeedback() {
document.getElementById("helperFeedbackSend").disabled = true
try {
await request({
url: " https://j8n6ydl8hd.execute-api.ap-southeast-1.amazonaws.com/create",
method: "POST",
body: document.getElementById("helperFeedbackInput").value
})
} catch (e) {
alert("Network error")
}
document.getElementById("helperFeedbackForm").classList.remove("helper-shown")
document.getElementById("helperFeedbackForm").insertAdjacentHTML("beforebegin", `
<p style="color: #AAAAAA">Thank you for your feedback!</p>
`)
document.getElementById("helperFeedbackButton2").remove()
}
// initialization
var version = GM_info.script.version;
document.getElementsByClassName("course-of-sem-wrapper")[0].insertAdjacentHTML("beforeend", `
<div class="helper-feedback">
<p>Powered by HKU Moodle Helper ver. ${version}</p>
<p id="helperFeedbackButton">Feedback</p>
<div id="helperFeedbackForm" class="helper-hidden">
<input id="helperFeedbackInput" type="text"/><br/>
<button id="helperFeedbackSend">Send</button>
</div>
</div>
`)
document.getElementById("helperFeedbackButton").addEventListener("click", showTextArea)
document.getElementById("helperFeedbackSend").addEventListener("click", sendFeedback)
}
globalThis.addMessageBox = function() {
const messageBox = `
<section class="helper-extension-persistent helper-message-box block_html block card mb-3" role="complementary" data-block="html" aria-labelledby="instance-330654-header">
<div class="card-body p-3">
<h5 class="card-title d-inline">Message from HKU Moodle Helper</h5>
<div class="card-text content mt-3">
<div class="no-overflow">
<p><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:black">
This is a message generated by the chrome extension <i>HKU Moodle Helper</i> that you intsalled.
</span></p>
<p><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:black">
As many of you have noticed, moodle underwent renovation, and it's unclear just how it would affect the extension yet.
</span></p>
<p><span style="font-size:11.0pt;font-family:"Calibri",sans-serif;color:black">
The extension will still be maintained, provided it's still relevant in new semesters to come.
In the meantime, please condider becoming a dev in <a href="https://github.com/AENeuro/HKU-Moodle-Helper" target="_blank">HKU Moodle Helper</a>.
Any PR or suggestions are welcomed of course.
</span></p>
</div>
<div class="footer"></div>
</div>
</div>
</section>
`
document.getElementById("block-region-side-post").firstChild.insertAdjacentHTML("beforebegin", messageBox)
}
const request = obj => {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(obj.method || "GET", obj.url);
if (obj.headers) {
Object.keys(obj.headers).forEach(key => {
xhr.setRequestHeader(key, obj.headers[key]);
});
}
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.statusText);
}
};
xhr.onerror = () => reject(xhr.statusText);
xhr.send(JSON.stringify(obj.body));
});
};
(function() {
const my_css = GM_getResourceText("mystyle");
GM_addStyle(my_css);
// Note: every element that is to be removed during a clearing session
// should be marked with a "helper-extension" classname
// Otherwise it should be marked with "helper-extension-persistent"
// Code splitting was done through globalThis (which was confined within ContentScript. Thus no pollutions were made)
mainFunction()
async function mainFunction() {
await addCourseOfSem()
globalThis.addFeedbackBox()
globalThis.addMessageBox()
}
async function addCourseOfSem() {
courseHTML = new Array()
courseIDs = JSON.parse(GM_getValue("courseid", "[]"))
//console.log(GM_getValue("courseid","[]"))
clearAll()
var courses = document.getElementsByClassName("coursebox")
for (var i = 0; i < courses.length; i++) {
currentCourseID = courses[i].dataset.courseid
var included = false
if (courseIDs) {
included = courseIDs.includes(currentCourseID)
}
if (included) {
//如果在列表中
//复制element,存入数组
courseHTML.push(courses[i].cloneNode(true))
// Applies to all courses on the page that is in the list (in "my courses" section)
courses[i].lastChild.lastChild.insertAdjacentHTML('beforebegin', `
<button class="helper-extension helper-remove-button" id="removeCourse${currentCourseID}">
Remove from this semester
</button>
`)
document.getElementById("removeCourse" + currentCourseID).addEventListener("click", function(e) {
removeCourse(e.target.id.slice(12), courseIDs)
})
} else {
// Applies to all courses on the page that is not in the list (in "my courses" section)
courses[i].lastChild.lastChild.insertAdjacentHTML('beforebegin', `
<button class="helper-extension helper-add-button" id="addCourse${currentCourseID}">
Add to this semester
</button>
`)
document.getElementById("addCourse" + currentCourseID).addEventListener("click", function(e) {
addCourse(e.target.id.slice(9), courseIDs)
})
}
}
var outerContainer = document.getElementById("frontpage-course-list")
if (courseIDs && courseIDs.length) {
//如果有课程
outerContainer.insertAdjacentHTML('afterbegin', `
<div class="helper-extension course-of-sem-wrapper">
<h2>
Course of this semester
<div id="removeAll">×</button>
</h2>
<div id="courseOfSem" class="courses frontpage-course-list-enrolled has-pre has-post course-of-sem"></div>
</div>
`)
document.getElementById("removeAll").addEventListener("click", function() {
if (confirm("Sure you wanna remove all courses from this semester?")) {
removeAll()
}
})
} else {
//没有课程
outerContainer.insertAdjacentHTML('afterbegin', `
<div class="helper-extension course-of-sem-wrapper">
<h2>Course of this semester</h2>
<p><i>Please click 'Add to this semester' on a course to bring it here.</i></p>
</div>
`)
}
var innerContainer = document.getElementById("courseOfSem")
for (var j = 0; j < courseHTML.length; j++) {
if (j % 2) {
//注意这里是偶数 => 这里是不能整除2(i是奇数),但是在显示顺序上是“偶数”
courseHTML[j].className = "coursebox clearfix even"
} else {
courseHTML[j].className = "coursebox clearfix odd"
}
// applies to all courses in this semester (in "course of this semester" section)
currentCourseID = courseHTML[j].dataset.courseid
courseHTML[j].insertAdjacentHTML('afterbegin', `
<a id="removeCourseA${currentCourseID}" style="position: absolute; top: 5px; right: 5px; font-size: 25px; color: darkgrey; cursor: pointer">
×
</a>
`)
innerContainer.appendChild(courseHTML[j])
document.getElementById("removeCourseA" + currentCourseID).addEventListener("click", function(e) {
removeCourse(e.target.id.slice(13), courseIDs)
})
}
}
// ======================================
// Helper functions
function clearAll() {
var clearElements = document.getElementsByClassName("helper-extension")
//必须倒序删除,因为HTMLCollection会因为remove方法动态变化
for (var i = clearElements.length - 1; i >= 0; --i) {
clearElements[i].remove()
}
}
async function addCourse(courseCode, courseIDs) {
if (courseIDs && courseIDs.length) {
courseIDs.push(courseCode)
} else {
courseIDs = [courseCode]
}
//console.log(JSON.stringify(courseIDs))
GM_setValue("courseid", JSON.stringify(courseIDs))
mainFunction()
}
async function removeCourse(courseCode, courseIDs) {
courseIDs = courseIDs.filter(function(value, index, arr) {
return value !== courseCode;
});
GM_setValue("courseid", JSON.stringify(courseIDs))
mainFunction()
}
async function removeAll() {
GM_setValue("courseid", "[]")
mainFunction()
}
})();