Skip to content

Commit

Permalink
Refactor to MVCish using vanilla TS
Browse files Browse the repository at this point in the history
  • Loading branch information
mihaeu committed Mar 26, 2024
1 parent 482886e commit 58b8d77
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 182 deletions.
23 changes: 1 addition & 22 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,7 @@
<title>Smorgasbord | Barcelona Polyamory</title>
</head>
<body>
<main>
<h1>Smorgasbord</h1>

<br>
<button id="share">Share yours</button>
<button id="compare">Compare results</button>
<button id="reset">Reset</button>
<div id="share-link"></div>
<div id="result"></div>
<p>
<label>
Name:
<input type="text" name="name" id="name" required minlength="2" />
</label>
</p>
<form action="" id="smorgasbord-form">
<section id="smorgasbord"></section>
</form>
</main>
<footer>
Made with ❤ by <a href="https://barcelona-polyamory.com">Barcelona Poly People</a>
</footer>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
12 changes: 12 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {Router} from "./router.ts";

export class App {
constructor(private readonly router: Router) {

}

init() {
const controller = this.router.route()
document.getElementById('app')?.appendChild(controller.render());
}
}
3 changes: 3 additions & 0 deletions src/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Controller {
render(): HTMLElement
}
163 changes: 3 additions & 160 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,161 +1,4 @@
import './style.css'
import {v1} from "./v1.ts";
import {App} from "./app.ts";
import {Router} from "./router.ts";

const sharedValues = new URLSearchParams(window.location.search).get("share") ?? ""
let sharedContent = {}
for (let i = 0; i <= sharedValues.length; i += 3) {
sharedContent[sharedValues.substring(i, i + 2)] = sharedValues.substring(i + 2, i + 3)
}
delete sharedContent[""]

document.getElementById('share')<HTMLButtonElement>.addEventListener("click", () => {
const values = Object.fromEntries(new FormData(window["smorgasbord-form"]))
const shareString = Object.entries(values).map(x => x.join("")).join("")
if (shareString.length === 0) {
alert("Please answer questions first.")
return;
}
const name = (document.getElementById("name") as HTMLInputElement).value
window["share-link"].innerText = `${document.location.origin}${document.location.pathname}?share=${shareString}${name === "" ? "" : `&name=${encodeURIComponent(name)}`}&time=${new Date().getTime()}`;
window["share-link"].style.display = "block";
})

document.getElementById('reset')<HTMLButtonElement>.addEventListener("click", () => {
window.localStorage.clear()
window.location.href = window.location.origin + window.location.pathname;
})

const data = v1
if (Object.keys(sharedContent).length > 0) {
for (const category of Object.keys(data)) {
for (let i = 0; i < data[category].length; ++i) {
if (!sharedContent[data[category][i].id]) {
delete data[category][i]
}
}
if (Object.keys(data[category]).length === 0) {
delete data[category]
}
}
}

const values = {
1: "yes",
2: "maybe",
3: "no",
}

// const values = {
// 1: "yes",
// 2: "maybe",
// 3: "maybe-future",
// 4: "talk",
// 5: "definitely-no",
// }

const name = window.localStorage.getItem("name");
const nameTextInput = document.getElementById("name") as HTMLInputElement;
if (name && name.length > 0) {
nameTextInput.value = name
}

const shareString = window.localStorage.getItem("share");
const savedValues = {}
if (shareString && shareString.length > 0) {
for (let i = 0; i <= shareString.length; i += 3) {
const key = shareString.substring(i, i + 2)
savedValues[key] = shareString.substring(i + 2, i + 3)
}
}

let content = []
for (const category of Object.keys(data)) {
content.push(`<h1>${category}</h1>`)
for (const item of data[category]) {
if (!item) continue;
content.push(`<section>
<h2>${item.subject}</h2>
<blockquote>${item.description}</blockquote>
<p>
<label for="${item.id}-yes"><input type="radio" name="${item.id}" id="${item.id}-yes" value="1" ${savedValues[item.id] === "1" && `checked`}/> Yes</label>
<label for="${item.id}-maybe"><input type="radio" name="${item.id}" id="${item.id}-maybe" value="2" ${savedValues[item.id] === "2" && `checked`}/> Maybe, Let's Talk</label>
<label for="${item.id}-no"><input type="radio" name="${item.id}" id="${item.id}-no" value="3" ${savedValues[item.id] === "3" && `checked`}/> No</label>
</p>
</section>`)
}
}
document.getElementById<HTMLDivElement>('smorgasbord').innerHTML = content.join("");

setTimeout(() => {
[...document.querySelectorAll('input')].forEach(element => element.addEventListener("change", () => {
const values = Object.fromEntries(new FormData(window["smorgasbord-form"]))
const shareString = Object.entries(values).map(x => x.join("")).join("")
window.localStorage.setItem("share", shareString)
window.localStorage.setItem("name", nameTextInput.value)
}))
}, 100)

document.getElementById<HTMLButtonElement>('compare').addEventListener("click", () => {
if (Object.keys(sharedContent).length === 0) {
alert("You can only compare your results to what others have sent you.")
}

if (window['result'].style.display === "block") {
window['result'].style.display = "none";
return;
}

const shareString = window.localStorage.getItem("share");
const filledInContent = {}
if (shareString && shareString.length > 0) {
for (let i = 0; i <= shareString.length; i += 3) {
const key = shareString.substring(i, i + 2)
filledInContent[key] = shareString.substring(i + 2, i + 3);
}
}
delete filledInContent[""]

console.log(sharedContent);
console.log(filledInContent);
if (Object.keys(sharedContent).join() !== Object.keys(filledInContent).join()) {
alert("Fill in all the subjects which where shared with you.")
return
}

const rowColor = (yours, theirs) => {
if (yours === "yes" && theirs === "yes") {
return 'limegreen'
}

if (`${yours}${theirs}`.match(/(yesmaybe|maybeyes|maybemaybe)/)) {
return 'yellow'
}

return 'inherit'
}
let content = [`<table>
<thead>
<tr>
<th>Category</th>
<th>Subject</th>
<th>You</th>
<th>Them</th>
</tr>
</thead><tbody>`]
for (const category of Object.keys(data)) {
for (const item of data[category]) {
if (!item) {
continue
}
content.push(`<tr style="background-color:${rowColor(values[sharedContent[item.id]], values[filledInContent[item.id]])};">
<td>${category}</td>
<td>${item.subject}</td>
<td>${values[sharedContent[item.id]]}</td>
<td>${values[filledInContent[item.id]]}</td>
</tr>`)
}
}
content.push(`</tbody></table>`)
window['result'].innerHTML = content.join("\n")
window['result'].style.display = "block";
})
new App(new Router()).init()
169 changes: 169 additions & 0 deletions src/mainController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import {Controller} from "./controller.ts";
import './style.css'
import {el, t} from "./util.ts";
import {Model} from "./model.ts";

export class MainController implements Controller {
constructor(private readonly model: Model) {
}

render() {
const header = el('h1', {}, t('Smorgasbord'))

const shareLink = el('div', {id: 'share-link'},)
const shareButton = this.shareButton(shareLink)

const result = el('div', {id: 'result'})
const compareButton = this.compareButton(result)

const resetButton = this.resetButton()

const smorgasbordForm = el('form', {id: "smorgasbord-form"})
const smorgasbordCategoriesContainer = el('section', {id: 'smorgasbord'}, smorgasbordForm)

for (const category of this.model.categories()) {
const categoryContainer = document.createElement('section')
const categoryHeading = document.createElement("h1")
categoryHeading.innerText = category
this.model.subjectsByCategory(category).forEach((item) => {
if (!item) return;
const sectionContainer = document.createElement('section')
const sectionHeading = document.createElement("h2")
sectionHeading.innerText = item.subject

const descriptionBlock = document.createElement('blockquote')
descriptionBlock.innerText = item.description

const saveChanges = (event: Event) => {
const target = event.target as HTMLInputElement;
if (target !== null) {
this.model.subject(target.name, target.value);
}
}
const labelContainer = document.createElement('p')

const yesLabel = document.createElement('label')
const yesOptionInput = document.createElement('input')
yesOptionInput.type = "radio"
yesOptionInput.name = item.id
yesOptionInput.id = item.id + '-yes'
yesOptionInput.value = "1"
yesOptionInput.checked = this.model.subject(item.id) === "1"
yesOptionInput.addEventListener("change", saveChanges)
yesLabel.append(yesOptionInput, document.createTextNode(' Yes'))

const maybeLabel = document.createElement('label')
const maybeOptionInput = document.createElement('input')
maybeOptionInput.type = "radio"
maybeOptionInput.name = item.id
maybeOptionInput.id = item.id + '-maybe'
maybeOptionInput.value = "2"
maybeOptionInput.checked = this.model.subject(item.id) === "2"
maybeOptionInput.addEventListener("change", saveChanges)
maybeLabel.append(maybeOptionInput, document.createTextNode(` Maybe, Let's Talk`))

const noLabel = document.createElement('label')
const noOptionInput = document.createElement('input')
noOptionInput.type = "radio"
noOptionInput.name = item.id
noOptionInput.id = item.id + '-no'
noOptionInput.value = "3"
noOptionInput.checked = this.model.subject(item.id) === "3"
noOptionInput.addEventListener("change", saveChanges)
noLabel.append(noOptionInput, document.createTextNode(' No'))

labelContainer.append(yesLabel, maybeLabel, noLabel)


sectionContainer.append(sectionHeading, descriptionBlock, labelContainer)
categoryContainer.append(sectionContainer)
})
smorgasbordForm.append(categoryContainer)
}

const footer = el('footer', {}, t('Made with ❤ by '), el('a', {href: 'https://barcelona-polyamory.com'}, t('Barcelona Poly People')))

return el('section', {}, header, shareButton, compareButton, resetButton, shareLink, result, smorgasbordCategoriesContainer, footer);
}

shareButton(shareLink: HTMLElement) {
const shareButton = document.createElement('button')
shareButton.innerText = 'Share yours'
shareButton.addEventListener("click", () => {
const values = this.model.subjects
const shareString = Object.entries(values).map(x => x.join("")).join("")
if (shareString.length === 0) {
alert("Please answer questions first.")
return;
}
shareLink.innerText = `${document.location.origin}${document.location.pathname}?share=${shareString}&time=${new Date().getTime()}`;
shareLink.style.display = "block";
})
return shareButton
}

resetButton() {
const resetButton = document.createElement('button')
resetButton.innerText = 'Reset'
resetButton.addEventListener("click", () => {
window.localStorage.clear()
window.location.href = window.location.origin + window.location.pathname;
})
return resetButton
}

compareButton(result: HTMLElement) {
const compareButton = document.createElement('button')
compareButton.innerText = 'Compare results'
compareButton.addEventListener("click", () => {
if (Object.keys(this.model.sharedSubjects).length === 0) {
alert("You can only compare your results to what others have sent you.")
}

if (result.style.display === "block") {
result.style.display = "none";
return;
}

const rowColor = (yours: string, theirs: string) => {
if (yours === "yes" && theirs === "yes") {
return 'limegreen'
}

if (`${yours}${theirs}`.match(/(yesmaybe|maybeyes|maybemaybe)/)) {
return 'yellow'
}

return 'inherit'
}
let content = [`<table>
<thead>
<tr>
<th>Category</th>
<th>Subject</th>
<th>You</th>
<th>Them</th>
</tr>
</thead><tbody>`]
const sharedContent = this.model.sharedSubjects
for (const category of this.model.categories()) {
for (const item of this.model.subjectsByCategory(category)) {
if (!item) {
continue
}
content.push(`<tr style="background-color:${rowColor(this.model.values[sharedContent[item.id]], this.model.values[this.model.subject(item.id) ?? ""])};">
<td>${category}</td>
<td>${item.subject}</td>
<td>${this.model.values[sharedContent[item.id]] ?? "n/a"}</td>
<td>${this.model.values[this.model.subject(item.id) ?? ""] ?? "n/a"}</td>
</tr>`)
}
}
content.push(`</tbody></table>`)
result.innerHTML = content.join("\n")
result.style.display = "block";
})

return compareButton
}
}
Loading

0 comments on commit 58b8d77

Please sign in to comment.