home ยป zplus/freepost.git
Author zPlus <-> 2016-03-18 14:46:20
Committer zPlus <-> 2016-03-18 14:46:20
Commit 1c0c257 (patch)
Tree 79c1e62
Parent(s)

Fix votes


commits diff: b54f3df..1c0c257
12 files changed, 620 insertions, 123 deletions โ€” download


Diffstat
-rwxr-xr-x .htaccess 3
-rw-r--r-- css/freepost.css 87
-rw-r--r-- database.php 371
-rwxr-xr-x images/downvote.png 0
-rwxr-xr-x images/upvote.png 0
-rw-r--r-- javascript/freepost.js 56
-rw-r--r-- post.php 15
-rw-r--r-- template/comment.twig 62
-rw-r--r-- template/index.twig 60
-rw-r--r-- template/post.twig 56
-rw-r--r-- template/vote.twig 21
-rw-r--r-- vote.php 12

Diff options
View
Side
Whitespace
Context lines
Inter-hunk lines
+3/-0 M   .htaccess
index 56fbae3..eb39e68
old size: 1K - new size: 1K
@@ -16,6 +16,9 @@
16 16 # Redirect /new to index.php
17 17 RewriteRule ^new$ index.php?new [NC,L,QSA]
18 18
19 + # For votes from post/...
20 + RewriteRule post/vote$ vote.php [NC,L,QSA]
21 +
19 22 # Show a post's page
20 23 RewriteRule post/(.+)$ post.php?hash_id=$1 [NC,L,QSA]
21 24

+62/-25 M   css/freepost.css
index cd55ac8..9bac743
old size: 8K - new size: 8K
@@ -69,40 +69,69 @@ html, body
69 69 line-height: 1.5em;
70 70 }
71 71
72 - /* Home page */
73 - .content table.posts
72 + .content .vote
74 73 {
74 + margin: 0 1.5em 0 0;
75 75 }
76 -
77 - .content table.posts .bump
76 +
77 + .content .vote > a
78 78 {
79 - color: #888;
79 + display: inline-block;
80 + margin: 0;
81 + overflow: hidden;
82 + padding: 0;
83 + text-decoration: none;
84 + vertical-align: middle;
85 + }
86 +
87 + .content .vote img {
80 88 cursor: pointer;
81 - font-size: 1.5em;
82 - font-weight: bold;
83 - padding: 0 0 1em 0;
84 - vertical-align: top;
89 + height: 1em;
90 + margin: 0;
91 + padding: .2em;
92 + float: left;
85 93 }
86 94
87 - .content table.posts .bump > a,
88 - .content table.posts .bump > a:hover
89 - {
90 - color: #AAA;
91 - text-decoration: none;
92 - }
95 + .content .vote .upvoted
96 + {
97 + background-color: #fff;
98 + border: 1px solid #00E313;
99 + border-radius: 999em;
100 + }
101 +
102 + .content .vote .downvoted
103 + {
104 + background-color: #fff;
105 + border: 1px solid #FF0000;
106 + border-radius: 999em;
107 + }
93 108
94 - .content table.posts .post
109 + .content .vote .count {
110 + margin: 0 .5em;
111 + }
112 +
113 + /* Home page */
114 + .content .posts
115 + {
116 + }
117 +
118 + .content .posts .post
95 119 {
96 - padding: 0 0 1em 1em;
120 + margin: 0 0 2em 0;
97 121 vertical-align: top;
98 122 }
99 123
100 - .content table.posts .post > .title
124 + .content .posts .post > .title
101 125 {
102 126 font-size: 1.5em;
103 127 }
104 128
105 - .content table.posts .post > .info
129 + .content .posts .post > .title > a
130 + {
131 + color: #000;
132 + }
133 +
134 + .content .posts .post > .info
106 135 {
107 136 color: #666;
108 137 }
@@ -161,20 +190,28 @@ html, body
161 190 {
162 191 margin: 0 0 2em 0;
163 192 }
164 -
165 - .content > .post > .comments > .comment > .info
193 +
194 + .content > .post > .comments > .comment .pin
195 + {
196 + color: #CD006B;
197 + font-size: .8em;
198 + }
199 +
200 + .content > .post > .comments > .comment .info
166 201 {
167 202 font-size: .9em;
203 + padding: 0 0 0 .5em;
168 204 }
169 205
170 - .content > .post > .comments > .comment > .info > .username > a,
171 - .content > .post > .comments > .comment > .info > .username > a:hover
206 + .content > .post > .comments > .comment .info .username > a,
207 + .content > .post > .comments > .comment .info .username > a:hover
172 208 {
209 + font-weight: bold;
173 210 padding: 0em 0.5em;
174 211 }
175 212
176 - .content > .post > .comments > .comment > .info > .op > a,
177 - .content > .post > .comments > .comment > .info > .op > a:hover
213 + .content > .post > .comments > .comment > .info .op > a,
214 + .content > .post > .comments > .comment > .info .op > a:hover
178 215 {
179 216 background-color: rgb(255, 175, 50);
180 217 border-radius: 4px;

+358/-13 M   database.php
index 9a0ee8c..68098c5
old size: 24K - new size: 36K
@@ -172,21 +172,21 @@ class Database
172 172 */
173 173 function get_post_comments ($post_id)
174 174 {
175 - $comments = array();
175 + $comments = array ();
176 176
177 - if (is_null($this->database))
177 + if (is_null ($this->database))
178 178 return $comments;
179 179
180 - $query = $this->database->prepare(
180 + $query = $this->database->prepare (
181 181 'SELECT C.*, U.`username`' .
182 182 'FROM `comment` AS C ' .
183 183 'JOIN `user` AS U ON C.`userId` = U.`id`' .
184 184 'WHERE C.`postId` = ? ' .
185 185 'ORDER BY C.`vote` DESC, C.`created` ASC');
186 186
187 - $query->execute(array($post_id));
187 + $query->execute (array ($post_id));
188 188
189 - $comments = $query->fetchAll(PDO::FETCH_ASSOC);
189 + $comments = $query->fetchAll (PDO::FETCH_ASSOC);
190 190
191 191 // Group comments by parentId
192 192 $comments_group = array();
@@ -290,7 +290,7 @@ class Database
290 290 'ORDER BY P.`created` DESC ' .
291 291 'LIMIT 50');
292 292
293 - $submissions = $query->fetchAll(PDO::FETCH_ASSOC);
293 + $submissions = $query->fetchAll (PDO::FETCH_ASSOC);
294 294
295 295 return $submissions;
296 296 }
@@ -434,6 +434,49 @@ class Database
434 434 }
435 435
436 436 /**
437 + * Retrieve a list of votes for a range of comments.
438 + *
439 + * @param comments_id list of IDs (eg. "2,4,5").
440 + * NOTE: Because arrays can't be used with PDO, $comments_id
441 + * is a string that's concatenated to the SQL query. For
442 + * this reason is the responsibility of the caller to
443 + * check that $comments_id is a valid string of integers
444 + * separated by commans (beware of SQL injection).
445 + */
446 + function get_comments_votes ($comments_id, $user_id)
447 + {
448 + $votes = array();
449 +
450 + if (is_null ($this->database) || is_null ($comments_id) || is_null ($user_id))
451 + return $votes;
452 +
453 + // Run a test anyway to make sure $posts_id is a valid string
454 + $comments_id_array = explode (',', $comments_id);
455 +
456 + foreach ($comments_id_array as $comment_id)
457 + if (!is_numeric ($comment_id))
458 + return $votes;
459 +
460 + // Retrieve the votes
461 + $query = $this->database->prepare (
462 + 'SELECT * ' .
463 + 'FROM `vote_comment`' .
464 + 'WHERE `commentId` IN(' . $comments_id . ') AND `userId` = ?');
465 +
466 + $query->execute (array ($user_id));
467 +
468 + $votes = $query->fetchAll (PDO::FETCH_ASSOC);
469 +
470 + // Create an array of votes with `commentId` as key
471 + $sorted_votes = array();
472 +
473 + foreach ($votes as $vote)
474 + $sorted_votes[$vote['commentId']] = $vote;
475 +
476 + return $sorted_votes;
477 + }
478 +
479 + /**
437 480 * Create new user account
438 481 */
439 482 function new_user ($username, $password)
@@ -696,13 +739,41 @@ class Database
696 739 return false;
697 740
698 741 $query = $this->database->prepare(
699 - 'SELECT 1 ' .
742 + 'SELECT * ' .
700 743 'FROM `vote_post`' .
701 744 'WHERE `postId` = ? and `userId` = ?');
702 745
703 - $query->execute(array($post_id, $user_id));
746 + $query->execute (array ($post_id, $user_id));
747 +
748 + $vote = $query->fetch (PDO::FETCH_ASSOC);
749 +
750 + if (is_null ($vote) || empty ($vote))
751 + return false;
704 752
705 - return $query->rowCount() > 0;
753 + return $vote;
754 + }
755 +
756 + /**
757 + * Tell if a user has voted a comment
758 + */
759 + function voted_comment ($comment_id, $user_id)
760 + {
761 + if (is_null($this->database))
762 + return false;
763 +
764 + $query = $this->database->prepare(
765 + 'SELECT * ' .
766 + 'FROM `vote_comment`' .
767 + 'WHERE `commentId` = ? and `userId` = ?');
768 +
769 + $query->execute (array ($comment_id, $user_id));
770 +
771 + $vote = $query->fetch (PDO::FETCH_ASSOC);
772 +
773 + if (is_null ($vote) || empty ($vote))
774 + return false;
775 +
776 + return $vote;
706 777 }
707 778
708 779 /**
@@ -718,24 +789,298 @@ class Database
718 789 $post = self::get_post ($post_hash_id);
719 790
720 791 // Already voted?
721 - $voted = self::voted_post ($post['id'], $user_id);
792 + $vote = self::voted_post ($post['id'], $user_id);
722 793
723 - if (!$voted)
794 + if (false == $vote)
724 795 {
725 796 // Cast upvote
726 797 $query = $this->database->prepare(
727 798 'INSERT INTO `vote_post` (`vote`, `datetime`, `postId`, `userId`)' .
728 799 'VALUES (1, NOW(), ?, ?)');
800 +
801 + $query->execute (array ($post['id'], $user_id));
802 +
803 + // Add +1 to post
804 + $query = $this->database->prepare (
805 + 'UPDATE `post`' .
806 + 'SET `vote` = `vote` + 1 ' .
807 + 'WHERE `id` = ?');
729 808
730 - $query->execute(array($post['id'], $user_id));
809 + $query->execute (array ($post['id']));
810 +
811 + } elseif ($vote['vote'] == 1) {
812 + // Already upvoted before. Remove upvote.
731 813
732 - // Add +1 to vote
814 + $query = $this->database->prepare(
815 + 'DELETE FROM `vote_post`' .
816 + 'WHERE `postId` = ? AND `userId` = ?');
817 +
818 + $query->execute (array ($post['id'], $user_id));
819 +
820 + // Remove upvote from post
821 + $query = $this->database->prepare (
822 + 'UPDATE `post`' .
823 + 'SET `vote` = `vote` - 1 ' .
824 + 'WHERE `id` = ?');
825 +
826 + $query->execute (array ($post['id']));
827 +
828 + } elseif ($vote['vote'] == -1) {
829 + // Already downvoted before. Change to upvote.
830 +
831 + $query = $this->database->prepare(
832 + 'UPDATE `vote_post`' .
833 + 'SET `vote` = 1 ' .
834 + 'WHERE `postId` = ? AND `userId` = ?');
835 +
836 + $query->execute (array ($post['id'], $user_id));
837 +
838 + /* Update post vote count
839 + * +2 because of the previous downvote
840 + */
841 + $query = $this->database->prepare (
842 + 'UPDATE `post`' .
843 + 'SET `vote` = `vote` + 2 ' .
844 + 'WHERE `id` = ?');
845 +
846 + $query->execute (array ($post['id']));
847 + }
848 +
849 + $this->database->commit ();
850 +
851 + } catch(PDOException $ex) {
852 +
853 + $this->database->rollBack();
854 +
855 + }
856 + }
857 +
858 + /**
859 + * Downvote a post
860 + */
861 + function downvote_post ($post_hash_id, $user_id)
862 + {
863 + try {
864 +
865 + $this->database->beginTransaction();
866 +
867 + // Get the post
868 + $post = self::get_post ($post_hash_id);
869 +
870 + // Already voted?
871 + $vote = self::voted_post ($post['id'], $user_id);
872 +
873 + if (false == $vote)
874 + {
875 + // Cast downvote
876 + $query = $this->database->prepare(
877 + 'INSERT INTO `vote_post` (`vote`, `datetime`, `postId`, `userId`)' .
878 + 'VALUES (-1, NOW(), ?, ?)');
879 +
880 + $query->execute (array ($post['id'], $user_id));
881 +
882 + // Add -1 to post
883 + $query = $this->database->prepare (
884 + 'UPDATE `post`' .
885 + 'SET `vote` = `vote` - 1 ' .
886 + 'WHERE `id` = ?');
887 +
888 + $query->execute (array ($post['id']));
889 +
890 + } elseif ($vote['vote'] == -1) {
891 + // Already downvoted before. Remove downvote.
892 +
893 + $query = $this->database->prepare(
894 + 'DELETE FROM `vote_post`' .
895 + 'WHERE `postId` = ? AND `userId` = ?');
896 +
897 + $query->execute (array ($post['id'], $user_id));
898 +
899 + // Remove downvote from post
733 900 $query = $this->database->prepare (
734 901 'UPDATE `post`' .
735 902 'SET `vote` = `vote` + 1 ' .
736 903 'WHERE `id` = ?');
737 904
738 905 $query->execute (array ($post['id']));
906 +
907 + } elseif ($vote['vote'] == 1) {
908 + // Already upvoted before. Change to downvote.
909 +
910 + $query = $this->database->prepare(
911 + 'UPDATE `vote_post`' .
912 + 'SET `vote` = -1 ' .
913 + 'WHERE `postId` = ? AND `userId` = ?');
914 +
915 + $query->execute (array ($post['id'], $user_id));
916 +
917 + /* Update post vote count
918 + * -2 because of the previous upvote
919 + */
920 + $query = $this->database->prepare (
921 + 'UPDATE `post`' .
922 + 'SET `vote` = `vote` - 2 ' .
923 + 'WHERE `id` = ?');
924 +
925 + $query->execute (array ($post['id']));
926 + }
927 +
928 + $this->database->commit ();
929 +
930 + } catch(PDOException $ex) {
931 +
932 + $this->database->rollBack();
933 +
934 + }
935 + }
936 +
937 + /**
938 + * Upvote a comment
939 + */
940 + function upvote_comment ($comment_hash_id, $user_id)
941 + {
942 + try {
943 +
944 + $this->database->beginTransaction();
945 +
946 + // Get the comment
947 + $comment = self::get_comment ($comment_hash_id);
948 +
949 + // Already voted?
950 + $vote = self::voted_comment ($comment['id'], $user_id);
951 +
952 + if (false == $vote)
953 + {
954 + // Cast upvote
955 + $query = $this->database->prepare(
956 + 'INSERT INTO `vote_comment` (`vote`, `datetime`, `commentId`, `userId`)' .
957 + 'VALUES (1, NOW(), ?, ?)');
958 +
959 + $query->execute (array ($comment['id'], $user_id));
960 +
961 + // Add +1 to comment
962 + $query = $this->database->prepare (
963 + 'UPDATE `comment`' .
964 + 'SET `vote` = `vote` + 1 ' .
965 + 'WHERE `id` = ?');
966 +
967 + $query->execute (array ($comment['id']));
968 +
969 + } elseif ($vote['vote'] == 1) {
970 + // Already upvoted before. Remove upvote.
971 +
972 + $query = $this->database->prepare(
973 + 'DELETE FROM `vote_comment`' .
974 + 'WHERE `commentId` = ? AND `userId` = ?');
975 +
976 + $query->execute (array ($comment['id'], $user_id));
977 +
978 + // Remove upvote from comment
979 + $query = $this->database->prepare (
980 + 'UPDATE `comment`' .
981 + 'SET `vote` = `vote` - 1 ' .
982 + 'WHERE `id` = ?');
983 +
984 + $query->execute (array ($comment['id']));
985 +
986 + } elseif ($vote['vote'] == -1) {
987 + // Already downvoted before. Change to upvote.
988 +
989 + $query = $this->database->prepare(
990 + 'UPDATE `vote_comment`' .
991 + 'SET `vote` = 1 ' .
992 + 'WHERE `commentId` = ? AND `userId` = ?');
993 +
994 + $query->execute (array ($comment['id'], $user_id));
995 +
996 + /* Update comment vote count
997 + * +2 because of the previous downvote
998 + */
999 + $query = $this->database->prepare (
1000 + 'UPDATE `comment`' .
1001 + 'SET `vote` = `vote` + 2 ' .
1002 + 'WHERE `id` = ?');
1003 +
1004 + $query->execute (array ($comment['id']));
1005 + }
1006 +
1007 + $this->database->commit ();
1008 +
1009 + } catch(PDOException $ex) {
1010 +
1011 + $this->database->rollBack();
1012 +
1013 + }
1014 + }
1015 +
1016 + /**
1017 + * Downvote a comment
1018 + */
1019 + function downvote_comment ($comment_hash_id, $user_id)
1020 + {
1021 + try {
1022 +
1023 + $this->database->beginTransaction();
1024 +
1025 + // Get the comment
1026 + $comment = self::get_comment ($comment_hash_id);
1027 +
1028 + // Already voted?
1029 + $vote = self::voted_comment ($comment['id'], $user_id);
1030 +
1031 + if (false == $vote)
1032 + {
1033 + // Cast downvote
1034 + $query = $this->database->prepare(
1035 + 'INSERT INTO `vote_comment` (`vote`, `datetime`, `commentId`, `userId`)' .
1036 + 'VALUES (-1, NOW(), ?, ?)');
1037 +
1038 + $query->execute (array ($comment['id'], $user_id));
1039 +
1040 + // Add -1 to comment
1041 + $query = $this->database->prepare (
1042 + 'UPDATE `comment`' .
1043 + 'SET `vote` = `vote` - 1 ' .
1044 + 'WHERE `id` = ?');
1045 +
1046 + $query->execute (array ($comment['id']));
1047 +
1048 + } elseif ($vote['vote'] == -1) {
1049 + // Already downvoted before. Remove downvote.
1050 +
1051 + $query = $this->database->prepare(
1052 + 'DELETE FROM `vote_comment`' .
1053 + 'WHERE `commentId` = ? AND `userId` = ?');
1054 +
1055 + $query->execute (array ($comment['id'], $user_id));
1056 +
1057 + // Remove downvote from comment
1058 + $query = $this->database->prepare (
1059 + 'UPDATE `comment`' .
1060 + 'SET `vote` = `vote` + 1 ' .
1061 + 'WHERE `id` = ?');
1062 +
1063 + $query->execute (array ($comment['id']));
1064 +
1065 + } elseif ($vote['vote'] == 1) {
1066 + // Already upvoted before. Change to downvote.
1067 +
1068 + $query = $this->database->prepare(
1069 + 'UPDATE `vote_comment`' .
1070 + 'SET `vote` = -1 ' .
1071 + 'WHERE `commentId` = ? AND `userId` = ?');
1072 +
1073 + $query->execute (array ($comment['id'], $user_id));
1074 +
1075 + /* Update comment vote count
1076 + * -2 because of the previous upvote
1077 + */
1078 + $query = $this->database->prepare (
1079 + 'UPDATE `comment`' .
1080 + 'SET `vote` = `vote` - 2 ' .
1081 + 'WHERE `id` = ?');
1082 +
1083 + $query->execute (array ($comment['id']));
739 1084 }
740 1085
741 1086 $this->database->commit ();

+0/-0 A   images/downvote.png
index 0000000..3cc8c56
old size: 0B - new size: 1K
new file mode: -rwxr-xr-x
Binary file

+0/-0 A   images/upvote.png
index 0000000..e7e68a4
old size: 0B - new size: 1K
new file mode: -rwxr-xr-x
Binary file

+54/-2 M   javascript/freepost.js
index 5c61a53..5091789
old size: 250B - new size: 2K
@@ -3,6 +3,58 @@
3 3 * to the user after clicks.
4 4 */
5 5
6 - function hide (dom_element) {
7 - dom_element.style.visibility = 'hidden';
6 + function vote (action, dom_element) {
7 + var arrow_up = dom_element.children[0];
8 + var vote_counter = dom_element.children[1];
9 + var arrow_down = dom_element.children[2];
10 +
11 + // Voted/Upvoted
12 + var current_status = 0;
13 +
14 + if ("upvoted" == arrow_up.className)
15 + current_status = 1;
16 +
17 + if ("downvoted" == arrow_down.className)
18 + current_status = -1;
19 +
20 + // Current vote
21 + var current_vote = Number (vote_counter.textContent);
22 +
23 + // Remove class from arrows
24 + arrow_up.className = "";
25 + arrow_down.className = "";
26 +
27 + // Toggle upvote class for arrow
28 + if ("up" == action)
29 + switch (current_status)
30 + {
31 + case -1:
32 + vote_counter.textContent = current_vote + 2;
33 + arrow_up.className = "upvoted";
34 + break;
35 + case 0:
36 + vote_counter.textContent = current_vote + 1;
37 + arrow_up.className = "upvoted";
38 + break;
39 + case 1:
40 + vote_counter.textContent = current_vote - 1;
41 + break;
42 + }
43 +
44 + // Toggle downvote class for arrow
45 + if ("down" == action)
46 + switch (current_status)
47 + {
48 + case -1:
49 + vote_counter.textContent = current_vote + 1;
50 + break;
51 + case 0:
52 + vote_counter.textContent = current_vote - 1;
53 + arrow_down.className = "downvoted";
54 + break;
55 + case 1:
56 + vote_counter.textContent = current_vote - 2;
57 + arrow_down.className = "downvoted";
58 + break;
59 + }
8 60 }
8 60 = \ No newline at end of file

+13/-2 M   post.php
index 0af8ae7..5be3509
old size: 1K - new size: 2K
@@ -56,11 +56,20 @@ if (empty ($post))
56 56 }
57 57
58 58 // Retrieve if user has voted this post
59 - $votes = $db->get_posts_votes ($post['id'], Session::get_userid ());
59 + $votes_post = $db->get_posts_votes ($post['id'], Session::get_userid ());
60 60
61 61 // Retrieve comments for this post
62 62 $comments = $db->get_post_comments ($post['id']);
63 63
64 + // Retrieve a list of user votes for the comments
65 + $IDs = array();
66 +
67 + foreach ($comments as $parent)
68 + foreach ($parent as $child)
69 + $IDs[] = $child['id'];
70 +
71 + $votes_comment = $db->get_comments_votes (implode (',', $IDs), Session::get_userid ());
72 +
64 73 // Render template
65 74 echo $twig->render (
66 75 'post.twig',
@@ -68,7 +77,9 @@ echo $twig->render (
68 77 'title' => $post['title'],
69 78 'post' => $post,
70 79 'comments' => $comments,
71 - 'votes' => $votes));
80 + 'votes' => array (
81 + 'post' => $votes_post,
82 + 'comment' => $votes_comment)));
72 83
73 84
74 85

+40/-22 M   template/comment.twig
index 6b40fbc..8cacf9f
old size: 1K - new size: 2K
@@ -1,38 +1,56 @@
1 1 {% if comments[parent_id] %}
2 2 {% for comment in comments[parent_id] %}
3 3
4 - <div class="comment" style="padding-left:{{ depth * 2 }}em">
4 + <table class="comment" style="margin-left:{{ depth * 2 }}em">
5 5 {# Add an anchor link for this comment #}
6 6 <a id="comment-{{ comment.hashId }}"></a>
7 7
8 - <div class="info">
9 - {# Username #}
10 - <span class="username {{ post.userId == comment.userId ? 'op' }}">
11 - <a href="{{ ('user/' ~ comment.username)|docroot }}">{{ comment.username }}</a>
12 - </span>
8 + <tr>
9 + <td class="pin">โ–ฃ</td>
13 10
14 - {# DateTime #}
15 - <a href="{{ ('post/' ~ post.hashId ~ '#comment-' ~ comment.hashId)|docroot }}"><em>{{ comment.created|ago }}</em></a>
16 -
17 - โ€”
18 -
19 - {# Reply #}
20 - <a href="../reply?comment={{ comment.hashId }}">Reply</a>
21 -
22 - {# Edit #}
23 - {% if user and comment.userId == user.id %}
24 - <a href="../edit?comment={{ comment.hashId }}">Edit</a>
25 - {% endif %}
26 - </div>
27 -
28 - {{ comment.text|markdown|raw }}
29 - </div>
11 + <td class="info">
12 + {# Username #}
13 + <span class="username {{ post.userId == comment.userId ? 'op' }}">
14 + <a href="{{ ('user/' ~ comment.username)|docroot }}">{{ comment.username }}</a>
15 + </span>
16 +
17 + {%
18 + include 'vote.twig' with {
19 + target: 'comment',
20 + hash_id: comment.hashId,
21 + vote: votes[comment.id] is defined ? votes[comment.id].vote : null,
22 + vote_count: comment.vote
23 + } only
24 + %}
25 +
26 + {# DateTime #}
27 + <a href="{{ ('post/' ~ post.hashId ~ '#comment-' ~ comment.hashId)|docroot }}"><em>{{ comment.created|ago }}</em></a>
28 +
29 + โ€”
30 +
31 + {# Reply #}
32 + <a href="../reply?comment={{ comment.hashId }}">Reply</a>
33 +
34 + {# Edit #}
35 + {% if user and comment.userId == user.id %}
36 + <a href="../edit?comment={{ comment.hashId }}">Edit</a>
37 + {% endif %}
38 + </td>
39 + </tr>
40 + <tr>
41 + <td></td>
42 + <td>
43 + {{ comment.text|markdown|raw }}
44 + </td>
45 + </tr>
46 + </table>
30 47
31 48 {# Add replies #}
32 49
33 50 {% include 'comment.twig' with {
34 51 'post': post,
35 52 'comments': comments,
53 + 'votes': votes.comment,
36 54 'parent_id': comment.id,
37 55 'depth': depth + 1
38 56 } %}

+32/-28 M   template/index.twig
index 36a6397..d69d2d6
old size: 1K - new size: 1K
@@ -1,37 +1,41 @@
1 1 {% include 'header.twig' %}
2 2
3 - <table class="posts">
3 + <div class="posts">
4 +
4 5 {% for post in posts %}
5 - <tr>
6 - <td class="bump">
7 - {% if not votes[post.id] %}
8 - <a href="vote?up&post={{ post.hashId }}" target="vote_sink" onclick="hide(this)">โ–ฒ</a>
6 +
7 + <div class="post">
8 + <div class="title">
9 + {% if post.link|length > 0 %}
10 + <a href="{{ post.link }}">
11 + {{ post.title }}
12 + </a>
13 + {% else %}
14 + <a href="post/{{ post.hashId }}">
15 + {{ post.title }}
16 + </a>
9 17 {% endif %}
10 - </td>
18 + </div>
11 19
12 - <td class="post">
13 - <div class="title">
14 - {% if post.link|length > 0 %}
15 - <a href="{{ post.link }}">
16 - {{ post.title }}
17 - </a>
18 - {% else %}
19 - <a href="post/{{ post.hashId }}">
20 - {{ post.title }}
21 - </a>
22 - {% endif %}
23 - </div>
20 + <div class="info">
21 + {%
22 + include 'vote.twig' with {
23 + target: 'post',
24 + hash_id: post.hashId,
25 + vote: votes[post.id] is defined ? votes[post.id].vote : null,
26 + vote_count: post.vote
27 + } only
28 + %}
29 +
30 + <em><a href="post/{{ post.hashId }}">{{ post.created|ago }}</a></em>
31 + by <a href="{{ ('user/' ~ post.username)|docroot }}">{{ post.username }}</a> โ€ข
24 32
25 - <div class="info">
26 - {{ post.vote }} votes
27 - <em><a href="post/{{ post.hashId }}">{{ post.created|ago }}</a></em>
28 - by <a href="{{ ('user/' ~ post.username)|docroot }}">{{ post.username }}</a> โ€ข
29 -
30 - <a href="post/{{ post.hashId }}#comments">{{ post.commentsCount ? post.commentsCount ~ ' comments' : 'discuss' }}</a>
31 - </div>
32 - </td>
33 - </tr>
33 + <a href="post/{{ post.hashId }}#comments">{{ post.commentsCount ? post.commentsCount }} comments</a>
34 + </div>
35 + </div>
36 +
34 37 {% endfor %}
35 - </table>
38 +
39 + </div>
36 40
37 41 {% include 'footer.twig' %}

+27/-29 M   template/post.twig
index 9aaca20..ef27fbc
old size: 2K - new size: 2K
@@ -2,36 +2,33 @@
2 2
3 3 <div class="post">
4 4
5 - <table class="posts">
6 - <tr>
7 - <td class="bump">
8 - {% if not votes[post.id] %}
9 - <a href="vote?up&post={{ post.hashId }}" target="vote_sink" onclick="hide(this)">โ–ฒ</a>
10 - {% endif %}
11 - </td>
12 -
13 - <td class="post">
14 - <div class="title">
15 - {% if post.link|length > 0 %}
16 - <a href="{{ post.link }}">
17 - {{ post.title }}
18 - </a>
19 - {% else %}
20 - {{ post.title }}
21 - {% endif %}
22 - </div>
5 + <div class="title">
6 + {% if post.link|length > 0 %}
7 + <a href="{{ post.link }}">
8 + {{ post.title }}
9 + </a>
10 + {% else %}
11 + {{ post.title }}
12 + {% endif %}
13 + </div>
23 14
24 - <div class="info">
25 - by <a href="{{ ('user/' ~ post.username)|docroot }}">{{ post.username }}</a> <em>{{ post.created|ago }}</em>
26 - โ€” {{ post.vote }} votes, <a href="#comments">{{ post.commentsCount }} comments</a>
27 -
28 - {% if user and post.userId == user.id %}
29 - โ€” <a href="../edit?post={{ post.hashId }}">Edit</a>
30 - {% endif %}
31 - </div>
32 - </td>
33 - </tr>
34 - </table>
15 + <div class="info">
16 + {%
17 + include 'vote.twig' with {
18 + target: 'post',
19 + hash_id: post.hashId,
20 + vote: votes.post[post.id] is defined ? votes.post[post.id].vote : null,
21 + vote_count: post.vote
22 + } only
23 + %}
24 +
25 + by <a href="{{ ('user/' ~ post.username)|docroot }}">{{ post.username }}</a> <em>{{ post.created|ago }}</em>
26 + โ€” {{ post.vote }} votes, <a href="#comments">{{ post.commentsCount }} comments</a>
27 +
28 + {% if user and post.userId == user.id %}
29 + โ€” <a href="../edit?post={{ post.hashId }}">Edit</a>
30 + {% endif %}
31 + </div>
35 32
36 33 <div class="text">
37 34 {{ post.text|markdown|raw }}
@@ -51,6 +48,7 @@
51 48 {% include 'comment.twig' with {
52 49 'post': post,
53 50 'comments': comments,
51 + 'votes': votes.comment,
54 52 'parent_id': 0,
55 53 'depth': 0
56 54 } %}

+21/-0 A   template/vote.twig
index 0000000..3288e0f
old size: 0B - new size: 888B
new file mode: -rw-r--r--
@@ -0,0 +1,21 @@
1 + {# Template for up/down vote arrows.
2 + # This template expects these inputs
3 + #
4 + # - target: ('post', 'comment')
5 + # - hash_id: the post/comment hashId
6 + # - vote: (optional) the vote already cast by current logged in user
7 + # - vote_count: the sum of votes for this post/comment
8 + #}
9 +
10 + <span class="vote">
11 + <a href="vote?up&{{ target }}={{ hash_id }}" target="vote_sink" class="{{ vote is defined and vote == 1 ? 'upvoted' }}" onclick="vote ('up', this.parentNode)">
12 + <img title="bump" alt="bump" src="images/upvote.png" />
13 + </a>
14 +
15 + {# Show number of votes #}
16 + <span class="count">{{ vote_count }}</span>
17 +
18 + <a href="vote?down&{{ target }}={{ hash_id }}" target="vote_sink" class="{{ vote is defined and vote == -1 ? 'downvoted' }}" onclick="vote ('down', this.parentNode)">
19 + <img title="sink" alt="sink" src="images/downvote.png" />
20 + </a>
21 + </span>
21 < \ No newline at end of file

+10/-2 M   vote.php
index e6425ff..371f7b7
old size: 391B - new size: 709B
@@ -16,12 +16,20 @@ if (isset ($_GET['post']))
16 16 if (isset ($_GET['up']))
17 17 $db->upvote_post ($_GET['post'], Session::get_userid ());
18 18
19 + if (isset ($_GET['down']))
20 + $db->downvote_post ($_GET['post'], Session::get_userid ());
21 +
19 22 exit ();
20 23 }
21 24
22 25 // Vote a comment
23 26 if (isset ($_GET['comment']))
24 27 {
28 + if (isset ($_GET['up']))
29 + $db->upvote_comment ($_GET['comment'], Session::get_userid ());
30 +
31 + if (isset ($_GET['down']))
32 + $db->downvote_comment ($_GET['comment'], Session::get_userid ());
33 +
25 34 exit ();
26 - }
27 -
35 + }
35 < \ No newline at end of file