Thanks for testing Jens. I think I've managed to resolve the issues
you've raised.

Jens, Bastien, you can find the latest revision of the patches attached :)

Jens Lechtenboerger <lech...@wi.uni-muenster.de> writes:

> [title export being dodgy, how about treating like author?]

Yep, ~org-element-interpret-data~ is necessary. I found that wrapping it
in ~org-html-plain-text~ seems better again though, as it encodes
entities like "---" (org) to "&#x2014;", and doesn't seem to introduce
any nested tags. I've also applied this to the author field as a result.

Maybe it should be applied to the rest (in ~org-html--build-meta-info~)?
I'm not sure.

> The keywords export as follows, where the name attribute is missing:
> <meta keywords="key, wörd, *bold*, sub_script" />

Fixed.

> The current lambda functions in org-html-meta-tags all accept three
> arguments, where the first one is ignored in all cases.  The second
> one is used in exactly one case.  Why not add four calls to
> org-html--build-meta-entry (for author, description, keywords,
> generator) in org-html--build-meta-info?

I had an idea on this, I think the new form is cleaner.
Either have a list where each item generates a meta entry, or a function
that generates such a list. No more mixing of the two.

How does this look?

Timothy.

>From 9848af808752bc03404befaab7ab5ebb902aa1d0 Mon Sep 17 00:00:00 2001
From: TEC <t...@tecosaur.com>
Date: Mon, 14 Dec 2020 17:41:33 +0800
Subject: [PATCH 1/2] lisp/ox-html.el: make html meta tag builder nicer

* lisp/ox-html.el (org-html--build-meta-info): Multi-line repeated
structure extracted to new function `org-html--build-meta-entry'.
The keyword value formatting is changed from `org-export-data' to
`org-html-encode-plain-text' to avoid potentially nesting HTML tags in
meta tags and the <title> element, which would violate W3C.
---
 lisp/ox-html.el | 114 ++++++++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 58 deletions(-)

diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index d2f24f5c6..005703f60 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -1835,78 +1835,76 @@ INFO is a plist used as a communication channel."
 
 ;;; Template
 
+(defun org-html--build-meta-entry (label identity &optional content-format &rest content-formatters)
+  "Construct <meta> tag of form <meta LABEL=\"IDENTITY\" />, or when CONTENT-FORMAT is present:
+<meta LABEL=\"IDENTITY\" content=\"{content}\" />
+
+Here {content} is determined by applying any CONTENT-FORMATTERS to the CONTENT-FORMAT and encoding
+the result as plain text."
+  (concat "<meta "
+	  (format "%s=\"%s" label identity)
+	  (when content-format
+	    (concat "\" content=\""
+		    (replace-regexp-in-string
+		     "\"" "&quot;"
+		     (org-html-encode-plain-text
+		      (if content-formatters
+			  (apply #'format content-format content-formatters)
+			content-format)))))
+	  "\" />\n"))
+
 (defun org-html--build-meta-info (info)
   "Return meta tags for exported document.
 INFO is a plist used as a communication channel."
-  (let* ((protect-string
-          (lambda (str)
-            (replace-regexp-in-string
-             "\"" "&quot;" (org-html-encode-plain-text str))))
-         (title (org-export-data (plist-get info :title) info))
-         ;; Set title to an invisible character instead of leaving it
-         ;; empty, which is invalid.
-         (title (if (org-string-nw-p title) title "&lrm;"))
-         (author (and (plist-get info :with-author)
-                      (let ((auth (plist-get info :author)))
+  (let* ((title (org-html-plain-text
+		 (org-element-interpret-data (plist-get info :title)) info))
+	 ;; Set title to an invisible character instead of leaving it
+	 ;; empty, which is invalid.
+	 (title (if (org-string-nw-p title) title "&lrm;"))
+	 (author (and (plist-get info :with-author)
+		      (let ((auth (plist-get info :author)))
 			;; Return raw Org syntax.
-                        (and auth (org-element-interpret-data auth)))))
-         (description (plist-get info :description))
-         (keywords (plist-get info :keywords))
-         (charset (or (and org-html-coding-system
-                           (fboundp 'coding-system-get)
-                           (coding-system-get org-html-coding-system
-                                              'mime-charset))
-                      "iso-8859-1")))
+			(and auth (org-html-plain-text
+				   (org-element-interpret-data auth) info)))))
+	 (charset (or (and org-html-coding-system
+			   (fboundp 'coding-system-get)
+			   (symbol-name
+			    (coding-system-get org-html-coding-system
+					       'mime-charset)))
+		      "iso-8859-1")))
     (concat
      (when (plist-get info :time-stamp-file)
        (format-time-string
 	(concat "<!-- "
 		(plist-get info :html-metadata-timestamp-format)
 		" -->\n")))
-     (format
-      (if (org-html-html5-p info)
-	  (org-html-close-tag "meta" "charset=\"%s\"" info)
-	(org-html-close-tag
-	 "meta" "http-equiv=\"Content-Type\" content=\"text/html;charset=%s\""
-	 info))
-      charset) "\n"
+
+     (if (org-html-html5-p info)
+	 (org-html--build-meta-entry "charset" charset)
+       (org-html--build-meta-entry "http-equiv" "Content-Type"
+				   (concat "text/html;charset=" charset)))
+
      (let ((viewport-options
 	    (cl-remove-if-not (lambda (cell) (org-string-nw-p (cadr cell)))
 			      (plist-get info :html-viewport))))
-       (and viewport-options
-	    (concat
-	     (org-html-close-tag
-	      "meta"
-	      (format "name=\"viewport\" content=\"%s\""
-		      (mapconcat
-		       (lambda (elm) (format "%s=%s" (car elm) (cadr elm)))
-		       viewport-options ", "))
-	      info)
-	     "\n")))
+       (if viewport-options
+	   (org-html--build-meta-entry "name" "viewport"
+				       (mapconcat
+					(lambda (elm) (format "%s=%s" (car elm) (cadr elm)))
+					viewport-options ", "))))
+
      (format "<title>%s</title>\n" title)
-     (org-html-close-tag "meta" "name=\"generator\" content=\"Org mode\"" info)
-     "\n"
-     (and (org-string-nw-p author)
-	  (concat
-	   (org-html-close-tag "meta"
-			       (format "name=\"author\" content=\"%s\""
-				       (funcall protect-string author))
-			       info)
-	   "\n"))
-     (and (org-string-nw-p description)
-	  (concat
-	   (org-html-close-tag "meta"
-			       (format "name=\"description\" content=\"%s\"\n"
-				       (funcall protect-string description))
-			       info)
-	   "\n"))
-     (and (org-string-nw-p keywords)
-	  (concat
-	   (org-html-close-tag "meta"
-			       (format "name=\"keywords\" content=\"%s\""
-				       (funcall protect-string keywords))
-			       info)
-	   "\n")))))
+
+     (when (org-string-nw-p author)
+       (org-html--build-meta-entry "name" "author" author))
+
+     (when (org-string-nw-p (plist-get info :description))
+       (org-html--build-meta-entry "name" "description" (plist-get info :description)))
+
+     (when (org-string-nw-p (plist-get info :keywords))
+	(org-html--build-meta-entry "keywords" (plist-get info :keywords)))
+
+     (org-html--build-meta-entry "name" "generator" "Org Mode"))))
 
 (defun org-html--build-head (info)
   "Return information for the <head>..</head> of the HTML output.
-- 
2.29.2

>From 3fdc205a549fe315b3096afb72a87868ef9c57d5 Mon Sep 17 00:00:00 2001
From: TEC <t...@tecosaur.com>
Date: Mon, 14 Dec 2020 17:50:15 +0800
Subject: [PATCH 2/2] lisp/ox-html.el: make html meta tags customizable

* lisp/ox-html.el (org-html-meta-tags): Introduce this as a new option
which can be modified to set the meta tags added in HTML exports.
(org-html--build-meta-info): Make use of `org-html-meta-tags' instead of
hardcoded meta tags.  This is leveraging the earlier restructuring of
`org-html--build-meta-info' into a much DRYer form, such that this
modification has a negligible impact on complexity and readability.
---
 lisp/ox-html.el | 47 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 005703f60..6a74cdca8 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -1425,6 +1425,22 @@ not be modified."
 
 ;;;; Template :: Styles
 
+(defcustom org-html-meta-tags #'org-html-meta-tags-default
+  "A list where each item is a list of arguments to be passed
+to `org-html--build-meta-entry'. Any nil items are ignored.
+
+Also accept a function which gives such a list when called with with
+signature (TITLE AUTHOR INFO) where TITLE and AUTHOR are strings,
+and INFO a communication plist."
+  :group 'org-export-html
+  :package-version '(Org . "9.5")
+  :type '(choice
+	  (repeat
+	   (list (string :tag "Meta label")
+		 (string :tag "label value")
+		 (string :tag "Content value")))
+	  function))
+
 (defcustom org-html-head-include-default-style t
   "Non-nil means include the default style in exported HTML files.
 The actual style is defined in `org-html-style-default' and
@@ -1835,6 +1851,22 @@ INFO is a plist used as a communication channel."
 
 ;;; Template
 
+(defun org-html-meta-tags-default (_title author info)
+  "Generate a list items, each of which is a list of arguments that can
+be passed to `org-html--build-meta-entry', to generate meta tags to be
+included in the HTML head.
+
+The documents's TITLE, AUTHOR, and communication plist INFO may be used."
+  (list
+   (when (org-string-nw-p author)
+     (list "name" "author" author))
+   (when (org-string-nw-p (plist-get info :description))
+     (list "name" "description"
+	   (plist-get info :description)))
+   (when (org-string-nw-p (plist-get info :keywords))
+     (list "name" "keywords" (plist-get info :keywords)))
+   '("name" "generator" "Org Mode")))
+
 (defun org-html--build-meta-entry (label identity &optional content-format &rest content-formatters)
   "Construct <meta> tag of form <meta LABEL=\"IDENTITY\" />, or when CONTENT-FORMAT is present:
 <meta LABEL=\"IDENTITY\" content=\"{content}\" />
@@ -1895,16 +1927,11 @@ INFO is a plist used as a communication channel."
 
      (format "<title>%s</title>\n" title)
 
-     (when (org-string-nw-p author)
-       (org-html--build-meta-entry "name" "author" author))
-
-     (when (org-string-nw-p (plist-get info :description))
-       (org-html--build-meta-entry "name" "description" (plist-get info :description)))
-
-     (when (org-string-nw-p (plist-get info :keywords))
-	(org-html--build-meta-entry "keywords" (plist-get info :keywords)))
-
-     (org-html--build-meta-entry "name" "generator" "Org Mode"))))
+     (mapconcat
+      (lambda (args) (apply #'org-html--build-meta-entry args))
+      (delq nil (if (functionp org-html-meta-tags)
+		    (funcall org-html-meta-tags title author info)
+		  org-html-meta-tags)) ""))))
 
 (defun org-html--build-head (info)
   "Return information for the <head>..</head> of the HTML output.
-- 
2.29.2

Reply via email to