From 472a4ca9c90947b902e8447c19fdd235c3c57162 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Wed, 23 Sep 2020 23:53:23 +0200 Subject: [PATCH 1/8] Further cleanup of code Signed-off-by: Jonas Rittershofer --- docs.md | 1 - lib/build-challenges.js | 3 ++- lib/{i18n-helpers.js => build-helpers.js} | 5 ++-- lib/build-pages.js | 3 ++- lib/exec-git.js | 19 ++++++++------- lib/handle-external-links.js | 28 ++++++++++++----------- lib/i18n-translate.js | 20 +++++++++++----- lib/i18nInit.js | 2 +- tests/test-helper.js | 14 ------------ tests/test-repository.js | 3 --- 10 files changed, 46 insertions(+), 52 deletions(-) rename lib/{i18n-helpers.js => build-helpers.js} (77%) delete mode 100644 tests/test-helper.js delete mode 100644 tests/test-repository.js diff --git a/docs.md b/docs.md index 3162271e..5b00b08e 100644 --- a/docs.md +++ b/docs.md @@ -15,7 +15,6 @@ How does this thing work? Below are general descriptions of directories and cont - **partials** HTML bits that are shared between either challenges or non-challenges pages, to be used in order to generate full HTML for pages. - **i18n** The translation-json-files. Translations are managed on Transifex. - **layouts** Handlebars templates to compile pages. -- **tests** App's test files. - **empty-data.json** The starter file that is duplicated and stored on the user's computer with their challenge completed statuses as they go through the lessons. - **main.js** App's main process file which spins up the renderer view for the pages. - **package.json** App's details and dependencies. diff --git a/lib/build-challenges.js b/lib/build-challenges.js index ea7984aa..fba3cd88 100644 --- a/lib/build-challenges.js +++ b/lib/build-challenges.js @@ -1,11 +1,12 @@ /* + * Runs in: Node - Build Application * This file builds out the challenge web pages. A simple static site * generator. It uses `partials` and `layouts`. */ const fs = require('fs') const path = require('path') const Handlebars = require('handlebars') -const { getLocaleMenu } = require('./i18n-helpers.js') +const { getLocaleMenu } = require('./build-helpers.js') const basepath = path.normalize(path.join(__dirname, '..')) const inputFolder = path.join(basepath, 'resources', 'content', 'challenges') diff --git a/lib/i18n-helpers.js b/lib/build-helpers.js similarity index 77% rename from lib/i18n-helpers.js rename to lib/build-helpers.js index b46aebfc..7f17dddc 100644 --- a/lib/i18n-helpers.js +++ b/lib/build-helpers.js @@ -1,12 +1,13 @@ /* - * Some helper functions to be used where necessary + * Runs in: Node - Build Application + * Some helper functions to be used in builds */ /** * Build locale menu * @return {string} */ -const getLocaleMenu = function () { +function getLocaleMenu () { const { appLanguages } = require('../config/i18next.config') let localeMenu = '' diff --git a/lib/build-pages.js b/lib/build-pages.js index d1302e1c..b2d3a146 100644 --- a/lib/build-pages.js +++ b/lib/build-pages.js @@ -1,11 +1,12 @@ /* + * Runs in: Node - Build Application * This file builds out the general web pages (like the about page). A simple * static site generator. It uses `partials` and `layouts`. */ const fs = require('fs') const path = require('path') const Handlebars = require('handlebars') -const { getLocaleMenu } = require('./i18n-helpers.js') +const { getLocaleMenu } = require('./build-helpers.js') const basepath = path.normalize(path.join(__dirname, '..')) const inputFolder = path.join(basepath, 'resources', 'content', 'pages') diff --git a/lib/exec-git.js b/lib/exec-git.js index fd561b81..621c023b 100644 --- a/lib/exec-git.js +++ b/lib/exec-git.js @@ -1,14 +1,13 @@ -// -// This file is a wrapper to the exec call used in each of the verify scripts. -// It first checks what operating system is being used and if Windows it uses -// the Portable Git rather than the system Git. -// +/* + * This file is a wrapper to the exec call used in each of the verify scripts. + * It first checks what operating system is being used and if Windows it uses + * the Portable Git rather than the system Git. + */ +const os = require('os') +const path = require('path') +const execSync = require('child_process').execSync -var execSync = require('child_process').execSync -var path = require('path') -var os = require('os') - -var winGit = path.join(__dirname, '../assets/PortableGit/bin/git.exe') +const winGit = path.join(__dirname, '../assets/PortableGit/bin/git.exe') module.exports = function execGit (command, options = {}) { // Encoding utf8 for usable output diff --git a/lib/handle-external-links.js b/lib/handle-external-links.js index 7445b4e1..5178ecd7 100644 --- a/lib/handle-external-links.js +++ b/lib/handle-external-links.js @@ -1,18 +1,20 @@ -// -// This file is used by ever web page to make sure all links that are not local -// are opened in the users default browser. -// +/* + * Runs in: Renderer-Process + * This file is used by every web page to make sure all links that are not local + * are opened in the users default browser. + */ +const shell = require('electron').shell -var shell = require('electron').shell +// Execute after DOM loaded +document.addEventListener('DOMContentLoaded', () => { + const links = document.querySelectorAll('a[href]') -document.addEventListener('DOMContentLoaded', function (event) { - var links = document.querySelectorAll('a[href]') - var array = [] - array.forEach.call(links, function (link) { - var url = link.getAttribute('href') - if (url.indexOf('http') > -1) { - link.addEventListener('click', function (e) { - e.preventDefault() + // On each external link add an event-listener, prevent default and open manually. + links.forEach(link => { + const url = link.getAttribute('href') + if (url.startsWith('http')) { + link.addEventListener('click', event => { + event.preventDefault() shell.openExternal(url) }) } diff --git a/lib/i18n-translate.js b/lib/i18n-translate.js index 8ac04f3d..73329e86 100644 --- a/lib/i18n-translate.js +++ b/lib/i18n-translate.js @@ -1,4 +1,6 @@ /* + * Runs in: Renderer-Process + * * Script to include in HTML-Pages * - Insert translated Content * - Set Language Dropdown @@ -24,29 +26,35 @@ const defaultOptions = { smc: ';' // semicolon } -// Insert translated Content on Loading page. -document.addEventListener('DOMContentLoaded', function (event) { +/* + * Insert translated Content after loading page. + */ +document.addEventListener('DOMContentLoaded', () => { setDropdownLanguage() insertDataTranslations() insertBoxTranslationStyles() // Box-Titles are done in CSS, so need specific handling }) /* - * Language change listener + * Set Language change listener * When changeLanguage is done, the main process will reload the window therefore executing translation-insert from scratch. */ const languageSelector = document.getElementById('lang-select') -languageSelector.addEventListener('change', function (event) { +languageSelector.addEventListener('change', () => { i18n.changeLanguage(languageSelector.value) }) -// set Language on Dropdown-Element +/* + * Select current Language in Dropdown-Element + */ function setDropdownLanguage () { const languageSelector = document.getElementById('lang-select') languageSelector.value = i18n.language } -// Insert Translations into HTML +/* + * Insert Translations into HTML + */ function insertDataTranslations () { const i18nElements = document.querySelectorAll('[i18n-data]') diff --git a/lib/i18nInit.js b/lib/i18nInit.js index 682a5a1f..f2e3d94c 100644 --- a/lib/i18nInit.js +++ b/lib/i18nInit.js @@ -1,10 +1,10 @@ /* + * Runs in: Main-Process * Init i18next and store instance on global i18n variable */ const i18next = require('i18next') const i18nextBackend = require('i18next-fs-backend') - const { i18nextConfig } = require('../config/i18next.config.js') // Store and Init i18next diff --git a/tests/test-helper.js b/tests/test-helper.js deleted file mode 100644 index a1a093ef..00000000 --- a/tests/test-helper.js +++ /dev/null @@ -1,14 +0,0 @@ -// create a git repository - -var exec = require('child_process').exec -var tmpDir = '' - -makeDirectory() - -function makeDirectory () { - -} - -exec('git init', {cwd: tmpDir}, function initalized (err, stderr, stdout) { - if (err) return console.log(err) -}) diff --git a/tests/test-repository.js b/tests/test-repository.js deleted file mode 100644 index 42ad00c9..00000000 --- a/tests/test-repository.js +++ /dev/null @@ -1,3 +0,0 @@ -// verify check path is directory -// verify if Git returns 'fatal not a Git repository' -// verify if Git returns 'On branch' From 71f332f6c26b38596cbbcef942e0ed2aa5aa5da9 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Fri, 25 Sep 2020 01:26:26 +0200 Subject: [PATCH 2/8] Cleanup user-data.js Signed-off-by: Jonas Rittershofer --- lib/challenge-completed.js | 12 +-- lib/challenge.js | 8 +- lib/challenges-completed.js | 12 +-- lib/user-data.js | 89 ++++++++++++--------- lib/verify/branches_arent_just_for_birds.js | 2 +- lib/verify/commit_to_it.js | 2 +- lib/verify/forks_and_clones.js | 2 +- lib/verify/get_git.js | 2 +- lib/verify/githubbin.js | 2 +- lib/verify/its_a_small_world.js | 2 +- lib/verify/merge_tada.js | 2 +- lib/verify/pull_never_out_of_date.js | 2 +- lib/verify/remote_control.js | 2 +- lib/verify/repository.js | 2 +- lib/verify/requesting_you_pull_please.js | 2 +- 15 files changed, 80 insertions(+), 63 deletions(-) diff --git a/lib/challenge-completed.js b/lib/challenge-completed.js index 588263c8..1cce06d3 100644 --- a/lib/challenge-completed.js +++ b/lib/challenge-completed.js @@ -59,8 +59,8 @@ var enableClearStatus = function (challenge) { clearStatusButton.style.display = 'inline-block' clearStatusButton.addEventListener('click', function clicked (event) { // set challenge to uncompleted and update the user's data file - data.contents[challenge].completed = false - fs.writeFileSync(data.path, JSON.stringify(data.contents, null, 2)) + data.content[challenge].completed = false + fs.writeFileSync(data.path, JSON.stringify(data.content, null, 2)) // remove the completed status from the page and renable verify button document.getElementById(challenge).classList.remove('completed') disableVerifyButtons(false) @@ -80,16 +80,16 @@ var completed = function (challenge) { document.addEventListener('DOMContentLoaded', function (event) { checkCompletedness(challenge) - Object.keys(data.contents).forEach(function (key) { - if (data.contents[key].completed) { + Object.keys(data.content).forEach(function (key) { + if (data.content[key].completed) { document.getElementById(key).classList.add('completed') } }) }) function checkCompletedness (challenge) { - data = userData.getData() - if (data.contents[challenge].completed) { + data = userData.getChallengeData() + if (data.content[challenge].completed) { document.getElementById(challenge).classList.add('completed') var header = document.getElementsByTagName('header')[0] header.className += ' challenge-is-completed' diff --git a/lib/challenge.js b/lib/challenge.js index cf39b4ac..75f32844 100644 --- a/lib/challenge.js +++ b/lib/challenge.js @@ -23,15 +23,15 @@ if (selectDirBtn) { ipc.on('selected-directory', function (event, path) { selectDirectory(path[0]) - userData.updateCurrentDirectory(path) + userData.updateSavedDir(path) }) } -var currentDirectory = userData.getSavedDir().contents.savedDir -var challengeCompleted = userData.getData().contents +var currentDirectory = userData.getSavedDir().content.savedDir +var challengeCompleted = userData.getChallengeData().content if (currentChallenge === 'forks_and_clones') { // on this challenge clear out the saved dir because it should change - userData.updateCurrentDirectory(null) + userData.updateSavedDir(null) } else if (selectDirBtn && currentDirectory && !challengeCompleted[currentChallenge].completed) { selectDirectory(currentDirectory) selectDirBtn.innerHTML = i18n.t('Change Directory') diff --git a/lib/challenges-completed.js b/lib/challenges-completed.js index 1e74aaab..957cdf72 100644 --- a/lib/challenges-completed.js +++ b/lib/challenges-completed.js @@ -11,7 +11,7 @@ var ipc = require('electron').ipcRenderer var userData = require(path.normalize(path.join(__dirname, '../../lib/user-data.js'))) document.addEventListener('DOMContentLoaded', function (event) { - var data = userData.getData() + var data = userData.getChallengeData() // Buttons var clearAllButtons = document.querySelectorAll('.js-clear-all-challenges') @@ -21,7 +21,7 @@ document.addEventListener('DOMContentLoaded', function (event) { var showWipRun = document.getElementById('show-wip-run') var showFinishedRun = document.getElementById('show-finished-run') - updateIndex(data.contents) + updateIndex(data.content) // Listen for Clear All Button Events, trigger confirmation dialog for (var i = 0; i < clearAllButtons.length; i++) { @@ -75,12 +75,12 @@ document.addEventListener('DOMContentLoaded', function (event) { } function clearAllChallenges (data) { - for (var chal in data.contents) { - if (data.contents[chal].completed) { - data.contents[chal].completed = false + for (var chal in data.content) { + if (data.content[chal].completed) { + data.content[chal].completed = false } } - fs.writeFileSync(data.path, JSON.stringify(data.contents, null, 2)) + fs.writeFileSync(data.path, JSON.stringify(data.content, null, 2)) // If they clear all challenges, go back to first run HTML var circles = document.querySelectorAll('.progress-circle') Array.prototype.forEach.call(circles, function (el) { diff --git a/lib/user-data.js b/lib/user-data.js index 3f323455..795b96e6 100644 --- a/lib/user-data.js +++ b/lib/user-data.js @@ -1,48 +1,65 @@ -// -// This file talks to the main process by fetching the path to the user data. -// It also writes updates to the user-data file. -// +/* + * Runs in: Renderer-Process + * This file handles the user-data.json and saved-dir.json files + * Uses electron-remote fs-module to still write out async, even when function gets terminated. + */ +const fs = require('electron').remote.require('fs') +const ipc = require('electron').ipcRenderer -var fs = require('electron').remote.require('fs') - -var ipc = require('electron').ipcRenderer - -var getData = function () { - var data = {} - data.path = ipc.sendSync('getUserDataPath', null) - data.contents = JSON.parse(fs.readFileSync(data.path)) +/**** + * user-data.json + */ +function getChallengeData () { + const data = {} + data.path = ipc.sendSync('getUserDataPath') + data.content = JSON.parse(fs.readFileSync(data.path)) return data } - -var getSavedDir = function () { - var savedDir = {} - savedDir.path = ipc.sendSync('getUserSavedDir', null) - savedDir.contents = JSON.parse(fs.readFileSync(savedDir.path)) - return savedDir +// Set given challenge completed-status +function setChallengeCompleted (challenge, completed) { + const data = getChallengeData() + data.content[challenge].completed = completed + writeData(data) } - -var writeData = function (data) { - fs.writeFile(data.path, JSON.stringify(data.contents, null, ' '), function updatedUserData (err) { - if (err) return console.log(err) +// Clear all challenges - Set all challenges as incomplete +function clearAllChallenges () { + const data = getChallengeData() + Object.keys(data.content).forEach(challenge => { + data.content[challenge].completed = false }) + writeData(data) } -// this could take in a boolean on compelte status -// and be named better in re: to updating ONE challenge, not all -var updateData = function (challenge) { - var data = getData() - data.contents[challenge].completed = true - +/**** + * saved-dir.json + */ +function getSavedDir () { + const data = {} + data.path = ipc.sendSync('getUserSavedDir') + data.content = JSON.parse(fs.readFileSync(data.path)) + return data +} +function updateSavedDir (path) { + const data = getSavedDir() + data.content.savedDir = path writeData(data) } -var updateCurrentDirectory = function (path) { - var data = getSavedDir() - data.contents.savedDir = path - writeData(data) +/**** + * Common function + * Write out data.content to data.path + * Writes out asynchronously. + */ +function writeData (data) { + fs.writeFile(data.path, JSON.stringify(data.content, null, 2), (err) => { + if (err) { + console.error(err) + } + }) } -module.exports.getData = getData -module.exports.getSavedDir = getSavedDir -module.exports.updateData = updateData -module.exports.updateCurrentDirectory = updateCurrentDirectory +exports.getChallengeData = getChallengeData +exports.setChallengeCompleted = setChallengeCompleted +exports.clearAllChallenges = clearAllChallenges +exports.getSavedDir = getSavedDir +exports.updateSavedDir = updateSavedDir diff --git a/lib/verify/branches_arent_just_for_birds.js b/lib/verify/branches_arent_just_for_birds.js index 63e3f859..7e008bed 100644 --- a/lib/verify/branches_arent_just_for_birds.js +++ b/lib/verify/branches_arent_just_for_birds.js @@ -99,6 +99,6 @@ module.exports = function verifyBranchesChallenge (repopath) { if (counter === total) { markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } } diff --git a/lib/verify/commit_to_it.js b/lib/verify/commit_to_it.js index bb5f7acc..55d5926c 100644 --- a/lib/verify/commit_to_it.js +++ b/lib/verify/commit_to_it.js @@ -30,7 +30,7 @@ module.exports = function commitVerify (path) { } else if (show.match('nothing to commit')) { addToList(i18n.t('verify~Changes have been committed!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { addToList(i18n.t('verify~Seems there are still changes to commit.'), false) helper.challengeIncomplete() diff --git a/lib/verify/forks_and_clones.js b/lib/verify/forks_and_clones.js index c39a9501..ccdee111 100644 --- a/lib/verify/forks_and_clones.js +++ b/lib/verify/forks_and_clones.js @@ -71,6 +71,6 @@ module.exports = function verifyForksAndClonesChallenge (path) { return helper.challengeIncomplete() } - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) helper.markChallengeCompleted(currentChallenge) } diff --git a/lib/verify/get_git.js b/lib/verify/get_git.js index 3a1e9d93..1baecc2a 100644 --- a/lib/verify/get_git.js +++ b/lib/verify/get_git.js @@ -75,6 +75,6 @@ module.exports = function verifyGetGitChallenge () { if (counter === total) { markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } } diff --git a/lib/verify/githubbin.js b/lib/verify/githubbin.js index 954730f8..4186c42b 100644 --- a/lib/verify/githubbin.js +++ b/lib/verify/githubbin.js @@ -79,6 +79,6 @@ module.exports = async function verifyGitHubbinChallenge () { // Check if all challenges succeeded. if (counter === total) { markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } } diff --git a/lib/verify/its_a_small_world.js b/lib/verify/its_a_small_world.js index 390d210e..9e81acfa 100644 --- a/lib/verify/its_a_small_world.js +++ b/lib/verify/its_a_small_world.js @@ -32,7 +32,7 @@ module.exports = async function verifySmallWorldChallenge () { if (response.data.collab === true) { addToList(i18n.t('verify~Reporobot has been added!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { // If they have a non 200 error, log it so that we can use // devtools to help user debug what went wrong diff --git a/lib/verify/merge_tada.js b/lib/verify/merge_tada.js index 3369f333..e62c98ae 100644 --- a/lib/verify/merge_tada.js +++ b/lib/verify/merge_tada.js @@ -65,7 +65,7 @@ module.exports = function verifyMergeTadaChallenge (path) { if (counter === total) { markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { helper.challengeIncomplete() } diff --git a/lib/verify/pull_never_out_of_date.js b/lib/verify/pull_never_out_of_date.js index 3c590180..18962e34 100644 --- a/lib/verify/pull_never_out_of_date.js +++ b/lib/verify/pull_never_out_of_date.js @@ -20,7 +20,7 @@ module.exports = function verifyPullChallenge (path) { if (status === '') { addToList(i18n.t('verify~Up to date!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { addToList(i18n.t('verify~There are changes to pull in.'), false) helper.challengeIncomplete() diff --git a/lib/verify/remote_control.js b/lib/verify/remote_control.js index 99f3748f..6c41210a 100644 --- a/lib/verify/remote_control.js +++ b/lib/verify/remote_control.js @@ -41,7 +41,7 @@ module.exports = function verifyRemoteControlChallenge (path) { if (ref.match('update by push')) { addToList(i18n.t('verify~You pushed changes!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { addToList(i18n.t('verify~No evidence of push.'), false) helper.challengeIncomplete() diff --git a/lib/verify/repository.js b/lib/verify/repository.js index feb58230..b42759f5 100644 --- a/lib/verify/repository.js +++ b/lib/verify/repository.js @@ -26,7 +26,7 @@ module.exports = function repositoryVerify (path) { if (status.match('On branch')) { addToList(i18n.t('verify~This is a Git repository!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { addToList(i18n.t('verify~This folder is not being tracked by Git.'), false) helper.challengeIncomplete() diff --git a/lib/verify/requesting_you_pull_please.js b/lib/verify/requesting_you_pull_please.js index 2a546e6b..a8a9a0ba 100644 --- a/lib/verify/requesting_you_pull_please.js +++ b/lib/verify/requesting_you_pull_please.js @@ -34,7 +34,7 @@ module.exports = async function verifyPRChallenge () { if (pr) { addToList(i18n.t('verify~Found your pull request!'), true) markChallengeCompleted(currentChallenge) - userData.updateData(currentChallenge) + userData.setChallengeCompleted(currentChallenge) } else { // TODO give user url to their repo also addToList(i18n.t('verify~No merged pull request found for username {/username/}. If you created a pull request on github, return there to see if reporobot left some comments.', From 9089a915ce4f572e87ccc2691695638014ebd468 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Fri, 25 Sep 2020 23:34:34 +0200 Subject: [PATCH 3/8] Cleanup index-challenge-handler.js Signed-off-by: Jonas Rittershofer --- lib/challenges-completed.js | 94 ------------------------- lib/index-challenge-handler.js | 106 +++++++++++++++++++++++++++++ main.js | 6 +- resources/content/pages/index.html | 44 ++---------- 4 files changed, 115 insertions(+), 135 deletions(-) delete mode 100644 lib/challenges-completed.js create mode 100644 lib/index-challenge-handler.js diff --git a/lib/challenges-completed.js b/lib/challenges-completed.js deleted file mode 100644 index 957cdf72..00000000 --- a/lib/challenges-completed.js +++ /dev/null @@ -1,94 +0,0 @@ -// -// Renderer Process—This file is required by the index page. -// It touches the DOM by showing progress in challenge completion. -// It also handles the clear buttons and writing to user-data. -// - -var fs = require('electron').remote.require('fs') -var path = require('electron').remote.require('path') -var ipc = require('electron').ipcRenderer - -var userData = require(path.normalize(path.join(__dirname, '../../lib/user-data.js'))) - -document.addEventListener('DOMContentLoaded', function (event) { - var data = userData.getChallengeData() - - // Buttons - var clearAllButtons = document.querySelectorAll('.js-clear-all-challenges') - var leftOffButton = document.getElementById('left-off-from') - // Sections - var showFirstRun = document.getElementById('show-first-run') - var showWipRun = document.getElementById('show-wip-run') - var showFinishedRun = document.getElementById('show-finished-run') - - updateIndex(data.content) - - // Listen for Clear All Button Events, trigger confirmation dialog - for (var i = 0; i < clearAllButtons.length; i++) { - clearAllButtons[i].addEventListener('click', function () { - ipc.send('confirm-clear') - }, false) - } - - ipc.on('confirm-clear-response', function (event, response) { - if (response === 0) { - clearAllChallenges(data) - } - }) - - // Go through each challenge in user data to see which are completed - function updateIndex (data) { - var circles = document.querySelectorAll('.progress-circle') - var counter = 0 - var completed = 0 - - for (var chal in data) { - if (data[chal].completed) { - // A challenge is completed so show the WIP run HTML - showWipRun.style.display = 'block' - showFirstRun.style.display = 'none' - showFinishedRun.style.display = 'none' - // Mark the corresponding circle as completed - circles[counter].classList.add('completed') - // Show the button to go to next challenge - leftOffButton.href = path.join(__dirname, '..', 'challenges', data[chal].next_challenge + '.html') - completed++ - counter++ - } else { - counter++ - } - } - - if (completed === 0) { - // No challenges are complete, show the first run HTML - showFirstRun.style.display = 'block' - showWipRun.style.display = 'none' - showFinishedRun.style.display = 'none' - } - - if (completed === Object.keys(data).length) { - // All of the challenges are complete! Show the finished run HTML - showFirstRun.style.display = 'none' - showWipRun.style.display = 'none' - showFinishedRun.style.display = 'block' - } - } - - function clearAllChallenges (data) { - for (var chal in data.content) { - if (data.content[chal].completed) { - data.content[chal].completed = false - } - } - fs.writeFileSync(data.path, JSON.stringify(data.content, null, 2)) - // If they clear all challenges, go back to first run HTML - var circles = document.querySelectorAll('.progress-circle') - Array.prototype.forEach.call(circles, function (el) { - el.classList.remove('completed') - }) - - showFirstRun.style.display = 'block' - showWipRun.style.display = 'none' - showFinishedRun.style.display = 'none' - } -}) diff --git a/lib/index-challenge-handler.js b/lib/index-challenge-handler.js new file mode 100644 index 00000000..0f6f97b2 --- /dev/null +++ b/lib/index-challenge-handler.js @@ -0,0 +1,106 @@ +/* + * Runs in: Renderer-Process + * + * This file is only required by the index page. + * It touches the DOM by showing progress in challenge completion. + * It also handles the clear buttons and writing to user-data. + */ +const path = require('path') +const ipc = require('electron').ipcRenderer +const userData = require(path.normalize(path.join(__dirname, '../../lib/user-data.js'))) + +const clearAllButtons = document.querySelectorAll('.js-clear-all-challenges') +const pickupButton = document.getElementById('pickup-button') +const progressCircles = document.querySelectorAll('.progress-circle') + +const IndexSectionStart = document.getElementById('index-section-start') +const IndexSectionWip = document.getElementById('index-section-wip') +const IndexSectionFinished = document.getElementById('index-section-finished') + +// Execute after DOM loaded. +document.addEventListener('DOMContentLoaded', () => { + // Get stored challengeUserData & store Key-Array as often used + const challengeUserData = userData.getChallengeData().content + const challengeUserDataKeys = Object.keys(challengeUserData) + + // Go through the challenges in challengeUserData to see which are completed + let countCompleted = 0 + challengeUserDataKeys.forEach((challengeKey, index) => { + if (challengeUserData[challengeKey].completed) { + countCompleted++ + progressCircles[index].classList.add('completed') // Mark corresponding circle as completed + if (index < challengeUserDataKeys.length - 1) { + pickupButton.href = path.join(__dirname, '..', 'challenges', challengeUserDataKeys[index + 1] + '.html') // Set Link on pickup-button to next challenge + } + } + }) + + // If no challenges are complete, show the start-section + if (countCompleted === 0) { + showSection('start') + } + // If only some challenges are complete, show the wip-section + if (countCompleted !== 0 && countCompleted !== challengeUserDataKeys.length) { + showSection('wip') + } + // If all challenges are complete, show the finished-section + if (countCompleted === challengeUserDataKeys.length) { + showSection('finished') + } + + // Add Listeners to ClearAll Buttons + clearAllButtons.forEach(btn => { + btn.addEventListener('click', () => { + ipc.send('dialog-clearAll') + }) + }) +}) + +/* + * Catch confirmed Clear-All Dialog + * Clear all challenges on userData, progressCircles and show Start-Section + */ +ipc.on('confirm-clearAll', () => { + // Clear stored userData + userData.clearAllChallenges() + + // Clear all ProgressCircles in TopBar + progressCircles.forEach(progressCircle => { + progressCircle.classList.remove('completed') + }) + + // Show Start-Index Page + showSection('start') +}) + +/* + * Show exclusively the specified section. + * section = 'start'|'wip'|'finished' + */ +function showSection (section) { + // Only accept specific section-keywords + const accept = ['start', 'wip', 'finished'] + + // Log if wrong keyword + if (accept.indexOf(section) < 0) { + console.error('Wrong Section Keyword: ', section) + } + + switch (section) { + case 'finished': + IndexSectionStart.style.display = 'none' + IndexSectionWip.style.display = 'none' + IndexSectionFinished.style.display = 'block' + break + case 'wip': + IndexSectionStart.style.display = 'none' + IndexSectionWip.style.display = 'block' + IndexSectionFinished.style.display = 'none' + break + case 'start': + default: + IndexSectionStart.style.display = 'block' + IndexSectionWip.style.display = 'none' + IndexSectionFinished.style.display = 'none' + } +} diff --git a/main.js b/main.js index c0677f92..b8d1a23a 100644 --- a/main.js +++ b/main.js @@ -105,7 +105,7 @@ app.on('ready', function appReady () { } }) - ipcMain.on('confirm-clear', function (event) { + ipcMain.on('dialog-clearAll', function (event) { var options = { type: 'info', buttons: [global.i18n.t('Yes'), global.i18n.t('No')], @@ -114,7 +114,9 @@ app.on('ready', function appReady () { } // TODO Change to promise-based showMessageBox (w/o sync) const resp = dialog.showMessageBoxSync(options) - event.sender.send('confirm-clear-response', resp) + if (resp === 0) { + event.sender.send('confirm-clearAll') + } }) /* diff --git a/resources/content/pages/index.html b/resources/content/pages/index.html index e9695e8c..c824e8cd 100644 --- a/resources/content/pages/index.html +++ b/resources/content/pages/index.html @@ -7,7 +7,7 @@ - +