Skip to content

Commit dadd331

Browse files
committed
Added "xml" as a new template file type (for e.g. RSS feeds and sitemaps).
Added functions: echoSmart(), gmatchAndBetween(), isValueHtml(), clampArray(), summarize(). Added site.description, page.description and page.dateModified . Added and exposed UTF-8 module. Added RSS feed and sitemap examples. Removed page.rssLink (which was never used). XML: Added contentsToXml() and contentsToHtml(). XML: walk() now accepts traversal actions.
1 parent 4b3d6ad commit dadd331

File tree

13 files changed

+554
-152
lines changed

13 files changed

+554
-152
lines changed

src/app.lua2p

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ local function setup()
339339
-- Lua libraries.
340340
json = jsonLib,
341341
lfs = lfs,
342+
utf8 = utf8, -- @Doc
342343
xml = xmlLib,
343344

344345
toml = { -- @Cleanup: Don't use 3rd party TOML library.
@@ -369,9 +370,11 @@ local function setup()
369370
generatorMeta = generatorMeta,
370371
getFilename = getFilename,
371372
getKeys = getKeys,
373+
gmatchAndBetween = gmatchAndBetween, -- @Doc
372374
indexOf = indexOf,
373375
ipairsr = ipairsr,
374376
isAny = isAny,
377+
isValueHtml = doesValueLookLikeHtml, -- @Doc
375378
markdown = markdownToHtml,
376379
max = math.max,
377380
min = math.min,
@@ -713,12 +716,140 @@ local function setup()
713716
return _dataParsers
714717
end,
715718

719+
-- array = function( array, length ) -- @Doc
720+
clampArray = function(t, len)
721+
for i = #t, len+1, -1 do
722+
t[i] = nil
723+
end
724+
return t
725+
end,
726+
727+
-- html = summarize( html, maxCharacters [, keepAnchorsAndImages=false ] ) -- @Doc
728+
summarize = function(html, maxChars, keepSomeElements)
729+
html = "<div>" .. html .. "</div>"
730+
local doc = assert(xmlLib.parseHtml(html))
731+
local protected
732+
733+
-- Protect certain things, like links.
734+
if keepSomeElements then
735+
protected = {--[[ element1, ... ]]}
736+
737+
xmlLib.walk(doc, false, function(tag, el)
738+
for i, childNode in ipairs(el) do
739+
if xmlLib.isText(childNode) then
740+
-- void
741+
742+
elseif childNode.tag == "a" and childNode.attr.href and not childNode.attr.href:find"^javascript:" then
743+
table.insert(protected, xmlLib.element("a", {href=childNode.attr.href, childNode:getText()}))
744+
el[i] = "$$PLACEHOLDER" .. #protected .. "$$" -- @Robustness: Make sure the string doesn't exist in the original content.
745+
746+
elseif childNode.tag == "img" and childNode.attr.src then
747+
table.insert(protected, xmlLib.element("img", {src=childNode.attr.src, alt=(childNode.attr.alt or "")}))
748+
el[i] = "$$PLACEHOLDER" .. #protected .. "$$" -- @Robustness: Make sure the string doesn't exist in the original content.
749+
end
750+
end
751+
end)
752+
end
753+
754+
-- Make the content into a list of paragraphs or similar.
755+
for i, childNode in ipairsr(doc) do
756+
if xmlLib.isText(childNode) then
757+
table.remove(doc, i)
758+
759+
else
760+
if childNode.tag == "ul" or childNode.tag == "ol" then
761+
doc[i] = xmlLib.newElement(childNode.tag)
762+
763+
for li in childNode:eachChildElement() do
764+
local text = trim(li:getText():gsub("%s+", " "))
765+
table.insert(doc[i], xmlLib.element("li", text))
766+
end
767+
768+
else
769+
local text = trim(childNode:getText():gsub("%s+", " "))
770+
doc[i] = xmlLib.element("p", text)
771+
end
772+
773+
if doc[i+1] then table.insert(doc, i+1, "\n") end -- Not needed, but it looks nicer.
774+
end
775+
end
776+
777+
-- Remove protections.
778+
if keepSomeElements then
779+
xmlLib.walk(doc, true, function(tag, el)
780+
for i, childNode in ipairsr(el) do
781+
if xmlLib.isText(childNode) and childNode:find("$$PLACEHOLDER", 1, true) then
782+
local newNodes = {}
783+
784+
for pos, isMatch, textOrProtIndex in gmatchAndBetween(childNode, "%$%$PLACEHOLDER(%d+)%$%$") do
785+
if isMatch then
786+
table.insert(newNodes, protected[tonumber(textOrProtIndex)])
787+
else
788+
table.insert(newNodes, textOrProtIndex)
789+
end
790+
end
791+
792+
table.remove(el, i)
793+
794+
for _, node in ipairsr(newNodes) do
795+
table.insert(el, i, node)
796+
end
797+
end
798+
end
799+
end)
800+
end
801+
802+
-- Limit text length.
803+
local charsRemaining = maxChars
804+
local hasText = {}
805+
806+
local function limit(node, parentEl, i)
807+
if charsRemaining <= 0 then
808+
parentEl[i] = ""
809+
810+
elseif xmlLib.isText(node) then
811+
hasText[parentEl] = true
812+
local len = utf8.getLength(node)
813+
charsRemaining = charsRemaining - len
814+
815+
if charsRemaining < 0 then
816+
!local ELLIPSIS = "(...)"
817+
local nextCharPos = #node + 1
818+
819+
for i = charsRemaining, !(#ELLIPSIS-1) do
820+
nextCharPos = utf8.getStartOfCharacter(node, nextCharPos-1)
821+
822+
if not nextCharPos then
823+
nextCharPos = 1
824+
break
825+
end
826+
end
827+
828+
parentEl[i] = node:sub(1, nextCharPos-1) .. !(ELLIPSIS)
829+
end
830+
831+
else
832+
for i, childNode in ipairs(node) do
833+
limit(childNode, node, i)
834+
end
835+
836+
if hasText[node] and parentEl then
837+
hasText[parentEl] = true
838+
end
839+
end
840+
end
841+
842+
limit(doc, nil, nil)
843+
844+
return (doc:contentsToHtml())
845+
end,
846+
716847
-- Context functions.
717848
----------------------------------------------------------------
718849

719-
echo = function(s)
850+
echo = function(v)
720851
assertContext("template", "echo")
721-
s = tostringForTemplates(s)
852+
local s = tostringForTemplates(v)
722853

723854
local ctx = getContext"template"
724855
if ctx.enableHtmlEncoding then
@@ -733,6 +864,17 @@ local function setup()
733864
table.insert(getContext"template".out, tostringForTemplates(s))
734865
end,
735866

867+
echoSmart = function(v) -- @Doc
868+
assertContext("template", "echoSmart")
869+
if v == nil then
870+
-- void Echo nothing.
871+
elseif doesValueLookLikeHtml(v) then
872+
scriptEnvironmentGlobals.echoRaw(v)
873+
else
874+
scriptEnvironmentGlobals.echo(v)
875+
end
876+
end,
877+
736878
echof = function(s, ...)
737879
assertContext("template", "echof")
738880
!ARGS "s:string"
@@ -928,6 +1070,7 @@ local function setup()
9281070
-- These functions are used by metaprograms.
9291071
scriptEnvironmentGlobals.echo__ = scriptEnvironmentGlobals.echo
9301072
scriptEnvironmentGlobals.echoRaw__ = scriptEnvironmentGlobals.echoRaw
1073+
scriptEnvironmentGlobals.echoSmart__ = scriptEnvironmentGlobals.echoSmart
9311074
scriptEnvironmentGlobals.fori__ = ipairs
9321075
scriptEnvironmentGlobals.foriReverse__ = ipairsr
9331076
scriptEnvironmentGlobals.lock__ = scriptEnvironmentGlobals.lock
@@ -1067,10 +1210,11 @@ local function buildWebsite()
10671210
)
10681211
end
10691212

1070-
site.title.v = getV("title", "", "string")
1071-
site.baseUrl.v = getV("baseUrl", "", "string")
1072-
site.languageCode.v = getV("languageCode", "", "string")
1073-
site.defaultLayout.v = getV("defaultLayout", "page", "string")
1213+
site.title.v = getV("title", site.title.v, "string")
1214+
site.description.v = getV("description", site.description.v, "string")
1215+
site.baseUrl.v = getV("baseUrl", site.baseUrl.v, "string")
1216+
site.languageCode.v = getV("languageCode", site.languageCode.v, "string")
1217+
site.defaultLayout.v = getV("defaultLayout", site.defaultLayout.v, "string")
10741218

10751219
site.redirections.v = getT("redirections", site.redirections.v, "string", "string")
10761220

@@ -1080,8 +1224,8 @@ local function buildWebsite()
10801224

10811225
site._fileTypes = getT("types", site._fileTypes, "string", "string")
10821226
site._fileProcessors = getT("processors", site._fileProcessors, "string", "function")
1083-
local customDataTextParsers = getT("dataTextParsers", {}, "string", "function") -- @Doc
1084-
local customDataBinaryParsers = getT("dataBinaryParsers", {}, "string", "function") -- @Doc
1227+
local customDataTextParsers = getT("dataTextParsers", {}, "string", "function")
1228+
local customDataBinaryParsers = getT("dataBinaryParsers", {}, "string", "function")
10851229

10861230
local htaRedirect = getV("htaccess.redirect", false, "boolean")
10871231
local htaWww = getV("htaccess.www", false, "boolean")
@@ -1211,7 +1355,7 @@ local function buildWebsite()
12111355
-- Template.
12121356
elseif site._fileTypes[extLower] then
12131357
-- Generate these later so e.g. urlExists() works better.
1214-
local pagesArray = (site._fileTypes[extLower] == "othertemplate" and nonPagePages or site._pages)
1358+
local pagesArray = ((site._fileTypes[extLower] == "markdown" or site._fileTypes[extLower] == "html") and site._pages or nonPagePages)
12151359
table.insert(pagesArray, newPage(pathRel, false))
12161360

12171361
-- Special.

0 commit comments

Comments
 (0)