summaryrefslogtreecommitdiff
path: root/ennum-html.el
diff options
context:
space:
mode:
Diffstat (limited to 'ennum-html.el')
-rw-r--r--ennum-html.el383
1 files changed, 383 insertions, 0 deletions
diff --git a/ennum-html.el b/ennum-html.el
new file mode 100644
index 0000000..1475927
--- /dev/null
+++ b/ennum-html.el
@@ -0,0 +1,383 @@
+;; -*- lexical-binding: t -*-
+
+(require 'ox)
+(require 'subr-x)
+(require 'xmlgen)
+
+(defconst ennum--iso-639-1-alist
+ '(("ab" . "аҧсуа бызшәа, аҧсшәа")
+ ("aa" . "Afaraf")
+ ("af" . "Afrikaans")
+ ("ak" . "Akan")
+ ("sq" . "Shqip")
+ ("am" . "አማርኛ")
+ ("ar" . "العربية")
+ ("an" . "aragonés")
+ ("hy" . "Հայերեն")
+ ("as" . "অসমীয়া")
+ ("av" . "авар мацӀ, магӀарул мацӀ")
+ ("ae" . "avesta")
+ ("ay" . "aymar aru")
+ ("az" . "azərbaycan dili")
+ ("bm" . "bamanankan")
+ ("ba" . "башҡорт теле")
+ ("eu" . "euskara, euskera")
+ ("be" . "беларуская мова")
+ ("bn" . "বাংলা")
+ ("bh" . "भोजपुरी")
+ ("bi" . "Bislama")
+ ("bs" . "bosanski jezik")
+ ("br" . "brezhoneg")
+ ("bg" . "български език")
+ ("my" . "ဗမာစာ")
+ ("ca" . "català")
+ ("ch" . "Chamoru")
+ ("ce" . "нохчийн мотт")
+ ("ny" . "chiCheŵa, chinyanja")
+ ("zh" . "中文 (Zhōngwén), 汉语, 漢語")
+ ("cv" . "чӑваш чӗлхи")
+ ("kw" . "Kernewek")
+ ("co" . "corsu, lingua corsa")
+ ("cr" . "ᓀᐦᐃᔭᐍᐏᐣ")
+ ("hr" . "hrvatski jezik")
+ ("cs" . "čeština, český jazyk")
+ ("da" . "dansk")
+ ("dv" . "ދިވެހި")
+ ("nl" . "Nederlands, Vlaams")
+ ("dz" . "རྫོང་ཁ")
+ ("en" . "English")
+ ("eo" . "Esperanto")
+ ("et" . "eesti, eesti keel")
+ ("ee" . "Eʋegbe")
+ ("fo" . "føroyskt")
+ ("fj" . "vosa Vakaviti")
+ ("fi" . "suomi, suomen kieli")
+ ("fr" . "français, langue française")
+ ("ff" . "Fulfulde, Pulaar, Pular")
+ ("gl" . "galego")
+ ("ka" . "ქართული")
+ ("de" . "Deutsch")
+ ("el" . "ελληνικά")
+ ("gn" . "Avañe'ẽ")
+ ("gu" . "ગુજરાતી")
+ ("ht" . "Kreyòl ayisyen")
+ ("ha" . "(Hausa) هَوُسَ")
+ ("he" . "עברית")
+ ("hz" . "Otjiherero")
+ ("hi" . "हिन्दी, हिंदी")
+ ("ho" . "Hiri Motu")
+ ("hu" . "magyar")
+ ("ia" . "Interlingua")
+ ("id" . "Bahasa Indonesia")
+ ("ie" . "Originally called Occidental; then Interlingue after WWII")
+ ("ga" . "Gaeilge")
+ ("ig" . "Asụsụ Igbo")
+ ("ik" . "Iñupiaq, Iñupiatun")
+ ("io" . "Ido")
+ ("is" . "Íslenska")
+ ("it" . "Italiano")
+ ("iu" . "ᐃᓄᒃᑎᑐᑦ")
+ ("ja" . "日本語 (にほんご)")
+ ("jv" . "ꦧꦱꦗꦮ, Basa Jawa")
+ ("kl" . "kalaallisut, kalaallit oqaasii")
+ ("kn" . "ಕನ್ನಡ")
+ ("kr" . "Kanuri")
+ ("ks" . "कश्मीरी, كشميري‎")
+ ("kk" . "қазақ тілі")
+ ("km" . "ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ")
+ ("ki" . "Gĩkũyũ")
+ ("rw" . "Ikinyarwanda")
+ ("ky" . "Кыргызча, Кыргыз тили")
+ ("kv" . "коми кыв")
+ ("kg" . "Kikongo")
+ ("ko" . "한국어")
+ ("ku" . "Kurdî, كوردی‎")
+ ("kj" . "Kuanyama")
+ ("la" . "latine, lingua latina")
+ ("lb" . "Lëtzebuergesch")
+ ("lg" . "Luganda")
+ ("li" . "Limburgs")
+ ("ln" . "Lingála")
+ ("lo" . "ພາສາລາວ")
+ ("lt" . "lietuvių kalba")
+ ("lu" . "Tshiluba")
+ ("lv" . "latviešu valoda")
+ ("gv" . "Gaelg, Gailck")
+ ("mk" . "македонски јазик")
+ ("mg" . "fiteny malagasy")
+ ("ms" . "bahasa Melayu, بهاس ملايو‎")
+ ("ml" . "മലയാളം")
+ ("mt" . "Malti")
+ ("mi" . "te reo Māori")
+ ("mr" . "मराठी")
+ ("mh" . "Kajin M̧ajeļ")
+ ("mn" . "Монгол хэл")
+ ("na" . "Dorerin Naoero")
+ ("nv" . "Diné bizaad")
+ ("nd" . "isiNdebele")
+ ("ne" . "नेपाली")
+ ("ng" . "Owambo")
+ ("nb" . "Norsk bokmål")
+ ("nn" . "Norsk nynorsk")
+ ("no" . "Norsk")
+ ("ii" . "ꆈꌠ꒿ Nuosuhxop")
+ ("nr" . "isiNdebele")
+ ("oc" . "occitan, lenga d'òc")
+ ("oj" . "ᐊᓂᔑᓈᐯᒧᐎᓐ")
+ ("cu" . "ѩзыкъ словѣньскъ")
+ ("om" . "Afaan Oromoo")
+ ("or" . "ଓଡ଼ିଆ")
+ ("os" . "ирон æвзаг")
+ ("pa" . "ਪੰਜਾਬੀ")
+ ("pi" . "पाऴि")
+ ("fa" . "فارسی")
+ ("pl" . "język polski, polszczyzna")
+ ("ps" . "پښتو")
+ ("pt" . "Português")
+ ("qu" . "Runa Simi, Kichwa")
+ ("rm" . "rumantsch grischun")
+ ("rn" . "Ikirundi")
+ ("ro" . "Română")
+ ("ru" . "Русский")
+ ("sa" . "संस्कृतम्")
+ ("sc" . "sardu")
+ ("sd" . "सिन्धी, سنڌي، سندھی‎")
+ ("se" . "Davvisámegiella")
+ ("sm" . "gagana fa'a Samoa")
+ ("sg" . "yângâ tî sängö")
+ ("sr" . "српски језик")
+ ("gd" . "Gàidhlig")
+ ("sn" . "chiShona")
+ ("si" . "සිංහල")
+ ("sk" . "slovenčina, slovenský jazyk")
+ ("sl" . "slovenski jezik, slovenščina")
+ ("so" . "Soomaaliga, af Soomaali")
+ ("st" . "Sesotho")
+ ("es" . "Español")
+ ("su" . "Basa Sunda")
+ ("sw" . "Kiswahili")
+ ("ss" . "SiSwati")
+ ("sv" . "svenska")
+ ("ta" . "தமிழ்")
+ ("te" . "తెలుగు")
+ ("tg" . "тоҷикӣ, toçikī, تاجیکی‎")
+ ("th" . "ไทย")
+ ("ti" . "ትግርኛ")
+ ("bo" . "བོད་ཡིག")
+ ("tk" . "Türkmen, Түркмен")
+ ("tl" . "Wikang Tagalog")
+ ("tn" . "Setswana")
+ ("to" . "faka Tonga")
+ ("tr" . "Türkçe")
+ ("ts" . "Xitsonga")
+ ("tt" . "татар теле, tatar tele")
+ ("tw" . "Twi")
+ ("ty" . "Reo Tahiti")
+ ("ug" . "ئۇيغۇرچە‎, Uyghurche")
+ ("uk" . "Українська")
+ ("ur" . "اردو")
+ ("uz" . "Oʻzbek, Ўзбек, أۇزبېك‎")
+ ("ve" . "Tshivenḓa")
+ ("vi" . "Tiếng Việt")
+ ("vo" . "Volapük")
+ ("wa" . "walon")
+ ("cy" . "Cymraeg")
+ ("wo" . "Wollof")
+ ("fy" . "Frysk")
+ ("xh" . "isiXhosa")
+ ("yi" . "ייִדיש")
+ ("yo" . "Yorùbá")
+ ("za" . "Saɯ cueŋƅ, Saw cuengh")
+ ("zu" . "isiZulu")))
+
+(defun expand-file-name* (name default-directory)
+ (expand-file-name name (concat "/" default-directory)))
+
+(org-export-define-derived-backend 'ennum-html 'html
+ :translate-alist
+ '((inner-template . ennum-html-inner-template)
+ (link . ennum-html-link))
+ :options-alist
+ '((:summary "SUMMARY" nil nil parse)
+ (:thumbnail "THUMBNAIL" nil nil t)
+ (:translation-group "TRANSLATION_GROUP" nil nil t)))
+
+(defun ennum-html-inner-template (contents info)
+ (concat
+ ;; Table of contents
+ (let ((depth (plist-get info :with-toc)))
+ (when depth (org-html-toc depth info)))
+ ;; Beginning of h-entry
+ "<article class=\"h-entry\">"
+ ;; Title
+ (format "<h1 class=\"p-name\">%s</h1>\n"
+ (org-export-data (plist-get info :title) info))
+ ;; Author and date
+ (let ((author (when (plist-get info :with-author)
+ (plist-get info :author)))
+ (date (when (plist-get info :with-date)
+ (org-export-get-date info))))
+ (when (or author date)
+ (xmlgen `(p "Published"
+ ,@(when author
+ `(" by "
+ (a :class "p-author h-card"
+ :href ,(ennum--absolute-uri "")
+ ,(car (plist-get info :author)))))
+ ,@(when date
+ `(" on "
+ (time :class "dt-published"
+ :datetime ,(org-export-get-date info "%Y-%m-%d 12:00:00")
+ ,(org-export-get-date info "%B %d, %Y"))))))))
+ ;; Interlanguage language links
+ (when-let (translations (plist-get info :translations))
+ (format "<p>In other languages: %s</p>"
+ (mapconcat
+ (lambda (translation)
+ (let ((lang (ennum-post-language translation))
+ (slug (ennum-post-slug translation)))
+ (replace-regexp-in-string
+ "<a " (format "<a hreflang=\"%s\" " lang)
+ (ennum-export-post slug
+ (map-elt ennum--iso-639-1-alist lang nil 'string=)
+ (org-export-backend-name
+ (plist-get info :back-end))))))
+ translations
+ ", ")))
+ ;; Tags
+ (when-let (tags (plist-get info :filetags))
+ (format "<p>Tags: %s</p>"
+ (mapconcat
+ (lambda (tag)
+ (replace-regexp-in-string
+ "<a " "<a class=\"p-category\" "
+ (ennum-export-tag (ennum-add-tongue-suffix tag (plist-get info :language))
+ tag (org-export-backend-name (plist-get info :back-end)))))
+ tags
+ ", ")))
+ ;; Summary
+ (format "<div class=\"p-summary\">%s</div>"
+ (org-export-data (plist-get info :summary) info))
+ ;; Document contents
+ (format "<div class=\"e-content\">%s</div>" contents)
+ ;; Footnotes section
+ (org-html-footnote-section info)
+ "</article>"))
+
+(defun ennum-html-link (link desc info)
+ ;; We override the html link transcoder to handle image links
+ ;; differently. We cannot use the `:export' property of
+ ;; `org-link-parameters' since those functions cannot access the
+ ;; `info' communication channel.
+ (let ((path (org-element-property :path link)))
+ (pcase (org-element-property :type link)
+ ("image"
+ ;; Convert image links to file links, get them transcoded by
+ ;; `org-html-link' and then remove the file:// scheme from the
+ ;; URI. Finally insert the transcoded image link in a link to a
+ ;; larger image as specified by the :image-link-width setting.
+ (format "<a href=\"%s\">%s</a>"
+ (expand-file-name*
+ (ennum-image-output-filename
+ path (ennum-setting :image-link-width))
+ (ennum-setting :images-directory))
+ (replace-regexp-in-string
+ (rx (group (or "src" "data")) "=\"file://") "\\1=\""
+ (org-html-link
+ (org-element-put-property
+ (org-element-put-property
+ link :path (url-encode-url
+ (expand-file-name*
+ (ennum-image-output-filename
+ path (ennum-setting :default-image-width))
+ (ennum-setting :images-directory))))
+ :type "file")
+ desc info))))
+ ;; Pass other link types to org-html-link
+ (_ (org-html-link link desc info)))))
+
+(defmacro ennum-follow (path)
+ `(ennum-with-current-directory (ennum-setting :working-directory)
+ (find-file ,path)))
+
+;; TODO: Pass title through org-export-data-with-backend or something
+;; similar in order to export org syntax in title
+(defun ennum-export-post (path desc backend)
+ (pcase backend
+ ((or 'ennum-html 'html)
+ (let ((filename (concat (expand-file-name path (ennum-setting :posts-directory))
+ ".org")))
+ (xmlgen `(a :href ,(url-encode-url
+ (expand-file-name* path (ennum-setting :posts-directory)))
+ ,(or desc (ennum-post-title (ennum-read-post filename)))))))))
+
+(defun ennum-follow-post (path)
+ (ennum-follow (expand-file-name (concat path ".org")
+ (ennum-setting :posts-directory))))
+
+(org-link-set-parameters
+ "post"
+ :export 'ennum-export-post
+ :follow 'ennum-follow-post)
+
+(defun ennum-follow-image (path)
+ (ennum-follow (expand-file-name path (ennum-setting :images-directory))))
+
+(org-link-set-parameters
+ "image" :follow 'ennum-follow-image)
+
+(defun ennum-export-thumbnail (path desc backend)
+ (pcase backend
+ ((or 'ennum-html 'html)
+ (xmlgen
+ `(img :src ,(url-encode-url
+ (expand-file-name*
+ (ennum-image-output-filename
+ path (ennum-setting :thumbnail-image-width))
+ (ennum-setting :images-directory))))))))
+
+(org-link-set-parameters
+ "thumbnail"
+ :export 'ennum-export-thumbnail
+ :follow 'ennum-follow-image)
+
+(defun ennum-export-video (path desc backend)
+ (pcase backend
+ ((or 'ennum-html 'html)
+ (let ((video-directory (ennum-setting :video-directory)))
+ (xmlgen
+ `(video :src ,(url-encode-url (expand-file-name* path video-directory))
+ :poster ,(url-encode-url
+ (expand-file-name* (ennum-video-poster path) video-directory))
+ :preload "none"
+ :controls ""))))))
+
+(org-link-set-parameters
+ "video" :export 'ennum-export-video)
+
+(defun ennum-export-static (path desc backend)
+ (pcase backend
+ ((or 'ennum-html 'html)
+ (xmlgen
+ `(a :href ,(url-encode-url
+ (expand-file-name* path (ennum-setting :static-directory)))
+ ,desc)))))
+
+(org-link-set-parameters
+ "static" :export 'ennum-export-static)
+
+(org-link-set-parameters
+ "tangle" :export 'ennum-export-static)
+
+(defun ennum-export-tag (tag desc backend)
+ (pcase backend
+ ((or 'ennum-html 'html)
+ (xmlgen
+ `(a :href ,(url-encode-url
+ (expand-file-name* tag (ennum-setting :tag-directory)))
+ ,(or desc tag))))))
+
+(org-link-set-parameters
+ "tag" :export 'ennum-export-tag)
+
+(provide 'ennum-html)