mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-27 11:26:22 -07:00
Fix errors pointed out by eslint
This commit is contained in:
parent
8dd98d2abf
commit
04d0948dc2
23 changed files with 345 additions and 343 deletions
|
@ -22,9 +22,9 @@ module.exports = {
|
|||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"indent": ["error", "tab"],
|
||||
"indent": ["warn", "tab"],
|
||||
"linebreak-style": ["error", "unix"],
|
||||
"quotes": ["error", "double", {
|
||||
"quotes": ["warn", "double", {
|
||||
"allowTemplateLiterals": true
|
||||
}],
|
||||
"semi": ["error", "always"],
|
||||
|
|
|
@ -20,7 +20,6 @@ export async function getBoardList() {
|
|||
url: webroot + "boards.json",
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
success: (d2 => {}),
|
||||
error: function(_err, _status, statusText) {
|
||||
console.error("Error getting board list: " + statusText);
|
||||
return nullBoardsList;
|
||||
|
@ -33,13 +32,12 @@ export async function getBoardList() {
|
|||
}
|
||||
|
||||
export async function getCatalog(board = "") {
|
||||
let useBoard = (board != "")?board:currentBoard();
|
||||
const useBoard = (board != "")?board:currentBoard();
|
||||
|
||||
const data = await $.ajax({
|
||||
url: webroot + useBoard + "/catalog.json",
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
success: (() => { }),
|
||||
error: function (err, status, statusText) {
|
||||
console.error(`Error getting catalog for /${board}/: ${statusText}`);
|
||||
}
|
||||
|
@ -52,7 +50,7 @@ export async function getCatalog(board = "") {
|
|||
}
|
||||
|
||||
export async function getThread(board = "", thread = 0) {
|
||||
let threadInfo = currentThread();
|
||||
const threadInfo = currentThread();
|
||||
if(board != "")
|
||||
threadInfo.board = board;
|
||||
if(thread > 0)
|
||||
|
|
|
@ -3,9 +3,9 @@ import $ from "jquery";
|
|||
import { openQR } from "./dom/qr";
|
||||
|
||||
export function handleKeydown(e: JQuery.KeyDownEvent) {
|
||||
let ta = e.target;
|
||||
let isPostMsg = ta.nodeName == "TEXTAREA" && ta.name == "postmsg";
|
||||
let inForm = ta.form != undefined;
|
||||
const ta = e.target;
|
||||
const isPostMsg = ta.nodeName == "TEXTAREA" && ta.name == "postmsg";
|
||||
const inForm = ta.form != undefined;
|
||||
if(!inForm && !e.ctrlKey && e.keyCode == 81) {
|
||||
openQR();
|
||||
} else if(isPostMsg && e.ctrlKey) {
|
||||
|
@ -16,35 +16,35 @@ export function handleKeydown(e: JQuery.KeyDownEvent) {
|
|||
export function applyBBCode(e: JQuery.KeyDownEvent) {
|
||||
let tag = "";
|
||||
switch(e.keyCode) {
|
||||
case 10: // Enter key
|
||||
case 13: // Enter key in Chrome/IE
|
||||
// trigger the form submit event, whether the QR post box or the static post box is currently
|
||||
$(e.target).parents("form#postform,form#qrpostform").trigger("submit");
|
||||
case 10: // Enter key
|
||||
case 13: // Enter key in Chrome/IE
|
||||
// trigger the form submit event, whether the QR post box or the static post box is currently
|
||||
$(e.target).parents("form#postform,form#qrpostform").trigger("submit");
|
||||
break;
|
||||
case 66: // B
|
||||
tag = "b"; // bold
|
||||
case 66: // B
|
||||
tag = "b"; // bold
|
||||
break;
|
||||
case 73: // I
|
||||
tag = "i"; // italics
|
||||
case 73: // I
|
||||
tag = "i"; // italics
|
||||
break;
|
||||
case 82: // R
|
||||
tag = "s"; // strikethrough
|
||||
case 82: // R
|
||||
tag = "s"; // strikethrough
|
||||
break;
|
||||
case 83:
|
||||
tag = "?"; // spoiler (not yet implemented)
|
||||
case 83:
|
||||
tag = "?"; // spoiler (not yet implemented)
|
||||
break;
|
||||
case 85: // U
|
||||
tag = "u"; // underline
|
||||
case 85: // U
|
||||
tag = "u"; // underline
|
||||
break;
|
||||
}
|
||||
if(tag == "") return;
|
||||
|
||||
e.preventDefault();
|
||||
let ta = e.target;
|
||||
let val = ta.value;
|
||||
let ss = ta.selectionStart;
|
||||
let se = ta.selectionEnd;
|
||||
let r = se + 2 + tag.length;
|
||||
const ta = e.target;
|
||||
const val = ta.value;
|
||||
const ss = ta.selectionStart;
|
||||
const se = ta.selectionEnd;
|
||||
const r = se + 2 + tag.length;
|
||||
ta.value = val.slice(0, ss) +
|
||||
`[${tag}]` +
|
||||
val.slice(ss, se) +
|
||||
|
|
|
@ -7,10 +7,10 @@ const YEAR_IN_MS = 365*24*60*60*1000;
|
|||
*/
|
||||
export function getCookie(name: string, defaultVal = "") {
|
||||
let val = defaultVal;
|
||||
let cookieArr = document.cookie.split("; ");
|
||||
const cookieArr = document.cookie.split("; ");
|
||||
|
||||
for(const cookie of cookieArr) {
|
||||
let pair = cookie.split("=");
|
||||
const pair = cookie.split("=");
|
||||
if(pair[0] != name) continue;
|
||||
try {
|
||||
val = decodeURIComponent(pair[1]).replace("+", " ");
|
||||
|
@ -47,7 +47,7 @@ export function setCookie(name: string, value: string, expires = "", root = webr
|
|||
let expiresStr = "";
|
||||
if(expires == "") {
|
||||
expiresStr = ";expires=";
|
||||
let d = new Date();
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + YEAR_IN_MS);
|
||||
expiresStr += d.toUTCString();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import $ from "jquery";
|
||||
|
||||
const emptyFunc = () => {};
|
||||
|
||||
const noop = () => {
|
||||
return;
|
||||
};
|
||||
export function removeLightbox(...customs: any) {
|
||||
$(".lightbox, .lightbox-bg").remove();
|
||||
for(const custom of customs) {
|
||||
|
@ -20,7 +21,7 @@ export function showLightBox(title: string, innerHTML: string) {
|
|||
function simpleLightbox(properties: any = {}, customCSS: any = {}, $elements: any[] = []) {
|
||||
if(properties["class"] === undefined)
|
||||
properties["class"] = "lightbox";
|
||||
let defaultCSS: {[key: string]: string} = {
|
||||
const defaultCSS: {[key: string]: string} = {
|
||||
"display": "inline-block",
|
||||
"top": "50%",
|
||||
"left": "50%",
|
||||
|
@ -35,7 +36,7 @@ function simpleLightbox(properties: any = {}, customCSS: any = {}, $elements: an
|
|||
customCSS[key] = defaultCSS[key];
|
||||
}
|
||||
|
||||
let $box = $("<div/>").prop(properties).css(customCSS).prependTo(document.body).append($elements);
|
||||
const $box = $("<div/>").prop(properties).css(customCSS).prependTo(document.body).append($elements);
|
||||
$("<div />").prop({
|
||||
class: "lightbox-bg"
|
||||
}).on("click", function() {
|
||||
|
@ -45,21 +46,21 @@ function simpleLightbox(properties: any = {}, customCSS: any = {}, $elements: an
|
|||
return $box;
|
||||
}
|
||||
|
||||
export function promptLightbox(defVal = "", isMasked = false, onOk: ($el:JQuery<HTMLElement>, val: any) => any = emptyFunc, title = "") {
|
||||
let $ok = $("<button/>").prop({
|
||||
export function promptLightbox(defVal = "", isMasked = false, onOk: ($el:JQuery<HTMLElement>, val: any) => any = noop, title = "") {
|
||||
const $ok = $("<button/>").prop({
|
||||
"id": "okbutton"
|
||||
}).text("OK");
|
||||
let $cancel = $("<button/>").prop({
|
||||
const $cancel = $("<button/>").prop({
|
||||
"id": "cancelbutton"
|
||||
}).text("Cancel");
|
||||
|
||||
let val = (typeof defVal == "string")?defVal:"";
|
||||
let $promptInput = $("<input/>").prop({
|
||||
const val = (typeof defVal == "string")?defVal:"";
|
||||
const $promptInput = $("<input/>").prop({
|
||||
id: "promptinput",
|
||||
type: isMasked?"password":"text"
|
||||
}).val(val);
|
||||
|
||||
let $form = $("<form/>").prop({
|
||||
const $form = $("<form/>").prop({
|
||||
"action": "javascript:;",
|
||||
"autocomplete": "off"
|
||||
}).append(
|
||||
|
@ -69,7 +70,7 @@ export function promptLightbox(defVal = "", isMasked = false, onOk: ($el:JQuery<
|
|||
$ok,
|
||||
$cancel
|
||||
);
|
||||
let $lb = simpleLightbox({}, {}, [$form]);
|
||||
const $lb = simpleLightbox({}, {}, [$form]);
|
||||
$promptInput.trigger("focus");
|
||||
$ok.on("click", function() {
|
||||
if(onOk($lb, $promptInput.val()) == false)
|
||||
|
@ -82,11 +83,11 @@ export function promptLightbox(defVal = "", isMasked = false, onOk: ($el:JQuery<
|
|||
return $lb;
|
||||
}
|
||||
|
||||
export function alertLightbox(msg = "", title = location.hostname, onOk: ($el: JQuery<HTMLElement>) => any = emptyFunc) {
|
||||
let $ok = $("<button/>").prop({
|
||||
export function alertLightbox(msg = "", title = location.hostname, onOk: ($el: JQuery<HTMLElement>) => any = noop) {
|
||||
const $ok = $("<button/>").prop({
|
||||
"id": "okbutton"
|
||||
}).text("OK");
|
||||
let $lb = simpleLightbox({}, {}, [
|
||||
const $lb = simpleLightbox({}, {}, [
|
||||
$("<b/>").prop({id:"alertTitle"}).text(title),
|
||||
"<hr/>",
|
||||
$("<span/>").prop({id:"alertText"}).text(msg),
|
||||
|
|
|
@ -11,7 +11,7 @@ import { updateThreadLock } from "../api/management";
|
|||
const idRe = /^((reply)|(op))(\d+)/;
|
||||
|
||||
function editPost(id: number, _board: string) {
|
||||
let cookiePass = getCookie("password");
|
||||
const cookiePass = getCookie("password");
|
||||
promptLightbox(cookiePass, true, (_jq, inputData) => {
|
||||
$("input[type=checkbox]").prop("checked", false);
|
||||
$(`input#check${id}`).prop("checked", true);
|
||||
|
@ -21,7 +21,7 @@ function editPost(id: number, _board: string) {
|
|||
}
|
||||
|
||||
function moveThread(id: number, _board: string) {
|
||||
let cookiePass = getCookie("password");
|
||||
const cookiePass = getCookie("password");
|
||||
promptLightbox(cookiePass, true, (_jq, inputData) => {
|
||||
$("input[type=checkbox]").prop("checked", false);
|
||||
$(`input#check${id}`).prop("checked", true);
|
||||
|
@ -33,7 +33,7 @@ function moveThread(id: number, _board: string) {
|
|||
function reportPost(id: number, board: string) {
|
||||
promptLightbox("", false, ($lb, reason) => {
|
||||
if(reason == "" || reason === null) return;
|
||||
let xhrFields: {[k: string]: string} = {
|
||||
const xhrFields: {[k: string]: string} = {
|
||||
board: board,
|
||||
report_btn: "Report",
|
||||
reason: reason,
|
||||
|
@ -56,7 +56,7 @@ function reportPost(id: number, board: string) {
|
|||
}
|
||||
|
||||
function deletePostFile(id: number) {
|
||||
let $elem = $(`div#op${id}.op-post, div#reply${id}.reply`);
|
||||
const $elem = $(`div#op${id}.op-post, div#reply${id}.reply`);
|
||||
if($elem.length === 0) return;
|
||||
$elem.find(".file-info,.upload-container").remove();
|
||||
$("<div/>").prop({
|
||||
|
@ -68,7 +68,7 @@ function deletePostFile(id: number) {
|
|||
}
|
||||
|
||||
function deletePostElement(id: number) {
|
||||
let $elem = $(`div#op${id}.op-post`);
|
||||
const $elem = $(`div#op${id}.op-post`);
|
||||
if($elem.length > 0) {
|
||||
$elem.parent().next().remove(); // also removes the <hr> element after
|
||||
$elem.parent().remove();
|
||||
|
@ -79,9 +79,9 @@ function deletePostElement(id: number) {
|
|||
}
|
||||
|
||||
function deletePost(id: number, board: string, fileOnly = false) {
|
||||
let cookiePass = getCookie("password");
|
||||
promptLightbox(cookiePass, true, ($lb, password) => {
|
||||
let xhrFields: {[k: string]: any} = {
|
||||
const cookiePass = getCookie("password");
|
||||
promptLightbox(cookiePass, true, (_lb, password) => {
|
||||
const xhrFields: {[k: string]: any} = {
|
||||
board: board,
|
||||
boardid: $("input[name=boardid]").val(),
|
||||
delete_btn: "Delete",
|
||||
|
@ -117,106 +117,106 @@ function deletePost(id: number, board: string, fileOnly = false) {
|
|||
}
|
||||
|
||||
function handleActions(action: string, postIDStr: string) {
|
||||
let idArr = idRe.exec(postIDStr);
|
||||
const idArr = idRe.exec(postIDStr);
|
||||
if(!idArr) return;
|
||||
let postID = Number.parseInt(idArr[4]);
|
||||
let board = currentBoard();
|
||||
const postID = Number.parseInt(idArr[4]);
|
||||
const board = currentBoard();
|
||||
switch(action) {
|
||||
case "Watch thread":
|
||||
watchThread(postID, board);
|
||||
break;
|
||||
case "Unwatch thread":
|
||||
unwatchThread(postID, board);
|
||||
break;
|
||||
case "Show thread":
|
||||
setThreadVisibility(postID, true);
|
||||
break;
|
||||
case "Hide thread":
|
||||
setThreadVisibility(postID, false);
|
||||
break;
|
||||
case "Move thread":
|
||||
moveThread(postID, board);
|
||||
break;
|
||||
case "Show post":
|
||||
setPostVisibility(postID, true);
|
||||
break;
|
||||
case "Hide post":
|
||||
setPostVisibility(postID, false);
|
||||
break;
|
||||
case "Edit post":
|
||||
editPost(postID, board);
|
||||
break;
|
||||
case "Report post":
|
||||
reportPost(postID, board);
|
||||
break;
|
||||
case "Delete file":
|
||||
deletePost(postID, board, true);
|
||||
break;
|
||||
case "Delete thread":
|
||||
case "Delete post":
|
||||
deletePost(postID, board, false);
|
||||
break;
|
||||
// manage stuff
|
||||
case "Lock thread":
|
||||
console.log(`Locking /${board}/${postID}`);
|
||||
updateThreadLock(board, postID, true);
|
||||
break;
|
||||
case "Unlock thread":
|
||||
console.log(`Unlocking /${board}/${postID}`);
|
||||
updateThreadLock(board, postID, false);
|
||||
break;
|
||||
case "Posts from this IP":
|
||||
getPostInfo(postID).then((info: any) => {
|
||||
window.open(`${webroot}manage/ipsearch?limit=100&ip=${info.ip}`);
|
||||
}).catch((reason: JQuery.jqXHR) => {
|
||||
alertLightbox(`Failed getting post IP: ${reason.statusText}`, "Error");
|
||||
});
|
||||
break;
|
||||
case "Ban filename":
|
||||
case "Ban file checksum": {
|
||||
let banType = (action == "Ban filename")?"filename":"checksum";
|
||||
getPostInfo(postID).then((info: any) => {
|
||||
return banFile(banType, info.originalFilename, info.checksum, `Added from post dropdown for post /${board}/${postID}`);
|
||||
}).then((result: any) => {
|
||||
if(result.error !== undefined && result.error != "") {
|
||||
if(result.message !== undefined)
|
||||
alertLightbox(`Failed applying ${banType} ban: ${result.message}`, "Error");
|
||||
else
|
||||
alertLightbox(`Failed applying ${banType} ban: ${result.error}`, "Error");
|
||||
case "Watch thread":
|
||||
watchThread(postID, board);
|
||||
break;
|
||||
case "Unwatch thread":
|
||||
unwatchThread(postID, board);
|
||||
break;
|
||||
case "Show thread":
|
||||
setThreadVisibility(postID, true);
|
||||
break;
|
||||
case "Hide thread":
|
||||
setThreadVisibility(postID, false);
|
||||
break;
|
||||
case "Move thread":
|
||||
moveThread(postID, board);
|
||||
break;
|
||||
case "Show post":
|
||||
setPostVisibility(postID, true);
|
||||
break;
|
||||
case "Hide post":
|
||||
setPostVisibility(postID, false);
|
||||
break;
|
||||
case "Edit post":
|
||||
editPost(postID, board);
|
||||
break;
|
||||
case "Report post":
|
||||
reportPost(postID, board);
|
||||
break;
|
||||
case "Delete file":
|
||||
deletePost(postID, board, true);
|
||||
break;
|
||||
case "Delete thread":
|
||||
case "Delete post":
|
||||
deletePost(postID, board, false);
|
||||
break;
|
||||
// manage stuff
|
||||
case "Lock thread":
|
||||
console.log(`Locking /${board}/${postID}`);
|
||||
updateThreadLock(board, postID, true);
|
||||
break;
|
||||
case "Unlock thread":
|
||||
console.log(`Unlocking /${board}/${postID}`);
|
||||
updateThreadLock(board, postID, false);
|
||||
break;
|
||||
case "Posts from this IP":
|
||||
getPostInfo(postID).then((info: any) => {
|
||||
window.open(`${webroot}manage/ipsearch?limit=100&ip=${info.ip}`);
|
||||
}).catch((reason: JQuery.jqXHR) => {
|
||||
alertLightbox(`Failed getting post IP: ${reason.statusText}`, "Error");
|
||||
});
|
||||
break;
|
||||
case "Ban filename":
|
||||
case "Ban file checksum": {
|
||||
const banType = (action == "Ban filename")?"filename":"checksum";
|
||||
getPostInfo(postID).then((info: any) => {
|
||||
return banFile(banType, info.originalFilename, info.checksum, `Added from post dropdown for post /${board}/${postID}`);
|
||||
}).then((result: any) => {
|
||||
if(result.error !== undefined && result.error != "") {
|
||||
if(result.message !== undefined)
|
||||
alertLightbox(`Failed applying ${banType} ban: ${result.message}`, "Error");
|
||||
else
|
||||
alertLightbox(`Failed applying ${banType} ban: ${result.error}`, "Error");
|
||||
} else {
|
||||
alertLightbox(`Successfully applied ${banType} ban`, "Success");
|
||||
}
|
||||
}).catch((reason: any) => {
|
||||
let messageDetail = "";
|
||||
try {
|
||||
const responseJSON = JSON.parse(reason.responseText);
|
||||
if((typeof responseJSON.message) == "string" && responseJSON.message != "") {
|
||||
messageDetail = responseJSON.message;
|
||||
} else {
|
||||
alertLightbox(`Successfully applied ${banType} ban`, "Success");
|
||||
}
|
||||
}).catch((reason: any) => {
|
||||
let messageDetail = "";
|
||||
try {
|
||||
const responseJSON = JSON.parse(reason.responseText);
|
||||
if((typeof responseJSON.message) == "string" && responseJSON.message != "") {
|
||||
messageDetail = responseJSON.message;
|
||||
} else {
|
||||
messageDetail = reason.statusText;
|
||||
}
|
||||
} catch(e) {
|
||||
messageDetail = reason.statusText;
|
||||
}
|
||||
alertLightbox(`Failed banning file: ${messageDetail}`, "Error");
|
||||
});
|
||||
}
|
||||
} catch(e) {
|
||||
messageDetail = reason.statusText;
|
||||
}
|
||||
alertLightbox(`Failed banning file: ${messageDetail}`, "Error");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function addPostDropdown($post: JQuery<HTMLElement>) {
|
||||
if($post.find("select.post-actions").length > 0)
|
||||
return $post;
|
||||
let $postInfo = $post.find("label.post-info");
|
||||
let isOP = $post.prop("class").split(" ").indexOf("op-post") > -1;
|
||||
let hasUpload = $postInfo.siblings("div.file-info").length > 0;
|
||||
let postID = $postInfo.parent().attr("id");
|
||||
let threadPost = isOP?"thread":"post";
|
||||
let $ddownMenu = $("<select />", {
|
||||
const $postInfo = $post.find("label.post-info");
|
||||
const isOP = $post.prop("class").split(" ").indexOf("op-post") > -1;
|
||||
const hasUpload = $postInfo.siblings("div.file-info").length > 0;
|
||||
const postID = $postInfo.parent().attr("id");
|
||||
const threadPost = isOP?"thread":"post";
|
||||
const $ddownMenu = $("<select />", {
|
||||
class: "post-actions",
|
||||
id: postID
|
||||
}).append("<option disabled selected>Actions</option>");
|
||||
let idNum = Number.parseInt(idRe.exec(postID)[4]);
|
||||
const idNum = Number.parseInt(idRe.exec(postID)[4]);
|
||||
if(isOP) {
|
||||
if(isThreadWatched(idNum, currentBoard())) {
|
||||
$ddownMenu.append("<option>Unwatch thread</option>");
|
||||
|
@ -225,17 +225,17 @@ export function addPostDropdown($post: JQuery<HTMLElement>) {
|
|||
}
|
||||
$ddownMenu.append("<option>Move thread</option>");
|
||||
}
|
||||
let showHide = isPostVisible(idNum)?"Hide":"Show";
|
||||
const showHide = isPostVisible(idNum)?"Hide":"Show";
|
||||
$ddownMenu.append(
|
||||
`<option>${showHide} ${threadPost}</option>`,
|
||||
"<option>Edit post</option>",
|
||||
"<option>Report post</option>",
|
||||
`<option>Delete ${threadPost}</option>`,
|
||||
).insertAfter($postInfo)
|
||||
.on("change", _e => {
|
||||
handleActions($ddownMenu.val() as string, postID);
|
||||
$ddownMenu.val("Actions");
|
||||
});
|
||||
.on("change", _e => {
|
||||
handleActions($ddownMenu.val() as string, postID);
|
||||
$ddownMenu.val("Actions");
|
||||
});
|
||||
if(hasUpload)
|
||||
$ddownMenu.append("<option>Delete file</option>");
|
||||
$post.trigger("postDropdownAdded", {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { getThumbFilename } from "../postinfo";
|
|||
* creates an element from the given post data
|
||||
*/
|
||||
export function createPostElement(post: ThreadPost, boardDir: string, elementClass = "inlinepostprev") {
|
||||
let $post = $("<div/>")
|
||||
const $post = $("<div/>")
|
||||
.prop({
|
||||
id: `reply${post.no}`,
|
||||
class: elementClass
|
||||
|
@ -40,9 +40,9 @@ export function createPostElement(post: ThreadPost, boardDir: string, elementCla
|
|||
href: `javascript:quote(${post.no})`
|
||||
}).text(post.no), "<br/>",
|
||||
);
|
||||
let $postInfo = $post.find("label.post-info");
|
||||
let postName = (post.name == "" && post.trip == "")?"Anonymous":post.name;
|
||||
let $postName = $("<span/>").prop({class: "postername"});
|
||||
const $postInfo = $post.find("label.post-info");
|
||||
const postName = (post.name == "" && post.trip == "")?"Anonymous":post.name;
|
||||
const $postName = $("<span/>").prop({class: "postername"});
|
||||
if(post.email == "") {
|
||||
$postName.text(postName);
|
||||
} else {
|
||||
|
@ -61,7 +61,7 @@ export function createPostElement(post: ThreadPost, boardDir: string, elementCla
|
|||
$postInfo.prepend($("<span/>").prop({class:"subject"}).text(post.sub), " ");
|
||||
|
||||
if(post.filename != "" && post.filename != "deleted") {
|
||||
let thumbFile = getThumbFilename(post.tim);
|
||||
const thumbFile = getThumbFilename(post.tim);
|
||||
$post.append(
|
||||
$("<div/>").prop({class: "file-info"})
|
||||
.append(
|
||||
|
@ -102,8 +102,8 @@ export function createPostElement(post: ThreadPost, boardDir: string, elementCla
|
|||
|
||||
export function shrinkOriginalFilenames(elem = $(document.body)) {
|
||||
elem.find<HTMLAnchorElement>("a.file-orig").each((i, el) => {
|
||||
let ext = extname(el.innerText);
|
||||
let noExt = el.innerText.slice(0,el.innerText.lastIndexOf("."));
|
||||
const ext = extname(el.innerText);
|
||||
const noExt = el.innerText.slice(0,el.innerText.lastIndexOf("."));
|
||||
if(noExt.length > 16) {
|
||||
const trimmed = noExt.slice(0, 15).trim() + "…" + ext;
|
||||
el.setAttribute("trimmed", trimmed);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import $ from "jquery";
|
||||
import { getStorageVal, setStorageVal } from "../storage";
|
||||
|
||||
const emptyFunc = () => {};
|
||||
|
||||
const noop = () => {
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* isPostVisible returns true if the post exists and is visible, otherwise false
|
||||
* @param id the id of the post
|
||||
*/
|
||||
export function isPostVisible(id: number) {
|
||||
let $post = $(`div#op${id}.op-post,div#reply${id}.reply`);
|
||||
const $post = $(`div#op${id}.op-post,div#reply${id}.reply`);
|
||||
if($post.length === 0)
|
||||
return false;
|
||||
return $post.find(".post-text").is(":visible");
|
||||
|
@ -22,21 +23,21 @@ export function isPostVisible(id: number) {
|
|||
* @param visibility the visibility to be set
|
||||
* @param onComplete called after the visibility is set
|
||||
*/
|
||||
export function setPostVisibility(id: number|string, visibility: boolean, onComplete = emptyFunc) {
|
||||
let $post = $(`div#op${id}.op-post, div#reply${id}.reply`);
|
||||
export function setPostVisibility(id: number|string, visibility: boolean, onComplete = noop) {
|
||||
const $post = $(`div#op${id}.op-post, div#reply${id}.reply`);
|
||||
|
||||
if($post.length === 0)
|
||||
return false;
|
||||
let $toSet = $post.find(".file-info,.post-text,.upload,.file-deleted-box,br");
|
||||
let $backlink = $post.find("a.backlink-click");
|
||||
let hiddenStorage = getStorageVal("hiddenposts", "").split(",");
|
||||
const $toSet = $post.find(".file-info,.post-text,.upload,.file-deleted-box,br");
|
||||
const $backlink = $post.find("a.backlink-click");
|
||||
const hiddenStorage = getStorageVal("hiddenposts", "").split(",");
|
||||
if(visibility) {
|
||||
$toSet.show(0, onComplete);
|
||||
$post.find<HTMLOptionElement>("select.post-actions option").each((e, elem) => {
|
||||
elem.text = elem.text.replace("Show", "Hide");
|
||||
});
|
||||
$backlink.text(id);
|
||||
let newHidden = [];
|
||||
const newHidden = [];
|
||||
for(const sID of hiddenStorage) {
|
||||
if(sID != id && newHidden.indexOf(sID) == -1) newHidden.push(sID);
|
||||
}
|
||||
|
@ -61,10 +62,10 @@ export function setPostVisibility(id: number|string, visibility: boolean, onComp
|
|||
* @param visibility the visibility to be set
|
||||
*/
|
||||
export function setThreadVisibility(opID: number|string, visibility: boolean) {
|
||||
let $thread = $(`div#op${opID}.op-post`).parent(".thread");
|
||||
const $thread = $(`div#op${opID}.op-post`).parent(".thread");
|
||||
if($thread.length === 0) return false;
|
||||
return setPostVisibility(opID, visibility, () => {
|
||||
let $toSet = $thread.find(".reply-container,b,br");
|
||||
const $toSet = $thread.find(".reply-container,b,br");
|
||||
if(visibility) {
|
||||
$toSet.show();
|
||||
} else {
|
||||
|
@ -79,7 +80,7 @@ $(() => {
|
|||
let hiddenPosts = getStorageVal("hiddenposts", "").split(",");
|
||||
if(typeof hiddenPosts === "number") hiddenPosts = [hiddenPosts];
|
||||
for(let i = 0; i < hiddenPosts.length; i++) {
|
||||
let id = hiddenPosts[i];
|
||||
const id = hiddenPosts[i];
|
||||
setThreadVisibility(id, false);
|
||||
setPostVisibility(id, false);
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ let threadCooldown = 0;
|
|||
let replyCooldown = 0;
|
||||
|
||||
const qrButtonHTML =
|
||||
'<input type="file" id="imagefile" name="imagefile" accept="image/jpeg,image/png,image/gif,video/webm,video/mp4"/>' +
|
||||
'<input type="submit" value="Post" style="float:right;min-width:50px"/>';
|
||||
`<input type="file" id="imagefile" name="imagefile" accept="image/jpeg,image/png,image/gif,video/webm,video/mp4"/>` +
|
||||
`<input type="submit" value="Post" style="float:right;min-width:50px"/>`;
|
||||
|
||||
const qrTitleBar =
|
||||
'<div id="qr-title">' +
|
||||
'<span id="qr-message"></span>' +
|
||||
`<div id="qr-title">` +
|
||||
`<span id="qr-message"></span>` +
|
||||
`<span id="qr-buttons"><a href="javascript:toBottom();">${downArrow}</a>` +
|
||||
`<a href="javascript:toTop();">${upArrow}</a><a href="javascript:closeQR();">X</a></span></div>`;
|
||||
|
||||
|
@ -46,7 +46,7 @@ function setSubmitButtonText(text: string) {
|
|||
}
|
||||
|
||||
function setSubmitButtonEnabled(enabled = true) {
|
||||
let $submit = $qr.find("input[type=submit]");
|
||||
const $submit = $qr.find("input[type=submit]");
|
||||
if(enabled) {
|
||||
$submit.removeAttr("disabled");
|
||||
} else {
|
||||
|
@ -56,15 +56,15 @@ function setSubmitButtonEnabled(enabled = true) {
|
|||
|
||||
function unsetQrUpload() {
|
||||
$("#imagefile").val("");
|
||||
let $uploadContainer = $qr.find("div#upload-container");
|
||||
const $uploadContainer = $qr.find("div#upload-container");
|
||||
$uploadContainer.empty();
|
||||
$uploadContainer.css("display","none");
|
||||
}
|
||||
|
||||
function qrUploadChange() {
|
||||
let $uploadContainer = $qr.find("div#upload-container");
|
||||
const $uploadContainer = $qr.find("div#upload-container");
|
||||
$uploadContainer.empty();
|
||||
let filename = getUploadFilename();
|
||||
const filename = getUploadFilename();
|
||||
$uploadContainer.append($(this).prop({
|
||||
"title": filename
|
||||
}).css({
|
||||
|
@ -78,7 +78,7 @@ function qrUploadChange() {
|
|||
|
||||
function setButtonTimeout(prefix = "", cooldown = 5) {
|
||||
let currentSeconds = cooldown;
|
||||
let interval: NodeJS.Timer;
|
||||
let interval: NodeJS.Timer = null;
|
||||
const timeoutCB = () => {
|
||||
if(currentSeconds == 0) {
|
||||
setSubmitButtonEnabled(true);
|
||||
|
@ -103,8 +103,7 @@ export function initQR() {
|
|||
return closeQR();
|
||||
}
|
||||
|
||||
|
||||
let onPostingPage = $("form input[name=boardid]").length > 0;
|
||||
const onPostingPage = $("form input[name=boardid]").length > 0;
|
||||
// don't open the QR box if we aren't on a board or thread page
|
||||
if(!onPostingPage)
|
||||
return;
|
||||
|
@ -113,10 +112,10 @@ export function initQR() {
|
|||
const emailCookie = getCookie("email");
|
||||
const $oldForm = $("form#postform");
|
||||
|
||||
let $qrbuttons = $("<div/>")
|
||||
const $qrbuttons = $("<div/>")
|
||||
.prop("id", "qrbuttons")
|
||||
.append(qrButtonHTML);
|
||||
let $postform = $("<form/>").prop({
|
||||
const $postform = $("<form/>").prop({
|
||||
id: "qrpostform",
|
||||
name: "qrpostform",
|
||||
action: webroot + "post",
|
||||
|
@ -168,10 +167,10 @@ export function initQR() {
|
|||
|
||||
let qrTop = 32;
|
||||
|
||||
let pintopbar = getBooleanStorageVal("pintopbar", true);
|
||||
const pintopbar = getBooleanStorageVal("pintopbar", true);
|
||||
if(pintopbar)
|
||||
qrTop = $topbar.outerHeight() + 16;
|
||||
let qrPos = getJsonStorageVal("qrpos", {top: qrTop, left: 16});
|
||||
const qrPos = getJsonStorageVal("qrpos", {top: qrTop, left: 16});
|
||||
if(!(qrPos.top > -1))
|
||||
qrPos.top = qrTop;
|
||||
if(!(qrPos.left > -1))
|
||||
|
@ -210,10 +209,10 @@ export function initQR() {
|
|||
return;
|
||||
}
|
||||
$postform.on("submit", function(e) {
|
||||
let $form = $<HTMLFormElement>(this as HTMLFormElement);
|
||||
const $form = $<HTMLFormElement>(this as HTMLFormElement);
|
||||
e.preventDefault();
|
||||
copyCaptchaResponse($form);
|
||||
let data = new FormData(this as HTMLFormElement);
|
||||
const data = new FormData(this as HTMLFormElement);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
|
@ -228,10 +227,10 @@ export function initQR() {
|
|||
return;
|
||||
}
|
||||
clearQR();
|
||||
let cooldown = (currentThread().id > 0)?replyCooldown:threadCooldown;
|
||||
const cooldown = (currentThread().id > 0)?replyCooldown:threadCooldown;
|
||||
setButtonTimeout("", cooldown);
|
||||
updateThread().then(clearQR).then(() => {
|
||||
let persist = getBooleanStorageVal("persistentqr", false);
|
||||
const persist = getBooleanStorageVal("persistentqr", false);
|
||||
if(!persist) closeQR();
|
||||
});
|
||||
return false;
|
||||
|
@ -245,12 +244,12 @@ export function initQR() {
|
|||
}
|
||||
|
||||
function copyCaptchaResponse($copyToForm: JQuery<HTMLElement>) {
|
||||
let $captchaResp = $("textarea[name=h-captcha-response]");
|
||||
const $captchaResp = $("textarea[name=h-captcha-response]");
|
||||
if($captchaResp.length > 0) {
|
||||
$("<textarea/>").prop({
|
||||
"name": "h-captcha-response"
|
||||
}).val($("textarea[name=h-captcha-response]").val()).css("display", "none")
|
||||
.appendTo($copyToForm);
|
||||
.appendTo($copyToForm);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +278,7 @@ export function closeQR() {
|
|||
window.closeQR = closeQR;
|
||||
|
||||
$(() => {
|
||||
let board = currentBoard();
|
||||
const board = currentBoard();
|
||||
if(board == "") return; // not on a board
|
||||
getThreadCooldown(board).then(cd => threadCooldown = cd);
|
||||
getReplyCooldown(board).then(cd => replyCooldown = cd);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import $ from "jquery";
|
||||
import $, { noop } from "jquery";
|
||||
|
||||
import { getBooleanStorageVal } from "../storage";
|
||||
|
||||
|
@ -20,7 +20,7 @@ export class TopBarButton {
|
|||
* @param title The text shown on the button
|
||||
* @param action The function executed when the button is clicked
|
||||
*/
|
||||
constructor(title: string, action: ()=>any = ()=>{}, beforeAfter:BeforeAfter = {}) {
|
||||
constructor(title: string, action: ()=>any = noop, beforeAfter: BeforeAfter = {}) {
|
||||
this.title = title;
|
||||
this.buttonAction = action;
|
||||
this.button = $<HTMLLinkElement>("<a/>").prop({
|
||||
|
@ -29,8 +29,8 @@ export class TopBarButton {
|
|||
"id": title.toLowerCase()
|
||||
}).text(title + "▼");
|
||||
|
||||
let $before = $topbar.find(beforeAfter.before);
|
||||
let $after = $topbar.find(beforeAfter.after);
|
||||
const $before = $topbar.find(beforeAfter.before);
|
||||
const $after = $topbar.find(beforeAfter.after);
|
||||
if($before.length > 0) {
|
||||
this.button.insertBefore($before);
|
||||
} else if($after.length > 0) {
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
let noop = ()=>{};
|
||||
const noop = ()=>{
|
||||
return;
|
||||
};
|
||||
|
||||
export function updateUploadImage($elem: JQuery<HTMLElement>, onLoad = noop) {
|
||||
if($elem.length == 0) return;
|
||||
$elem[0].onchange = function() {
|
||||
let img = new Image();
|
||||
const img = new Image();
|
||||
img.src = URL.createObjectURL((this as any).files[0]);
|
||||
img.onload = onLoad;
|
||||
};
|
||||
}
|
||||
|
||||
export function getUploadFilename(): string {
|
||||
let elem = document.getElementById("imagefile") as HTMLInputElement;
|
||||
const elem = document.getElementById("imagefile") as HTMLInputElement;
|
||||
if(elem === null) return "";
|
||||
if(elem.files === undefined || elem.files.length < 1) return "";
|
||||
return elem.files[0].name;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* @param dateStr timestamp string, assumed to be in ISO Date-Time format
|
||||
*/
|
||||
export function formatDateString(dateStr: string) {
|
||||
let date = new Date(dateStr);
|
||||
const date = new Date(dateStr);
|
||||
return date.toDateString() + ", " + date.toLocaleTimeString();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,17 +24,17 @@ export function toBottom() {
|
|||
window.toBottom = toBottom;
|
||||
|
||||
$(() => {
|
||||
let style = getStorageVal("style", defaultStyle);
|
||||
let themeElem = document.getElementById("theme");
|
||||
const style = getStorageVal("style", defaultStyle);
|
||||
const themeElem = document.getElementById("theme");
|
||||
if(themeElem) themeElem.setAttribute("href", `${webroot}css/${style}`);
|
||||
let pageThread = getPageThread();
|
||||
const pageThread = getPageThread();
|
||||
initStaff()
|
||||
.then(createStaffMenu)
|
||||
.catch(() => {
|
||||
// not logged in
|
||||
});
|
||||
.catch(() => {
|
||||
// not logged in
|
||||
});
|
||||
|
||||
let passwordText = $("input#postpassword").val();
|
||||
const passwordText = $("input#postpassword").val();
|
||||
$("input#delete-password").val(passwordText);
|
||||
|
||||
setPageBanner();
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import $ from 'jquery';
|
||||
import $ from "jquery";
|
||||
|
||||
import { alertLightbox } from "../dom/lightbox";
|
||||
import { $topbar, TopBarButton } from '../dom/topbar';
|
||||
import { $topbar, TopBarButton } from "../dom/topbar";
|
||||
import "./sections";
|
||||
import "./filebans";
|
||||
import { isThreadLocked } from '../api/management';
|
||||
import { isThreadLocked } from "../api/management";
|
||||
|
||||
const notAStaff: StaffInfo = {
|
||||
ID: 0,
|
||||
|
@ -39,7 +39,7 @@ function setupManagementEvents() {
|
|||
const $post = $(el.parentElement);
|
||||
const isLocked = isThreadLocked($post);
|
||||
if(!dropdownHasItem(el, "Staff Actions")) {
|
||||
$el.append('<option disabled="disabled">Staff Actions</option>');
|
||||
$el.append(`<option disabled="disabled">Staff Actions</option>`);
|
||||
}
|
||||
if($post.hasClass("op-post")) {
|
||||
if(isLocked) {
|
||||
|
@ -51,7 +51,7 @@ function setupManagementEvents() {
|
|||
if(!dropdownHasItem(el, "Posts from this IP")) {
|
||||
$el.append("<option>Posts from this IP</option>");
|
||||
}
|
||||
let filenameOrig = $post.find("div.file-info a.file-orig").text();
|
||||
const filenameOrig = $post.find("div.file-info a.file-orig").text();
|
||||
if(filenameOrig != "" && !dropdownHasItem(el, "Ban filename")) {
|
||||
$el.append(
|
||||
"<option>Ban filename</option>",
|
||||
|
@ -84,16 +84,16 @@ export function banFile(banType: string, filename: string, checksum: string, sta
|
|||
json: 1
|
||||
};
|
||||
switch(banType) {
|
||||
case "filename":
|
||||
xhrFields.filename = filename;
|
||||
xhrFields.dofilenameban = "Create";
|
||||
break;
|
||||
case "checksum":
|
||||
xhrFields.checksum = checksum;
|
||||
xhrFields.dochecksumban = "Create";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case "filename":
|
||||
xhrFields.filename = filename;
|
||||
xhrFields.dofilenameban = "Create";
|
||||
break;
|
||||
case "checksum":
|
||||
xhrFields.checksum = checksum;
|
||||
xhrFields.dochecksumban = "Create";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return $.ajax({
|
||||
method: "POST",
|
||||
|
@ -121,7 +121,7 @@ export async function initStaff() {
|
|||
staffActions = result;
|
||||
}
|
||||
},
|
||||
error: (e) => {
|
||||
error: (e: JQuery.jqXHR) => {
|
||||
console.error("Error getting actions list:", e);
|
||||
}
|
||||
}).then(getStaffInfo).then(info => {
|
||||
|
@ -174,10 +174,10 @@ export async function isLoggedIn() {
|
|||
}
|
||||
|
||||
export function banSelectedPost() {
|
||||
let boardDirArr = location.pathname.split("/");
|
||||
const boardDirArr = location.pathname.split("/");
|
||||
if(boardDirArr.length < 2) return;
|
||||
let boardDir = boardDirArr[1];
|
||||
let checks = $("input[type=checkbox]");
|
||||
const boardDir = boardDirArr[1];
|
||||
const checks = $("input[type=checkbox]");
|
||||
if(checks.length === 0) {
|
||||
alertLightbox("No posts selected");
|
||||
return false;
|
||||
|
@ -197,10 +197,10 @@ export function banSelectedPost() {
|
|||
*/
|
||||
function menuItem(action: StaffAction|string, isCategory = false) {
|
||||
return isCategory ? $("<div/>").append($("<b/>").text(action as string)) : $("<div/>").append(
|
||||
$("<a/>").prop({
|
||||
href: `${webroot}manage/${(action as StaffAction).id}`
|
||||
}).text((action as StaffAction).title)
|
||||
);
|
||||
$("<a/>").prop({
|
||||
href: `${webroot}manage/${(action as StaffAction).id}`
|
||||
}).text((action as StaffAction).title)
|
||||
);
|
||||
}
|
||||
|
||||
function getAction(id: string) {
|
||||
|
@ -224,7 +224,7 @@ function filterAction(action: StaffAction, perms: number) {
|
|||
* @param staff an object representing the staff's username and rank
|
||||
*/
|
||||
export function createStaffMenu(staff = staffInfo) {
|
||||
let rank = staff.Rank;
|
||||
const rank = staff.Rank;
|
||||
if(rank === 0) return;
|
||||
$staffMenu = $("<div/>").prop({
|
||||
id: "staffmenu",
|
||||
|
@ -235,14 +235,14 @@ export function createStaffMenu(staff = staffInfo) {
|
|||
menuItem(getAction("logout")),
|
||||
menuItem(getAction("dashboard")));
|
||||
|
||||
let janitorActions = staffActions.filter(val => filterAction(val, 1));
|
||||
const janitorActions = staffActions.filter(val => filterAction(val, 1));
|
||||
$staffMenu.append(menuItem("Janitorial", true));
|
||||
for(const action of janitorActions) {
|
||||
$staffMenu.append(menuItem(action));
|
||||
}
|
||||
|
||||
if(rank >= 2) {
|
||||
let modActions = staffActions.filter(val => filterAction(val, 2));
|
||||
const modActions = staffActions.filter(val => filterAction(val, 2));
|
||||
if(modActions.length > 0)
|
||||
$staffMenu.append(menuItem("Moderation", true));
|
||||
for(const action of modActions) {
|
||||
|
@ -251,7 +251,7 @@ export function createStaffMenu(staff = staffInfo) {
|
|||
getReports().then(updateReports);
|
||||
}
|
||||
if(rank == 3) {
|
||||
let adminActions = staffActions.filter(val => filterAction(val, 3));
|
||||
const adminActions = staffActions.filter(val => filterAction(val, 3));
|
||||
if(adminActions.length > 0)
|
||||
$staffMenu.append(menuItem("Administration", true));
|
||||
for(const action of adminActions) {
|
||||
|
@ -273,7 +273,7 @@ function updateReports(reports: any[]) {
|
|||
// append " (#)" to the Reports link, replacing # with the number of reports
|
||||
$staffMenu.find("a").each((e, elem) => {
|
||||
if(elem.text.search(reportsTextRE) != 0) return;
|
||||
let $span = $("<span/>").text(` (${reports.length})`).appendTo(elem);
|
||||
const $span = $("<span/>").text(` (${reports.length})`).appendTo(elem);
|
||||
if(reports.length > 0) {
|
||||
// make it bold and red if there are reports
|
||||
$span.css({
|
||||
|
|
|
@ -9,18 +9,18 @@ import { alertLightbox } from "../dom/lightbox";
|
|||
|
||||
let $sectionsTable: JQuery<HTMLTableElement> = null;
|
||||
let changesButtonAdded = false;
|
||||
let initialOrders: string[] = [];
|
||||
const initialOrders: string[] = [];
|
||||
|
||||
function applyOrderChanges() {
|
||||
let $sections = $sectionsTable.find("tr.sectionrow");
|
||||
const $sections = $sectionsTable.find("tr.sectionrow");
|
||||
let errorShown = false; // only show one error if something goes wrong
|
||||
$sections.each((i, el) => {
|
||||
let $el = $(el);
|
||||
let updatesection = /^section(\d+)$/.exec(el.id)[1];
|
||||
let sectionname = $el.find(":nth-child(1)").html();
|
||||
let sectionabbr = $el.find(":nth-child(2)").html();
|
||||
let sectionpos = $el.find(":nth-child(3)").html();
|
||||
let sectionhidden = $el.find(":nth-child(4)").html().toLowerCase() == "yes"?"on":"off";
|
||||
const $el = $(el);
|
||||
const updatesection = /^section(\d+)$/.exec(el.id)[1];
|
||||
const sectionname = $el.find(":nth-child(1)").html();
|
||||
const sectionabbr = $el.find(":nth-child(2)").html();
|
||||
const sectionpos = $el.find(":nth-child(3)").html();
|
||||
const sectionhidden = $el.find(":nth-child(4)").html().toLowerCase() == "yes"?"on":"off";
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: webroot + "manage/boardsections",
|
||||
|
@ -54,7 +54,7 @@ function applyOrderChanges() {
|
|||
|
||||
function cancelOrderChanges() {
|
||||
$sectionsTable.find("tbody").sortable("cancel");
|
||||
let $sections = $sectionsTable.find("tr.sectionrow");
|
||||
const $sections = $sectionsTable.find("tr.sectionrow");
|
||||
$sections.each((i, el) => {
|
||||
$(el).find(":nth-child(3)").text(initialOrders[i]);
|
||||
});
|
||||
|
@ -85,7 +85,7 @@ $(() => {
|
|||
items: "tr.sectionrow",
|
||||
stop: () => {
|
||||
$sectionsTable.find("tr.sectionrow").each((i, el) => {
|
||||
let $order = $(el).find(":nth-child(3)");
|
||||
const $order = $(el).find(":nth-child(3)");
|
||||
initialOrders.push($order.text());
|
||||
$order.text(i + 1);
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ function canNotify() {
|
|||
}
|
||||
|
||||
export function notify(title: string, body: string, img = noteIcon) {
|
||||
let n = new Notification(title, {
|
||||
const n = new Notification(title, {
|
||||
body: body,
|
||||
image: img,
|
||||
icon: noteIcon
|
||||
|
@ -19,7 +19,7 @@ export function notify(title: string, body: string, img = noteIcon) {
|
|||
}, noteCloseTime);
|
||||
}
|
||||
|
||||
$(document).on("ready", () => {
|
||||
$(() => {
|
||||
if(!canNotify())
|
||||
return;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ const opRE = /\/res\/(\d+)(p(\d)+)?.html$/;
|
|||
const threadRE = /^\d+/;
|
||||
|
||||
export function currentBoard() {
|
||||
let board = $("form#main-form input[type=hidden][name=board]").val();
|
||||
const board = $("form#main-form input[type=hidden][name=board]").val();
|
||||
if(typeof board == "string")
|
||||
return board;
|
||||
return "";
|
||||
|
@ -15,12 +15,12 @@ export function getPageThread() {
|
|||
let pathname = window.location.pathname;
|
||||
if(typeof webroot == "string" && webroot != "/") {
|
||||
pathname = pathname.slice(webroot.length);
|
||||
if(pathname === "" || pathname[0] != '/') {
|
||||
if(pathname === "" || pathname[0] != "/") {
|
||||
pathname = "/" + pathname;
|
||||
}
|
||||
}
|
||||
let arr = opRE.exec(pathname);
|
||||
let info = {
|
||||
const arr = opRE.exec(pathname);
|
||||
const info = {
|
||||
board: currentBoard(),
|
||||
boardID: -1,
|
||||
op: -1,
|
||||
|
@ -36,18 +36,18 @@ export function getPageThread() {
|
|||
|
||||
export function currentThread(): WatchedThreadJSON {
|
||||
// returns the board and thread ID if we are viewing a thread
|
||||
let thread = {board: currentBoard(), id: 0};
|
||||
const thread = {board: currentBoard(), id: 0};
|
||||
let pathname = location.pathname;
|
||||
if(typeof webroot == "string" && webroot != "/") {
|
||||
pathname = pathname.slice(webroot.length);
|
||||
if(pathname === "" || pathname[0] != '/') {
|
||||
if(pathname === "" || pathname[0] != "/") {
|
||||
pathname = "/" + pathname;
|
||||
}
|
||||
}
|
||||
let splits = pathname.split("/");
|
||||
const splits = pathname.split("/");
|
||||
if(splits.length != 4)
|
||||
return thread;
|
||||
let reArr = threadRE.exec(splits[3]);
|
||||
const reArr = threadRE.exec(splits[3]);
|
||||
if(reArr.length > 0)
|
||||
thread.id = Number.parseInt(reArr[0]);
|
||||
return thread;
|
||||
|
@ -61,9 +61,9 @@ export function insideOP(elem: any) {
|
|||
* Return the appropriate thumbnail filename for the given upload filename (replacing gif/webm with jpg, etc)
|
||||
*/
|
||||
export function getThumbFilename(filename: string) {
|
||||
let nameParts = /([^.]+)\.([^.]+)$/.exec(filename);
|
||||
const nameParts = /([^.]+)\.([^.]+)$/.exec(filename);
|
||||
if(nameParts === null) return filename;
|
||||
let name = nameParts[1] + "t";
|
||||
const name = nameParts[1] + "t";
|
||||
let ext = nameParts[2];
|
||||
if(ext == "gif" || ext == "webm")
|
||||
ext = "jpg";
|
||||
|
|
|
@ -24,21 +24,21 @@ let currentThreadJSON: BoardThread = {
|
|||
export function getUploadPostID(upload: any, container: any) {
|
||||
// if container, upload is div.upload-container
|
||||
// otherwise it's img or video
|
||||
let jqu = container? $(upload) : $(upload).parent();
|
||||
const jqu = container? $(upload) : $(upload).parent();
|
||||
return insideOP(jqu) ? jqu.siblings().eq(4).text() : jqu.siblings().eq(3).text();
|
||||
}
|
||||
|
||||
export async function updateThreadJSON() {
|
||||
let thread = currentThread();
|
||||
const thread = currentThread();
|
||||
if(thread.id === 0) return; // not in a thread
|
||||
const json = await getThreadJSON(thread.id, thread.board);
|
||||
if (!(json.posts instanceof Array) || json.posts.length === 0)
|
||||
if(!(json.posts instanceof Array) || json.posts.length === 0)
|
||||
return;
|
||||
currentThreadJSON = json;
|
||||
}
|
||||
|
||||
function updateThreadHTML() {
|
||||
let thread = currentThread();
|
||||
const thread = currentThread();
|
||||
if(thread.id === 0) return; // not in a thread
|
||||
let numAdded = 0;
|
||||
for(const post of currentThreadJSON.posts) {
|
||||
|
@ -47,12 +47,12 @@ function updateThreadHTML() {
|
|||
selector += `div#op${post.no}`;
|
||||
else
|
||||
selector += `div#reply${post.no}`;
|
||||
let elementExists = $(selector).length > 0;
|
||||
const elementExists = $(selector).length > 0;
|
||||
if(elementExists)
|
||||
continue; // TODO: check for edits
|
||||
|
||||
let $post = createPostElement(post, thread.board, "reply");
|
||||
let $replyContainer = $("<div/>").prop({
|
||||
const $post = createPostElement(post, thread.board, "reply");
|
||||
const $replyContainer = $("<div/>").prop({
|
||||
id: `replycontainer${post.no}`,
|
||||
class: "reply-container"
|
||||
}).append($post);
|
||||
|
@ -94,20 +94,20 @@ function previewMoveHandler(e: JQuery.Event) {
|
|||
function expandPost(e: JQuery.MouseEventBase) {
|
||||
e.preventDefault();
|
||||
if($hoverPreview !== null) $hoverPreview.remove();
|
||||
let $next = $(e.target).next();
|
||||
const $next = $(e.target).next();
|
||||
if($next.prop("class") == "inlinepostprev" && e.type == "click") {
|
||||
// inline preview is already opened, close it
|
||||
$next.remove();
|
||||
return;
|
||||
}
|
||||
let href = e.target.href;
|
||||
let hrefArr = postrefRE.exec(href);
|
||||
const href = e.target.href;
|
||||
const hrefArr = postrefRE.exec(href);
|
||||
if(hrefArr === null) return; // not actually a link to a post, abort
|
||||
let postID = hrefArr[4]?hrefArr[4]:hrefArr[2];
|
||||
const postID = hrefArr[4]?hrefArr[4]:hrefArr[2];
|
||||
|
||||
let $post = $(`div#op${postID}, div#reply${postID}`).first();
|
||||
if($post.length > 0) {
|
||||
let $preview = createPostPreview(e, $post, e.type == "click");
|
||||
const $preview = createPostPreview(e, $post, e.type == "click");
|
||||
if(e.type == "mouseenter") {
|
||||
$hoverPreview = $preview.insertAfter(e.target);
|
||||
$(document.body).on("mousemove", previewMoveHandler);
|
||||
|
@ -165,41 +165,40 @@ export function prepareThumbnails($parent: JQuery<HTMLElement> = null) {
|
|||
|
||||
e.preventDefault();
|
||||
|
||||
const thumb = $a.find("img.upload");
|
||||
const thumbURL = thumb.attr("src");
|
||||
const uploadURL = thumb.attr("alt");
|
||||
thumb.removeAttr("width").removeAttr("height");
|
||||
const $thumb = $a.find("img.upload");
|
||||
const thumbURL = $thumb.attr("src");
|
||||
const uploadURL = $thumb.attr("alt");
|
||||
$thumb.removeAttr("width").removeAttr("height");
|
||||
|
||||
var fileInfoElement = $a.prevAll(".file-info:first");
|
||||
const $fileInfo = $a.prevAll(".file-info:first");
|
||||
|
||||
if(videoTestRE.test(thumbURL + uploadURL)) {
|
||||
// Upload is a video
|
||||
thumb.hide();
|
||||
var video = $("<video />")
|
||||
.prop({
|
||||
src: uploadURL,
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
class: "upload",
|
||||
loop: true
|
||||
}).insertAfter(fileInfoElement);
|
||||
$thumb.hide();
|
||||
const $video = $("<video />")
|
||||
.prop({
|
||||
src: uploadURL,
|
||||
autoplay: true,
|
||||
controls: true,
|
||||
class: "upload",
|
||||
loop: true
|
||||
}).insertAfter($fileInfo);
|
||||
|
||||
fileInfoElement.append($("<a />")
|
||||
.prop("href", "javascript:;")
|
||||
.on("click", function() {
|
||||
video.remove();
|
||||
thumb.show();
|
||||
this.remove();
|
||||
thumb.prop({
|
||||
src: thumbURL,
|
||||
alt: uploadURL
|
||||
});
|
||||
}).css({
|
||||
"padding-left": "8px"
|
||||
}).html("[Close]<br />"));
|
||||
$fileInfo.append($("<a />")
|
||||
.prop("href", "javascript:;").on("click", function() {
|
||||
$video.remove();
|
||||
$thumb.show();
|
||||
this.remove();
|
||||
$thumb.prop({
|
||||
src: thumbURL,
|
||||
alt: uploadURL
|
||||
});
|
||||
}).css({
|
||||
"padding-left": "8px"
|
||||
}).html("[Close]<br />"));
|
||||
} else {
|
||||
// upload is an image
|
||||
thumb.attr({
|
||||
$thumb.attr({
|
||||
src: uploadURL,
|
||||
alt: thumbURL
|
||||
});
|
||||
|
@ -217,25 +216,23 @@ export function quote(no: number) {
|
|||
if(getBooleanStorageVal("useqr", true)) {
|
||||
openQR();
|
||||
}
|
||||
let msgboxID = "postmsg";
|
||||
|
||||
const msgboxID = "postmsg";
|
||||
let msgbox = document.getElementById("qr" + msgboxID) as HTMLInputElement;
|
||||
if(msgbox === null)
|
||||
msgbox = document.getElementById(msgboxID) as HTMLInputElement;
|
||||
let selected = selectedText();
|
||||
let lines = selected.split("\n");
|
||||
const selected = selectedText();
|
||||
const lines = selected.split("\n");
|
||||
|
||||
if(selected !== "") {
|
||||
for(let l = 0; l < lines.length; l++) {
|
||||
lines[l] = ">" + lines[l];
|
||||
}
|
||||
}
|
||||
let cursor = (msgbox.selectionStart !== undefined)?msgbox.selectionStart:msgbox.value.length;
|
||||
const cursor = (msgbox.selectionStart !== undefined)?msgbox.selectionStart:msgbox.value.length;
|
||||
let quoted = lines.join("\n");
|
||||
if(quoted != "") quoted += "\n";
|
||||
msgbox.value = msgbox.value.slice(0, cursor) + `>>${no}\n` +
|
||||
quoted +
|
||||
msgbox.value.slice(cursor);
|
||||
quoted + msgbox.value.slice(cursor);
|
||||
|
||||
if(msgbox.id == "postmsg")
|
||||
window.scroll(0,msgbox.offsetTop - 48);
|
||||
|
|
|
@ -13,19 +13,23 @@ const settings: Map<string, Setting<boolean|number|string,HTMLElement>> = new Ma
|
|||
|
||||
type ElementValue = string|number|string[];
|
||||
|
||||
const noop = () => {
|
||||
return;
|
||||
};
|
||||
|
||||
class Setting<T = any, E extends HTMLElement = HTMLElement> {
|
||||
key: string;
|
||||
title: string;
|
||||
defaultVal: T;
|
||||
onSave: () => any;
|
||||
element: JQuery<E>
|
||||
element: JQuery<E>;
|
||||
/**
|
||||
* @param key The name of the setting
|
||||
* @param title text that gets shown in the Settings lightbox
|
||||
* @param defaultVal the setting's default value
|
||||
* @param onSave function that gets called when you save the settings
|
||||
*/
|
||||
constructor(key: string, title: string, defaultVal:T, onSave = () => {}) {
|
||||
constructor(key: string, title: string, defaultVal:T, onSave = noop) {
|
||||
this.key = key;
|
||||
this.title = title;
|
||||
this.defaultVal = defaultVal;
|
||||
|
@ -55,11 +59,11 @@ class Setting<T = any, E extends HTMLElement = HTMLElement> {
|
|||
}
|
||||
|
||||
class TextSetting extends Setting<string, HTMLTextAreaElement> {
|
||||
constructor(key: string, title: string, defaultVal = "", onSave = () => {}) {
|
||||
constructor(key: string, title: string, defaultVal = "", onSave = noop) {
|
||||
super(key, title, defaultVal, onSave);
|
||||
this.element = this.createElement("<textarea/>");
|
||||
this.element.text(defaultVal);
|
||||
let val = this.getStorageValue();
|
||||
const val = this.getStorageValue();
|
||||
if(val != "") {
|
||||
this.setElementValue(val);
|
||||
}
|
||||
|
@ -69,12 +73,11 @@ class TextSetting extends Setting<string, HTMLTextAreaElement> {
|
|||
}
|
||||
}
|
||||
|
||||
class DropdownSetting<T> extends Setting<ElementValue, HTMLSelectElement> {
|
||||
constructor(key: string, title: string, options:any[] = [], defaultVal: ElementValue, onSave = () => {}) {
|
||||
class DropdownSetting extends Setting<ElementValue, HTMLSelectElement> {
|
||||
constructor(key: string, title: string, options:any[] = [], defaultVal: ElementValue, onSave = noop) {
|
||||
super(key, title, defaultVal, onSave);
|
||||
this.element = this.createElement("<select/>");
|
||||
for(const option of options) {
|
||||
let s: HTMLSelectElement
|
||||
$<HTMLSelectElement>("<option/>").val(option.val).text(option.text).appendTo(this.element);
|
||||
}
|
||||
this.element.val(this.getStorageValue());
|
||||
|
@ -82,7 +85,7 @@ class DropdownSetting<T> extends Setting<ElementValue, HTMLSelectElement> {
|
|||
}
|
||||
|
||||
class BooleanSetting extends Setting<boolean, HTMLInputElement> {
|
||||
constructor(key: string, title: string, defaultVal = false, onSave = () => {}) {
|
||||
constructor(key: string, title: string, defaultVal = false, onSave = noop) {
|
||||
super(key, title, defaultVal, onSave);
|
||||
this.element = this.createElement("<input/>", {
|
||||
type: "checkbox",
|
||||
|
@ -96,7 +99,7 @@ class BooleanSetting extends Setting<boolean, HTMLInputElement> {
|
|||
this.element.prop("checked", newVal);
|
||||
}
|
||||
getStorageValue() {
|
||||
let val = super.getStorageValue();
|
||||
const val = super.getStorageValue();
|
||||
return val == true;
|
||||
}
|
||||
}
|
||||
|
@ -107,9 +110,9 @@ interface MinMax {
|
|||
max?: number;
|
||||
}
|
||||
class NumberSetting extends Setting<number, HTMLInputElement> {
|
||||
constructor(key: string, title: string, defaultVal = 0, minMax: MinMax = {min: null, max: null}, onSave = () => {}) {
|
||||
constructor(key: string, title: string, defaultVal = 0, minMax: MinMax = {min: null, max: null}, onSave = noop) {
|
||||
super(key, title, defaultVal, onSave);
|
||||
let props: MinMax = {
|
||||
const props: MinMax = {
|
||||
type: "number"
|
||||
};
|
||||
if(typeof minMax.min == "number" && !isNaN(minMax.min))
|
||||
|
@ -127,8 +130,8 @@ class NumberSetting extends Setting<number, HTMLInputElement> {
|
|||
}
|
||||
|
||||
function createLightbox() {
|
||||
let settingsHTML =
|
||||
'<div id="settings-container" style="overflow:auto"><table width="100%"><colgroup><col span="1" width="50%"><col span="1" width="50%"></colgroup></table></div><div class="lightbox-footer"><hr /><button id="save-settings-button">Save Settings</button></div>';
|
||||
const settingsHTML =
|
||||
`<div id="settings-container" style="overflow:auto"><table width="100%"><colgroup><col span="1" width="50%"><col span="1" width="50%"></colgroup></table></div><div class="lightbox-footer"><hr /><button id="save-settings-button">Save Settings</button></div>`;
|
||||
showLightBox("Settings", settingsHTML);
|
||||
$("button#save-settings-button").on("click", () => {
|
||||
settings.forEach((setting, key) => {
|
||||
|
@ -136,9 +139,9 @@ function createLightbox() {
|
|||
setting.onSave();
|
||||
});
|
||||
});
|
||||
let $settingsTable = $("#settings-container table");
|
||||
const $settingsTable = $("#settings-container table");
|
||||
settings.forEach((setting) => {
|
||||
let $tr = $("<tr/>").appendTo($settingsTable);
|
||||
const $tr = $("<tr/>").appendTo($settingsTable);
|
||||
$("<td/>").append($("<b/>").text(setting.title)).appendTo($tr);
|
||||
$("<td/>").append(setting.element).appendTo($tr);
|
||||
});
|
||||
|
@ -148,7 +151,7 @@ function createLightbox() {
|
|||
* executes the custom JavaScript set in the settings
|
||||
*/
|
||||
export function setCustomJS() {
|
||||
let customJS = getStorageVal("customjs");
|
||||
const customJS = getStorageVal("customjs");
|
||||
if(customJS != "") {
|
||||
eval(customJS);
|
||||
}
|
||||
|
@ -158,22 +161,21 @@ export function setCustomJS() {
|
|||
* applies the custom CSS set in the settings
|
||||
*/
|
||||
export function setCustomCSS() {
|
||||
let customCSS = getStorageVal("customcss");
|
||||
const customCSS = getStorageVal("customcss");
|
||||
if(customCSS != "") {
|
||||
$("style#customCSS").remove();
|
||||
$("<style/>").prop({
|
||||
id: "customCSS"
|
||||
}).html(customCSS)
|
||||
.appendTo(document.head);
|
||||
}).html(customCSS).appendTo(document.head);
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
let styleOptions = [];
|
||||
const styleOptions = [];
|
||||
for(const style of styles) {
|
||||
styleOptions.push({text: style.Name, val: style.Filename});
|
||||
}
|
||||
settings.set("style", new DropdownSetting<string>("style", "Style", styleOptions, defaultStyle, function() {
|
||||
settings.set("style", new DropdownSetting("style", "Style", styleOptions, defaultStyle, function() {
|
||||
document.getElementById("theme").setAttribute("href",
|
||||
`${webroot}css/${this.getElementValue()}`);
|
||||
}) as Setting);
|
||||
|
|
|
@ -4,14 +4,14 @@ import { getCookie, setCookie } from "./cookies";
|
|||
export function getStorageVal(key: string, defaultVal = "") {
|
||||
if(localStorage == undefined)
|
||||
return getCookie(key, defaultVal);
|
||||
let val = localStorage.getItem(key);
|
||||
const val = localStorage.getItem(key);
|
||||
if(val === null)
|
||||
return defaultVal;
|
||||
return val;
|
||||
}
|
||||
|
||||
export function getBooleanStorageVal(key: string, defaultVal = false) {
|
||||
let val = getStorageVal(key, defaultVal?"true":"false");
|
||||
const val = getStorageVal(key, defaultVal?"true":"false");
|
||||
return val == "true";
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ export function getJsonStorageVal<T>(key: string, defaultVal: T) {
|
|||
}
|
||||
|
||||
export function setStorageVal(key: string, val: any, isJSON = false) {
|
||||
let storeVal = isJSON?JSON.stringify(val):val;
|
||||
const storeVal = isJSON?JSON.stringify(val):val;
|
||||
if(localStorage == undefined)
|
||||
setCookie(key, storeVal);
|
||||
else
|
||||
|
|
2
frontend/ts/types/index.d.ts
vendored
2
frontend/ts/types/index.d.ts
vendored
|
@ -1,3 +1,5 @@
|
|||
/* eslint no-var: 0 */
|
||||
|
||||
import "jquery";
|
||||
|
||||
declare global {
|
||||
|
|
|
@ -18,7 +18,7 @@ function addThreadToMenu(thread: WatchedThreadJSON) {
|
|||
return;
|
||||
}
|
||||
if(thread.op == "") thread.op = "Anonymous";
|
||||
let $replyCounter = $("<span/>")
|
||||
const $replyCounter = $("<span/>")
|
||||
.prop({id: "reply-counter"})
|
||||
.text(`(Replies: ${thread.posts - 1})`);
|
||||
let infoElem = ` - <b>OP:</b> ${thread.op}<br/>`;
|
||||
|
@ -27,7 +27,7 @@ function addThreadToMenu(thread: WatchedThreadJSON) {
|
|||
} else {
|
||||
infoElem += `<b>Subject: </b> ${thread.subject}`;
|
||||
}
|
||||
let $watcherItem = $("<div/>").prop({
|
||||
const $watcherItem = $("<div/>").prop({
|
||||
id: `thread${thread.id}`,
|
||||
class: "watcher-item"
|
||||
}).append(
|
||||
|
@ -45,10 +45,10 @@ function addThreadToMenu(thread: WatchedThreadJSON) {
|
|||
}).text("X"), " "
|
||||
);
|
||||
if(thread.err !== undefined)
|
||||
$watcherItem.append($("<span/>")
|
||||
.prop({class: "warning"})
|
||||
.text(`(${thread.err})`)
|
||||
);
|
||||
$watcherItem.append($("<span/>")
|
||||
.prop({class: "warning"})
|
||||
.text(`(${thread.err})`)
|
||||
);
|
||||
$watcherMenu.append(
|
||||
$watcherItem.append(infoElem)
|
||||
);
|
||||
|
@ -59,16 +59,16 @@ function addThreadToMenu(thread: WatchedThreadJSON) {
|
|||
function removeThreadFromMenu(threadID: number) {
|
||||
$watcherMenu.find(`div#thread${threadID}`).remove();
|
||||
if($watcherMenu.find("div.watcher-item").length == 0)
|
||||
$watcherMenu.append('<i id="no-threads">no watched threads</i>');
|
||||
$watcherMenu.append(`<i id="no-threads">no watched threads</i>`);
|
||||
}
|
||||
|
||||
function updateThreadInWatcherMenu(thread: WatchedThreadJSON) {
|
||||
let currentPage = currentThread();
|
||||
const currentPage = currentThread();
|
||||
|
||||
let $item = $watcherMenu.find(`div#thread${thread.op}`);
|
||||
const $item = $watcherMenu.find(`div#thread${thread.op}`);
|
||||
if($item.length == 0) return; // watched thread isn't in the menu
|
||||
$item.find("span#reply-counter").remove();
|
||||
let $replyCounter = $("<span>").prop({
|
||||
const $replyCounter = $("<span>").prop({
|
||||
id: "reply-counter"
|
||||
}).insertBefore($item.find(`a#unwatch${thread.op}`));
|
||||
|
||||
|
@ -101,7 +101,7 @@ $(() => {
|
|||
$watcherMenu = $("<div/>").prop({
|
||||
id: "watchermenu",
|
||||
class: "dropdown-menu"
|
||||
}).append('<b>Watched threads</b><br/><i id="no-threads">no watched threads</i>');
|
||||
}).append(`<b>Watched threads</b><br/><i id="no-threads">no watched threads</i>`);
|
||||
}
|
||||
if(watcherBtn === null) {
|
||||
watcherBtn = new TopBarButton("Watcher", () => {
|
||||
|
@ -117,8 +117,8 @@ $(() => {
|
|||
.on("beginNewPostsCheck", () => {
|
||||
numUpdatedThreads = 0;
|
||||
});
|
||||
let watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
let boards = Object.keys(watched);
|
||||
const watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
const boards = Object.keys(watched);
|
||||
for(const board of boards) {
|
||||
for(const thread of watched[board]) {
|
||||
addThreadToMenu(thread);
|
||||
|
|
|
@ -7,12 +7,12 @@ import "./menu";
|
|||
|
||||
const subjectCuttoff = 24;
|
||||
|
||||
let watcherInterval = -1;
|
||||
const watcherInterval = -1;
|
||||
|
||||
export function updateWatchedThreads() {
|
||||
let watched = getJsonStorageVal<any>("watched", {});
|
||||
let boards = Object.keys(watched);
|
||||
let currentPage = currentThread();
|
||||
const watched = getJsonStorageVal<any>("watched", {});
|
||||
const boards = Object.keys(watched);
|
||||
const currentPage = currentThread();
|
||||
for(const board of boards) {
|
||||
if(!(watched[board] instanceof Array)) {
|
||||
console.error(`Invalid data for board ${board}: expected Array object, deleting.`);
|
||||
|
@ -67,8 +67,8 @@ export interface WatchedThreadJSON {
|
|||
}
|
||||
|
||||
export function isThreadWatched(threadID: number, board: string) {
|
||||
let watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
let threads = watched[board];
|
||||
const watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
const threads = watched[board];
|
||||
if(threads == undefined) return false;
|
||||
for(const thread of threads) {
|
||||
if(thread.id == threadID) return true;
|
||||
|
@ -77,7 +77,7 @@ export function isThreadWatched(threadID: number, board: string) {
|
|||
}
|
||||
|
||||
export function watchThread(threadID: string|number, board: string) {
|
||||
let watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
const watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
if(typeof threadID == "string") {
|
||||
threadID = parseInt(threadID);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ export function watchThread(threadID: string|number, board: string) {
|
|||
}
|
||||
getThreadJSON(threadID, board).then(data => {
|
||||
const op = data.posts[0];
|
||||
let threadObj: WatchedThreadJSON = {
|
||||
const threadObj: WatchedThreadJSON = {
|
||||
id: threadID as number,
|
||||
board: board,
|
||||
posts: data.posts.length,
|
||||
|
@ -114,7 +114,7 @@ export function watchThread(threadID: string|number, board: string) {
|
|||
}
|
||||
|
||||
export function unwatchThread(threadID: number, board: string) {
|
||||
let watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
const watched = getJsonStorageVal<WatchedThreadsListJSON>("watched", {});
|
||||
if(!(watched[board] instanceof Array))
|
||||
return;
|
||||
for(const i in watched[board]) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue