diff options
author | Vitaly Takmazov | 2016-07-07 15:13:47 +0300 |
---|---|---|
committer | Vitaly Takmazov | 2016-07-07 15:13:47 +0300 |
commit | e5c8298beee5dde90ca98cc4707faac4bf0e2f0c (patch) | |
tree | 10178a0103ae8ac17849e56914b87b0ee681d0ba /juick-www/src/main/java/com/juick/www/PageTemplates.java | |
parent | d85424021a63c1519e18bd6518ad3424de61fb9f (diff) |
reorganize project
Diffstat (limited to 'juick-www/src/main/java/com/juick/www/PageTemplates.java')
-rw-r--r-- | juick-www/src/main/java/com/juick/www/PageTemplates.java | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/juick-www/src/main/java/com/juick/www/PageTemplates.java b/juick-www/src/main/java/com/juick/www/PageTemplates.java new file mode 100644 index 00000000..f2483ac0 --- /dev/null +++ b/juick-www/src/main/java/com/juick/www/PageTemplates.java @@ -0,0 +1,479 @@ +/* + * Juick + * Copyright (C) 2008-2011, Ugnich Anton + * + * 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.juick.www; + +import com.juick.Message; +import com.juick.Tag; +import com.juick.server.MessagesQueries; +import com.juick.server.TagQueries; +import com.juick.server.UserQueries; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.util.StringUtils; +import ru.sape.Sape; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * + * @author Ugnich Anton + */ +public class PageTemplates { + + public static Sape sape = null; + protected static final SimpleDateFormat sdfSQL = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static SimpleDateFormat sdfSimple = new SimpleDateFormat("d MMM"); + private static SimpleDateFormat sdfFull = new SimpleDateFormat("d MMM yyyy"); + private static String tagsHTML = null; + + public static void pageHead(PrintWriter out, String title, String headers) { + out.println("<!DOCTYPE html>"); + out.print("<html>"); + out.print("<head>"); + out.println("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">"); + out.print("<link rel=\"stylesheet\" href=\"/style.css\"/>"); + out.print("<script type=\"text/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js\"></script>"); + out.print("<script type=\"text/javascript\" src=\"/scripts.js\"></script>"); + if (headers != null) { + out.print(headers); + } + out.print("<title>" + title + "</title>"); + out.println("<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,user-scalable=no\"/>"); + out.println("<link rel=\"icon\" href=\"//i.juick.com/favicon.png\"/>"); + out.println("<!--[if lt IE 9 & (!IEMobile 7)]>"); + out.println("<script src=\"//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js\"></script>"); + out.println("<![endif]-->"); + out.println("</head>"); + out.flush(); + out.println("<body>"); + } + + public static void pageNavigation(PrintWriter out, com.juick.User visitor, String search) { + out.println("<header>"); + out.println(" <div id=\"logo\"><a href=\"/\">Juick</a></div>"); + out.print(" <nav id=\"global\"><ul>"); + out.print("<li><a href=\"/\">Популярные</a></li>"); + out.print("<li><a href=\"/?show=all\" rel=\"nofollow\">Все сообщения</a></li>"); + out.print("<li><a href=\"/?show=photos\" rel=\"nofollow\">Фотографии</a></li>"); + out.println("</ul></nav>"); + out.print(" <div id=\"search\"><form action=\"/\"><input type=\"text\" name=\"search\" class=\"text\" placeholder=\"Поиск\""); + if (search != null) { + out.print(" value=\"" + Utils.encodeHTML(search) + "\""); + } + out.println("/></form></div>"); + out.println(" <section id=\"headdiv\">"); + if (visitor != null) { + out.print(" <nav id=\"user\"><ul>"); + out.print("<li><a href=\"/?show=my\">Моя лента</a></li>"); + out.print("<li><a href=\"/pm/inbox\">Приватные</a></li>"); + out.print("<li><a href=\"/?show=discuss\">Обсуждения</a></li>"); + out.print("<li><a href=\"/?show=recommended\">Рекомендации</a></li>"); + out.println("</ul></nav>"); + out.print(" <nav id=\"actions\"><ul>"); + out.print("<li><a href=\"/#post\">Написать</a></li>"); + out.print("<li><a href=\"/" + visitor.getUName() + "\">@" + visitor.getUName() + "</a></li>"); + out.print("<li><a href=\"/logout\">Выйти</a></li>"); + out.println("</ul></nav>"); + } else { + out.println("<p>Чтобы добавлять сообщения и комментарии, <a href=\"#\" onclick=\"return openDialogLogin()\">представьтесь</a>.</p>"); + } + out.println(" </section>"); + out.println("</header>"); + } + + public static void pageHomeColumn(PrintWriter out, JdbcTemplate sql, com.juick.User visitor) { + pageHomeColumn(out, sql, visitor, false); + } + + public static void pageHomeColumn(PrintWriter out, JdbcTemplate sql, com.juick.User visitor, boolean showAdv) { + if (tagsHTML == null) { + tagsHTML = PageTemplates.formatPopularTags(sql, 80); + } + + out.println("<aside id=\"column\">"); + out.print(" <p class=\"tags\">" + tagsHTML); + if (showAdv) { + out.print(" <a href=\"http://ru.wix.com/\">конструктор сайтов</a>"); + } + out.println("</p>"); +// if (visitor != null) { +// printContestRating(out, sql); +// } + out.println("</aside>"); + } + + public static String formatPopularTags(JdbcTemplate sql, int cnt) { + List<String> popularTags = TagQueries.getPopularTags(sql).stream() + .map(t -> "<a href=\"/tag/" + URLEncoder.encode(t) + "\">" + Utils.encodeHTML(t) + "</a>").collect(Collectors.toList()); + return StringUtils.collectionToDelimitedString(popularTags, " "); + } + + public static void pageFooter(HttpServletRequest request, PrintWriter out, com.juick.User visitor, boolean sapeon) { + out.println("<div id=\"footer\">"); + out.println(" <div id=\"footer-right\"><a href=\"/settings\" rel=\"nofollow\">Настройки</a> · <a href=\"/help/ru/contacts\" rel=\"nofollow\">Контакты</a> · <a href=\"/help/\" rel=\"nofollow\">Справка</a> · <a href=\"/help/ru/adv\" rel=\"nofollow\">Реклама</a></div>"); + out.print(" <div id=\"footer-social\">"); + out.print("<a href=\"https://twitter.com/Juick\" rel=\"nofollow\" class=\"ico32-twi\">Twitter</a>"); + out.print("<a href=\"https://vk.com/juick\" rel=\"nofollow\" class=\"ico32-vk\">ВКонтакте</a>"); + out.print("<a href=\"https://www.facebook.com/JuickCom\" rel=\"nofollow\" class=\"ico32-fb\">Facebook</a>"); + out.println("</div>"); + out.print(" <div id=\"footer-left\">juick.com © 2008-2016"); + + String queryString = request.getQueryString(); + String requestURI = request.getRequestURI(); + if (sapeon && sape != null && (visitor == null || visitor.getUID() == 1) && queryString == null) { + String links = sape.getPageLinks(requestURI, request.getCookies()).render(); + if (links != null && !links.isEmpty()) { + out.print("<br/>Спонсоры: " + links); + } + } + + out.println("</div>"); + out.println("</div>"); + + if (visitor != null) { + out.println("<script type=\"text/javascript\">"); + out.println("var hash=\"" + visitor.getAuthHash() + "\";"); + out.println("</script>"); + } + + out.println("<script>"); + out.println("(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){"); + out.println("(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),"); + out.println("m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)"); + out.println("})(window,document,'script','//www.google-analytics.com/analytics.js','ga');"); + out.println("ga('create','UA-385578-4','juick.com');"); + out.println("ga('require','displayfeatures');"); + out.println("ga('send','pageview');"); + + if (sapeon) { + out.println("var _acic={dataProvider:10};"); + out.println("(function(){"); + out.println("var e=document.createElement('script');e.type='text/javascript';e.async=true;e.src='//www2.aci'+'nt.net/aci.js';"); + out.println("var t=document.getElementsByTagName('script')[0];t.parentNode.insertBefore(e,t);"); + out.println("})();"); + } + + out.println("</script>"); + } + + public static void pageEnd(PrintWriter out) { + out.println("</body></html>"); + } + + public static String formatTags(List<Tag> tags) { + String ret = ""; + for (Tag tag : tags) { + String tagName = tag.Name.replaceAll("<", "<").replaceAll(">", ">"); + try { + ret += " *<a href=\"/tag/" + URLEncoder.encode(tag.Name, "utf-8") + "\""; + if (tag.UsageCnt < 2) { + ret += " rel=\"nofollow\""; + } + ret += ">" + tagName + "</a>"; + } catch (UnsupportedEncodingException e) { + } + } + + return ret; + } + + public static String formatTags(List<String> tags, com.juick.User user) { + String ret = ""; + for (String tag : tags) { + tag = tag.replaceAll("<", "<"); + tag = tag.replaceAll(">", ">"); + try { + ret += " *<a href=\""; + if (user == null) { + ret += "/tag/"; + } else { + ret += "/" + user.getUName() + "/?tag="; + } + ret += URLEncoder.encode(tag, "utf-8") + "\">" + tag + "</a>"; + } catch (UnsupportedEncodingException e) { + } + } + + return ret; + } + + public static String formatDate(int minutes, Date fulldate) { + if (minutes < 1) { + return "сейчас"; + } else if (minutes < 60) { + String unit; + int ld = minutes % 10; + if ((minutes < 10 || minutes > 20) && ld == 1) { + unit = "минуту"; + } else if ((minutes < 10 || minutes > 20) && ld > 1 && ld < 5) { + unit = "минуты"; + } else { + unit = "минут"; + } + return minutes + " " + unit + " назад"; + } else if (minutes < 1440) { + int hours = (minutes / 60); + String unit; + int ld = hours % 10; + if ((hours < 10 || hours > 20) && ld == 1) { + unit = "час"; + } else if ((hours < 10 || hours > 20) && ld > 1 && ld < 5) { + unit = "часа"; + } else { + unit = "часов"; + } + return hours + " " + unit + " назад"; + } else if (minutes < 20160) { + int days = (minutes / 1440); + String unit; + int ld = days % 10; + if ((days < 10 || days > 20) && ld == 1) { + unit = "день"; + } else if ((days < 10 || days > 20) && ld > 1 && ld < 5) { + unit = "дня"; + } else { + unit = "дней"; + } + return days + " " + unit + " назад"; + } else { + String ret = sdfFull.format(fulldate); + synchronized (sdfSQL) { + try { + Calendar c = Calendar.getInstance(); + int curyear = c.get(Calendar.YEAR); + c.setTime(fulldate); + if (c.get(Calendar.YEAR) == curyear) { + ret = sdfSimple.format(fulldate); + } else { + ret = sdfFull.format(fulldate); + } + } catch (Exception e) { + System.err.println("PARSE EXCEPTION: " + fulldate); + } + } + return ret; + } + } + + public static 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 static String formatReplies(int replies) { + 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 + " ответов"; + } + } + private static Pattern regexLinks2 = Pattern.compile("((?<=\\s)|(?<=\\A))([\\[\\{]|<)((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\\"\\)\\!]+)/?(?:[^\\]\\}](?<!>))*)([\\]\\}]|>)"); + + public static String formatMessageCode(String msg) { + msg = msg.replaceAll("&", "&"); + msg = msg.replaceAll("<", "<"); + msg = msg.replaceAll(">", ">"); + + // http://juick.com/last?page=2 + // <a href="http://juick.com/last?page=2" rel="nofollow">http://juick.com/last?page=2</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"]+)/?[^\\s\\n\\\"]*)", "$1<a href=\"$2\" rel=\"nofollow\">$2</a>"); + + // (http://juick.com/last?page=2) + // (<a href="http://juick.com/last?page=2" rel="nofollow">http://juick.com/last?page=2</a>) + Matcher m = regexLinks2.matcher(msg); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String url = m.group(3).replace(" ", "%20").replaceAll("\\s+", ""); + m.appendReplacement(sb, "$1$2<a href=\"" + url + "\" rel=\"nofollow\">" + url + "</a>$5"); + } + m.appendTail(sb); + msg = sb.toString(); + + return "<pre>" + msg + "</pre>"; + } + + public static String formatMessage(String msg) { + msg = msg.replaceAll("&", "&"); + msg = msg.replaceAll("<", "<"); + msg = msg.replaceAll(">", ">"); + + // -- + // — + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\-\\-?((?=\\s)|(?=\\Z))", "$1—$2"); + + // http://juick.com/last?page=2 + // <a href="http://juick.com/last?page=2" rel="nofollow">juick.com</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))((?:ht|f)tps?://(?:www\\.)?([^\\/\\s\\n\\\"]+)/?[^\\s\\n\\\"]*)", "$1<a href=\"$2\" rel=\"nofollow\">$3</a>"); + + // [link text][http://juick.com/last?page=2] + // <a href="http://juick.com/last?page=2" rel="nofollow">link text</a> + msg = msg.replaceAll("\\[([^\\]]+)\\]\\[((?:ht|f)tps?://[^\\]]+)\\]", "<a href=\"$2\" rel=\"nofollow\">$1</a>"); + msg = msg.replaceAll("\\[([^\\]]+)\\]\\(((?:ht|f)tps?://[^\\)]+)\\)", "<a href=\"$2\" rel=\"nofollow\">$1</a>"); + + // #12345 + // <a href="http://juick.com/12345">#12345</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=\\p{Punct}))#(\\d+)((?=\\s)|(?=\\Z)|(?=\\))|(?=\\.)|(?=\\,))", "$1<a href=\"http://juick.com/$2\">#$2</a>$3"); + + // #12345/65 + // <a href="http://juick.com/12345#65">#12345/65</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=\\p{Punct}))#(\\d+)/(\\d+)((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<a href=\"http://juick.com/$2#$3\">#$2/$3</a>$4"); + + // *bold* + // <b>bold</b> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A)|(?<=\\p{Punct}))\\*([^\\*\\n<>]+)\\*((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<b>$2</b>$3"); + + // /italic/ + // <i>italic</i> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))/([^\\/\\n<>]+)/((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<i>$2</i>$3"); + + // _underline_ + // <span class="u">underline</span> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))_([^\\_\\n<>]+)_((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<span class=\"u\">$2</span>$3"); + + // /12 + // <a href="#12">/12</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))\\/(\\d+)((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<a href=\"#$2\">/$2</a>$3"); + + // @username@jabber.org + // <a href="http://juick.com/username@jabber.org/">@username@jabber.org</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-\\.]+@[\\w\\-\\.]+)((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<a href=\"http://juick.com/$2/\">@$2</a>$3"); + + // @username + // <a href="http://juick.com/username/">@username</a> + msg = msg.replaceAll("((?<=\\s)|(?<=\\A))@([\\w\\-]{2,16})((?=\\s)|(?=\\Z)|(?=\\p{Punct}))", "$1<a href=\"http://juick.com/$2/\">@$2</a>$3"); + + // (http://juick.com/last?page=2) + // (<a href="http://juick.com/last?page=2" rel="nofollow">juick.com</a>) + Matcher m = regexLinks2.matcher(msg); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String url = m.group(3).replace(" ", "%20").replaceAll("\\s+", ""); + m.appendReplacement(sb, "$1$2<a href=\"" + url + "\" rel=\"nofollow\">$4</a>$5"); + } + m.appendTail(sb); + msg = sb.toString(); + + // > citate + msg = msg.replaceAll("(?:(?<=\\n)|(?<=\\A))> *(.*)?(\\n|(?=\\Z))", "<q>$1</q>"); + msg = msg.replaceAll("</q><q>", "\n"); + + msg = msg.replaceAll("\n", "<br/>\n"); + return msg; + } + + public static void printMessages(PrintWriter out, JdbcTemplate sql, com.juick.User user, List<Integer> mids, com.juick.User visitor, int YandexID, int ad_mid) { + List<com.juick.Message> msgs = MessagesQueries.getMessages(sql, mids); + + for (int i = 0; i < msgs.size(); i++) { + com.juick.Message msg = msgs.get(i); + if (msg.getMID() == ad_mid) { + msgs.remove(i); + msgs.add(0, msg); + break; + } + } + + List<Integer> blUIDs = new ArrayList<Integer>(20); + if (visitor != null) { + for (Message msg : msgs) { + blUIDs.add(msg.getUser().getUID()); + } + blUIDs = UserQueries.checkBL(sql, visitor.getUID(), blUIDs); + } + + for (int i = 0; i < msgs.size(); i++) { + + com.juick.Message msg = msgs.get(i); + + List<com.juick.Tag> tags = MessagesQueries.getMessageTags(sql, msg.getMID()); + String tagsStr = formatTags(tags); + if (msg.ReadOnly) { + tagsStr += " *readonly"; + } + if (msg.Privacy < 0) { + tagsStr += " *friends"; + } + if (msg.getMID() == ad_mid) { + tagsStr += " *реклама"; + } + + String txt; + if (!msg.Tags.isEmpty() && msg.Tags.contains("code")) { + txt = formatMessageCode(msg.getText()); + } else { + txt = formatMessage(msg.getText()); + } + + out.println("<article data-mid=\"" + msg.getMID() + "\">"); + out.println(" <aside><a href=\"/" + msg.getUser().getUName() + "/\"><img src=\"//i.juick.com/a/" + msg.getUser().getUID() + ".png\" alt=\"" + msg.getUser().getUName() + "\"/></a></aside>"); + out.println(" <header class=\"u\">@<a href=\"/" + msg.getUser().getUName() + "/\">" + msg.getUser().getUName() + "</a>:" + tagsStr + "</header>"); + out.println(" <header class=\"t\"><a href=\"/" + msg.getUser().getUName() + "/" + msg.getMID() + "\"><time datetime=\"" + sdfSQL.format(msg.getDate()) + "Z\" title=\"" + sdfSQL.format(msg.getDate()) + " GMT\">" + formatDate(msg.TimeAgo, msg.getDate()) + "</time></a></header>"); + if (msg.AttachmentType != null) { + String fname = msg.getMID() + "." + msg.AttachmentType; + out.println(" <p class=\"ir\"><a href=\"//i.juick.com/photos-512/" + fname + "\" onclick=\"return showPhotoDialog('" + fname + "')\"><img src=\"//i.juick.com/photos-512/" + fname + "\" alt=\"\"/></a></p>"); + } + out.println(" <p>" + txt + "</p>"); + if (msg.AttachmentType != null) { + out.println(" <div class=\"irbr\"></div>"); + } + out.print(" <nav class=\"l\">"); + msg.ReadOnly |= blUIDs.contains(msg.getUser().getUID()); + out.print("<a href=\"#\" onclick=\"return likeMessage(this," + msg.getMID() + ")\">Мне нравится</a>"); + if (visitor == null && !msg.ReadOnly) { + out.print("<a href=\"#\" onclick=\"return openDialogLogin()\">Комментировать</a> "); + } else if (visitor != null && (!msg.ReadOnly || visitor.getUID() == msg.getUser().getUID())) { + out.print("<a href=\"#\" onclick=\"return showCommentFooter(this)\">Комментировать</a> "); + } + if (visitor != null && msg.Privacy < 0 && msg.getUser().getUID() == visitor.getUID()) { + out.print(" <a href=\"#\" onclick=\"return setPrivacy(this," + msg.getMID() + ")\">Открыть доступ</a>"); + } + if (visitor != null && visitor.getUID() == 3694) { + out.print(" <a href=\"#\" onclick=\"return setPopular(this," + msg.getMID() + ",2)\">+</a>"); + out.print(" <a href=\"#\" onclick=\"return setPopular(this," + msg.getMID() + ",-1)\">-</a>"); + out.print(" <a href=\"#\" onclick=\"return setPopular(this," + msg.getMID() + ",-2)\">x</a>"); + } + out.println("</nav>"); + + out.print(" <nav class=\"s\">"); + if (msg.Likes > 0) { + out.print("<a href=\"/" + msg.getUser().getUName() + "/" + msg.getMID() + "\" class=\"likes\">" + msg.Likes + "</a>"); + } + if (msg.Replies > 0) { + out.print("<a href=\"/" + msg.getUser().getUName() + "/" + msg.getMID() + "\" class=\"replies\">" + msg.Replies + "</a>"); + } + out.println("</nav>"); + out.print("</article>"); + } + } +} |