您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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.7
- // @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, taogoddd
- // @resource mystyle https://cdn.jsdelivr.net/gh/AENeuro/HKU-Moodle-Helper@ede423d/myStyle.css
- // @resource fontawesome https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.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", `
- <div>
- <p id="helperFeedbackButton2" style="color: #AAAAAA;">Check the
- <a href="https://github.com/AENeuro/HKU-Moodle-Helper" target="_blank">
- <span style="color: #AAAAAA;"><u>FAQ</u></span>
- </a>
- or 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>
- </div>
- `)
- document.getElementById("helperFeedbackButton").remove()
- }
- async function sendFeedback() {
- if (!document.getElementById("helperFeedbackInput").value) {
- return 0
- }
- 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
- document.getElementsByClassName("course-of-sem-wrapper")[0].insertAdjacentHTML("beforeend",`
- <div class="helper-feedback">
- <p>Powered by HKU Moodle Helper ver. 1.4.7</p>
- <p id="helperFeedbackButton">Feedback</p>
- <div id="helperFeedbackForm" class="helper-hidden">
- <input id="helperFeedbackInput" type="text" placeholder="Email [Optional] + issue"/><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 installed.
- </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(){
- // 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)
- const my_css = GM_getResourceText("mystyle");
- GM_addStyle(my_css);
- const fontawesome = GM_getResourceText("fontawesome");
- GM_addStyle(fontawesome)
- mainFunction();
- async function mainFunction() {
- //addCssByLink("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css");
- await addCourseOfSem();
- globalThis.addFeedbackBox();
- globalThis.addMessageBox();
- }
- async function addCourseOfSem() {
- courseElements = new Array();
- courseList = JSON.parse(GM_getValue("courselist", "[]"))
- clearAll();
- var courses = document.getElementsByClassName("coursebox");
- pagePath = window.location.pathname;
- for (var i = 0; i < courses.length; i++) {
- currentCourseID = courses[i].dataset.courseid;
- var included = false;
- if (courseList) {
- included = courseList
- .map((value, index, array) => {
- return value.courseID;
- })
- .includes(currentCourseID);
- }
- if (included) {
- //如果在列表中
- //复制element,存入数组
- if (pagePath != "/course/search.php") {
- courseElements.push({
- courseID: currentCourseID,
- courseHTML: 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), courseList);
- });
- } 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) {
- courseInfo = extractInfo(LocateCourse(currentCourseID, courses));
- if (pagePath == "/course/search.php")
- addCourse(pagePath, e.target.id.slice(9), courseList, courseInfo);
- else addCourse(pagePath, e.target.id.slice(9), courseList);
- });
- }
- }
- // addcourses buttons for side bars
- var sidebarlist = document.getElementsByClassName("column c1");
- for (var i = 0; i < sidebarlist.length; i++) {
- // id comes from the ref: https://moodle.hku.hk/course/view.php?id=xxx
- var included = false;
- const id = sidebarlist[i].firstChild.href.slice(41);
- if (courseList) {
- included = courseList
- .map((value, index, array) => {
- return value.courseID;
- })
- .includes(id);
- }
- const text = sidebarlist[i].removeChild(sidebarlist[i].lastChild);
- const anchor = document.createElement("span");
- sidebarlist[i].appendChild(anchor);
- sidebarlist[i].firstChild.insertAdjacentHTML(
- "afterEnd",
- `<div class="helper-extension helper-sidebar-wrapper">
- <div class="helper-extension helper-sidebar-button-${
- included ? "minus" : "plus"
- }" id="sidebarbtn${id}" title='${
- included ? "remove from" : "add to"
- } this semester' >${included ? "×" : "+"}</div>
- </div>`
- );
- sidebarlist[i].removeChild(anchor);
- sidebarlist[i].lastChild.insertAdjacentElement("beforeBegin", text);
- if (included) {
- document
- .getElementById("sidebarbtn" + id)
- .addEventListener("click", function (e) {
- removeCourse(e.target.id.slice(10), courseList);
- });
- } else {
- document
- .getElementById("sidebarbtn" + id)
- .addEventListener("click", function (e) {
- addCourse("/course/search.php", e.target.id.slice(10), courseList, {
- title: text.innerText,
- teachers: "",
- });
- });
- }
- }
- var outerContainer = document.getElementById("frontpage-course-list");
- if (courseList && courseList.length && outerContainer) {
- //如果有课程
- 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("Do you wish to 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 i = 0; i < courseList.length; i++) {
- /* if (i % 2) {
- //注意这里是偶数 => 这里是不能整除2(i是奇数),但是在显示顺序上是“偶数”
- courseHTML[i].className = "coursebox clearfix even";
- } else {
- courseHTML[i].className = "coursebox clearfix odd";
- } */
- // applies to all courses in this semester (in "course of this semester" section)
- currentCourseID = courseList[i].courseID;
- if (
- courseElements
- .map((value, index, array) => {
- return value.courseID;
- })
- .includes(courseList[i].courseID)
- ) {
- currentCourseHTML = courseElements.filter((value, index) => {
- return value.courseID == currentCourseID;
- })[0].courseHTML;
- currentCourseHTML.insertAdjacentHTML(
- "afterbegin",
- `
- <a id="removeCourseA${currentCourseID}" style="position: absolute; top: 5px; right: 5px; font-size: 25px; color: darkgrey; cursor: pointer">
- ×
- </a>
- `
- );
- innerContainer.appendChild(currentCourseHTML);
- document
- .getElementById("removeCourseA" + currentCourseID)
- .addEventListener("click", function (e) {
- removeCourse(e.target.id.slice(13), courseList);
- });
- } else {
- let courseDoc = new DOMParser().parseFromString(
- createCard(courseList[i]),
- "text/html"
- );
- var courseElement = courseDoc.querySelector("div");
- courseElement.insertAdjacentHTML(
- "afterbegin",
- `
- <a id="removeCourseA${currentCourseID}" style="position: absolute; top: 5px; right: 5px; font-size: 25px; color: darkgrey; cursor: pointer">
- ×
- </a>
- `
- );
- innerContainer.appendChild(courseElement);
- document
- .getElementById("removeCourseA" + currentCourseID)
- .addEventListener("click", function (e) {
- removeCourse(e.target.id.slice(13), courseList);
- });
- }
- }
- }
- // ======================================
- // Helper functions
- function addCssByLink(url) {
- var doc = document;
- var link = doc.createElement("link");
- link.setAttribute("rel", "stylesheet");
- link.setAttribute("href", url);
- var heads = doc.getElementsByTagName("head");
- if (heads.length) heads[0].appendChild(link);
- else doc.documentElement.appendChild(link);
- }
- function clearAll() {
- var clearElements = document.getElementsByClassName("helper-extension");
- //必须倒序删除,因为HTMLCollection会因为remove方法动态变化
- for (var i = clearElements.length - 1; i >= 0; --i) {
- clearElements[i].remove();
- }
- }
- function createCard(course) {
- courseID = course.courseID;
- courseInfo = course.courseInfo;
- return `<div class="coursebox clearfix odd first" data-courseid=${courseID} data-type="1">
- <div class="info">
- <h3 class="coursename">
- <a class="aalink" href="https://moodle.hku.hk/course/view.php?id=${courseID}">
- <span class="highlight">${courseInfo.title}</span>
- </a>
- </h3>
- <div class="moreinfo"></div>
- </div>
- <div class="content">
- <div class="summary">
- <h3 class="coursename">
- <a style="display: inline" href="https://moodle.hku.hk/course/view.php?id=${courseID}">${courseInfo.title}</a>
- <div class='history'>
- <div class="bubble" style="background-color: #332d2d;">
- <i style="width: 0px;height: 0px;color: #332d2d;border-width: 14px 15px 8px 0px;border-style: solid;border-color: currentcolor transparent transparent;top: 95%;left: 0px;margin-bottom: 4px;">
- </i>
- <div class="text">This course card was constructed based on your last visit to the search page or the sidebar</div>
- </div>
- <i class="fa fa-history history-icon" ></i>
- </div>
- </h3>
- <div></div>
- </div>
- <div class="teachers" >
- Teachers:
- <a style="color: #966b00;">${courseInfo.teachers}</a>
- </div>
- <div class="course-btn">
- <p>
- <a
- class="btn btn-primary"
- href="https://moodle.hku.hk/course/view.php?id=${courseID}"
- >
- Click to enter this course
- </a>
- </p>
- </div>
- </div>
- </div>`;
- }
- function LocateCourse(courseID, courses) {
- for (let i = 0; i < courses.length; i++) {
- if (courses[i].dataset.courseid == courseID) return courses[i];
- }
- return;
- }
- function extractInfo(courseElement) {
- title = courseElement.querySelector(".aalink").innerText;
- teachers = courseElement.querySelector(".teachers").innerText.slice(9);
- return { title: title, teachers: teachers };
- }
- async function addCourse(pageURL, courseID, courseList, courseInfo = {}) {
- if (pageURL == "/course/search.php") {
- if (courseList && courseList.length) {
- courseList.push({ courseID: courseID, courseInfo: courseInfo });
- } else {
- courseList = [{ courseID: courseID, courseInfo: courseInfo }];
- }
- GM_setValue("courselist", JSON.stringify(courseList));
- } else {
- if (courseList && courseList.length) {
- courseList.push({ courseID: courseID });
- } else {
- courseList = [{ courseID: courseID }];
- }
- GM_setValue("courselist", JSON.stringify(courseList));
- }
- mainFunction();
- }
- async function removeCourse(courseCode, courseList) {
- courseList = courseList.filter(function (value, index, arr) {
- return value.courseID !== courseCode;
- });
- GM_setValue("courselist", JSON.stringify(courseList));
- mainFunction();
- }
- async function removeAll() {
- GM_setValue("courselist", "[]")
- mainFunction();
- }
- })();