Added final null checks

This commit is contained in:
Eduard Urbach 2019-04-22 15:59:08 +09:00
parent 70a62f06e5
commit 480ba3a370
8 changed files with 145 additions and 93 deletions

View File

@ -17,18 +17,14 @@ var correctResponseRendered = {
"company": false
}
// Search types
var searchTypes = Object.keys(correctResponseRendered)
// Save old term to compare
var oldTerm = ""
// Containers for all the search results
var animeSearchResults: HTMLElement
var characterSearchResults: HTMLElement
var postsSearchResults: HTMLElement
var threadsSearchResults: HTMLElement
var soundtrackSearchResults: HTMLElement
var userSearchResults: HTMLElement
var amvSearchResults: HTMLElement
var companySearchResults: HTMLElement
var results = new Map<string, HTMLElement>()
// Delay before a request is sent
const searchDelay = 140
@ -60,14 +56,9 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
oldTerm = term
// Reset
correctResponseRendered.anime = false
correctResponseRendered.character = false
correctResponseRendered.posts = false
correctResponseRendered.threads = false
correctResponseRendered.soundtrack = false
correctResponseRendered.user = false
correctResponseRendered.amv = false
correctResponseRendered.company = false
for(let key of searchTypes) {
correctResponseRendered[key] = false
}
// Set browser URL
let url = "/search/" + term
@ -109,15 +100,11 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
return
}
if(!animeSearchResults) {
animeSearchResults = document.getElementById("anime-search-results")
characterSearchResults = document.getElementById("character-search-results")
postsSearchResults = document.getElementById("posts-search-results")
threadsSearchResults = document.getElementById("threads-search-results")
soundtrackSearchResults = document.getElementById("soundtrack-search-results")
userSearchResults = document.getElementById("user-search-results")
amvSearchResults = document.getElementById("amv-search-results")
companySearchResults = document.getElementById("company-search-results")
if(!results["anime"]) {
for(let key of searchTypes) {
results[key] = document.getElementById(`${key}-search-results`)
}
searchPageTitle = document.getElementsByTagName("h1")[0]
}
@ -129,9 +116,9 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
return
}
// Start searching
// Start searching anime
fetch("/_/anime-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "anime", animeSearchResults))
.then(showResponseInElement(arn, url, "anime", results["anime"]))
.catch(console.error)
requestIdleCallback(() => {
@ -140,33 +127,16 @@ export async function search(arn: AnimeNotifier, search: HTMLInputElement, evt?:
return
}
fetch("/_/character-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "character", characterSearchResults))
.catch(console.error)
// Search the other types (everything except anime)
for(let key of searchTypes) {
if(key === "anime") {
continue
}
fetch("/_/posts-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "posts", postsSearchResults))
.catch(console.error)
fetch("/_/threads-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "threads", threadsSearchResults))
.catch(console.error)
fetch("/_/soundtrack-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "soundtrack", soundtrackSearchResults))
.catch(console.error)
fetch("/_/user-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "user", userSearchResults))
.catch(console.error)
fetch("/_/amv-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "amv", amvSearchResults))
.catch(console.error)
fetch("/_/company-search/" + term, fetchOptions)
.then(showResponseInElement(arn, url, "company", companySearchResults))
.catch(console.error)
fetch(`/_/${key}-search/` + term, fetchOptions)
.then(showResponseInElement(arn, url, key, results[key]))
.catch(console.error)
}
})
} catch(err) {
console.error(err)
@ -180,9 +150,9 @@ function showResponseInElement(arn: AnimeNotifier, url: string, typeName: string
let html = await response.text()
if(html.includes("no-search-results")) {
Diff.mutations.queue(() => element.parentElement.classList.add("search-section-disabled"))
Diff.mutations.queue(() => (element.parentElement as HTMLElement).classList.add("search-section-disabled"))
} else {
Diff.mutations.queue(() => element.parentElement.classList.remove("search-section-disabled"))
Diff.mutations.queue(() => (element.parentElement as HTMLElement).classList.remove("search-section-disabled"))
}
if(arn.app.currentPath !== url) {
@ -236,7 +206,6 @@ export function searchBySpeech(arn: AnimeNotifier, element: HTMLElement) {
recognition.onend = e => {
searchInput.placeholder = oldPlaceholder
element.classList.remove("speech-listening")
recognition = null
}
// Focus search field

View File

@ -3,11 +3,16 @@ import { applyTheme } from "./Theme"
// Save new data from an input field
export async function save(arn: AnimeNotifier, input: HTMLElement) {
if(!input.dataset.field) {
console.error("Input element missing data-field:", input)
return
}
let obj = {}
let isContentEditable = input.isContentEditable
let value = isContentEditable ? input.textContent : (input as HTMLInputElement).value
if(value === undefined) {
if(value === undefined || value === null) {
return
}
@ -61,6 +66,11 @@ export async function save(arn: AnimeNotifier, input: HTMLElement) {
// Enable (bool field)
export async function enable(arn: AnimeNotifier, button: HTMLButtonElement) {
if(!button.dataset.field) {
console.error("Button missing data-field:", button)
return
}
let obj = {}
let apiEndpoint = arn.findAPIEndpoint(button)
@ -84,6 +94,11 @@ export async function enable(arn: AnimeNotifier, button: HTMLButtonElement) {
// Disable (bool field)
export async function disable(arn: AnimeNotifier, button: HTMLButtonElement) {
if(!button.dataset.field) {
console.error("Button missing data-field:", button)
return
}
let obj = {}
let apiEndpoint = arn.findAPIEndpoint(button)
@ -106,18 +121,21 @@ export async function disable(arn: AnimeNotifier, button: HTMLButtonElement) {
}
// Append new element to array
export function arrayAppend(arn: AnimeNotifier, element: HTMLElement) {
export async function arrayAppend(arn: AnimeNotifier, element: HTMLElement) {
let field = element.dataset.field
let object = element.dataset.object || ""
let apiEndpoint = arn.findAPIEndpoint(element)
arn.post(apiEndpoint + "/field/" + field + "/append", object)
.then(() => arn.reloadContent())
.catch(err => arn.statusMessage.showError(err))
try {
await arn.post(apiEndpoint + "/field/" + field + "/append", object)
await arn.reloadContent()
} catch(err) {
arn.statusMessage.showError(err)
}
}
// Remove element from array
export function arrayRemove(arn: AnimeNotifier, element: HTMLElement) {
export async function arrayRemove(arn: AnimeNotifier, element: HTMLElement) {
if(!confirm("Are you sure you want to remove this element?")) {
return
}
@ -126,9 +144,12 @@ export function arrayRemove(arn: AnimeNotifier, element: HTMLElement) {
let index = element.dataset.index
let apiEndpoint = arn.findAPIEndpoint(element)
arn.post(apiEndpoint + "/field/" + field + "/remove/" + index)
.then(() => arn.reloadContent())
.catch(err => arn.statusMessage.showError(err))
try {
await arn.post(apiEndpoint + "/field/" + field + "/remove/" + index)
await arn.reloadContent()
} catch(err) {
arn.statusMessage.showError(err)
}
}
// Increase episode
@ -137,10 +158,16 @@ export function increaseEpisode(arn: AnimeNotifier, element: HTMLElement) {
return
}
let prev = element.previousSibling as HTMLElement
let prev = element.previousSibling
if(prev === null || !(prev instanceof HTMLElement) || prev.textContent === null) {
console.error("Previous sibling is invalid:", element)
return
}
let episodes = parseInt(prev.textContent)
prev.textContent = String(episodes + 1)
save(arn, prev)
return save(arn, prev)
}
// Add number
@ -149,6 +176,11 @@ export function addNumber(arn: AnimeNotifier, element: HTMLElement) {
return
}
if(!element.dataset.id || !element.dataset.add) {
console.error("Element is missing the data-id or data-add attribute:", element)
return
}
let input = document.getElementById(element.dataset.id) as HTMLInputElement
let add = parseInt(element.dataset.add)
let num = parseInt(input.value)
@ -167,5 +199,5 @@ export function addNumber(arn: AnimeNotifier, element: HTMLElement) {
}
input.value = newValue.toString()
save(arn, input)
return save(arn, input)
}

View File

@ -36,8 +36,19 @@ export function chargeUp(arn: AnimeNotifier, button: HTMLElement) {
// Toggle fade
export function toggleFade(arn: AnimeNotifier, button: HTMLElement) {
let elementId = button.dataset.elementId
if(!elementId) {
console.error("Missing element ID:", elementId)
return
}
let element = document.getElementById(elementId)
if(!element) {
console.error("Invalid element ID:", elementId)
return
}
if(element.classList.contains("fade-out")) {
element.classList.remove("fade-out")
} else {

View File

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

View File

@ -3,26 +3,31 @@ import { bytesHumanReadable, uploadWithProgress } from "../Utils"
// Select file
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
if(button.dataset.endpoint === "/api/upload/cover" && arn.user.dataset.pro !== "true") {
let fileType = button.dataset.type
let endpoint = button.dataset.endpoint
if(endpoint === "/api/upload/cover" && arn.user && arn.user.dataset.pro !== "true") {
alert("Please buy a PRO account to use this feature.")
return
}
let fileType = button.dataset.type
let endpoint = button.dataset.endpoint
// Click on virtual file input element
let input = document.createElement("input")
input.setAttribute("type", "file")
input.value = null
input.value = ""
input.onchange = async () => {
let file = input.files[0]
if(!file) {
if(!fileType || !endpoint) {
console.error("Missing data-type or data-endpoint:", button)
return
}
if(!input.files || input.files.length === 0) {
return
}
let file = input.files[0]
// Check mime type for images
if(fileType === "image" && !file.type.startsWith("image/")) {
arn.statusMessage.showError(file.name + " is not an image file!")
@ -171,7 +176,7 @@ function previewImage(dataURL: string, endpoint: string, previews: HTMLCollectio
// Update sidebar avatar
function updateSideBarAvatar(url: string) {
let sidebar = document.getElementById("sidebar")
let sidebar = document.getElementById("sidebar") as HTMLElement
let userImage = sidebar.getElementsByClassName("user-image")[0] as HTMLImageElement
let lazyLoad = userImage["became visible"]

View File

@ -3,21 +3,28 @@ import Diff from "scripts/Diff"
// Follow user
export async function followUser(arn: AnimeNotifier, element: HTMLElement) {
try {
await arn.post(element.dataset.api)
await arn.reloadContent()
arn.statusMessage.showInfo("You are now following " + document.getElementById("nick").textContent + ".")
} catch(err) {
arn.statusMessage.showError(err)
}
return updateFollow(arn, element, "You are now following")
}
// Unfollow user
export async function unfollowUser(arn: AnimeNotifier, element: HTMLElement) {
return updateFollow(arn, element, "You stopped following")
}
// Update follow
async function updateFollow(arn: AnimeNotifier, element: HTMLElement, message: string) {
let api = element.dataset.api
let nick = document.getElementById("nick")
if(!api || !nick || !nick.textContent) {
console.error("Missing data-api or invalid nick:", element)
return
}
try {
await arn.post(element.dataset.api)
await arn.post(api)
await arn.reloadContent()
arn.statusMessage.showInfo("You stopped following " + document.getElementById("nick").textContent + ".")
arn.statusMessage.showInfo(`${message} ${nick.textContent}.`)
} catch(err) {
arn.statusMessage.showError(err)
}

View File

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

View File

@ -1474,7 +1474,7 @@ export default class AnimeNotifier {
}
// This is called every time an uncaught JavaScript error is thrown
onError(evt: ErrorEvent) {
async onError(evt: ErrorEvent) {
let report = {
message: evt.message,
stack: evt.error.stack,
@ -1483,8 +1483,11 @@ export default class AnimeNotifier {
columnNumber: evt.colno,
}
this.post("/api/new/clienterrorreport", report)
.then(() => console.log("Successfully reported the error to the website staff."))
.catch(() => console.warn("Failed reporting the error to the website staff."))
try {
await this.post("/api/new/clienterrorreport", report)
console.log("Successfully reported the error to the website staff.")
} catch(err) {
console.warn("Failed reporting the error to the website staff:", err)
}
}
}