diff --git a/cmd/present/static/styles.css b/cmd/present/static/styles.css index 2d8d3544d1e..91b8bca80c8 100644 --- a/cmd/present/static/styles.css +++ b/cmd/present/static/styles.css @@ -532,3 +532,12 @@ figcaption { -moz-border-radius: 10px; -webkit-border-radius: 10px; } + +blockquote { + padding: 5px 20px; + border-left: 5px solid #999; +} +blockquote cite { + font-size: 85%; + color: #999; +} diff --git a/cmd/present/templates/action.tmpl b/cmd/present/templates/action.tmpl index 8bde042c90b..ad752cc9c3a 100644 --- a/cmd/present/templates/action.tmpl +++ b/cmd/present/templates/action.tmpl @@ -60,3 +60,10 @@ It determines how the formatting actions are rendered. {{define "html"}}{{.HTML}}{{end}} {{define "caption"}}
{{style .Text}}
{{end}} + +{{define "quote"}} +
+

{{style .Text}}

+ {{with .Citation}}— {{style .}}{{end}} +
+{{end}} diff --git a/present/doc.go b/present/doc.go index 45039b646d2..cf3fcfc3c16 100644 --- a/present/doc.go +++ b/present/doc.go @@ -63,6 +63,7 @@ After that come slides/sections, each after a blank line: .link http://foo label .html file.html .caption _Gopher_ by [[https://www.instagram.com/reneefrench/][Renée French]] + .quote Never memorize something that you can look up //CITATION: Albert Einstein Again, more text @@ -214,6 +215,16 @@ processing styling and links as in standard text lines. .caption _Gopher_ by [[http://www.reneefrench.com][Renée French]] +quote: + +The template uses the function "quote" to inject quotes and citations. + +The text after ".quote" is embedded in a blockquote element after +processing styling. The text after the optional "//CITATION:" is treated +as a citation and embedded in a cite element after processing styling. + + .quote Never memorize something that you can look up //CITATION: Albert Einstein + iframe: The function "iframe" injects iframes (pages inside pages). diff --git a/present/quote.go b/present/quote.go new file mode 100644 index 00000000000..d47b6a7ab92 --- /dev/null +++ b/present/quote.go @@ -0,0 +1,50 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package present + +import ( + "fmt" + "strings" +) + +func init() { + Register("quote", parseQuote) +} + +type Quote struct { + Text string + Citation string +} + +func (c Quote) TemplateName() string { return "quote" } + +const citationToken = "//CITATION:" + +// parseQuote parses a quote present directive. Its syntax: +// .quote [citation] +func parseQuote(_ *Context, sourceFile string, sourceLine int, cmd string) (Elem, error) { + + cmd = strings.TrimSpace(strings.TrimPrefix(cmd, ".quote")) + + tokens := strings.Split(cmd, citationToken) + + text := strings.TrimSpace(strings.TrimPrefix(tokens[0], ".quote")) + citation := "" + + if text == "" { + return nil, fmt.Errorf("%s:%d invalid quote syntax", sourceFile, sourceLine) + } + + if len(tokens) == 1 { + return Quote{text, citation}, nil + } + + citation = strings.TrimSpace(tokens[1]) + if citation == "" || len(tokens) > 2 { + return nil, fmt.Errorf("%s:%d invalid citation syntax", sourceFile, sourceLine) + } + + return Quote{text, citation}, nil +} diff --git a/present/quote_test.go b/present/quote_test.go new file mode 100644 index 00000000000..f260a81c049 --- /dev/null +++ b/present/quote_test.go @@ -0,0 +1,78 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package present + +import ( + "strings" + "testing" +) + +func TestQuoteParsing(t *testing.T) { + var tests = []struct { + name string + cmd string + err string + Quote + }{ + { + name: "quote with invalid citation syntax", + cmd: ".quote a quote //CITATION: ", + err: "invalid citation syntax", + }, + { + name: "quote without text and valid citation", + cmd: ".quote //CITATION: citation", + err: "invalid quote syntax", + }, + { + name: "quote with text", + cmd: ".quote some text", + Quote: Quote{ + Text: "some text", + Citation: "", + }, + }, + { + name: "quote with text and citation", + cmd: ".quote some text //CITATION: other text", + Quote: Quote{ + Text: "some text", + Citation: "other text", + }, + }, + } + + for _, test := range tests { + element, err := parseQuote(nil, "test.slide", 0, test.cmd) + + if err != nil { + if test.err == "" { + t.Errorf("%s: unexpected error %v", test.name, err) + } else if !strings.Contains(err.Error(), test.err) { + t.Errorf("%s: expected error %s; got %v", test.name, test.err, err) + } + continue + } + + if test.err != "" { + t.Errorf("%s: expected error %s; but got none", test.name, test.err) + continue + } + + quote, ok := element.(Quote) + if !ok { + t.Errorf("%s: expected a Code value; got %T", test.name, quote) + continue + } + + if quote.Text != test.Text { + t.Errorf("%s: expected Text %s; got %s", test.name, test.Text, quote.Text) + } + + if quote.Citation != test.Citation { + t.Errorf("%s: expected Citation %s; got %s", test.name, test.Citation, quote.Citation) + } + } +}