Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional for semantic html output #137

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 85 additions & 28 deletions org-static-blog.el
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

;;; Code:

(require 'cl-macs)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this needed for?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cl-destructuring-bind comes from this package

(require 'cl-extra)
(require 'org)
(require 'ox-html)
Expand Down Expand Up @@ -265,6 +266,36 @@ Only if og tags are enabled. It can be overridden with the
:type '(string)
:safe t)

(defcustom org-static-blog-use-semantic-html nil
"Use semantic html tags instead of <div>.

Semantic html output is customizable via `org-static-blog-semantic-html-mapping'"
:type '(boolean)
:safe t)

(defvar org-static-blog-semantic-html-mapping
'((preamble "header" "id=\"preamble\" class=\"status\"")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that mapping correct? We do have a page header and footer for each page. The preamble and postamble are part of the content really, not of the page.

Copy link
Author

@fapdash fapdash Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mostly following your instructions here: #8 (comment)

The preamble and postamble are part of the content really, not of the page.

Mh, I 'm not sure if I understand what you mean by the difference between content and page.
Isn't the preamble and postamble the same for all pages?

(defcustom org-static-blog-page-preamble ""
"HTML to put before the content of each page."
:type '(string)
:safe t)
(defcustom org-static-blog-page-postamble ""
"HTML to put after the content of each page."
:type '(string)
:safe t)

The structure in the org-static-blog-template is

  • preamble
  • content
  • postamble

"<body>\n"
"<div id=\"preamble\" class=\"status\">"
org-static-blog-page-preamble
"</div>\n"
"<div id=\"content\">\n"
tContent
"</div>\n"
"<div id=\"postamble\" class=\"status\">"
org-static-blog-page-postamble
"</div>\n"
"</body>\n"

tContent is either a single post or a multipost-page.

From https://html.spec.whatwg.org/multipage/sections.html#the-header-element:

The header element represents a group of introductory or navigational aids.

This is how the preamble is currently used in the blogs linked in the README.

Also see the last <header> example from the spec linked above:

<body>
 <header>
  <h1>Little Green Guys With Guns</h1>
  <nav>
   <ul>
    <li><a href="/games">Games</a>
    <li><a href="/forum">Forum</a>
    <li><a href="/download">Download</a>
   </ul>
  </nav>
  <h2>Important News</h2> <!-- this starts a second subsection -->
  <!-- this is part of the subsection entitled "Important News" -->
  <p>To play today's games you will need to update your client.</p>
  <h2>Games</h2> <!-- this starts a third subsection -->
 </header>
 <p>You have three active games:</p>
 <!-- this is still part of the subsection entitled "Games" -->
 ...

From the <footer> spec:

The footer element represents a footer for its nearest ancestor sectioning content element, or for the body element if there is no such ancestor. A footer typically contains information about its section such as who wrote it, links to related documents, copyright data, and the like.

When the footer element contains entire sections, they represent appendices, indices, long colophons, verbose license agreements, and other such content.

This is also the usage that I found in the blogs that I had a look at.

(postamble "footer" "id=\"postamble\" class=\"status\"")
(content "main" "")
(post-date "time" "datetime=\"%Y-%m-%d\"")
(article "article" ""))
"Mapping for the semantic html output activated by `org-static-blog-use-semantic-html'.

The value must be an alist.
The key of the alist must map to two values.
The first value element is a string containing the name of the html node.
The second value element is a string containing the attributes of the html node.
If the html node should not have any attributes the second element must be
the empty string.

Recognized keys are:
'preamble Controls the parent node of the preamble.
'postamble Controls the parent node of the postamble.
'content Controls the parent node of the content.
'post-date Controls the rendering of post dates.
The node is formatted via `format-time-string'.
'article Controls the parent node of articles on multipost pages.")

;; localization support
(defconst org-static-blog-texts
'((other-posts
Expand Down Expand Up @@ -394,27 +425,45 @@ Only if og tags are enabled. It can be overridden with the
org-static-blog-page-header
"</head>\n"
"<body>\n"
"<div id=\"preamble\" class=\"status\">"
org-static-blog-page-preamble
"</div>\n"
"<div id=\"content\">\n"
tContent
"</div>\n"
"<div id=\"postamble\" class=\"status\">"
org-static-blog-page-postamble
"</div>\n"
(org-static-blog-wrap-node "<div id=\"preamble\" class=\"status\">"
org-static-blog-page-preamble
'preamble)
(org-static-blog-wrap-node "<div id=\"content\">\n"
tContent
'content)
(org-static-blog-wrap-node "<div id=\"postamble\" class=\"status\">"
org-static-blog-page-postamble
'postamble)
"</body>\n"
"</html>\n"))

(defun org-static-blog-wrap-node (default-wrapper to-wrap semantic-mapping)
"Wrap node TO-WRAP in a parent node.
Use DEFAULT-WRAPPER if `org-static-html-use-semantic-html' is nil,
otherwise resolve and use SEMANTIC-MAPPING.

This function is used to allow for rendering of semantic html.
The function assumes that all parents nodes provided via DEFAULT-WRAPPER
are divs, as is the case for the legacy non-semantic nodes."
(if org-static-blog-use-semantic-html
(cl-destructuring-bind (tag attributes)
(alist-get semantic-mapping org-static-blog-semantic-html-mapping)
(concat (format "<%s %s>" tag attributes)
to-wrap
(format "</%s>\n" tag)))
(concat "<div id=\"preamble\" class=\"status\">"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(concat "<div id=\"preamble\" class=\"status\">"
(concat default-wrapper

to-wrap
"</div>\n")))

(defun org-static-blog-gettext (text-id)
"Return localized text.
Depends on org-static-blog-langcode and org-static-blog-texts."
(let* ((text-node (assoc text-id org-static-blog-texts))
(text-lang-node (if text-node
(assoc org-static-blog-langcode text-node)
nil)))
(text-lang-node (if text-node
(assoc org-static-blog-langcode text-node)
nil)))
(if text-lang-node
(cdr text-lang-node)
(cdr text-lang-node)
(concat "[" (symbol-name text-id) ":" org-static-blog-langcode "]"))))


Expand Down Expand Up @@ -583,7 +632,6 @@ Preamble and Postamble are excluded, too."
(with-temp-buffer
(insert-file-contents (org-static-blog-matching-publish-filename post-filename))
(let ((post-title (org-static-blog-get-title post-filename))
(post-date (org-static-blog-get-date post-filename))
(post-taglist (org-static-blog-post-taglist post-filename))
(post-ellipsis "")
(preview-region (org-static-blog--preview-region)))
Expand All @@ -599,10 +647,7 @@ Preamble and Postamble are excluded, too."
(format "<h2 class=\"post-title\"><a href=\"%s\">%s</a></h2>"
(org-static-blog-get-post-url post-filename) post-title))
(date-link
(format-time-string (concat "<div class=\"post-date\">"
(org-static-blog-gettext 'date-format)
"</div>")
post-date)))
(org-static-blog-post-date post-filename)))
(concat
(if org-static-blog-preview-date-first-p
(concat date-link title-link)
Expand Down Expand Up @@ -763,13 +808,21 @@ This function is called for every post and prepended to the post body.
Modify this function if you want to change a posts headline."
(concat
org-static-blog-post-preamble-text
"<div class=\"post-date\">" (format-time-string (org-static-blog-gettext 'date-format)
(org-static-blog-get-date post-filename))
"</div>"
(org-static-blog-post-date post-filename)
"<h1 class=\"post-title\">"
"<a href=\"" (org-static-blog-get-post-url post-filename) "\">" (org-static-blog-get-title post-filename) "</a>"
"</h1>\n"))

(defun org-static-blog-post-date (post-filename)
"Return the formatted post date of POST-FILENAME.
This function is called whenever the date of a post is rendered.
Modify this function if you want to change how post dates are rendered.
If `org-static-blog-use-semantic-html' is non-nil the rendering
can also be changed via `org-static-blog-semantic-html-mapping'"
(format-time-string (org-static-blog-wrap-node "<div class=\"post-date\">"
(org-static-blog-gettext 'date-format)
'post-date)
(org-static-blog-get-date post-filename)))

(defun org-static-blog-post-taglist (post-filename)
"Returns the tag list of the post.
Expand Down Expand Up @@ -916,13 +969,17 @@ blog post, but no post body."
This function is called for every post on the archive and
tags-archive page. Modify this function if you want to change an
archive headline."
(concat
"<div class=\"post-date\">"
(format-time-string (org-static-blog-gettext 'date-format) (org-static-blog-get-date post-filename))
"</div>"
"<h2 class=\"post-title\">"
"<a href=\"" (org-static-blog-get-post-url post-filename) "\">" (org-static-blog-get-title post-filename) "</a>"
"</h2>\n"))
(let ((post-summary
(concat
(org-static-blog-post-date post-filename)
"<h2 class=\"post-title\">"
"<a href=\"" (org-static-blog-get-post-url post-filename) "\">"
(org-static-blog-get-title post-filename)
"</a>"
"</h2>\n")))
(if org-static-blog-use-semantic-html
(org-static-blog-wrap-node nil post-summary 'article)
post-summary)))

(defun org-static-blog-assemble-tags ()
"Render the tag archive and tag pages."
Expand Down