From 0f3acaf7c2b187f844569dbed8a727dc12e23122 Mon Sep 17 00:00:00 2001 From: BurnyLlama Date: Thu, 5 Aug 2021 23:27:11 +0200 Subject: [PATCH] ToC is now automaticcaly server-side rendered. --- README.md | 2 +- content/code/test.js | 12 --- content/components/toc.njk | 6 +- content/pages/article/how-to.njk | 106 ----------------------- content/pages/article/markdown.njk | 29 ------- content/pages/docs/main.njk | 25 ++++++ content/pages/docs/main_md.njk | 16 ++++ content/pages/index.njk | 16 ---- content/pages/test1.njk | 3 - content/pages/test2/index.njk | 3 - content/pages/theme.njk | 133 ----------------------------- content/templates/article.njk | 5 +- content/templates/article_md.njk | 31 +++++++ index.js | 38 +++++---- libs/mdRenderer.js | 10 +++ libs/njkRenderer.js | 35 ++++++++ libs/requestHandler.js | 13 ++- package.json | 2 +- 18 files changed, 151 insertions(+), 334 deletions(-) delete mode 100644 content/code/test.js delete mode 100644 content/pages/article/how-to.njk delete mode 100644 content/pages/article/markdown.njk create mode 100644 content/pages/docs/main.njk create mode 100644 content/pages/docs/main_md.njk delete mode 100644 content/pages/index.njk delete mode 100644 content/pages/test1.njk delete mode 100644 content/pages/test2/index.njk delete mode 100644 content/pages/theme.njk create mode 100644 content/templates/article_md.njk create mode 100644 libs/mdRenderer.js create mode 100644 libs/njkRenderer.js diff --git a/README.md b/README.md index 9f033fa..35dc918 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ I can *promise* you that there is no malicious code or dependency in this projec The project depends on the following packages (installed when you ran `npm i`): * express (a web server framework) * nunjucks (a templating engine) -* nunjucks-append (an extension that adds more functionality to nunjucks) * nunjucks-markdown (markdown support in nunjucks) * marked (markdown parser/compiler) * highlight.js (syntax highlighting) +* jsdom (an extension that can use the DOM server-side - used to render the ToC) * chokidar (reload templates if they change on disk) * fs (used for filesystem operations) diff --git a/content/code/test.js b/content/code/test.js deleted file mode 100644 index 84a7eda..0000000 --- a/content/code/test.js +++ /dev/null @@ -1,12 +0,0 @@ -const niceObject = { - type: "the greatest", - knownFor: [ - "indenting", - "everything", - { - and: "wanting", - to: "keep", - it: "so" - } - ] -} \ No newline at end of file diff --git a/content/components/toc.njk b/content/components/toc.njk index 7c9613f..4dd0e44 100644 --- a/content/components/toc.njk +++ b/content/components/toc.njk @@ -1,9 +1,5 @@ {% macro header(size, text) %} - {% append "toc" %} - {{ text }} - {% endappend %} - - + <{{ size }}> {{ text }} diff --git a/content/pages/article/how-to.njk b/content/pages/article/how-to.njk deleted file mode 100644 index c92e133..0000000 --- a/content/pages/article/how-to.njk +++ /dev/null @@ -1,106 +0,0 @@ -{% extends "templates/article.njk" %} -{% import "components/toc.njk" as toc with context %} - -{% block header %} - How to - Article template -{% endblock %} - -{% block toc %} - {% output "toc" %}{% endoutput %} -{% endblock %} - -{% block body %} -
- - {{ toc.header("h1", "Introduction", tocList) }} -

- I want to start off by saying that this article template (as of now) is really fricking shit. - The code base is somewhat okay in complexity, but I do not feel like it is done in a efficient/good - way and won't work without CSS enabled (although, most people don't disable CSS). - Please use with causition until I've implemented something better that would work without CSS. -

- - {{ toc.header("h2", "Terminology", tocList) }} -

- Whenever I say "ToC" in this article I am refering to "Table of Contents". (I couldn't be bothered - writing it out all the times...) -

- - {{ toc.header("h1", "Usage", tocList ) }} -

- To use the template you would simply extend templates/article.njk and - import components/toc.njk: - - - {{ ' -{% extends "templates/article.njk" %} -{% import "components/toc.njk" as toc with context %} - -{% block header %} - Your header -{% endblock %} - -{% block body %} -

-

- Your content goes here -

-
-{% endblock %}' | escape | replace("\n", "", 1) | replace("\n", "
") | replace(" ", " ") }} -
- - You would use the header block to define a header, and then you place your - content inside a div with the class content in your body-block. -

- - {{ toc.header("h2", "Adding headers to the ToC", tocList) }} -

- Adding headers is kind of easy, {% raw %}{% import "components/toc.njk" as toc with context %}{% endraw %} - imports a macro that will create a header and automatically add it to the table of contents. You use it as such: - - - {{ '{{ toc.header(size, text, tocList) }}' }} - - - size is a string and is a header level (aka h1, h2, h3, etc.), - text is a string that holds the text you would want to display, and finally tocList is a - variable inherited from template/article.njk that keeps a hold of which headers should go in the ToC.
- - If you would want to display an {{ '

' }} with the text "Introduction" you would do: - - - {{ '{{ toc.header("h1", "Introduction", tocList) }}' }} - -

- - {{ toc.header("h2", "Generate the ToC", tocList) }} -

- Sadly it isn't enough to just add the heading to the ToC. You will have to generate the ToC as well, but - this isn't hard at all to do. You simply add {{ '{{ toc.generate(tocList) }}' }} to the end - of your body-block. -

- - {{ toc.header("h1", "Example code", tocList) }} - - {{ ' -{% extends "templates/article.njk" %} -{% import "components/toc.njk" as toc with context %} - -{% block header %} - Your header -{% endblock %} - -{% block body %} -
- {{ toc.header("h1", "Introduction", tocList) }} -

- Your introduction goes here... -

-
- - {{ toc.generate(tocList) }} -{% endblock %}' | escape | replace("\n", "", 1) | replace("\n", "
") | replace(" ", " ") }} -
-

- -{% endblock %} \ No newline at end of file diff --git a/content/pages/article/markdown.njk b/content/pages/article/markdown.njk deleted file mode 100644 index 5672de6..0000000 --- a/content/pages/article/markdown.njk +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "templates/article.njk" %} -{% import "components/toc.njk" as toc with context %} -{% import "components/code.njk" as code with context %} - -{% block header %} - Markdown -{% endblock %} - -{% block toc %} - {% output "toc" %}{% endoutput %} -{% endblock %} - -{% block body %} - {% markdown %} -# Test of markdown - -{{ code.import("code/test.js", "javascript") }} - -* A list item -* A list item -* A list item -* A list item - -*italic* **bold** - -{{ toc.header("h1", "test header") }} - - {% endmarkdown %} -{% endblock %} \ No newline at end of file diff --git a/content/pages/docs/main.njk b/content/pages/docs/main.njk new file mode 100644 index 0000000..acda156 --- /dev/null +++ b/content/pages/docs/main.njk @@ -0,0 +1,25 @@ +{% extends "templates/article.njk" %} +{% import "components/toc.njk" as toc with context %} + +{% block head %} + qwik cms - docs - main +{% endblock %} + +{% block header %} + qwik cms - docs +{% endblock %} + +{% block main %} + {{ toc.header("h1", "Basic idea") }} +

+ Our CMS can be used in multiple (different) ways thanks to the underlying technologies. + The basic idea is that every page is a file. Although how you treat that file is really + up to you. It can be plain HTML, nunjucks/njk (a templating language for HTML) or even + markdown (although not "plain markdown"). +

+ {{ toc.header("h2", "Views on bloat") }} +

+ I do not want to bloat this CMS, but I must admit that it is bloated. + {{ hello }} +

+{% endblock %} \ No newline at end of file diff --git a/content/pages/docs/main_md.njk b/content/pages/docs/main_md.njk new file mode 100644 index 0000000..77eba6f --- /dev/null +++ b/content/pages/docs/main_md.njk @@ -0,0 +1,16 @@ +{% extends "templates/article_md.njk" %} + +{% block head %} + qwik cms - docs - main +{% endblock %} + +{% block header %} + qwik cms - docs +{% endblock %} + +{% block main %} + # Test + Heyyy you there! + + ## Undertest +{% endblock %} \ No newline at end of file diff --git a/content/pages/index.njk b/content/pages/index.njk deleted file mode 100644 index 24d9ddd..0000000 --- a/content/pages/index.njk +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Hello World! - - -

Hello World!

-

- Welcome to {{ serverName }}!
- Test 1
- Test 2
-

- - \ No newline at end of file diff --git a/content/pages/test1.njk b/content/pages/test1.njk deleted file mode 100644 index aaf3a3c..0000000 --- a/content/pages/test1.njk +++ /dev/null @@ -1,3 +0,0 @@ -

- Test 1 -

\ No newline at end of file diff --git a/content/pages/test2/index.njk b/content/pages/test2/index.njk deleted file mode 100644 index e671a37..0000000 --- a/content/pages/test2/index.njk +++ /dev/null @@ -1,3 +0,0 @@ -

- Test 2 -

\ No newline at end of file diff --git a/content/pages/theme.njk b/content/pages/theme.njk deleted file mode 100644 index 3f56fe0..0000000 --- a/content/pages/theme.njk +++ /dev/null @@ -1,133 +0,0 @@ - - - - {% include "templates/defaultTags.njk" %} - Document - - -
- Actual Header -
- -

Header 1

-

Header 2

-

Header 3

-

Header 4

-
Header 5
-
Header 6
- -

- This is a paragraph. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Voluptate non ut commodi quisquam in, a dicta rem expedita tenetur quis ratione aut nesciunt corporis soluta similique eius accusantium, optio numquam? Dolorem, voluptates! -

- -

- Italic text
- Bold text
- This is an example link -

- -
- This is a blockquote. Lorem ipsum dolor sit amet consectetur adipisicing elit. Quidem voluptates soluta dolorem esse aperiam natus provident nemo, dicta dolores quae velit officia minus expedita cum modi eveniet minima suscipit mollitia aspernatur ad. -
- - - -
    -
  1. This is a list item!
  2. -
  3. This is a list item!
  4. -
  5. This is a list item!
  6. -
  7. This is a list item!
  8. -
  9. This is a list item!
  10. -
      -
    1. This is a nested list.
    2. -
    3. This is a nested list.
    4. -
    5. This is a nested list.
    6. -
        -
      1. This is a nested list.
      2. -
      3. This is a nested list.
      4. -
      5. This is a nested list.
      6. -
      -
    -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AnimalNameAge
BunnyJumpy2 years
CatBiter4 months
BunnyJumpy2 years
CatBiter4 months
BunnyJumpy2 years
CatBiter4 months
BunnyJumpy2 years
CatBiter4 months
- - -{{ ' - - - - - - Document - - - - - -' | escape | replace("\n", "", 1) | replace("\n", "
") | replace(" ", " ") }} -
- - \ No newline at end of file diff --git a/content/templates/article.njk b/content/templates/article.njk index b57121d..7294c78 100644 --- a/content/templates/article.njk +++ b/content/templates/article.njk @@ -17,7 +17,10 @@

Table of Contents

- {% block toc %}{% endblock %} + {% for tocLink in tocLinks %} + {{ tocLink | safe }} + {% endfor %} +
diff --git a/content/templates/article_md.njk b/content/templates/article_md.njk new file mode 100644 index 0000000..ccec1f9 --- /dev/null +++ b/content/templates/article_md.njk @@ -0,0 +1,31 @@ + + + + {% include "./defaultTags.njk" %} + + + {% block head %} + {{ serverName }} + {% endblock %} + + +
+
+ {% block header %}{% endblock %} +
+ +
+
+

Table of Contents

+ {% for tocLink in tocLinks %} + {{ tocLink | safe }} + {% endfor %} +
+
+ + {% markdown %} + {% block main %}{% endblock %} + {% endmarkdown %} +
+ + \ No newline at end of file diff --git a/index.js b/index.js index 32525d7..a3ad0b4 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,17 @@ -import express from 'express' -import njk from 'nunjucks' -import njkAppend from 'nunjucks-append' -import njkMarkdown from 'nunjucks-markdown' -import marked from 'marked' import fs from 'fs' -import { requestHandler } from './libs/requestHandler.js' +import express from 'express' + +import njk from 'nunjucks' +import njkMarkdown from 'nunjucks-markdown' + +import marked from 'marked' import hljs from 'highlight.js' +import { requestHandler } from './libs/requestHandler.js' +import { mdRenderer } from './libs/mdRenderer.js' +// Load in config const ConfigFile = fs.readFileSync('./config.json') const Config = JSON.parse(ConfigFile) @@ -16,12 +19,15 @@ const Config = JSON.parse(ConfigFile) const Server = express() + + +// Some config Server.use('/assets', express.static(Config.assetsDir)) const njkEnv = njk.configure( Config.contentDir, { - autoescape: false, + autoescape: true, watch: true, trimBlocks: true, lstripBlocks: true, @@ -35,21 +41,21 @@ marked.setOptions({ return hljs.highlight(language, code) .value.replace(/\n/g, "
").replace(/•/g, " ") }, - gfm: true, - smartypants: true, - smartLists: true, - silent: true + gfm: true }) -njkAppend.initialise(njkEnv) +marked.use({ renderer: mdRenderer }) + njkMarkdown.register(njkEnv, marked) -Server.get( - '*', - (req, res) => requestHandler(req, res, Config) -) +// Send all requests to the requestHandler. +Server.get('*', (req, res) => requestHandler(req, res, Config)) + + + +// Start the server Server.listen( Config.serverPort, () => { diff --git a/libs/mdRenderer.js b/libs/mdRenderer.js new file mode 100644 index 0000000..78daf3f --- /dev/null +++ b/libs/mdRenderer.js @@ -0,0 +1,10 @@ +export const mdRenderer = { + heading(text, level) { + return ` + + + ${text} + + ` + } +} \ No newline at end of file diff --git a/libs/njkRenderer.js b/libs/njkRenderer.js new file mode 100644 index 0000000..0b46880 --- /dev/null +++ b/libs/njkRenderer.js @@ -0,0 +1,35 @@ +import fs from 'fs' +import njk from 'nunjucks' +import { JSDOM } from 'jsdom' + +// Load in config +const ConfigFile = fs.readFileSync('./config.json') +const Config = JSON.parse(ConfigFile) + +function generateToc(dom) { + const tocAnchors = dom.window.document.querySelectorAll(".toc-anchor") + let tocLinks = [] + + // This basically creates a proper link for the ToC. :))) + tocAnchors.forEach(anchor => tocLinks.push(`${anchor.getAttribute('data-orig-text')}`)) + + return tocLinks +} + +function generateContext(renderedNjk) { + const dom = new JSDOM(renderedNjk) + + return { + serverName: Config.serverName, + tocLinks: generateToc(dom) + } +} + +export function njkRenderer(path) { + const njkFile = fs.readFileSync(path).toString() + const renderedNjk = njk.renderString(njkFile) + + const context = generateContext(renderedNjk) + + return njk.renderString(njkFile, context) +} \ No newline at end of file diff --git a/libs/requestHandler.js b/libs/requestHandler.js index 62a8695..287aef8 100644 --- a/libs/requestHandler.js +++ b/libs/requestHandler.js @@ -1,15 +1,12 @@ import fs from 'fs' +import { njkRenderer } from './njkRenderer.js' export function requestHandler(req, res, Config) { - const context = { - serverName: Config.serverName - } + if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.njk`)) + return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}.njk`)) - if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}.njk`, context)) - return res.render(`pages/${req.path}.njk`) - - if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.njk`, context)) - return res.render(`pages/${req.path}/index.njk`) + if (fs.existsSync(`./${Config.contentDir}/pages/${req.path}/index.njk`)) + return res.send(njkRenderer(`./${Config.contentDir}/pages/${req.path}/index.njk`)) return res.status(404).render('errors/404.njk', context) } \ No newline at end of file diff --git a/package.json b/package.json index 96d82a9..f2cdb8a 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,9 @@ "chokidar": "^3.5.2", "express": "^4.17.1", "highlight.js": "^11.2.0", + "jsdom": "^16.7.0", "marked": "^2.1.3", "nunjucks": "^3.2.3", - "nunjucks-append": "^0.0.3", "nunjucks-markdown": "^2.0.1" } }