diff --git a/mixins/Input.pixy b/mixins/Input.pixy index bbbbebf6..7da14926 100644 --- a/mixins/Input.pixy +++ b/mixins/Input.pixy @@ -1,14 +1,14 @@ component InputText(id string, value string, label string, placeholder string) .widget-input label(for=id)= label + ":" - input.widget-element(id=id, type="text", value=value, placeholder=placeholder) + input.widget-element.action(id=id, type="text", value=value, placeholder=placeholder, data-action="save", data-trigger="change") component InputTextArea(id string, value string, label string, placeholder string) .widget-input label(for=id)= label + ":" - textarea.widget-element(id=id, value=value, placeholder=placeholder) + textarea.widget-element.action(id=id, placeholder=placeholder, data-action="save", data-trigger="change")= value -component InputNumber(id string, value int, label string, placeholder string, min int, max int) +component InputNumber(id string, value int, label string, placeholder string, min string, max string) .widget-input label(for=id)= label + ":" - input.widget-element(id=id, type="number", value=value, min=min, max=max, placeholder=placeholder) \ No newline at end of file + input.widget-element.action(id=id, type="number", value=value, min=min, max=max, placeholder=placeholder, data-action="save", data-trigger="change") \ No newline at end of file diff --git a/pages/animelist/animelist.pixy b/pages/animelist/animelist.pixy index b3a3e3b4..da17b5c8 100644 --- a/pages/animelist/animelist.pixy +++ b/pages/animelist/animelist.pixy @@ -7,7 +7,7 @@ component AnimeList(animeList *arn.AnimeList) th.anime-list-item-rating Rating tbody each item in animeList.Items - tr.anime-list-item.mountable + tr.anime-list-item.mountable(title=item.Notes) td.anime-list-item-name a.ajax(href=item.Anime().Link())= item.Anime().Title.Canonical td.anime-list-item-episodes= toString(item.Episodes) + " / " + item.Anime().EpisodeCountString() diff --git a/pages/animelistitem/animelistitem.pixy b/pages/animelistitem/animelistitem.pixy index e7721a6e..a03510f2 100644 --- a/pages/animelistitem/animelistitem.pixy +++ b/pages/animelistitem/animelistitem.pixy @@ -1,14 +1,12 @@ component AnimeListItem(viewUser *arn.User, item *arn.AnimeListItem, anime *arn.Anime) .widgets.mountable - .widget.anime-list-item-view + .widget.anime-list-item-view(data-api="/api/animelist/" + viewUser.ID + "/update/" + anime.ID) h2= anime.Title.Canonical - if anime.EpisodeCount == 0 - InputNumber("episodes", item.Episodes, "Episodes", "Number of episodes you watched", 0, 10000) - else - InputNumber("episodes", item.Episodes, "Episodes", "Number of episodes you watched", 0, anime.EpisodeCount) + InputNumber("Episodes", item.Episodes, "Episodes", "Number of episodes you watched", "0", arn.EpisodeCountMax(anime.EpisodeCount)) + InputNumber("RewatchCount", item.RewatchCount, "Rewatched", "How often you rewatched this anime", "0", "100") - InputTextArea("notes", item.Notes, "Notes", "Notes") + InputTextArea("Notes", item.Notes, "Notes", "Your notes") .buttons.mountable a.ajax.button(href="/+" + viewUser.Nick + "/animelist") diff --git a/pages/settings/settings.pixy b/pages/settings/settings.pixy index c3a29d6d..3cd68590 100644 --- a/pages/settings/settings.pixy +++ b/pages/settings/settings.pixy @@ -1,20 +1,20 @@ component Settings(user *arn.User) h2.page-title Settings - .widgets + .widgets(data-api="/api/user/" + user.ID) .widget.mountable h3.widget-title Icon("user") span Personal - InputText("nick", user.Nick, "Username", "Your username on notify.moe") - InputText("tagline", user.Tagline, "Tagline", "Text that appears below your username") - InputText("website", user.Website, "Website", "Your homepage") + InputText("Nick", user.Nick, "Username", "Your username on notify.moe") + InputText("Tagline", user.Tagline, "Tagline", "Text that appears below your username") + InputText("Website", user.Website, "Website", "Your homepage") .widget.mountable h3.widget-title Icon("cubes") span Accounts - InputText("accounts.anilist.nick", user.Accounts.AniList.Nick, "AniList", "Your username on anilist.co") - InputText("accounts.myanimelist.nick", user.Accounts.MyAnimeList.Nick, "MyAnimeList", "Your username on myanimelist.net") - InputText("accounts.kitsu.nick", user.Accounts.Kitsu.Nick, "Kitsu", "Your username on kitsu.io") \ No newline at end of file + InputText("Accounts.AniList.Nick", user.Accounts.AniList.Nick, "AniList", "Your username on anilist.co") + InputText("Accounts.MyAnimeList.Nick", user.Accounts.MyAnimeList.Nick, "MyAnimeList", "Your username on myanimelist.net") + InputText("Accounts.Kitsu.Nick", user.Accounts.Kitsu.Nick, "Kitsu", "Your username on kitsu.io") \ No newline at end of file diff --git a/scripts/APIObject.ts b/scripts/APIObject.ts new file mode 100644 index 00000000..481cb4de --- /dev/null +++ b/scripts/APIObject.ts @@ -0,0 +1,31 @@ +// Save new data from an input field +// export function save(arn: AnimeNotifier, input: HTMLInputElement | HTMLTextAreaElement) { + // let apiObject: HTMLElement + // let parent = input as HTMLElement + + // while(parent = parent.parentElement) { + // if(parent.classList.contains("api-object")) { + // apiObject = parent + // break + // } + // } + + // if(!apiObject) { + // throw "API object not found" + // } + + // let request = apiObject["api-fetch"] + + // request.then(obj => { + // obj[input.id] = input.value + // console.log(obj) + // }) +// } + +// updateAPIObjects() { +// for(let element of findAll(".api-object")) { +// let apiObject = element + +// apiObject["api-fetch"] = fetch(element.dataset.api).then(response => response.json()) +// } +// } \ No newline at end of file diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 661a79b7..c4b86407 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -30,11 +30,8 @@ export class AnimeNotifier { this.app.loading.classList.add(this.app.fadeOutClass) } } - - onContentLoaded() { - this.updateMountables() - this.updateAvatars() - + + updateActions() { for(let element of findAll(".action")) { let actionName = element.dataset.action @@ -46,31 +43,6 @@ export class AnimeNotifier { } } - onPopState(e: PopStateEvent) { - if(e.state) { - this.app.load(e.state, { - addToHistory: false - }) - } else if(this.app.currentPath !== this.app.originalPath) { - this.app.load(this.app.originalPath, { - addToHistory: false - }) - } - } - - onKeyDown(e: KeyboardEvent) { - // Ctrl + Q = Search - if(e.ctrlKey && e.keyCode == 81) { - let search = this.app.find("search") as HTMLInputElement - - search.focus() - search.select() - - e.preventDefault() - e.stopPropagation() - } - } - updateAvatars() { for(let element of findAll(".user-image")) { let img = element as HTMLImageElement @@ -108,6 +80,38 @@ export class AnimeNotifier { } } + onContentLoaded() { + // Update each of these asynchronously + Promise.resolve().then(() => this.updateMountables()) + Promise.resolve().then(() => this.updateAvatars()) + Promise.resolve().then(() => this.updateActions()) + } + + onPopState(e: PopStateEvent) { + if(e.state) { + this.app.load(e.state, { + addToHistory: false + }) + } else if(this.app.currentPath !== this.app.originalPath) { + this.app.load(this.app.originalPath, { + addToHistory: false + }) + } + } + + onKeyDown(e: KeyboardEvent) { + // Ctrl + Q = Search + if(e.ctrlKey && e.keyCode == 81) { + let search = this.app.find("search") as HTMLInputElement + + search.focus() + search.select() + + e.preventDefault() + e.stopPropagation() + } + } + // onResize(e: UIEvent) { // let hasScrollbar = this.app.content.clientHeight === this.app.content.scrollHeight diff --git a/scripts/actions.ts b/scripts/actions.ts index 60053f5e..04503c7c 100644 --- a/scripts/actions.ts +++ b/scripts/actions.ts @@ -2,6 +2,55 @@ import { Application } from "./Application" import { AnimeNotifier } from "./AnimeNotifier" import { Diff } from "./Diff" +// Save new data from an input field +export function save(arn: AnimeNotifier, input: HTMLInputElement | HTMLTextAreaElement) { + arn.loading(true) + + let obj = {} + let value = input.value + + if(input.type === "number") { + obj[input.id] = parseInt(value) + } else { + obj[input.id] = value + } + + // console.log(input.type, input.dataset.api, obj, JSON.stringify(obj)) + + let apiObject: HTMLElement + let parent = input as HTMLElement + + while(parent = parent.parentElement) { + if(parent.dataset.api !== undefined) { + apiObject = parent + break + } + } + + if(!apiObject) { + throw "API object not found" + } + + input.disabled = true + + fetch(apiObject.dataset.api, { + method: "POST", + body: JSON.stringify(obj), + credentials: "same-origin" + }) + .then(response => response.text()) + .then(body => { + if(body !== "ok") { + throw body + } + }) + .catch(console.error) + .then(() => { + arn.loading(false) + input.disabled = false + }) +} + // Search export function search(arn: AnimeNotifier, search: HTMLInputElement, e: KeyboardEvent) { if(e.ctrlKey || e.altKey) { diff --git a/tests.go b/tests.go index 83690aae..f2c142d8 100644 --- a/tests.go +++ b/tests.go @@ -109,4 +109,5 @@ func init() { app.Test("/auth/google", nil) app.Test("/auth/google/callback", nil) app.Test("/user", nil) + app.Test("/settings", nil) }