From dc6a0e9ea362e172d415ffda78fd5c445f5e6cfe Mon Sep 17 00:00:00 2001 From: gsechaud Date: Wed, 1 Feb 2017 15:15:02 +0100 Subject: [PATCH 01/14] Add tab-group switching --- .../org/pegdown/ast/VerbatimGroupNode.java | 43 +++++++++++++++++++ .../paradox/markdown/Directive.scala | 3 +- .../paradox/markdown/StyledVerbatim.scala | 17 ++++++-- themes/generic/src/main/assets/js/page.js | 37 +++++++++++++--- 4 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java/org/pegdown/ast/VerbatimGroupNode.java diff --git a/core/src/main/java/org/pegdown/ast/VerbatimGroupNode.java b/core/src/main/java/org/pegdown/ast/VerbatimGroupNode.java new file mode 100644 index 00000000..06846336 --- /dev/null +++ b/core/src/main/java/org/pegdown/ast/VerbatimGroupNode.java @@ -0,0 +1,43 @@ +/* + * Copyright © 2015 - 2016 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.pegdown.ast; + +public class VerbatimGroupNode extends VerbatimNode { + private final String group; + + public VerbatimGroupNode(String text) { + this(text, "", ""); + } + + public VerbatimGroupNode(String text, String type) { + this(text, type, ""); + } + + public VerbatimGroupNode(String text, String type, String group) { + super(text, type); + this.group = group; + } + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + public String getGroup() { + return group; + } +} \ No newline at end of file diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index 04fe80ec..0b14d903 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -311,7 +311,8 @@ case class SnipDirective(page: Page, variables: Map[String, String]) } else new File(page.file.getParentFile, source) val text = Snippet(file, labels) val lang = Option(node.attributes.value("type")).getOrElse(Snippet.language(file)) - new VerbatimNode(text, lang).accept(visitor) + val group = Option(node.attributes.value("group")).getOrElse("") + new VerbatimGroupNode(text, lang, group).accept(visitor) } catch { case e: FileNotFoundException => throw new SnipDirective.LinkException(s"Unknown snippet [${e.getMessage}] referenced from [${page.path}]") diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala b/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala index 12ba71e3..1b1a98e3 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala @@ -17,7 +17,7 @@ package com.lightbend.paradox.markdown import org.parboiled.common.StringUtils -import org.pegdown.ast.VerbatimNode +import org.pegdown.ast.{ VerbatimNode, VerbatimGroupNode } import org.pegdown.{ Printer, VerbatimSerializer } /** @@ -25,7 +25,7 @@ import org.pegdown.{ Printer, VerbatimSerializer } */ abstract class StyledVerbatimSerializer extends VerbatimSerializer { - def printPreAttributes(printer: Printer): Unit + def printPreAttributes(printer: Printer, nodeGroup: String = ""): Unit def printCodeAttributes(printer: Printer, nodeType: String): Unit @@ -34,7 +34,10 @@ abstract class StyledVerbatimSerializer extends VerbatimSerializer { printer.print(" printPreAttributes(printer, vgn.getGroup) + case vn: VerbatimNode => printPreAttributes(printer) + } } printer.print(">") @@ -66,7 +69,13 @@ abstract class StyledVerbatimSerializer extends VerbatimSerializer { * Add prettify markup around verbatim blocks. */ object PrettifyVerbatimSerializer extends StyledVerbatimSerializer { - override def printPreAttributes(printer: Printer): Unit = printClass(printer, "prettyprint") + override def printPreAttributes(printer: Printer, nodeGroup: String): Unit = { + nodeGroup match { + case "" => printClass(printer, "prettyprint") + case g => printClass(printer, "prettyprint tab-group-" + g) + } + } + override def printCodeAttributes(printer: Printer, nodeType: String): Unit = nodeType match { case "text" | "nocode" => printClass(printer, "nocode") case _ => printClass(printer, s"language-$nodeType") diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 4b4daf48..9cedea7c 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -26,12 +26,37 @@ $(function() { $("dl.tabbed dt a").click(function(e){ e.preventDefault(); - var current = $(this).parent("dt"); - var dl = current.parent("dl"); - dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - current.addClass("current"); - var currentContent = current.next("dd").addClass("current").show(); - dl.css("height", current.height() + currentContent.height()); + var currentDt = $(this).parent("dt"); + var currentDl = currentDt.parent("dl"); + var currentClasses = currentDt.next("dd").find("pre").attr("class").split(' '); + var currentGroup; + var regex = new RegExp("^tab-group-.*"); + for(var i = 0; i < currentClasses.length && currentGroup == undefined; i++) { + if(regex.test(currentClasses[i])) { + currentGroup = currentClasses[i]; + } + } + + if(currentGroup == undefined) { + currentDl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); + currentDt.addClass("current"); + var currentContent = currentDt.next("dd").addClass("current").show(); + currentDl.css("height", currentDt.height() + currentContent.height()); + } else { + $("dl").has("dd > pre").each(function() { + var dl = $(this); + dl.find("dt").each(function() { + var dt = $(this); + var pre = dt.next("dd").find("pre"); + if(pre.hasClass(currentGroup)) { + dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); + dt.addClass("current"); + var currentContent = dt.next("dd").addClass("current").show(); + dl.css("height", dt.height() + currentContent.height()); + } + }); + }); + } }); }); From dc376269a6ce8d52c8e8fadc965fe8ea9005e332 Mon Sep 17 00:00:00 2001 From: gsechaud Date: Wed, 1 Feb 2017 15:40:38 +0100 Subject: [PATCH 02/14] Update docs --- .../paradox/features/snippet-inclusion.md | 39 +++++++++++++++++++ .../resources/tab-switching/examples.java | 15 +++++++ .../resources/tab-switching/examples.scala | 11 ++++++ 3 files changed, 65 insertions(+) create mode 100644 docs/src/main/resources/tab-switching/examples.java create mode 100644 docs/src/main/resources/tab-switching/examples.scala diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md index 6c446b92..6e0e855a 100644 --- a/docs/src/main/paradox/features/snippet-inclusion.md +++ b/docs/src/main/paradox/features/snippet-inclusion.md @@ -58,6 +58,45 @@ should not be highlighted set `type=text` in the directive's attribute section: @@snip [example.log](example.log) { #example-log type=text } ``` +#### tab switching + +It is possible to associate multiple snippets under the same "tag". If some tab of a snippet is switched by the user, all tabs associated with the selected one will be switched as well. To associate snippet tabs under some tag, set the `group` field of the snippet: + +@@@vars +```markdown +First-java +: @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first group=java } +$empty$ +First-scala +: @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } +$empty$ +Some separator. +$empty$ +Second-java +: @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } +$empty$ +Second-scala +: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) { #scala_second group=scala } +``` +@@@ + +The result will be rendered like this (try to switch tabs): + +First-java +: @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first group=java } + +First-scala +: @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } + +Some separator. + +Second-java +: @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } + +Second-scala +: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) { #scala_second group=scala } + + ### snip.*.base_dir In order to specify your snippet source paths off certain base directories you can define placeholders diff --git a/docs/src/main/resources/tab-switching/examples.java b/docs/src/main/resources/tab-switching/examples.java new file mode 100644 index 00000000..349e7bee --- /dev/null +++ b/docs/src/main/resources/tab-switching/examples.java @@ -0,0 +1,15 @@ +// #java_first +class JavaFirst { + public static void main(String[] args) { + System.out.println("Hello java!"); + } +} +// #java_first + +// #java_second +class JavaSecond { + public static void main(String[] args) { + System.out.println("Hello java!"); + } +} +// #java_second \ No newline at end of file diff --git a/docs/src/main/resources/tab-switching/examples.scala b/docs/src/main/resources/tab-switching/examples.scala new file mode 100644 index 00000000..b823ae87 --- /dev/null +++ b/docs/src/main/resources/tab-switching/examples.scala @@ -0,0 +1,11 @@ +// #scala_first +object ScalaFirst extends App { + println("Hello scala!") +} +// #scala_first + +// #scala_second +object ScalaSecond extends App { + println("Hello scala!") +} +// #scala_second \ No newline at end of file From b39cf76c78f9b80dc508bf03c198484f93c98ce1 Mon Sep 17 00:00:00 2001 From: gsechaud Date: Wed, 1 Feb 2017 16:05:00 +0100 Subject: [PATCH 03/14] Add scripted test --- plugin/src/sbt-test/paradox/snippets/expected/group.html | 2 ++ plugin/src/sbt-test/paradox/snippets/src/main/paradox/group.md | 3 +++ plugin/src/sbt-test/paradox/snippets/test | 1 + 3 files changed, 6 insertions(+) create mode 100644 plugin/src/sbt-test/paradox/snippets/expected/group.html create mode 100644 plugin/src/sbt-test/paradox/snippets/src/main/paradox/group.md diff --git a/plugin/src/sbt-test/paradox/snippets/expected/group.html b/plugin/src/sbt-test/paradox/snippets/expected/group.html new file mode 100644 index 00000000..5a2e73e3 --- /dev/null +++ b/plugin/src/sbt-test/paradox/snippets/expected/group.html @@ -0,0 +1,2 @@ +
private class SomethingElse
+
import scala.util.Try
\ No newline at end of file diff --git a/plugin/src/sbt-test/paradox/snippets/src/main/paradox/group.md b/plugin/src/sbt-test/paradox/snippets/src/main/paradox/group.md new file mode 100644 index 00000000..7aa50108 --- /dev/null +++ b/plugin/src/sbt-test/paradox/snippets/src/main/paradox/group.md @@ -0,0 +1,3 @@ +@@ snip [Group A](../../test/scala/Multiple.scala) { #multiple-something-else group=a } + +@@ snip [Group B](../../test/scala/Multiple.scala) { #parseint-imports group=b } diff --git a/plugin/src/sbt-test/paradox/snippets/test b/plugin/src/sbt-test/paradox/snippets/test index 186f2c70..838b93a7 100644 --- a/plugin/src/sbt-test/paradox/snippets/test +++ b/plugin/src/sbt-test/paradox/snippets/test @@ -6,3 +6,4 @@ $ must-mirror target/paradox/site/main/multiple.html expected/multiple.html $ must-mirror target/paradox/site/main/some-xml.html expected/some-xml.html $ must-mirror target/paradox/site/main/nocode.html expected/nocode.html $ must-mirror target/paradox/site/main/configured-bases.html expected/configured-bases.html +$ must-mirror target/paradox/site/main/group.html expected/group.html From f07cad63aa645818115c224a726fe3530ce237c2 Mon Sep 17 00:00:00 2001 From: gsechaud Date: Thu, 2 Feb 2017 15:03:08 +0100 Subject: [PATCH 04/14] Add tab snippets to cookie --- themes/generic/src/main/assets/js/page.js | 73 +++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 9cedea7c..eb58ab30 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -1,6 +1,56 @@ $(function() { // Tabbed code samples + + var tabGroupClass = "tab-group"; + var tabGroupCookie = "tabGroupsPref"; + var cookieTg = getCookie(tabGroupCookie); + var cookieTgList = []; + if(cookieTg != "") + cookieTgList = JSON.parse(cookieTg); + + // http://www.w3schools.com/js/js_cookies.asp + function setCookie(cname,cvalue,exdays) { + if(!exdays) exdays = 365; + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = "expires=" + d.toGMTString(); + document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; + } + + // http://www.w3schools.com/js/js_cookies.asp + function getCookie(cname) { + var name = cname + "="; + var decodedCookie = decodeURIComponent(document.cookie); + var ca = decodedCookie.split(';'); + for(var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length, c.length); + } + } + return ""; + } + + function arrayToJson(arr) { + return JSON.stringify(arr); + } + + // http://stackoverflow.com/questions/12551635/jquery-remove-duplicates-from-an-array-of-strings/12551709#12551709 + function addToList(arr, elem) { + function unique(list) { + var result = []; + $.each(list, function(i, e) { + if ($.inArray(e, result) == -1) result.push(e); + }); + return result; + } + arr.unshift(elem); + return unique(arr); + } $("dl").has("dd > pre").each(function() { var dl = $(this); @@ -18,8 +68,21 @@ $(function() { dd.addClass("has-note"); } }); - var current = dts.first().addClass("first").addClass("current"); + + var current; + for(var i = 0; i < cookieTgList.length && !current; i++) { + dts.each(function() { + var dt = $(this); + var pre = dt.next("dd").find("pre"); + if(pre.hasClass(cookieTgList[i])) + current = dt.addClass("current"); + }); + } + + if(!current) + current = dts.first().addClass("current"); var currentContent = current.next("dd").addClass("current").show(); + dts.first().addClass("first"); dts.last().addClass("last"); dl.css("height", current.height() + currentContent.height()); }); @@ -30,14 +93,16 @@ $(function() { var currentDl = currentDt.parent("dl"); var currentClasses = currentDt.next("dd").find("pre").attr("class").split(' '); var currentGroup; - var regex = new RegExp("^tab-group-.*"); - for(var i = 0; i < currentClasses.length && currentGroup == undefined; i++) { + var regex = new RegExp("^" + tabGroupClass + "-.*"); + for(var i = 0; i < currentClasses.length && !currentGroup; i++) { if(regex.test(currentClasses[i])) { currentGroup = currentClasses[i]; + cookieTgList = addToList(cookieTgList, currentGroup); + setCookie(tabGroupCookie, arrayToJson(cookieTgList)); } } - if(currentGroup == undefined) { + if(!currentGroup) { currentDl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); currentDt.addClass("current"); var currentContent = currentDt.next("dd").addClass("current").show(); From c09450d0b55bc7299809d83bba111a17a6a8523c Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Wed, 19 Apr 2017 13:55:23 +0200 Subject: [PATCH 05/14] Allow any fragment to be switched as part of a group Expanding on the proposal in #95, added support for having other parts of the documentation change as well when changing a group. --- .../paradox/markdown/Directive.scala | 31 +++++++++ .../paradox/markdown/StyledVerbatim.scala | 2 +- .../lightbend/paradox/markdown/Writer.scala | 5 +- .../markdown/InlineWrapDirectiveSpec.scala | 36 +++++++++++ .../paradox/features/snippet-inclusion.md | 8 ++- .../paradox/snippets/expected/group.html | 4 +- themes/generic/src/main/assets/js/page.js | 63 ++++++++++++++----- 7 files changed, 129 insertions(+), 20 deletions(-) create mode 100644 core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index 0b14d903..4794982f 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -474,3 +474,34 @@ case class WrapDirective(typ: String) extends ContainerBlockDirective(Array(typ, printer.print(s"") } } + +/** + * Inline wrap directive + * + * Wraps inner contents in a `span`, optionally with custom `id` and/or `class` attributes. + */ +case class InlineWrapDirective(typ: String) extends InlineDirective("span") { + def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = { + val id = + node.attributes.identifier match { + case null => "" + case x => s""" id="$x"""" + } + val classes = + node.attributes.classesString match { + case "" => "" + case x => s""" class="$x"""" + } + printer.print(s"""<$typ$id$classes>""") + node.contentsNode.accept(visitor) + printer.print(s"") + } +} + +case object SupergroupDirective extends LeafBlockDirective("supergroup") { + def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = { + printer.print("""""") + printer.print(node.attributes.value("groups").split(",").map(group => s"""$group""").mkString) + printer.print("""""") + } +} \ No newline at end of file diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala b/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala index 1b1a98e3..ce18c97a 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/StyledVerbatim.scala @@ -72,7 +72,7 @@ object PrettifyVerbatimSerializer extends StyledVerbatimSerializer { override def printPreAttributes(printer: Printer, nodeGroup: String): Unit = { nodeGroup match { case "" => printClass(printer, "prettyprint") - case g => printClass(printer, "prettyprint tab-group-" + g) + case g => printClass(printer, "prettyprint group-" + g) } } diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala index 0785b288..c8478776 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala @@ -119,7 +119,10 @@ object Writer { VarsDirective(context.properties), CalloutDirective("note", "Note"), CalloutDirective("warning", "Warning"), - WrapDirective("div")) + WrapDirective("div"), + InlineWrapDirective("span"), + SupergroupDirective + ) class DefaultLinkRenderer(context: Context) extends LinkRenderer { private lazy val imgBase = { diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala new file mode 100644 index 00000000..88522f51 --- /dev/null +++ b/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala @@ -0,0 +1,36 @@ +/* + * Copyright © 2015 - 2016 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown + +import com.lightbend.paradox.tree.Tree.Location + +class InlineWrapDirectiveSpec extends MarkdownBaseSpec { + + "The inline `wrap` directive" should "render wrapping `span`s" in { + markdown("@span[Simple sentence here]") shouldEqual html("

Simple sentence here

") + } + + it should "render the example from the docs" in { + markdown("@span[Scala variant containing ***markdown*** and @ref:[Linking](test.md)] { .group-scala }") shouldEqual html(""" + |

Scala variant containing markdown and Linking

""") + } + + it should "support a custom id and custom CSS classes at the same time" in { + markdown("@span[Simple sentence here.] { #yeah .red .blue }") shouldEqual html("""

Simple sentence here.

""") + } + +} diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md index 6e0e855a..128fb8df 100644 --- a/docs/src/main/paradox/features/snippet-inclusion.md +++ b/docs/src/main/paradox/features/snippet-inclusion.md @@ -70,6 +70,10 @@ $empty$ First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } $empty$ +@@supergroup { name=Language groups=scala,java } +$empty$ +Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } +$empty$ Some separator. $empty$ Second-java @@ -88,7 +92,9 @@ First-java First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } -Some separator. +@@supergroup { name=Language groups=scala,java } + +Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } Second-java : @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } diff --git a/plugin/src/sbt-test/paradox/snippets/expected/group.html b/plugin/src/sbt-test/paradox/snippets/expected/group.html index 5a2e73e3..c7113739 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/group.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/group.html @@ -1,2 +1,2 @@ -
private class SomethingElse
-
import scala.util.Try
\ No newline at end of file +
private class SomethingElse
+
import scala.util.Try
\ No newline at end of file diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index eb58ab30..fb94e02d 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -1,10 +1,11 @@ $(function() { - // Tabbed code samples - - var tabGroupClass = "tab-group"; - var tabGroupCookie = "tabGroupsPref"; - var cookieTg = getCookie(tabGroupCookie); + // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. + // Supergroups can be defined (such as 'languages', containing 'scala' and 'java') to initialize the group. + + var groupClass = "group"; + var groupCookie = "groupsPref"; + var cookieTg = getCookie(groupCookie); var cookieTgList = []; if(cookieTg != "") cookieTgList = JSON.parse(cookieTg); @@ -52,6 +53,30 @@ $(function() { return unique(arr); } + $(".supergroup").each(function() { + var groups = $(this).find(".group") + + var current; + for(var i = 0; i < cookieTgList.length && !current; i++) { + groups.each(function() { + var group = "group-" + $(this).text(); + if(group == cookieTgList[i]) + current = group; + }); + } + if (!current) { + current = "group-" + groups.first().text(); + cookieTgList = addToList(cookieTgList, current); + } + + groups.each(function() { + var group = "group-" + $(this).text(); + if(group != current) { + $("span." + group).hide() + } + }); + }); + $("dl").has("dd > pre").each(function() { var dl = $(this); dl.addClass("tabbed"); @@ -91,16 +116,8 @@ $(function() { e.preventDefault(); var currentDt = $(this).parent("dt"); var currentDl = currentDt.parent("dl"); - var currentClasses = currentDt.next("dd").find("pre").attr("class").split(' '); - var currentGroup; - var regex = new RegExp("^" + tabGroupClass + "-.*"); - for(var i = 0; i < currentClasses.length && !currentGroup; i++) { - if(regex.test(currentClasses[i])) { - currentGroup = currentClasses[i]; - cookieTgList = addToList(cookieTgList, currentGroup); - setCookie(tabGroupCookie, arrayToJson(cookieTgList)); - } - } + + var currentGroup = groupOf(currentDt); if(!currentGroup) { currentDl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); @@ -108,6 +125,7 @@ $(function() { var currentContent = currentDt.next("dd").addClass("current").show(); currentDl.css("height", currentDt.height() + currentContent.height()); } else { + $("span ." + currentGroup).show(); $("dl").has("dd > pre").each(function() { var dl = $(this); dl.find("dt").each(function() { @@ -118,10 +136,25 @@ $(function() { dt.addClass("current"); var currentContent = dt.next("dd").addClass("current").show(); dl.css("height", dt.height() + currentContent.height()); + $("span." + currentGroup).show() + } else { + $("span." + groupOf(dt)).hide() } }); }); } }); + function groupOf(elem) { + var currentClasses = elem.next("dd").find("pre").attr("class").split(' '); + var regex = new RegExp("^" + groupClass + "-.*"); + for(var i = 0; i < currentClasses.length; i++) { + if(regex.test(currentClasses[i])) { + var currentGroup = currentClasses[i]; + cookieTgList = addToList(cookieTgList, currentGroup); + setCookie(groupCookie, arrayToJson(cookieTgList)); + return currentGroup; + } + } + } }); From 09f0ccde4759c159642e4e5729161dd250929126 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Thu, 20 Apr 2017 16:45:53 +0200 Subject: [PATCH 06/14] Allow group shorthand, configured from sbt --- .../lightbend/paradox/ParadoxProcessor.scala | 3 ++- .../paradox/markdown/Directive.scala | 8 ++++++ .../lightbend/paradox/markdown/Writer.scala | 2 ++ .../markdown/InlineGroupDirectiveSpec.scala | 27 +++++++++++++++++++ .../paradox/markdown/MarkdownBaseSpec.scala | 6 ++++- .../lightbend/paradox/sbt/ParadoxKeys.scala | 1 + .../lightbend/paradox/sbt/ParadoxPlugin.scala | 2 ++ 7 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala diff --git a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala index a34258dd..c8811544 100644 --- a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala +++ b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala @@ -37,6 +37,7 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) outputDirectory: File, sourceSuffix: String, targetSuffix: String, + groups: Map[String, Seq[String]], properties: Map[String, String], navigationDepth: Int, themeDir: File, @@ -51,7 +52,7 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) val page = loc.tree.label val pageProperties = properties ++ page.properties.get val currentMapping = Path.generateTargetFile(Path.relativeLocalPath(page.rootSrcPage, page.file.getPath), globalPageMappings)_ - val writerContext = Writer.Context(loc, paths, currentMapping, sourceSuffix, targetSuffix, pageProperties) + val writerContext = Writer.Context(loc, paths, currentMapping, sourceSuffix, targetSuffix, groups, pageProperties) val pageToc = new TableOfContents(pages = true, headers = false, ordered = false, maxDepth = navigationDepth) val headerToc = new TableOfContents(pages = false, headers = true, ordered = false, maxDepth = navigationDepth) val pageContext = PageContents(leadingBreadcrumbs, loc, writer, writerContext, pageToc, headerToc) diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index 4794982f..f2883087 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -498,6 +498,14 @@ case class InlineWrapDirective(typ: String) extends InlineDirective("span") { } } +case class InlineGroupDirective(groups: Seq[String]) extends InlineDirective(groups: _*) { + def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = { + printer.print(s"""""") + node.contentsNode.accept(visitor) + printer.print(s"") + } +} + case object SupergroupDirective extends LeafBlockDirective("supergroup") { def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = { printer.print("""""") diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala index c8478776..9e0d6822 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala @@ -91,6 +91,7 @@ object Writer { pageMappings: String => String = Path.replaceExtension(DefaultSourceSuffix, DefaultTargetSuffix), sourceSuffix: String = DefaultSourceSuffix, targetSuffix: String = DefaultTargetSuffix, + groups: Map[String, Seq[String]] = Map.empty, properties: Map[String, String] = Map.empty) def defaultLinks(context: Context): LinkRenderer = @@ -121,6 +122,7 @@ object Writer { CalloutDirective("warning", "Warning"), WrapDirective("div"), InlineWrapDirective("span"), + InlineGroupDirective(context.groups.values.flatten.map(_.toLowerCase).toSeq), SupergroupDirective ) diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala new file mode 100644 index 00000000..4c60cf80 --- /dev/null +++ b/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala @@ -0,0 +1,27 @@ +/* + * Copyright © 2015 - 2016 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown + +import com.lightbend.paradox.tree.Tree.Location + +class InlineGroupDirectiveSpec extends MarkdownBaseSpec { + + "The inline `group` directive" should "render wrapping groups" in { + markdown("@scala[Simple sentence here]") shouldEqual html("""

Simple sentence here

""") + } + +} diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/MarkdownBaseSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/MarkdownBaseSpec.scala index c0549400..35a93bfa 100644 --- a/core/src/test/scala/com/lightbend/paradox/markdown/MarkdownBaseSpec.scala +++ b/core/src/test/scala/com/lightbend/paradox/markdown/MarkdownBaseSpec.scala @@ -81,7 +81,11 @@ abstract class MarkdownBaseSpec extends FlatSpec with Matchers { } def writerContext(location: Location[Page]): Writer.Context = { - Writer.Context(location, Page.allPaths(List(location.root.tree)).toSet) + Writer.Context( + location, + Page.allPaths(List(location.root.tree)).toSet, + groups = Map("Language" -> Seq("Scala", "Java")) + ) } def pages(mappings: (String, String)*): Forest[Page] = { diff --git a/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxKeys.scala b/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxKeys.scala index 7829f0bf..6ae1c110 100644 --- a/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxKeys.scala +++ b/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxKeys.scala @@ -35,4 +35,5 @@ trait ParadoxKeys { val paradoxOverlayDirectories = settingKey[Seq[File]]("Directory containing common source files for configuration.") val paradoxTemplate = taskKey[PageTemplate]("PageTemplate to use when generating HTML pages.") val paradoxVersion = settingKey[String]("Paradox plugin version.") + val paradoxGroups = settingKey[Map[String, Seq[String]]]("Paradox groups.") } diff --git a/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxPlugin.scala b/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxPlugin.scala index 5357f06d..80b5e862 100644 --- a/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxPlugin.scala +++ b/plugin/src/main/scala/com/lightbend/paradox/sbt/ParadoxPlugin.scala @@ -46,6 +46,7 @@ object ParadoxPlugin extends AutoPlugin { paradoxProperties := Map.empty, paradoxTheme := Some(builtinParadoxTheme("generic")), paradoxLeadingBreadcrumbs := Nil, + paradoxGroups := Map.empty, libraryDependencies ++= paradoxTheme.value.toSeq ) @@ -125,6 +126,7 @@ object ParadoxPlugin extends AutoPlugin { (target in paradoxMarkdownToHtml).value, paradoxSourceSuffix.value, paradoxTargetSuffix.value, + paradoxGroups.value, paradoxProperties.value, paradoxNavigationDepth.value, paradoxThemeDirectory.value, From de72f11a163f9d5bbc87cf02272265d137ea5784 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Thu, 20 Apr 2017 17:43:29 +0200 Subject: [PATCH 07/14] Generate 'groups' block on the page Removes the need to define the 'supergroup' in the markdown. Next up is of course switching from the dropdown. --- .../lightbend/paradox/ParadoxProcessor.scala | 7 ++--- .../paradox/markdown/Directive.scala | 8 ------ .../lightbend/paradox/markdown/Groups.scala | 26 +++++++++++++++++++ .../lightbend/paradox/markdown/Writer.scala | 9 +++++-- .../paradox/features/snippet-inclusion.md | 6 ----- themes/generic/src/main/assets/groups.st | 1 + themes/generic/src/main/assets/js/page.js | 4 +-- themes/generic/src/main/assets/navigation.st | 1 + 8 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala create mode 100644 themes/generic/src/main/assets/groups.st diff --git a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala index c8811544..86df2c81 100644 --- a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala +++ b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala @@ -16,7 +16,7 @@ package com.lightbend.paradox -import com.lightbend.paradox.markdown.{ Breadcrumbs, Page, Path, Reader, TableOfContents, Writer, Frontin, PropertyUrl, Url } +import com.lightbend.paradox.markdown.{ Breadcrumbs, Groups, Page, Path, Reader, TableOfContents, Writer, Frontin, PropertyUrl, Url } import com.lightbend.paradox.template.{ CachedTemplates, PageTemplate } import com.lightbend.paradox.tree.Tree.{ Forest, Location } import java.io.File @@ -55,7 +55,7 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) val writerContext = Writer.Context(loc, paths, currentMapping, sourceSuffix, targetSuffix, groups, pageProperties) val pageToc = new TableOfContents(pages = true, headers = false, ordered = false, maxDepth = navigationDepth) val headerToc = new TableOfContents(pages = false, headers = true, ordered = false, maxDepth = navigationDepth) - val pageContext = PageContents(leadingBreadcrumbs, loc, writer, writerContext, pageToc, headerToc) + val pageContext = PageContents(leadingBreadcrumbs, groups, loc, writer, writerContext, pageToc, headerToc) val outputFile = new File(outputDirectory, page.path) val template = CachedTemplates(themeDir, page.properties(Page.Properties.DefaultLayoutMdIndicator, PageTemplate.DefaultName)) outputFile.getParentFile.mkdirs @@ -69,7 +69,7 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) /** * Default template contents for a markdown page at a particular location. */ - case class PageContents(leadingBreadcrumbs: List[(String, String)], loc: Location[Page], writer: Writer, context: Writer.Context, pageToc: TableOfContents, headerToc: TableOfContents) extends PageTemplate.Contents { + case class PageContents(leadingBreadcrumbs: List[(String, String)], groups: Map[String, Seq[String]], loc: Location[Page], writer: Writer, context: Writer.Context, pageToc: TableOfContents, headerToc: TableOfContents) extends PageTemplate.Contents { import scala.collection.JavaConverters._ private val page = loc.tree.label @@ -83,6 +83,7 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) lazy val getNext = link(loc.next) lazy val getBreadcrumbs = writer.writeBreadcrumbs(Breadcrumbs.markdown(leadingBreadcrumbs, loc.path), context) lazy val getNavigation = writer.writeNavigation(pageToc.root(loc), context) + lazy val getGroups = Groups.html(groups) lazy val hasSubheaders = page.headers.nonEmpty lazy val getToc = writer.writeToc(headerToc.headers(loc), context) lazy val getSource_url = githubLink(Some(loc)).getHtml diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index f2883087..e64a969d 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -504,12 +504,4 @@ case class InlineGroupDirective(groups: Seq[String]) extends InlineDirective(gro node.contentsNode.accept(visitor) printer.print(s"
") } -} - -case object SupergroupDirective extends LeafBlockDirective("supergroup") { - def render(node: DirectiveNode, visitor: Visitor, printer: Printer): Unit = { - printer.print("""""") - printer.print(node.attributes.value("groups").split(",").map(group => s"""$group""").mkString) - printer.print("""""") - } } \ No newline at end of file diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala new file mode 100644 index 00000000..0758c122 --- /dev/null +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala @@ -0,0 +1,26 @@ +/* + * Copyright © 2015 - 2016 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown + +object Groups { + def html(supergroups: Map[String, Seq[String]]) = { + supergroups.map { + case (_, groups) => + """" + }.mkString("\n") + } +} \ No newline at end of file diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala index 9e0d6822..be112d5b 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Writer.scala @@ -53,6 +53,12 @@ class Writer(serializer: Writer.Context => ToHtmlSerializer) { def writeNavigation(node: Node, context: Writer.Context): String = writeFragment(node, context) + /** + * Write groups fragment. + */ + def writeGroups(node: Node, context: Writer.Context): String = + writeFragment(node, context) + /** * Write navigation fragment. */ @@ -122,8 +128,7 @@ object Writer { CalloutDirective("warning", "Warning"), WrapDirective("div"), InlineWrapDirective("span"), - InlineGroupDirective(context.groups.values.flatten.map(_.toLowerCase).toSeq), - SupergroupDirective + InlineGroupDirective(context.groups.values.flatten.map(_.toLowerCase).toSeq) ) class DefaultLinkRenderer(context: Context) extends LinkRenderer { diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md index 128fb8df..03843ef4 100644 --- a/docs/src/main/paradox/features/snippet-inclusion.md +++ b/docs/src/main/paradox/features/snippet-inclusion.md @@ -70,12 +70,8 @@ $empty$ First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } $empty$ -@@supergroup { name=Language groups=scala,java } -$empty$ Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } $empty$ -Some separator. -$empty$ Second-java : @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } $empty$ @@ -92,8 +88,6 @@ First-java First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } -@@supergroup { name=Language groups=scala,java } - Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } Second-java diff --git a/themes/generic/src/main/assets/groups.st b/themes/generic/src/main/assets/groups.st new file mode 100644 index 00000000..7358d501 --- /dev/null +++ b/themes/generic/src/main/assets/groups.st @@ -0,0 +1 @@ +$page.groups$ \ No newline at end of file diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index fb94e02d..55cc24eb 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -1,7 +1,7 @@ $(function() { // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. - // Supergroups can be defined (such as 'languages', containing 'scala' and 'java') to initialize the group. + // The catalog of groups can be defined in the sbt parameters to initialize the group. var groupClass = "group"; var groupCookie = "groupsPref"; @@ -59,7 +59,7 @@ $(function() { var current; for(var i = 0; i < cookieTgList.length && !current; i++) { groups.each(function() { - var group = "group-" + $(this).text(); + var group = "group-" + $(this).text().toLowerCase(); if(group == cookieTgList[i]) current = group; }); diff --git a/themes/generic/src/main/assets/navigation.st b/themes/generic/src/main/assets/navigation.st index cd45efc5..6441077d 100644 --- a/themes/generic/src/main/assets/navigation.st +++ b/themes/generic/src/main/assets/navigation.st @@ -6,6 +6,7 @@ $page.properties.("project.version.short")$ +$groups()$ From 0a01685cf4153384084ad97d21e0bc3e3b34a82b Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Fri, 21 Apr 2017 10:43:03 +0200 Subject: [PATCH 08/14] Show group dropdown, default groups For snippets, the group now defaults to the type of snippet (e.g. java/scala). --- build.sbt | 1 + .../paradox/markdown/Directive.scala | 2 +- .../lightbend/paradox/markdown/Groups.scala | 4 +- .../markdown/InlineGroupDirectiveSpec.scala | 8 +- .../markdown/InlineWrapDirectiveSpec.scala | 8 +- .../paradox/markdown/SnipDirectiveSpec.scala | 81 +++++++++++++++++++ .../lightbend/paradox/markdown/example.scala | 23 ++++++ .../lightbend/paradox/markdown/example2.java | 25 ++++++ .../paradox/features/snippet-inclusion.md | 16 ++-- .../snippets/expected/configured-bases.html | 8 +- .../paradox/snippets/expected/multiple.html | 6 +- .../paradox/snippets/expected/nocode.html | 2 +- .../paradox/snippets/expected/reference.html | 4 +- .../paradox/snippets/expected/snippets.html | 8 +- .../paradox/snippets/expected/some-xml.html | 2 +- themes/generic/src/main/assets/js/page.js | 70 ++++++++++------ 16 files changed, 209 insertions(+), 59 deletions(-) create mode 100644 core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala create mode 100644 core/src/test/scala/com/lightbend/paradox/markdown/example.scala create mode 100644 core/src/test/scala/com/lightbend/paradox/markdown/example2.java diff --git a/build.sbt b/build.sbt index 73cde108..947ea341 100644 --- a/build.sbt +++ b/build.sbt @@ -107,6 +107,7 @@ lazy val docs = (project in file("docs")) name := "paradox docs", paradoxTheme := Some(builtinParadoxTheme("generic")), paradoxProperties in Compile += ("empty" -> "") + //paradoxGroups := Map("Languages" -> Seq("Scala", "Java")) ) addCommandAlias("verify", ";test ;scripted ;docs/paradox") diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index 506c9e1f..7c2f5698 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -311,7 +311,7 @@ case class SnipDirective(page: Page, variables: Map[String, String]) } else new File(page.file.getParentFile, source) val text = Snippet(file, labels) val lang = Option(node.attributes.value("type")).getOrElse(Snippet.language(file)) - val group = Option(node.attributes.value("group")).getOrElse("") + val group = Option(node.attributes.value("group")).getOrElse(lang) new VerbatimGroupNode(text, lang, group).accept(visitor) } catch { case e: FileNotFoundException => diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala index 78124e94..6ed09a14 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala @@ -20,7 +20,9 @@ object Groups { def html(supergroups: Map[String, Seq[String]]) = { supergroups.map { case (_, groups) => - """" + """" }.mkString("\n") } } \ No newline at end of file diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala index 4c60cf80..5eb97e69 100644 --- a/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala +++ b/core/src/test/scala/com/lightbend/paradox/markdown/InlineGroupDirectiveSpec.scala @@ -1,12 +1,12 @@ /* - * Copyright © 2015 - 2016 Lightbend, Inc. - * + * Copyright © 2015 - 2017 Lightbend, Inc. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala index 88522f51..b2a1db36 100644 --- a/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala +++ b/core/src/test/scala/com/lightbend/paradox/markdown/InlineWrapDirectiveSpec.scala @@ -1,12 +1,12 @@ /* - * Copyright © 2015 - 2016 Lightbend, Inc. - * + * Copyright © 2015 - 2017 Lightbend, Inc. + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala new file mode 100644 index 00000000..6ce58dbf --- /dev/null +++ b/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala @@ -0,0 +1,81 @@ +/* + * Copyright © 2015 - 2017 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown + +import com.lightbend.paradox.tree.Tree.Location + +class SnipDirectiveSpec extends MarkdownBaseSpec { + + val testProperties = Map("version" -> "1.2.3") + + implicit val context: Location[Page] => Writer.Context = { loc => + writerContext(loc).copy(properties = testProperties) + } + + "The `snip` directive" should "render code snippets" in { + markdown("""@@snip[example.scala](core/src/test/scala/com/lightbend/paradox/markdown/example.scala) {#example }""") shouldEqual html(""" + |
+      |
+      |object example extends App {
+      |  println("Hello, World!")
+      |}
+      |
""") + } + + it should "render code snippets in definition lists" in { + markdown(""" + |Scala + |: @@snip[example.scala](core/src/test/scala/com/lightbend/paradox/markdown/example.scala) { #example } + | + |Java + |: @@snip[example2.java](core/src/test/scala/com/lightbend/paradox/markdown/example2.java) { #example2 } + |""") shouldEqual html(""" + |
+ |
Scala
+ |
+ |
+      |
+      |object example extends App {
+      |  println("Hello, World!")
+      |}
+      |
+ |
+ |
Java
+ |
+ |
+      |
+      |public class example2 {
+      |    public static void main(String[] args) {
+      |        System.out.println("Hello, World");
+      |    }
+      |}
+      |
+ |
+ |
""") + } + + it should "support a custom id and custom CSS classes at the same time" in { + markdown(""" + |@@@ div { #yeah .red .blue } + |Simple sentence here. + |@@@""") shouldEqual html(""" + |
+ |

Simple sentence here.

+ |
""") + } + +} diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/example.scala b/core/src/test/scala/com/lightbend/paradox/markdown/example.scala new file mode 100644 index 00000000..943bcc64 --- /dev/null +++ b/core/src/test/scala/com/lightbend/paradox/markdown/example.scala @@ -0,0 +1,23 @@ +/* + * Copyright © 2015 - 2017 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown + +//#example +object example extends App { + println("Hello, World!") +} +//#example diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/example2.java b/core/src/test/scala/com/lightbend/paradox/markdown/example2.java new file mode 100644 index 00000000..384c3cd3 --- /dev/null +++ b/core/src/test/scala/com/lightbend/paradox/markdown/example2.java @@ -0,0 +1,25 @@ +/* + * Copyright © 2015 - 2017 Lightbend, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.lightbend.paradox.markdown; + +//#example2 +public class example2 { + public static void main(String[] args) { + System.out.println("Hello, World"); + } +} +//#example2 diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md index 03843ef4..1dde3e29 100644 --- a/docs/src/main/paradox/features/snippet-inclusion.md +++ b/docs/src/main/paradox/features/snippet-inclusion.md @@ -70,13 +70,13 @@ $empty$ First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } $empty$ -Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } +Some separator with text describing the @java[Java variant] @scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. The group defaults to the snippet language: $empty$ Second-java -: @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } +: @@snip [example-second.java](../../resources/tab-switching/examples.java) $empty$ Second-scala -: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) { #scala_second group=scala } +: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) ``` @@@ @@ -88,13 +88,13 @@ First-java First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } -Some separator with text describing the @span[Java variant] { .group-java } @span[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)] { .group-scala } +Some separator with text describing the @java[Java variant] @scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. The group defaults to the snippet language: -Second-java -: @@snip [example-second.java](../../resources/tab-switching/examples.java) { #java_second group=java } +Java +: @@snip [example-second.java](../../resources/tab-switching/examples.java) -Second-scala -: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) { #scala_second group=scala } +Scala +: @@snip [example-second.scala](../../resources/tab-switching/examples.scala) ### snip.*.base_dir diff --git a/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html b/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html index 8ad3a6b3..c10ce2ce 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html @@ -1,4 +1,4 @@ -
val foo = 42
-
val foo = 42
-
val foo = 42
-
val foo = 42
\ No newline at end of file +
val foo = 42
+
val foo = 42
+
val foo = 42
+
val foo = 42
\ No newline at end of file diff --git a/plugin/src/sbt-test/paradox/snippets/expected/multiple.html b/plugin/src/sbt-test/paradox/snippets/expected/multiple.html index 717998d5..b0d2865e 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/multiple.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/multiple.html @@ -1,10 +1,10 @@ -
import scala.concurrent.duration._
+
import scala.concurrent.duration._
 
 case class Measurement(method: Method, duration: Duration)
-
import scala.util.Try
+
import scala.util.Try
 
 def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
-
# HTTP Configuration
+
# HTTP Configuration
 http {
   port=80
   host=0.0.0.0
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/nocode.html b/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
index 6b838a24..5e9fb819 100644
--- a/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
+++ b/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
@@ -1,4 +1,4 @@
-
certpath: -Using checker7 ... [sun.security.provider.certpath.RevocationChecker]
+
certpath: -Using checker7 ... [sun.security.provider.certpath.RevocationChecker]
 certpath: connecting to OCSP service at: http://gtssl2-ocsp.geotrust.com
 certpath: OCSP response status: SUCCESSFUL
 certpath: OCSP response type: basic
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/reference.html b/plugin/src/sbt-test/paradox/snippets/expected/reference.html
index bdaab0f8..c96851aa 100644
--- a/plugin/src/sbt-test/paradox/snippets/expected/reference.html
+++ b/plugin/src/sbt-test/paradox/snippets/expected/reference.html
@@ -1,9 +1,9 @@
-
# This should be included
+
# This should be included
 #and this as well
 
 snippets {
   # this snip is a snap
   snip = "snap"
 }
-
# this snip is a snap
+
# this snip is a snap
 snip = "snap"
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/snippets.html b/plugin/src/sbt-test/paradox/snippets/expected/snippets.html index bc16abac..8a343915 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/snippets.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/snippets.html @@ -1,8 +1,8 @@ -
def indented = {
+
def indented = {
   1 + 2
 }
-
snippets {
+
snippets {
   test = 1
 }
-
val symbols = Seq('symbols, Symbol("@"), 'EOL)
-
val spacy = "Please do not remove ending spaces after these markers"
+
val symbols = Seq('symbols, Symbol("@"), 'EOL)
+
val spacy = "Please do not remove ending spaces after these markers"
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html b/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html index aa75dc31..8118450f 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html @@ -1,3 +1,3 @@ -
<bar>
+
<bar>
     XML FTW
 </bar>
diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 55cc24eb..a55dd0ea 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -3,7 +3,6 @@ $(function() { // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. // The catalog of groups can be defined in the sbt parameters to initialize the group. - var groupClass = "group"; var groupCookie = "groupsPref"; var cookieTg = getCookie(groupCookie); var cookieTgList = []; @@ -65,16 +64,22 @@ $(function() { }); } if (!current) { - current = "group-" + groups.first().text(); + current = "group-" + groups.first().text().toLowerCase(); cookieTgList = addToList(cookieTgList, current); } groups.each(function() { - var group = "group-" + $(this).text(); - if(group != current) { + var group = "group-" + $(this).text().toLowerCase(); + if(group == current) { + switchToGroup(this.value); + } else { $("span." + group).hide() } }); + + $(this).on("change", function() { + switchToGroup(this.value); + }); }); $("dl").has("dd > pre").each(function() { @@ -125,35 +130,48 @@ $(function() { var currentContent = currentDt.next("dd").addClass("current").show(); currentDl.css("height", currentDt.height() + currentContent.height()); } else { - $("span ." + currentGroup).show(); - $("dl").has("dd > pre").each(function() { - var dl = $(this); - dl.find("dt").each(function() { - var dt = $(this); - var pre = dt.next("dd").find("pre"); - if(pre.hasClass(currentGroup)) { - dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - dt.addClass("current"); - var currentContent = dt.next("dd").addClass("current").show(); - dl.css("height", dt.height() + currentContent.height()); - $("span." + currentGroup).show() - } else { - $("span." + groupOf(dt)).hide() - } - }); - }); + switchToGroup(currentGroup); } }); + function switchToGroup(group) { + // Cookie: + cookieTgList = addToList(cookieTgList, group); + setCookie(groupCookie, arrayToJson(cookieTgList)); + + // Dropdown switcher: + $("select") + .has("option[value=" + group +"]") + .val(group); + + // Inline snippets: + $("span ." + group).show(); + + // Tabbed snippets: + $("dl").has("dd > pre").each(function() { + var dl = $(this); + dl.find("dt").each(function() { + var dt = $(this); + var pre = dt.next("dd").find("pre"); + if(pre.hasClass(group)) { + dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); + dt.addClass("current"); + var currentContent = dt.next("dd").addClass("current").show(); + dl.css("height", dt.height() + currentContent.height()); + $("span." + group).show() + } else { + $("span." + groupOf(dt)).hide() + } + }); + }); + } + function groupOf(elem) { var currentClasses = elem.next("dd").find("pre").attr("class").split(' '); - var regex = new RegExp("^" + groupClass + "-.*"); + var regex = new RegExp("^group-.*"); for(var i = 0; i < currentClasses.length; i++) { if(regex.test(currentClasses[i])) { - var currentGroup = currentClasses[i]; - cookieTgList = addToList(cookieTgList, currentGroup); - setCookie(groupCookie, arrayToJson(cookieTgList)); - return currentGroup; + return currentClasses[i]; } } } From 27b9bfead589fe4739ca7bd8e3e07679eda5d12d Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Thu, 11 May 2017 10:56:02 +0200 Subject: [PATCH 09/14] Only switch groups declared in the configuration --- .../lightbend/paradox/ParadoxProcessor.scala | 2 + .../lightbend/paradox/markdown/Groups.scala | 4 +- themes/generic/src/main/assets/js/page.js | 92 +++++++++---------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala index ee272b18..64307e81 100644 --- a/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala +++ b/core/src/main/scala/com/lightbend/paradox/ParadoxProcessor.scala @@ -43,6 +43,8 @@ class ParadoxProcessor(reader: Reader = new Reader, writer: Writer = new Writer) navigationDepth: Int, pageTemplate: PageTemplate, errorListener: STErrorListener): Seq[(File, String)] = { + require(!groups.values.flatten.map(_.toLowerCase).groupBy(identity).values.exists(_.size > 1), "Group names may not overlap") + val pages = parsePages(mappings, Path.replaceSuffix(sourceSuffix, targetSuffix)) val paths = Page.allPaths(pages).toSet val globalPageMappings = rootPageMappings(pages) diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala index 6ed09a14..2a35feab 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Groups.scala @@ -19,8 +19,8 @@ package com.lightbend.paradox.markdown object Groups { def html(supergroups: Map[String, Seq[String]]) = { supergroups.map { - case (_, groups) => - """""" + groups.map(group => s"""""").mkString + "" }.mkString("\n") diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index a55dd0ea..283483af 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -3,11 +3,15 @@ $(function() { // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. // The catalog of groups can be defined in the sbt parameters to initialize the group. - var groupCookie = "groupsPref"; + var groupCookie = "paradoxGroups"; var cookieTg = getCookie(groupCookie); - var cookieTgList = []; + var currentGroups = {}; + + var catalog = {} + var supergroupByGroup = {}; + if(cookieTg != "") - cookieTgList = JSON.parse(cookieTg); + currentGroups = JSON.parse(cookieTg); // http://www.w3schools.com/js/js_cookies.asp function setCookie(cname,cvalue,exdays) { @@ -35,50 +39,31 @@ $(function() { return ""; } - function arrayToJson(arr) { - return JSON.stringify(arr); - } - - // http://stackoverflow.com/questions/12551635/jquery-remove-duplicates-from-an-array-of-strings/12551709#12551709 - function addToList(arr, elem) { - function unique(list) { - var result = []; - $.each(list, function(i, e) { - if ($.inArray(e, result) == -1) result.push(e); - }); - return result; - } - arr.unshift(elem); - return unique(arr); - } - $(".supergroup").each(function() { - var groups = $(this).find(".group") + var supergroup = $(this).attr('name').toLowerCase(); + var groups = $(this).find(".group"); - var current; - for(var i = 0; i < cookieTgList.length && !current; i++) { - groups.each(function() { - var group = "group-" + $(this).text().toLowerCase(); - if(group == cookieTgList[i]) - current = group; - }); - } + var current = currentGroups[supergroup]; if (!current) { current = "group-" + groups.first().text().toLowerCase(); - cookieTgList = addToList(cookieTgList, current); + currentGroups[supergroup] = current; } + catalog[supergroup] = []; + groups.each(function() { var group = "group-" + $(this).text().toLowerCase(); + catalog[supergroup].push(group); + supergroupByGroup[group] = supergroup; if(group == current) { - switchToGroup(this.value); + switchToGroup(supergroup, this.value); } else { $("span." + group).hide() } }); $(this).on("change", function() { - switchToGroup(this.value); + switchToGroup(supergroup, this.value); }); }); @@ -100,11 +85,11 @@ $(function() { }); var current; - for(var i = 0; i < cookieTgList.length && !current; i++) { + for (var supergroup in currentGroups) { dts.each(function() { var dt = $(this); var pre = dt.next("dd").find("pre"); - if(pre.hasClass(cookieTgList[i])) + if(pre.hasClass(currentGroups[supergroup])) current = dt.addClass("current"); }); } @@ -130,14 +115,18 @@ $(function() { var currentContent = currentDt.next("dd").addClass("current").show(); currentDl.css("height", currentDt.height() + currentContent.height()); } else { - switchToGroup(currentGroup); + var supergroup = supergroupByGroup[currentGroup] + if (supergroup) { + switchToGroup(supergroup, currentGroup); + } else { + switchToTab(currentDt); + } } }); - function switchToGroup(group) { - // Cookie: - cookieTgList = addToList(cookieTgList, group); - setCookie(groupCookie, arrayToJson(cookieTgList)); + function switchToGroup(supergroup, group) { + currentGroups[supergroup] = group; + setCookie(groupCookie, JSON.stringify(currentGroups)); // Dropdown switcher: $("select") @@ -145,7 +134,14 @@ $(function() { .val(group); // Inline snippets: - $("span ." + group).show(); + for (var i = 0; i < catalog[supergroup].length; i++) { + var peer = catalog[supergroup][i]; + if (peer == group) { + $("span." + group).show(); + } else { + $("span." + peer).hide(); + } + } // Tabbed snippets: $("dl").has("dd > pre").each(function() { @@ -154,18 +150,20 @@ $(function() { var dt = $(this); var pre = dt.next("dd").find("pre"); if(pre.hasClass(group)) { - dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - dt.addClass("current"); - var currentContent = dt.next("dd").addClass("current").show(); - dl.css("height", dt.height() + currentContent.height()); - $("span." + group).show() - } else { - $("span." + groupOf(dt)).hide() + switchToTab(dt); } }); }); } + function switchToTab(dt) { + var dl = dt.parent("dl"); + dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); + dt.addClass("current"); + var currentContent = dt.next("dd").addClass("current").show(); + dl.css("height", dt.height() + currentContent.height()); + } + function groupOf(elem) { var currentClasses = elem.next("dd").find("pre").attr("class").split(' '); var regex = new RegExp("^group-.*"); From be0bf4b51e42de74aaab02b237b9b51cfdf53230 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Thu, 11 May 2017 13:31:02 +0200 Subject: [PATCH 10/14] Also switch tabs which are not code snippets Though definition lists that don't contain any code snippets currently don't become tabs, this makes things a bit more robust. --- themes/generic/src/main/assets/js/page.js | 102 +++++++++------------- 1 file changed, 43 insertions(+), 59 deletions(-) diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 283483af..7848cd42 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -39,6 +39,30 @@ $(function() { return ""; } + $("dl").has("dd > pre").each(function() { + var dl = $(this); + dl.addClass("tabbed"); + var dts = dl.find("dt"); + dts.each(function(i) { + var dt = $(this); + dt.html("" + dt.text() + ""); + }); + var dds = dl.find("dd"); + dds.each(function(i) { + var dd = $(this); + dd.hide(); + if (dd.find("blockquote").length) { + dd.addClass("has-note"); + } + }); + + // Default to the first tab, for grouped tabs switch again later + switchToTab(dts.first()); + + dts.first().addClass("first"); + dts.last().addClass("last"); + }); + $(".supergroup").each(function() { var supergroup = $(this).attr('name').toLowerCase(); var groups = $(this).find(".group"); @@ -55,53 +79,15 @@ $(function() { var group = "group-" + $(this).text().toLowerCase(); catalog[supergroup].push(group); supergroupByGroup[group] = supergroup; - if(group == current) { - switchToGroup(supergroup, this.value); - } else { - $("span." + group).hide() - } }); + switchToGroup(supergroup, current); + $(this).on("change", function() { switchToGroup(supergroup, this.value); }); }); - $("dl").has("dd > pre").each(function() { - var dl = $(this); - dl.addClass("tabbed"); - var dts = dl.find("dt"); - dts.each(function(i) { - var dt = $(this); - dt.html("" + dt.text() + ""); - }); - var dds = dl.find("dd"); - dds.each(function(i) { - var dd = $(this); - dd.hide(); - if (dd.find("blockquote").length) { - dd.addClass("has-note"); - } - }); - - var current; - for (var supergroup in currentGroups) { - dts.each(function() { - var dt = $(this); - var pre = dt.next("dd").find("pre"); - if(pre.hasClass(currentGroups[supergroup])) - current = dt.addClass("current"); - }); - } - - if(!current) - current = dts.first().addClass("current"); - var currentContent = current.next("dd").addClass("current").show(); - dts.first().addClass("first"); - dts.last().addClass("last"); - dl.css("height", current.height() + currentContent.height()); - }); - $("dl.tabbed dt a").click(function(e){ e.preventDefault(); var currentDt = $(this).parent("dt"); @@ -109,18 +95,11 @@ $(function() { var currentGroup = groupOf(currentDt); - if(!currentGroup) { - currentDl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - currentDt.addClass("current"); - var currentContent = currentDt.next("dd").addClass("current").show(); - currentDl.css("height", currentDt.height() + currentContent.height()); + var supergroup = supergroupByGroup[currentGroup] + if (supergroup) { + switchToGroup(supergroup, currentGroup); } else { - var supergroup = supergroupByGroup[currentGroup] - if (supergroup) { - switchToGroup(supergroup, currentGroup); - } else { - switchToTab(currentDt); - } + switchToTab(currentDt); } }); @@ -144,12 +123,11 @@ $(function() { } // Tabbed snippets: - $("dl").has("dd > pre").each(function() { + $("dl.tabbed").each(function() { var dl = $(this); dl.find("dt").each(function() { var dt = $(this); - var pre = dt.next("dd").find("pre"); - if(pre.hasClass(group)) { + if(groupOf(dt) == group) { switchToTab(dt); } }); @@ -165,12 +143,18 @@ $(function() { } function groupOf(elem) { - var currentClasses = elem.next("dd").find("pre").attr("class").split(' '); - var regex = new RegExp("^group-.*"); - for(var i = 0; i < currentClasses.length; i++) { - if(regex.test(currentClasses[i])) { - return currentClasses[i]; + var classAttribute = elem.next("dd").find("pre").attr("class"); + if (classAttribute) { + var currentClasses = classAttribute.split(' '); + var regex = new RegExp("^group-.*"); + for(var i = 0; i < currentClasses.length; i++) { + if(regex.test(currentClasses[i])) { + return currentClasses[i]; + } } } + + // No class found? Then use the tab title + return "group-" + elem.find('a').text().toLowerCase(); } }); From 13de02ae02c79cfe36cd20ee1af777389a016493 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Fri, 12 May 2017 00:24:22 +0200 Subject: [PATCH 11/14] Documentation section for groups --- docs/src/main/paradox/features/groups.md | 72 +++++++++++++++++++ .../paradox/features/snippet-inclusion.md | 15 ++-- docs/src/main/paradox/index.md | 1 + 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 docs/src/main/paradox/features/groups.md diff --git a/docs/src/main/paradox/features/groups.md b/docs/src/main/paradox/features/groups.md new file mode 100644 index 00000000..fac0b400 --- /dev/null +++ b/docs/src/main/paradox/features/groups.md @@ -0,0 +1,72 @@ +Groups +------ + +Paradox supports 'groups' which allow users to easily switch between different +'variations' of the documentation. + +## Configuration + +Groups must be configured through sbt: + +``` +.enablePlugins(NoPublish, ParadoxPlugin) + .settings( + name := "paradox docs", + paradoxTheme := Some(builtinParadoxTheme("generic")), + paradoxGroups := Map("Languages" -> Seq("Scala", "Java")) + ) +``` + +## Syntax + +### Tabs + +Groups are used for tabs: + +Java +: @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first } + +Scala +: @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first } + +And will synchronize: + +Java +: @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first } + +Scala +: @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first } + + +But tabs not associated with groups are left alone: + +sbt +: @@snip [build.sbt](../../resources/build.sbt) { #setup_example } + +Maven +: @@snip [pom.xml](../../resources/pom.xml) { #setup_example } + +Gradle +: Non-snippet tab body + + +### Inline + +For each group a directive is automatically created. This can be used for +switching inline text: + +``` +Text describing the @java[Java variant]@scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. +``` + +Text describing the @java[Java variant]@scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. + + +## Behavior + +Switching is currently done in javascript. When the page loads, a script in +`page.js` looks for entities with class `supergroup` and derives the groups +catalog from that. If you use a custom theme, use `$groups()$` to generate +the catalog in javascript. + +The currently selected group for each category is stored in a cookie. diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md index 1dde3e29..0eff4c47 100644 --- a/docs/src/main/paradox/features/snippet-inclusion.md +++ b/docs/src/main/paradox/features/snippet-inclusion.md @@ -70,12 +70,12 @@ $empty$ First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } $empty$ -Some separator with text describing the @java[Java variant] @scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. The group defaults to the snippet language: +Some separator. $empty$ -Second-java +Java : @@snip [example-second.java](../../resources/tab-switching/examples.java) $empty$ -Second-scala +Scala : @@snip [example-second.scala](../../resources/tab-switching/examples.scala) ``` @@@ @@ -88,7 +88,7 @@ First-java First-scala : @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala } -Some separator with text describing the @java[Java variant] @scala[Scala variant containing ***markdown*** and @ref:[Linking](linking.md)]. The group defaults to the snippet language: +Some separator. Java : @@snip [example-second.java](../../resources/tab-switching/examples.java) @@ -96,6 +96,13 @@ Java Scala : @@snip [example-second.scala](../../resources/tab-switching/examples.scala) +This is also synced if some tabs have no snippet: + +Java +: @@snip [example-second.java](../../resources/tab-switching/examples.java) + +Scala +: More inline tabbing ### snip.*.base_dir diff --git a/docs/src/main/paradox/index.md b/docs/src/main/paradox/index.md index bad7321b..46d102de 100644 --- a/docs/src/main/paradox/index.md +++ b/docs/src/main/paradox/index.md @@ -54,6 +54,7 @@ which basically means that all of our extensions would start with `@` (for inlin * [Multi Configuration](features/multi-configuration.md) * [Organizing pages](features/organizing-pages.md) * [Linking](features/linking.md) +* [Groups](features/groups.md) * [Snippet inclusion](features/snippet-inclusion.md) * [Callouts](features/callouts.md) * [CSS Friendliness](features/css-friendliness.md) From 4cf24e5487faa0d3e50643ac38b04501eec9927b Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Fri, 12 May 2017 00:55:09 +0200 Subject: [PATCH 12/14] Don't autogenerate 'group' attribute, prefer tab name --- .../paradox/markdown/Directive.scala | 4 +-- .../paradox/markdown/SnipDirectiveSpec.scala | 6 ++-- docs/src/main/paradox/features/groups.md | 28 ++++++++++++++++--- .../paradox/features/snippet-inclusion.md | 6 ++-- .../snippets/expected/configured-bases.html | 8 +++--- .../paradox/snippets/expected/multiple.html | 6 ++-- .../paradox/snippets/expected/nocode.html | 2 +- .../paradox/snippets/expected/reference.html | 4 +-- .../paradox/snippets/expected/snippets.html | 8 +++--- .../paradox/snippets/expected/some-xml.html | 2 +- 10 files changed, 47 insertions(+), 27 deletions(-) diff --git a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala index 7c2f5698..8d42001d 100644 --- a/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala +++ b/core/src/main/scala/com/lightbend/paradox/markdown/Directive.scala @@ -311,7 +311,7 @@ case class SnipDirective(page: Page, variables: Map[String, String]) } else new File(page.file.getParentFile, source) val text = Snippet(file, labels) val lang = Option(node.attributes.value("type")).getOrElse(Snippet.language(file)) - val group = Option(node.attributes.value("group")).getOrElse(lang) + val group = Option(node.attributes.value("group")).getOrElse("") new VerbatimGroupNode(text, lang, group).accept(visitor) } catch { case e: FileNotFoundException => @@ -504,4 +504,4 @@ case class InlineGroupDirective(groups: Seq[String]) extends InlineDirective(gro node.contentsNode.accept(visitor) printer.print(s"") } -} \ No newline at end of file +} diff --git a/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala b/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala index 6ce58dbf..b3d6dc4e 100644 --- a/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala +++ b/core/src/test/scala/com/lightbend/paradox/markdown/SnipDirectiveSpec.scala @@ -28,7 +28,7 @@ class SnipDirectiveSpec extends MarkdownBaseSpec { "The `snip` directive" should "render code snippets" in { markdown("""@@snip[example.scala](core/src/test/scala/com/lightbend/paradox/markdown/example.scala) {#example }""") shouldEqual html(""" - |
+      |
       |
       |object example extends App {
       |  println("Hello, World!")
@@ -47,7 +47,7 @@ class SnipDirectiveSpec extends MarkdownBaseSpec {
       |
|
Scala
|
- |
+      |
       |
       |object example extends App {
       |  println("Hello, World!")
@@ -56,7 +56,7 @@ class SnipDirectiveSpec extends MarkdownBaseSpec {
       |
|
Java
|
- |
+      |
       |
       |public class example2 {
       |    public static void main(String[] args) {
diff --git a/docs/src/main/paradox/features/groups.md b/docs/src/main/paradox/features/groups.md
index fac0b400..58a2934b 100644
--- a/docs/src/main/paradox/features/groups.md
+++ b/docs/src/main/paradox/features/groups.md
@@ -21,15 +21,17 @@ Groups must be configured through sbt:
 
 ### Tabs
 
-Groups are used for tabs:
+Groups are used for tabs, where the group is determined by the tab name:
 
+@@@vars
+```markdown
 Java
 :   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first }
-
+$empty$
 Scala
 :   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first }
-
-And will synchronize:
+```
+@@@
 
 Java
 :   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first }
@@ -37,6 +39,24 @@ Java
 Scala
 :   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first }
 
+or by the group parameter on the snippet:
+
+@@@vars
+```markdown
+example-first.java
+:   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first group=java }
+$empty$
+example-first.scala
+:   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala }
+```
+@@@
+
+example-first.java
+:   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first group=java }
+
+example-first.scala
+:   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala }
+
 
 But tabs not associated with groups are left alone:
 
diff --git a/docs/src/main/paradox/features/snippet-inclusion.md b/docs/src/main/paradox/features/snippet-inclusion.md
index 0eff4c47..48995577 100644
--- a/docs/src/main/paradox/features/snippet-inclusion.md
+++ b/docs/src/main/paradox/features/snippet-inclusion.md
@@ -60,15 +60,15 @@ should not be highlighted set `type=text` in the directive's attribute section:
 
 #### tab switching
 
-It is possible to associate multiple snippets under the same "tag". If some tab of a snippet is switched by the user, all tabs associated with the selected one will be switched as well. To associate snippet tabs under some tag, set the `group` field of the snippet:
+It is possible to associate multiple snippets under the same "tag". If some tab of a snippet is switched by the user, all tabs associated with the selected one will be switched as well.
 
 @@@vars
 ```markdown
 First-java
-:   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first group=java }
+:   @@snip [example-first.java](../../resources/tab-switching/examples.java) { #java_first }
 $empty$
 First-scala
-:   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first group=scala }
+:   @@snip [example-first.scala](../../resources/tab-switching/examples.scala) { #scala_first }
 $empty$
 Some separator.
 $empty$
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html b/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html
index c10ce2ce..8ad3a6b3 100644
--- a/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html
+++ b/plugin/src/sbt-test/paradox/snippets/expected/configured-bases.html
@@ -1,4 +1,4 @@
-
val foo = 42
-
val foo = 42
-
val foo = 42
-
val foo = 42
\ No newline at end of file +
val foo = 42
+
val foo = 42
+
val foo = 42
+
val foo = 42
\ No newline at end of file diff --git a/plugin/src/sbt-test/paradox/snippets/expected/multiple.html b/plugin/src/sbt-test/paradox/snippets/expected/multiple.html index b0d2865e..717998d5 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/multiple.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/multiple.html @@ -1,10 +1,10 @@ -
import scala.concurrent.duration._
+
import scala.concurrent.duration._
 
 case class Measurement(method: Method, duration: Duration)
-
import scala.util.Try
+
import scala.util.Try
 
 def parseInt(s: String): Option[Int] = Try(s.toInt).toOption
-
# HTTP Configuration
+
# HTTP Configuration
 http {
   port=80
   host=0.0.0.0
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/nocode.html b/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
index 5e9fb819..6b838a24 100644
--- a/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
+++ b/plugin/src/sbt-test/paradox/snippets/expected/nocode.html
@@ -1,4 +1,4 @@
-
certpath: -Using checker7 ... [sun.security.provider.certpath.RevocationChecker]
+
certpath: -Using checker7 ... [sun.security.provider.certpath.RevocationChecker]
 certpath: connecting to OCSP service at: http://gtssl2-ocsp.geotrust.com
 certpath: OCSP response status: SUCCESSFUL
 certpath: OCSP response type: basic
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/reference.html b/plugin/src/sbt-test/paradox/snippets/expected/reference.html
index c96851aa..bdaab0f8 100644
--- a/plugin/src/sbt-test/paradox/snippets/expected/reference.html
+++ b/plugin/src/sbt-test/paradox/snippets/expected/reference.html
@@ -1,9 +1,9 @@
-
# This should be included
+
# This should be included
 #and this as well
 
 snippets {
   # this snip is a snap
   snip = "snap"
 }
-
# this snip is a snap
+
# this snip is a snap
 snip = "snap"
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/snippets.html b/plugin/src/sbt-test/paradox/snippets/expected/snippets.html index 8a343915..bc16abac 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/snippets.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/snippets.html @@ -1,8 +1,8 @@ -
def indented = {
+
def indented = {
   1 + 2
 }
-
snippets {
+
snippets {
   test = 1
 }
-
val symbols = Seq('symbols, Symbol("@"), 'EOL)
-
val spacy = "Please do not remove ending spaces after these markers"
+
val symbols = Seq('symbols, Symbol("@"), 'EOL)
+
val spacy = "Please do not remove ending spaces after these markers"
diff --git a/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html b/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html index 8118450f..aa75dc31 100644 --- a/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html +++ b/plugin/src/sbt-test/paradox/snippets/expected/some-xml.html @@ -1,3 +1,3 @@ -
<bar>
+
<bar>
     XML FTW
 </bar>
From 637831b52da4f1013a747ecd073c2ef0ce7cfb47 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Fri, 12 May 2017 01:36:13 +0200 Subject: [PATCH 13/14] Allow extending group switch functionality --- docs/src/main/paradox/features/groups.md | 12 +++++++++++- themes/generic/src/main/assets/js/page.js | 13 ++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/src/main/paradox/features/groups.md b/docs/src/main/paradox/features/groups.md index 58a2934b..8347e450 100644 --- a/docs/src/main/paradox/features/groups.md +++ b/docs/src/main/paradox/features/groups.md @@ -86,7 +86,17 @@ Text describing the @java[Java variant]@scala[Scala variant containing ***markdo Switching is currently done in javascript. When the page loads, a script in `page.js` looks for entities with class `supergroup` and derives the groups -catalog from that. If you use a custom theme, use `$groups()$` to generate +catalog from that. If you use a custom theme, use `$page.groups$` to generate the catalog in javascript. The currently selected group for each category is stored in a cookie. + +## Extending + +You can register an event listener that will be called whenever a group is switched: + +``` +window.groupChanged(function(group, supergroup, catalog) { + // your code here +}); +``` \ No newline at end of file diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 7848cd42..20565f23 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -1,3 +1,9 @@ +groupChangeListeners = []; + +window.groupChanged = function(callback) { + groupChangeListeners.push(callback); +} + $(function() { // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. @@ -10,6 +16,7 @@ $(function() { var catalog = {} var supergroupByGroup = {}; + if(cookieTg != "") currentGroups = JSON.parse(cookieTg); @@ -132,6 +139,10 @@ $(function() { } }); }); + + for (var i = 0; i < groupChangeListeners.length; i++) { + groupChangeListeners[i](group, supergroup, catalog); + } } function switchToTab(dt) { @@ -157,4 +168,4 @@ $(function() { // No class found? Then use the tab title return "group-" + elem.find('a').text().toLowerCase(); } -}); +}); \ No newline at end of file From 7f55c0c71bfbfc6a987c2693b19dcbb74c9dc9a3 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Fri, 12 May 2017 01:46:30 +0200 Subject: [PATCH 14/14] Put groups/tabs logic in its own .js file --- themes/generic/src/main/assets/js/groups.js | 171 ++++++++++++++++++++ themes/generic/src/main/assets/js/page.js | 169 ------------------- themes/generic/src/main/assets/page.st | 1 + 3 files changed, 172 insertions(+), 169 deletions(-) create mode 100644 themes/generic/src/main/assets/js/groups.js diff --git a/themes/generic/src/main/assets/js/groups.js b/themes/generic/src/main/assets/js/groups.js new file mode 100644 index 00000000..20565f23 --- /dev/null +++ b/themes/generic/src/main/assets/js/groups.js @@ -0,0 +1,171 @@ +groupChangeListeners = []; + +window.groupChanged = function(callback) { + groupChangeListeners.push(callback); +} + +$(function() { + + // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. + // The catalog of groups can be defined in the sbt parameters to initialize the group. + + var groupCookie = "paradoxGroups"; + var cookieTg = getCookie(groupCookie); + var currentGroups = {}; + + var catalog = {} + var supergroupByGroup = {}; + + + if(cookieTg != "") + currentGroups = JSON.parse(cookieTg); + + // http://www.w3schools.com/js/js_cookies.asp + function setCookie(cname,cvalue,exdays) { + if(!exdays) exdays = 365; + var d = new Date(); + d.setTime(d.getTime() + (exdays*24*60*60*1000)); + var expires = "expires=" + d.toGMTString(); + document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; + } + + // http://www.w3schools.com/js/js_cookies.asp + function getCookie(cname) { + var name = cname + "="; + var decodedCookie = decodeURIComponent(document.cookie); + var ca = decodedCookie.split(';'); + for(var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == ' ') { + c = c.substring(1); + } + if (c.indexOf(name) == 0) { + return c.substring(name.length, c.length); + } + } + return ""; + } + + $("dl").has("dd > pre").each(function() { + var dl = $(this); + dl.addClass("tabbed"); + var dts = dl.find("dt"); + dts.each(function(i) { + var dt = $(this); + dt.html("" + dt.text() + ""); + }); + var dds = dl.find("dd"); + dds.each(function(i) { + var dd = $(this); + dd.hide(); + if (dd.find("blockquote").length) { + dd.addClass("has-note"); + } + }); + + // Default to the first tab, for grouped tabs switch again later + switchToTab(dts.first()); + + dts.first().addClass("first"); + dts.last().addClass("last"); + }); + + $(".supergroup").each(function() { + var supergroup = $(this).attr('name').toLowerCase(); + var groups = $(this).find(".group"); + + var current = currentGroups[supergroup]; + if (!current) { + current = "group-" + groups.first().text().toLowerCase(); + currentGroups[supergroup] = current; + } + + catalog[supergroup] = []; + + groups.each(function() { + var group = "group-" + $(this).text().toLowerCase(); + catalog[supergroup].push(group); + supergroupByGroup[group] = supergroup; + }); + + switchToGroup(supergroup, current); + + $(this).on("change", function() { + switchToGroup(supergroup, this.value); + }); + }); + + $("dl.tabbed dt a").click(function(e){ + e.preventDefault(); + var currentDt = $(this).parent("dt"); + var currentDl = currentDt.parent("dl"); + + var currentGroup = groupOf(currentDt); + + var supergroup = supergroupByGroup[currentGroup] + if (supergroup) { + switchToGroup(supergroup, currentGroup); + } else { + switchToTab(currentDt); + } + }); + + function switchToGroup(supergroup, group) { + currentGroups[supergroup] = group; + setCookie(groupCookie, JSON.stringify(currentGroups)); + + // Dropdown switcher: + $("select") + .has("option[value=" + group +"]") + .val(group); + + // Inline snippets: + for (var i = 0; i < catalog[supergroup].length; i++) { + var peer = catalog[supergroup][i]; + if (peer == group) { + $("span." + group).show(); + } else { + $("span." + peer).hide(); + } + } + + // Tabbed snippets: + $("dl.tabbed").each(function() { + var dl = $(this); + dl.find("dt").each(function() { + var dt = $(this); + if(groupOf(dt) == group) { + switchToTab(dt); + } + }); + }); + + for (var i = 0; i < groupChangeListeners.length; i++) { + groupChangeListeners[i](group, supergroup, catalog); + } + } + + function switchToTab(dt) { + var dl = dt.parent("dl"); + dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); + dt.addClass("current"); + var currentContent = dt.next("dd").addClass("current").show(); + dl.css("height", dt.height() + currentContent.height()); + } + + function groupOf(elem) { + var classAttribute = elem.next("dd").find("pre").attr("class"); + if (classAttribute) { + var currentClasses = classAttribute.split(' '); + var regex = new RegExp("^group-.*"); + for(var i = 0; i < currentClasses.length; i++) { + if(regex.test(currentClasses[i])) { + return currentClasses[i]; + } + } + } + + // No class found? Then use the tab title + return "group-" + elem.find('a').text().toLowerCase(); + } +}); \ No newline at end of file diff --git a/themes/generic/src/main/assets/js/page.js b/themes/generic/src/main/assets/js/page.js index 20565f23..cb2ef674 100644 --- a/themes/generic/src/main/assets/js/page.js +++ b/themes/generic/src/main/assets/js/page.js @@ -1,171 +1,2 @@ -groupChangeListeners = []; - -window.groupChanged = function(callback) { - groupChangeListeners.push(callback); -} - $(function() { - - // Groups (like 'java' and 'scala') represent groups of 'switchable' content, either in tabs or in regular text. - // The catalog of groups can be defined in the sbt parameters to initialize the group. - - var groupCookie = "paradoxGroups"; - var cookieTg = getCookie(groupCookie); - var currentGroups = {}; - - var catalog = {} - var supergroupByGroup = {}; - - - if(cookieTg != "") - currentGroups = JSON.parse(cookieTg); - - // http://www.w3schools.com/js/js_cookies.asp - function setCookie(cname,cvalue,exdays) { - if(!exdays) exdays = 365; - var d = new Date(); - d.setTime(d.getTime() + (exdays*24*60*60*1000)); - var expires = "expires=" + d.toGMTString(); - document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; - } - - // http://www.w3schools.com/js/js_cookies.asp - function getCookie(cname) { - var name = cname + "="; - var decodedCookie = decodeURIComponent(document.cookie); - var ca = decodedCookie.split(';'); - for(var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == ' ') { - c = c.substring(1); - } - if (c.indexOf(name) == 0) { - return c.substring(name.length, c.length); - } - } - return ""; - } - - $("dl").has("dd > pre").each(function() { - var dl = $(this); - dl.addClass("tabbed"); - var dts = dl.find("dt"); - dts.each(function(i) { - var dt = $(this); - dt.html("" + dt.text() + ""); - }); - var dds = dl.find("dd"); - dds.each(function(i) { - var dd = $(this); - dd.hide(); - if (dd.find("blockquote").length) { - dd.addClass("has-note"); - } - }); - - // Default to the first tab, for grouped tabs switch again later - switchToTab(dts.first()); - - dts.first().addClass("first"); - dts.last().addClass("last"); - }); - - $(".supergroup").each(function() { - var supergroup = $(this).attr('name').toLowerCase(); - var groups = $(this).find(".group"); - - var current = currentGroups[supergroup]; - if (!current) { - current = "group-" + groups.first().text().toLowerCase(); - currentGroups[supergroup] = current; - } - - catalog[supergroup] = []; - - groups.each(function() { - var group = "group-" + $(this).text().toLowerCase(); - catalog[supergroup].push(group); - supergroupByGroup[group] = supergroup; - }); - - switchToGroup(supergroup, current); - - $(this).on("change", function() { - switchToGroup(supergroup, this.value); - }); - }); - - $("dl.tabbed dt a").click(function(e){ - e.preventDefault(); - var currentDt = $(this).parent("dt"); - var currentDl = currentDt.parent("dl"); - - var currentGroup = groupOf(currentDt); - - var supergroup = supergroupByGroup[currentGroup] - if (supergroup) { - switchToGroup(supergroup, currentGroup); - } else { - switchToTab(currentDt); - } - }); - - function switchToGroup(supergroup, group) { - currentGroups[supergroup] = group; - setCookie(groupCookie, JSON.stringify(currentGroups)); - - // Dropdown switcher: - $("select") - .has("option[value=" + group +"]") - .val(group); - - // Inline snippets: - for (var i = 0; i < catalog[supergroup].length; i++) { - var peer = catalog[supergroup][i]; - if (peer == group) { - $("span." + group).show(); - } else { - $("span." + peer).hide(); - } - } - - // Tabbed snippets: - $("dl.tabbed").each(function() { - var dl = $(this); - dl.find("dt").each(function() { - var dt = $(this); - if(groupOf(dt) == group) { - switchToTab(dt); - } - }); - }); - - for (var i = 0; i < groupChangeListeners.length; i++) { - groupChangeListeners[i](group, supergroup, catalog); - } - } - - function switchToTab(dt) { - var dl = dt.parent("dl"); - dl.find(".current").removeClass("current").next("dd").removeClass("current").hide(); - dt.addClass("current"); - var currentContent = dt.next("dd").addClass("current").show(); - dl.css("height", dt.height() + currentContent.height()); - } - - function groupOf(elem) { - var classAttribute = elem.next("dd").find("pre").attr("class"); - if (classAttribute) { - var currentClasses = classAttribute.split(' '); - var regex = new RegExp("^group-.*"); - for(var i = 0; i < currentClasses.length; i++) { - if(regex.test(currentClasses[i])) { - return currentClasses[i]; - } - } - } - - // No class found? Then use the tab title - return "group-" + elem.find('a').text().toLowerCase(); - } }); \ No newline at end of file diff --git a/themes/generic/src/main/assets/page.st b/themes/generic/src/main/assets/page.st index 1cc6ac9a..0bec374c 100644 --- a/themes/generic/src/main/assets/page.st +++ b/themes/generic/src/main/assets/page.st @@ -9,6 +9,7 @@ +