You now get an alert when someone replies to one of your topics.

Greatly improved the Alert CSS for every theme.
Fixed a bug where alerts aren't closed when the page is extremely short and you click outside it's bounds.
Fixed a bug where liking a topic didn't reload the cached data.
Fixed a few misnamed HTML tags.
This commit is contained in:
Azareal 2017-03-05 07:53:41 +00:00
parent c7d058fe90
commit 905a51d294
11 changed files with 118 additions and 59 deletions

View File

@ -138,7 +138,7 @@ CREATE TABLE `activity_subscriptions`(
`user` int not null, `user` int not null,
`targetID` int not null, /* the ID of the element being acted upon */ `targetID` int not null, /* the ID of the element being acted upon */
`targetType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */ `targetType` varchar(50) not null, /* topic, post (calling it post here to differentiate it from the 'reply' event), forum, user */
`level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies, 2: Everyone*/ `level` tinyint DEFAULT 0 not null /* 0: Mentions (aka the global default for any post), 1: Replies To You, 2: All Replies*/
); );
CREATE TABLE `settings`( CREATE TABLE `settings`(

View File

@ -36,6 +36,7 @@ var add_likes_to_reply_stmt *sql.Stmt
var add_activity_stmt *sql.Stmt var add_activity_stmt *sql.Stmt
var notify_watchers_stmt *sql.Stmt var notify_watchers_stmt *sql.Stmt
var notify_one_stmt *sql.Stmt var notify_one_stmt *sql.Stmt
var add_subscription_stmt *sql.Stmt
var edit_topic_stmt *sql.Stmt var edit_topic_stmt *sql.Stmt
var edit_reply_stmt *sql.Stmt var edit_reply_stmt *sql.Stmt
var delete_reply_stmt *sql.Stmt var delete_reply_stmt *sql.Stmt
@ -248,7 +249,7 @@ func init_database(err error) {
} }
log.Print("Preparing notify_watchers statement.") log.Print("Preparing notify_watchers statement.")
notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, ? AS asid FROM activity_subscriptions LEFT JOIN activity_stream ON activity_subscriptions.targetType=activity_stream.elementType and activity_subscriptions.targetID=activity_stream.elementID") notify_watchers_stmt, err = db.Prepare("INSERT INTO activity_stream_matches(watcher, asid) SELECT activity_subscriptions.user, activity_stream.asid FROM activity_stream INNER JOIN activity_subscriptions ON activity_subscriptions.targetType = activity_stream.elementType and activity_subscriptions.targetID = activity_stream.elementID and activity_subscriptions.user != activity_stream.actor where asid = ?")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -259,6 +260,12 @@ func init_database(err error) {
log.Fatal(err) log.Fatal(err)
} }
log.Print("Preparing add_subscription statement.")
add_subscription_stmt, err = db.Prepare("INSERT INTO activity_subscriptions(user,targetID,targetType,level) VALUES(?,?,?,2)")
if err != nil {
log.Fatal(err)
}
log.Print("Preparing edit_topic statement.") log.Print("Preparing edit_topic statement.")
edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?") edit_topic_stmt, err = db.Prepare("UPDATE topics SET title = ?, content = ?, parsed_content = ?, is_closed = ? WHERE tid = ?")
if err != nil { if err != nil {
@ -296,7 +303,7 @@ func init_database(err error) {
} }
log.Print("Preparing get_activity_feed_by_watcher statement.") log.Print("Preparing get_activity_feed_by_watcher statement.")
get_activity_feed_by_watcher_stmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` LEFT JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid WHERE `watcher` = ?") get_activity_feed_by_watcher_stmt, err = db.Prepare("SELECT activity_stream_matches.asid, activity_stream.actor, activity_stream.targetUser, activity_stream.event, activity_stream.elementType, activity_stream.elementID FROM `activity_stream_matches` INNER JOIN `activity_stream` ON activity_stream_matches.asid = activity_stream.asid AND activity_stream_matches.watcher != activity_stream.actor WHERE `watcher` = ?")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -226,7 +226,7 @@ $(document).ready(function(){
} }
}); });
$('body').click(function() { $(this).click(function() {
$(".selectedAlert").removeClass("selectedAlert"); $(".selectedAlert").removeClass("selectedAlert");
}); });

View File

@ -639,7 +639,13 @@ func route_create_topic(w http.ResponseWriter, r *http.Request) {
forums[fid].LastReplyerID = user.ID forums[fid].LastReplyerID = user.ID
forums[fid].LastTopicTime = "" forums[fid].LastTopicTime = ""
http.Redirect(w, r, "/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther) _, err = add_subscription_stmt.Exec(user.ID,lastId,"topic")
if err != nil {
InternalError(err,w,r)
return
}
http.Redirect(w,r,"/topic/" + strconv.FormatInt(lastId,10), http.StatusSeeOther)
err = increase_post_user_stats(wcount,user.ID,true,user) err = increase_post_user_stats(wcount,user.ID,true,user)
if err != nil { if err != nil {
InternalError(err,w,r) InternalError(err,w,r)
@ -661,7 +667,8 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
var topic_name string var topic_name string
var fid int var fid int
err = db.QueryRow("select title, parentID from topics where tid = ?",tid).Scan(&topic_name,&fid) var createdBy int
err = db.QueryRow("select title, parentID, createdBy from topics where tid = ?",tid).Scan(&topic_name,&fid,&createdBy)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
PreError("Couldn't find the parent topic",w,r) PreError("Couldn't find the parent topic",w,r)
return return
@ -704,7 +711,24 @@ func route_create_reply(w http.ResponseWriter, r *http.Request) {
return return
} }
http.Redirect(w,r, "/topic/" + strconv.Itoa(tid), http.StatusSeeOther) res, err := add_activity_stmt.Exec(user.ID,createdBy,"reply","topic",tid)
if err != nil {
InternalError(err,w,r)
return
}
lastId, err := res.LastInsertId()
if err != nil {
InternalError(err,w,r)
return
}
_, err = notify_watchers_stmt.Exec(lastId)
if err != nil {
InternalError(err,w,r)
return
}
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid), http.StatusSeeOther)
err = increase_post_user_stats(wcount, user.ID, false, user) err = increase_post_user_stats(wcount, user.ID, false, user)
if err != nil { if err != nil {
InternalError(err,w,r) InternalError(err,w,r)
@ -800,6 +824,16 @@ func route_like_topic(w http.ResponseWriter, r *http.Request) {
return return
} }
// Reload the topic...
err = topics.Load(tid)
if err != nil && err != sql.ErrNoRows {
LocalError("The liked topic no longer exists",w,r,user)
return
} else if err != nil {
InternalError(err,w,r)
return
}
http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther) http.Redirect(w,r,"/topic/" + strconv.Itoa(tid),http.StatusSeeOther)
} }
@ -1756,6 +1790,8 @@ func route_api(w http.ResponseWriter, r *http.Request) {
"{x}{liked}{your post on}{user}{'s profile}" todo "{x}{liked}{your post on}{user}{'s profile}" todo
"{x}{liked}{your post in}{topic}" "{x}{liked}{your post in}{topic}"
"{x}{replied to}{your post in}{topic}" todo "{x}{replied to}{your post in}{topic}" todo
"{x}{replied to}{topic}"
"{x}{replied to}{your topic}{topic}"
"{x}{created a new topic}{topic}" "{x}{created a new topic}{topic}"
*/ */
@ -1789,6 +1825,7 @@ func route_api(w http.ResponseWriter, r *http.Request) {
} }
url = build_topic_url(elementID) url = build_topic_url(elementID)
area = topic.Title area = topic.Title
if targetUser_id == user.ID { if targetUser_id == user.ID {
post_act = " your topic" post_act = " your topic"
} }
@ -1816,23 +1853,25 @@ func route_api(w http.ResponseWriter, r *http.Request) {
LocalErrorJS("Invalid elementType",w,r) LocalErrorJS("Invalid elementType",w,r)
} }
if event == "like" { switch(event) {
if elementType == "user" { case "like":
act = "likes" if elementType == "user" {
end_frag = "" act = "likes"
if targetUser.ID == user.ID { end_frag = ""
area = "you" if targetUser.ID == user.ID {
area = "you"
}
} else {
act = "liked"
} }
} else { case "mention":
act = "liked" if elementType == "user" {
} act = "mentioned you on"
} else if event == "mention" { } else {
if elementType == "user" { act = "mentioned you in"
act = "mentioned you on" post_act = ""
} else { }
act = "mentioned you in" case "reply": act = "replied to"
post_act = ""
}
} }
msglist += `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `"},` msglist += `{"msg":"{0} ` + start_frag + act + post_act + ` {1}` + end_frag + `","sub":["` + actor.Name + `","` + area + `"],"path":"` + url + `","avatar":"` + actor.Avatar + `"},`

View File

@ -15,7 +15,7 @@
<div class="formitem"><input name="account-avatar" type="file" /></div> <div class="formitem"><input name="account-avatar" type="file" /></div>
</div> </div>
<div class="formrow"> <div class="formrow">
<div class="formitem"><button name="account-button" class="formbutton">Update</div></div> <div class="formitem"><button name="account-button" class="formbutton">Update</button></div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -14,7 +14,7 @@
<div class="formitem"><input name="account-new-username" type="text" /></div> <div class="formitem"><input name="account-new-username" type="text" /></div>
</div> </div>
<div class="formrow"> <div class="formrow">
<div class="formitem"><button name="account-button" class="formbutton">Update</div></div> <div class="formitem"><button name="account-button" class="formbutton">Update</button></div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -18,7 +18,7 @@
<div class="formitem"><input name="account-confirm-password" type="password" placeholder="*****" /></div> <div class="formitem"><input name="account-confirm-password" type="password" placeholder="*****" /></div>
</div> </div>
<div class="formrow"> <div class="formrow">
<div class="formitem"><button name="account-button" class="formbutton">Update</div></div> <div class="formitem"><button name="account-button" class="formbutton">Update</button></div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -18,7 +18,7 @@
<div class="formitem"><textarea name="topic-content" placeholder="Insert content here"></textarea></div> <div class="formitem"><textarea name="topic-content" placeholder="Insert content here"></textarea></div>
</div> </div>
<div class="formrow"> <div class="formrow">
<div class="formitem"><button name="topic-button" class="formbutton">Create Topic</div></div> <div class="formitem"><button name="topic-button" class="formbutton">Create Topic</button></div>
</div> </div>
</form> </form>
</div> </div>

View File

@ -117,6 +117,10 @@ li:hover
.selectedAlert:hover { .selectedAlert:hover {
background: white; background: white;
color: black; color: black;
font-weight: bold;
}
.selectedAlert .alert_counter {
display: none;
} }
.menu_alerts .alertList { .menu_alerts .alertList {
display: none; display: none;
@ -128,7 +132,7 @@ li:hover
background: white; background: white;
font-size: 10px; font-size: 10px;
line-height: 16px; line-height: 16px;
width: 135px; width: 156px;
right: -15px; right: -15px;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
border-left: 1px solid #ccc; border-left: 1px solid #ccc;
@ -141,21 +145,25 @@ li:hover
} }
.alertItem.withAvatar { .alertItem.withAvatar {
/*background-image: url('/uploads/avatar_1.jpg');*/ /*background-image: url('/uploads/avatar_1.jpg');*/
background-size: auto 56px; background-size: 36px;
background-repeat: no-repeat; background-repeat: no-repeat;
text-align: right; text-align: center;
padding-right: 12px; padding-right: 12px;
padding-left: 42px;
height: 46px; height: 46px;
} }
.alertItem.withAvatar:not(:last-child) { .alertItem.withAvatar:not(:last-child) {
border-bottom: 1px solid rgb(230,230,230); border-bottom: 1px solid rgb(230,230,230);
} }
.alertItem.withAvatar .text { .alertItem .text {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
float: right;
width: calc(100% - 20px);
height: 30px; height: 30px;
width: 100%;
color: black;
}
.alertItem .text.smaller {
font-size: 9px;
} }
#footer #footer

View File

@ -89,22 +89,28 @@ li a
.selectedAlert:hover { .selectedAlert:hover {
background: white; background: white;
color: black; color: black;
font-weight: bold;
}
.selectedAlert .alert_counter {
display: none;
} }
.menu_alerts .alertList { .menu_alerts .alertList {
display: none; display: none;
text-transform: none;
} }
.selectedAlert .alertList { .selectedAlert .alertList {
position: absolute; position: absolute;
top: 41px; top: 43px;
display: block; display: block;
background: white; background: white;
font-size: 10px; font-size: 10px;
line-height: 16px; line-height: 16px;
width: 135px; width: 156px;
right: -15px; right: calc(5% + 7px);
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
border-left: 1px solid #ccc; border-left: 1px solid #ccc;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
} }
.alertItem { .alertItem {
padding: 8px; padding: 8px;
@ -113,21 +119,25 @@ li a
} }
.alertItem.withAvatar { .alertItem.withAvatar {
/*background-image: url('/uploads/avatar_1.jpg');*/ /*background-image: url('/uploads/avatar_1.jpg');*/
background-size: auto 56px; background-size: 36px;
background-repeat: no-repeat; background-repeat: no-repeat;
text-align: right; text-align: center;
padding-right: 12px; padding-right: 12px;
padding-left: 42px;
height: 46px; height: 46px;
} }
.alertItem.withAvatar:not(:last-child) { .alertItem.withAvatar:not(:last-child) {
border-bottom: 1px solid rgb(230,230,230); border-bottom: 1px solid rgb(230,230,230);
} }
.alertItem.withAvatar .text { .alertItem .text {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
float: right;
width: calc(100% - 20px);
height: 30px; height: 30px;
width: 100%;
color: black;
}
.alertItem .text.smaller {
font-size: 9px;
} }
.container .container
@ -514,17 +524,13 @@ button.username
/* Media Queries from Simple. Probably useless in Conflux */ /* Media Queries from Simple. Probably useless in Conflux */
@media (max-width: 880px) { @media (max-width: 880px) {
li li { height: 25px; font-size: 15px; padding-left: 7px; }
{
height: 25px;
font-size: 15px;
padding-left: 7px;
}
ul { height: 26px; margin-top: 8px; } ul { height: 26px; margin-top: 8px; }
.menu_left { padding-right: 7px; } .menu_left { padding-right: 7px; }
.menu_right { padding-right: 7px; } .menu_right { padding-right: 7px; }
body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; } body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; }
.container { width: auto; } .container { width: auto; }
.selectedAlert .alertList { top: 33px; right: 4px; }
} }
@media (max-width: 810px) { @media (max-width: 810px) {
@ -547,7 +553,8 @@ button.username
ul { height: 24px; } ul { height: 24px; }
.menu_left { padding-right: 5px; } .menu_left { padding-right: 5px; }
.menu_right { padding-right: 5px; } .menu_right { padding-right: 5px; }
.menu_create_topic { display: none;} .menu_create_topic { display: none; }
.menu_alerts { padding-left: 4px; padding-right: 4px; }
.hide_on_mobile { display: none; } .hide_on_mobile { display: none; }
.prev_button, .next_button { top: auto;bottom: 5px; } .prev_button, .next_button { top: auto;bottom: 5px; }
} }

View File

@ -90,19 +90,21 @@ li a
} }
.menu_alerts .alertList { .menu_alerts .alertList {
display: none; display: none;
text-transform: none;
} }
.selectedAlert .alertList { .selectedAlert .alertList {
position: absolute; position: absolute;
top: 41px; top: 43px;
display: block; display: block;
background: white; background: white;
font-size: 10px; font-size: 10px;
line-height: 16px; line-height: 16px;
width: 135px; width: 135px;
right: -15px; right: calc(5% + 7px);
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
border-left: 1px solid #ccc; border-left: 1px solid #ccc;
border-right: 1px solid #ccc; border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
} }
.alertItem { .alertItem {
padding: 8px; padding: 8px;
@ -110,7 +112,6 @@ li a
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.alertItem.withAvatar { .alertItem.withAvatar {
/*background-image: url('/uploads/avatar_1.jpg');*/
background-size: auto 56px; background-size: auto 56px;
background-repeat: no-repeat; background-repeat: no-repeat;
text-align: right; text-align: right;
@ -231,7 +232,7 @@ li a
background-color: white; background-color: white;
} }
/*Clearfix*/ /* Clearfix */
.formrow:before, .formrow:after { .formrow:before, .formrow:after {
content: " "; content: " ";
display: table; display: table;
@ -390,17 +391,13 @@ button.username
.next_button { right: 14px; } .next_button { right: 14px; }
@media (max-width: 880px) { @media (max-width: 880px) {
li li { height: 25px; font-size: 15px; padding-left: 7px; }
{
height: 25px;
font-size: 15px;
padding-left: 7px;
}
ul { height: 26px; margin-top: 8px; } ul { height: 26px; margin-top: 8px; }
.menu_left { padding-right: 7px; } .menu_left { padding-right: 7px; }
.menu_right { padding-right: 7px; } .menu_right { padding-right: 7px; }
body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; } body { padding-left: 4px; padding-right: 4px; margin: 0px !important; width: 100% !important; height: 100% !important; overflow-x: hidden; }
.container { width: auto; } .container { width: auto; }
.selectedAlert .alertList { top: 33px; right: 4px; }
} }
@media (max-width: 810px) { @media (max-width: 810px) {
@ -424,8 +421,9 @@ button.username
.menu_left { padding-right: 5px; } .menu_left { padding-right: 5px; }
.menu_right { padding-right: 5px; } .menu_right { padding-right: 5px; }
.menu_create_topic { display: none;} .menu_create_topic { display: none;}
.menu_alerts { padding-left: 4px; padding-right: 4px; }
.hide_on_mobile { display: none; } .hide_on_mobile { display: none; }
.prev_button, .next_button { top: auto;bottom: 5px; } .prev_button, .next_button { top: auto; bottom: 5px; }
} }
@media (max-width: 470px) { @media (max-width: 470px) {