From 19e49c0a2463b90c3468903672d8ba600da217d2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 23 Apr 2017 17:23:00 +0200 Subject: [PATCH] Render loaded HTML pages --- .../sone/template/LinkedElementRenderFilter.kt | 13 ++++++++++- src/main/resources/static/css/sone.css | 27 +++++++++++++++++++++- src/main/resources/static/javascript/sone.js | 12 ++++++---- src/main/resources/templates/linked/html-page.html | 6 +++++ .../sone/template/LinkedElementRenderFilterTest.kt | 23 ++++++++++++++++-- 5 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/templates/linked/html-page.html diff --git a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt index 8d328be..e15f68b 100644 --- a/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt +++ b/src/main/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilter.kt @@ -16,6 +16,7 @@ class LinkedElementRenderFilter @Inject constructor(private val templateContextF companion object { private val loadedImageTemplate = """<%include linked/image.html>""".parse() + private val loadedHtmlPageTemplate = """<%include linked/html-page.html>""".parse() private val notLoadedImageTemplate = """<%include linked/notLoaded.html>""".parse() private fun String.parse() = StringReader(this).use { TemplateParser.parse(it) }!! @@ -24,7 +25,8 @@ class LinkedElementRenderFilter @Inject constructor(private val templateContextF override fun format(templateContext: TemplateContext?, data: Any?, parameters: Map?) = when { data is LinkedElement && data.loading -> renderNotLoadedLinkedElement(data) - data is LinkedElement -> renderLinkedImage(data) + data is LinkedElement && data.properties["type"] == "image" -> renderLinkedImage(data) + data is LinkedElement && data.properties["type"] == "html" -> renderHtmlPage(data) else -> null } @@ -36,6 +38,15 @@ class LinkedElementRenderFilter @Inject constructor(private val templateContextF it }.toString() + private fun renderHtmlPage(linkedElement: LinkedElement) = + StringWriter().use { + val templateContext = templateContextFactory.createTemplateContext() + templateContext["link"] = linkedElement.link + templateContext["title"] = linkedElement.properties["title"] ?: "No title" + templateContext["description"] = linkedElement.properties["description"] ?: "No description" + it.also { loadedHtmlPageTemplate.render(templateContext, it) } + }.toString() + private fun renderNotLoadedLinkedElement(linkedElement: LinkedElement) = StringWriter().use { val templateContext = templateContextFactory.createTemplateContext() diff --git a/src/main/resources/static/css/sone.css b/src/main/resources/static/css/sone.css index 7392483..1c85743 100644 --- a/src/main/resources/static/css/sone.css +++ b/src/main/resources/static/css/sone.css @@ -444,7 +444,7 @@ textarea { margin-top: 1ex; } -#sone .post .linked-element.loaded .image { +#sone .linked-element.loaded .image { display: inline-block; border: solid 1px black; width: 160px; @@ -455,6 +455,31 @@ textarea { margin-bottom: 1ex; } +#sone .linked-element.loaded .html-page { + display: inline-block; + width: 160px; + max-height: 120px; + overflow: hidden; + vertical-align: top; +} + +#sone .reply .linked-element.loaded .html-page { + width: 120px; + max-height: 90px; +} + +#sone .linked-element.loaded .html-page .heading { + font-size: 125%; + font-weight: 600; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +#sone .linked-element.loaded .html-page { + display: inline-block; +} + #sone .post .replies { clear: both; padding-top: 0.2ex; diff --git a/src/main/resources/static/javascript/sone.js b/src/main/resources/static/javascript/sone.js index a003780..b3f5c83 100644 --- a/src/main/resources/static/javascript/sone.js +++ b/src/main/resources/static/javascript/sone.js @@ -1535,7 +1535,9 @@ function loadLinkedElements(links) { }); if (failedElements.length > 0) { failedElements.forEach(function(element) { - $(getLinkedElement(element.link)).remove() + getLinkedElements(element.link).each(function() { + $(this).remove() + }); }); } var loadedElements = links.filter(function(element) { @@ -1549,15 +1551,17 @@ function loadLinkedElements(links) { }, function (data, textStatus) { if ((data != null) && (data.success)) { data.linkedElements.forEach(function (linkedElement) { - $(getLinkedElement(linkedElement.link)).replaceWith(linkedElement.html); + getLinkedElements(linkedElement.link).each(function() { + $(this).replaceWith(linkedElement.html); + }); }); } }); } } -function getLinkedElement(link) { - return $(".linked-element[title='" + link + "']")[0] +function getLinkedElements(link) { + return $(".linked-element[title='" + link + "']") } /** diff --git a/src/main/resources/templates/linked/html-page.html b/src/main/resources/templates/linked/html-page.html new file mode 100644 index 0000000..e60fb9e --- /dev/null +++ b/src/main/resources/templates/linked/html-page.html @@ -0,0 +1,6 @@ + + +
<% title|html>
+
<% description|html>
+
+
diff --git a/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt b/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt index c3e26c0..07cba3d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/template/LinkedElementRenderFilterTest.kt @@ -9,9 +9,12 @@ import net.pterodactylus.util.template.HtmlFilter import net.pterodactylus.util.template.TemplateContextFactory import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.`is` +import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.equalTo import org.hamcrest.Matchers.notNullValue import org.hamcrest.Matchers.nullValue import org.jsoup.Jsoup +import org.jsoup.nodes.Element import org.junit.Test /** @@ -46,7 +49,7 @@ class LinkedElementRenderFilterTest { @Test fun `filter can render linked images`() { - val html = filter.format(null, LinkedElement("KSK@gpl.png"), emptyMap()) as String + val html = filter.format(null, LinkedElement("KSK@gpl.png", properties = mapOf("type" to "image")), emptyMap()) as String val outerSpanNode = Jsoup.parseBodyFragment(html).body().child(0) assertThat(outerSpanNode.nodeName(), `is`("span")) assertThat(outerSpanNode.attr("class"), `is`("linked-element loaded")) @@ -59,8 +62,24 @@ class LinkedElementRenderFilterTest { } @Test + fun `filter can render HTML pages`() { + val html = filter.format(null, LinkedElement("KSK@gpl.html", properties = mapOf("type" to "html", "title" to "Page Title", "description" to "This is the description.")), emptyMap()) as String + val outerSpanNode = Jsoup.parseBodyFragment(html).body().child(0) + assertThat(outerSpanNode.nodeName(), equalTo("span")) + assertThat(outerSpanNode.attr("class"), `is`("linked-element loaded")) + assertThat(outerSpanNode.attr("title"), `is`("KSK@gpl.html")) + val linkNode = outerSpanNode.child(0) + assertThat(linkNode.nodeName(), equalTo("a")) + assertThat(linkNode.attr("href"), equalTo("/KSK@gpl.html")) + val divNodes = linkNode.children() + assertThat(divNodes.map(Element::nodeName), contains("div", "div")) + assertThat(divNodes.map { it.attr("class") }, contains("heading", "description")) + assertThat(divNodes.map(Element::text), contains("Page Title", "This is the description.")) + } + + @Test fun `render filter can be created by guice`() { - val injector = Guice.createInjector(TemplateContextFactory::class.isProvidedByMock()) + val injector = Guice.createInjector(TemplateContextFactory::class.isProvidedByMock()) assertThat(injector.getInstance(), notNullValue()) } -- 2.7.4