diff --git a/LICENSE.md b/LICENSE.md index e69de29..877d652 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -0,0 +1,7 @@ +[![License: CC BY 4.0](https://licensebuttons.net/l/by/4.0/80x15.png)](https://creativecommons.org/licenses/by/4.0/) : 2019 -> Present + +Licensed by Hack Your Future Belgium: @HackYourFutureBelgium, https://hackyourfuture.be, contact@hackyourfuture.be + +___ +___ +### diff --git a/dependencies/prism/script.js b/dependencies/prism/script.js index a8782fb..0ddc38f 100644 --- a/dependencies/prism/script.js +++ b/dependencies/prism/script.js @@ -1,5 +1,6 @@ /* PrismJS 1.17.1 -https://prismjs.com/download.html#themes=prism-okaidia&languages=clike+javascript */ -var _self = "undefined" != typeof window ? window : "undefined" != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope ? self : {}, Prism = function (u) { var c = /\blang(?:uage)?-([\w-]+)\b/i, a = 0; var _ = { manual: u.Prism && u.Prism.manual, disableWorkerMessageHandler: u.Prism && u.Prism.disableWorkerMessageHandler, util: { encode: function (e) { return e instanceof L ? new L(e.type, _.util.encode(e.content), e.alias) : Array.isArray(e) ? e.map(_.util.encode) : e.replace(/&/g, "&").replace(/ e.length) return; if (!(k instanceof L)) { if (h && y != a.length - 1) { if (c.lastIndex = v, !(x = c.exec(e))) break; for (var b = x.index + (f && x[1] ? x[1].length : 0), w = x.index + x[0].length, A = y, P = v, O = a.length; A < O && (P < w || !a[A].type && !a[A - 1].greedy); ++A)(P += a[A].length) <= b && (++y, v = P); if (a[y] instanceof L) continue; j = A - y, k = e.slice(v, P), x.index -= v } else { c.lastIndex = 0; var x = c.exec(k), j = 1 } if (x) { f && (d = x[1] ? x[1].length : 0); w = (b = x.index + d) + (x = x[0].slice(d)).length; var N = k.slice(0, b), S = k.slice(w), C = [y, j]; N && (++y, v += N.length, C.push(N)); var E = new L(l, g ? _.tokenize(x, g) : x, m, x, h); if (C.push(E), S && C.push(S), Array.prototype.splice.apply(a, C), 1 != j && _.matchGrammar(e, a, n, y, v, !0, l + "," + u), i) break } else if (i) break } } } } }, tokenize: function (e, a) { var n = [e], r = a.rest; if (r) { for (var t in r) a[t] = r[t]; delete a.rest } return _.matchGrammar(e, n, a, 0, 0, !1), n }, hooks: { all: {}, add: function (e, a) { var n = _.hooks.all; n[e] = n[e] || [], n[e].push(a) }, run: function (e, a) { var n = _.hooks.all[e]; if (n && n.length) for (var r, t = 0; r = n[t++];)r(a) } }, Token: L }; function L(e, a, n, r, t) { this.type = e, this.content = a, this.alias = n, this.length = 0 | (r || "").length, this.greedy = !!t } if (u.Prism = _, L.stringify = function (e, a) { if ("string" == typeof e) return e; if (Array.isArray(e)) return e.map(function (e) { return L.stringify(e, a) }).join(""); var n = { type: e.type, content: L.stringify(e.content, a), tag: "span", classes: ["token", e.type], attributes: {}, language: a }; if (e.alias) { var r = Array.isArray(e.alias) ? e.alias : [e.alias]; Array.prototype.push.apply(n.classes, r) } _.hooks.run("wrap", n); var t = Object.keys(n.attributes).map(function (e) { return e + '="' + (n.attributes[e] || "").replace(/"/g, """) + '"' }).join(" "); return "<" + n.tag + ' class="' + n.classes.join(" ") + '"' + (t ? " " + t : "") + ">" + n.content + "" }, !u.document) return u.addEventListener && (_.disableWorkerMessageHandler || u.addEventListener("message", function (e) { var a = JSON.parse(e.data), n = a.language, r = a.code, t = a.immediateClose; u.postMessage(_.highlight(r, _.languages[n], n)), t && u.close() }, !1)), _; var e = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop(); if (e && (_.filename = e.src, e.hasAttribute("data-manual") && (_.manual = !0)), !_.manual) { function n() { _.manual || _.highlightAll() } "loading" !== document.readyState ? window.requestAnimationFrame ? window.requestAnimationFrame(n) : window.setTimeout(n, 16) : document.addEventListener("DOMContentLoaded", n) } return _ }(_self); "undefined" != typeof module && module.exports && (module.exports = Prism), "undefined" != typeof global && (global.Prism = Prism); -Prism.languages.clike = { comment: [{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0 }, { pattern: /(^|[^\\:])\/\/.*/, lookbehind: !0, greedy: !0 }], string: { pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: !0 }, "class-name": { pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i, lookbehind: !0, inside: { punctuation: /[.\\]/ } }, keyword: /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, boolean: /\b(?:true|false)\b/, function: /\w+(?=\()/, number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, operator: /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, punctuation: /[{}[\];(),.:]/ }; -Prism.languages.javascript = Prism.languages.extend("clike", { "class-name": [Prism.languages.clike["class-name"], { pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, lookbehind: !0 }], keyword: [{ pattern: /((?:^|})\s*)(?:catch|finally)\b/, lookbehind: !0 }, { pattern: /(^|[^.])\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, lookbehind: !0 }], number: /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/, function: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, operator: /--|\+\+|\*\*=?|=>|&&|\|\||[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|[~?:]/ }), Prism.languages.javascript["class-name"][0].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/, Prism.languages.insertBefore("javascript", "keyword", { regex: { pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=\s*($|[\r\n,.;})\]]))/, lookbehind: !0, greedy: !0 }, "function-variable": { pattern: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/, alias: "function" }, parameter: [{ pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, lookbehind: !0, inside: Prism.languages.javascript }, { pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i, inside: Prism.languages.javascript }, { pattern: /(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/, lookbehind: !0, inside: Prism.languages.javascript }, { pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/, lookbehind: !0, inside: Prism.languages.javascript }], constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/ }), Prism.languages.insertBefore("javascript", "string", { "template-string": { pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/, greedy: !0, inside: { "template-punctuation": { pattern: /^`|`$/, alias: "string" }, interpolation: { pattern: /((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/, lookbehind: !0, inside: { "interpolation-punctuation": { pattern: /^\${|}$/, alias: "punctuation" }, rest: Prism.languages.javascript } }, string: /[\s\S]+/ } } }), Prism.languages.markup && Prism.languages.markup.tag.addInlined("script", "javascript"), Prism.languages.js = Prism.languages.javascript; +https://prismjs.com/download.html#themes=prism-okaidia&languages=clike+javascript&plugins=line-numbers */ +var _self = "undefined" != typeof window ? window : "undefined" != typeof WorkerGlobalScope && self instanceof WorkerGlobalScope ? self : {}, Prism = function (u) { var c = /\blang(?:uage)?-([\w-]+)\b/i, r = 0; var _ = { manual: u.Prism && u.Prism.manual, disableWorkerMessageHandler: u.Prism && u.Prism.disableWorkerMessageHandler, util: { encode: function (e) { return e instanceof L ? new L(e.type, _.util.encode(e.content), e.alias) : Array.isArray(e) ? e.map(_.util.encode) : e.replace(/&/g, "&").replace(/ e.length) return; if (!(k instanceof L)) { if (d && y != r.length - 1) { if (c.lastIndex = v, !(O = c.exec(e))) break; for (var b = O.index + (f && O[1] ? O[1].length : 0), w = O.index + O[0].length, A = y, P = v, x = r.length; A < x && (P < w || !r[A].type && !r[A - 1].greedy); ++A)(P += r[A].length) <= b && (++y, v = P); if (r[y] instanceof L) continue; S = A - y, k = e.slice(v, P), O.index -= v } else { c.lastIndex = 0; var O = c.exec(k), S = 1 } if (O) { f && (h = O[1] ? O[1].length : 0); w = (b = O.index + h) + (O = O[0].slice(h)).length; var j = k.slice(0, b), N = k.slice(w), E = [y, S]; j && (++y, v += j.length, E.push(j)); var C = new L(l, g ? _.tokenize(O, g) : O, m, O, d); if (E.push(C), N && E.push(N), Array.prototype.splice.apply(r, E), 1 != S && _.matchGrammar(e, r, n, y, v, !0, l + "," + u), i) break } else if (i) break } } } } }, tokenize: function (e, r) { var n = [e], t = r.rest; if (t) { for (var a in t) r[a] = t[a]; delete r.rest } return _.matchGrammar(e, n, r, 0, 0, !1), n }, hooks: { all: {}, add: function (e, r) { var n = _.hooks.all; n[e] = n[e] || [], n[e].push(r) }, run: function (e, r) { var n = _.hooks.all[e]; if (n && n.length) for (var t, a = 0; t = n[a++];)t(r) } }, Token: L }; function L(e, r, n, t, a) { this.type = e, this.content = r, this.alias = n, this.length = 0 | (t || "").length, this.greedy = !!a } if (u.Prism = _, L.stringify = function (e, r) { if ("string" == typeof e) return e; if (Array.isArray(e)) return e.map(function (e) { return L.stringify(e, r) }).join(""); var n = { type: e.type, content: L.stringify(e.content, r), tag: "span", classes: ["token", e.type], attributes: {}, language: r }; if (e.alias) { var t = Array.isArray(e.alias) ? e.alias : [e.alias]; Array.prototype.push.apply(n.classes, t) } _.hooks.run("wrap", n); var a = Object.keys(n.attributes).map(function (e) { return e + '="' + (n.attributes[e] || "").replace(/"/g, """) + '"' }).join(" "); return "<" + n.tag + ' class="' + n.classes.join(" ") + '"' + (a ? " " + a : "") + ">" + n.content + "" }, !u.document) return u.addEventListener && (_.disableWorkerMessageHandler || u.addEventListener("message", function (e) { var r = JSON.parse(e.data), n = r.language, t = r.code, a = r.immediateClose; u.postMessage(_.highlight(t, _.languages[n], n)), a && u.close() }, !1)), _; var e = _.util.currentScript(); if (e && (_.filename = e.src, e.hasAttribute("data-manual") && (_.manual = !0)), !_.manual) { function n() { _.manual || _.highlightAll() } var t = document.readyState; "loading" === t || "interactive" === t && e && e.defer ? document.addEventListener("DOMContentLoaded", n) : window.requestAnimationFrame ? window.requestAnimationFrame(n) : window.setTimeout(n, 16) } return _ }(_self); "undefined" != typeof module && module.exports && (module.exports = Prism), "undefined" != typeof global && (global.Prism = Prism); +Prism.languages.clike = { comment: [{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0 }, { pattern: /(^|[^\\:])\/\/.*/, lookbehind: !0, greedy: !0 }], string: { pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, greedy: !0 }, "class-name": { pattern: /(\b(?:class|interface|extends|implements|trait|instanceof|new)\s+|\bcatch\s+\()[\w.\\]+/i, lookbehind: !0, inside: { punctuation: /[.\\]/ } }, keyword: /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, boolean: /\b(?:true|false)\b/, function: /\w+(?=\()/, number: /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i, operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, punctuation: /[{}[\];(),.:]/ }; +Prism.languages.javascript = Prism.languages.extend("clike", { "class-name": [Prism.languages.clike["class-name"], { pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/, lookbehind: !0 }], keyword: [{ pattern: /((?:^|})\s*)(?:catch|finally)\b/, lookbehind: !0 }, { pattern: /(^|[^.])\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, lookbehind: !0 }], number: /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/, function: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, operator: /--|\+\+|\*\*=?|=>|&&|\|\||[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?[.?]?|[~:]/ }), Prism.languages.javascript["class-name"][0].pattern = /(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/, Prism.languages.insertBefore("javascript", "keyword", { regex: { pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=\s*(?:$|[\r\n,.;})\]]))/, lookbehind: !0, greedy: !0 }, "function-variable": { pattern: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/, alias: "function" }, parameter: [{ pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/, lookbehind: !0, inside: Prism.languages.javascript }, { pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i, inside: Prism.languages.javascript }, { pattern: /(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/, lookbehind: !0, inside: Prism.languages.javascript }, { pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/, lookbehind: !0, inside: Prism.languages.javascript }], constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/ }), Prism.languages.insertBefore("javascript", "string", { "template-string": { pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/, greedy: !0, inside: { "template-punctuation": { pattern: /^`|`$/, alias: "string" }, interpolation: { pattern: /((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/, lookbehind: !0, inside: { "interpolation-punctuation": { pattern: /^\${|}$/, alias: "punctuation" }, rest: Prism.languages.javascript } }, string: /[\s\S]+/ } } }), Prism.languages.markup && Prism.languages.markup.tag.addInlined("script", "javascript"), Prism.languages.js = Prism.languages.javascript; +!function () { if ("undefined" != typeof self && self.Prism && self.document) { var l = "line-numbers", c = /\n(?!$)/g, m = function (e) { var t = a(e)["white-space"]; if ("pre-wrap" === t || "pre-line" === t) { var n = e.querySelector("code"), r = e.querySelector(".line-numbers-rows"), s = e.querySelector(".line-numbers-sizer"), i = n.textContent.split(c); s || ((s = document.createElement("span")).className = "line-numbers-sizer", n.appendChild(s)), s.style.display = "block", i.forEach(function (e, t) { s.textContent = e || "\n"; var n = s.getBoundingClientRect().height; r.children[t].style.height = n + "px" }), s.textContent = "", s.style.display = "none" } }, a = function (e) { return e ? window.getComputedStyle ? getComputedStyle(e) : e.currentStyle || null : null }; window.addEventListener("resize", function () { Array.prototype.forEach.call(document.querySelectorAll("pre." + l), m) }), Prism.hooks.add("complete", function (e) { if (e.code) { var t = e.element, n = t.parentNode; if (n && /pre/i.test(n.nodeName) && !t.querySelector(".line-numbers-rows")) { for (var r = !1, s = /(?:^|\s)line-numbers(?:\s|$)/, i = t; i; i = i.parentNode)if (s.test(i.className)) { r = !0; break } if (r) { t.className = t.className.replace(s, " "), s.test(n.className) || (n.className += " line-numbers"); var l, a = e.code.match(c), o = a ? a.length + 1 : 1, u = new Array(o + 1).join(""); (l = document.createElement("span")).setAttribute("aria-hidden", "true"), l.className = "line-numbers-rows", l.innerHTML = u, n.hasAttribute("data-start") && (n.style.counterReset = "linenumber " + (parseInt(n.getAttribute("data-start"), 10) - 1)), e.element.appendChild(l), m(n), Prism.hooks.run("line-numbers", e) } } } }), Prism.hooks.add("line-numbers", function (e) { e.plugins = e.plugins || {}, e.plugins.lineNumbers = !0 }), Prism.plugins.lineNumbers = { getLine: function (e, t) { if ("PRE" === e.tagName && e.classList.contains(l)) { var n = e.querySelector(".line-numbers-rows"), r = parseInt(e.getAttribute("data-start"), 10) || 1, s = r + (n.children.length - 1); t < r && (t = r), s < t && (t = s); var i = t - r; return n.children[i] } } } } }(); diff --git a/dependencies/prism/style.css b/dependencies/prism/style.css index af3bbad..cedea10 100644 --- a/dependencies/prism/style.css +++ b/dependencies/prism/style.css @@ -1,5 +1,5 @@ /* PrismJS 1.17.1 -https://prismjs.com/download.html#themes=prism-okaidia&languages=clike+javascript */ +https://prismjs.com/download.html#themes=prism-okaidia&languages=clike+javascript&plugins=line-numbers */ /** * okaidia theme for JavaScript, CSS and HTML * Loosely based on Monokai textmate theme by http://www.monokai.nl/ @@ -124,3 +124,45 @@ pre[class*="language-"] { cursor: help; } +pre[class*="language-"].line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} + +pre[class*="language-"].line-numbers > code { + position: relative; + white-space: inherit; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + border-right: 1px solid #999; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + +} + + .line-numbers-rows > span { + pointer-events: none; + display: block; + counter-increment: linenumber; + } + + .line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; + } + diff --git a/dependencies/toString.js b/dependencies/toString.js index ea80a88..979392c 100644 --- a/dependencies/toString.js +++ b/dependencies/toString.js @@ -1,3 +1,5 @@ +// ** doesn't do nicely with lots of comments in a method + /* opinionated & lazy formatting assumes double-spaced indentation diff --git a/week-1-project/app.js b/week-1-project/app.js index fd5f1e0..5fdfbea 100644 --- a/week-1-project/app.js +++ b/week-1-project/app.js @@ -34,7 +34,7 @@ const object = { // write me! }, sumOfNumbery: function () { - // write me! + // write me! (using a Array.prototype.reduce()) }, sumOfNaNy: function () { // write me! diff --git a/week-1-project/index.html b/week-1-project/index.html index 3de938b..55a6cd3 100644 --- a/week-1-project/index.html +++ b/week-1-project/index.html @@ -46,18 +46,20 @@

Week 1 Project

diff --git a/week-1-project/practice-problems/arrays.js b/week-1-project/practice-problems/arrays.js index c5add90..9342ce9 100644 --- a/week-1-project/practice-problems/arrays.js +++ b/week-1-project/practice-problems/arrays.js @@ -1,4 +1,4 @@ -// https://www.youtube.com/watch?v=W1NTK09o-vM&list=PLzV58Zm8FuBJFfQN5il3ujx6FDAY8Ds3u&index=4 +// https://www.youtube.com/watch?v=W1NTK09o-vM&list=PLzV58Zm8FuBJFfQN5il3ujx6FDAY8Ds3u&index=4 // https://medium.com/@naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600 { @@ -35,6 +35,7 @@ try { // to create a new array in memory, you must write new square brackets + // (or call an array method that returns a copy, more on that later) const array3 = []; // reassigning object2 will make it point to ... array2 = array3; diff --git a/week-2-project/README.md b/week-2-project/README.md index 4591553..abad0a2 100644 --- a/week-2-project/README.md +++ b/week-2-project/README.md @@ -1,19 +1,60 @@ -practice problems -- -- -- -- - -app object -- -- -- -- -- - -user interface -- -- -- -- -- + +## Week 2 Project + + + +The weekly projects in JS 2 will be making an even stronger distinction between your core application and the user interface. To help you with this transition there will be two assignment tables, one for the core app object and another for the user interface. + + + +What you should notice and think about is that there is not a perfect 1-1 pairing between user stories (what is seen on the screen) and the core object (the software that makes the UI possible). Some User Stories are all about the UI/UX and don't require any changes in the core object, while some methods in the core object have no direct representation in the UI. + + + +--- + + + +### Core Object + + + +> this table is written like documentation + + + + +| __it should ...__ | __syntax__ | __parameters__ | __return value__ | __description__ | +| --- | --- | --- | --- | --- | +| _... determines if values are primitive or not_ | ```obj.isPrimitive(value)``` | _value_: any JS value | Boolean | It returns ```true``` if the argument is a primitive, otherwise it returns ```false```. | +| _... determines if an object has a given key_ | ```obj.hasKey(obj, key)``` | _obj_: an object
_key_: a string | Boolean | It returns ```true``` if the object has the given key, otherwise it returns ```false```. | +| _... determines if an object has a given value_ | ```obj.hasValue(obj, value)``` | _obj_: an object
_value_: any JS type | Boolean | It returns ```true``` if any key in the object stores this value, otherwise it returns ```false```. | +| _... adds key/value pairs to ```this.entries```_ | ```obj.addEntry(key, value)``` | _key_: a string
_value_: any primitive value | ```true``` or an error | It returns ```true``` if the key/value pair was successfully added, otherwise it returns helpful error describing what went wrong. | +| _... removes a key/value pair from ```this.entries```_ | ```obj.removeEntry(key)``` | _key_: a string | ```true``` or an error | It returns ```true``` if the key/value pair was successfully removed, otherwise it returns helpful error describing what went wrong. | +| _... updates a key/value pair in ```this.entries```_ | ```obj.updateEntry(key, value)``` | _key_: a string
_value_: any primitive type | ```true``` or an error | It returns ```true``` if the key/value pair was successfully updated, otherwise it returns helpful error describing what went wrong. | +| _... returns all key/value pairs in ```this.entries```_ | ```obj.readAll()``` | (no parameters) | an object | a new object with the same key/value pairs as ```this.entries``` | +| _... finds an entry by key_ | ```obj.findByKey(key)``` | _key_: a string | an object or an error | It returns an object with the given key, and it's value in ```this.entries```. Or a helpful error | +| _... finds an entry by value | ```obj.findByValue(value)``` | _value_: a primitive | an object or an error | It returns an object with all key/value pairs in ```this.entries``` containing the given value. Or a helpful error | + + + +--- + + + +### User Interface + + + +> this table is written as user stories + + + +| __As a/n__ ... | __I can__ ... | __so that__ ... | +| --- | --- | --- | +| _... enthusiastic JS student_ | ... know what this site does and how to use it | ... I can use it to organize my favorite primitive values | +| _... enthusiastic JS student_ | ... set input new keys and primitive values | ... I can practice always being aware of what types _and_ values my application stores | +| _... enthusiastic JS student_ | ... select a method to call with my inputs | ... modify the values stored in this app, and search for particular entries | +| _... enthusiastic JS student_ | ... see the values stored in ```this.entries``` rendered to the DOM | ... I can easily know what is stored in the app without console.logging | +| _... HYF coach_ | ... resize the browser window | ... I can test your responsive design | +| _... HYF coach_ | ... inspect the web page | ... I can see if you correctly used HTML5 semantic elements, CSS classes, and generally wrote clean code | diff --git a/week-2-project/app.js b/week-2-project/app.js index 81aeeae..90e883b 100644 --- a/week-2-project/app.js +++ b/week-2-project/app.js @@ -8,6 +8,9 @@ - and users can access & modify that data */ + + + const object = { entries: {}, isPrimitive: function (value) { @@ -27,7 +30,7 @@ const object = { return new TypeError('addEntry: value should be a primitive'); } if (null) { // write me! (using this.hasKey) - return { [key]: new Error(`addEntry: key "${key}" already exists`) }; + return new Error(`addEntry: key "${key}" already exists`); } // write me! @@ -37,9 +40,11 @@ const object = { return new TypeError('removeEntry: key should be a string'); } if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`removeEntry: no property "${key}" in this.entries`) }; + return new ReferenceError(`removeEntry: no property "${key}" in this.entries`); } + delete this.entries[key] + return true // write me! }, updateEntry: function (key, value) { @@ -50,7 +55,7 @@ const object = { return new TypeError('updateEntry: value should be a primitive'); } if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`updateEntry: no property "${key}" in this.entries`) }; + return new ReferenceError(`updateEntry: no property "${key}" in this.entries`); } // write me! @@ -63,7 +68,7 @@ const object = { return new TypeError('findByKey: key should be a string'); } if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`findByKey: no property "${key}" in this.entries`) }; + return new ReferenceError(`findByKey: no property "${key}" in this.entries`); } // write me! diff --git a/week-2-project/index.html b/week-2-project/index.html index e559c32..f4e68c4 100644 --- a/week-2-project/index.html +++ b/week-2-project/index.html @@ -45,18 +45,20 @@

Week 2 Project

diff --git a/week-2-project/practice-problems/arrays-vs-objects.js b/week-2-project/practice-problems/arrays-vs-objects.js index 4a7e82c..35261ea 100644 --- a/week-2-project/practice-problems/arrays-vs-objects.js +++ b/week-2-project/practice-problems/arrays-vs-objects.js @@ -35,8 +35,8 @@ try { // asserts - console.assert(obj[obj_key] === "object", "obj assert"); - console.assert(arr[arr_index] === "array", "arr assert"); + console.assert(obj[objKey] === "object", "obj assert"); + console.assert(arr[arrIndex] === "array", "arr assert"); } evaluate(swapValues2); diff --git a/week-2-project/practice-problems/index.html b/week-2-project/practice-problems/index.html index 3b4bfc6..48a7c5f 100644 --- a/week-2-project/practice-problems/index.html +++ b/week-2-project/practice-problems/index.html @@ -22,8 +22,11 @@ - + + + +
diff --git a/week-2-project/practice-problems/objects.js b/week-2-project/practice-problems/objects.js index 003bc42..be4dbb3 100644 --- a/week-2-project/practice-problems/objects.js +++ b/week-2-project/practice-problems/objects.js @@ -1,5 +1,6 @@ // https://medium.com/@naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600 // https://www.youtube.com/watch?v=Z_ozyN5MyWY&list=PLzV58Zm8FuBJFfQN5il3ujx6FDAY8Ds3u&index=5 +// http://javascript.info/object { const pageTitle = 'objects'; @@ -114,22 +115,22 @@ try { function passTheAssertions1() { - ; // declare and assign a1 - ; // declare and assign a2 + const a1 = {}; // declare and assign a1 + const a2 = a1; // declare and assign a2 console.assert(a1 === a2, 'a1 should strictly equal a2'); - ; // declare and assign b1 - ; // declare and assign b2 + const b1 = {}; // declare and assign b1 + const b2 = {}; // declare and assign b2 console.assert(b1 !== b2, 'b1 should not strictly equal b2'); // --- - ; // write one line to pass the assertions + a1.x = 'hi!'; // write one line to pass the assertions console.assert(a1.x === a2.x, 'a1.x should strictly equal a2.x'); console.assert(a1.x === 'hi!', 'a1.x should strictly equal "hi!"'); - ; // write two lines to pass the assertions - ; + b1.x = 'bye!'; // write two lines to pass the assertions + b2.x = 'bye!'; console.assert(b1.x === b2.x, 'b1.x should strictly equal b2.x'); console.assert(b1.x === 'bye!', 'b1.x should strictly equal "bye!"'); diff --git a/week-2-project/tests/add-entry.js b/week-2-project/tests/add-entry.js index 47914e6..a0987f7 100644 --- a/week-2-project/tests/add-entry.js +++ b/week-2-project/tests/add-entry.js @@ -30,8 +30,8 @@ describe(`addEntry: should add a new key/value pair to this.entries`, () => { ['firstKey', 'secondKey', 'thirdKey', 'fourthKey'].forEach(arg => { it(`${arg}`, () => { const result = object.addEntry(arg, ''); - assert.ok(result[arg] instanceof Error); - assert.strictEqual(result[arg].message, `addEntry: key "${arg}" already exists`); + assert.ok(result instanceof Error); + assert.strictEqual(result.message, `addEntry: key "${arg}" already exists`); }); }); }); diff --git a/week-2-project/tests/find-by-key.js b/week-2-project/tests/find-by-key.js index 183cafe..1916184 100644 --- a/week-2-project/tests/find-by-key.js +++ b/week-2-project/tests/find-by-key.js @@ -21,8 +21,8 @@ describe(`findByKey: returns the requested key/value pair, or an informative err ['a', 'b', 'c', 'd'].forEach(arg => { it(`${arg}`, () => { const result = object.findByKey(arg); - assert.ok(result[arg] instanceof ReferenceError); - assert.strictEqual(result[arg].message, `findByKey: no property "${arg}" in this.entries`); + assert.ok(result instanceof ReferenceError); + assert.strictEqual(result.message, `findByKey: no property "${arg}" in this.entries`); }); }); }); diff --git a/week-2-project/tests/find-by-value.js b/week-2-project/tests/find-by-value.js index 5042fcc..457a7af 100644 --- a/week-2-project/tests/find-by-value.js +++ b/week-2-project/tests/find-by-value.js @@ -37,18 +37,26 @@ describe(`findByValue: returns the requested key/value pair, or an informative e ['secondValue', { secondKey: 'secondValue' }], ['thirdValue', { thirdKey: 'thirdValue' }], ].forEach(arg => { - it(`it finds the correct key for ${arg[0]}`, () => { + it(`it returns the correct entry for value : ${arg[0]}`, () => { const result = object.findByValue(arg[0]); assert.deepStrictEqual(result, arg[1]); }); }); - it(`it finds all keys containing "fourthValue"`, () => { + it(`it finds all keys containing "fourthValue ... "`, () => { const result = object.findByValue('fourthValue'); - assert.deepStrictEqual(Object.keys(result), ['fourthKey', 'fifthKey', 'sixthKey']); + assert.deepStrictEqual(result, { + 'fourthKey': 'fourthValue', + 'fifthKey': 'fourthValue', + 'sixthKey': 'fourthValue' + }); }); - it(`and all keys containing "fifthValue"`, () => { + it(`... and all keys containing "fifthValue"`, () => { const result = object.findByValue('fifthValue'); - assert.deepStrictEqual(Object.keys(result), ['seventhKey', 'eighthKey', 'ninthKey']); + assert.deepStrictEqual(result, { + 'seventhKey': 'fifthValue', + 'eighthKey': 'fifthValue', + 'ninthKey': 'fifthValue' + }); }); }); }); diff --git a/week-2-project/tests/has-key.js b/week-2-project/tests/has-key.js index 7388df3..62184f1 100644 --- a/week-2-project/tests/has-key.js +++ b/week-2-project/tests/has-key.js @@ -35,7 +35,18 @@ describe(`hasKey: determines if an object has a given key`, () => { }); }); describe(`and returns false for non-existant entries.`, () => { - ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty'].forEach(arg => { + ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty', ''].forEach(arg => { + it(arg, () => { + const result = object.hasKey(object.entries, arg); + assert.strictEqual(result, false); + }); + }); + }); + describe(`or when there are no entries!`, () => { + before(() => { + object.entries = {}; + }); + ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty', ''].forEach(arg => { it(arg, () => { const result = object.hasKey(object.entries, arg); assert.strictEqual(result, false); diff --git a/week-2-project/tests/has-value.js b/week-2-project/tests/has-value.js index 8e9c4fa..b86416e 100644 --- a/week-2-project/tests/has-value.js +++ b/week-2-project/tests/has-value.js @@ -42,4 +42,16 @@ describe(`hasValue: determines if an object has a given value`, () => { }); }); }); + describe(`even when there are no entries!`, () => { + before(() => { + object.entries = {}; + }); + ['tomato', null, true, undefined, 4].forEach(arg => { + const argString = typeof arg === 'string' ? '"' + arg + '"' : String(arg); + it(argString, () => { + const result = object.hasValue(object.entries, arg); + assert.strictEqual(result, false); + }); + }); + }); }); diff --git a/week-2-project/tests/remove-entry.js b/week-2-project/tests/remove-entry.js index 17e22c5..8a14f0c 100644 --- a/week-2-project/tests/remove-entry.js +++ b/week-2-project/tests/remove-entry.js @@ -21,8 +21,8 @@ describe(`removeEntry: should remove a key/value pair from this.entries`, () => ['tomato', 'potato', 'patate', 'pomme de terre'].forEach(arg => { it(`${arg}`, () => { const result = object.removeEntry(arg); - assert.ok(result[arg] instanceof Error); - assert.strictEqual(result[arg].message, `removeEntry: no property "${arg}" in this.entries`); + assert.ok(result instanceof Error); + assert.strictEqual(result.message, `removeEntry: no property "${arg}" in this.entries`); }); }); }); @@ -38,7 +38,7 @@ describe(`removeEntry: should remove a key/value pair from this.entries`, () => describe(`... and actually removes the entries!`, () => { valuesToRemove.forEach(arg => { it(`object.hasKey(object.entries, ${arg}) === false`, () => { - assert.strictEqual(object.hasKey(object.entries, arg), false); + assert.strictEqual(object.entries.hasOwnProperty(arg), false); }); }); }); diff --git a/week-2-project/tests/update-entry.js b/week-2-project/tests/update-entry.js index fd9870f..f670fa0 100644 --- a/week-2-project/tests/update-entry.js +++ b/week-2-project/tests/update-entry.js @@ -30,8 +30,8 @@ describe(`updateEntry: should add a new key/value pair to this.entries`, () => { ['tomato', 'potato', 'patate', 'pomme'].forEach(arg => { it(`${arg}`, () => { const result = object.updateEntry(arg, ''); - assert.ok(result[arg] instanceof ReferenceError); - assert.strictEqual(result[arg].message, `updateEntry: no property "${arg}" in this.entries`); + assert.ok(result instanceof ReferenceError); + assert.strictEqual(result.message, `updateEntry: no property "${arg}" in this.entries`); }); }); }); diff --git a/week-3-project/README.md b/week-3-project/README.md index 4591553..6850231 100644 --- a/week-3-project/README.md +++ b/week-3-project/README.md @@ -1,19 +1,61 @@ -practice problems -- -- -- -- - -app object -- -- -- -- -- - -user interface -- -- -- -- -- + +## Week 3 Project + + + +This project builds directly from last week's, so the tables below are pretty big but there actually less to build than last week! + + +--- + + + +### Core Object + + + +> this table is written like documentation + + + + +| __it should ...__ | __syntax__ | __parameters__ | __return value__ | __description__ | +| --- | --- | --- | --- | --- | +| _... set the the current key_| ```obj.currentEntry = key;``` | _key_: a string | ```true``` if the key is valid, otherwise throws an error | this setter will save the ```key``` as the currentKey if it is a string, and if ```this.entries``` has that key. otherwise it throws a helpful error | +| _... get the the current entry_| ```const entry = obj.currentEntry;``` | (none) | an object with one property: ```{key:value}```. key is the currentKey, and value is the value in ```this.entries``` or a helpful error | this getter allows you to always have access to an up-to-date value for ```this.currentKey```. If a user deletes that entry but doesn't reset the ```currentEntry```, no problem! | +| _... get an object with all the liked entries_| ```const likedEntries = obj.likedEntries``` | (none) | an Object with all liked entries | this getter will return an object with all the entries in ```this.entries``` matching the keys in ```this.likedKeys```. If an entry has been removed, the return value will have a helpful error | +| _... like entries_| ```obj.likeEntry(key)``` | _key_: a string | ```true``` if the key is valid, otherwise returns an error | it will push the key into ```this.likedKeys``` if it is valid, otherwise returns an error | +| _... unlike entries_| ```obj.unlikeEntry(key)``` | _key_: a string | ```true``` if the key is valid and already liked, otherwise returns an error | if the key is valid, and is in ```this.likedEntries``` it will be removed from the array. otherwise a helpful error is returned | +| _... determines if values are primitive or not_ | ```obj.isPrimitive(value)``` | _value_: any JS value | Boolean | It returns ```true``` if the argument is a primitive, otherwise it returns ```false```. | +| _... determines if an object has a given key_ | ```obj.hasKey(obj, key)``` | _obj_: an object
_key_: a string | Boolean | It returns ```true``` if the object has the given key, otherwise it returns ```false```. | +| _... determines if an object has a given value_ | ```obj.hasValue(obj, value)``` | _obj_: an object
_value_: any JS type | Boolean | It returns ```true``` if any key in the object stores this value, otherwise it returns ```false```. | +| _... adds key/value pairs to ```this.entries```_ | ```obj.addEntry(key, value)``` | _key_: a string
_value_: any primitive value | ```true``` or an error | It returns ```true``` if the key/value pair was successfully added, otherwise it returns helpful error describing what went wrong. | +| _... removes a key/value pair from ```this.entries```_ | ```obj.removeEntry(key)``` | _key_: a string | ```true``` or an error | It returns ```true``` if the key/value pair was successfully removed, otherwise it returns helpful error describing what went wrong. | +| _... updates a key/value pair in ```this.entries```_ | ```obj.updateEntry(key, value)``` | _key_: a string
_value_: any primitive type | ```true``` or an error | It returns ```true``` if the key/value pair was successfully updated, otherwise it returns helpful error describing what went wrong. | +| _... returns all key/value pairs in ```this.entries```_ | ```obj.readAll()``` | (no parameters) | an object | a new object with the same key/value pairs as ```this.entries``` | +| _... finds an entry by key_ | ```obj.findByKey(key)``` | _key_: a string | an object or an error | It returns an object with the given key, and it's value in ```this.entries```. Or a helpful error | +| _... finds an entry by value | ```obj.findByValue(value)``` | _value_: a primitive | an object or an error | It returns an object with all key/value pairs in ```this.entries``` containing the given value. Or a helpful error | + + + +--- + + + +### User Interface + + + +> this table is written as user stories. notice that users can't set or get the current entry! + + + +| __As a/n__ ... | __I can__ ... | __so that__ ... | +| --- | --- | --- | +| _... user_ | ... remember which entries were most interesting | ... I can study more effectively over long periods of time | +| _... enthusiastic JS student_ | ... know what this site does and how to use it | ... I can use it to organize my favorite primitive values | +| _... enthusiastic JS student_ | ... set input new keys and primitive values | ... I can practice always being aware of what types _and_ values my application stores | +| _... enthusiastic JS student_ | ... select a method to call with my inputs | ... modify the values stored in this app, and search for particular entries | +| _... enthusiastic JS student_ | ... see the values stored in ```this.entries``` rendered to the DOM | ... I can easily know what is stored in the app without console.logging | +| _... HYF coach_ | ... resize the browser window | ... I can test your responsive design | +| _... HYF coach_ | ... inspect the web page | ... I can see if you correctly used HTML5 semantic elements, CSS classes, and generally wrote clean code | diff --git a/week-3-project/app.js b/week-3-project/app.js index 4320ac7..b4fe84f 100644 --- a/week-3-project/app.js +++ b/week-3-project/app.js @@ -1,12 +1,10 @@ - - const object = { currentKey: '', set currentEntry(key) { - if (null) { // write this early return condition! + if (null) { // write the early return condition throw new TypeError('set currentEntry: key should be a string'); } - if (null) { // write this early return condition! (using this.hasKey) + if (null) { // write the early return condition throw new ReferenceError(`set currentEntry: no entry with key "${key}"`); } @@ -14,43 +12,35 @@ const object = { }, get currentEntry() { // write me! - // consider using this.findByKey & this.currentKey }, likedKeys: [], get likedEntries() { + // write me! - // consider using .map & this.findByKey, then .reduce & Object.assign - // this can be done in two steps: - // first, build an array of all the liked entries (this.findByKey) - // second, build a single object containing all of the liked entries }, likeEntry: function (key) { - if (null) { // write this early-return condition! + if (null) { // write the early return condition return new TypeError('likeEntry: key should be a string'); } - if (null) { // write this early-return condition! (using this.hasKey) + if (null) { // write the early return condition return new ReferenceError(`likeEntry: key "${key}" has been removed`); } - if (null) { // write this early-return condition! (using .every()) + if (null) { // write the early return condition return new Error(`likeEntry: key "${key}" is already liked`); } // write me! }, unlikeEntry: function (key) { - if (null) { // write this early-return condition! + if (null) { // write the early return condition return new TypeError('unlikeEntry: key should be a string'); } - if (null) { // write this early-return condition! (using .every()) + if (null) { // write the early return condition return new Error(`unlikeEntry: key "${key}" is not in this.likedKeys`); } // write me! - // consider using .filter }, - - // everything below here is the same as last week's project - // this week's project will build on top of last week's entries: {}, isPrimitive: function (value) { // write me! @@ -62,62 +52,22 @@ const object = { // write me! }, addEntry: function (key, value) { - if (null) { // write me! - return new TypeError('addEntry: key should be a string'); - } - if (null) { // write me! (using this.isPrimitive) - return new TypeError('addEntry: value should be a primitive'); - } - if (null) { // write me! (using this.hasKey) - return { [key]: new Error(`addEntry: key "${key}" already exists`) }; - } - // write me! }, removeEntry: function (key) { - if (null) { // write me! - return new TypeError('removeEntry: key should be a string'); - } - if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`removeEntry: no property "${key}" in this.entries`) }; - } - // write me! }, updateEntry: function (key, value) { - if (null) { // write me! - return new TypeError('updateEntry: key should be a string'); - } - if (null) { // write me! (using this.isPrimitive) - return new TypeError('updateEntry: value should be a primitive'); - } - if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`updateEntry: no property "${key}" in this.entries`) }; - } - // write me! }, readAll: function () { // write me! }, findByKey: function (key) { - if (null) { // write me! - return new TypeError('findByKey: key should be a string'); - } - if (null) { // write me! (using this.hasKey) - return { [key]: new ReferenceError(`findByKey: no property "${key}" in this.entries`) }; - } - // write me! }, findByValue: function (value) { - if (null) { // write me! (using this.isPrimitive) - return new TypeError('findByValue: value should be a primitive'); - } - if (null) { // write me! (using this.hasValue) - return new ReferenceError(`findByValue: no entry with value (${typeof value}, ${value})`); - } - // write me! }, } + diff --git a/week-3-project/index.html b/week-3-project/index.html index 3105d68..344e85a 100644 --- a/week-3-project/index.html +++ b/week-3-project/index.html @@ -18,10 +18,10 @@ - + - + @@ -30,7 +30,7 @@
-

Week 2 Project

+

Week 3 Project

@@ -42,21 +42,24 @@

Week 2 Project

-
+
diff --git a/week-3-project/practice-problems/arrays-vs-objects.js b/week-3-project/practice-problems/arrays-vs-objects.js index 4a7e82c..35261ea 100644 --- a/week-3-project/practice-problems/arrays-vs-objects.js +++ b/week-3-project/practice-problems/arrays-vs-objects.js @@ -35,8 +35,8 @@ try { // asserts - console.assert(obj[obj_key] === "object", "obj assert"); - console.assert(arr[arr_index] === "array", "arr assert"); + console.assert(obj[objKey] === "object", "obj assert"); + console.assert(arr[arrIndex] === "array", "arr assert"); } evaluate(swapValues2); diff --git a/week-3-project/practice-problems/error-based-decisions.js b/week-3-project/practice-problems/error-based-decisions.js new file mode 100644 index 0000000..f0b2f66 --- /dev/null +++ b/week-3-project/practice-problems/error-based-decisions.js @@ -0,0 +1,124 @@ +{ + const pageTitle = 'error-based decisions'; + const header = document.createElement("h2"); + header.innerHTML = pageTitle; + document.body.appendChild(header); + console.groupCollapsed(pageTitle); +} + +try { + + + /* this function is meant to be confusing, no need to understand it! + the point of these exercises is to learn how to work with functions that return errors + you can (and often will!) have to work with functions that return errors + ... without understanding what they do! + */ + const mightReturnAnError = a => "object" == typeof a + ? a instanceof Object + ? (() => { try { return a(), !0 } catch (a) { return new Error('second error') } })() + : new Error('first error') + : +a === +a || new Error('third error'); + + + const exercise1Tests = [ + { name: 'first', args: [-5], expected: true }, + { name: 'second', args: [null], expected: false }, + { name: 'third', args: [undefined], expected: false }, + { name: 'fourth', args: [true], expected: true }, + { name: 'fifth', args: [['second error']], expected: false }, + { name: 'sixth', args: [{ a: 'x' }], expected: false }, + { name: 'seventh', args: [() => { }], expected: false }, + { name: 'eighth', args: ['13'], expected: true }, + { name: 'ninth', args: ['second error'], expected: false }, + ] + function exercise1(arg) { + const result = mightReturnAnError(arg); + + if (null) { // write this condition + // write me! + } else { + // write me! + } + + } + exercise1.display = true; + evaluate(exercise1, exercise1Tests); + + + const exercise2Tests = [ + { name: 'first', args: [4], expected: 4 }, + { name: 'second', args: [null], expected: 'first error' }, + { name: 'third', args: [undefined], expected: 'third error' }, + { name: 'fourth', args: [false], expected: false }, + { name: 'fifth', args: [[]], expected: 'second error' }, + { name: 'sixth', args: [{}], expected: 'second error' }, + { name: 'seventh', args: [function () { }], expected: 'third error' }, + { name: 'eighth', args: ['4'], expected: '4' }, + { name: 'ninth', args: ['e'], expected: 'third error' }, + ] + function exercise2(arg) { + const result = mightReturnAnError(arg); + + // write me! + + } + exercise2.display = true; + evaluate(exercise2, exercise2Tests); + + + + const exercise3Tests = [ + { name: 'first', args: [4], expected: { number: 4 } }, + { name: 'second', args: [null], expected: { object: 'first error' } }, + { name: 'third', args: [undefined], expected: { 'undefined': 'third error' } }, + { name: 'fourth', args: [false], expected: { 'boolean': false } }, + { name: 'fifth', args: [[]], expected: { object: 'second error' } }, + { name: 'sixth', args: [{}], expected: { object: 'second error' } }, + { name: 'seventh', args: [function () { }], expected: { 'function': 'third error' } }, + { name: 'eighth', args: ['4'], expected: { string: '4' } }, + { name: 'ninth', args: ['e'], expected: { string: 'third error' } }, + ] + function exercise3(arg) { + const result = mightReturnAnError(arg); + + // write me! + + } + exercise3.display = true; + evaluate(exercise3, exercise3Tests); + + + const exercise4Tests = [ + { name: 'first', args: [4], expected: [null, 4] }, + { name: 'second', args: [null], expected: ['first error'] }, + { name: 'third', args: [undefined], expected: ['third error'] }, + { name: 'fourth', args: [false], expected: [null, false] }, + { name: 'fifth', args: [[]], expected: ['second error'] }, + { name: 'sixth', args: [{}], expected: ['second error'] }, + { name: 'seventh', args: [function () { }], expected: ['third error'] }, + { name: 'eighth', args: ['4'], expected: [null, '4'] }, + { name: 'ninth', args: ['e'], expected: ['third error'] }, + ] + function exercise4(arg) { + const result = mightReturnAnError(arg); + + // write me! + + } + exercise4.display = true; + evaluate(exercise4, exercise4Tests); + + + +} catch (err) { + console.log(err); + document.body.appendChild( + evaluate.errorSearchComponent('.js file', err) + ); +} + +{ + console.groupEnd(); + document.body.appendChild(document.createElement('hr')); +} diff --git a/week-3-project/practice-problems/getters-and-setters.js b/week-3-project/practice-problems/getters-and-setters.js index 68671d0..c5f2609 100644 --- a/week-3-project/practice-problems/getters-and-setters.js +++ b/week-3-project/practice-problems/getters-and-setters.js @@ -15,7 +15,7 @@ try { - function example_refactorMethodToGetter() { + function getterRefactor1() { const obj1 = { name: 'obj1', @@ -24,27 +24,211 @@ try { } } - console.assert(obj1.getGreeting() === `hi, I'm obj1`, 'assert 1'); - obj1.name = 'brussels' - console.assert(obj1.getGreeting() === `hi, I'm brussels`, 'assert 2'); - const obj2 = { name: 'obj2', get greeting() { - return `hi, I'm ${this.name}`; + // write me! } } - console.assert(obj2.greeting === `hi, I'm obj2`, 'assert 3'); - obj2.name = 'belgium' - console.assert(obj2.greeting === `hi, I'm belgium`, 'assert 4'); + const obj1Greeting1 = obj1.getGreeting(); + console.assert(obj1Greeting1 === `hi, I'm obj1`, `obj1's greeting is correct (1)`); + + const obj2Greeting1 = null; // fix this line! + console.assert(obj2Greeting1 === `hi, I'm obj2`, `obj2's greeting is correct (1)`); + + obj1.name = "first"; + obj2.name = "second"; + + const obj1Greeting2 = obj1.getGreeting(); + console.assert(obj1Greeting2 === `hi, I'm first`, `obj1's greeting is correct (2)`); + + const obj2Greeting2 = null; // fix this line! + console.assert(obj2Greeting2 === `hi, I'm second`, `obj2's greeting is correct (2)`); + + } + getterRefactor1.display = true; + evaluate(getterRefactor1); + + + function getterRefactor2() { + + const obj1 = { + numbers: [12, 4, 9, 36, 7, 0, -2], + modulo: 3, + getZeroMods: function () { + return this.numbers.filter(x => x % this.modulo === 0); + } + } + + const obj2 = { + numbers: [12, 4, 9, 36, 7, 0, -2], + modulo: 3, + get zeroMods() { + // write me! + } + } + + const obj1mods3 = null; + console.assert(obj1mods3[0] === 12, 'assert 1'); + console.assert(obj1mods3[1] === 9, 'assert 2'); + console.assert(obj1mods3[2] === 36, 'assert 3'); + + const obj2mods3 = null; + console.assert(obj2mods3[0] === 12, 'assert 4'); + console.assert(obj2mods3[1] === 9, 'assert 5'); + console.assert(obj2mods3[2] === 36, 'assert 6'); + + + obj1.modulo = 6; + obj2.modulo = 6; + + const obj1mods3second = null; + console.assert(obj1mods3second[0] === 12, 'assert 7'); + console.assert(obj1mods3second[1] === 36, 'assert 8'); + + const obj2mods3second = null; + console.assert(obj2mods3second[0] === 12, 'assert 9'); + console.assert(obj2mods3second[1] === 36, 'assert 10'); + + } + getterRefactor2.display = true; + evaluate(getterRefactor2); + + + function getterRefactor3() { + + const obj1 = { + entries: { first: 'hi!', second: 'bye!' }, + currentKey: 'second', + getCurrentEntry: function () { + return this.entries[this.currentKey]; + } + } + + const obj2 = { + entries: { first: 'hi!', second: 'bye!' }, + currentKey: 'second', + get currentEntry() { + // write me! + } + } + + // replace the null's to pass the asserts: + + const obj1current1 = null; + console.assert(obj1current1 === 'bye!', 'assert 1'); + + const obj2current1 = null; + console.assert(obj2current1 === 'bye!', 'assert 2'); + + obj1.currentKey = null; + obj2.currentKey = null; + + const obj1current2 = null; + console.assert(obj1current2 === 'hi!', 'assert 3'); + + const obj2current2 = null; + console.assert(obj2current2 === 'hi!', 'assert 4'); } - evaluate(example_refactorMethodToGetter); + getterRefactor3.display = true; + evaluate(getterRefactor3); + + + + function setterRefactor1() { + + const obj1 = { + greeting: ``, + setGreetingName: function (newName) { + this.greeting = `hi, I'm ${newName}!`; + } + }; + + const obj2 = { + greeting: ``, + set greetingName(newName) { + // write me! + } + }; + + obj1.setGreetingName('obj1'); + console.assert(obj1.greeting === "hi, I'm obj1!", 'assert 1'); + + ; // write me! + console.assert(obj2.greeting === "hi, I'm obj2!", 'assert 2'); + + obj1.setGreetingName('hi'); + console.assert(obj1.greeting === "hi, I'm hi!", 'assert 3'); + + ; // write me! + console.assert(obj2.greeting === "hi, I'm bye!", 'assert 4'); + + } + setterRefactor1.display = true; + evaluate(setterRefactor1); + + + function setterRefactor2() { + + + + } + setterRefactor2.display = true; + evaluate(setterRefactor2); + + + function setterRefactor3() { + + const obj1 = { + entries: { first: 'hi!', second: 'bye!' }, + current: {}, + setCurrentEntry: function (key) { + if (this.entries.hasOwnProperty(key)) { + this.current = { [key]: this.entries[key] }; + } else { + this.current = { [key]: new Error(`no entry with key "${key}"`) } + } + } + } + + const obj2 = { + entries: { first: 'hi!', second: 'bye!' }, + current: {}, + // write me! + } + + obj1.setCurrentEntry('second'); + console.assert(obj1.current.second === "bye!", 'assert 1'); + + ; // write me! + console.assert(obj2.current.second === "bye!", 'assert 2'); + + + obj1.setCurrentEntry('first'); + console.assert(obj1.current.first === "hi!", 'assert 3'); + console.assert(obj1.current.hasOwnProperty('second') === false, 'assert 4'); + + ; // write me! + console.assert(obj2.current.first === "hi!", 'assert 5'); + console.assert(obj2.current.hasOwnProperty('second') === false, 'assert 6'); + + + obj1.setCurrentEntry('hi'); + console.assert(obj1.current.hi.message === 'no entry with key "hi"', 'assert 7'); + console.assert(obj1.current.hasOwnProperty('first') === false, 'assert 8'); + + ; // write me! + console.assert(obj2.current.hi.message === 'no entry with key "hi"', 'assert 9'); + console.assert(obj2.current.hasOwnProperty('first') === false, 'assert 10'); + + } + setterRefactor3.display = true; + evaluate(setterRefactor3); - // more coming soon } catch (err) { console.log(err); diff --git a/week-3-project/practice-problems/index.html b/week-3-project/practice-problems/index.html index 5e3f15a..5831ef6 100644 --- a/week-3-project/practice-problems/index.html +++ b/week-3-project/practice-problems/index.html @@ -24,6 +24,7 @@ +
diff --git a/week-3-project/tests/add-entry.js b/week-3-project/tests/add-entry.js index 47914e6..a0987f7 100644 --- a/week-3-project/tests/add-entry.js +++ b/week-3-project/tests/add-entry.js @@ -30,8 +30,8 @@ describe(`addEntry: should add a new key/value pair to this.entries`, () => { ['firstKey', 'secondKey', 'thirdKey', 'fourthKey'].forEach(arg => { it(`${arg}`, () => { const result = object.addEntry(arg, ''); - assert.ok(result[arg] instanceof Error); - assert.strictEqual(result[arg].message, `addEntry: key "${arg}" already exists`); + assert.ok(result instanceof Error); + assert.strictEqual(result.message, `addEntry: key "${arg}" already exists`); }); }); }); diff --git a/week-3-project/tests/find-by-key.js b/week-3-project/tests/find-by-key.js index b0600d4..beb14ec 100644 --- a/week-3-project/tests/find-by-key.js +++ b/week-3-project/tests/find-by-key.js @@ -21,8 +21,8 @@ describe(`findByKey: returns the requested key/value pair, or an informative err ['a', 'b', 'c', 'd'].forEach(arg => { it(`${arg}`, () => { const result = object.findByKey(arg); - assert.ok(result[arg] instanceof ReferenceError); - assert.strictEqual(result[arg].message, `findByKey: no property "${arg}" in this.entries`); + assert.ok(result instanceof ReferenceError); + assert.strictEqual(result.message, `findByKey: no property "${arg}" in this.entries`); }); }); }); diff --git a/week-3-project/tests/find-by-value.js b/week-3-project/tests/find-by-value.js index 5042fcc..457a7af 100644 --- a/week-3-project/tests/find-by-value.js +++ b/week-3-project/tests/find-by-value.js @@ -37,18 +37,26 @@ describe(`findByValue: returns the requested key/value pair, or an informative e ['secondValue', { secondKey: 'secondValue' }], ['thirdValue', { thirdKey: 'thirdValue' }], ].forEach(arg => { - it(`it finds the correct key for ${arg[0]}`, () => { + it(`it returns the correct entry for value : ${arg[0]}`, () => { const result = object.findByValue(arg[0]); assert.deepStrictEqual(result, arg[1]); }); }); - it(`it finds all keys containing "fourthValue"`, () => { + it(`it finds all keys containing "fourthValue ... "`, () => { const result = object.findByValue('fourthValue'); - assert.deepStrictEqual(Object.keys(result), ['fourthKey', 'fifthKey', 'sixthKey']); + assert.deepStrictEqual(result, { + 'fourthKey': 'fourthValue', + 'fifthKey': 'fourthValue', + 'sixthKey': 'fourthValue' + }); }); - it(`and all keys containing "fifthValue"`, () => { + it(`... and all keys containing "fifthValue"`, () => { const result = object.findByValue('fifthValue'); - assert.deepStrictEqual(Object.keys(result), ['seventhKey', 'eighthKey', 'ninthKey']); + assert.deepStrictEqual(result, { + 'seventhKey': 'fifthValue', + 'eighthKey': 'fifthValue', + 'ninthKey': 'fifthValue' + }); }); }); }); diff --git a/week-3-project/tests/get-current-entry.js b/week-3-project/tests/get-current-entry.js index 0c9d0ca..ca8f218 100644 --- a/week-3-project/tests/get-current-entry.js +++ b/week-3-project/tests/get-current-entry.js @@ -21,4 +21,18 @@ describe(`get currentEntry: get the value of this.currentKey if the argument is }); }); }); + describe(`if the current entry has been removed, return the key with it's error`, () => { + [ + 'firstKey', + 'secondKey', + 'thirdKey', + 'fourthKey', + ].forEach(key => { + it(`${key}`, () => { + delete object.entries[key]; + object.currentKey = key; + assert.deepStrictEqual(object.currentEntry[key].message, `findByKey: no property "${key}" in this.entries`); + }); + }); + }); }); diff --git a/week-3-project/tests/has-key.js b/week-3-project/tests/has-key.js index 7388df3..ff26be3 100644 --- a/week-3-project/tests/has-key.js +++ b/week-3-project/tests/has-key.js @@ -35,7 +35,19 @@ describe(`hasKey: determines if an object has a given key`, () => { }); }); describe(`and returns false for non-existant entries.`, () => { - ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty'].forEach(arg => { + ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty', ''].forEach(arg => { + it(arg, () => { + const result = object.hasKey(object.entries, arg); + console.log(result) + assert.strictEqual(result, false); + }); + }); + }); + describe(`or when there are no entries!`, () => { + before(() => { + object.entries = {}; + }); + ['entries', 'hasKey', 'toSource', 'valueOf', 'hasOwnProperty', ''].forEach(arg => { it(arg, () => { const result = object.hasKey(object.entries, arg); assert.strictEqual(result, false); diff --git a/week-3-project/tests/has-value.js b/week-3-project/tests/has-value.js index 8e9c4fa..b86416e 100644 --- a/week-3-project/tests/has-value.js +++ b/week-3-project/tests/has-value.js @@ -42,4 +42,16 @@ describe(`hasValue: determines if an object has a given value`, () => { }); }); }); + describe(`even when there are no entries!`, () => { + before(() => { + object.entries = {}; + }); + ['tomato', null, true, undefined, 4].forEach(arg => { + const argString = typeof arg === 'string' ? '"' + arg + '"' : String(arg); + it(argString, () => { + const result = object.hasValue(object.entries, arg); + assert.strictEqual(result, false); + }); + }); + }); }); diff --git a/week-3-project/tests/remove-entry.js b/week-3-project/tests/remove-entry.js index 17e22c5..8a14f0c 100644 --- a/week-3-project/tests/remove-entry.js +++ b/week-3-project/tests/remove-entry.js @@ -21,8 +21,8 @@ describe(`removeEntry: should remove a key/value pair from this.entries`, () => ['tomato', 'potato', 'patate', 'pomme de terre'].forEach(arg => { it(`${arg}`, () => { const result = object.removeEntry(arg); - assert.ok(result[arg] instanceof Error); - assert.strictEqual(result[arg].message, `removeEntry: no property "${arg}" in this.entries`); + assert.ok(result instanceof Error); + assert.strictEqual(result.message, `removeEntry: no property "${arg}" in this.entries`); }); }); }); @@ -38,7 +38,7 @@ describe(`removeEntry: should remove a key/value pair from this.entries`, () => describe(`... and actually removes the entries!`, () => { valuesToRemove.forEach(arg => { it(`object.hasKey(object.entries, ${arg}) === false`, () => { - assert.strictEqual(object.hasKey(object.entries, arg), false); + assert.strictEqual(object.entries.hasOwnProperty(arg), false); }); }); }); diff --git a/week-3-project/tests/update-entry.js b/week-3-project/tests/update-entry.js index fd9870f..f670fa0 100644 --- a/week-3-project/tests/update-entry.js +++ b/week-3-project/tests/update-entry.js @@ -30,8 +30,8 @@ describe(`updateEntry: should add a new key/value pair to this.entries`, () => { ['tomato', 'potato', 'patate', 'pomme'].forEach(arg => { it(`${arg}`, () => { const result = object.updateEntry(arg, ''); - assert.ok(result[arg] instanceof ReferenceError); - assert.strictEqual(result[arg].message, `updateEntry: no property "${arg}" in this.entries`); + assert.ok(result instanceof ReferenceError); + assert.strictEqual(result.message, `updateEntry: no property "${arg}" in this.entries`); }); }); }); diff --git a/week-3-project/user-interface/handlers/favoriting.js b/week-3-project/user-interface/handlers/favoriting.js new file mode 100644 index 0000000..cd52854 --- /dev/null +++ b/week-3-project/user-interface/handlers/favoriting.js @@ -0,0 +1,23 @@ +function addStringHandler() { + + // read and process user input + + /* write the code to read the string input from the user */ + const key = null; // <------------- + const prop = null; // <------------- + + // pass user input through core logic (this works! no need to change it) + const result = typeof obj[prop] === 'function' // <---------------- + ? obj[prop](key) + : obj[prop] + + // report result to user (this works, no need to change it!) + // <--------------- + + // logs for developer + console.log('\n--- addStringHandler ---'); + console.log('stringToAdd:', typeof stringToAdd, ',', stringToAdd); + console.log('isNumbery:', typeof isNumbery, ',', isNumbery); + +}; +// connect this to it's button with an event listener! <---------- diff --git a/week-3-project/user-interface/index.html b/week-3-project/user-interface/index.html index 0a3d9e1..1b6655b 100644 --- a/week-3-project/user-interface/index.html +++ b/week-3-project/user-interface/index.html @@ -14,54 +14,82 @@ -
-
- key
- -
-
- value
- - -
+
+

CRUDing entries

+
+
+ key
+ +
+
+ value
+ + +
+
+
+
+
+ Which method do you want to call? + + + +
+
+
+
+ +
+
+
+
-
-
-
- Which method do you want to call? - - - -
-
-
-
- + +
+ +
+

favoriting

+
+ +
+
+
+
+ What do you want to do with this key? + + + +
+
+
+
-
-


- +
+