Remove shortening from render filter
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 11 Nov 2016 15:01:13 +0000 (16:01 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 11 Nov 2016 17:17:50 +0000 (18:17 +0100)
src/main/java/net/pterodactylus/sone/web/WebInterface.java
src/main/java/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.java
src/main/kotlin/net/pterodactylus/sone/template/RenderFilter.kt
src/main/resources/templates/include/viewPost.html
src/main/resources/templates/include/viewReply.html
src/test/kotlin/net/pterodactylus/sone/template/RenderFilterTest.kt

index bbb3396..45b8307 100644 (file)
@@ -91,6 +91,7 @@ import net.pterodactylus.sone.template.RenderFilter;
 import net.pterodactylus.sone.template.ReplyAccessor;
 import net.pterodactylus.sone.template.ReplyGroupFilter;
 import net.pterodactylus.sone.template.RequestChangeFilter;
+import net.pterodactylus.sone.template.ShortenFilter;
 import net.pterodactylus.sone.template.SoneAccessor;
 import net.pterodactylus.sone.template.SubstringFilter;
 import net.pterodactylus.sone.template.TrustAccessor;
@@ -199,6 +200,7 @@ public class WebInterface {
 
        /** The parser filter. */
        private final ParserFilter parserFilter;
+       private final ShortenFilter shortenFilter;
        private final RenderFilter renderFilter;
 
        private final ListNotificationFilter listNotificationFilter;
@@ -287,6 +289,7 @@ public class WebInterface {
                templateContextFactory.addFilter("css", new CssClassNameFilter());
                templateContextFactory.addFilter("js", new JavascriptFilter());
                templateContextFactory.addFilter("parse", parserFilter = new ParserFilter(getCore(), soneTextParser));
+               templateContextFactory.addFilter("shorten", shortenFilter = new ShortenFilter());
                templateContextFactory.addFilter("render", renderFilter = new RenderFilter(getCore(), templateContextFactory));
                templateContextFactory.addFilter("reparse", new ReparseFilter());
                templateContextFactory.addFilter("unknown", new UnknownDateFilter(getL10n(), "View.Sone.Text.UnknownDate"));
@@ -748,7 +751,7 @@ public class WebInterface {
                pageToadlets.add(pageToadletFactory.createPageToadlet(new FollowSoneAjaxPage(this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new UnfollowSoneAjaxPage(this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new EditAlbumAjaxPage(this)));
-               pageToadlets.add(pageToadletFactory.createPageToadlet(new EditImageAjaxPage(this, parserFilter, renderFilter)));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(new EditImageAjaxPage(this, parserFilter, shortenFilter, renderFilter)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustAjaxPage(this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustAjaxPage(this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustAjaxPage(this)));
index f606e50..d6256c1 100644 (file)
 
 package net.pterodactylus.sone.web.ajax;
 
+import com.google.common.collect.ImmutableMap;
 import net.pterodactylus.sone.data.Image;
 import net.pterodactylus.sone.template.ParserFilter;
 import net.pterodactylus.sone.template.RenderFilter;
-import net.pterodactylus.sone.text.Part;
+import net.pterodactylus.sone.template.ShortenFilter;
 import net.pterodactylus.sone.text.TextFilter;
 import net.pterodactylus.sone.web.WebInterface;
 import net.pterodactylus.sone.web.page.FreenetRequest;
 import net.pterodactylus.util.template.TemplateContext;
 
-import com.google.common.collect.ImmutableMap;
-
 /**
  * Page that stores a user’s image modifications.
  *
@@ -36,6 +35,7 @@ import com.google.common.collect.ImmutableMap;
 public class EditImageAjaxPage extends JsonPage {
 
        private final ParserFilter parserFilter;
+       private final ShortenFilter shortenFilter;
        private final RenderFilter renderFilter;
 
        /**
@@ -46,9 +46,10 @@ public class EditImageAjaxPage extends JsonPage {
         * @param parserFilter
         *            The parser filter for image descriptions
         */
-       public EditImageAjaxPage(WebInterface webInterface, ParserFilter parserFilter, RenderFilter renderFilter) {
+       public EditImageAjaxPage(WebInterface webInterface, ParserFilter parserFilter, ShortenFilter shortenFilter, RenderFilter renderFilter) {
                super("editImage.ajax", webInterface);
                this.parserFilter = parserFilter;
+               this.shortenFilter = shortenFilter;
                this.renderFilter = renderFilter;
        }
 
@@ -93,7 +94,8 @@ public class EditImageAjaxPage extends JsonPage {
                TemplateContext templateContext = new TemplateContext();
                ImmutableMap<String, Object> parameters = ImmutableMap.<String, Object>builder().put("sone", image.getSone()).build();
                Object parts = parserFilter.format(templateContext, image.getDescription(), parameters);
-               return (String) renderFilter.format(templateContext, parts, parameters);
+               Object shortenedParts = shortenFilter.format(templateContext, parts, parameters);
+               return (String) renderFilter.format(templateContext, shortenedParts, parameters);
        }
 
 }
index e9992e9..9f785ca 100644 (file)
@@ -18,7 +18,6 @@ import java.io.StringReader
 import java.io.StringWriter
 import java.io.Writer
 import java.net.URLEncoder
-import java.util.ArrayList
 
 /**
  * Renders a number of pre-parsed [Part] into a [String].
@@ -34,49 +33,12 @@ class RenderFilter(private val core: Core, private val templateContextFactory: T
 
        override fun format(templateContext: TemplateContext?, data: Any?, parameters: MutableMap<String, Any?>?): Any? {
                @Suppress("UNCHECKED_CAST")
-               val parts = getPartsToRender(parameters, data as? Iterable<Part> ?: return null)
+               val parts = data as? Iterable<Part> ?: return null
                val parsedTextWriter = StringWriter()
                render(parsedTextWriter, parts)
                return parsedTextWriter.toString()
        }
 
-       private fun Map<String, Any?>.parseInt(key: String) = this[key]?.toString()?.toInt()
-
-       private fun getPartsToRender(parameters: MutableMap<String, Any?>?, parts: Iterable<Part>): Iterable<Part> {
-               val length = parameters?.parseInt("length") ?: -1
-               val cutOffLength = parameters?.parseInt("cut-off-length") ?: length
-               if (length > -1) {
-                       var allPartsLength = 0
-                       val shortenedParts = ArrayList<Part>()
-                       for (part in parts) {
-                               if (part is PlainTextPart) {
-                                       val longText = part.text
-                                       if (allPartsLength < cutOffLength) {
-                                               if (allPartsLength + longText.length > cutOffLength) {
-                                                       shortenedParts.add(PlainTextPart(longText.substring(0, cutOffLength - allPartsLength) + "…"))
-                                               } else {
-                                                       shortenedParts.add(part)
-                                               }
-                                       }
-                                       allPartsLength += longText.length
-                               } else if (part is LinkPart) {
-                                       if (allPartsLength < cutOffLength) {
-                                               shortenedParts.add(part)
-                                       }
-                                       allPartsLength += part.text.length
-                               } else {
-                                       if (allPartsLength < cutOffLength) {
-                                               shortenedParts.add(part)
-                                       }
-                               }
-                       }
-                       if (allPartsLength >= length) {
-                               return shortenedParts
-                       }
-               }
-               return parts
-       }
-
        private fun render(writer: Writer, parts: Iterable<Part>) {
                parts.forEach { render(writer, it) }
        }
@@ -90,7 +52,6 @@ class RenderFilter(private val core: Core, private val templateContextFactory: T
                        is SonePart -> render(writer, part)
                        is PostPart -> render(writer, part)
                        is FreemailPart -> render(writer, part)
-                       is Iterable<*> -> render(writer, part as Iterable<Part>)
                }
        }
 
index 24ce420..7cba220 100644 (file)
                                <%/if>
                        <%/if>
                        <% post.text|html|store key==originalText text==true>
-                       <% post.text|parse sone=post.sone|render|store key==parsedText text==true>
-                       <% post.text|parse sone=post.sone length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|render|store key==shortText text==true>
+                       <% post.text|parse sone=post.sone|store key==parsedText>
+                       <% parsedText|render|store key==renderedText text==true>
+                       <% parsedText|shorten length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|render|store key==shortText text==true>
                        <div class="post-text raw-text<%if !raw> hidden<%/if>"><% originalText></div>
-                       <div class="post-text text<%if raw> hidden<%/if><%if !shortText|match key=parsedText> hidden<%/if>"><% parsedText></div>
-                       <div class="post-text short-text<%if raw> hidden<%/if><%if shortText|match key=parsedText> hidden<%/if>"><% shortText></div>
-                       <%if !shortText|match value=parsedText><%if !raw><a class="expand-post-text" href="viewPost.html?post=<% post.id|html>&amp;raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
-                       <%if !shortText|match value=parsedText><%if !raw><a class="shrink-post-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
+                       <div class="post-text text<%if raw> hidden<%/if><%if !shortText|match key=renderedText> hidden<%/if>"><% renderedText></div>
+                       <div class="post-text short-text<%if raw> hidden<%/if><%if shortText|match key=renderedText> hidden<%/if>"><% shortText></div>
+                       <%if !shortText|match value=renderedText><%if !raw><a class="expand-post-text" href="viewPost.html?post=<% post.id|html>&amp;raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
+                       <%if !shortText|match value=renderedText><%if !raw><a class="shrink-post-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
                </div>
                <div class="post-status-line status-line<%if !post.loaded> hidden<%/if>">
                        <div class="bookmarks">
@@ -56,7 +57,7 @@
                        <div class="permalink permalink-post"><a href="post://<%post.id|html>">[<%= View.Post.Permalink|l10n|html>]</a></div>
                        <span class='separator'>·</span>
                        <div class="permalink permalink-author"><a href="sone://<%post.sone.id|html>">[<%= View.Post.PermalinkAuthor|l10n|html>]</a></div>
-                       <%if ! originalText|match value=parsedText>
+                       <%if ! originalText|match value=renderedText>
                                <span class='separator'>·</span>
                                <div class="show-source"><a href="viewPost.html?post=<% post.id|html>&amp;raw=<%if raw>false<%else>true<%/if>"><%= View.Post.ShowSource|l10n|html></a></div>
                        <%/if>
index 1ef4d99..1ef8f13 100644 (file)
                <div>
                        <div class="author profile-link"><a href="viewSone.html?sone=<% reply.sone.id|html>"><% reply.sone.niceName|html></a></div>
                        <% reply.text|html|store key==originalText text==true>
-                       <% reply.text|parse sone=reply.sone|render|store key==parsedText text==true>
-                       <% reply.text|parse sone=reply.sone length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|render|store key==shortText text==true>
+                       <% reply.text|parse sone=reply.sone|store key==parsedText>
+                       <% parsedText|render|store key==renderedText text==true>
+                       <% parsedText|shorten length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|render|store key==shortText text==true>
                        <div class="reply-text raw-text<%if !raw> hidden<%/if>"><% originalText></div>
-                       <div class="reply-text text<%if raw> hidden<%/if><%if !shortText|match key=parsedText> hidden<%/if>"><% parsedText></div>
-                       <div class="reply-text short-text<%if raw> hidden<%/if><%if shortText|match key=parsedText> hidden<%/if>"><% shortText></div>
-                       <%if !shortText|match value=parsedText><%if !raw><a class="expand-reply-text" href="viewPost.html?post=<% reply.postId|html>&amp;raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
-                       <%if !shortText|match value=parsedText><%if !raw><a class="shrink-reply-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
+                       <div class="reply-text text<%if raw> hidden<%/if><%if !shortText|match key=renderedText> hidden<%/if>"><% renderedText></div>
+                       <div class="reply-text short-text<%if raw> hidden<%/if><%if shortText|match key=renderedText> hidden<%/if>"><% shortText></div>
+                       <%if !shortText|match value=renderedText><%if !raw><a class="expand-reply-text" href="viewPost.html?post=<% reply.postId|html>&amp;raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
+                       <%if !shortText|match value=renderedText><%if !raw><a class="shrink-reply-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
                </div>
                <div class="reply-status-line status-line">
                        <div class="time"><% reply.time|date format=="MMM d, yyyy, HH:mm:ss"></div>
                        <span class='separator'>·</span>
                        <div class="permalink permalink-author"><a href="sone://<%reply.sone.id|html>">[<%= View.Post.PermalinkAuthor|l10n|html>]</a></div>
-                       <%if ! originalText|match value=parsedText>
+                       <%if ! originalText|match value=renderedText>
                                <span class='separator'>·</span>
                                <div class="show-reply-source"><a href="viewPost.html?post=<% post.id|html>&amp;raw=<%if raw>false<%else>true<%/if>"><%= View.Post.ShowSource|l10n|html></a></div>
                        <%/if>
index fbafdaf..b8d6259 100644 (file)
@@ -22,7 +22,6 @@ import org.hamcrest.Matchers.containsInAnyOrder
 import org.jsoup.Jsoup
 import org.jsoup.nodes.Attribute
 import org.jsoup.nodes.Element
-import org.jsoup.nodes.TextNode
 import org.junit.Test
 import org.mockito.Mockito.`when`
 import java.net.URLEncoder
@@ -60,70 +59,6 @@ class RenderFilterTest {
        private fun renderParts(vararg part: Part) = filter.format(templateContext, listOf(*part), parameters) as String
 
        @Test
-       fun `plain text part is shortened if length exceeds maxl ength`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
-       }
-
-       @Test
-       fun `plain text part is not shortened if length does not exceed max length`() {
-               setLengthAndCutOffLength(20, 10)
-               assertThat(renderParts(PlainTextPart("This is a long text.")), `is`("This is a &hellip;"))
-       }
-
-       @Test
-       fun `short parts are not shortened`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This.")), `is`("This."))
-       }
-
-       @Test
-       fun `multiple plain text parts are shortened`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This "), PlainTextPart("is a long text.")), `is`("This is a &hellip;"))
-       }
-
-       @Test
-       fun `parts after length has been reached are ignored`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This is a long text."), PlainTextPart(" And even more.")), `is`("This is a &hellip;"))
-       }
-
-       @Test
-       fun `link parts are not shortened`() {
-               setLengthAndCutOffLength(15, 10)
-               val linkNode = Jsoup.parseBodyFragment(renderParts(FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false))).body().child(0)
-               verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "This is a long text.")
-       }
-
-       @Test
-       fun `additional link parts are ignored`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This is a long text."), FreenetLinkPart("KSK@gpl.txt", "This is a long text.", false)), `is`("This is a &hellip;"))
-       }
-
-       private fun setLengthAndCutOffLength(length: Int, cutOffLength: Int) {
-               parameters.put("length", length)
-               parameters.put("cut-off-length", cutOffLength)
-       }
-
-       @Test
-       fun `sone parts are added but their length is ignored`() {
-               setLengthAndCutOffLength(15, 10)
-               val body = Jsoup.parseBodyFragment(renderParts(SonePart(sone), PlainTextPart("This is a long text."))).body()
-               val linkNode = body.childNode(0) as Element
-               println(linkNode)
-               verifyLink(linkNode, "viewSone.html?sone=$SONE_IDENTITY", "in-sone", "First", "First")
-               assertThat((body.childNode(1) as TextNode).text(), `is`("This is a …"))
-       }
-
-       @Test
-       fun `additional sone parts are ignored`() {
-               setLengthAndCutOffLength(15, 10)
-               assertThat(renderParts(PlainTextPart("This is a long text."), SonePart(sone)), `is`("This is a &hellip;"))
-       }
-
-       @Test
        fun `freenet link is rendered correctly`() {
                val linkNode = renderParts(FreenetLinkPart("KSK@gpl.txt", "gpl.txt", false)).toLinkNode()
                verifyLink(linkNode, "/KSK@gpl.txt", "freenet", "KSK@gpl.txt", "gpl.txt")