Use const variables when applicable

This commit is contained in:
Eduard Urbach 2019-11-17 18:25:14 +09:00
parent 454e8572e3
commit 878f1913e3
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
39 changed files with 405 additions and 403 deletions

View File

@ -4,22 +4,22 @@ import AnimeNotifier from "../AnimeNotifier"
export async function addAnimeToCollection(arn: AnimeNotifier, button: HTMLButtonElement) { export async function addAnimeToCollection(arn: AnimeNotifier, button: HTMLButtonElement) {
button.disabled = true button.disabled = true
let {animeId} = button.dataset const {animeId} = button.dataset
if(!animeId) { if(!animeId) {
console.error("Button without anime ID:", button) console.error("Button without anime ID:", button)
return return
} }
let apiEndpoint = arn.findAPIEndpoint(button) const apiEndpoint = arn.findAPIEndpoint(button)
try { try {
await arn.post(apiEndpoint + "/add/" + animeId) await arn.post(apiEndpoint + "/add/" + animeId)
arn.reloadContent() arn.reloadContent()
// Show status message // Show status message
let response = await fetch("/api/anime/" + animeId) const response = await fetch("/api/anime/" + animeId)
let anime = await response.json() const anime = await response.json()
arn.statusMessage.showInfo(`Added ${anime.title.canonical} to your collection.`) arn.statusMessage.showInfo(`Added ${anime.title.canonical} to your collection.`)
} catch(err) { } catch(err) {
arn.statusMessage.showError(err) arn.statusMessage.showError(err)
@ -33,15 +33,15 @@ export async function removeAnimeFromCollection(arn: AnimeNotifier, button: HTML
} }
button.textContent = "Removing..." button.textContent = "Removing..."
let {animeId, nick} = button.dataset const {animeId, nick} = button.dataset
if(!animeId || !nick) { if(!animeId || !nick) {
console.error("Button without nick or anime ID:", button) console.error("Button without nick or anime ID:", button)
return return
} }
let apiEndpoint = arn.findAPIEndpoint(button) const apiEndpoint = arn.findAPIEndpoint(button)
let status = document.getElementById("Status") as HTMLSelectElement const status = document.getElementById("Status") as HTMLSelectElement
try { try {
await arn.post(apiEndpoint + "/remove/" + animeId) await arn.post(apiEndpoint + "/remove/" + animeId)
@ -58,7 +58,7 @@ export async function deleteAnimeList(arn: AnimeNotifier, button: HTMLElement) {
} }
button.textContent = "Deleting..." button.textContent = "Deleting..."
let {returnPath} = button.dataset const {returnPath} = button.dataset
if(!returnPath) { if(!returnPath) {
console.error("Button without data-return-path:", button) console.error("Button without data-return-path:", button)

View File

@ -2,7 +2,7 @@ import AnimeNotifier from "../AnimeNotifier"
// Play audio // Play audio
export function playAudio(arn: AnimeNotifier, element: HTMLElement) { export function playAudio(arn: AnimeNotifier, element: HTMLElement) {
let {mediaId, audioSrc} = element.dataset const {mediaId, audioSrc} = element.dataset
if(!mediaId || !audioSrc) { if(!mediaId || !audioSrc) {
console.error("Invalid media ID or audio source:", element) console.error("Invalid media ID or audio source:", element)
@ -39,7 +39,7 @@ export async function playNextTrack(arn: AnimeNotifier) {
// Set volume // Set volume
export function setVolume(arn: AnimeNotifier, element: HTMLInputElement) { export function setVolume(arn: AnimeNotifier, element: HTMLInputElement) {
let volume = parseFloat(element.value) / 100.0 const volume = parseFloat(element.value) / 100.0
arn.audioPlayer.setVolume(volume) arn.audioPlayer.setVolume(volume)
} }

View File

@ -3,7 +3,7 @@ import { requestIdleCallback } from "../Utils"
// Load // Load
export function load(arn: AnimeNotifier, element: HTMLElement) { export function load(arn: AnimeNotifier, element: HTMLElement) {
let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") const url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href")
if(!url) { if(!url) {
arn.statusMessage.showError("Link doesn't have a target") arn.statusMessage.showError("Link doesn't have a target")
@ -15,7 +15,7 @@ export function load(arn: AnimeNotifier, element: HTMLElement) {
// Diff // Diff
export async function diff(arn: AnimeNotifier, element: HTMLElement) { export async function diff(arn: AnimeNotifier, element: HTMLElement) {
let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") const url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href")
if(!url) { if(!url) {
arn.statusMessage.showError("Link doesn't have a target") arn.statusMessage.showError("Link doesn't have a target")

View File

@ -6,8 +6,8 @@ export async function newAnimeDiffIgnore(arn: AnimeNotifier, button: HTMLButtonE
return return
} }
let id = button.dataset.id const id = button.dataset.id
let hash = button.dataset.hash const hash = button.dataset.hash
try { try {
await arn.post(`/api/new/ignoreanimedifference`, { await arn.post(`/api/new/ignoreanimedifference`, {
@ -27,15 +27,15 @@ export async function importKitsuAnime(arn: AnimeNotifier, button: HTMLButtonEle
return return
} }
let newTab = window.open() const newTab = window.open()
if(!newTab) { if(!newTab) {
arn.statusMessage.showError("Error opening new tab") arn.statusMessage.showError("Error opening new tab")
return return
} }
let animeId = button.dataset.id const animeId = button.dataset.id
let response = await fetch(`/api/import/kitsu/anime/${animeId}`, { const response = await fetch(`/api/import/kitsu/anime/${animeId}`, {
method: "POST", method: "POST",
credentials: "same-origin" credentials: "same-origin"
}) })
@ -54,22 +54,22 @@ export async function deleteKitsuAnime(arn: AnimeNotifier, button: HTMLButtonEle
return return
} }
let animeId = button.dataset.id const animeId = button.dataset.id
await arn.post(`/api/delete/kitsu/anime/${animeId}`) await arn.post(`/api/delete/kitsu/anime/${animeId}`)
arn.reloadContent() arn.reloadContent()
} }
// Multi-search anime // Multi-search anime
export async function multiSearchAnime(arn: AnimeNotifier, textarea: HTMLTextAreaElement) { export async function multiSearchAnime(arn: AnimeNotifier, textarea: HTMLTextAreaElement) {
let results = document.getElementById("multi-search-anime") as HTMLDivElement const results = document.getElementById("multi-search-anime") as HTMLDivElement
let animeTitles = textarea.value.split("\n") const animeTitles = textarea.value.split("\n")
results.innerHTML = "" results.innerHTML = ""
for(let i = 0; i < animeTitles.length; i++) { for(let i = 0; i < animeTitles.length; i++) {
console.log(animeTitles[i]) console.log(animeTitles[i])
let response = await fetch("/_/anime-search/" + animeTitles[i]) const response = await fetch("/_/anime-search/" + animeTitles[i])
let html = await response.text() const html = await response.text()
results.innerHTML += "<h3>" + animeTitles[i] + "</h3>" + html results.innerHTML += "<h3>" + animeTitles[i] + "</h3>" + html
} }
@ -79,7 +79,7 @@ export async function multiSearchAnime(arn: AnimeNotifier, textarea: HTMLTextAre
// Download soundtrack file // Download soundtrack file
export async function downloadSoundTrackFile(arn: AnimeNotifier, button: HTMLButtonElement) { export async function downloadSoundTrackFile(arn: AnimeNotifier, button: HTMLButtonElement) {
let id = button.dataset.id const id = button.dataset.id
try { try {
await arn.post(`/api/soundtrack/${id}/download`) await arn.post(`/api/soundtrack/${id}/download`)
@ -96,7 +96,7 @@ export async function startJob(arn: AnimeNotifier, button: HTMLButtonElement) {
return return
} }
let jobName = button.dataset.job const jobName = button.dataset.job
if(!confirm(`Are you sure you want to start the "${jobName}" job?`)) { if(!confirm(`Are you sure you want to start the "${jobName}" job?`)) {
return return

View File

@ -3,24 +3,24 @@ import { findAll } from "scripts/Utils"
// Filter anime on explore page // Filter anime on explore page
export function filterAnime(arn: AnimeNotifier, _: HTMLInputElement) { export function filterAnime(arn: AnimeNotifier, _: HTMLInputElement) {
let root = document.getElementById("filter-root") as HTMLElement const root = document.getElementById("filter-root") as HTMLElement
let elementYear = document.getElementById("filter-year") as HTMLSelectElement const elementYear = document.getElementById("filter-year") as HTMLSelectElement
let elementSeason = document.getElementById("filter-season") as HTMLSelectElement const elementSeason = document.getElementById("filter-season") as HTMLSelectElement
let elementStatus = document.getElementById("filter-status") as HTMLSelectElement const elementStatus = document.getElementById("filter-status") as HTMLSelectElement
let elementType = document.getElementById("filter-type") as HTMLSelectElement const elementType = document.getElementById("filter-type") as HTMLSelectElement
for(let element of findAll("anime-grid-image")) { for(const element of findAll("anime-grid-image")) {
let img = element as HTMLImageElement const img = element as HTMLImageElement
img.src = arn.emptyPixel() img.src = arn.emptyPixel()
img.classList.remove("element-found") img.classList.remove("element-found")
img.classList.remove("element-color-preview") img.classList.remove("element-color-preview")
} }
let year = elementYear.value || "any" const year = elementYear.value || "any"
let season = elementSeason.value || "any" const season = elementSeason.value || "any"
let status = elementStatus.value || "any" const status = elementStatus.value || "any"
let type = elementType.value || "any" const type = elementType.value || "any"
arn.diff(`${root.dataset.url}/${year}/${season}/${status}/${type}`) arn.diff(`${root.dataset.url}/${year}/${season}/${status}/${type}`)
} }
@ -32,7 +32,7 @@ export function toggleHideAddedAnime() {
// Hides anime that are already in your list. // Hides anime that are already in your list.
export function hideAddedAnime() { export function hideAddedAnime() {
for(let anime of findAll("anime-grid-cell")) { for(const anime of findAll("anime-grid-cell")) {
if(anime.dataset.added !== "true") { if(anime.dataset.added !== "true") {
continue continue
} }
@ -43,7 +43,7 @@ export function hideAddedAnime() {
// Hides anime that are not in your list. // Hides anime that are not in your list.
export async function calendarShowAddedAnimeOnly(arn: AnimeNotifier, element: HTMLInputElement) { export async function calendarShowAddedAnimeOnly(arn: AnimeNotifier, element: HTMLInputElement) {
let calendar = document.getElementById("calendar") const calendar = document.getElementById("calendar")
if(!calendar || calendar.dataset.showAddedAnimeOnly === undefined) { if(!calendar || calendar.dataset.showAddedAnimeOnly === undefined) {
return return
@ -57,8 +57,8 @@ export async function calendarShowAddedAnimeOnly(arn: AnimeNotifier, element: HT
} }
// Save the state in the database // Save the state in the database
let showAddedAnimeOnly = calendar.dataset.showAddedAnimeOnly === "true" const showAddedAnimeOnly = calendar.dataset.showAddedAnimeOnly === "true"
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint, { await arn.post(apiEndpoint, {

View File

@ -2,22 +2,22 @@ import AnimeNotifier from "../AnimeNotifier"
// Edit post // Edit post
export function editPost(_: AnimeNotifier, element: HTMLElement) { export function editPost(_: AnimeNotifier, element: HTMLElement) {
let postId = element.dataset.id const postId = element.dataset.id
if(!postId) { if(!postId) {
console.error("Post missing post ID:", postId) console.error("Post missing post ID:", postId)
return return
} }
let render = document.getElementById("render-" + postId) as HTMLElement const render = document.getElementById("render-" + postId) as HTMLElement
let source = document.getElementById("source-" + postId) as HTMLElement const source = document.getElementById("source-" + postId) as HTMLElement
let edit = document.getElementById("edit-toolbar-" + postId) as HTMLElement const edit = document.getElementById("edit-toolbar-" + postId) as HTMLElement
render.classList.toggle("hidden") render.classList.toggle("hidden")
source.classList.toggle("hidden") source.classList.toggle("hidden")
edit.classList.toggle("hidden") edit.classList.toggle("hidden")
let title = document.getElementById("title-" + postId) const title = document.getElementById("title-" + postId)
if(title) { if(title) {
title.classList.toggle("hidden") title.classList.toggle("hidden")
@ -26,12 +26,12 @@ export function editPost(_: AnimeNotifier, element: HTMLElement) {
// Save post // Save post
export async function savePost(arn: AnimeNotifier, element: HTMLElement) { export async function savePost(arn: AnimeNotifier, element: HTMLElement) {
let postId = element.dataset.id const postId = element.dataset.id
let source = document.getElementById("source-" + postId) as HTMLTextAreaElement const source = document.getElementById("source-" + postId) as HTMLTextAreaElement
let title = document.getElementById("title-" + postId) as HTMLInputElement const title = document.getElementById("title-" + postId) as HTMLInputElement
let text = source.value const text = source.value
let updates: any = { const updates: any = {
Text: text, Text: text,
} }
@ -40,7 +40,7 @@ export async function savePost(arn: AnimeNotifier, element: HTMLElement) {
updates.Title = title.value updates.Title = title.value
} }
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint, updates) await arn.post(apiEndpoint, updates)
@ -56,7 +56,7 @@ export async function deletePost(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let endpoint = arn.findAPIEndpoint(element) const endpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(endpoint + "/delete") await arn.post(endpoint + "/delete")
@ -68,10 +68,10 @@ export async function deletePost(arn: AnimeNotifier, element: HTMLElement) {
// Create post // Create post
export async function createPost(arn: AnimeNotifier, element: HTMLElement) { export async function createPost(arn: AnimeNotifier, element: HTMLElement) {
let textarea = document.getElementById("new-post-text") as HTMLTextAreaElement const textarea = document.getElementById("new-post-text") as HTMLTextAreaElement
let {parentId, parentType} = element.dataset const {parentId, parentType} = element.dataset
let post = { const post = {
text: textarea.value, text: textarea.value,
parentId, parentId,
parentType, parentType,
@ -89,11 +89,11 @@ export async function createPost(arn: AnimeNotifier, element: HTMLElement) {
// Create thread // Create thread
export async function createThread(arn: AnimeNotifier) { export async function createThread(arn: AnimeNotifier) {
let title = document.getElementById("title") as HTMLInputElement const title = document.getElementById("title") as HTMLInputElement
let text = document.getElementById("text") as HTMLTextAreaElement const text = document.getElementById("text") as HTMLTextAreaElement
let category = document.getElementById("tag") as HTMLInputElement const category = document.getElementById("tag") as HTMLInputElement
let thread = { const thread = {
title: title.value, title: title.value,
text: text.value, text: text.value,
tags: [category.value] tags: [category.value]
@ -109,9 +109,9 @@ export async function createThread(arn: AnimeNotifier) {
// Reply to a post // Reply to a post
export async function reply(arn: AnimeNotifier, element: HTMLElement) { export async function reply(arn: AnimeNotifier, element: HTMLElement) {
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
let repliesId = `replies-${element.dataset.postId}` const repliesId = `replies-${element.dataset.postId}`
let replies = document.getElementById(repliesId) const replies = document.getElementById(repliesId)
if(!replies) { if(!replies) {
console.error("Missing replies container:", element) console.error("Missing replies container:", element)
@ -119,14 +119,14 @@ export async function reply(arn: AnimeNotifier, element: HTMLElement) {
} }
// Delete old reply area // Delete old reply area
let oldReplyArea = document.getElementById("new-post") const oldReplyArea = document.getElementById("new-post")
if(oldReplyArea) { if(oldReplyArea) {
oldReplyArea.remove() oldReplyArea.remove()
} }
// Delete old reply button // Delete old reply button
let oldPostActions = document.getElementsByClassName("new-post-actions")[0] const oldPostActions = document.getElementsByClassName("new-post-actions")[0]
if(oldPostActions) { if(oldPostActions) {
oldPostActions.remove() oldPostActions.remove()
@ -134,8 +134,8 @@ export async function reply(arn: AnimeNotifier, element: HTMLElement) {
// Fetch new reply UI // Fetch new reply UI
try { try {
let response = await fetch(`${apiEndpoint}/reply/ui`) const response = await fetch(`${apiEndpoint}/reply/ui`)
let html = await response.text() const html = await response.text()
replies.innerHTML = html + replies.innerHTML replies.innerHTML = html + replies.innerHTML
arn.onNewContent(replies) arn.onNewContent(replies)
arn.assignActions() arn.assignActions()
@ -161,13 +161,13 @@ export function unlockThread(arn: AnimeNotifier, element: HTMLButtonElement) {
// Set thread locked state // Set thread locked state
async function setThreadLock(arn: AnimeNotifier, element: HTMLButtonElement, state: boolean) { async function setThreadLock(arn: AnimeNotifier, element: HTMLButtonElement, state: boolean) {
let verb = state ? "lock" : "unlock" const verb = state ? "lock" : "unlock"
if(!confirm(`Are you sure you want to ${verb} this Thread?`)) { if(!confirm(`Are you sure you want to ${verb} this Thread?`)) {
return return
} }
let endpoint = arn.findAPIEndpoint(element) const endpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(`${endpoint}/${verb}`) await arn.post(`${endpoint}/${verb}`)

View File

@ -6,7 +6,7 @@ export async function join(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(`${apiEndpoint}/join`) await arn.post(`${apiEndpoint}/join`)
@ -23,7 +23,7 @@ export async function leave(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(`${apiEndpoint}/leave`) await arn.post(`${apiEndpoint}/leave`)

View File

@ -17,10 +17,10 @@ export async function loadMore(arn: AnimeNotifier, button: HTMLButtonElement) {
arn.loading(true) arn.loading(true)
button.disabled = true button.disabled = true
let index = button.dataset.index const index = button.dataset.index
try { try {
let response = await fetch("/_" + arn.app.currentPath + "/from/" + index, { const response = await fetch("/_" + arn.app.currentPath + "/from/" + index, {
credentials: "same-origin" credentials: "same-origin"
}) })
@ -28,7 +28,7 @@ export async function loadMore(arn: AnimeNotifier, button: HTMLButtonElement) {
throw response.statusText throw response.statusText
} }
let newIndex = response.headers.get("X-LoadMore-Index") const newIndex = response.headers.get("X-LoadMore-Index")
// End of data? // End of data?
if(!newIndex || newIndex === "-1") { if(!newIndex || newIndex === "-1") {
@ -39,7 +39,7 @@ export async function loadMore(arn: AnimeNotifier, button: HTMLButtonElement) {
} }
// Get the HTML response // Get the HTML response
let html = await response.text() const html = await response.text()
// Add the HTML to the existing target // Add the HTML to the existing target
Diff.mutations.queue(() => { Diff.mutations.queue(() => {

View File

@ -3,7 +3,7 @@ import AnimeNotifier from "../AnimeNotifier"
// like // like
export async function like(arn: AnimeNotifier, element: HTMLElement) { export async function like(arn: AnimeNotifier, element: HTMLElement) {
arn.statusMessage.showInfo("Liked!", 1000) arn.statusMessage.showInfo("Liked!", 1000)
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint + "/like") await arn.post(apiEndpoint + "/like")
@ -16,7 +16,7 @@ export async function like(arn: AnimeNotifier, element: HTMLElement) {
// unlike // unlike
export async function unlike(arn: AnimeNotifier, element: HTMLElement) { export async function unlike(arn: AnimeNotifier, element: HTMLElement) {
arn.statusMessage.showInfo("Disliked!", 1000) arn.statusMessage.showInfo("Disliked!", 1000)
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint + "/unlike") await arn.post(apiEndpoint + "/unlike")

View File

@ -2,7 +2,7 @@ import AnimeNotifier from "../AnimeNotifier"
// New // New
export async function newObject(arn: AnimeNotifier, button: HTMLButtonElement) { export async function newObject(arn: AnimeNotifier, button: HTMLButtonElement) {
let dataType = button.dataset.type const dataType = button.dataset.type
if(!dataType) { if(!dataType) {
console.error("Missing data type:", button) console.error("Missing data type:", button)
@ -10,13 +10,13 @@ export async function newObject(arn: AnimeNotifier, button: HTMLButtonElement) {
} }
try { try {
let response = await arn.post(`/api/new/${dataType}`) const response = await arn.post(`/api/new/${dataType}`)
if(!response) { if(!response) {
throw `Failed creating ${dataType}` throw `Failed creating ${dataType}`
} }
let json = await response.json() const json = await response.json()
await arn.app.load(`/${dataType}/${json.id}/edit`) await arn.app.load(`/${dataType}/${json.id}/edit`)
} catch(err) { } catch(err) {
arn.statusMessage.showError(err) arn.statusMessage.showError(err)
@ -25,8 +25,8 @@ export async function newObject(arn: AnimeNotifier, button: HTMLButtonElement) {
// Delete // Delete
export async function deleteObject(arn: AnimeNotifier, button: HTMLButtonElement) { export async function deleteObject(arn: AnimeNotifier, button: HTMLButtonElement) {
let confirmType = button.dataset.confirmType const confirmType = button.dataset.confirmType
let returnPath = button.dataset.returnPath const returnPath = button.dataset.returnPath
if(!confirm(`Are you sure you want to delete this ${confirmType}?`)) { if(!confirm(`Are you sure you want to delete this ${confirmType}?`)) {
return return
@ -39,7 +39,7 @@ export async function deleteObject(arn: AnimeNotifier, button: HTMLButtonElement
} }
} }
let endpoint = arn.findAPIEndpoint(button) const endpoint = arn.findAPIEndpoint(button)
try { try {
await arn.post(endpoint + "/delete") await arn.post(endpoint + "/delete")

View File

@ -2,7 +2,7 @@ import AnimeNotifier from "../AnimeNotifier"
// Publish // Publish
export async function publish(arn: AnimeNotifier, button: HTMLButtonElement) { export async function publish(arn: AnimeNotifier, button: HTMLButtonElement) {
let endpoint = arn.findAPIEndpoint(button) const endpoint = arn.findAPIEndpoint(button)
try { try {
await arn.post(endpoint + "/publish") await arn.post(endpoint + "/publish")
@ -14,7 +14,7 @@ export async function publish(arn: AnimeNotifier, button: HTMLButtonElement) {
// Unpublish // Unpublish
export async function unpublish(arn: AnimeNotifier, button: HTMLButtonElement) { export async function unpublish(arn: AnimeNotifier, button: HTMLButtonElement) {
let endpoint = arn.findAPIEndpoint(button) const endpoint = arn.findAPIEndpoint(button)
try { try {
await arn.post(endpoint + "/unpublish") await arn.post(endpoint + "/unpublish")

View File

@ -3,10 +3,10 @@ import { delay, requestIdleCallback } from "../Utils"
import Diff from "scripts/Diff"; import Diff from "scripts/Diff";
// Search page reference // Search page reference
var emptySearchHTML = "" let emptySearchHTML = ""
var searchPage: HTMLElement let searchPage: HTMLElement
var searchPageTitle: HTMLElement let searchPageTitle: HTMLElement
var correctResponseRendered = { const correctResponseRendered = {
"anime": false, "anime": false,
"character": false, "character": false,
"posts": false, "posts": false,
@ -18,13 +18,13 @@ var correctResponseRendered = {
} }
// Search types // Search types
var searchTypes = Object.keys(correctResponseRendered) const searchTypes = Object.keys(correctResponseRendered)
// Save old term to compare // Save old term to compare
var oldTerm = "" let oldTerm = ""
// Containers for all the search results // Containers for all the search results
var results = new Map<string, HTMLElement>() const results = new Map<string, HTMLElement>()
// Delay before a request is sent // Delay before a request is sent
const searchDelay = 140 const searchDelay = 140
@ -44,10 +44,10 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
} }
// Determine if we're already seeing the search page // Determine if we're already seeing the search page
let searchPageActivated = (searchPage === arn.app.content.children[0]) const searchPageActivated = (searchPage === arn.app.content.children[0])
// Check if the search term really changed // Check if the search term really changed
let term = search.value.trim() const term = search.value.trim()
if(term === oldTerm && searchPageActivated) { if(term === oldTerm && searchPageActivated) {
return return
@ -56,12 +56,12 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
oldTerm = term oldTerm = term
// Reset // Reset
for(let key of searchTypes) { for(const key of searchTypes) {
correctResponseRendered[key] = false correctResponseRendered[key] = false
} }
// Set browser URL // Set browser URL
let url = "/search/" + term const url = "/search/" + term
document.title = "Search: " + term document.title = "Search: " + term
arn.app.currentPath = url arn.app.currentPath = url
@ -74,7 +74,7 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
try { try {
// Fetch empty search frame if needed // Fetch empty search frame if needed
if(emptySearchHTML === "") { if(emptySearchHTML === "") {
let response = await fetch("/_/empty-search") const response = await fetch("/_/empty-search")
emptySearchHTML = await response.text() emptySearchHTML = await response.text()
} }
@ -101,7 +101,7 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
} }
if(!results["anime"]) { if(!results["anime"]) {
for(let key of searchTypes) { for(const key of searchTypes) {
results[key] = document.getElementById(`${key}-search-results`) results[key] = document.getElementById(`${key}-search-results`)
} }
@ -128,7 +128,7 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
} }
// Search the other types (everything except anime) // Search the other types (everything except anime)
for(let key of searchTypes) { for(const key of searchTypes) {
if(key === "anime") { if(key === "anime") {
continue continue
} }
@ -151,7 +151,7 @@ function showResponseInElement(arn: AnimeNotifier, url: string, typeName: string
throw response.statusText throw response.statusText
} }
let html = await response.text() const html = await response.text()
if(html.includes("no-search-results")) { if(html.includes("no-search-results")) {
Diff.mutations.queue(() => (element.parentElement as HTMLElement).classList.add("search-section-disabled")) Diff.mutations.queue(() => (element.parentElement as HTMLElement).classList.add("search-section-disabled"))
@ -179,10 +179,10 @@ export function searchBySpeech(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let searchInput = document.getElementById("search") as HTMLInputElement const searchInput = document.getElementById("search") as HTMLInputElement
let oldPlaceholder = searchInput.placeholder const oldPlaceholder = searchInput.placeholder
let SpeechRecognition: any = window["SpeechRecognition"] || window["webkitSpeechRecognition"] const SpeechRecognition: any = window["SpeechRecognition"] || window["webkitSpeechRecognition"]
recognition = new SpeechRecognition() recognition = new SpeechRecognition()
recognition.continuous = false recognition.continuous = false
recognition.interimResults = false recognition.interimResults = false
@ -190,8 +190,8 @@ export function searchBySpeech(arn: AnimeNotifier, element: HTMLElement) {
recognition.onresult = evt => { recognition.onresult = evt => {
if(evt.results.length > 0) { if(evt.results.length > 0) {
let result = evt.results.item(0).item(0) const result = evt.results.item(0).item(0)
let term = result.transcript const term = result.transcript
if(term !== "") { if(term !== "") {
searchInput.value = term searchInput.value = term

View File

@ -8,8 +8,8 @@ export async function save(arn: AnimeNotifier, input: HTMLElement) {
return return
} }
let obj = {} const obj = {}
let isContentEditable = input.isContentEditable const isContentEditable = input.isContentEditable
let value = isContentEditable ? input.textContent : (input as HTMLInputElement).value let value = isContentEditable ? input.textContent : (input as HTMLInputElement).value
if(value === undefined || value === null) { if(value === undefined || value === null) {
@ -35,7 +35,7 @@ export async function save(arn: AnimeNotifier, input: HTMLElement) {
(input as HTMLInputElement).disabled = true (input as HTMLInputElement).disabled = true
} }
let apiEndpoint = arn.findAPIEndpoint(input) const apiEndpoint = arn.findAPIEndpoint(input)
try { try {
await arn.post(apiEndpoint, obj) await arn.post(apiEndpoint, obj)
@ -71,8 +71,8 @@ export async function enable(arn: AnimeNotifier, button: HTMLButtonElement) {
return return
} }
let obj = {} const obj = {}
let apiEndpoint = arn.findAPIEndpoint(button) const apiEndpoint = arn.findAPIEndpoint(button)
obj[button.dataset.field] = true obj[button.dataset.field] = true
button.disabled = true button.disabled = true
@ -99,8 +99,8 @@ export async function disable(arn: AnimeNotifier, button: HTMLButtonElement) {
return return
} }
let obj = {} const obj = {}
let apiEndpoint = arn.findAPIEndpoint(button) const apiEndpoint = arn.findAPIEndpoint(button)
obj[button.dataset.field] = false obj[button.dataset.field] = false
button.disabled = true button.disabled = true
@ -122,9 +122,9 @@ export async function disable(arn: AnimeNotifier, button: HTMLButtonElement) {
// Append new element to array // Append new element to array
export async function arrayAppend(arn: AnimeNotifier, element: HTMLElement) { export async function arrayAppend(arn: AnimeNotifier, element: HTMLElement) {
let field = element.dataset.field const field = element.dataset.field
let object = element.dataset.object || "" const object = element.dataset.object || ""
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint + "/field/" + field + "/append", object) await arn.post(apiEndpoint + "/field/" + field + "/append", object)
@ -140,9 +140,9 @@ export async function arrayRemove(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let field = element.dataset.field const field = element.dataset.field
let index = element.dataset.index const index = element.dataset.index
let apiEndpoint = arn.findAPIEndpoint(element) const apiEndpoint = arn.findAPIEndpoint(element)
try { try {
await arn.post(apiEndpoint + "/field/" + field + "/remove/" + index) await arn.post(apiEndpoint + "/field/" + field + "/remove/" + index)
@ -158,14 +158,14 @@ export function increaseEpisode(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let prev = element.previousSibling const prev = element.previousSibling
if(prev === null || !(prev instanceof HTMLElement) || prev.textContent === null) { if(prev === null || !(prev instanceof HTMLElement) || prev.textContent === null) {
console.error("Previous sibling is invalid:", element) console.error("Previous sibling is invalid:", element)
return return
} }
let episodes = parseInt(prev.textContent) const episodes = parseInt(prev.textContent)
prev.textContent = String(episodes + 1) prev.textContent = String(episodes + 1)
return save(arn, prev) return save(arn, prev)
} }
@ -181,12 +181,12 @@ export function addNumber(arn: AnimeNotifier, element: HTMLElement) {
return return
} }
let input = document.getElementById(element.dataset.id) as HTMLInputElement const input = document.getElementById(element.dataset.id) as HTMLInputElement
let add = parseInt(element.dataset.add) const add = parseInt(element.dataset.add)
let num = parseInt(input.value) const num = parseInt(input.value)
let newValue = num + add const newValue = num + add
let min = parseInt(input.min) const min = parseInt(input.min)
let max = parseInt(input.max) const max = parseInt(input.max)
if(newValue > max) { if(newValue > max) {
arn.statusMessage.showError("Maximum: " + max) arn.statusMessage.showError("Maximum: " + max)

View File

@ -2,7 +2,7 @@ import AnimeNotifier from "../AnimeNotifier"
// Charge up // Charge up
export function chargeUp(arn: AnimeNotifier, button: HTMLElement) { export function chargeUp(arn: AnimeNotifier, button: HTMLElement) {
let amount = button.dataset.amount const amount = button.dataset.amount
arn.loading(true) arn.loading(true)
arn.statusMessage.showInfo("Creating PayPal transaction... This might take a few seconds.") arn.statusMessage.showInfo("Creating PayPal transaction... This might take a few seconds.")
@ -18,7 +18,7 @@ export function chargeUp(arn: AnimeNotifier, button: HTMLElement) {
throw "Error creating PayPal payment" throw "Error creating PayPal payment"
} }
let link = payment.links.find(link => link.rel === "approval_url") const link = payment.links.find(link => link.rel === "approval_url")
if(!link) { if(!link) {
throw "Error finding PayPal payment link" throw "Error finding PayPal payment link"
@ -26,7 +26,7 @@ export function chargeUp(arn: AnimeNotifier, button: HTMLElement) {
arn.statusMessage.showInfo("Redirecting to PayPal...", 5000) arn.statusMessage.showInfo("Redirecting to PayPal...", 5000)
let url = link.href const url = link.href
window.location.href = url window.location.href = url
}) })
.catch(err => arn.statusMessage.showError(err)) .catch(err => arn.statusMessage.showError(err))
@ -35,14 +35,14 @@ export function chargeUp(arn: AnimeNotifier, button: HTMLElement) {
// Toggle fade // Toggle fade
export function toggleFade(_: AnimeNotifier, button: HTMLElement) { export function toggleFade(_: AnimeNotifier, button: HTMLElement) {
let elementId = button.dataset.elementId const elementId = button.dataset.elementId
if(!elementId) { if(!elementId) {
console.error("Missing element ID:", elementId) console.error("Missing element ID:", elementId)
return return
} }
let element = document.getElementById(elementId) const element = document.getElementById(elementId)
if(!element) { if(!element) {
console.error("Invalid element ID:", elementId) console.error("Invalid element ID:", elementId)
@ -58,9 +58,9 @@ export function toggleFade(_: AnimeNotifier, button: HTMLElement) {
// Buy item // Buy item
export function buyItem(arn: AnimeNotifier, button: HTMLElement) { export function buyItem(arn: AnimeNotifier, button: HTMLElement) {
let itemId = button.dataset.itemId const itemId = button.dataset.itemId
let itemName = button.dataset.itemName const itemName = button.dataset.itemName
let price = button.dataset.price const price = button.dataset.price
if(!confirm(`Would you like to buy ${itemName} for ${price} gems?`)) { if(!confirm(`Would you like to buy ${itemName} for ${price} gems?`)) {
return return

View File

@ -2,6 +2,6 @@ import AnimeNotifier from "../AnimeNotifier"
// Toggle sidebar // Toggle sidebar
export function toggleSidebar(_: AnimeNotifier) { export function toggleSidebar(_: AnimeNotifier) {
let sidebar = document.getElementById("sidebar") as HTMLElement const sidebar = document.getElementById("sidebar") as HTMLElement
sidebar.classList.toggle("sidebar-visible") sidebar.classList.toggle("sidebar-visible")
} }

View File

@ -102,7 +102,7 @@ export function nextTheme(arn: AnimeNotifier) {
// Find current index and apply theme of next index // Find current index and apply theme of next index
for(let i = 0; i < themesSorted.length; i++) { for(let i = 0; i < themesSorted.length; i++) {
if(themesSorted[i] === currentThemeName) { if(themesSorted[i] === currentThemeName) {
let newIndex = (i + 1) % themesSorted.length const newIndex = (i + 1) % themesSorted.length
applyThemeAndPreview(arn, themesSorted[newIndex]) applyThemeAndPreview(arn, themesSorted[newIndex])
break break
} }
@ -135,15 +135,15 @@ export function applyThemeAndPreview(arn: AnimeNotifier, themeName: string) {
// Apply theme // Apply theme
export function applyTheme(themeName: string) { export function applyTheme(themeName: string) {
let rootStyle = document.documentElement.style const rootStyle = document.documentElement.style
let theme = themes[themeName] const theme = themes[themeName]
// Apply base theme // Apply base theme
if(theme["base-theme"]) { if(theme["base-theme"]) {
applyTheme(theme["base-theme"]) applyTheme(theme["base-theme"])
} }
for(let property in theme) { for(const property in theme) {
if(!theme.hasOwnProperty(property)) { if(!theme.hasOwnProperty(property)) {
continue continue
} }
@ -164,13 +164,13 @@ export function applyTheme(themeName: string) {
// Color picker // Color picker
export function pickColor(_: AnimeNotifier, element: HTMLElement) { export function pickColor(_: AnimeNotifier, element: HTMLElement) {
let rootStyle = document.documentElement.style const rootStyle = document.documentElement.style
let variableName = `--${element.dataset.variable}` const variableName = `--${element.dataset.variable}`
let input = document.createElement("input") const input = document.createElement("input")
input.type = "color" input.type = "color"
input.oninput = () => { input.oninput = () => {
let color = hexToHSL(input.value) const color = hexToHSL(input.value)
if(!color) { if(!color) {
return return

View File

@ -3,8 +3,8 @@ import { bytesHumanReadable, uploadWithProgress } from "../Utils"
// Select file // Select file
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) { export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
let fileType = button.dataset.type const fileType = button.dataset.type
let endpoint = button.dataset.endpoint const endpoint = button.dataset.endpoint
if(endpoint === "/api/upload/user/cover" && arn.user && arn.user.dataset.pro !== "true") { if(endpoint === "/api/upload/user/cover" && arn.user && arn.user.dataset.pro !== "true") {
alert("Please buy a PRO account to use this feature.") alert("Please buy a PRO account to use this feature.")
@ -12,7 +12,7 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
} }
// Click on virtual file input element // Click on virtual file input element
let input = document.createElement("input") const input = document.createElement("input")
input.setAttribute("type", "file") input.setAttribute("type", "file")
input.value = "" input.value = ""
@ -26,7 +26,7 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
return return
} }
let file = input.files[0] const file = input.files[0]
// Check mime type for images // Check mime type for images
if(fileType === "image" && !file.type.startsWith("image/")) { if(fileType === "image" && !file.type.startsWith("image/")) {
@ -42,9 +42,9 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
// Preview image // Preview image
if(fileType === "image") { if(fileType === "image") {
let previews = document.getElementsByClassName(button.id + "-preview") const previews = document.getElementsByClassName(button.id + "-preview")
let dataURL = await readImageAsDataURL(file) const dataURL = await readImageAsDataURL(file)
let img = await loadImage(dataURL) const img = await loadImage(dataURL)
switch(endpoint) { switch(endpoint) {
case "/api/upload/user/image": case "/api/upload/user/image":
@ -73,11 +73,11 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
// Upload file // Upload file
function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNotifier) { function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNotifier) {
let reader = new FileReader() const reader = new FileReader()
reader.onloadend = async () => { reader.onloadend = async () => {
let result = reader.result as ArrayBuffer const result = reader.result as ArrayBuffer
let fileSize = result.byteLength const fileSize = result.byteLength
if(fileSize === 0) { if(fileSize === 0) {
arn.statusMessage.showError("File is empty") arn.statusMessage.showError("File is empty")
@ -87,7 +87,7 @@ function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNo
arn.statusMessage.showInfo(`Preparing to upload ${fileType} (${bytesHumanReadable(fileSize)})`, -1) arn.statusMessage.showInfo(`Preparing to upload ${fileType} (${bytesHumanReadable(fileSize)})`, -1)
try { try {
let responseText = await uploadWithProgress(endpoint, { const responseText = await uploadWithProgress(endpoint, {
method: "POST", method: "POST",
credentials: "include", credentials: "include",
headers: { headers: {
@ -95,7 +95,7 @@ function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNo
}, },
body: reader.result body: reader.result
}, e => { }, e => {
let progress = e.loaded / (e.lengthComputable ? e.total : fileSize) * 100 const progress = e.loaded / (e.lengthComputable ? e.total : fileSize) * 100
arn.statusMessage.showInfo(`Uploading ${fileType}...${progress.toFixed(1)}%`, -1) arn.statusMessage.showInfo(`Uploading ${fileType}...${progress.toFixed(1)}%`, -1)
}) })
@ -118,10 +118,10 @@ function uploadFile(file: File, fileType: string, endpoint: string, arn: AnimeNo
// Read image as data URL // Read image as data URL
function readImageAsDataURL(file: File): Promise<string> { function readImageAsDataURL(file: File): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let reader = new FileReader() const reader = new FileReader()
reader.onloadend = () => { reader.onloadend = () => {
let dataURL = reader.result as string const dataURL = reader.result as string
resolve(dataURL) resolve(dataURL)
} }
@ -137,7 +137,7 @@ function readImageAsDataURL(file: File): Promise<string> {
// Load image and resolve when loading has finished // Load image and resolve when loading has finished
function loadImage(url: string): Promise<HTMLImageElement> { function loadImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let img = new Image() const img = new Image()
img.src = url img.src = url
img.onload = () => { img.onload = () => {
@ -153,15 +153,15 @@ function loadImage(url: string): Promise<HTMLImageElement> {
// Preview image // Preview image
function previewImage(dataURL: string, endpoint: string, previews: HTMLCollectionOf<Element>) { function previewImage(dataURL: string, endpoint: string, previews: HTMLCollectionOf<Element>) {
if(endpoint === "/api/upload/user/image") { if(endpoint === "/api/upload/user/image") {
let svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement const svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement
if(svgPreview) { if(svgPreview) {
svgPreview.classList.add("hidden") svgPreview.classList.add("hidden")
} }
} }
for(let preview of previews) { for(const preview of previews) {
let img = preview as HTMLImageElement const img = preview as HTMLImageElement
img.classList.remove("hidden") img.classList.remove("hidden")
// Make not found images visible again // Make not found images visible again
@ -176,9 +176,9 @@ function previewImage(dataURL: string, endpoint: string, previews: HTMLCollectio
// Update sidebar avatar // Update sidebar avatar
function updateSideBarAvatar(url: string) { function updateSideBarAvatar(url: string) {
let sidebar = document.getElementById("sidebar") as HTMLElement const sidebar = document.getElementById("sidebar") as HTMLElement
let userImage = sidebar.getElementsByClassName("user-image")[0] as HTMLImageElement const userImage = sidebar.getElementsByClassName("user-image")[0] as HTMLImageElement
let lazyLoad = userImage["became visible"] const lazyLoad = userImage["became visible"]
if(lazyLoad) { if(lazyLoad) {
userImage.dataset.src = url userImage.dataset.src = url

View File

@ -13,8 +13,8 @@ export async function unfollowUser(arn: AnimeNotifier, element: HTMLElement) {
// Update follow // Update follow
async function updateFollow(arn: AnimeNotifier, element: HTMLElement, message: string) { async function updateFollow(arn: AnimeNotifier, element: HTMLElement, message: string) {
let api = element.dataset.api const api = element.dataset.api
let nick = document.getElementById("nick") const nick = document.getElementById("nick")
if(!api || !nick || !nick.textContent) { if(!api || !nick || !nick.textContent) {
console.error("Missing data-api or invalid nick:", element) console.error("Missing data-api or invalid nick:", element)
@ -34,7 +34,7 @@ async function updateFollow(arn: AnimeNotifier, element: HTMLElement, message: s
export function showMore(_: AnimeNotifier, showMoreElement: HTMLElement) { export function showMore(_: AnimeNotifier, showMoreElement: HTMLElement) {
const elements = [...document.getElementsByClassName("show-more")] const elements = [...document.getElementsByClassName("show-more")]
for(let element of elements) { for(const element of elements) {
Diff.mutations.queue(() => element.classList.remove("show-more")) Diff.mutations.queue(() => element.classList.remove("show-more"))
} }

View File

@ -2,21 +2,21 @@ import AnimeNotifier from "../AnimeNotifier"
// Toggle play video // Toggle play video
export function togglePlayVideo(arn: AnimeNotifier, element: HTMLElement) { export function togglePlayVideo(arn: AnimeNotifier, element: HTMLElement) {
let mediaId = element.dataset.mediaId const mediaId = element.dataset.mediaId
if(!mediaId) { if(!mediaId) {
console.error("Missing data-media-id:", element) console.error("Missing data-media-id:", element)
return return
} }
let container = document.getElementById(mediaId) const container = document.getElementById(mediaId)
if(!container) { if(!container) {
console.error("Invalid data-media-id:", element) console.error("Invalid data-media-id:", element)
return return
} }
let video = container.getElementsByTagName("video")[0] const video = container.getElementsByTagName("video")[0]
video.volume = arn.audioPlayer.volume video.volume = arn.audioPlayer.volume
if(video.readyState >= 2) { if(video.readyState >= 2) {
@ -41,23 +41,23 @@ function togglePlayVideoElement(video: HTMLVideoElement) {
// Toggle fullscreen // Toggle fullscreen
export function toggleFullscreen(_: AnimeNotifier, button: HTMLElement) { export function toggleFullscreen(_: AnimeNotifier, button: HTMLElement) {
let elementId = button.dataset.id const elementId = button.dataset.id
if(!elementId) { if(!elementId) {
console.error("Missing data-id:", button) console.error("Missing data-id:", button)
return return
} }
let element = document.getElementById(elementId) const element = document.getElementById(elementId)
if(!element) { if(!element) {
console.error("Invalid data-id:", button) console.error("Invalid data-id:", button)
return return
} }
let requestFullscreen = element.requestFullscreen || element["mozRequestFullScreen"] || element["webkitRequestFullScreen"] || element["msRequestFullscreen"] const requestFullscreen = element.requestFullscreen || element["mozRequestFullScreen"] || element["webkitRequestFullScreen"] || element["msRequestFullscreen"]
let exitFullscreen = document.exitFullscreen || document["mozCancelFullScreen"] || document["webkitExitFullscreen"] || document["msExitFullscreen"] const exitFullscreen = document.exitFullscreen || document["mozCancelFullScreen"] || document["webkitExitFullscreen"] || document["msExitFullscreen"]
let fullscreen = document.fullscreen || document["webkitIsFullScreen"] || document["mozFullScreen"] const fullscreen = document.fullscreen || document["webkitIsFullScreen"] || document["mozFullScreen"]
if(fullscreen) { if(fullscreen) {
exitFullscreen.call(document) exitFullscreen.call(document)

View File

@ -1,6 +1,6 @@
export default class Analytics { export default class Analytics {
push() { push() {
let analytics = { const analytics = {
general: { general: {
timezoneOffset: new Date().getTimezoneOffset() timezoneOffset: new Date().getTimezoneOffset()
}, },
@ -23,7 +23,7 @@ export default class Analytics {
} }
if("connection" in navigator) { if("connection" in navigator) {
let connection = navigator["connection"] as any const connection = navigator["connection"] as any
analytics.connection = { analytics.connection = {
downLink: connection.downlink, downLink: connection.downlink,

View File

@ -115,7 +115,7 @@ export default class AnimeNotifier {
// Enable lazy load // Enable lazy load
this.visibilityObserver = new IntersectionObserver( this.visibilityObserver = new IntersectionObserver(
entries => { entries => {
for(let entry of entries) { for(const entry of entries) {
if(entry.isIntersecting) { if(entry.isIntersecting) {
entry.target["became visible"]() entry.target["became visible"]()
this.visibilityObserver.unobserve(entry.target) this.visibilityObserver.unobserve(entry.target)
@ -203,7 +203,7 @@ export default class AnimeNotifier {
// Auto-focus first input element on welcome page. // Auto-focus first input element on welcome page.
if(location.pathname === "/welcome") { if(location.pathname === "/welcome") {
let firstInput = this.app.content.getElementsByTagName("input")[0] as HTMLInputElement const firstInput = this.app.content.getElementsByTagName("input")[0] as HTMLInputElement
if(firstInput) { if(firstInput) {
firstInput.focus() firstInput.focus()
@ -212,7 +212,7 @@ export default class AnimeNotifier {
} }
applyPageTitle() { applyPageTitle() {
let headers = document.getElementsByTagName("h1") const headers = document.getElementsByTagName("h1")
if(this.app.currentPath === "/" || headers.length === 0 || headers[0].textContent === "NOTIFY.MOE") { if(this.app.currentPath === "/" || headers.length === 0 || headers[0].textContent === "NOTIFY.MOE") {
if(document.title !== this.title) { if(document.title !== this.title) {
@ -281,8 +281,8 @@ export default class AnimeNotifier {
const minHeight = 800 const minHeight = 800
if(window.outerWidth <= minWidth || window.outerHeight <= minHeight) { if(window.outerWidth <= minWidth || window.outerHeight <= minHeight) {
let finalWidth = window.outerWidth < minWidth ? minWidth : window.outerWidth const finalWidth = window.outerWidth < minWidth ? minWidth : window.outerWidth
let finalHeight = window.outerHeight < minHeight ? minHeight : window.outerHeight const finalHeight = window.outerHeight < minHeight ? minHeight : window.outerHeight
window.resizeTo(finalWidth, finalHeight) window.resizeTo(finalWidth, finalHeight)
} }
@ -332,7 +332,7 @@ export default class AnimeNotifier {
this.tip.setAttribute("active", "false") this.tip.setAttribute("active", "false")
// Assign mouse enter event handler // Assign mouse enter event handler
for(let element of elements) { for(const element of elements) {
element.onmouseenter = () => { element.onmouseenter = () => {
this.tip.classList.remove("fade-out") this.tip.classList.remove("fade-out")
this.tip.show(element) this.tip.show(element)
@ -346,21 +346,21 @@ export default class AnimeNotifier {
dragAndDrop() { dragAndDrop() {
if(location.pathname.includes("/animelist/")) { if(location.pathname.includes("/animelist/")) {
for(let listItem of findAll("anime-list-item")) { for(const listItem of findAll("anime-list-item")) {
// Skip elements that have their event listeners attached already // Skip elements that have their event listeners attached already
if(listItem["drag-listeners-attached"]) { if(listItem["drag-listeners-attached"]) {
continue continue
} }
let name = listItem.getElementsByClassName("anime-list-item-name")[0] const name = listItem.getElementsByClassName("anime-list-item-name")[0]
let imageContainer = listItem.getElementsByClassName("anime-list-item-image-container")[0] const imageContainer = listItem.getElementsByClassName("anime-list-item-image-container")[0]
let onDrag = evt => { const onDrag = evt => {
if(!evt.dataTransfer) { if(!evt.dataTransfer) {
return return
} }
let image = imageContainer.getElementsByClassName("anime-list-item-image")[0] const image = imageContainer.getElementsByClassName("anime-list-item-image")[0]
if(image) { if(image) {
evt.dataTransfer.setDragImage(image, 0, 0) evt.dataTransfer.setDragImage(image, 0, 0)
@ -381,7 +381,7 @@ export default class AnimeNotifier {
listItem["drag-listeners-attached"] = true listItem["drag-listeners-attached"] = true
} }
for(let element of findAll("tab")) { for(const element of findAll("tab")) {
// Skip elements that have their event listeners attached already // Skip elements that have their event listeners attached already
if(element["drop-listeners-attached"]) { if(element["drop-listeners-attached"]) {
continue continue
@ -400,7 +400,7 @@ export default class AnimeNotifier {
return return
} }
let data = e.dataTransfer.getData("text/plain") const data = e.dataTransfer.getData("text/plain")
let json: any let json: any
try { try {
@ -416,7 +416,7 @@ export default class AnimeNotifier {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
let tabText = toElement.textContent const tabText = toElement.textContent
if(!tabText) { if(!tabText) {
return return
@ -459,7 +459,7 @@ export default class AnimeNotifier {
} }
if(location.pathname.startsWith("/inventory")) { if(location.pathname.startsWith("/inventory")) {
for(let element of findAll("inventory-slot")) { for(const element of findAll("inventory-slot")) {
// Skip elements that have their event listeners attached already // Skip elements that have their event listeners attached already
if(element["drag-listeners-attached"]) { if(element["drag-listeners-attached"]) {
continue continue
@ -478,13 +478,13 @@ export default class AnimeNotifier {
return return
} }
let itemName = element.getAttribute("aria-label") const itemName = element.getAttribute("aria-label")
if(element.dataset.consumable !== "true") { if(element.dataset.consumable !== "true") {
return this.statusMessage.showError(itemName + " is not a consumable item.") return this.statusMessage.showError(itemName + " is not a consumable item.")
} }
let apiEndpoint = this.findAPIEndpoint(element) const apiEndpoint = this.findAPIEndpoint(element)
try { try {
await this.post(apiEndpoint + "/use/" + element.dataset.index) await this.post(apiEndpoint + "/use/" + element.dataset.index)
@ -513,20 +513,20 @@ export default class AnimeNotifier {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
let inventory = element.parentElement const inventory = element.parentElement
if(!inventory || !e.dataTransfer) { if(!inventory || !e.dataTransfer) {
return return
} }
let fromIndex = e.dataTransfer.getData("text") const fromIndex = e.dataTransfer.getData("text")
if(!fromIndex) { if(!fromIndex) {
return return
} }
let fromElement = inventory.childNodes[fromIndex] as HTMLElement const fromElement = inventory.childNodes[fromIndex] as HTMLElement
let toIndex = element.dataset.index const toIndex = element.dataset.index
if(!toIndex || fromElement === element || fromIndex === toIndex) { if(!toIndex || fromElement === element || fromIndex === toIndex) {
console.error("Invalid drag & drop from", fromIndex, "to", toIndex) console.error("Invalid drag & drop from", fromIndex, "to", toIndex)
@ -534,7 +534,7 @@ export default class AnimeNotifier {
} }
// Swap in database // Swap in database
let apiEndpoint = this.findAPIEndpoint(inventory) const apiEndpoint = this.findAPIEndpoint(inventory)
try { try {
await this.post(apiEndpoint + "/swap/" + fromIndex + "/" + toIndex) await this.post(apiEndpoint + "/swap/" + fromIndex + "/" + toIndex)
@ -560,9 +560,9 @@ export default class AnimeNotifier {
return return
} }
let enableButton = document.getElementById("enable-notifications") as HTMLButtonElement const enableButton = document.getElementById("enable-notifications") as HTMLButtonElement
let disableButton = document.getElementById("disable-notifications") as HTMLButtonElement const disableButton = document.getElementById("disable-notifications") as HTMLButtonElement
let testButton = document.getElementById("test-notification") as HTMLButtonElement const testButton = document.getElementById("test-notification") as HTMLButtonElement
if(!this.pushManager.pushSupported) { if(!this.pushManager.pushSupported) {
enableButton.classList.add("hidden") enableButton.classList.add("hidden")
@ -571,7 +571,7 @@ export default class AnimeNotifier {
return return
} }
let subscription = await this.pushManager.subscription() const subscription = await this.pushManager.subscription()
if(subscription) { if(subscription) {
enableButton.classList.add("hidden") enableButton.classList.add("hidden")
@ -587,16 +587,16 @@ export default class AnimeNotifier {
return return
} }
for(let element of findAll("character-ranking")) { for(const element of findAll("character-ranking")) {
fetch(`/api/character/${element.dataset.characterId}/ranking`).then(async response => { fetch(`/api/character/${element.dataset.characterId}/ranking`).then(async response => {
let ranking = await response.json() const ranking = await response.json()
if(!ranking.rank) { if(!ranking.rank) {
return return
} }
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
let percentile = Math.ceil(ranking.percentile * 100) const percentile = Math.ceil(ranking.percentile * 100)
element.textContent = "#" + ranking.rank.toString() element.textContent = "#" + ranking.rank.toString()
element.title = "Top " + percentile + "%" element.title = "Top " + percentile + "%"
@ -610,7 +610,7 @@ export default class AnimeNotifier {
return return
} }
for(let element of findAll("color-box")) { for(const element of findAll("color-box")) {
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
if(!element.dataset.color) { if(!element.dataset.color) {
console.error("color-box missing data-color attribute:", element) console.error("color-box missing data-color attribute:", element)
@ -627,19 +627,19 @@ export default class AnimeNotifier {
return return
} }
for(let element of findAll("count-up")) { for(const element of findAll("count-up")) {
if(!element.textContent) { if(!element.textContent) {
console.error("count-up missing text content:", element) console.error("count-up missing text content:", element)
continue continue
} }
let final = parseInt(element.textContent) const final = parseInt(element.textContent)
let duration = 2000.0 const duration = 2000.0
let start = Date.now() const start = Date.now()
element.textContent = "0" element.textContent = "0"
let callback = () => { const callback = () => {
let progress = (Date.now() - start) / duration let progress = (Date.now() - start) / duration
if(progress > 1) { if(progress > 1) {
@ -658,7 +658,7 @@ export default class AnimeNotifier {
} }
markPlayingMedia() { markPlayingMedia() {
for(let element of findAll("media-play-area")) { for(const element of findAll("media-play-area")) {
if(element.dataset.mediaId === this.currentMediaId) { if(element.dataset.mediaId === this.currentMediaId) {
element.classList.add("playing") element.classList.add("playing")
} }
@ -666,8 +666,8 @@ export default class AnimeNotifier {
} }
setSelectBoxValue() { setSelectBoxValue() {
for(let element of document.getElementsByTagName("select")) { for(const element of document.getElementsByTagName("select")) {
let attributeValue = element.getAttribute("value") const attributeValue = element.getAttribute("value")
if(!attributeValue) { if(!attributeValue) {
console.error("Select box without a value:", element) console.error("Select box without a value:", element)
@ -681,21 +681,21 @@ export default class AnimeNotifier {
displayLocalDates() { displayLocalDates() {
const now = new Date() const now = new Date()
for(let element of findAll("utc-airing-date")) { for(const element of findAll("utc-airing-date")) {
displayAiringDate(element, now) displayAiringDate(element, now)
} }
for(let element of findAll("utc-date")) { for(const element of findAll("utc-date")) {
displayDate(element, now) displayDate(element, now)
} }
for(let element of findAll("utc-date-absolute")) { for(const element of findAll("utc-date-absolute")) {
displayTime(element) displayTime(element)
} }
} }
reloadContent(cached?: boolean) { reloadContent(cached?: boolean) {
let headers = new Headers() const headers = new Headers()
if(cached) { if(cached) {
headers.set("X-Force-Cache", "true") headers.set("X-Force-Cache", "true")
@ -703,7 +703,7 @@ export default class AnimeNotifier {
headers.set("X-No-Cache", "true") headers.set("X-No-Cache", "true")
} }
let path = this.lastReloadContentPath = this.app.currentPath const path = this.lastReloadContentPath = this.app.currentPath
return fetch("/_" + path, { return fetch("/_" + path, {
credentials: "same-origin", credentials: "same-origin",
@ -724,7 +724,7 @@ export default class AnimeNotifier {
reloadPage() { reloadPage() {
console.log("reload page", this.app.currentPath) console.log("reload page", this.app.currentPath)
let path = this.app.currentPath const path = this.app.currentPath
this.lastReloadContentPath = path this.lastReloadContentPath = path
return fetch(path, { return fetch(path, {
@ -756,16 +756,16 @@ export default class AnimeNotifier {
} }
assignActions() { assignActions() {
for(let element of findAll("action")) { for(const element of findAll("action")) {
let actionTrigger = element.dataset.trigger const actionTrigger = element.dataset.trigger
let actionName = element.dataset.action const actionName = element.dataset.action
// Filter out invalid definitions // Filter out invalid definitions
if(!actionTrigger || !actionName) { if(!actionTrigger || !actionName) {
continue continue
} }
let oldAction = element["action assigned"] const oldAction = element["action assigned"]
if(oldAction) { if(oldAction) {
if(oldAction.trigger === actionTrigger && oldAction.action === actionName) { if(oldAction.trigger === actionTrigger && oldAction.action === actionName) {
@ -787,7 +787,7 @@ export default class AnimeNotifier {
} }
// Register the actual action handler // Register the actual action handler
let actionHandler = e => { const actionHandler = e => {
if(!actionName) { if(!actionName) {
return return
} }
@ -818,7 +818,7 @@ export default class AnimeNotifier {
await this.webpCheck await this.webpCheck
for(let element of elements) { for(const element of elements) {
switch(element.tagName) { switch(element.tagName) {
case "IMG": case "IMG":
this.lazyLoadImage(element as HTMLImageElement) this.lazyLoadImage(element as HTMLImageElement)
@ -840,24 +840,24 @@ export default class AnimeNotifier {
} }
lazyLoadImage(element: HTMLImageElement) { lazyLoadImage(element: HTMLImageElement) {
let pixelRatio = window.devicePixelRatio const pixelRatio = window.devicePixelRatio
// Once the image becomes visible, load it // Once the image becomes visible, load it
element["became visible"] = () => { element["became visible"] = () => {
let dataSrc = element.dataset.src const dataSrc = element.dataset.src
if(!dataSrc) { if(!dataSrc) {
console.error("Image missing data-src attribute:", element) console.error("Image missing data-src attribute:", element)
return return
} }
let dotPos = dataSrc.lastIndexOf(".") const dotPos = dataSrc.lastIndexOf(".")
let base = dataSrc.substring(0, dotPos) let base = dataSrc.substring(0, dotPos)
let extension = "" let extension = ""
// Replace URL with WebP if supported // Replace URL with WebP if supported
if(this.webpEnabled && element.dataset.webp === "true" && !dataSrc.endsWith(".svg")) { if(this.webpEnabled && element.dataset.webp === "true" && !dataSrc.endsWith(".svg")) {
let queryPos = dataSrc.lastIndexOf("?") const queryPos = dataSrc.lastIndexOf("?")
if(queryPos !== -1) { if(queryPos !== -1) {
extension = ".webp" + dataSrc.substring(queryPos) extension = ".webp" + dataSrc.substring(queryPos)
@ -875,7 +875,7 @@ export default class AnimeNotifier {
} }
} }
let finalSrc = base + extension const finalSrc = base + extension
if(element.src !== finalSrc && element.src !== "https:" + finalSrc && element.src !== "https://notify.moe" + finalSrc) { if(element.src !== finalSrc && element.src !== "https:" + finalSrc && element.src !== "https://notify.moe" + finalSrc) {
// Show average color // Show average color
@ -945,7 +945,7 @@ export default class AnimeNotifier {
// Once the video becomes visible, load it // Once the video becomes visible, load it
video["became visible"] = () => { video["became visible"] = () => {
if(!video["listeners attached"]) { if(!video["listeners attached"]) {
let videoParent = video.parentElement const videoParent = video.parentElement
if(!videoParent) { if(!videoParent) {
console.error("video has no parent element") console.error("video has no parent element")
@ -956,16 +956,16 @@ export default class AnimeNotifier {
video.addEventListener("contextmenu", e => e.preventDefault()) video.addEventListener("contextmenu", e => e.preventDefault())
// Show and hide controls on mouse movement // Show and hide controls on mouse movement
let controls = videoParent.getElementsByClassName("video-controls")[0] const controls = videoParent.getElementsByClassName("video-controls")[0]
let playButton = videoParent.getElementsByClassName("video-control-play")[0] as HTMLElement const playButton = videoParent.getElementsByClassName("video-control-play")[0] as HTMLElement
let pauseButton = videoParent.getElementsByClassName("video-control-pause")[0] as HTMLElement const pauseButton = videoParent.getElementsByClassName("video-control-pause")[0] as HTMLElement
let hideControls = () => { const hideControls = () => {
controls.classList.add("fade-out") controls.classList.add("fade-out")
video.style.cursor = "none" video.style.cursor = "none"
} }
let showControls = () => { const showControls = () => {
controls.classList.remove("fade-out") controls.classList.remove("fade-out")
video.style.cursor = "default" video.style.cursor = "default"
} }
@ -976,9 +976,9 @@ export default class AnimeNotifier {
video["hideControlsTimeout"] = setTimeout(hideControls, hideControlsDelay) video["hideControlsTimeout"] = setTimeout(hideControls, hideControlsDelay)
}) })
let progressElement = videoParent.getElementsByClassName("video-progress")[0] as HTMLElement const progressElement = videoParent.getElementsByClassName("video-progress")[0] as HTMLElement
let progressClickable = videoParent.getElementsByClassName("video-progress-clickable")[0] const progressClickable = videoParent.getElementsByClassName("video-progress-clickable")[0]
let timeElement = videoParent.getElementsByClassName("video-time")[0] const timeElement = videoParent.getElementsByClassName("video-time")[0]
video.addEventListener("canplay", () => { video.addEventListener("canplay", () => {
video["playable"] = true video["playable"] = true
@ -989,10 +989,10 @@ export default class AnimeNotifier {
return return
} }
let time = video.currentTime const time = video.currentTime
let minutes = Math.trunc(time / 60) const minutes = Math.trunc(time / 60)
let seconds = Math.trunc(time) % 60 const seconds = Math.trunc(time) % 60
let paddedSeconds = ("00" + seconds).slice(-2) const paddedSeconds = ("00" + seconds).slice(-2)
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
timeElement.textContent = `${minutes}:${paddedSeconds}` timeElement.textContent = `${minutes}:${paddedSeconds}`
@ -1019,9 +1019,9 @@ export default class AnimeNotifier {
}) })
progressClickable.addEventListener("click", (e: MouseEvent) => { progressClickable.addEventListener("click", (e: MouseEvent) => {
let rect = progressClickable.getBoundingClientRect() const rect = progressClickable.getBoundingClientRect()
let x = e.clientX const x = e.clientX
let progress = (x - rect.left) / rect.width const progress = (x - rect.left) / rect.width
video.currentTime = progress * video.duration video.currentTime = progress * video.duration
video.dispatchEvent(new Event("timeupdate")) video.dispatchEvent(new Event("timeupdate"))
e.stopPropagation() e.stopPropagation()
@ -1032,12 +1032,12 @@ export default class AnimeNotifier {
let modified = false let modified = false
for(let child of video.children) { for(const child of video.children) {
if(child.tagName !== "SOURCE") { if(child.tagName !== "SOURCE") {
continue continue
} }
let element = child as HTMLSourceElement const element = child as HTMLSourceElement
if(!element.dataset.src || !element.dataset.type) { if(!element.dataset.src || !element.dataset.type) {
console.error("Source element missing data-src or data-type attribute:", element) console.error("Source element missing data-src or data-type attribute:", element)
@ -1077,7 +1077,7 @@ export default class AnimeNotifier {
} }
unmountMountables() { unmountMountables() {
for(let element of findAll("mountable")) { for(const element of findAll("mountable")) {
if(element.classList.contains("never-unmount")) { if(element.classList.contains("never-unmount")) {
continue continue
} }
@ -1091,13 +1091,13 @@ export default class AnimeNotifier {
const delay = 20 const delay = 20
let time = 0 let time = 0
let start = Date.now() const start = Date.now()
let maxTime = start + maxDelay const maxTime = start + maxDelay
let mountableTypes = new Map<string, number>() const mountableTypes = new Map<string, number>()
let mountableTypeMutations = new Map<string, any[]>() const mountableTypeMutations = new Map<string, any[]>()
for(let element of elements) { for(const element of elements) {
// Skip already mounted elements. // Skip already mounted elements.
// This helps a lot when dealing with infinite scrolling // This helps a lot when dealing with infinite scrolling
// where the first elements are already mounted. // where the first elements are already mounted.
@ -1105,8 +1105,8 @@ export default class AnimeNotifier {
continue continue
} }
let type = element.dataset.mountableType || "general" const type = element.dataset.mountableType || "general"
let typeTime = mountableTypes.get(type) const typeTime = mountableTypes.get(type)
if(typeTime !== undefined) { if(typeTime !== undefined) {
time = typeTime + delay time = typeTime + delay
@ -1132,11 +1132,11 @@ export default class AnimeNotifier {
for(const mutations of mountableTypeMutations.values()) { for(const mutations of mountableTypeMutations.values()) {
let mutationIndex = 0 let mutationIndex = 0
let updateBatch = () => { const updateBatch = () => {
let now = Date.now() const now = Date.now()
for(; mutationIndex < mutations.length; mutationIndex++) { for(; mutationIndex < mutations.length; mutationIndex++) {
let mutation = mutations[mutationIndex] const mutation = mutations[mutationIndex]
if(mutation.time > now) { if(mutation.time > now) {
break break
@ -1159,11 +1159,11 @@ export default class AnimeNotifier {
return null return null
} }
let path = "/_" + url const path = "/_" + url
try { try {
// Start the request // Start the request
let request = fetch(path, { const request = fetch(path, {
credentials: "same-origin" credentials: "same-origin"
}) })
.then(response => response.text()) .then(response => response.text())
@ -1178,7 +1178,7 @@ export default class AnimeNotifier {
// Delay by mountable-transition-speed // Delay by mountable-transition-speed
await delay(150) await delay(150)
let html = await request const html = await request
// If the response for the correct path has not arrived yet, show this response // If the response for the correct path has not arrived yet, show this response
if(!this.diffCompletedForCurrentPath) { if(!this.diffCompletedForCurrentPath) {
@ -1251,22 +1251,22 @@ export default class AnimeNotifier {
const contentPadding = 23 const contentPadding = 23
let newScroll = 0 let newScroll = 0
let finalScroll = Math.max(target.getBoundingClientRect().top - contentPadding, 0) const finalScroll = Math.max(target.getBoundingClientRect().top - contentPadding, 0)
// Calculating scrollTop will force a layout - careful! // Calculating scrollTop will force a layout - careful!
let contentContainer = this.app.content.parentElement as HTMLElement const contentContainer = this.app.content.parentElement as HTMLElement
let oldScroll = contentContainer.scrollTop const oldScroll = contentContainer.scrollTop
let scrollDistance = finalScroll - oldScroll const scrollDistance = finalScroll - oldScroll
if(scrollDistance > 0 && scrollDistance < 1) { if(scrollDistance > 0 && scrollDistance < 1) {
return return
} }
let timeStart = Date.now() const timeStart = Date.now()
let timeEnd = timeStart + duration const timeEnd = timeStart + duration
let scroll = () => { const scroll = () => {
let time = Date.now() const time = Date.now()
let progress = (time - timeStart) / duration let progress = (time - timeStart) / duration
if(progress > 1.0) { if(progress > 1.0) {
@ -1322,7 +1322,7 @@ export default class AnimeNotifier {
} }
onKeyDown(e: KeyboardEvent) { onKeyDown(e: KeyboardEvent) {
let activeElement = document.activeElement const activeElement = document.activeElement
if(!activeElement) { if(!activeElement) {
return return
@ -1343,7 +1343,7 @@ export default class AnimeNotifier {
} }
// When called, this will prevent the default action for that key. // When called, this will prevent the default action for that key.
let preventDefault = () => { const preventDefault = () => {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
} }
@ -1375,7 +1375,7 @@ export default class AnimeNotifier {
// "F" = Search // "F" = Search
if(e.keyCode === 70) { if(e.keyCode === 70) {
let search = document.getElementById("search") as HTMLInputElement const search = document.getElementById("search") as HTMLInputElement
search.focus() search.focus()
search.select() search.select()
@ -1429,11 +1429,11 @@ export default class AnimeNotifier {
// Number keys activate sidebar menus // Number keys activate sidebar menus
for(let i = 48; i <= 57; i++) { for(let i = 48; i <= 57; i++) {
if(e.keyCode === i) { if(e.keyCode === i) {
let index = i === 48 ? 9 : i - 49 const index = i === 48 ? 9 : i - 49
let links = [...findAll("sidebar-link")] const links = [...findAll("sidebar-link")]
if(index < links.length) { if(index < links.length) {
let element = links[index] as HTMLElement const element = links[index] as HTMLElement
element.click() element.click()
return preventDefault() return preventDefault()
@ -1444,7 +1444,7 @@ export default class AnimeNotifier {
// This is called every time an uncaught JavaScript error is thrown // This is called every time an uncaught JavaScript error is thrown
async onError(evt: ErrorEvent) { async onError(evt: ErrorEvent) {
let report = { const report = {
message: evt.message, message: evt.message,
stack: evt.error.stack, stack: evt.error.stack,
fileName: evt.filename, fileName: evt.filename,

View File

@ -53,7 +53,7 @@ export default class AudioPlayer {
} }
this.playId++ this.playId++
let currentPlayId = this.playId const currentPlayId = this.playId
if(this.lastRequest) { if(this.lastRequest) {
this.lastRequest.abort() this.lastRequest.abort()
@ -73,7 +73,7 @@ export default class AudioPlayer {
this.audioPlayer.classList.remove("decoded") this.audioPlayer.classList.remove("decoded")
// Request // Request
let request = new XMLHttpRequest() const request = new XMLHttpRequest()
request.open("GET", trackUrl, true) request.open("GET", trackUrl, true)
request.responseType = "arraybuffer" request.responseType = "arraybuffer"
@ -133,7 +133,7 @@ export default class AudioPlayer {
return return
} }
let progress = e.loaded / e.total * 100 const progress = e.loaded / e.total * 100
this.arn.statusMessage.showInfo(`Loading audio...${progress.toFixed(1)}%`, -1) this.arn.statusMessage.showInfo(`Loading audio...${progress.toFixed(1)}%`, -1)
} }
@ -197,9 +197,9 @@ export default class AudioPlayer {
this.arn.currentMediaId = "" this.arn.currentMediaId = ""
// Remove CSS class "playing" // Remove CSS class "playing"
let playingElements = document.getElementsByClassName("playing") const playingElements = document.getElementsByClassName("playing")
for(let playing of playingElements) { for(const playing of playingElements) {
playing.classList.remove("playing") playing.classList.remove("playing")
} }
@ -238,8 +238,8 @@ export default class AudioPlayer {
// Next track // Next track
async next() { async next() {
// Get random track // Get random track
let response = await fetch("/api/next/soundtrack") const response = await fetch("/api/next/soundtrack")
let track = await response.json() const track = await response.json()
this.play(track.id, "https://notify.moe/audio/" + track.file) this.play(track.id, "https://notify.moe/audio/" + track.file)
// arn.statusMessage.showInfo("Now playing: " + track.title) // arn.statusMessage.showInfo("Now playing: " + track.title)
@ -293,8 +293,8 @@ export default class AudioPlayer {
// Update track info // Update track info
async updateTrackInfo(trackId: string) { async updateTrackInfo(trackId: string) {
// Set track title // Set track title
let trackInfoResponse = await fetch("/api/soundtrack/" + trackId) const trackInfoResponse = await fetch("/api/soundtrack/" + trackId)
let track = await trackInfoResponse.json() const track = await trackInfoResponse.json()
this.trackLink.href = "/soundtrack/" + track.id this.trackLink.href = "/soundtrack/" + track.id
this.trackLink.textContent = track.title.canonical || track.title.native this.trackLink.textContent = track.title.canonical || track.title.native
@ -305,7 +305,7 @@ export default class AudioPlayer {
return return
} }
for(let tag of (track.tags as string[])) { for(const tag of (track.tags as string[])) {
if(tag.startsWith("anime:")) { if(tag.startsWith("anime:")) {
animeId = tag.split(":")[1] animeId = tag.split(":")[1]
break break
@ -318,8 +318,8 @@ export default class AudioPlayer {
// Set anime info // Set anime info
this.animeInfo.classList.remove("hidden") this.animeInfo.classList.remove("hidden")
let animeResponse = await fetch("/api/anime/" + animeId) const animeResponse = await fetch("/api/anime/" + animeId)
let anime = await animeResponse.json() as Anime const anime = await animeResponse.json() as Anime
this.animeLink.title = anime.title.canonical this.animeLink.title = anime.title.canonical
this.animeLink.href = "/anime/" + anime.id this.animeLink.href = "/anime/" + anime.id
this.animeImage.dataset.src = "//media.notify.moe/images/anime/medium/" + anime.id + ".jpg?" + anime.image.lastModified.toString() this.animeImage.dataset.src = "//media.notify.moe/images/anime/medium/" + anime.id + ".jpg?" + anime.image.lastModified.toString()

View File

@ -8,14 +8,14 @@ const oneWeek = 7 * oneDay
const oneMonth = 30 * oneDay const oneMonth = 30 * oneDay
const oneYear = 365.25 * oneDay const oneYear = 365.25 * oneDay
export var monthNames = [ export let monthNames = [
"January", "February", "March", "January", "February", "March",
"April", "May", "June", "July", "April", "May", "June", "July",
"August", "September", "October", "August", "September", "October",
"November", "December" "November", "December"
] ]
export var dayNames = [ export let dayNames = [
"Sunday", "Sunday",
"Monday", "Monday",
"Tuesday", "Tuesday",
@ -26,7 +26,7 @@ export var dayNames = [
] ]
function getRemainingTime(remaining: number): string { function getRemainingTime(remaining: number): string {
let remainingAbs = Math.abs(remaining) const remainingAbs = Math.abs(remaining)
if(remainingAbs >= oneYear) { if(remainingAbs >= oneYear) {
return plural(Math.round(remaining / oneYear), "year") return plural(Math.round(remaining / oneYear), "year")
@ -65,20 +65,20 @@ export function displayAiringDate(element: HTMLElement, now: Date) {
return return
} }
let startDate = new Date(element.dataset.startDate) const startDate = new Date(element.dataset.startDate)
let endDate = new Date(element.dataset.endDate) const endDate = new Date(element.dataset.endDate)
let h = startDate.getHours() let h = startDate.getHours()
let m = startDate.getMinutes() let m = startDate.getMinutes()
let startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m) const startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m)
h = endDate.getHours() h = endDate.getHours()
m = endDate.getMinutes() m = endDate.getMinutes()
let endTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m) const endTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m)
let airingVerb = "will be airing" let airingVerb = "will be airing"
let remaining = startDate.getTime() - now.getTime() const remaining = startDate.getTime() - now.getTime()
let remainingString = getRemainingTime(remaining) let remainingString = getRemainingTime(remaining)
// Add "ago" if the date is in the past // Add "ago" if the date is in the past
@ -92,7 +92,7 @@ export function displayAiringDate(element: HTMLElement, now: Date) {
airingVerb = "aired" airingVerb = "aired"
} }
let tooltip = "Episode " + element.dataset.episodeNumber + " " + airingVerb + " " + dayNames[startDate.getDay()] + " from " + startTime + " - " + endTime const tooltip = "Episode " + element.dataset.episodeNumber + " " + airingVerb + " " + dayNames[startDate.getDay()] + " from " + startTime + " - " + endTime
if(element.classList.contains("no-tip")) { if(element.classList.contains("no-tip")) {
element.title = tooltip element.title = tooltip
@ -108,13 +108,13 @@ export function displayDate(element: HTMLElement, now: Date) {
return return
} }
let startDate = new Date(element.dataset.date) const startDate = new Date(element.dataset.date)
let h = startDate.getHours() const h = startDate.getHours()
let m = startDate.getMinutes() const m = startDate.getMinutes()
let startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m) const startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m)
let remaining = startDate.getTime() - now.getTime() const remaining = startDate.getTime() - now.getTime()
let remainingString = getRemainingTime(remaining) let remainingString = getRemainingTime(remaining)
// Add "ago" if the date is in the past // Add "ago" if the date is in the past
@ -123,7 +123,7 @@ export function displayDate(element: HTMLElement, now: Date) {
} }
element.textContent = remainingString element.textContent = remainingString
let tooltip = dayNames[startDate.getDay()] + " " + startTime const tooltip = dayNames[startDate.getDay()] + " " + startTime
if(element.classList.contains("no-tip")) { if(element.classList.contains("no-tip")) {
element.title = tooltip element.title = tooltip
@ -139,11 +139,11 @@ export function displayTime(element: HTMLElement) {
return return
} }
let startDate = new Date(element.dataset.date) const startDate = new Date(element.dataset.date)
let h = startDate.getHours() const h = startDate.getHours()
let m = startDate.getMinutes() const m = startDate.getMinutes()
let startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m) const startTime = (h <= 9 ? "0" + h : h) + ":" + (m <= 9 ? "0" + m : m)
element.textContent = startTime element.textContent = startTime
} }

View File

@ -18,7 +18,7 @@ export default class Diff {
// innerHTML will diff the element with the given HTML string and apply DOM mutations. // innerHTML will diff the element with the given HTML string and apply DOM mutations.
static innerHTML(aRoot: HTMLElement, html: string): Promise<void> { static innerHTML(aRoot: HTMLElement, html: string): Promise<void> {
let container = document.createElement("main") const container = document.createElement("main")
container.innerHTML = html container.innerHTML = html
return new Promise((resolve, _) => { return new Promise((resolve, _) => {
@ -30,7 +30,7 @@ export default class Diff {
// root will diff the document root element with the given HTML string and apply DOM mutations. // root will diff the document root element with the given HTML string and apply DOM mutations.
static root(aRoot: HTMLElement, html: string) { static root(aRoot: HTMLElement, html: string) {
return new Promise((resolve, _) => { return new Promise((resolve, _) => {
let rootContainer = document.createElement("html") const rootContainer = document.createElement("html")
rootContainer.innerHTML = html.replace("<!DOCTYPE html>", "") rootContainer.innerHTML = html.replace("<!DOCTYPE html>", "")
Diff.childNodes(aRoot.getElementsByTagName("body")[0], rootContainer.getElementsByTagName("body")[0]) Diff.childNodes(aRoot.getElementsByTagName("body")[0], rootContainer.getElementsByTagName("body")[0])
@ -40,12 +40,12 @@ export default class Diff {
// childNodes diffs the child nodes of 2 given elements and applies DOM mutations. // childNodes diffs the child nodes of 2 given elements and applies DOM mutations.
static childNodes(aRoot: Node, bRoot: Node) { static childNodes(aRoot: Node, bRoot: Node) {
let aChild = [...aRoot.childNodes] const aChild = [...aRoot.childNodes]
let bChild = [...bRoot.childNodes] const bChild = [...bRoot.childNodes]
let numNodes = Math.max(aChild.length, bChild.length) const numNodes = Math.max(aChild.length, bChild.length)
for(let i = 0; i < numNodes; i++) { for(let i = 0; i < numNodes; i++) {
let a = aChild[i] const a = aChild[i]
// Remove nodes at the end of a that do not exist in b // Remove nodes at the end of a that do not exist in b
if(i >= bChild.length) { if(i >= bChild.length) {
@ -53,7 +53,7 @@ export default class Diff {
continue continue
} }
let b = bChild[i] const b = bChild[i]
// If a doesn't have that many nodes, simply append at the end of a // If a doesn't have that many nodes, simply append at the end of a
if(i >= aChild.length) { if(i >= aChild.length) {
@ -77,13 +77,13 @@ export default class Diff {
// HTML element: // HTML element:
if(a.nodeType === Node.ELEMENT_NODE) { if(a.nodeType === Node.ELEMENT_NODE) {
let elemA = a as HTMLElement const elemA = a as HTMLElement
let elemB = b as HTMLElement const elemB = b as HTMLElement
let removeAttributes: Attr[] = [] const removeAttributes: Attr[] = []
for(let x = 0; x < elemA.attributes.length; x++) { for(let x = 0; x < elemA.attributes.length; x++) {
let attrib = elemA.attributes[x] const attrib = elemA.attributes[x]
if(attrib.specified) { if(attrib.specified) {
if(!elemB.hasAttribute(attrib.name) && !Diff.persistentAttributes.has(attrib.name)) { if(!elemB.hasAttribute(attrib.name) && !Diff.persistentAttributes.has(attrib.name)) {
@ -93,13 +93,13 @@ export default class Diff {
} }
this.mutations.queue(() => { this.mutations.queue(() => {
for(let attr of removeAttributes) { for(const attr of removeAttributes) {
elemA.removeAttributeNode(attr) elemA.removeAttributeNode(attr)
} }
}) })
for(let x = 0; x < elemB.attributes.length; x++) { for(let x = 0; x < elemB.attributes.length; x++) {
let attrib = elemB.attributes[x] const attrib = elemB.attributes[x]
if(!attrib.specified) { if(!attrib.specified) {
continue continue
@ -111,22 +111,22 @@ export default class Diff {
} }
if(attrib.name === "class") { if(attrib.name === "class") {
let classesA = elemA.classList const classesA = elemA.classList
let classesB = elemB.classList const classesB = elemB.classList
let removeClasses: string[] = [] const removeClasses: string[] = []
for(let className of classesA) { for(const className of classesA) {
if(!classesB.contains(className) && !Diff.persistentClasses.has(className)) { if(!classesB.contains(className) && !Diff.persistentClasses.has(className)) {
removeClasses.push(className) removeClasses.push(className)
} }
} }
this.mutations.queue(() => { this.mutations.queue(() => {
for(let className of removeClasses) { for(const className of removeClasses) {
classesA.remove(className) classesA.remove(className)
} }
for(let className of classesB) { for(const className of classesB) {
if(!classesA.contains(className)) { if(!classesA.contains(className)) {
classesA.add(className) classesA.add(className)
} }

View File

@ -14,10 +14,10 @@ export default class SVGIcon extends HTMLElement {
} }
async render() { async render() {
let cache = SVGIcon.cache.get(this.name) const cache = SVGIcon.cache.get(this.name)
if(cache) { if(cache) {
let svg = await cache const svg = await cache
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
// Remove all existing child nodes // Remove all existing child nodes
@ -33,8 +33,8 @@ export default class SVGIcon extends HTMLElement {
} }
SVGIcon.cache.set(this.name, new Promise(async (resolve, reject) => { SVGIcon.cache.set(this.name, new Promise(async (resolve, reject) => {
let url = `//media.notify.moe/images/icons/${this.name}.svg` const url = `//media.notify.moe/images/icons/${this.name}.svg`
let response = await fetch(url) const response = await fetch(url)
if(!response.ok) { if(!response.ok) {
console.warn(`Failed loading SVG icon: ${url}`) console.warn(`Failed loading SVG icon: ${url}`)
@ -42,11 +42,11 @@ export default class SVGIcon extends HTMLElement {
return return
} }
let text = await response.text() const text = await response.text()
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
this.innerHTML = text this.innerHTML = text
let svg = this.firstChild const svg = this.firstChild
if(!svg) { if(!svg) {
console.warn("Invalid SVG icon:", svg) console.warn("Invalid SVG icon:", svg)

View File

@ -25,13 +25,13 @@ export default class ToolTip extends HTMLElement {
this.anchor = anchor this.anchor = anchor
this.box.textContent = this.anchor.getAttribute("aria-label") this.box.textContent = this.anchor.getAttribute("aria-label")
let anchorRect = this.anchor.getBoundingClientRect() const anchorRect = this.anchor.getBoundingClientRect()
let boxRect = this.box.getBoundingClientRect() const boxRect = this.box.getBoundingClientRect()
let finalX = anchorRect.left + anchorRect.width / 2 - boxRect.width / 2 let finalX = anchorRect.left + anchorRect.width / 2 - boxRect.width / 2
let finalY = anchorRect.top - boxRect.height let finalY = anchorRect.top - boxRect.height
let contentRect = { const contentRect = {
left: distanceToBorder, left: distanceToBorder,
top: distanceToBorder, top: distanceToBorder,
right: document.body.clientWidth - distanceToBorder, right: document.body.clientWidth - distanceToBorder,
@ -54,7 +54,7 @@ export default class ToolTip extends HTMLElement {
finalY += offsetY finalY += offsetY
} }
let arrowX = boxRect.width / 2 - offsetX const arrowX = boxRect.width / 2 - offsetX
Diff.mutations.queue(() => { Diff.mutations.queue(() => {
this.style.left = finalX + "px" this.style.left = finalX + "px"

View File

@ -8,7 +8,7 @@ export default class InfiniteScroller {
this.container = container this.container = container
this.threshold = threshold this.threshold = threshold
let check = () => { const check = () => {
if(this.container.scrollTop + this.container.clientHeight >= this.container.scrollHeight - threshold) { if(this.container.scrollTop + this.container.clientHeight >= this.container.scrollHeight - threshold) {
this.loadMore() this.loadMore()
} }
@ -28,7 +28,7 @@ export default class InfiniteScroller {
} }
loadMore() { loadMore() {
let button = document.getElementById("load-more-button") const button = document.getElementById("load-more-button")
if(!button) { if(!button) {
return return

View File

@ -26,7 +26,7 @@ export default class MutationQueue {
} }
mutateAll() { mutateAll() {
let start = performance.now() const start = performance.now()
for(let i = 0; i < this.mutations.length; i++) { for(let i = 0; i < this.mutations.length; i++) {
if(performance.now() - start > timeCapacity) { if(performance.now() - start > timeCapacity) {
@ -49,7 +49,7 @@ export default class MutationQueue {
this.mutations.length = 0 this.mutations.length = 0
if(this.onClearCallBacks.length > 0) { if(this.onClearCallBacks.length > 0) {
for(let callback of this.onClearCallBacks) { for(const callback of this.onClearCallBacks) {
callback() callback()
} }

View File

@ -11,11 +11,11 @@ export default class NotificationManager {
} }
async update() { async update() {
let response = await fetch("/api/count/notifications/unseen", { const response = await fetch("/api/count/notifications/unseen", {
credentials: "same-origin" credentials: "same-origin"
}) })
let body = await response.text() const body = await response.text()
this.setCounter(parseInt(body)) this.setCounter(parseInt(body))
} }

View File

@ -10,8 +10,8 @@ export default class PushManager {
return Promise.resolve(null) return Promise.resolve(null)
} }
let registration = await navigator.serviceWorker.ready const registration = await navigator.serviceWorker.ready
let subscription = await registration.pushManager.getSubscription() const subscription = await registration.pushManager.getSubscription()
return Promise.resolve(subscription) return Promise.resolve(subscription)
} }
@ -21,7 +21,7 @@ export default class PushManager {
return return
} }
let registration = await navigator.serviceWorker.ready const registration = await navigator.serviceWorker.ready
let subscription = await registration.pushManager.getSubscription() let subscription = await registration.pushManager.getSubscription()
if(!subscription) { if(!subscription) {
@ -41,8 +41,8 @@ export default class PushManager {
return return
} }
let registration = await navigator.serviceWorker.ready const registration = await navigator.serviceWorker.ready
let subscription = await registration.pushManager.getSubscription() const subscription = await registration.pushManager.getSubscription()
if(!subscription) { if(!subscription) {
console.error("Subscription does not exist") console.error("Subscription does not exist")
@ -57,15 +57,15 @@ export default class PushManager {
subscribeOnServer(subscription: PushSubscription, userId: string) { subscribeOnServer(subscription: PushSubscription, userId: string) {
console.log("Send subscription to server...") console.log("Send subscription to server...")
let rawKey = subscription.getKey("p256dh") const rawKey = subscription.getKey("p256dh")
let key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : "" const key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : ""
let rawSecret = subscription.getKey("auth") const rawSecret = subscription.getKey("auth")
let secret = rawSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawSecret))) : "" const secret = rawSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawSecret))) : ""
let endpoint = subscription.endpoint const endpoint = subscription.endpoint
let pushSubscription = { const pushSubscription = {
endpoint, endpoint,
p256dh: key, p256dh: key,
auth: secret, auth: secret,
@ -88,7 +88,7 @@ export default class PushManager {
console.log("Send unsubscription to server...") console.log("Send unsubscription to server...")
console.log(subscription) console.log(subscription)
let pushSubscription = { const pushSubscription = {
endpoint: subscription.endpoint endpoint: subscription.endpoint
} }

View File

@ -49,9 +49,9 @@ export default class ServerEvents {
} }
etag(e: ServerEvent) { etag(e: ServerEvent) {
let data = JSON.parse(e.data) const data = JSON.parse(e.data)
let oldETag = this.etags.get(data.url) const oldETag = this.etags.get(data.url)
let newETag = data.etag const newETag = data.etag
if(oldETag && newETag && oldETag != newETag) { if(oldETag && newETag && oldETag != newETag) {
this.arn.statusMessage.showInfo("A new version of the website is available. Please refresh the page.", -1) this.arn.statusMessage.showInfo("A new version of the website is available. Please refresh the page.", -1)
@ -65,7 +65,7 @@ export default class ServerEvents {
return return
} }
let isFollowingUser = JSON.parse(e.data) const isFollowingUser = JSON.parse(e.data)
// If we're on the followed only feed and we receive an activity // If we're on the followed only feed and we receive an activity
// about a user we don't follow, ignore the message. // about a user we don't follow, ignore the message.
@ -73,19 +73,19 @@ export default class ServerEvents {
return return
} }
let button = document.getElementById("load-new-activities") const button = document.getElementById("load-new-activities")
if(!button || !button.dataset.count) { if(!button || !button.dataset.count) {
return return
} }
let buttonText = document.getElementById("load-new-activities-text") const buttonText = document.getElementById("load-new-activities-text")
if(!buttonText) { if(!buttonText) {
return return
} }
let newCount = parseInt(button.dataset.count) + 1 const newCount = parseInt(button.dataset.count) + 1
button.dataset.count = newCount.toString() button.dataset.count = newCount.toString()
buttonText.textContent = plural(newCount, "new activity") buttonText.textContent = plural(newCount, "new activity")
} }

View File

@ -47,7 +47,7 @@ class MyCache {
async store(request: RequestInfo, response: Response) { async store(request: RequestInfo, response: Response) {
try { try {
// This can fail if the disk space quota has been exceeded. // This can fail if the disk space quota has been exceeded.
let cache = await caches.open(this.version) const cache = await caches.open(this.version)
await cache.put(request, response) await cache.put(request, response)
} catch(err) { } catch(err) {
console.log("Disk quota exceeded, can't store in cache:", request, response, err) console.log("Disk quota exceeded, can't store in cache:", request, response, err)
@ -55,8 +55,8 @@ class MyCache {
} }
async serve(request: RequestInfo): Promise<Response> { async serve(request: RequestInfo): Promise<Response> {
let cache = await caches.open(this.version) const cache = await caches.open(this.version)
let matching = await cache.match(request) const matching = await cache.match(request)
if(matching) { if(matching) {
return matching return matching
@ -100,12 +100,12 @@ function onActivate(_: any) {
console.log("service worker activate") console.log("service worker activate")
// Only keep current version of the cache and delete old caches // Only keep current version of the cache and delete old caches
let cacheWhitelist = [cache.version] const cacheWhitelist = [cache.version]
// Query existing cache keys // Query existing cache keys
let deleteOldCache = caches.keys().then(keyList => { const deleteOldCache = caches.keys().then(keyList => {
// Create a deletion for every key that's not whitelisted // Create a deletion for every key that's not whitelisted
let deletions = keyList.map(key => { const deletions = keyList.map(key => {
if(cacheWhitelist.indexOf(key) === -1) { if(cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key) return caches.delete(key)
} }
@ -118,7 +118,7 @@ function onActivate(_: any) {
}) })
// Immediate claim helps us gain control over a new client immediately // Immediate claim helps us gain control over a new client immediately
let immediateClaim = self.clients.claim() const immediateClaim = self.clients.claim()
return Promise.all([ return Promise.all([
deleteOldCache, deleteOldCache,
@ -130,7 +130,7 @@ function onActivate(_: any) {
// Simply returning, without calling evt.respondWith(), // Simply returning, without calling evt.respondWith(),
// will let the browser deal with the request normally. // will let the browser deal with the request normally.
async function onRequest(evt: FetchEvent) { async function onRequest(evt: FetchEvent) {
let request = evt.request as Request const request = evt.request as Request
// If it's not a GET request, fetch it normally. // If it's not a GET request, fetch it normally.
// Let the browser handle XHR upload requests via POST, // Let the browser handle XHR upload requests via POST,
@ -248,16 +248,16 @@ async function onRequest(evt: FetchEvent) {
// onMessage is called when the service worker receives a message from a client (browser tab). // onMessage is called when the service worker receives a message from a client (browser tab).
async function onMessage(evt: ServiceWorkerMessageEvent) { async function onMessage(evt: ServiceWorkerMessageEvent) {
let message = JSON.parse(evt.data) const message = JSON.parse(evt.data)
let clientId = (evt.source as any).id const clientId = (evt.source as any).id
let client = await MyClient.get(clientId) const client = await MyClient.get(clientId)
client.onMessage(message) client.onMessage(message)
} }
// onPush is called on push events and requires the payload to contain JSON information about the notification. // onPush is called on push events and requires the payload to contain JSON information about the notification.
function onPush(evt: PushEvent) { function onPush(evt: PushEvent) {
var payload = evt.data ? evt.data.json() : {} const payload = evt.data ? evt.data.json() : {}
// Notify all clients about the new notification so they can update their notification counter // Notify all clients about the new notification so they can update their notification counter
broadcast({ broadcast({
@ -278,15 +278,15 @@ function onPushSubscriptionChange(evt: any) {
.then(async subscription => { .then(async subscription => {
console.log("send subscription to server...") console.log("send subscription to server...")
let rawKey = subscription.getKey("p256dh") const rawKey = subscription.getKey("p256dh")
let key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : "" const key = rawKey ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawKey))) : ""
let rawSecret = subscription.getKey("auth") const rawSecret = subscription.getKey("auth")
let secret = rawSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawSecret))) : "" const secret = rawSecret ? btoa(String.fromCharCode.apply(null, new Uint8Array(rawSecret))) : ""
let endpoint = subscription.endpoint const endpoint = subscription.endpoint
let pushSubscription = { const pushSubscription = {
endpoint, endpoint,
p256dh: key, p256dh: key,
auth: secret, auth: secret,
@ -298,8 +298,8 @@ function onPushSubscriptionChange(evt: any) {
} }
} }
let response = await fetch("/api/me", {credentials: "same-origin"}) const response = await fetch("/api/me", {credentials: "same-origin"})
let user = await response.json() const user = await response.json()
return fetch("/api/pushsubscriptions/" + user.id + "/add", { return fetch("/api/pushsubscriptions/" + user.id + "/add", {
method: "POST", method: "POST",
@ -311,12 +311,12 @@ function onPushSubscriptionChange(evt: any) {
// onNotificationClick is called when the user clicks on a notification. // onNotificationClick is called when the user clicks on a notification.
function onNotificationClick(evt: NotificationEvent) { function onNotificationClick(evt: NotificationEvent) {
let notification = evt.notification const notification = evt.notification
notification.close() notification.close()
return self.clients.matchAll().then(function(clientList) { return self.clients.matchAll().then(function(clientList) {
// If we have a link, use that link to open a new window. // If we have a link, use that link to open a new window.
let url = notification.data const url = notification.data
if(url) { if(url) {
return self.clients.openWindow(url) return self.clients.openWindow(url)
@ -337,7 +337,7 @@ function broadcast(msg: object) {
const msgText = JSON.stringify(msg) const msgText = JSON.stringify(msg)
self.clients.matchAll().then(function(clientList) { self.clients.matchAll().then(function(clientList) {
for(let client of clientList) { for(const client of clientList) {
client.postMessage(msgText) client.postMessage(msgText)
} }
}) })
@ -345,7 +345,7 @@ function broadcast(msg: object) {
// installCache is called when the service worker is installed for the first time. // installCache is called when the service worker is installed for the first time.
function installCache() { function installCache() {
let urls = [ const urls = [
"/", "/",
"/scripts", "/scripts",
"/styles", "/styles",
@ -353,8 +353,8 @@ function installCache() {
"https://media.notify.moe/images/elements/noise-strong.png", "https://media.notify.moe/images/elements/noise-strong.png",
] ]
let requests = urls.map(async url => { const requests = urls.map(async url => {
let request = new Request(url, { const request = new Request(url, {
credentials: "same-origin", credentials: "same-origin",
mode: "cors" mode: "cors"
}) })

View File

@ -22,7 +22,7 @@ export default class ServiceWorkerManager {
}) })
// This will send a message to the service worker that the DOM has been loaded // This will send a message to the service worker that the DOM has been loaded
let sendContentLoadedEvent = () => { const sendContentLoadedEvent = () => {
if(!navigator.serviceWorker.controller) { if(!navigator.serviceWorker.controller) {
return return
} }
@ -71,7 +71,7 @@ export default class ServiceWorkerManager {
} }
onMessage(evt: MessageEvent) { onMessage(evt: MessageEvent) {
let message = JSON.parse(evt.data) const message = JSON.parse(evt.data)
switch(message.type) { switch(message.type) {
case "new notification": case "new notification":

View File

@ -30,7 +30,7 @@ export default class SideBar {
} }
toggle() { toggle() {
let visible = this.element.style.display !== "none" const visible = this.element.style.display !== "none"
if(visible) { if(visible) {
this.element.style.display = "none" this.element.style.display = "none"

View File

@ -1,5 +1,5 @@
export function* findAll(className: string): IterableIterator<HTMLElement> { export function* findAll(className: string): IterableIterator<HTMLElement> {
let elements = document.getElementsByClassName(className) const elements = document.getElementsByClassName(className)
for(let i = 0; i < elements.length; ++i) { for(let i = 0; i < elements.length; ++i) {
yield elements[i] as HTMLElement yield elements[i] as HTMLElement
@ -7,7 +7,7 @@ export function* findAll(className: string): IterableIterator<HTMLElement> {
} }
export function* findAllInside(className: string, root: HTMLElement): IterableIterator<HTMLElement> { export function* findAllInside(className: string, root: HTMLElement): IterableIterator<HTMLElement> {
let elements = root.getElementsByClassName(className) const elements = root.getElementsByClassName(className)
for(let i = 0; i < elements.length; ++i) { for(let i = 0; i < elements.length; ++i) {
yield elements[i] as HTMLElement yield elements[i] as HTMLElement

View File

@ -1,5 +1,5 @@
export function hexToHSL(hex: string) { export function hexToHSL(hex: string) {
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
if(!result) { if(!result) {
return null return null
@ -13,17 +13,17 @@ export function hexToHSL(hex: string) {
g /= 255 g /= 255
b /= 255 b /= 255
let max = Math.max(r, g, b) const max = Math.max(r, g, b)
let min = Math.min(r, g, b) const min = Math.min(r, g, b)
let h = 0 let h = 0
let s = 0 let s = 0
let l = (max + min) / 2 const l = (max + min) / 2
if(max == min) { if(max == min) {
h = s = 0 h = s = 0
} else { } else {
let d = max - min const d = max - min
s = l > 0.5 ? d / (2 - max - min) : d / (max + min) s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
switch(max) { switch(max) {

View File

@ -1,7 +1,7 @@
// swapElements assumes that both elements have valid parent nodes. // swapElements assumes that both elements have valid parent nodes.
export function swapElements(a: Node, b: Node) { export function swapElements(a: Node, b: Node) {
let bParent = b.parentNode as Node const bParent = b.parentNode as Node
let bNext = b.nextSibling const bNext = b.nextSibling
// Special case for when a is the next sibling of b // Special case for when a is the next sibling of b
if(bNext === a) { if(bNext === a) {

View File

@ -1,6 +1,6 @@
export function uploadWithProgress(url, options: RequestInit, onProgress: ((ev: ProgressEvent) => any) | null): Promise<string> { export function uploadWithProgress(url, options: RequestInit, onProgress: ((ev: ProgressEvent) => any) | null): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest() const xhr = new XMLHttpRequest()
xhr.onload = () => { xhr.onload = () => {
if(xhr.status >= 400) { if(xhr.status >= 400) {
@ -21,7 +21,7 @@ export function uploadWithProgress(url, options: RequestInit, onProgress: ((ev:
xhr.open(options.method || "GET", url, true) xhr.open(options.method || "GET", url, true)
if(options.headers) { if(options.headers) {
for(let key in options.headers) { for(const key in options.headers) {
xhr.setRequestHeader(key, options.headers[key]) xhr.setRequestHeader(key, options.headers[key])
} }
} }

View File

@ -9,7 +9,9 @@
"indent": [true, "tabs", 4], "indent": [true, "tabs", 4],
"whitespace": false, "whitespace": false,
"arrow-parens": false, "arrow-parens": false,
"trailing-comma": false "trailing-comma": false,
"prefer-const": true,
"no-var-keyword": true
}, },
"rulesDirectory": [] "rulesDirectory": []
} }