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');