2017-08-18 12:16:56 +00:00
'use strict' ;
2017-01-31 05:13:38 +00:00
var form _vars = { } ;
2017-06-10 07:58:15 +00:00
var alertList = [ ] ;
var alertCount = 0 ;
2017-06-12 09:03:14 +00:00
var conn ;
2017-10-30 09:57:08 +00:00
var selectedTopics = [ ] ;
var attachItemCallback = function ( ) { }
2018-01-14 12:03:20 +00:00
// Topic move
var forumToMoveTo = 0 ;
2017-10-30 09:57:08 +00:00
// TODO: Write a friendlier error handler which uses a .notice or something, we could have a specialised one for alerts
function ajaxError ( xhr , status , errstr ) {
console . log ( "The AJAX request failed" ) ;
console . log ( "xhr" , xhr ) ;
console . log ( "status" , status ) ;
console . log ( "errstr" , errstr ) ;
if ( status == "parsererror" ) {
console . log ( "The server didn't respond with a valid JSON response" ) ;
}
console . trace ( ) ;
}
2017-01-31 05:13:38 +00:00
2017-10-30 09:57:08 +00:00
function postLink ( event )
2016-12-02 07:38:54 +00:00
{
event . preventDefault ( ) ;
2017-10-30 09:57:08 +00:00
let formAction = $ ( event . target ) . closest ( 'a' ) . attr ( "href" ) ;
//console.log("Form Action: " + formAction);
$ . ajax ( { url : formAction , type : "POST" , dataType : "json" , error : ajaxError , data : { js : "1" } } ) ;
2016-12-02 07:38:54 +00:00
}
2017-10-30 09:57:08 +00:00
function bindToAlerts ( ) {
2017-08-18 12:16:56 +00:00
$ ( ".alertItem.withAvatar a" ) . click ( function ( event ) {
event . stopPropagation ( ) ;
2017-10-30 09:57:08 +00:00
$ . ajax ( { url : "/api/?action=set&module=dismiss-alert" , type : "POST" , dataType : "json" , error : ajaxError , data : { asid : $ ( this ) . attr ( "data-asid" ) } } ) ;
2017-08-18 12:16:56 +00:00
} ) ;
}
2017-09-10 16:57:22 +00:00
// TODO: Add the ability for users to dismiss alerts
2017-11-06 16:24:45 +00:00
function loadAlerts ( menuAlerts )
2017-03-03 16:28:49 +00:00
{
2017-11-06 16:24:45 +00:00
var alertListNode = menuAlerts . getElementsByClassName ( "alertList" ) [ 0 ] ;
var alertCounterNode = menuAlerts . getElementsByClassName ( "alert_counter" ) [ 0 ] ;
2017-08-17 11:13:49 +00:00
alertCounterNode . textContent = "0" ;
2017-03-03 16:28:49 +00:00
$ . ajax ( {
2017-11-06 16:24:45 +00:00
type : 'get' ,
dataType : 'json' ,
url : '/api/?action=get&module=alerts' ,
success : function ( data ) {
if ( "errmsg" in data ) {
alertListNode . innerHTML = "<div class='alertItem'>" + data . errmsg + "</div>" ;
return ;
}
2017-05-29 14:52:37 +00:00
2017-11-06 16:24:45 +00:00
var alist = "" ;
for ( var i in data . msgs ) {
var msg = data . msgs [ i ] ;
var mmsg = msg . msg ;
2017-05-29 14:52:37 +00:00
2017-11-06 16:24:45 +00:00
if ( "sub" in msg ) {
for ( var i = 0 ; i < msg . sub . length ; i ++ ) {
mmsg = mmsg . replace ( "\{" + i + "\}" , msg . sub [ i ] ) ;
//console.log("Sub #" + i + ":",msg.sub[i]);
2017-03-03 16:28:49 +00:00
}
}
2017-05-29 14:52:37 +00:00
2017-11-06 16:24:45 +00:00
if ( "avatar" in msg ) {
2018-01-16 08:01:02 +00:00
alist += "<div class='alertItem withAvatar' style='background-image:url(\"" + msg . avatar + "\");'><img src='" + msg . avatar + "' class='bgsub' /><a class='text' data-asid='" + msg . asid + "' href=\"" + msg . path + "\">" + mmsg + "</a></div>" ;
alertList . push ( "<div class='alertItem withAvatar' style='background-image:url(\"" + msg . avatar + "\");'><img src='" + msg . avatar + "' class='bgsub' /><a class='text' data-asid='" + msg . asid + "' href=\"" + msg . path + "\">" + mmsg + "</a></div>" ) ;
2017-08-15 13:47:56 +00:00
} else {
2017-11-06 16:24:45 +00:00
alist += "<div class='alertItem'><a href=\"" + msg . path + "\" class='text'>" + mmsg + "</a></div>" ;
alertList . push ( "<div class='alertItem'><a href=\"" + msg . path + "\" class='text'>" + mmsg + "</a></div>" ) ;
2017-08-15 13:47:56 +00:00
}
2017-11-06 16:24:45 +00:00
//console.log(msg);
//console.log(mmsg);
}
2017-08-18 12:16:56 +00:00
2017-11-06 16:24:45 +00:00
if ( alist == "" ) alist = "<div class='alertItem'>You don't have any alerts</div>" ;
alertListNode . innerHTML = alist ;
if ( data . msgCount != 0 && data . msgCount != undefined ) {
alertCounterNode . textContent = data . msgCount ;
menuAlerts . classList . add ( "has_alerts" ) ;
} else {
menuAlerts . classList . remove ( "has_alerts" ) ;
2017-03-03 16:28:49 +00:00
}
2017-11-06 16:24:45 +00:00
alertCount = data . msgCount ;
bindToAlerts ( ) ;
} ,
error : function ( magic , theStatus , error ) {
let errtxt
try {
var data = JSON . parse ( magic . responseText ) ;
if ( "errmsg" in data ) errtxt = data . errmsg ;
else errtxt = "Unable to get the alerts" ;
} catch ( err ) {
errtxt = "Unable to get the alerts" ;
console . log ( magic . responseText ) ;
console . log ( err ) ;
}
console . log ( "error" , error ) ;
alertListNode . innerHTML = "<div class='alertItem'>" + errtxt + "</div>" ;
}
} ) ;
2017-03-03 16:28:49 +00:00
}
2017-08-15 13:47:56 +00:00
function SplitN ( data , ch , n ) {
var out = [ ] ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
if ( data . length === 0 ) return out ;
2017-08-15 13:47:56 +00:00
var lastIndex = 0 ;
var j = 0 ;
var lastN = 1 ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
for ( let i = 0 ; i < data . length ; i ++ ) {
if ( data [ i ] === ch ) {
2017-08-15 13:47:56 +00:00
out [ j ++ ] = data . substring ( lastIndex , i ) ;
lastIndex = i ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
if ( lastN === n ) break ;
2017-08-15 13:47:56 +00:00
lastN ++ ;
2017-05-11 13:04:43 +00:00
}
}
2017-08-15 13:47:56 +00:00
if ( data . length > lastIndex ) out [ out . length - 1 ] += data . substring ( lastIndex ) ;
return out ;
}
2017-05-29 14:52:37 +00:00
2017-11-06 16:24:45 +00:00
function runWebSockets ( ) {
if ( window . location . protocol == "https:" )
conn = new WebSocket ( "wss://" + document . location . host + "/ws/" ) ;
else conn = new WebSocket ( "ws://" + document . location . host + "/ws/" ) ;
2017-06-10 07:58:15 +00:00
2017-11-06 16:24:45 +00:00
conn . onopen = function ( ) {
console . log ( "The WebSockets connection was opened" ) ;
conn . send ( "page " + document . location . pathname + '\r' ) ;
// TODO: Don't ask again, if it's denied. We could have a setting in the UCP which automatically requests this when someone flips desktop notifications on
Notification . requestPermission ( ) ;
}
conn . onclose = function ( ) {
conn = false ;
console . log ( "The WebSockets connection was closed" ) ;
}
conn . onmessage = function ( event ) {
//console.log("WS_Message:", event.data);
if ( event . data [ 0 ] == "{" ) {
try {
var data = JSON . parse ( event . data ) ;
} catch ( err ) {
console . log ( err ) ;
}
2017-08-18 12:16:56 +00:00
2017-11-06 16:24:45 +00:00
if ( "msg" in data ) {
var msg = data . msg
if ( "sub" in data )
for ( var i = 0 ; i < data . sub . length ; i ++ )
msg = msg . replace ( "\{" + i + "\}" , data . sub [ i ] ) ;
if ( "avatar" in data ) alertList . push ( "<div class='alertItem withAvatar' style='background-image:url(\"" + data . avatar + "\");'><a class='text' data-asid='" + data . asid + "' href=\"" + data . path + "\">" + msg + "</a></div>" ) ;
else alertList . push ( "<div class='alertItem'><a href=\"" + data . path + "\" class='text'>" + msg + "</a></div>" ) ;
if ( alertList . length > 8 ) alertList . shift ( ) ;
//console.log("post alertList",alertList);
alertCount ++ ;
var alist = ""
for ( var i = 0 ; i < alertList . length ; i ++ ) alist += alertList [ i ] ;
//console.log(alist);
// TODO: Add support for other alert feeds like PM Alerts
var generalAlerts = document . getElementById ( "general_alerts" ) ;
var alertListNode = generalAlerts . getElementsByClassName ( "alertList" ) [ 0 ] ;
var alertCounterNode = generalAlerts . getElementsByClassName ( "alert_counter" ) [ 0 ] ;
alertListNode . innerHTML = alist ;
alertCounterNode . textContent = alertCount ;
// TODO: Add some sort of notification queue to avoid flooding the end-user with notices?
// TODO: Use the site name instead of "Something Happened"
if ( Notification . permission === "granted" ) {
var n = new Notification ( "Something Happened" , {
body : msg ,
icon : data . avatar ,
} ) ;
setTimeout ( n . close . bind ( n ) , 8000 ) ;
2017-06-10 07:58:15 +00:00
}
2017-11-06 16:24:45 +00:00
bindToAlerts ( ) ;
2017-06-10 07:58:15 +00:00
}
2017-11-06 16:24:45 +00:00
}
2017-06-10 07:58:15 +00:00
2017-11-06 16:24:45 +00:00
var messages = event . data . split ( '\r' ) ;
for ( var i = 0 ; i < messages . length ; i ++ ) {
//console.log("Message: ",messages[i]);
if ( messages [ i ] . startsWith ( "set " ) ) {
//msgblocks = messages[i].split(' ',3);
let msgblocks = SplitN ( messages [ i ] , " " , 3 ) ;
if ( msgblocks . length < 3 ) continue ;
document . querySelector ( msgblocks [ 1 ] ) . innerHTML = msgblocks [ 2 ] ;
} else if ( messages [ i ] . startsWith ( "set-class " ) ) {
let msgblocks = SplitN ( messages [ i ] , " " , 3 ) ;
if ( msgblocks . length < 3 ) continue ;
document . querySelector ( msgblocks [ 1 ] ) . className = msgblocks [ 2 ] ;
2017-05-11 13:04:43 +00:00
}
}
}
2017-11-06 16:24:45 +00:00
}
$ ( document ) . ready ( function ( ) {
if ( window [ "WebSocket" ] ) runWebSockets ( ) ;
2017-06-05 11:57:27 +00:00
else conn = false ;
2017-05-29 14:52:37 +00:00
2016-12-02 07:38:54 +00:00
$ ( ".open_edit" ) . click ( function ( event ) {
2017-08-18 15:56:36 +00:00
//console.log("clicked on .open_edit");
2016-12-02 07:38:54 +00:00
event . preventDefault ( ) ;
$ ( ".hide_on_edit" ) . hide ( ) ;
$ ( ".show_on_edit" ) . show ( ) ;
} ) ;
2017-05-29 14:52:37 +00:00
2017-01-31 05:13:38 +00:00
$ ( ".topic_item .submit_edit" ) . click ( function ( event ) {
2016-12-02 07:38:54 +00:00
event . preventDefault ( ) ;
2017-08-20 09:39:02 +00:00
//console.log("clicked on .topic_item .submit_edit");
2016-12-02 07:38:54 +00:00
$ ( ".topic_name" ) . html ( $ ( ".topic_name_input" ) . val ( ) ) ;
$ ( ".topic_content" ) . html ( $ ( ".topic_content_input" ) . val ( ) ) ;
$ ( ".topic_status_e:not(.open_edit)" ) . html ( $ ( ".topic_status_input" ) . val ( ) ) ;
2017-05-29 14:52:37 +00:00
2016-12-02 07:38:54 +00:00
$ ( ".hide_on_edit" ) . show ( ) ;
$ ( ".show_on_edit" ) . hide ( ) ;
2017-05-29 14:52:37 +00:00
2017-10-16 07:32:58 +00:00
let topicNameInput = $ ( '.topic_name_input' ) . val ( ) ;
let topicStatusInput = $ ( '.topic_status_input' ) . val ( ) ;
let topicContentInput = $ ( '.topic_content_input' ) . val ( ) ;
let formAction = this . form . getAttribute ( "action" ) ;
2017-10-21 00:27:47 +00:00
//console.log("New Topic Name: ", topicNameInput);
//console.log("New Topic Status: ", topicStatusInput);
//console.log("New Topic Content: ", topicContentInput);
//console.log("Form Action: ", formAction);
2016-12-02 07:38:54 +00:00
$ . ajax ( {
2017-10-16 07:32:58 +00:00
url : formAction ,
2017-05-29 14:52:37 +00:00
type : "POST" ,
dataType : "json" ,
2017-10-30 09:57:08 +00:00
error : ajaxError ,
2016-12-02 07:38:54 +00:00
data : {
2017-10-16 07:32:58 +00:00
topic _name : topicNameInput ,
topic _status : topicStatusInput ,
topic _content : topicContentInput ,
2016-12-02 07:38:54 +00:00
topic _js : 1
2017-05-29 14:52:37 +00:00
}
2016-12-02 07:38:54 +00:00
} ) ;
} ) ;
2017-05-29 14:52:37 +00:00
2016-12-02 07:38:54 +00:00
$ ( ".delete_item" ) . click ( function ( event )
{
2017-10-30 09:57:08 +00:00
postLink ( event ) ;
2017-10-16 07:32:58 +00:00
$ ( this ) . closest ( '.deletable_block' ) . remove ( ) ;
2016-12-02 07:38:54 +00:00
} ) ;
2017-05-29 14:52:37 +00:00
2018-01-08 08:53:51 +00:00
$ ( ".edit_item" ) . click ( function ( event ) {
2016-12-02 07:38:54 +00:00
event . preventDefault ( ) ;
2017-10-16 07:32:58 +00:00
let blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
let block = blockParent . find ( '.editable_block' ) . eq ( 0 ) ;
2016-12-03 04:50:35 +00:00
block . html ( "<textarea style='width: 99%;' name='edit_item'>" + block . html ( ) + "</textarea><br /><a href='" + $ ( this ) . closest ( 'a' ) . attr ( "href" ) + "'><button class='submit_edit' type='submit'>Update</button></a>" ) ;
2017-05-29 14:52:37 +00:00
2018-01-08 08:53:51 +00:00
$ ( ".submit_edit" ) . click ( function ( event ) {
2016-12-02 07:38:54 +00:00
event . preventDefault ( ) ;
2017-10-16 07:32:58 +00:00
let blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
let block = blockParent . find ( '.editable_block' ) . eq ( 0 ) ;
let newContent = block . find ( 'textarea' ) . eq ( 0 ) . val ( ) ;
2016-12-02 07:38:54 +00:00
block . html ( newContent ) ;
2017-05-29 14:52:37 +00:00
2017-10-16 07:32:58 +00:00
var formAction = $ ( this ) . closest ( 'a' ) . attr ( "href" ) ;
2017-10-21 00:27:47 +00:00
//console.log("Form Action:",formAction);
2017-10-30 09:57:08 +00:00
$ . ajax ( { url : formAction , type : "POST" , error : ajaxError , dataType : "json" , data : { isJs : "1" , edit _item : newContent }
2016-12-02 07:38:54 +00:00
} ) ;
} ) ;
} ) ;
2017-05-29 14:52:37 +00:00
2018-01-08 08:53:51 +00:00
$ ( "#forum_quick_perms" ) . click ( function ( ) {
$ ( ".submit_edit" ) . click ( function ( event ) {
} ) ;
} ) ;
2016-12-06 10:26:48 +00:00
$ ( ".edit_field" ) . click ( function ( event )
{
event . preventDefault ( ) ;
2017-10-16 07:32:58 +00:00
let blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
let block = blockParent . find ( '.editable_block' ) . eq ( 0 ) ;
2016-12-06 10:26:48 +00:00
block . html ( "<input name='edit_field' value='" + block . text ( ) + "' type='text'/><a href='" + $ ( this ) . closest ( 'a' ) . attr ( "href" ) + "'><button class='submit_edit' type='submit'>Update</button></a>" ) ;
2017-05-29 14:52:37 +00:00
2017-10-21 00:27:47 +00:00
$ ( ".submit_edit" ) . click ( function ( event ) {
2016-12-06 10:26:48 +00:00
event . preventDefault ( ) ;
2017-10-16 07:32:58 +00:00
let blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
let block = blockParent . find ( '.editable_block' ) . eq ( 0 ) ;
let newContent = block . find ( 'input' ) . eq ( 0 ) . val ( ) ;
2016-12-06 10:26:48 +00:00
block . html ( newContent ) ;
2017-05-29 14:52:37 +00:00
2017-10-16 07:32:58 +00:00
let formAction = $ ( this ) . closest ( 'a' ) . attr ( "href" ) ;
2017-10-21 00:27:47 +00:00
//console.log("Form Action:", formAction);
2016-12-06 10:26:48 +00:00
$ . ajax ( {
2017-10-16 07:32:58 +00:00
url : formAction + "?session=" + session ,
2016-12-06 10:26:48 +00:00
type : "POST" ,
dataType : "json" ,
2017-10-30 09:57:08 +00:00
error : ajaxError ,
2017-10-21 00:27:47 +00:00
data : { isJs : "1" , edit _item : newContent }
2016-12-06 10:26:48 +00:00
} ) ;
} ) ;
} ) ;
2017-05-29 14:52:37 +00:00
2017-01-31 05:13:38 +00:00
$ ( ".edit_fields" ) . click ( function ( event )
{
event . preventDefault ( ) ;
2017-08-27 09:33:45 +00:00
if ( $ ( this ) . find ( "input" ) . length !== 0 ) return ;
2017-05-29 14:52:37 +00:00
//console.log("clicked .edit_fields");
2017-10-30 09:57:08 +00:00
var blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
//console.log(blockParent);
blockParent . find ( '.hide_on_edit' ) . hide ( ) ;
blockParent . find ( '.show_on_edit' ) . show ( ) ;
blockParent . find ( '.editable_block' ) . show ( ) ;
blockParent . find ( '.editable_block' ) . each ( function ( ) {
var fieldName = this . getAttribute ( "data-field" ) ;
var fieldType = this . getAttribute ( "data-type" ) ;
if ( fieldType == "list" )
2017-05-29 14:52:37 +00:00
{
2017-10-30 09:57:08 +00:00
var fieldValue = this . getAttribute ( "data-value" ) ;
if ( fieldName in form _vars ) var it = form _vars [ fieldName ] ;
2017-01-31 05:13:38 +00:00
else var it = [ 'No' , 'Yes' ] ;
var itLen = it . length ;
var out = "" ;
2017-10-30 09:57:08 +00:00
//console.log("Field Name:",fieldName);
//console.log("Field Type:",fieldType);
//console.log("Field Value:",fieldValue);
2017-06-05 11:57:27 +00:00
for ( var i = 0 ; i < itLen ; i ++ ) {
2017-09-25 00:48:35 +00:00
var sel = "" ;
2017-10-30 09:57:08 +00:00
if ( fieldValue == i || fieldValue == it [ i ] ) {
2017-05-29 14:52:37 +00:00
sel = "selected " ;
2017-10-30 09:57:08 +00:00
this . classList . remove ( fieldName + '_' + it [ i ] ) ;
2017-05-29 14:52:37 +00:00
this . innerHTML = "" ;
2017-09-25 00:48:35 +00:00
}
2017-01-31 05:13:38 +00:00
out += "<option " + sel + "value='" + i + "'>" + it [ i ] + "</option>" ;
}
2017-10-30 09:57:08 +00:00
this . innerHTML = "<select data-field='" + fieldName + "' name='" + fieldName + "'>" + out + "</select>" ;
2017-01-31 05:13:38 +00:00
}
2017-10-30 09:57:08 +00:00
else if ( fieldType == "hidden" ) { }
else this . innerHTML = "<input name='" + fieldName + "' value='" + this . textContent + "' type='text'/>" ;
2017-01-31 05:13:38 +00:00
} ) ;
2017-05-29 14:52:37 +00:00
// Remove any handlers already attached to the submitter
$ ( ".submit_edit" ) . unbind ( "click" ) ;
2017-01-31 05:13:38 +00:00
$ ( ".submit_edit" ) . click ( function ( event )
{
event . preventDefault ( ) ;
2017-05-29 14:52:37 +00:00
//console.log("running .submit_edit event");
2017-10-30 09:57:08 +00:00
var outData = { isJs : "1" }
var blockParent = $ ( this ) . closest ( '.editable_parent' ) ;
blockParent . find ( '.editable_block' ) . each ( function ( ) {
var fieldName = this . getAttribute ( "data-field" ) ;
var fieldType = this . getAttribute ( "data-type" ) ;
if ( fieldType == "list" ) {
2017-05-29 14:52:37 +00:00
var newContent = $ ( this ) . find ( 'select :selected' ) . text ( ) ;
2017-10-30 09:57:08 +00:00
this . classList . add ( fieldName + '_' + newContent ) ;
2017-05-29 14:52:37 +00:00
this . innerHTML = "" ;
2017-10-30 09:57:08 +00:00
} else if ( fieldType == "hidden" ) {
2017-06-05 11:57:27 +00:00
var newContent = $ ( this ) . val ( ) ;
2017-05-29 14:52:37 +00:00
} else {
var newContent = $ ( this ) . find ( 'input' ) . eq ( 0 ) . val ( ) ;
this . innerHTML = newContent ;
}
this . setAttribute ( "data-value" , newContent ) ;
2017-10-30 09:57:08 +00:00
outData [ fieldName ] = newContent ;
2017-01-31 05:13:38 +00:00
} ) ;
2017-05-29 14:52:37 +00:00
2017-10-30 09:57:08 +00:00
var formAction = $ ( this ) . closest ( 'a' ) . attr ( "href" ) ;
//console.log("Form Action:", formAction);
//console.log(outData);
$ . ajax ( { url : formAction + "?session=" + session , type : "POST" , dataType : "json" , data : outData , error : ajaxError } ) ;
blockParent . find ( '.hide_on_edit' ) . show ( ) ;
blockParent . find ( '.show_on_edit' ) . hide ( ) ;
2017-01-31 05:13:38 +00:00
} ) ;
} ) ;
2017-05-29 14:52:37 +00:00
2017-08-18 12:16:56 +00:00
// This one's for Tempra Conflux
2017-09-10 16:57:22 +00:00
// TODO: We might want to use pure JS here
2017-02-16 06:47:55 +00:00
$ ( ".ip_item" ) . each ( function ( ) {
var ip = this . textContent ;
2017-01-17 07:55:46 +00:00
if ( ip . length > 10 ) {
2017-02-16 06:47:55 +00:00
this . innerHTML = "Show IP" ;
2017-10-30 09:57:08 +00:00
this . onclick = function ( event ) {
2017-01-17 07:55:46 +00:00
event . preventDefault ( ) ;
2017-02-16 06:47:55 +00:00
this . textContent = ip ;
} ;
2017-01-17 07:55:46 +00:00
}
} ) ;
2017-05-29 14:52:37 +00:00
2017-03-05 07:53:41 +00:00
$ ( this ) . click ( function ( ) {
2017-03-03 16:28:49 +00:00
$ ( ".selectedAlert" ) . removeClass ( "selectedAlert" ) ;
2017-06-05 11:57:27 +00:00
$ ( "#back" ) . removeClass ( "alertActive" ) ;
} ) ;
$ ( ".alert_bell" ) . click ( function ( ) {
2017-10-30 09:57:08 +00:00
var menuAlerts = $ ( this ) . parent ( ) ;
if ( menuAlerts . hasClass ( "selectedAlert" ) ) {
2017-06-05 11:57:27 +00:00
event . stopPropagation ( ) ;
2017-10-30 09:57:08 +00:00
menuAlerts . removeClass ( "selectedAlert" ) ;
2017-06-05 11:57:27 +00:00
$ ( "#back" ) . removeClass ( "alertActive" ) ;
}
2017-03-03 16:28:49 +00:00
} ) ;
2017-05-29 14:52:37 +00:00
2017-10-30 09:57:08 +00:00
var alertMenuList = document . getElementsByClassName ( "menu_alerts" ) ;
for ( var i = 0 ; i < alertMenuList . length ; i ++ ) {
loadAlerts ( alertMenuList [ i ] ) ;
2017-08-15 13:47:56 +00:00
}
2017-05-29 14:52:37 +00:00
2017-03-01 11:36:50 +00:00
$ ( ".menu_alerts" ) . click ( function ( event ) {
2017-03-03 16:28:49 +00:00
event . stopPropagation ( ) ;
2017-03-01 11:36:50 +00:00
if ( $ ( this ) . hasClass ( "selectedAlert" ) ) return ;
2017-10-30 09:57:08 +00:00
if ( ! conn ) loadAlerts ( this ) ;
2017-06-05 11:57:27 +00:00
this . className += " selectedAlert" ;
document . getElementById ( "back" ) . className += " alertActive"
2017-03-01 11:36:50 +00:00
} ) ;
2017-05-29 14:52:37 +00:00
2017-06-16 10:41:30 +00:00
$ ( "input,textarea,select,option" ) . keyup ( function ( event ) {
event . stopPropagation ( ) ;
} )
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
$ ( ".create_topic_link" ) . click ( function ( event ) {
event . preventDefault ( ) ;
$ ( ".topic_create_form" ) . show ( ) ;
} ) ;
$ ( ".topic_create_form .close_form" ) . click ( function ( ) {
event . preventDefault ( ) ;
$ ( ".topic_create_form" ) . hide ( ) ;
} ) ;
function uploadFileHandler ( ) {
var fileList = this . files ;
// Truncate the number of files to 5
let files = [ ] ;
for ( var i = 0 ; i < fileList . length && i < 5 ; i ++ )
files [ i ] = fileList [ i ] ;
// Iterate over the files
for ( let i = 0 ; i < files . length ; i ++ ) {
console . log ( "files[" + i + "]" , files [ i ] ) ;
let reader = new FileReader ( ) ;
reader . onload = function ( e ) {
var fileDock = document . getElementById ( "upload_file_dock" ) ;
var fileItem = document . createElement ( "label" ) ;
console . log ( "fileItem" , fileItem ) ;
if ( ! files [ i ] [ "name" ] . indexOf ( '.' > - 1 ) ) {
// TODO: Surely, there's a prettier and more elegant way of doing this?
alert ( "This file doesn't have an extension" ) ;
return ;
}
var ext = files [ i ] [ "name" ] . split ( '.' ) . pop ( ) ;
fileItem . innerText = "." + ext ;
fileItem . className = "formbutton uploadItem" ;
fileItem . style . backgroundImage = "url(" + e . target . result + ")" ;
fileDock . appendChild ( fileItem ) ;
let reader = new FileReader ( ) ;
reader . onload = function ( e ) {
crypto . subtle . digest ( 'SHA-256' , e . target . result ) . then ( function ( hash ) {
const hashArray = Array . from ( new Uint8Array ( hash ) )
return hashArray . map ( b => ( '00' + b . toString ( 16 ) ) . slice ( - 2 ) ) . join ( '' )
} ) . then ( function ( hash ) {
console . log ( "hash" , hash ) ;
2017-10-12 03:24:14 +00:00
let content = document . getElementById ( "input_content" )
2017-10-30 09:57:08 +00:00
console . log ( "content.value" , content . value ) ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
2017-10-30 09:57:08 +00:00
let attachItem ;
if ( content . value == "" ) attachItem = "//" + siteURL + "/attachs/" + hash + "." + ext ;
else attachItem = "\r\n//" + siteURL + "/attachs/" + hash + "." + ext ;
content . value = content . value + attachItem ;
console . log ( "content.value" , content . value ) ;
// For custom / third party text editors
attachItemCallback ( attachItem ) ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
} ) ;
}
reader . readAsArrayBuffer ( files [ i ] ) ;
}
reader . readAsDataURL ( files [ i ] ) ;
}
}
2017-10-12 03:24:14 +00:00
var uploadFiles = document . getElementById ( "upload_files" ) ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
if ( uploadFiles != null ) {
uploadFiles . addEventListener ( "change" , uploadFileHandler , false ) ;
}
2017-10-30 09:57:08 +00:00
$ ( ".moderate_link" ) . click ( function ( event ) {
event . preventDefault ( ) ;
$ ( ".pre_opt" ) . removeClass ( "auto_hide" ) ;
$ ( ".topic_row" ) . each ( function ( ) {
$ ( this ) . click ( function ( ) {
selectedTopics . push ( parseInt ( $ ( this ) . attr ( "data-tid" ) , 10 ) ) ;
if ( selectedTopics . length == 1 ) {
$ ( ".mod_floater_head span" ) . html ( "What do you want to do with this topic?" ) ;
} else {
$ ( ".mod_floater_head span" ) . html ( "What do you want to do with these " + selectedTopics . length + " topics?" ) ;
}
$ ( this ) . addClass ( "topic_selected" ) ;
$ ( ".mod_floater" ) . removeClass ( "auto_hide" ) ;
} ) ;
} ) ;
2018-01-14 12:03:20 +00:00
2018-01-15 08:24:18 +00:00
let bulkActionSender = function ( action , selectedTopics , fragBit ) {
let url = "/topic/" + action + "/submit/" + fragBit + "?session=" + session ;
2018-01-14 12:03:20 +00:00
$ . ajax ( {
url : url ,
type : "POST" ,
data : JSON . stringify ( selectedTopics ) ,
contentType : "application/json" ,
error : ajaxError ,
success : function ( ) {
window . location . reload ( ) ;
}
} ) ;
} ;
2017-10-30 09:57:08 +00:00
$ ( ".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" ) ;
//console.log("action",action);
2018-01-11 08:03:17 +00:00
// Handle these specially
switch ( action ) {
case "move" :
console . log ( "move action" ) ;
2018-01-14 12:03:20 +00:00
let modTopicMover = $ ( "#mod_topic_mover" ) ;
2018-01-11 08:03:17 +00:00
$ ( "#mod_topic_mover" ) . removeClass ( "auto_hide" ) ;
2018-01-14 12:03:20 +00:00
$ ( "#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 ) ;
2018-01-15 08:24:18 +00:00
forumToMoveTo = fid ;
$ ( "#mover_submit" ) . click ( function ( event ) {
event . preventDefault ( ) ;
bulkActionSender ( "move" , selectedTopics , forumToMoveTo ) ;
} ) ;
2018-01-14 12:03:20 +00:00
} ) ;
2018-01-11 08:03:17 +00:00
return ;
}
2017-10-30 09:57:08 +00:00
2018-01-15 08:24:18 +00:00
bulkActionSender ( action , selectedTopics , "" ) ;
2017-10-30 09:57:08 +00:00
} ) ;
} ) ;
Added Quick Topic.
Added Attachments.
Added Attachment Media Embeds.
Renamed a load of *Store and *Cache methods to reduce the amount of unneccesary typing.
Added petabytes as a unit and cleaned up a few of the friendly units.
Refactored the username change logic to make it easier to maintain.
Refactored the avatar change logic to make it easier to maintain.
Shadow now uses CSS Variables for most of it's colours. We have plans to transpile this to support older browsers later on!
Snuck some CSS Variables into Tempra Conflux.
Added the GroupCache interface to MemoryGroupStore.
Added the Length method to MemoryGroupStore.
Added support for a site short name.
Added the UploadFiles permission.
Renamed more functions.
Fixed the background for the left gutter on the postbit for Tempra Simple and Shadow.
Added support for if statements operating on int8, int16, int32, int32, int64, uint, uint8, uint16, uint32, uint64, float32, and float64 for the template compiler.
Added support for if statements operating on slices and maps for the template compiler.
Fixed a security exploit in reply editing.
Fixed a bug in the URL detector in the parser where it couldn't find URLs with non-standard ports.
Fixed buttons having blue outlines on focus on Shadow.
Refactored the topic creation logic to make it easier to maintain.
Made a few responsive fixes, but there's still more to do in the following commits!
2017-10-05 10:20:28 +00:00
2017-09-10 16:57:22 +00:00
$ ( "#themeSelectorSelect" ) . change ( function ( ) {
console . log ( "Changing the theme to " + this . options [ this . selectedIndex ] . getAttribute ( "val" ) ) ;
$ . ajax ( {
url : this . form . getAttribute ( "action" ) + "?session=" + session ,
type : "POST" ,
dataType : "json" ,
data : { "newTheme" : this . options [ this . selectedIndex ] . getAttribute ( "val" ) , isJs : "1" } ,
2017-10-30 09:57:08 +00:00
error : ajaxError ,
2017-09-10 16:57:22 +00:00
success : function ( data , status , xhr ) {
console . log ( "Theme successfully switched" ) ;
2017-10-30 09:57:08 +00:00
console . log ( "data" , data ) ;
console . log ( "status" , status ) ;
console . log ( "xhr" , xhr ) ;
2017-09-10 16:57:22 +00:00
window . location . reload ( ) ;
}
} ) ;
} ) ;
2018-01-08 08:53:51 +00:00
// The time range selector for the time graphs in the Control Panel
$ ( ".timeRangeSelector" ) . change ( function ( ) {
console . log ( "Changed the time range to " + this . options [ this . selectedIndex ] . getAttribute ( "val" ) ) ;
window . location = this . form . getAttribute ( "action" ) + "?timeRange=" + this . options [ this . selectedIndex ] . getAttribute ( "val" ) ; // Do a redirect as a form submission refuses to work properly
} ) ;
2018-01-10 03:32:48 +00:00
$ ( ".unix_to_24_hour_time" ) . each ( function ( ) {
let unixTime = this . innerText ;
let date = new Date ( unixTime * 1000 ) ;
console . log ( "date: " , date ) ;
let minutes = "0" + date . getMinutes ( ) ;
let formattedTime = date . getHours ( ) + ":" + minutes . substr ( - 2 ) ;
console . log ( "formattedTime:" , formattedTime ) ;
this . innerText = formattedTime ;
} ) ;
2017-06-16 10:41:30 +00:00
this . onkeyup = function ( event ) {
2017-02-16 06:47:55 +00:00
if ( event . which == 37 ) this . querySelectorAll ( "#prevFloat a" ) [ 0 ] . click ( ) ;
if ( event . which == 39 ) this . querySelectorAll ( "#nextFloat a" ) [ 0 ] . click ( ) ;
} ;
2018-01-08 08:53:51 +00:00
2017-05-29 14:52:37 +00:00
} ) ;