381 lines
10 KiB
TypeScript

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))
}
// 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'.")
}