From b79e096a83a06c2248e756262e969662ba942ca8 Mon Sep 17 00:00:00 2001 From: "Chris K.Y. FUNG" <8746768+chriskyfung@users.noreply.github.com> Date: Wed, 29 Sep 2021 22:04:45 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=20Refactor=20Tasks=20on=20A=20Lab/Que?= =?UTF-8?q?st=20Pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qwiklabs-explorer.user.js | 222 ++++++++++++++++++++++---------------- 1 file changed, 127 insertions(+), 95 deletions(-) diff --git a/qwiklabs-explorer.user.js b/qwiklabs-explorer.user.js index 7230fa1..f6cde5c 100644 --- a/qwiklabs-explorer.user.js +++ b/qwiklabs-explorer.user.js @@ -2,7 +2,7 @@ // @name Qwiklabs Completed Labs Tracker // @name:ja Qwiklabsラボ完成トラッカー // @namespace https://chriskyfung.github.io/ -// @version 2.0.3 +// @version 2.0.4 // @author chriskyfung // @description Label completed quests and labs on the Catalog page(s) and Lab pages on Qwiklabs (https://www.qwiklabs.com/catalog) // @homepage https://chriskyfung.github.io/blog/qwiklabs/Userscript-for-Labelling-Completed-Qwiklabs @@ -658,7 +658,7 @@ /** * Load Database when the Program Starts */ - async function loadDB() { + async function loadDB() { if (!(await Dexie.exists(qdb.name))) { console.log('Db does not exist'); await initDB().catch(Dexie.BulkError, function(e) { @@ -829,6 +829,7 @@ }; } + /** */ async function getQuestByTitle(title) { const s = await tmpdb.quests.filter(function(i) { return i.name == title; @@ -870,20 +871,22 @@ * Set the background color of an element by a predefined color key. * @param {Object} element - A DOM element * @param {string} icon_key - A key from iconMap - * @param {number} format_key - The key of icon format to load, where 0 specifies for icon font and 1 for SVG image + * @param {Object} options - The key of icon format to load, where 0 specifies for icon font and 1 for SVG image * @return {string} The XML code of a SVG from iconMap */ - function appendIcon(element, icon_key, format_key=0) { + function appendIcon(element, icon_key, options={}) { + const format_key = options.format_key ? options.format_key : 0; + const elementType = options.elementType ? options.elementType : 'p'; const iconMap = { - 'check': { + check: { 0: '', 1: '', }, - 'game': { + game: { 0: '', 1: '', }, - 'new': { + new: { 0: 'fiber_new', 1: '', }, @@ -892,14 +895,20 @@ return null; }; const icon = iconMap[icon_key][format_key]; - const newElm = document.createElement('p'); + const newElm = document.createElement(elementType); newElm.classList = 'qclt-icon'; newElm.innerHTML = icon; element.appendChild(newElm); return icon; } - function appendUpdateBtn(el, text, foo) { + /** + * Add a icon buton to run database update. + * @param {Object} el - A DOM element + * @param {string} text - A string to display as button title text + * @param {*} foo - A function to call when the button is clicked + */ + function appendDbUpdateBtn(el, text, foo) { el.innerHTML += ' '; el.querySelector('.db-update-button').addEventListener('click', foo); } @@ -918,15 +927,14 @@ switch (await getLabStatusById(id)) { case 'finished': // Annotate as a Completed Lab - // appendIcon(e, 'check', 1); - appendIcon(shadow, 'check', 1); + appendIcon(shadow, 'check', { format_key: 1 }); continue; break; case null: // Annotate as Unregistered console.warn( `[ status = null ] for lab ${id}: ${i.getAttribute('name')}`); // Append New Icon; - appendIcon(shadow, 'new', 1); + appendIcon(shadow, 'new', { format_key: 1 }); break; }; break; @@ -934,14 +942,14 @@ switch (await getQuestStatusById(id)) { case 'finished': // Annotate as a Completed Quest - appendIcon(shadow, 'check', 1); + appendIcon(shadow, 'check', { format_key: 1 }); continue; break; case null: // Annotate as Unregistered console.warn( `[ status = null ] for quest ${id}: ${i.getAttribute('name')}`); // append New Icon - appendIcon(shadow, 'new', 1); + appendIcon(shadow, 'new', { format_key: 1 }); break; }; break; @@ -951,6 +959,105 @@ }; } + /** + * Label the title on a lab page based on the recorded status from the database + * @param {number} id - The id to query the record from the database. + */ + async function trackLabTitle(id) { + const el = document.querySelector('div.header__title > h1'); + const title = el.innerText; + switch (await getLabStatusById(id)) { + case 'finished': + // Annotate as Completed + setBackgroundColor(el, 'green'); + appendIcon(el, 'check', { elementType: 'span' }); + updateRecordById('labs', id, {'name': title}); + break; + case null: + // Annotate as Unregistered; + console.log(`[ status = null ] for lab ${id}: ${el.innerText}`); + setBackgroundColor(el, 'yellow'); + appendIcon(el, 'new', { elementType: 'span' }); + createRecord('labs', id, {'name': title, 'status': ''}); + break; + }; + } + + /** + * Label the title on a quest page based on the recorded status from the database + * @param {number} id - The id to query the record from the database. + */ + async function trackQuestTitle(id) { + const el = document.querySelector('.ql-headline-1'); + const title = el.innerText; + switch (await getQuestStatusById(id)) { + case 'finished': + // Annotate as Completed + setBackgroundColor(el, 'green'); + appendIcon(el, 'check', { elementType: 'span' }); + updateRecordById('quests', id, {'name': title}); + break; + case null: + // Annotate as Unregistered; + console.log(`[ status = null ] for lab ${id}: ${el.innerText}`); + setBackgroundColor(el, 'yellow'); + appendIcon(el, 'new', { elementType: 'span' }); + createRecord('quests', id, {'name': title, 'status': ''}); + break; + }; + } + + /** + * Extract ids from the title links, label the titles based on the recorded status from the database + * @param {Object[]} titles - An array of the DOM elements that contain lab/quest titles + */ + async function trackListOfTitles(titles) { + for (const title of titles) { + const matches = title.innerHTML.match(/data-type="(.+)" \D+(\d+)/); + if (matches == null) { + continue; + }; + const id = matches[2]; + const type = matches[1].toLowerCase(); + switch (type) { + case 'lab': + // tracking a lab on catalog page + switch (await getLabStatusById(id)) { + case 'finished': + // Annotate as a Completed Lab + setBackgroundColor(title, 'green'); + appendIcon(title, 'check'); + continue; + break; + case null: + // Annotate as Unregistered + console.warn( `[ status = null ] for lab ${id}: ${title.innerText}`); + setBackgroundColor(title, 'yellow'); + appendIcon(title, 'new'); + break; + }; + break; + case 'quest': + // tracking a quest on catalog page + switch (await getQuestStatusById(id)) { + case 'finished': + // Annotate as a Completed Quest + setBackgroundColor(title, 'green'); + appendIcon(title, 'check'); + continue; + break; + case null: + // Annotate as Unregistered + console.warn( `[ status = null ] for quest ${id}: ${title.innerText}`); + setBackgroundColor(title, 'yellow'); + appendIcon(title, 'new'); + break; + }; + break; + }; + }; + } + /** * Append an update button to an Activities tab. */ @@ -958,7 +1065,7 @@ const pResults = document.querySelector('.pagination__page'); // element that shows 1 - 10 of N const totalResults = parseInt(pResults.innerText.split('of')[1]); pResults.innerHTML = `${pResults.innerHTML}`; - appendUpdateBtn(pResults, 'Update to DB', bulkUpdateDb); + appendDbUpdateBtn(pResults, 'Update to DB', bulkUpdateDb); } /** @@ -980,7 +1087,7 @@ // Specify a class, change the background in purple color, and add a Gamepad icon to the second column to the row of a Game record. 'game': function(el) { setBackgroundColor(el, 'purple'); - appendIcon(el.children[1], 'game', 1); + appendIcon(el.children[1], 'game', { format_key: 1 }); el.classList.add('completed-game'); }, 'lab': async function(el, name) { @@ -1007,7 +1114,7 @@ 'null': function(el, name, type) { //console.warn(`[ status = null ] for ${type} : "${name}"`); setBackgroundColor(el, 'yellow'); - appendIcon(el.children[1], 'new', 1); + appendIcon(el.children[1], 'new', { format_key: 1 }); el.classList.add(`new-${type}`); }, }; @@ -1043,96 +1150,21 @@ // if (pathRe[1] == '/focuses') { console.log('On a lab page'); - const el = document.querySelector('div.header__title > h1'); const id = pathRe[2]; - const title = el.innerText; - switch (await getLabStatusById(id)) { - case 'finished': - // Annotate as Completed - setBackgroundColor(el, 'green'); - appendIcon(el, 'check'); - updateRecordById('labs', id, {'name': title}); - break; - case null: - // Annotate as Unregistered; - console.log(`[ status = null ] for lab ${id}: ${el.innerText}`); - setBackgroundColor(el, 'yellow'); - appendIcon(el, 'new'); - createRecord('labs', id, {'name': title, 'status': ''}); - break; - }; + await trackLabTitle(id); } else if ( pathRe[0].startsWith('/catalog') || pathRe[1] == '/quests' ) { // // Check if the current page is a catalog page or a quest page // if (pathRe[1] == '/quests') { console.log('On a quest page'); - const el = document.querySelector('.ql-headline-1'); const id = pathRe[2]; - const title = el.innerText; - switch (await getQuestStatusById(id)) { - case 'finished': - // Annotate as Completed - setBackgroundColor(el, 'green'); - appendIcon(el, 'check'); - updateRecordById('quests', id, {'name': title}); - break; - case null: - // Annotate as Unregistered; - console.log(`[ status = null ] for lab ${id}: ${el.innerText}`); - setBackgroundColor(el, 'yellow'); - appendIcon(el, 'new'); - createRecord('quests', id, {'name': title, 'status': ''}); - break; - }; + await trackQuestTitle(id); } else { console.log('On a catalog page'); } const titles = document.querySelectorAll('.catalog-item__title'); - for (const title of titles) { - const matches = title.innerHTML.match(/data-type="(.+)" \D+(\d+)/); - if (matches == null) { - continue; - }; - const id = matches[2]; - const type = matches[1].toLowerCase(); - switch (type) { - case 'lab': - // tracking a lab on catalog page - switch (await getLabStatusById(id)) { - case 'finished': - // Annotate as a Completed Lab - setBackgroundColor(title, 'green'); - appendIcon(title, 'check'); - continue; - break; - case null: - // Annotate as Unregistered - console.warn( `[ status = null ] for lab ${id}: ${title.innerText}`); - setBackgroundColor(title, 'yellow'); - appendIcon(title, 'new'); - break; - }; - break; - case 'quest': - // tracking a quest on catalog page - switch (await getQuestStatusById(id)) { - case 'finished': - // Annotate as a Completed Quest - setBackgroundColor(title, 'green'); - appendIcon(title, 'check'); - continue; - break; - case null: - // Annotate as Unregistered - console.warn( `[ status = null ] for quest ${id}: ${title.innerText}`); - setBackgroundColor(title, 'yellow'); - appendIcon(title, 'new'); - break; - }; - break; - }; - }; + await trackListOfTitles(titles); } else if (pathname == '/') { // Check if the current page is the Home page console.log('On Home page');