count.js: add comment count display JS
This commit is contained in:
parent
216016a4be
commit
15b1640f89
@ -1,27 +1,51 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/lib/pq"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func commentCount(domain string, path string) (int, error) {
|
||||
// path can be empty
|
||||
func commentCount(domain string, paths []string) (map[string]int, error) {
|
||||
commentCounts := map[string]int{}
|
||||
|
||||
if domain == "" {
|
||||
return 0, errorMissingField
|
||||
return nil, errorMissingField
|
||||
}
|
||||
|
||||
p, err := pageGet(domain, path)
|
||||
if len(paths) == 0 {
|
||||
return nil, errorEmptyPaths
|
||||
}
|
||||
|
||||
statement := `
|
||||
SELECT path, commentCount
|
||||
FROM pages
|
||||
WHERE domain = $1 AND path = ANY($2);
|
||||
`
|
||||
rows, err := db.Query(statement, domain, pq.Array(paths))
|
||||
if err != nil {
|
||||
return 0, errorInternal
|
||||
logger.Errorf("cannot get comments: %v", err)
|
||||
return nil, errorInternal
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var path string
|
||||
var commentCount int
|
||||
if err = rows.Scan(&path, &commentCount); err != nil {
|
||||
logger.Errorf("cannot scan path and commentCount: %v", err)
|
||||
return nil, errorInternal
|
||||
}
|
||||
|
||||
commentCounts[path] = commentCount
|
||||
}
|
||||
|
||||
return p.CommentCount, nil
|
||||
return commentCounts, nil
|
||||
}
|
||||
|
||||
func commentCountHandler(w http.ResponseWriter, r *http.Request) {
|
||||
type request struct {
|
||||
Domain *string `json:"domain"`
|
||||
Path *string `json:"path"`
|
||||
Domain *string `json:"domain"`
|
||||
Paths *[]string `json:"paths"`
|
||||
}
|
||||
|
||||
var x request
|
||||
@ -31,13 +55,12 @@ func commentCountHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
domain := domainStrip(*x.Domain)
|
||||
path := *x.Path
|
||||
|
||||
count, err := commentCount(domain, path)
|
||||
commentCounts, err := commentCount(domain, *x.Paths)
|
||||
if err != nil {
|
||||
bodyMarshal(w, response{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
bodyMarshal(w, response{"success": true, "count": count})
|
||||
bodyMarshal(w, response{"success": true, "commentCounts": commentCounts})
|
||||
}
|
||||
|
@ -44,3 +44,4 @@ var errorNewOwnerForbidden = errors.New("New user registrations are forbidden an
|
||||
var errorThreadLocked = errors.New("This thread is locked. You cannot add new comments.")
|
||||
var errorDatabaseMigration = errors.New("Encountered error applying database migration.")
|
||||
var errorNoSuchUnsubscribeSecretHex = errors.New("Invalid unsubscribe link.")
|
||||
var errorEmptyPaths = errors.New("Empty paths field.")
|
||||
|
@ -76,6 +76,7 @@ const jsCompileMap = {
|
||||
"js/logout.js"
|
||||
],
|
||||
"js/commento.js": ["js/commento.js"],
|
||||
"js/count.js": ["js/count.js"],
|
||||
"js/unsubscribe.js": [
|
||||
"js/constants.js",
|
||||
"js/utils.js",
|
||||
|
96
frontend/js/count.js
Normal file
96
frontend/js/count.js
Normal file
@ -0,0 +1,96 @@
|
||||
(function(global, document) {
|
||||
"use strict";
|
||||
|
||||
var origin = "[[[.Origin]]]";
|
||||
|
||||
function post(url, data, callback) {
|
||||
var xmlDoc = new XMLHttpRequest();
|
||||
|
||||
xmlDoc.open("POST", url, true);
|
||||
xmlDoc.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xmlDoc.onload = function() {
|
||||
callback(JSON.parse(xmlDoc.response));
|
||||
};
|
||||
|
||||
xmlDoc.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function main() {
|
||||
var paths = [];
|
||||
var doms = [];
|
||||
var as = document.getElementsByTagName("a");
|
||||
for (var i = 0; i < as.length; i++) {
|
||||
var href = as[i].href;
|
||||
if (href === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
href = href.replace(/^.*\/\/[^\/]+/, "");
|
||||
|
||||
if (href.endsWith("#commento")) {
|
||||
var path = href.substr(0, href.indexOf("#commento"));
|
||||
if (path.startsWith(parent.location.host)) {
|
||||
path = path.substr(parent.location.host.length);
|
||||
}
|
||||
|
||||
paths.push(path);
|
||||
doms.push(as[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var json = {
|
||||
"domain": parent.location.host,
|
||||
"paths": paths,
|
||||
};
|
||||
|
||||
post(origin + "/api/comment/count", json, function(resp) {
|
||||
if (!resp.success) {
|
||||
console.log("[commento] error: " + resp.message);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var count = 0;
|
||||
if (paths[i] in resp.commentCounts) {
|
||||
count = resp.commentCounts[paths[i]];
|
||||
}
|
||||
|
||||
doms[i].innerText = count + " " + (count === 1 ? "comment" : "comments");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var initted = false;
|
||||
|
||||
function init() {
|
||||
if (initted) {
|
||||
return;
|
||||
}
|
||||
initted = true;
|
||||
|
||||
main(undefined);
|
||||
}
|
||||
|
||||
var readyLoad = function() {
|
||||
var readyState = document.readyState;
|
||||
|
||||
if (readyState === "loading") {
|
||||
// The document is still loading. The div we need to fill might not have
|
||||
// been parsed yet, so let's wait and retry when the readyState changes.
|
||||
// If there is more than one state change, we aren't affected because we
|
||||
// have a double-call protection in init().
|
||||
document.addEventListener("readystatechange", readyLoad);
|
||||
} else if (readyState === "interactive") {
|
||||
// The document has been parsed and DOM objects are now accessible. While
|
||||
// JS, CSS, and images are still loading, we don't need to wait.
|
||||
init();
|
||||
} else if (readyState === "complete") {
|
||||
// The page has fully loaded (including JS, CSS, and images). From our
|
||||
// point of view, this is practically no different from interactive.
|
||||
init();
|
||||
}
|
||||
};
|
||||
|
||||
readyLoad();
|
||||
|
||||
}(window, document));
|
Loading…
Reference in New Issue
Block a user