1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-18 07:36:24 -07:00

Add lock/unlock option to post dropdown

This commit is contained in:
Eggbertx 2023-02-08 12:40:36 -08:00
parent 5956223d1f
commit 69320d5df4
12 changed files with 88 additions and 10 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2013-2022, Gochan development group
Copyright (c) 2013-2023, Gochan development group
All rights reserved.
Redistribution and use in source and binary forms, with or without

View file

@ -0,0 +1,56 @@
import $ from "jquery";
/**
* Returns true if the post has a lock icon without making a GET request
* @param {JQuery<HTMLElement>} $elem the jQuery element of the post
*/
export function isThreadLocked($elem) {
return $elem.find("span.status-icons img.locked-icon").length == 1;
}
/**
* Sends a POST request to the server to lock or unlock a thread
* @param {string} board The board dir of the thread to be (un)locked, e.g. "test2"
* @param {number} op The post number of the top post in the thread
* @param {boolean} lock If true, the thread will be locked, otherwise it will be unlocked
*/
export async function updateThreadLock(board, op, lock) {
const data = {
board: board,
thread: op,
json: 1
};
if(lock) {
data.lock = "Not locked";
} else {
data.unlock = "Locked";
}
$.post({
url: webroot + "manage/threadattrs",
data: data
}).then((_data) => {
alert("Thread " + (lock?"locked":"unlocked") + " successfully");
const $lockOpt = $(`select#op${op} option`)
.filter((_i, el) => el.textContent == "Lock thread" || el.textContent == "Unlock thread");
if(lock) {
$(`div#op${op} span.status-icons`).append(
$("<img/>").attr({
class: "locked-icon",
src: webroot + "static/lock.png",
alt: "Thread locked",
title: "Thread locked"
})
);
$lockOpt.text("Unlock thread");
} else {
$(`div#op${op} img.locked-icon`).remove();
$lockOpt.text("Lock thread");
}
}).catch((data, status, xhr) => {
if(data.responseJSON !== undefined && data.responseJSON.message !== undefined) {
alert(`Error updating thread /${board}/${op} lock status: ${data.responseJSON.message}`);
} else {
alert("Unable to send request: " + xhr);
}
});
}

View file

@ -6,6 +6,7 @@ import { currentBoard } from "../postinfo";
import { getCookie } from "../cookies";
import { alertLightbox, promptLightbox } from "./lightbox";
import { banFile, getPostInfo } from "../management/manage";
import { updateThreadLock } from "../api/management";
const idRe = /^((reply)|(op))(\d+)/;
@ -154,6 +155,14 @@ function handleActions(action, postIDStr) {
deletePost(postID, board);
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 => {
window.open(`${webroot}manage/ipsearch?limit=100&ip=${info.ip}`);

View file

@ -9,6 +9,7 @@ import { alertLightbox } from "../dom/lightbox";
import { $topbar, TopBarButton } from '../dom/topbar';
import "./sections";
import "./filebans";
import { isThreadLocked } from '../api/management';
/**
* @type {StaffInfo}
@ -49,14 +50,22 @@ function dropdownHasItem(dropdown, item) {
function setupManagementEvents() {
$("select.post-actions").each((_i, el) => {
let $el = $(el);
const $el = $(el);
const $post = $(el.parentElement);
const isLocked = isThreadLocked($post);
if(!dropdownHasItem(el, "Staff Actions")) {
$el.append(`<option disabled="disabled">Staff Actions</option>`);
}
if($post.hasClass("op-post")) {
if(isLocked) {
$el.append("<option>Unlock thread</option>");
} else {
$el.append("<option>Lock thread</option>");
}
}
if(!dropdownHasItem(el, "Posts from this IP")) {
$el.append("<option>Posts from this IP</option>");
}
let $post = $(el.parentElement);
let filenameOrig = $post.find("div.file-info a.file-orig").text();
if(filenameOrig != "" && !dropdownHasItem(el, "Ban filename")) {
$el.append(

View file

@ -4,7 +4,8 @@ export default (window.$ = window.jQuery = jquery);
// overwrite jQuery's deferred exception hook, because otherwise the sourcemap
// is useless if AJAX is involved
jquery.Deferred.exceptionHook = function(err) {
throw err;
// throw err;
return err;
};

View file

@ -1,6 +1,6 @@
{
"name": "gochan.js",
"version": "3.4.1",
"version": "3.5.0",
"description": "",
"type": "module",
"source": "js/gochan.js",

View file

@ -7,6 +7,6 @@
<h1>404: File not found</h1>
<img src="./lol 404.gif" border="0" alt="">
<p>The requested file could not be found on this server.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.4.1
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.5.0
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>Error 500: Internal Server error</h1>
<img src="./server500.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon they get around to it, whenever that is. Hopefully soon.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.4.1
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.5.0
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>Error 502: Bad gateway</h1>
<img src="./server500.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon they get around to it, whenever that is. Hopefully soon.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.4.1
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.5.0
</body>
</html>

View file

@ -55,6 +55,9 @@ func GetPostThread(opID int) (*Thread, error) {
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical,
&thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
))
if errors.Is(err, sql.ErrNoRows) {
err = ErrThreadDoesNotExist
}
return thread, err
}

View file

@ -16,7 +16,7 @@
{{- if ne .post.Tripcode ""}}<span class="tripcode">!{{.post.Tripcode}}</span>{{end}} {{formatTimestamp .post.Timestamp -}}
</label><a href="{{.post.WebPath}}">No.</a> <a href="javascript:quote({{.post.ID}})" class="backlink-click">{{.post.ID}}</a>
<span class="status-icons">
{{- if $.thread.Locked -}}<img src="{{webPath "/static/lock.png"}}" alt="Thread locked" title="Thread locked">{{end -}}
{{- if $.thread.Locked -}}<img src="{{webPath "/static/lock.png"}}" class="locked-icon" alt="Thread locked" title="Thread locked">{{end -}}
</span>
{{if $.is_board_page -}}
[<a href="{{$.post.ThreadPath}}">View</a>]

View file

@ -1 +1 @@
3.4.1
3.5.0