Split some of the member only logic out of global.js and into member.js
Moved the script in register.html into an external file. Client hooks can now be dynamically created thus reducing the burden on init.js to pre-define all of them. The current user is now passed in as an argument to the action_end_create_topic hook. Shorted more common. to c. Added the almost_end_init client hook.
This commit is contained in:
parent
e3e5d62e94
commit
d0e40ae81b
13
mysql.go
13
mysql.go
|
@ -11,7 +11,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
"github.com/Azareal/Gosora/query_gen"
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -26,11 +26,11 @@ func init() {
|
||||||
|
|
||||||
func initMySQL() (err error) {
|
func initMySQL() (err error) {
|
||||||
err = qgen.Builder.Init("mysql", map[string]string{
|
err = qgen.Builder.Init("mysql", map[string]string{
|
||||||
"host": common.DbConfig.Host,
|
"host": c.DbConfig.Host,
|
||||||
"port": common.DbConfig.Port,
|
"port": c.DbConfig.Port,
|
||||||
"name": common.DbConfig.Dbname,
|
"name": c.DbConfig.Dbname,
|
||||||
"username": common.DbConfig.Username,
|
"username": c.DbConfig.Username,
|
||||||
"password": common.DbConfig.Password,
|
"password": c.DbConfig.Password,
|
||||||
"collation": dbCollation,
|
"collation": dbCollation,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,6 +41,7 @@ func initMySQL() (err error) {
|
||||||
db = qgen.Builder.GetConn()
|
db = qgen.Builder.GetConn()
|
||||||
db.SetMaxOpenConns(64)
|
db.SetMaxOpenConns(64)
|
||||||
db.SetMaxIdleConns(32)
|
db.SetMaxIdleConns(32)
|
||||||
|
//db.SetConnMaxLifetime(time.Second * 60 * 5) // Just in case we accumulate some bad connections due to the MySQL driver being stupid
|
||||||
|
|
||||||
// Only hold connections open for five seconds to avoid accumulating a large number of stale connections
|
// Only hold connections open for five seconds to avoid accumulating a large number of stale connections
|
||||||
//db.SetConnMaxLifetime(5 * time.Second)
|
//db.SetConnMaxLifetime(5 * time.Second)
|
||||||
|
|
302
public/global.js
302
public/global.js
|
@ -852,284 +852,6 @@ function mainInit(){
|
||||||
$(".topic_create_form").hide();
|
$(".topic_create_form").hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
function uploadFileHandler(fileList, maxFiles = 5, step1 = () => {}, step2 = () => {}) {
|
|
||||||
let files = [];
|
|
||||||
for(var i = 0; i < fileList.length && i < 5; i++) files[i] = fileList[i];
|
|
||||||
|
|
||||||
let totalSize = 0;
|
|
||||||
for(let i = 0; i < files.length; i++) {
|
|
||||||
console.log("files[" + i + "]",files[i]);
|
|
||||||
totalSize += files[i]["size"];
|
|
||||||
}
|
|
||||||
if(totalSize > me.Site.MaxRequestSize) {
|
|
||||||
throw("You can't upload this much at once, max: " + me.Site.MaxRequestSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let i = 0; i < files.length; i++) {
|
|
||||||
let filename = files[i]["name"];
|
|
||||||
let f = (e) => {
|
|
||||||
step1(e,filename)
|
|
||||||
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.onload = (e2) => {
|
|
||||||
crypto.subtle.digest('SHA-256',e2.target.result)
|
|
||||||
.then((hash) => {
|
|
||||||
const hashArray = Array.from(new Uint8Array(hash))
|
|
||||||
return hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('')
|
|
||||||
}).then(hash => step2(e,hash,filename));
|
|
||||||
}
|
|
||||||
reader.readAsArrayBuffer(files[i]);
|
|
||||||
};
|
|
||||||
|
|
||||||
let ext = getExt(filename);
|
|
||||||
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
|
||||||
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
|
||||||
if(isImage) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.onload = f;
|
|
||||||
reader.readAsDataURL(files[i]);
|
|
||||||
} else f(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Surely, there's a prettier and more elegant way of doing this?
|
|
||||||
function getExt(filename) {
|
|
||||||
if(!filename.indexOf('.' > -1)) throw("This file doesn't have an extension");
|
|
||||||
return filename.split('.').pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attachment Manager
|
|
||||||
function uploadAttachHandler2() {
|
|
||||||
let post = this.closest(".post_item");
|
|
||||||
let fileDock = this.closest(".attach_edit_bay");
|
|
||||||
try {
|
|
||||||
uploadFileHandler(this.files, 5, () => {},
|
|
||||||
(e, hash, filename) => {
|
|
||||||
console.log("hash",hash);
|
|
||||||
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append("session",me.User.Session);
|
|
||||||
for(let i = 0; i < this.files.length; i++) formData.append("upload_files",this.files[i]);
|
|
||||||
bindAttachManager();
|
|
||||||
|
|
||||||
let req = new XMLHttpRequest();
|
|
||||||
req.addEventListener("load", () => {
|
|
||||||
let data = JSON.parse(req.responseText);
|
|
||||||
//console.log("rdata:",data);
|
|
||||||
let fileItem = document.createElement("div");
|
|
||||||
let ext = getExt(filename);
|
|
||||||
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
|
||||||
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
|
||||||
let c = "";
|
|
||||||
if(isImage) c = " attach_image_holder"
|
|
||||||
fileItem.className = "attach_item attach_item_item" + c;
|
|
||||||
fileItem.innerHTML = Template_topic_c_attach_item({
|
|
||||||
ID: data.elems[hash+"."+ext],
|
|
||||||
ImgSrc: isImage ? e.target.result : "",
|
|
||||||
Path: hash+"."+ext,
|
|
||||||
FullPath: "//" + window.location.host + "/attachs/" + hash + "." + ext,
|
|
||||||
});
|
|
||||||
fileDock.insertBefore(fileItem,fileDock.querySelector(".attach_item_buttons"));
|
|
||||||
|
|
||||||
post.classList.add("has_attachs");
|
|
||||||
bindAttachItems();
|
|
||||||
});
|
|
||||||
req.open("POST","//"+window.location.host+"/"+fileDock.getAttribute("type")+"/attach/add/submit/"+fileDock.getAttribute("id"));
|
|
||||||
req.send(formData);
|
|
||||||
});
|
|
||||||
} catch(e) {
|
|
||||||
// TODO: Use a notice instead
|
|
||||||
console.log("e:",e);
|
|
||||||
alert(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quick Topic / Quick Reply
|
|
||||||
function uploadAttachHandler() {
|
|
||||||
try {
|
|
||||||
uploadFileHandler(this.files, 5, (e,filename) => {
|
|
||||||
// TODO: Use client templates here
|
|
||||||
let fileDock = document.getElementById("upload_file_dock");
|
|
||||||
let fileItem = document.createElement("label");
|
|
||||||
console.log("fileItem",fileItem);
|
|
||||||
|
|
||||||
let ext = getExt(filename);
|
|
||||||
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
|
||||||
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
|
||||||
fileItem.innerText = "." + ext;
|
|
||||||
fileItem.className = "formbutton uploadItem";
|
|
||||||
// TODO: Check if this is actually an image
|
|
||||||
if(isImage) fileItem.style.backgroundImage = "url("+e.target.result+")";
|
|
||||||
|
|
||||||
fileDock.appendChild(fileItem);
|
|
||||||
},(e,hash, filename) => {
|
|
||||||
console.log("hash",hash);
|
|
||||||
let ext = getExt(filename)
|
|
||||||
let content = document.getElementById("input_content")
|
|
||||||
console.log("content.value", content.value);
|
|
||||||
|
|
||||||
let attachItem;
|
|
||||||
if(content.value == "") attachItem = "//" + window.location.host + "/attachs/" + hash + "." + ext;
|
|
||||||
else attachItem = "\r\n//" + window.location.host + "/attachs/" + hash + "." + ext;
|
|
||||||
content.value = content.value + attachItem;
|
|
||||||
console.log("content.value", content.value);
|
|
||||||
|
|
||||||
// For custom / third party text editors
|
|
||||||
attachItemCallback(attachItem);
|
|
||||||
});
|
|
||||||
} catch(e) {
|
|
||||||
// TODO: Use a notice instead
|
|
||||||
console.log("e:",e);
|
|
||||||
alert(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let uploadFiles = document.getElementById("upload_files");
|
|
||||||
if(uploadFiles != null) {
|
|
||||||
uploadFiles.addEventListener("change", uploadAttachHandler, false);
|
|
||||||
}
|
|
||||||
let uploadFilesOp = document.getElementById("upload_files_op");
|
|
||||||
if(uploadFilesOp != null) {
|
|
||||||
uploadFilesOp.addEventListener("change", uploadAttachHandler2, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindAttachManager() {
|
|
||||||
let uploadFiles = document.getElementsByClassName("upload_files_post");
|
|
||||||
if(uploadFiles == null) return;
|
|
||||||
for(let i = 0; i < uploadFiles.length; i++) {
|
|
||||||
let uploader = uploadFiles[i];
|
|
||||||
uploader.value = "";
|
|
||||||
uploader.removeEventListener("change", uploadAttachHandler2, false);
|
|
||||||
uploader.addEventListener("change", uploadAttachHandler2, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bindAttachManager();
|
|
||||||
|
|
||||||
function copyToClipboard(str) {
|
|
||||||
const el = document.createElement('textarea');
|
|
||||||
el.value = str;
|
|
||||||
el.setAttribute('readonly', '');
|
|
||||||
el.style.position = 'absolute';
|
|
||||||
el.style.left = '-9999px';
|
|
||||||
document.body.appendChild(el);
|
|
||||||
el.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindAttachItems() {
|
|
||||||
$(".attach_item_select").unbind("click");
|
|
||||||
$(".attach_item_copy").unbind("click");
|
|
||||||
$(".attach_item_select").click(function(){
|
|
||||||
let hold = $(this).closest(".attach_item");
|
|
||||||
if(hold.hasClass("attach_item_selected")) hold.removeClass("attach_item_selected");
|
|
||||||
else hold.addClass("attach_item_selected");
|
|
||||||
});
|
|
||||||
$(".attach_item_copy").click(function(){
|
|
||||||
let hold = $(this).closest(".attach_item");
|
|
||||||
let pathNode = hold.find(".attach_item_path");
|
|
||||||
copyToClipboard(pathNode.attr("fullPath"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
bindAttachItems();
|
|
||||||
|
|
||||||
$(".attach_item_delete").click(function(){
|
|
||||||
let formData = new URLSearchParams();
|
|
||||||
formData.append("session",me.User.Session);
|
|
||||||
|
|
||||||
let post = this.closest(".post_item");
|
|
||||||
let aidList = "";
|
|
||||||
let elems = post.getElementsByClassName("attach_item_selected");
|
|
||||||
if(elems == null) return;
|
|
||||||
|
|
||||||
for(let i = 0; i < elems.length; i++) {
|
|
||||||
let pathNode = elems[i].querySelector(".attach_item_path");
|
|
||||||
console.log("pathNode",pathNode);
|
|
||||||
aidList += pathNode.getAttribute("aid") + ",";
|
|
||||||
elems[i].remove();
|
|
||||||
}
|
|
||||||
if(aidList.length > 0) aidList = aidList.slice(0, -1);
|
|
||||||
console.log("aidList",aidList)
|
|
||||||
formData.append("aids",aidList);
|
|
||||||
|
|
||||||
let ec = 0;
|
|
||||||
let e = post.getElementsByClassName("attach_item_item");
|
|
||||||
if(e!=null) ec = e.length;
|
|
||||||
if(ec==0) post.classList.remove("has_attachs");
|
|
||||||
|
|
||||||
let req = new XMLHttpRequest();
|
|
||||||
let fileDock = this.closest(".attach_edit_bay");
|
|
||||||
req.open("POST","//"+window.location.host+"/"+fileDock.getAttribute("type")+"/attach/remove/submit/"+fileDock.getAttribute("id"),true);
|
|
||||||
req.send(formData);
|
|
||||||
|
|
||||||
bindAttachItems();
|
|
||||||
bindAttachManager();
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".moderate_link").click((event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
$(".pre_opt").removeClass("auto_hide");
|
|
||||||
$(".moderate_link").addClass("moderate_open");
|
|
||||||
$(".topic_row").each(function(){
|
|
||||||
$(this).click(function(){
|
|
||||||
selectedTopics.push(parseInt($(this).attr("data-tid"),10));
|
|
||||||
if(selectedTopics.length==1) {
|
|
||||||
var msg = phraseBox["topic_list"]["topic_list.what_to_do_single"];
|
|
||||||
} else {
|
|
||||||
var msg = "What do you want to do with these "+selectedTopics.length+" topics?";
|
|
||||||
}
|
|
||||||
$(".mod_floater_head span").html(msg);
|
|
||||||
$(this).addClass("topic_selected");
|
|
||||||
$(".mod_floater").removeClass("auto_hide");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let bulkActionSender = function(action, selectedTopics, fragBit) {
|
|
||||||
let url = "/topic/"+action+"/submit/"+fragBit+"?session=" + me.User.Session;
|
|
||||||
$.ajax({
|
|
||||||
url: url,
|
|
||||||
type: "POST",
|
|
||||||
data: JSON.stringify(selectedTopics),
|
|
||||||
contentType: "application/json",
|
|
||||||
error: ajaxError,
|
|
||||||
success: () => {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
$(".mod_floater_submit").click(function(event){
|
|
||||||
event.preventDefault();
|
|
||||||
let selectNode = this.form.querySelector(".mod_floater_options");
|
|
||||||
let optionNode = selectNode.options[selectNode.selectedIndex];
|
|
||||||
let action = optionNode.getAttribute("val");
|
|
||||||
|
|
||||||
// Handle these specially
|
|
||||||
switch(action) {
|
|
||||||
case "move":
|
|
||||||
console.log("move action");
|
|
||||||
let modTopicMover = $("#mod_topic_mover");
|
|
||||||
$("#mod_topic_mover").removeClass("auto_hide");
|
|
||||||
$("#mod_topic_mover .pane_row").click(function(){
|
|
||||||
modTopicMover.find(".pane_row").removeClass("pane_selected");
|
|
||||||
let fid = this.getAttribute("data-fid");
|
|
||||||
if (fid == null) return;
|
|
||||||
this.classList.add("pane_selected");
|
|
||||||
console.log("fid: " + fid);
|
|
||||||
forumToMoveTo = fid;
|
|
||||||
|
|
||||||
$("#mover_submit").unbind("click");
|
|
||||||
$("#mover_submit").click(function(event){
|
|
||||||
event.preventDefault();
|
|
||||||
bulkActionSender("move",selectedTopics,forumToMoveTo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bulkActionSender(action,selectedTopics,"");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#themeSelectorSelect").change(function(){
|
$("#themeSelectorSelect").change(function(){
|
||||||
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
|
console.log("Changing the theme to " + this.options[this.selectedIndex].getAttribute("val"));
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -1180,28 +902,6 @@ function mainInit(){
|
||||||
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
|
if(event.which == 39) this.querySelectorAll("#nextFloat a")[0].click();
|
||||||
};
|
};
|
||||||
|
|
||||||
function addPollInput() {
|
|
||||||
console.log("clicked on pollinputinput");
|
|
||||||
let dataPollInput = $(this).parent().attr("data-pollinput");
|
|
||||||
console.log("dataPollInput: ", dataPollInput);
|
|
||||||
if(dataPollInput == undefined) return;
|
|
||||||
if(dataPollInput != (pollInputIndex-1)) return;
|
|
||||||
|
|
||||||
$(".poll_content_row .formitem").append("<div class='pollinput' data-pollinput='"+pollInputIndex+"'><input type='checkbox' disabled /><label class='pollinputlabel'></label><input form='quick_post_form' name='pollinputitem["+pollInputIndex+"]' class='pollinputinput' type='text' placeholder='Add new poll option' /></div>");
|
|
||||||
pollInputIndex++;
|
|
||||||
console.log("new pollInputIndex: ", pollInputIndex);
|
|
||||||
$(".pollinputinput").off("click");
|
|
||||||
$(".pollinputinput").click(addPollInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pollInputIndex = 1;
|
|
||||||
$("#add_poll_button").click((event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
$(".poll_content_row").removeClass("auto_hide");
|
|
||||||
$("#has_poll_input").val("1");
|
|
||||||
$(".pollinputinput").click(addPollInput);
|
|
||||||
});
|
|
||||||
|
|
||||||
//id="poll_results_{{.Poll.ID}}" class="poll_results auto_hide"
|
//id="poll_results_{{.Poll.ID}}" class="poll_results auto_hide"
|
||||||
$(".poll_results_button").click(function(){
|
$(".poll_results_button").click(function(){
|
||||||
let pollID = $(this).attr("data-poll-id");
|
let pollID = $(this).attr("data-poll-id");
|
||||||
|
@ -1211,7 +911,6 @@ function mainInit(){
|
||||||
}).then((response) => response.text()).catch((error) => console.error("Error:",error)).then((rawData) => {
|
}).then((response) => response.text()).catch((error) => console.error("Error:",error)).then((rawData) => {
|
||||||
// TODO: Make sure the received data is actually a list of integers
|
// TODO: Make sure the received data is actually a list of integers
|
||||||
let data = JSON.parse(rawData);
|
let data = JSON.parse(rawData);
|
||||||
|
|
||||||
let allZero = true;
|
let allZero = true;
|
||||||
for(let i = 0; i < data.length; i++) {
|
for(let i = 0; i < data.length; i++) {
|
||||||
if(data[i] != "0") allZero = false;
|
if(data[i] != "0") allZero = false;
|
||||||
|
@ -1233,5 +932,6 @@ function mainInit(){
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
runInitHook("almost_end_init");
|
||||||
runInitHook("end_init");
|
runInitHook("end_init");
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ var hooks = { // Shorten this list by binding the hooks just in time?
|
||||||
"pre_iffe": [],
|
"pre_iffe": [],
|
||||||
"pre_init": [],
|
"pre_init": [],
|
||||||
"start_init": [],
|
"start_init": [],
|
||||||
|
"almost_end_init": [],
|
||||||
"end_init": [],
|
"end_init": [],
|
||||||
"after_phrases":[],
|
"after_phrases":[],
|
||||||
"after_add_alert":[],
|
"after_add_alert":[],
|
||||||
|
@ -33,6 +34,7 @@ function runHook(name, ...args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHook(name, callback) {
|
function addHook(name, callback) {
|
||||||
|
if(hooks[name]===undefined) hooks[name] = [];
|
||||||
hooks[name].push(callback);
|
hooks[name].push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,303 @@
|
||||||
|
(() => {
|
||||||
|
addInitHook("almost_end_init", () => {
|
||||||
|
function copyToClipboard(str) {
|
||||||
|
const el = document.createElement('textarea');
|
||||||
|
el.value = str;
|
||||||
|
el.setAttribute('readonly', '');
|
||||||
|
el.style.position = 'absolute';
|
||||||
|
el.style.left = '-9999px';
|
||||||
|
document.body.appendChild(el);
|
||||||
|
el.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Surely, there's a prettier and more elegant way of doing this?
|
||||||
|
function getExt(filename) {
|
||||||
|
if(!filename.indexOf('.' > -1)) throw("This file doesn't have an extension");
|
||||||
|
return filename.split('.').pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadFileHandler(fileList, maxFiles = 5, step1 = () => {}, step2 = () => {}) {
|
||||||
|
let files = [];
|
||||||
|
for(var i = 0; i < fileList.length && i < 5; i++) files[i] = fileList[i];
|
||||||
|
|
||||||
|
let totalSize = 0;
|
||||||
|
for(let i = 0; i < files.length; i++) {
|
||||||
|
console.log("files[" + i + "]",files[i]);
|
||||||
|
totalSize += files[i]["size"];
|
||||||
|
}
|
||||||
|
if(totalSize > me.Site.MaxRequestSize) {
|
||||||
|
throw("You can't upload this much at once, max: " + me.Site.MaxRequestSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let i = 0; i < files.length; i++) {
|
||||||
|
let filename = files[i]["name"];
|
||||||
|
let f = (e) => {
|
||||||
|
step1(e,filename)
|
||||||
|
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = (e2) => {
|
||||||
|
crypto.subtle.digest('SHA-256',e2.target.result)
|
||||||
|
.then((hash) => {
|
||||||
|
const hashArray = Array.from(new Uint8Array(hash))
|
||||||
|
return hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('')
|
||||||
|
}).then(hash => step2(e,hash,filename));
|
||||||
|
}
|
||||||
|
reader.readAsArrayBuffer(files[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
let ext = getExt(filename);
|
||||||
|
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
||||||
|
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
||||||
|
if(isImage) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = f;
|
||||||
|
reader.readAsDataURL(files[i]);
|
||||||
|
} else f(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attachment Manager
|
||||||
|
function uploadAttachHandler2() {
|
||||||
|
let post = this.closest(".post_item");
|
||||||
|
let fileDock = this.closest(".attach_edit_bay");
|
||||||
|
try {
|
||||||
|
uploadFileHandler(this.files, 5, () => {},
|
||||||
|
(e, hash, filename) => {
|
||||||
|
console.log("hash",hash);
|
||||||
|
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("session",me.User.Session);
|
||||||
|
for(let i = 0; i < this.files.length; i++) formData.append("upload_files",this.files[i]);
|
||||||
|
bindAttachManager();
|
||||||
|
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
req.addEventListener("load", () => {
|
||||||
|
let data = JSON.parse(req.responseText);
|
||||||
|
//console.log("rdata:",data);
|
||||||
|
let fileItem = document.createElement("div");
|
||||||
|
let ext = getExt(filename);
|
||||||
|
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
||||||
|
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
||||||
|
let c = "";
|
||||||
|
if(isImage) c = " attach_image_holder"
|
||||||
|
fileItem.className = "attach_item attach_item_item" + c;
|
||||||
|
fileItem.innerHTML = Template_topic_c_attach_item({
|
||||||
|
ID: data.elems[hash+"."+ext],
|
||||||
|
ImgSrc: isImage ? e.target.result : "",
|
||||||
|
Path: hash+"."+ext,
|
||||||
|
FullPath: "//" + window.location.host + "/attachs/" + hash + "." + ext,
|
||||||
|
});
|
||||||
|
fileDock.insertBefore(fileItem,fileDock.querySelector(".attach_item_buttons"));
|
||||||
|
|
||||||
|
post.classList.add("has_attachs");
|
||||||
|
bindAttachItems();
|
||||||
|
});
|
||||||
|
req.open("POST","//"+window.location.host+"/"+fileDock.getAttribute("type")+"/attach/add/submit/"+fileDock.getAttribute("id"));
|
||||||
|
req.send(formData);
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
// TODO: Use a notice instead
|
||||||
|
console.log("e:",e);
|
||||||
|
alert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick Topic / Quick Reply
|
||||||
|
function uploadAttachHandler() {
|
||||||
|
try {
|
||||||
|
uploadFileHandler(this.files, 5, (e,filename) => {
|
||||||
|
// TODO: Use client templates here
|
||||||
|
let fileDock = document.getElementById("upload_file_dock");
|
||||||
|
let fileItem = document.createElement("label");
|
||||||
|
console.log("fileItem",fileItem);
|
||||||
|
|
||||||
|
let ext = getExt(filename);
|
||||||
|
// TODO: Push ImageFileExts to the client from the server in some sort of gen.js?
|
||||||
|
let isImage = ["png", "jpg", "jpeg", "svg", "bmp", "gif", "tif", "webp"].includes(ext);
|
||||||
|
fileItem.innerText = "." + ext;
|
||||||
|
fileItem.className = "formbutton uploadItem";
|
||||||
|
// TODO: Check if this is actually an image
|
||||||
|
if(isImage) fileItem.style.backgroundImage = "url("+e.target.result+")";
|
||||||
|
|
||||||
|
fileDock.appendChild(fileItem);
|
||||||
|
},(e,hash, filename) => {
|
||||||
|
console.log("hash",hash);
|
||||||
|
let ext = getExt(filename)
|
||||||
|
let content = document.getElementById("input_content")
|
||||||
|
console.log("content.value", content.value);
|
||||||
|
|
||||||
|
let attachItem;
|
||||||
|
if(content.value == "") attachItem = "//" + window.location.host + "/attachs/" + hash + "." + ext;
|
||||||
|
else attachItem = "\r\n//" + window.location.host + "/attachs/" + hash + "." + ext;
|
||||||
|
content.value = content.value + attachItem;
|
||||||
|
console.log("content.value", content.value);
|
||||||
|
|
||||||
|
// For custom / third party text editors
|
||||||
|
attachItemCallback(attachItem);
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
// TODO: Use a notice instead
|
||||||
|
console.log("e:",e);
|
||||||
|
alert(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let uploadFiles = document.getElementById("upload_files");
|
||||||
|
if(uploadFiles != null) {
|
||||||
|
uploadFiles.addEventListener("change", uploadAttachHandler, false);
|
||||||
|
}
|
||||||
|
let uploadFilesOp = document.getElementById("upload_files_op");
|
||||||
|
if(uploadFilesOp != null) {
|
||||||
|
uploadFilesOp.addEventListener("change", uploadAttachHandler2, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindAttachManager() {
|
||||||
|
let uploadFiles = document.getElementsByClassName("upload_files_post");
|
||||||
|
if(uploadFiles == null) return;
|
||||||
|
for(let i = 0; i < uploadFiles.length; i++) {
|
||||||
|
let uploader = uploadFiles[i];
|
||||||
|
uploader.value = "";
|
||||||
|
uploader.removeEventListener("change", uploadAttachHandler2, false);
|
||||||
|
uploader.addEventListener("change", uploadAttachHandler2, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bindAttachManager();
|
||||||
|
|
||||||
|
function bindAttachItems() {
|
||||||
|
$(".attach_item_select").unbind("click");
|
||||||
|
$(".attach_item_copy").unbind("click");
|
||||||
|
$(".attach_item_select").click(function(){
|
||||||
|
let hold = $(this).closest(".attach_item");
|
||||||
|
if(hold.hasClass("attach_item_selected")) hold.removeClass("attach_item_selected");
|
||||||
|
else hold.addClass("attach_item_selected");
|
||||||
|
});
|
||||||
|
$(".attach_item_copy").click(function(){
|
||||||
|
let hold = $(this).closest(".attach_item");
|
||||||
|
let pathNode = hold.find(".attach_item_path");
|
||||||
|
copyToClipboard(pathNode.attr("fullPath"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
bindAttachItems();
|
||||||
|
|
||||||
|
$(".attach_item_delete").click(function(){
|
||||||
|
let formData = new URLSearchParams();
|
||||||
|
formData.append("session",me.User.Session);
|
||||||
|
|
||||||
|
let post = this.closest(".post_item");
|
||||||
|
let aidList = "";
|
||||||
|
let elems = post.getElementsByClassName("attach_item_selected");
|
||||||
|
if(elems == null) return;
|
||||||
|
|
||||||
|
for(let i = 0; i < elems.length; i++) {
|
||||||
|
let pathNode = elems[i].querySelector(".attach_item_path");
|
||||||
|
console.log("pathNode",pathNode);
|
||||||
|
aidList += pathNode.getAttribute("aid") + ",";
|
||||||
|
elems[i].remove();
|
||||||
|
}
|
||||||
|
if(aidList.length > 0) aidList = aidList.slice(0, -1);
|
||||||
|
console.log("aidList",aidList)
|
||||||
|
formData.append("aids",aidList);
|
||||||
|
|
||||||
|
let ec = 0;
|
||||||
|
let e = post.getElementsByClassName("attach_item_item");
|
||||||
|
if(e!=null) ec = e.length;
|
||||||
|
if(ec==0) post.classList.remove("has_attachs");
|
||||||
|
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
let fileDock = this.closest(".attach_edit_bay");
|
||||||
|
req.open("POST","//"+window.location.host+"/"+fileDock.getAttribute("type")+"/attach/remove/submit/"+fileDock.getAttribute("id"),true);
|
||||||
|
req.send(formData);
|
||||||
|
|
||||||
|
bindAttachItems();
|
||||||
|
bindAttachManager();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".moderate_link").click((event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
$(".pre_opt").removeClass("auto_hide");
|
||||||
|
$(".moderate_link").addClass("moderate_open");
|
||||||
|
$(".topic_row").each(function(){
|
||||||
|
$(this).click(function(){
|
||||||
|
selectedTopics.push(parseInt($(this).attr("data-tid"),10));
|
||||||
|
if(selectedTopics.length==1) {
|
||||||
|
var msg = phraseBox["topic_list"]["topic_list.what_to_do_single"];
|
||||||
|
} else {
|
||||||
|
var msg = "What do you want to do with these "+selectedTopics.length+" topics?";
|
||||||
|
}
|
||||||
|
$(".mod_floater_head span").html(msg);
|
||||||
|
$(this).addClass("topic_selected");
|
||||||
|
$(".mod_floater").removeClass("auto_hide");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let bulkActionSender = function(action, selectedTopics, fragBit) {
|
||||||
|
let url = "/topic/"+action+"/submit/"+fragBit+"?session=" + me.User.Session;
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
type: "POST",
|
||||||
|
data: JSON.stringify(selectedTopics),
|
||||||
|
contentType: "application/json",
|
||||||
|
error: ajaxError,
|
||||||
|
success: () => {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$(".mod_floater_submit").click(function(event){
|
||||||
|
event.preventDefault();
|
||||||
|
let selectNode = this.form.querySelector(".mod_floater_options");
|
||||||
|
let optionNode = selectNode.options[selectNode.selectedIndex];
|
||||||
|
let action = optionNode.getAttribute("val");
|
||||||
|
|
||||||
|
// Handle these specially
|
||||||
|
switch(action) {
|
||||||
|
case "move":
|
||||||
|
console.log("move action");
|
||||||
|
let modTopicMover = $("#mod_topic_mover");
|
||||||
|
$("#mod_topic_mover").removeClass("auto_hide");
|
||||||
|
$("#mod_topic_mover .pane_row").click(function(){
|
||||||
|
modTopicMover.find(".pane_row").removeClass("pane_selected");
|
||||||
|
let fid = this.getAttribute("data-fid");
|
||||||
|
if (fid == null) return;
|
||||||
|
this.classList.add("pane_selected");
|
||||||
|
console.log("fid: " + fid);
|
||||||
|
forumToMoveTo = fid;
|
||||||
|
|
||||||
|
$("#mover_submit").unbind("click");
|
||||||
|
$("#mover_submit").click(function(event){
|
||||||
|
event.preventDefault();
|
||||||
|
bulkActionSender("move",selectedTopics,forumToMoveTo);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bulkActionSender(action,selectedTopics,"");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function addPollInput() {
|
||||||
|
console.log("clicked on pollinputinput");
|
||||||
|
let dataPollInput = $(this).parent().attr("data-pollinput");
|
||||||
|
console.log("dataPollInput: ", dataPollInput);
|
||||||
|
if(dataPollInput == undefined) return;
|
||||||
|
if(dataPollInput != (pollInputIndex-1)) return;
|
||||||
|
|
||||||
|
$(".poll_content_row .formitem").append("<div class='pollinput' data-pollinput='"+pollInputIndex+"'><input type='checkbox' disabled /><label class='pollinputlabel'></label><input form='quick_post_form' name='pollinputitem["+pollInputIndex+"]' class='pollinputinput' type='text' placeholder='Add new poll option' /></div>");
|
||||||
|
pollInputIndex++;
|
||||||
|
console.log("new pollInputIndex: ", pollInputIndex);
|
||||||
|
$(".pollinputinput").off("click");
|
||||||
|
$(".pollinputinput").click(addPollInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pollInputIndex = 1;
|
||||||
|
$("#add_poll_button").click((event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
$(".poll_content_row").removeClass("auto_hide");
|
||||||
|
$("#has_poll_input").val("1");
|
||||||
|
$(".pollinputinput").click(addPollInput);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
|
@ -0,0 +1,14 @@
|
||||||
|
(() => {
|
||||||
|
addInitHook("end_init", () => {
|
||||||
|
fetch("/api/watches/")
|
||||||
|
.then(response => {
|
||||||
|
if(response.status!==200) {
|
||||||
|
console.log("error");
|
||||||
|
console.log("response:", response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.text().then(data => eval(data));
|
||||||
|
})
|
||||||
|
.catch(err => console.log("err:", err));
|
||||||
|
});
|
||||||
|
})();
|
|
@ -192,7 +192,7 @@ func AccountRegister(w http.ResponseWriter, r *http.Request, user c.User, header
|
||||||
return c.LocalError("You're already logged in.", w, r, user)
|
return c.LocalError("You're already logged in.", w, r, user)
|
||||||
}
|
}
|
||||||
header.Title = phrases.GetTitlePhrase("register")
|
header.Title = phrases.GetTitlePhrase("register")
|
||||||
header.LooseCSP = true
|
header.AddScriptAsync("register.js")
|
||||||
return renderTemplate("register", w, r, header, c.Page{header, tList, nil})
|
return renderTemplate("register", w, r, header, c.Page{header, tList, nil})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,7 @@ func CreateTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
||||||
counters.PostCounter.Bump()
|
counters.PostCounter.Bump()
|
||||||
counters.TopicCounter.Bump()
|
counters.TopicCounter.Bump()
|
||||||
// TODO: Pass more data to this hook?
|
// TODO: Pass more data to this hook?
|
||||||
skip, rerr := lite.Hooks.VhookSkippable("action_end_create_topic", tid)
|
skip, rerr := lite.Hooks.VhookSkippable("action_end_create_topic", tid, &user)
|
||||||
if skip || rerr != nil {
|
if skip || rerr != nil {
|
||||||
return rerr
|
return rerr
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
{{range .Header.PreScriptsAsync}}
|
{{range .Header.PreScriptsAsync}}
|
||||||
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
||||||
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
<meta property="x-loggedin" content="{{.CurrentUser.Loggedin}}" />
|
||||||
<script type="text/javascript" src="/static/init.js?i=2"></script>
|
<script type="text/javascript" src="/static/init.js?i=3"></script>
|
||||||
{{range .Header.ScriptsAsync}}
|
{{range .Header.ScriptsAsync}}
|
||||||
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
<script async type="text/javascript" src="/static/{{.}}"></script>{{end}}
|
||||||
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
|
<script type="text/javascript" src="/static/jquery-3.1.1.min.js"></script>
|
||||||
|
|
|
@ -35,16 +35,4 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<script>
|
|
||||||
fetch("/api/watches/")
|
|
||||||
.then(response => {
|
|
||||||
if(response.status!==200) {
|
|
||||||
console.log("error");
|
|
||||||
console.log("response:", response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
response.text().then(data => eval(data));
|
|
||||||
})
|
|
||||||
.catch(err => console.log("err:", err));
|
|
||||||
</script>
|
|
||||||
{{template "footer.html" . }}
|
{{template "footer.html" . }}
|
||||||
|
|
Loading…
Reference in New Issue