From d65f3fd7bb226b15d989df51ca07ed6cff1ba92b Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Tue, 17 Oct 2017 11:27:15 +0200 Subject: [PATCH] Refactor actions --- scripts/Actions.ts | 444 +--------------------------- scripts/Actions/AnimeList.ts | 25 ++ scripts/Actions/Diff.ts | 14 + scripts/Actions/FollowUser.ts | 17 ++ scripts/Actions/Forum.ts | 78 +++++ scripts/Actions/InfiniteScroller.ts | 49 +++ scripts/Actions/Install.ts | 12 + scripts/Actions/Like.ts | 19 ++ scripts/Actions/Notifications.ts | 20 ++ scripts/Actions/Publish.ts | 19 ++ scripts/Actions/Search.ts | 17 ++ scripts/Actions/Serialization.ts | 80 +++++ scripts/Actions/Shop.ts | 64 ++++ scripts/Actions/SideBar.ts | 6 + scripts/Actions/SoundTrack.ts | 9 + scripts/Actions/StatusMessage.ts | 6 + 16 files changed, 450 insertions(+), 429 deletions(-) create mode 100644 scripts/Actions/AnimeList.ts create mode 100644 scripts/Actions/Diff.ts create mode 100644 scripts/Actions/FollowUser.ts create mode 100644 scripts/Actions/Forum.ts create mode 100644 scripts/Actions/InfiniteScroller.ts create mode 100644 scripts/Actions/Install.ts create mode 100644 scripts/Actions/Like.ts create mode 100644 scripts/Actions/Notifications.ts create mode 100644 scripts/Actions/Publish.ts create mode 100644 scripts/Actions/Search.ts create mode 100644 scripts/Actions/Serialization.ts create mode 100644 scripts/Actions/Shop.ts create mode 100644 scripts/Actions/SideBar.ts create mode 100644 scripts/Actions/SoundTrack.ts create mode 100644 scripts/Actions/StatusMessage.ts diff --git a/scripts/Actions.ts b/scripts/Actions.ts index 2c70ac74..60d4a79e 100644 --- a/scripts/Actions.ts +++ b/scripts/Actions.ts @@ -1,429 +1,15 @@ -import { Application } from "./Application" -import { AnimeNotifier } from "./AnimeNotifier" -import { Diff } from "./Diff" -import { findAll } from "./Utils" - -// Follow user -export function followUser(arn: AnimeNotifier, elem: HTMLElement) { - return arn.post(elem.dataset.api, "") - .then(() => arn.reloadContent()) - .then(() => arn.statusMessage.showInfo("You are now following " + arn.app.find("nick").innerText + ".")) - .catch(err => arn.statusMessage.showError(err)) -} - -// Unfollow user -export function unfollowUser(arn: AnimeNotifier, elem: HTMLElement) { - return arn.post(elem.dataset.api, "") - .then(() => arn.reloadContent()) - .then(() => arn.statusMessage.showInfo("You stopped following " + arn.app.find("nick").innerText + ".")) - .catch(err => arn.statusMessage.showError(err)) -} - -// Toggle sidebar -export function toggleSidebar(arn: AnimeNotifier) { - arn.app.find("sidebar").classList.toggle("sidebar-visible") -} - -// Save new data from an input field -export function save(arn: AnimeNotifier, input: HTMLElement) { - let obj = {} - let isContentEditable = input.isContentEditable - let value = isContentEditable ? input.innerText : (input as HTMLInputElement).value - - if(value === undefined) { - return - } - - if((input as HTMLInputElement).type === "number" || input.dataset.type === "number") { - if(input.getAttribute("step") === "1" || input.dataset.step === "1") { - obj[input.dataset.field] = parseInt(value) - } else { - obj[input.dataset.field] = parseFloat(value) - } - } else { - obj[input.dataset.field] = value - } - - if(isContentEditable) { - input.contentEditable = "false" - } else { - (input as HTMLInputElement).disabled = true - } - - let apiEndpoint = arn.findAPIEndpoint(input) - - arn.post(apiEndpoint, obj) - .catch(err => arn.statusMessage.showError(err)) - .then(() => { - if(isContentEditable) { - input.contentEditable = "true" - } else { - (input as HTMLInputElement).disabled = false - } - - return arn.reloadContent() - }) -} - -// Close status message -export function closeStatusMessage(arn: AnimeNotifier) { - arn.statusMessage.close() -} - -// Increase episode -export function increaseEpisode(arn: AnimeNotifier, element: HTMLElement) { - if(arn.isLoading) { - return - } - - let prev = element.previousSibling as HTMLElement - let episodes = parseInt(prev.innerText) - prev.innerText = String(episodes + 1) - save(arn, prev) -} - -// Load -export function load(arn: AnimeNotifier, element: HTMLElement) { - let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") - arn.app.load(url) -} - -// Soon -export function soon() { - alert("Coming Soon™") -} - -// Diff -export function diff(arn: AnimeNotifier, element: HTMLElement) { - let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") - - arn.diff(url).then(() => arn.scrollTo(element)) -} - -// Edit post -export function editPost(arn: AnimeNotifier, element: HTMLElement) { - let postId = element.dataset.id - - let render = arn.app.find("render-" + postId) - let toolbar = arn.app.find("toolbar-" + postId) - let title = arn.app.find("title-" + postId) - let source = arn.app.find("source-" + postId) - let edit = arn.app.find("edit-toolbar-" + postId) - - render.classList.toggle("hidden") - toolbar.classList.toggle("hidden") - source.classList.toggle("hidden") - edit.classList.toggle("hidden") - - if(title) { - title.classList.toggle("hidden") - } -} - -// Save post -export function savePost(arn: AnimeNotifier, element: HTMLElement) { - let postId = element.dataset.id - let source = arn.app.find("source-" + postId) as HTMLTextAreaElement - let title = arn.app.find("title-" + postId) as HTMLInputElement - let text = source.value - - let updates: any = { - Text: text, - } - - // Add title for threads only - if(title) { - updates.Title = title.value - } - - let apiEndpoint = arn.findAPIEndpoint(element) - - arn.post(apiEndpoint, updates) - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// like -export function like(arn: AnimeNotifier, element: HTMLElement) { - let apiEndpoint = arn.findAPIEndpoint(element) - - arn.post(apiEndpoint + "/like", null) - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// unlike -export function unlike(arn: AnimeNotifier, element: HTMLElement) { - let apiEndpoint = arn.findAPIEndpoint(element) - - arn.post(apiEndpoint + "/unlike", null) - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// Forum reply -export function forumReply(arn: AnimeNotifier) { - let textarea = arn.app.find("new-reply") as HTMLTextAreaElement - let thread = arn.app.find("thread") - - let post = { - text: textarea.value, - threadId: thread.dataset.id, - tags: [] - } - - arn.post("/api/new/post", post) - .then(() => arn.reloadContent()) - .then(() => textarea.value = "") - .catch(err => arn.statusMessage.showError(err)) -} - -// Create thread -export function createThread(arn: AnimeNotifier) { - let title = arn.app.find("title") as HTMLInputElement - let text = arn.app.find("text") as HTMLTextAreaElement - let category = arn.app.find("tag") as HTMLInputElement - - let thread = { - title: title.value, - text: text.value, - tags: [category.value] - } - - arn.post("/api/new/thread", thread) - .then(() => arn.app.load("/forum/" + thread.tags[0])) - .catch(err => arn.statusMessage.showError(err)) -} - -// New soundtrack -export function newSoundTrack(arn: AnimeNotifier, button: HTMLButtonElement) { - arn.post("/api/new/soundtrack", "") - .then(response => response.json()) - .then(track => arn.app.load(`/soundtrack/${track.id}/edit`)) - .catch(err => arn.statusMessage.showError(err)) -} - -// Publish -export function publish(arn: AnimeNotifier, button: HTMLButtonElement) { - let endpoint = arn.findAPIEndpoint(button) - - arn.post(endpoint + "/publish", "") - .then(() => arn.app.load(arn.app.currentPath.replace("/edit", ""))) - .catch(err => arn.statusMessage.showError(err)) -} - -// Unpublish -export function unpublish(arn: AnimeNotifier, button: HTMLButtonElement) { - let endpoint = arn.findAPIEndpoint(button) - - arn.post(endpoint + "/unpublish", "") - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// Search -export function search(arn: AnimeNotifier, search: HTMLInputElement, e: KeyboardEvent) { - if(e.ctrlKey || e.altKey) { - return - } - - let term = search.value - - if(!term || term.length < 2) { - arn.app.content.innerHTML = "Please enter at least 2 characters to start searching." - return - } - - arn.diff("/search/" + term) -} - -// Enable notifications -export async function enableNotifications(arn: AnimeNotifier, button: HTMLElement) { - await arn.pushManager.subscribe(arn.user.dataset.id) - arn.updatePushUI() -} - -// Disable notifications -export async function disableNotifications(arn: AnimeNotifier, button: HTMLElement) { - await arn.pushManager.unsubscribe(arn.user.dataset.id) - arn.updatePushUI() -} - -// Test notification -export function testNotification(arn: AnimeNotifier) { - fetch("/api/test/notification", { - credentials: "same-origin" - }) -} - -// Add anime to collection -export function addAnimeToCollection(arn: AnimeNotifier, button: HTMLElement) { - button.innerText = "Adding..." - - let {animeId} = button.dataset - let apiEndpoint = arn.findAPIEndpoint(button) - - arn.post(apiEndpoint + "/add/" + animeId, "") - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// Remove anime from collection -export function removeAnimeFromCollection(arn: AnimeNotifier, button: HTMLElement) { - button.innerText = "Removing..." - - let {animeId, nick} = button.dataset - let apiEndpoint = arn.findAPIEndpoint(button) - - arn.post(apiEndpoint + "/remove/" + animeId, "") - .then(() => arn.app.load("/animelist/" + (arn.app.find("Status") as HTMLSelectElement).value)) - .catch(err => arn.statusMessage.showError(err)) -} - -// Charge up -export function chargeUp(arn: AnimeNotifier, button: HTMLElement) { - let amount = button.dataset.amount - - arn.loading(true) - arn.statusMessage.showInfo("Creating PayPal transaction... This might take a few seconds.") - - fetch("/api/paypal/payment/create", { - method: "POST", - body: amount, - credentials: "same-origin" - }) - .then(response => response.json()) - .then(payment => { - if(!payment || !payment.links) { - throw "Error creating PayPal payment" - } - - console.log(payment) - let link = payment.links.find(link => link.rel === "approval_url") - - if(!link) { - throw "Error finding PayPal payment link" - } - - arn.statusMessage.showInfo("Redirecting to PayPal...", 5000) - - let url = link.href - window.location.href = url - }) - .catch(err => arn.statusMessage.showError(err)) - .then(() => arn.loading(false)) -} - -// Buy item -export function buyItem(arn: AnimeNotifier, button: HTMLElement) { - let itemId = button.dataset.itemId - let itemName = button.dataset.itemName - let price = button.dataset.price - - if(!confirm(`Would you like to buy ${itemName} for ${price} gems?`)) { - return - } - - arn.loading(true) - - fetch(`/api/shop/buy/${itemId}/1`, { - method: "POST", - credentials: "same-origin" - }) - .then(response => response.text()) - .then(body => { - if(body !== "ok") { - throw body - } - - return arn.reloadContent() - }) - .then(() => arn.statusMessage.showInfo(`You bought ${itemName} for ${price} gems. Check out your inventory to confirm the purchase.`, 4000)) - .catch(err => arn.statusMessage.showError(err)) - .then(() => arn.loading(false)) -} - -// Append new element to array -export function arrayAppend(arn: AnimeNotifier, element: HTMLElement) { - let field = element.dataset.field - let object = element.dataset.object || "" - let apiEndpoint = arn.findAPIEndpoint(element) - - arn.post(apiEndpoint + "/field/" + field + "/append", object) - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// Remove element from array -export function arrayRemove(arn: AnimeNotifier, element: HTMLElement) { - if(!confirm("Are you sure you want to remove this element?")) { - return - } - - let field = element.dataset.field - let index = element.dataset.index - let apiEndpoint = arn.findAPIEndpoint(element) - - arn.post(apiEndpoint + "/field/" + field + "/remove/" + index, "") - .then(() => arn.reloadContent()) - .catch(err => arn.statusMessage.showError(err)) -} - -// Load more -export function loadMore(arn: AnimeNotifier, button: HTMLButtonElement) { - // Prevent firing this event multiple times - if(arn.isLoading || button.disabled) { - return - } - - arn.loading(true) - button.disabled = true - - let target = arn.app.find("load-more-target") - let index = button.dataset.index - - fetch("/_" + arn.app.currentPath + "/from/" + index) - .then(response => { - let newIndex = response.headers.get("X-LoadMore-Index") - - // End of data? - if(newIndex === "-1") { - button.classList.add("hidden") - } else { - button.dataset.index = newIndex - } - - return response - }) - .then(response => response.text()) - .then(body => { - let tmp = document.createElement(target.tagName) - tmp.innerHTML = body - - let children = [...tmp.childNodes] - - window.requestAnimationFrame(() => { - for(let child of children) { - target.appendChild(child) - } - - arn.app.emit("DOMContentLoaded") - }) - }) - .catch(err => arn.statusMessage.showError(err)) - .then(() => { - arn.loading(false) - button.disabled = false - }) -} - -// Chrome extension installation -export function installExtension(arn: AnimeNotifier, button: HTMLElement) { - let browser: any = window["chrome"] - browser.webstore.install() -} - -// Desktop app installation -export function installApp() { - alert("Open your browser menu > 'More tools' > 'Add to desktop' and enable 'Open as window'.") -} \ No newline at end of file +export * from "./Actions/AnimeList" +export * from "./Actions/Diff" +export * from "./Actions/FollowUser" +export * from "./Actions/Forum" +export * from "./Actions/InfiniteScroller" +export * from "./Actions/Install" +export * from "./Actions/Like" +export * from "./Actions/Notifications" +export * from "./Actions/Publish" +export * from "./Actions/Search" +export * from "./Actions/Serialization" +export * from "./Actions/Shop" +export * from "./Actions/SideBar" +export * from "./Actions/SoundTrack" +export * from "./Actions/StatusMessage" \ No newline at end of file diff --git a/scripts/Actions/AnimeList.ts b/scripts/Actions/AnimeList.ts new file mode 100644 index 00000000..06530483 --- /dev/null +++ b/scripts/Actions/AnimeList.ts @@ -0,0 +1,25 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Add anime to collection +export function addAnimeToCollection(arn: AnimeNotifier, button: HTMLElement) { + button.innerText = "Adding..." + + let {animeId} = button.dataset + let apiEndpoint = arn.findAPIEndpoint(button) + + arn.post(apiEndpoint + "/add/" + animeId, "") + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} + +// Remove anime from collection +export function removeAnimeFromCollection(arn: AnimeNotifier, button: HTMLElement) { + button.innerText = "Removing..." + + let {animeId, nick} = button.dataset + let apiEndpoint = arn.findAPIEndpoint(button) + + arn.post(apiEndpoint + "/remove/" + animeId, "") + .then(() => arn.app.load("/animelist/" + (arn.app.find("Status") as HTMLSelectElement).value)) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/Diff.ts b/scripts/Actions/Diff.ts new file mode 100644 index 00000000..66e35c81 --- /dev/null +++ b/scripts/Actions/Diff.ts @@ -0,0 +1,14 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Load +export function load(arn: AnimeNotifier, element: HTMLElement) { + let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") + arn.app.load(url) +} + +// Diff +export function diff(arn: AnimeNotifier, element: HTMLElement) { + let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") + + arn.diff(url).then(() => arn.scrollTo(element)) +} \ No newline at end of file diff --git a/scripts/Actions/FollowUser.ts b/scripts/Actions/FollowUser.ts new file mode 100644 index 00000000..096016a5 --- /dev/null +++ b/scripts/Actions/FollowUser.ts @@ -0,0 +1,17 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Follow user +export function followUser(arn: AnimeNotifier, elem: HTMLElement) { + return arn.post(elem.dataset.api, "") + .then(() => arn.reloadContent()) + .then(() => arn.statusMessage.showInfo("You are now following " + arn.app.find("nick").innerText + ".")) + .catch(err => arn.statusMessage.showError(err)) +} + +// Unfollow user +export function unfollowUser(arn: AnimeNotifier, elem: HTMLElement) { + return arn.post(elem.dataset.api, "") + .then(() => arn.reloadContent()) + .then(() => arn.statusMessage.showInfo("You stopped following " + arn.app.find("nick").innerText + ".")) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/Forum.ts b/scripts/Actions/Forum.ts new file mode 100644 index 00000000..7bc14bce --- /dev/null +++ b/scripts/Actions/Forum.ts @@ -0,0 +1,78 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Edit post +export function editPost(arn: AnimeNotifier, element: HTMLElement) { + let postId = element.dataset.id + + let render = arn.app.find("render-" + postId) + let toolbar = arn.app.find("toolbar-" + postId) + let title = arn.app.find("title-" + postId) + let source = arn.app.find("source-" + postId) + let edit = arn.app.find("edit-toolbar-" + postId) + + render.classList.toggle("hidden") + toolbar.classList.toggle("hidden") + source.classList.toggle("hidden") + edit.classList.toggle("hidden") + + if(title) { + title.classList.toggle("hidden") + } +} + +// Save post +export function savePost(arn: AnimeNotifier, element: HTMLElement) { + let postId = element.dataset.id + let source = arn.app.find("source-" + postId) as HTMLTextAreaElement + let title = arn.app.find("title-" + postId) as HTMLInputElement + let text = source.value + + let updates: any = { + Text: text, + } + + // Add title for threads only + if(title) { + updates.Title = title.value + } + + let apiEndpoint = arn.findAPIEndpoint(element) + + arn.post(apiEndpoint, updates) + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} + +// Forum reply +export function forumReply(arn: AnimeNotifier) { + let textarea = arn.app.find("new-reply") as HTMLTextAreaElement + let thread = arn.app.find("thread") + + let post = { + text: textarea.value, + threadId: thread.dataset.id, + tags: [] + } + + arn.post("/api/new/post", post) + .then(() => arn.reloadContent()) + .then(() => textarea.value = "") + .catch(err => arn.statusMessage.showError(err)) +} + +// Create thread +export function createThread(arn: AnimeNotifier) { + let title = arn.app.find("title") as HTMLInputElement + let text = arn.app.find("text") as HTMLTextAreaElement + let category = arn.app.find("tag") as HTMLInputElement + + let thread = { + title: title.value, + text: text.value, + tags: [category.value] + } + + arn.post("/api/new/thread", thread) + .then(() => arn.app.load("/forum/" + thread.tags[0])) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/InfiniteScroller.ts b/scripts/Actions/InfiniteScroller.ts new file mode 100644 index 00000000..213ced6e --- /dev/null +++ b/scripts/Actions/InfiniteScroller.ts @@ -0,0 +1,49 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Load more +export function loadMore(arn: AnimeNotifier, button: HTMLButtonElement) { + // Prevent firing this event multiple times + if(arn.isLoading || button.disabled) { + return + } + + arn.loading(true) + button.disabled = true + + let target = arn.app.find("load-more-target") + let index = button.dataset.index + + fetch("/_" + arn.app.currentPath + "/from/" + index) + .then(response => { + let newIndex = response.headers.get("X-LoadMore-Index") + + // End of data? + if(newIndex === "-1") { + button.classList.add("hidden") + } else { + button.dataset.index = newIndex + } + + return response + }) + .then(response => response.text()) + .then(body => { + let tmp = document.createElement(target.tagName) + tmp.innerHTML = body + + let children = [...tmp.childNodes] + + window.requestAnimationFrame(() => { + for(let child of children) { + target.appendChild(child) + } + + arn.app.emit("DOMContentLoaded") + }) + }) + .catch(err => arn.statusMessage.showError(err)) + .then(() => { + arn.loading(false) + button.disabled = false + }) +} \ No newline at end of file diff --git a/scripts/Actions/Install.ts b/scripts/Actions/Install.ts new file mode 100644 index 00000000..8903d1ef --- /dev/null +++ b/scripts/Actions/Install.ts @@ -0,0 +1,12 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Chrome extension installation +export function installExtension(arn: AnimeNotifier, button: HTMLElement) { + let browser: any = window["chrome"] + browser.webstore.install() +} + +// Desktop app installation +export function installApp() { + alert("Open your browser menu > 'More tools' > 'Add to desktop' and enable 'Open as window'.") +} \ No newline at end of file diff --git a/scripts/Actions/Like.ts b/scripts/Actions/Like.ts new file mode 100644 index 00000000..22783139 --- /dev/null +++ b/scripts/Actions/Like.ts @@ -0,0 +1,19 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// like +export function like(arn: AnimeNotifier, element: HTMLElement) { + let apiEndpoint = arn.findAPIEndpoint(element) + + arn.post(apiEndpoint + "/like", null) + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} + +// unlike +export function unlike(arn: AnimeNotifier, element: HTMLElement) { + let apiEndpoint = arn.findAPIEndpoint(element) + + arn.post(apiEndpoint + "/unlike", null) + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/Notifications.ts b/scripts/Actions/Notifications.ts new file mode 100644 index 00000000..10557525 --- /dev/null +++ b/scripts/Actions/Notifications.ts @@ -0,0 +1,20 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Enable notifications +export async function enableNotifications(arn: AnimeNotifier, button: HTMLElement) { + await arn.pushManager.subscribe(arn.user.dataset.id) + arn.updatePushUI() +} + +// Disable notifications +export async function disableNotifications(arn: AnimeNotifier, button: HTMLElement) { + await arn.pushManager.unsubscribe(arn.user.dataset.id) + arn.updatePushUI() +} + +// Test notification +export function testNotification(arn: AnimeNotifier) { + fetch("/api/test/notification", { + credentials: "same-origin" + }) +} \ No newline at end of file diff --git a/scripts/Actions/Publish.ts b/scripts/Actions/Publish.ts new file mode 100644 index 00000000..3e49721b --- /dev/null +++ b/scripts/Actions/Publish.ts @@ -0,0 +1,19 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Publish +export function publish(arn: AnimeNotifier, button: HTMLButtonElement) { + let endpoint = arn.findAPIEndpoint(button) + + arn.post(endpoint + "/publish", "") + .then(() => arn.app.load(arn.app.currentPath.replace("/edit", ""))) + .catch(err => arn.statusMessage.showError(err)) +} + +// Unpublish +export function unpublish(arn: AnimeNotifier, button: HTMLButtonElement) { + let endpoint = arn.findAPIEndpoint(button) + + arn.post(endpoint + "/unpublish", "") + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/Search.ts b/scripts/Actions/Search.ts new file mode 100644 index 00000000..d1615cf3 --- /dev/null +++ b/scripts/Actions/Search.ts @@ -0,0 +1,17 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Search +export function search(arn: AnimeNotifier, search: HTMLInputElement, e: KeyboardEvent) { + if(e.ctrlKey || e.altKey) { + return + } + + let term = search.value + + if(!term || term.length < 2) { + arn.app.content.innerHTML = "Please enter at least 2 characters to start searching." + return + } + + arn.diff("/search/" + term) +} \ No newline at end of file diff --git a/scripts/Actions/Serialization.ts b/scripts/Actions/Serialization.ts new file mode 100644 index 00000000..c575cb4f --- /dev/null +++ b/scripts/Actions/Serialization.ts @@ -0,0 +1,80 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Save new data from an input field +export function save(arn: AnimeNotifier, input: HTMLElement) { + let obj = {} + let isContentEditable = input.isContentEditable + let value = isContentEditable ? input.innerText : (input as HTMLInputElement).value + + if(value === undefined) { + return + } + + if((input as HTMLInputElement).type === "number" || input.dataset.type === "number") { + if(input.getAttribute("step") === "1" || input.dataset.step === "1") { + obj[input.dataset.field] = parseInt(value) + } else { + obj[input.dataset.field] = parseFloat(value) + } + } else { + obj[input.dataset.field] = value + } + + if(isContentEditable) { + input.contentEditable = "false" + } else { + (input as HTMLInputElement).disabled = true + } + + let apiEndpoint = arn.findAPIEndpoint(input) + + arn.post(apiEndpoint, obj) + .catch(err => arn.statusMessage.showError(err)) + .then(() => { + if(isContentEditable) { + input.contentEditable = "true" + } else { + (input as HTMLInputElement).disabled = false + } + + return arn.reloadContent() + }) +} + +// Append new element to array +export function arrayAppend(arn: AnimeNotifier, element: HTMLElement) { + let field = element.dataset.field + let object = element.dataset.object || "" + let apiEndpoint = arn.findAPIEndpoint(element) + + arn.post(apiEndpoint + "/field/" + field + "/append", object) + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} + +// Remove element from array +export function arrayRemove(arn: AnimeNotifier, element: HTMLElement) { + if(!confirm("Are you sure you want to remove this element?")) { + return + } + + let field = element.dataset.field + let index = element.dataset.index + let apiEndpoint = arn.findAPIEndpoint(element) + + arn.post(apiEndpoint + "/field/" + field + "/remove/" + index, "") + .then(() => arn.reloadContent()) + .catch(err => arn.statusMessage.showError(err)) +} + +// Increase episode +export function increaseEpisode(arn: AnimeNotifier, element: HTMLElement) { + if(arn.isLoading) { + return + } + + let prev = element.previousSibling as HTMLElement + let episodes = parseInt(prev.innerText) + prev.innerText = String(episodes + 1) + save(arn, prev) +} \ No newline at end of file diff --git a/scripts/Actions/Shop.ts b/scripts/Actions/Shop.ts new file mode 100644 index 00000000..5f7a8cf1 --- /dev/null +++ b/scripts/Actions/Shop.ts @@ -0,0 +1,64 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Charge up +export function chargeUp(arn: AnimeNotifier, button: HTMLElement) { + let amount = button.dataset.amount + + arn.loading(true) + arn.statusMessage.showInfo("Creating PayPal transaction... This might take a few seconds.") + + fetch("/api/paypal/payment/create", { + method: "POST", + body: amount, + credentials: "same-origin" + }) + .then(response => response.json()) + .then(payment => { + if(!payment || !payment.links) { + throw "Error creating PayPal payment" + } + + console.log(payment) + let link = payment.links.find(link => link.rel === "approval_url") + + if(!link) { + throw "Error finding PayPal payment link" + } + + arn.statusMessage.showInfo("Redirecting to PayPal...", 5000) + + let url = link.href + window.location.href = url + }) + .catch(err => arn.statusMessage.showError(err)) + .then(() => arn.loading(false)) +} + +// Buy item +export function buyItem(arn: AnimeNotifier, button: HTMLElement) { + let itemId = button.dataset.itemId + let itemName = button.dataset.itemName + let price = button.dataset.price + + if(!confirm(`Would you like to buy ${itemName} for ${price} gems?`)) { + return + } + + arn.loading(true) + + fetch(`/api/shop/buy/${itemId}/1`, { + method: "POST", + credentials: "same-origin" + }) + .then(response => response.text()) + .then(body => { + if(body !== "ok") { + throw body + } + + return arn.reloadContent() + }) + .then(() => arn.statusMessage.showInfo(`You bought ${itemName} for ${price} gems. Check out your inventory to confirm the purchase.`, 4000)) + .catch(err => arn.statusMessage.showError(err)) + .then(() => arn.loading(false)) +} \ No newline at end of file diff --git a/scripts/Actions/SideBar.ts b/scripts/Actions/SideBar.ts new file mode 100644 index 00000000..7547b701 --- /dev/null +++ b/scripts/Actions/SideBar.ts @@ -0,0 +1,6 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Toggle sidebar +export function toggleSidebar(arn: AnimeNotifier) { + arn.app.find("sidebar").classList.toggle("sidebar-visible") +} \ No newline at end of file diff --git a/scripts/Actions/SoundTrack.ts b/scripts/Actions/SoundTrack.ts new file mode 100644 index 00000000..1e435414 --- /dev/null +++ b/scripts/Actions/SoundTrack.ts @@ -0,0 +1,9 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// New soundtrack +export function newSoundTrack(arn: AnimeNotifier, button: HTMLButtonElement) { + arn.post("/api/new/soundtrack", "") + .then(response => response.json()) + .then(track => arn.app.load(`/soundtrack/${track.id}/edit`)) + .catch(err => arn.statusMessage.showError(err)) +} \ No newline at end of file diff --git a/scripts/Actions/StatusMessage.ts b/scripts/Actions/StatusMessage.ts new file mode 100644 index 00000000..a5f6f014 --- /dev/null +++ b/scripts/Actions/StatusMessage.ts @@ -0,0 +1,6 @@ +import { AnimeNotifier } from "../AnimeNotifier" + +// Close status message +export function closeStatusMessage(arn: AnimeNotifier) { + arn.statusMessage.close() +} \ No newline at end of file