diff options
Diffstat (limited to 'juick-www')
11 files changed, 311 insertions, 1188 deletions
diff --git a/juick-www/package-lock.json b/juick-www/package-lock.json index 9a0871cf..b47230b6 100644 --- a/juick-www/package-lock.json +++ b/juick-www/package-lock.json @@ -1071,7 +1071,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -2399,905 +2398,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.6.2", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -4485,13 +3585,6 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, - "nan": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", - "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", - "dev": true, - "optional": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java b/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java index f62b7678..a01cbc55 100644 --- a/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java +++ b/juick-www/src/main/java/com/juick/www/controllers/PageTemplates.java @@ -286,13 +286,6 @@ public class PageTemplates { } } - public String formatJSLocalTime(Date ts) { - return "<script type=\"text/javascript\">" - + "var d=new Date(" + ts.getTime() + ");" - + "document.write((d.getDate()<10?'0':'')+d.getDate()+'.'+(d.getMonth()<9?'0':'')+(d.getMonth()+1)+'.'+d.getFullYear()+' '+(d.getHours()<10?'0':'')+d.getHours()+':'+(d.getMinutes()<10?'0':'')+d.getMinutes());" - + "</script>"; - } - public String formatReplies(int replies) { int ld = replies % 10; int lh = replies % 100; diff --git a/juick-www/src/main/java/com/juick/www/controllers/UserThread.java b/juick-www/src/main/java/com/juick/www/controllers/UserThread.java index 543d52ad..9ab45333 100644 --- a/juick-www/src/main/java/com/juick/www/controllers/UserThread.java +++ b/juick-www/src/main/java/com/juick/www/controllers/UserThread.java @@ -17,7 +17,7 @@ package com.juick.www.controllers; import com.juick.Message; -import com.juick.server.helpers.TagStats; +import com.juick.server.util.HttpForbiddenException; import com.juick.server.util.HttpNotFoundException; import com.juick.service.MessagesService; import com.juick.service.TagService; @@ -28,11 +28,10 @@ import com.juick.www.WebApp; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.*; import javax.inject.Inject; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -57,14 +56,14 @@ public class UserThread { PageTemplates templates; @GetMapping("/{uname}/{mid}") - protected void doGetThread(HttpServletRequest request, HttpServletResponse response, - @PathVariable String uname, - @PathVariable int mid) throws IOException { + protected String threadAction(ModelMap model, + @PathVariable String uname, + @PathVariable int mid, + @RequestParam(required = false, value = "view") String paramView) throws IOException { com.juick.User visitor = UserUtils.getCurrentUser(); if (!messagesService.canViewThread(mid, visitor.getUid())) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; + throw new HttpForbiddenException(); } com.juick.Message msg = messagesService.getMessage(mid); @@ -75,12 +74,16 @@ public class UserThread { com.juick.User user = userService.getUserByName(uname); if (user.getUid() == 0 || !msg.getUser().equals(user)) { - response.sendRedirect(String.format("/%s/%d", msg.getUser().getName(), mid)); - return; + return String.format("redirect:/%s/%d", msg.getUser().getName(), mid); } + msg.VisitorCanComment = visitor.getUid() > 0; + if (visitor.getUid() > 0) { + msg.VisitorCanComment = visitor.getUid() == msg.getUser().getUid() + || !userService.isInBL(msg.getUser().getUid(), visitor.getUid()); + } + model.addAttribute("msg", msg); boolean listview = false; - String paramView = request.getParameter("view"); if (paramView != null) { if (paramView.equals("list")) { listview = true; @@ -93,136 +96,31 @@ public class UserThread { } else if (visitor.getUid() > 0 && userService.getUserOptionInt(visitor.getUid(), "repliesview", 0) == 1) { listview = true; } - + model.addAttribute("listview", listview); String title = msg.getUser().getName() + ": " + msg.getTagsString(); - response.setContentType("text/html; charset=UTF-8"); - try (PrintWriter out = response.getWriter()) { - String headers = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" + msg.getUser().getName() + "\" href=\"//rss.juick.com/" + msg.getUser().getName() + "/blog\"/>"; - if (paramView != null) { - headers += "<link rel=\"canonical\" href=\"http://juick.com/" + msg.getUser().getName() + "/" + msg.getMid() + "\"/>"; - } - if (msg.Hidden) { - headers += "<meta name=\"robots\" content=\"noindex\"/>"; - } - templates.pageHead(out, visitor, title, headers); - templates.pageNavigation(out, visitor, null); - - out.println("<section id=\"content\" data-mid=\"" + msg.getMid() + "\" style=\"margin-left: 0; width: 100%\">"); - printMessage(out, msg, visitor); - printReplies(out, msg, visitor, listview); - out.println("</section>"); - - templates.pageFooter(request, out, visitor, visitor.getUid() == 0); - - templates.pageEnd(out); - } - } - - // when message id is not fit to int - @ExceptionHandler(NumberFormatException.class) - public ResponseEntity<String> notfound() { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); - } - - public com.juick.Message printMessage(PrintWriter out, com.juick.Message msg, com.juick.User visitor) { - msg.VisitorCanComment = visitor.getUid() > 0; - - List<TagStats> tags = tagService.getMessageTags(msg.getMid()); - String tagsStr = templates.formatTags(tags); - if (msg.ReadOnly) { - tagsStr += "<a>readonly</a>"; - msg.VisitorCanComment = false; - } - if (msg.getPrivacy() < 0) { - tagsStr += "<a>friends</a>"; - } - - String txt; - if (msg.getTags().stream().anyMatch(t -> t.getName().equals("code"))) { - txt = MessageUtils.formatMessageCode(msg.getText()); - } else { - txt = MessageUtils.formatMessage(msg.getText()); - } - - if (!tags.isEmpty()) { - tagsStr = "<div class=\"msg-tags\">" + tagsStr + "</div>"; - } - - out.println("<ul>"); - out.println(" <li id=\"msg-" + msg.getMid() + "\" data-mid=\"" + msg.getMid() + "\" class=\"msg msgthread\">"); - out.println(" <div class=\"msg-cont\">"); - out.println(" <div class=\"msg-menu\"><a href=\"#\"></a></div>"); - out.println(" <div class=\"msg-ts\">" + templates.formatJSLocalTime(msg.getDate()) + "</div>"); - out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>"); - out.println(" <div class=\"msg-header\">@<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:" + tagsStr + "</div>"); - out.println(" <div class=\"msg-txt\">" + txt + "</div>"); - - if (msg.getAttachmentType() != null) { - out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>"); - } - - boolean visitorInBL = false; - if (visitor.getUid() > 0) { - if (visitor.getUid() == msg.getUser().getUid()) { - msg.VisitorCanComment = true; - } else { - visitorInBL = userService.isInBL(msg.getUser().getUid(), visitor.getUid()); - if (visitorInBL) { - msg.VisitorCanComment = false; - } - } - } - - if (msg.VisitorCanComment) { - out.println(" <form action=\"/comment\" method=\"POST\" enctype=\"multipart/form-data\"><input type=\"hidden\" name=\"mid\" value=\"" + msg.getMid() + "\"/>"); - out.println(" <div class=\"msg-comment\"><div class=\"ta-wrapper\"><textarea name=\"body\" rows=\"1\" class=\"reply\" placeholder=\"Написать комментарий\"></textarea></div></div>"); - out.println(" </form>"); - } - - List<String> recomm = messagesService.getMessageRecommendations(msg.getMid()); - if (!recomm.isEmpty()) { - out.print(" <div class=\"msg-recomms\">Рекомендовали (" + recomm.size() + "): "); - for (int i = 0; i < recomm.size(); i++) { - if (i > 0) { - out.print(", "); - } - out.print("<a href=\"/" + recomm.get(i) + "/\">@" + recomm.get(i) + "</a>"); - } - out.println("</div>"); + model.addAttribute("title", title); + model.addAttribute("visitor", visitor); + String headers = "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"@" + msg.getUser().getName() + "\" href=\"//rss.juick.com/" + msg.getUser().getName() + "/blog\"/>"; + if (paramView != null) { + headers += "<link rel=\"canonical\" href=\"http://juick.com/" + msg.getUser().getName() + "/" + msg.getMid() + "\"/>"; } - out.println(" </div>"); - out.println(" </li>"); - - out.println(" <li class=\"toolbar\"><ul>"); - out.println(" <li><a href=\"/" + msg.getMid() + "\"><div style=\"background-position: -64px 0\"></div>" + msg.getMid() + "</a></li>"); - if (visitor.getUid() > 0) { - if (visitor.getUid() != msg.getUser().getUid()) { - if (messagesService.isSubscribed(visitor.getUid(), msg.getMid())) { - out.println(" <li><a href=\"/post?body=U+%23" + msg.getMid() + "\"><div style=\"background-position: -48px 0\"></div>Подписан</a></li>"); - } else { - out.println(" <li><a href=\"/post?body=S+%23" + msg.getMid() + "\"><div style=\"background-position: -16px 0\"></div>Подписаться</a></li>"); - } - if (!visitorInBL) { - out.println(" <li><a href=\"/post?body=%21+%23" + msg.getMid() + "\"><div style=\"background-position: -32px 0\"></div>Рекомендовать</a></li>"); - } - } else { - out.println(" <li><a href=\"/post?body=D+%23" + msg.getMid() + "\"><div style=\"background-position: 0\"></div>Удалить</a></li>"); - } + if (msg.Hidden) { + headers += "<meta name=\"robots\" content=\"noindex\"/>"; } - out.println(" </ul></li>"); - out.println("</ul>"); - - return msg; - } - - public void printReplies(PrintWriter out, com.juick.Message msg, com.juick.User visitor, boolean listview) { + model.addAttribute("headers", headers); + model.addAttribute("contentStyle", "margin-left: 0; width: 100%"); + model.addAttribute("isModerator", visitor.getUid() == 3694); + model.addAttribute("visitorSubscribed", messagesService.isSubscribed(visitor.getUid(), msg.getMid())); + model.addAttribute("visitorInBL", userService.isInBL(msg.getUser().getUid(), visitor.getUid())); + model.addAttribute("recomm", messagesService.getMessageRecommendations(msg.getMid())); List<com.juick.Message> replies = messagesService.getReplies(msg.getMid()); - List<Integer> blUIDs = new ArrayList<Integer>(); + List<Integer> blUIDs = new ArrayList<>(); for (int i = 0; i < replies.size(); i++) { com.juick.Message reply = replies.get(i); - if (reply.getUser().getUid() != msg.getUser().getUid() && !blUIDs.contains(reply.getUser().getUid())) { + if (reply.getUser().getUid() != msg.getUser().getUid() + && !blUIDs.contains(reply.getUser().getUid())) { blUIDs.add(reply.getUser().getUid()); } if (reply.getReplyto() > 0) { @@ -238,6 +136,15 @@ public class UserThread { reply.setReplyto(0); } } + if (visitor.getUid() > 0 && msg.getUser().getUid() == visitor.getUid()) { + reply.VisitorCanComment = true; + } else if (visitor.getUid() > 0 && msg.VisitorCanComment) { + List<Integer> blUIDs2 = userService.checkBL(visitor.getUid(), blUIDs); + reply.VisitorCanComment = reply.getUser().getUid() == visitor.getUid() + || !blUIDs2.contains(reply.getUser().getUid()); + } else { + reply.VisitorCanComment = false; + } } boolean foldable = false; @@ -249,145 +156,14 @@ public class UserThread { } } } - - out.println("<div class=\"title2\">"); - out.print(" <div class=\"title2-right\">"); - if (listview) { - out.print("<a href=\"?view=tree\" rel=\"nofollow\">Показать деревом</a>"); - } else { - if (foldable) { - out.print("<span id=\"unfoldall\"><a href=\"#\">Раскрыть все</a> · </span>"); - } - out.print("<a href=\"?view=list\" rel=\"nofollow\">Показать списком</a>"); - } - out.print("</div>"); - out.println(" <h2>Ответы (" + replies.size() + ")</h2>"); - out.println("</div>"); - - out.println("<ul id=\"replies\">"); - - if (!replies.isEmpty()) { - if (visitor.getUid() > 0 && msg.getUser().getUid() == visitor.getUid()) { - for (Message reply : replies) { - reply.VisitorCanComment = true; - } - } else if (visitor.getUid() > 0 && msg.VisitorCanComment) { - blUIDs = userService.checkBL(visitor.getUid(), blUIDs); - for (Message reply : replies) { - reply.VisitorCanComment = reply.getUser().getUid() == visitor.getUid() || !blUIDs.contains(reply.getUser().getUid()); - } - } else { - for (Message reply : replies) { - reply.VisitorCanComment = false; - } - } - - if (listview) { - printList(out, replies, visitor); - } else { - printTree(out, replies, visitor, 0, 0, false); - } - - for (Message reply : replies) { - reply.cleanupChilds(); - } - replies.clear(); - } - - out.println("</ul>"); + model.addAttribute("replies", replies); + model.addAttribute("foldable", foldable); + return "views/thread"; } - public void printTree(PrintWriter out, List<com.juick.Message> replies, com.juick.User visitor, int ReplyTo, int margin, boolean hidden) { - if (margin > 240) { - margin = 240; - } - - for (int i = 0; i < replies.size(); i++) { - com.juick.Message msg = replies.get(i); - if (msg.getReplyto() == ReplyTo) { - - out.print(" <li id=\"" + msg.getRid() + "\" class=\"msg\" style=\""); - if (margin > 0) { - out.print("margin-left: " + margin + "px;"); - } - if (hidden) { - out.print("display:none;"); - } - out.println("\">"); - out.println(" <div class=\"msg-cont\">"); - out.println(" <div class=\"msg-header\">"); - if (!msg.getUser().isBanned()) { - out.println(" @<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:"); - out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>"); - } else { - out.println(" [удалено]:"); - out.println(" <div class=\"msg-avatar\"><img src=\"//i.juick.com/av-96.png\"/></div>"); - } - out.println(" <div class=\"msg-menu\"><a href=\"#\" class=\"a-thread-links\"></a></div>"); - out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.getMid() + "#" + msg.getRid() + "\" title=\"" + templates.sdfSQL.format(msg.getDate()) + " GMT\">" + templates.formatDate(msg.TimeAgo, msg.getDate()) + "</a></div>"); - out.println(" </div>"); - out.println(" <div class=\"msg-txt\">" + MessageUtils.formatMessage(msg.getText()) + "</div>"); - if (msg.getAttachmentType() != null) { - out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>"); - } - out.print(" <div class=\"msg-links\">/" + msg.getRid()); - if (msg.getReplyto() > 0) { - out.print(" в ответ на <a href=\"#" + msg.getReplyto() + "\">/" + msg.getReplyto() + "</a>"); - } - if (msg.VisitorCanComment) { - out.println(" · <a href=\"/post?body=%23" + msg.getMid() + "/" + msg.getRid() + "%20\" class=\"a-thread-comment\">Ответить</a></div>"); - out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>"); - } else if (visitor.getUid() == 0) { - out.println(" · <a href=\"#\" class=\"a-login\">Ответить</a></div>"); - } - - int childs = msg.getChildsCount(); - if (ReplyTo == 0 && childs > 1 && replies.size() > 10) { - out.println(" <div class=\"msg-comments\"><a href=\"#\">" + templates.formatReplies(childs) + "</a></div>"); - } - out.println(" </div>"); - out.println(" </li>"); - - if (ReplyTo == 0 && childs > 1 && replies.size() > 10) { - printTree(out, msg.childs, visitor, msg.getRid(), margin + 20, true); - } else if (childs > 0) { - printTree(out, msg.childs, visitor, msg.getRid(), margin + 20, hidden); - } - } - } - } - - public void printList(PrintWriter out, List<com.juick.Message> replies, com.juick.User visitor) { - for (Message msg : replies) { - out.print(" <li id=\"" + msg.getRid() + "\" class=\"msg\">"); - out.println(" <div class=\"msg-cont\">"); - out.println(" <div class=\"msg-header\">"); - if (!msg.getUser().isBanned()) { - out.println(" @<a href=\"/" + msg.getUser().getName() + "/\">" + msg.getUser().getName() + "</a>:"); - out.println(" <div class=\"msg-avatar\"><a href=\"/" + msg.getUser().getName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUid() + ".png\" alt=\"" + msg.getUser().getName() + "\"/></a></div>"); - } else { - out.println(" [удалено]:"); - out.println(" <div class=\"msg-avatar\"><img src=\"//i.juick.com/av-96.png\"/></div>"); - } - out.println(" <div class=\"msg-menu\"><a href=\"#\" class=\"a-thread-links\"></a></div>"); - out.println(" <div class=\"msg-ts\"><a href=\"/" + msg.getMid() + "#" + msg.getRid() + "\" title=\"" + PageTemplates.sdfSQL.format(msg.getDate()) + " GMT\">" + templates.formatDate(msg.TimeAgo, msg.getDate()) + "</a></div>"); - out.println(" </div>"); - out.println(" <div class=\"msg-txt\">" + MessageUtils.formatMessage(msg.getText()) + "</div>"); - if (msg.getAttachmentType() != null) { - out.println(" <div class=\"msg-media\"><a href=\"//i.juick.com/p/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\"><img src=\"//i.juick.com/photos-512/" + msg.getMid() + "-" + msg.getRid() + "." + msg.getAttachmentType() + "\" alt=\"\"/></a></div>"); - } - out.print(" <div class=\"msg-links\">/" + msg.getRid()); - if (msg.getReplyto() > 0) { - out.print(" в ответ на <a href=\"#" + msg.getReplyto() + "\">/" + msg.getReplyto() + "</a>"); - } - if (msg.VisitorCanComment) { - out.println(" · <a href=\"#\" class=\"a-thread-comment\">Ответить</a></div>"); - out.println(" <div class=\"msg-comment\" style=\"display: none\"></div>"); - } else if (visitor.getUid() == 0) { - out.println(" <div class=\"msg-links\"><a href=\"/post?body=%23" + msg.getMid() + "/" + msg.getRid() + "%20\" class=\"a-thread-comment\">Ответить</a></div>"); - } - out.println(" </div>"); - out.println(" </li>"); - } + // when message id is not fit to int + @ExceptionHandler(NumberFormatException.class) + public ResponseEntity<String> notFoundAction() { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } diff --git a/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java b/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java index 01b63b0a..7702a316 100644 --- a/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java +++ b/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/FormatterExtension.java @@ -18,6 +18,7 @@ package com.mitchellbosecke.pebble.extension; import com.mitchellbosecke.pebble.extension.filters.FormatMessageFilter; +import com.mitchellbosecke.pebble.extension.filters.FormatRepliesFilter; import com.mitchellbosecke.pebble.extension.filters.PrettyTimeFilter; import com.mitchellbosecke.pebble.extension.filters.TagsListFilter; @@ -32,6 +33,7 @@ public class FormatterExtension extends AbstractExtension { public Map<String, Filter> getFilters() { Map<String, Filter> filters = new HashMap<>(); filters.put("formatMessage", new FormatMessageFilter()); + filters.put("formatReplies", new FormatRepliesFilter()); filters.put("prettyTime", new PrettyTimeFilter()); filters.put("tagsList", new TagsListFilter()); return filters; diff --git a/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatRepliesFilter.java b/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatRepliesFilter.java new file mode 100644 index 00000000..f375ecdb --- /dev/null +++ b/juick-www/src/main/java/com/mitchellbosecke/pebble/extension/filters/FormatRepliesFilter.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008-2017, Juick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package com.mitchellbosecke.pebble.extension.filters; + +import com.juick.Message; +import com.mitchellbosecke.pebble.extension.Filter; + +import java.util.List; +import java.util.Map; + +public class FormatRepliesFilter implements Filter { + @Override + public Object apply(Object input, Map<String, Object> args) { + if (input instanceof Message) { + int replies = ((Message)input).getChildsCount(); + int ld = replies % 10; + int lh = replies % 100; + if ((lh < 10 || lh > 20) && ld == 1) { + return replies + " ответ"; + } else if ((lh < 10 || lh > 20) && ld > 1 && ld < 5) { + return replies + " ответа"; + } else { + return replies + " ответов"; + } + } + throw new IllegalArgumentException("invalid input"); + } + + @Override + public List<String> getArgumentNames() { + return null; + } +} diff --git a/juick-www/src/main/webapp/WEB-INF/layouts/content.html b/juick-www/src/main/webapp/WEB-INF/layouts/content.html index 420d4e0c..c059678e 100644 --- a/juick-www/src/main/webapp/WEB-INF/layouts/content.html +++ b/juick-www/src/main/webapp/WEB-INF/layouts/content.html @@ -31,7 +31,8 @@ </head> <body id="body"> {% include "views/partial/navigation" %} -<section id="content"> +<section id="content" style="{{ contentStyle | default('') }}" + {% if msg | default('') is not empty %}data-mid="{{ msg.mid }}"{% endif %}> {% block content %} {% endblock %} </section> diff --git a/juick-www/src/main/webapp/WEB-INF/views/macros/tree.html b/juick-www/src/main/webapp/WEB-INF/views/macros/tree.html new file mode 100644 index 00000000..3e35f92a --- /dev/null +++ b/juick-www/src/main/webapp/WEB-INF/views/macros/tree.html @@ -0,0 +1,54 @@ +{% macro tree(replies, visitor, level, margin, hidden) %} +{% for msg in replies %} + {% if msg.replyto == level %} + <li id="{{ msg.rid }}" style="margin-left: {{ margin }}px;{% if hidden %}display: none;{% endif %}" class="msg"> + <div class="msg-cont"> + <div class="msg-header"> +{% if not msg.user.banned %} + @<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>: + <div class="msg-avatar"><a href="/{{ msg.user.name }}/"> + <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a> + </div> +{% else %} + [удалено]: + <div class="msg-avatar"> + <img src="//i.juick.com/av-96.png"/> + </div> +{% endif %} + <div class="msg-menu"> + <a href="#" class="a-thread-links"></a> + </div> + <div class="msg-ts"> + <a href="/{{ msg.mid }}#{{ msg.rid }}"> + <time datetime="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }}Z" + title="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }} GMT"> + {{ msg.date | prettyTime }} + </time> + </a> + </div> + </div> + <div class="msg-txt">{{ msg | formatMessage }}</div> + <div class="msg-media"></div> + <div class="msg-links">/{{ msg.rid }} +{% if msg.replyto > 0 %} + в ответ на <a href="#{{ msg.replyto }}">/{{ msg.replyto }}</a> +{% endif %} +{% if msg.VisitorCanComment %} + · <a href="/post?body=%23{{ msg.mid }}/{{ msg.rid }}%20" class="a-thread-comment">Ответить</a></div> + <div class="msg-comment" style="display: none"></div> +{% elseif visitor.uid == 0 %} + · <a href="#" class="a-login">Ответить</a></div> +{% endif %} + +{% if level == 0 and msg.childsCount > 1 and replies.size() > 10 %} + <div class="msg-comments"><a href="#">{{ msg | formatReplies }}</a></div> +{% endif %} + </li> + {% if (level == 0 and msg.childsCount > 1 and replies.size() > 10) %} + {{ tree(msg.childs, visitor, msg.rid, margin + 20, true) }} + {% elseif (msg.childsCount > 0) %} + {{ tree(msg.childs, visitor, msg.rid, margin + 20, hidden) }} + {% endif %} + {% endif %} +{% endfor %} +{% endmacro %}
\ No newline at end of file diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/message.html b/juick-www/src/main/webapp/WEB-INF/views/partial/message.html index cdfad6b6..f67362ce 100644 --- a/juick-www/src/main/webapp/WEB-INF/views/partial/message.html +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/message.html @@ -1,7 +1,9 @@ <article data-mid="{{ msg.mid }}"> - <header class="h">@<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>: + <header class="h"> + @<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>: <div class="msg-avatar"><a href="/{{ msg.user.name }}/"> - <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a></div> + <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a> + </div> <div class="msg-menu"><a href="#"></a></div> <div class="msg-ts"> <a href="/{{ msg.user.name }}/{{ msg.mid }}"> diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/thread_list.html b/juick-www/src/main/webapp/WEB-INF/views/partial/thread_list.html new file mode 100644 index 00000000..b59d8b22 --- /dev/null +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/thread_list.html @@ -0,0 +1,44 @@ +{% for msg in replies %} +<li id="{{ msg.rid }}" class="msg"> + <div class="msg-cont"> + <div class="msg-header"> + {% if not msg.user.banned %} + @<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>: + <div class="msg-avatar"><a href="/{{ msg.user.name }}/"> + <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a> + </div> + {% else %} + [удалено]: + <div class="msg-avatar"> + <img src="//i.juick.com/av-96.png"/> + </div> + {% endif %} + <div class="msg-menu"> + <a href="#" class="a-thread-links"></a> + </div> + <div class="msg-ts"> + <a href="/{{ msg.mid }}#{{ msg.rid }}"> + <time datetime="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }}Z" + title="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }} GMT"> + {{ msg.date | prettyTime }} + </time> + </a> + </div> + </div> + <div class="msg-txt">{{ msg | formatMessage }}</div> + <div class="msg-media"></div> + <div class="msg-links">/{{ msg.rid }} + {% if msg.replyto > 0 %} + в ответ на <a href="#{{ msg.replyto }}">/{{ msg.replyto }}</a> + {% endif %} + {% if msg.VisitorCanComment %} + · <a href="/post?body=%23{{ msg.mid }}/{{ msg.rid }}%20" class="a-thread-comment">Ответить</a> + </div> + <div class="msg-comment" style="display: none;"></div> + {% else %} + </div> + {% endif %} + </div> + </div> +</li> +{% endfor %}
\ No newline at end of file diff --git a/juick-www/src/main/webapp/WEB-INF/views/partial/thread_tree.html b/juick-www/src/main/webapp/WEB-INF/views/partial/thread_tree.html new file mode 100644 index 00000000..f207b8e0 --- /dev/null +++ b/juick-www/src/main/webapp/WEB-INF/views/partial/thread_tree.html @@ -0,0 +1,2 @@ +{% import "views/macros/tree" %} +{{ tree(replies, visitor, 0, 0, false) }}
\ No newline at end of file diff --git a/juick-www/src/main/webapp/WEB-INF/views/thread.html b/juick-www/src/main/webapp/WEB-INF/views/thread.html new file mode 100644 index 00000000..301ad8f8 --- /dev/null +++ b/juick-www/src/main/webapp/WEB-INF/views/thread.html @@ -0,0 +1,108 @@ +{% extends "layouts/content" %} +{% import "views/macros/tags" %} +{% block content %} +<ul> + <li id="msg-{{ msg.mid }}" class="msg msgthread"> + <div class="msg-cont"> + <div class="msg-menu"><a href="#"></a></div> + <div class="msg-ts"><a href="/{{ msg.user.name }}/{{ msg.mid }}"> + <time datetime="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }}Z" + title="{{ msg.date | date('yyyy-MM-dd HH:mm:ss') }} GMT"> + {{ msg.date | prettyTime }} + </time> + </a> + </div> + <div class="msg-avatar"> + <a href="/{{ msg.user.name }}/"> + <img src="//i.juick.com/a/{{ msg.user.uid }}.png" alt="{{ msg.user.name }}"/></a> + </div> + <div class="msg-header">@<a href="/{{ msg.user.name }}/">{{ msg.user.name }}</a>: + <div class="msg-tags"> + {{ tags(msg.user.name, msg.tags | tagsList) }} + </div> + </div> + <div class="msg-txt">{{ msg | formatMessage }}</div> + {% if msg.AttachmentType is not empty %} + <div class="msg-media"> + <a href="//i.juick.com/p/{{ msg.mid }}.{{ msg.AttachmentType }}"> + <img src="//i.juick.com/photos-512/{{ msg.mid }}.{{ msg.AttachmentType }}" alt=""/> + </a> + </div> + {% endif %} + {% if msg.VisitorCanComment %} + <form action="/comment" method="POST" enctype="multipart/form-data"> + <input type="hidden" name="mid" value="{{ msg.mid }}"/> + <div class="msg-comment"> + <div class="ta-wrapper"> + <textarea name="body" rows="1" class="reply" placeholder="Написать комментарий"> + + </textarea> + </div> + </div> + </form> + {% endif %} + {% if recomm is not empty %} + <div class="msg-recomms">Рекомендовали ({{ recomm.size() }}): + {% for rec in recomm %} + <a href="/{{ rec }}/">@{{ rec }}</a>{% if loop.index < (loop.length - 1) %}, {% endif %} + {% endfor %} + </div> + {% endif %} + </div> + </li> + + <li class="toolbar"> + <ul> + <li><a href="/{{ msg.mid }}"> + <div style="background-position: -64px 0"></div> + {{ msg.mid }}</a> + </li> + {% if visitor.uid > 0 %} + {% if visitor.uid != msg.user.uid %} + {% if visitorSubscribed %} + <li><a href="/post?body=U+%23{{ msg.mid }}"> + <div style="background-position: -48px 0"></div> + Подписан</a></li> + {% else %} + <li><a href="/post?body=S+%23{{ msg.mid }}"> + <div style="background-position: -16px 0"></div> + Подписаться</a></li> + {% endif %} + {% if not visitorInBL %} + <li><a href="/post?body=%21+%23{{ msg.mid }}"> + <div style="background-position: -32px 0"></div> + Рекомендовать</a></li> + {% endif %} + {% else %} + <li><a href="/post?body=D+%23{{ msg.mid }}"> + <div style="background-position: 0"></div> + Удалить</a></li> + {% endif %} + {% endif %} + </ul> + </li> +</ul> +<div class="title2"> + <div class="title2-right"> + {% if listview %} + <a href="?view=tree" rel="nofollow">Показать деревом</a> + {% else %} + {% if foldable %} + <span id="unfoldall"><a href="#">Раскрыть все</a> · </span> + {% endif %} + <a href="?view=list" rel="nofollow">Показать списком</a> + {% endif %} + </div> + <h2>Ответы ({{ replies.size() }})</h2> +</div> + +<ul id="replies"> + {% if (listview) %} + {% include "views/partial/thread_list" %} + {% else %} + {% include "views/partial/thread_tree" %} + {% endif %} +</ul> +{% endblock %} +{% block "column" %} +{% endblock %}
\ No newline at end of file |