Author | zPlus <-> 2016-03-18 14:46:20 |
Committer | zPlus <-> 2016-03-18 14:46:20 |
Commit | 1c0c257 (patch) |
Tree | 79c1e62 |
Parent(s) |
-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 |
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 |
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; |
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 (); |
index 0000000..3cc8c56 | |||
old size: 0B - new size: 1K | |||
new file mode: -rwxr-xr-x |
Binary file |
index 0000000..e7e68a4 | |||
old size: 0B - new size: 1K | |||
new file mode: -rwxr-xr-x |
Binary file |
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 |
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 |
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 | } %} |
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' %} |
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 | } %} |
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 |
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 |