;; -*- lexical-binding: t -*-
(require 'ox)
(require 'subr-x)
(require 'xmlgen)
(require 'ennum-lang)
(defun expand-file-name* (name base-directory)
(expand-file-name name (concat "/" base-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)
(:html-doctype "HTML_DOCTYPE" nil "html5")))
(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
""
;; Title
(format "%s
\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 (ennum-post-translations (plist-get info :ennum-post)))
(format "In other languages: %s
"
(mapconcat
(pcase-lambda (`(,lang . ,slug))
(replace-regexp-in-string
"Tags: %s
"
(mapconcat
(lambda (tag)
(replace-regexp-in-string
"%s"
(org-export-data (plist-get info :summary) info))
;; Document contents
(format "%s
" contents)
;; Footnotes section
(org-html-footnote-section info)
""))
(defun ennum-html-find-link (type path info)
"Find link of TYPE and PATH in post object stored in
:ennum-posts of property list INFO."
(seq-find (lambda (link)
(and (eq (ennum-link-type link) type)
(string= (ennum-link-path link) path)))
(ennum-post-links (plist-get info :ennum-post))))
(defun ennum-html-link (link desc info)
;; We override the html link transcoder to handle image, post and
;; video 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 "%s"
(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 :image-width))
(ennum-setting :images-directory))))
:type "file")
desc info))))
("post"
(ennum-html-export-post
path
(or desc (ennum-post-link-target-title
(ennum-html-find-link 'post path info)))
(org-export-backend-name (plist-get info :back-end))))
("video"
(xmlgen
`(video :src ,(url-encode-url
(expand-file-name* path (ennum-setting :videos-directory)))
:poster ,(url-encode-url
(expand-file-name*
(ennum-video-link-poster
(ennum-html-find-link 'video path info))
(ennum-setting :images-directory)))
:preload "none"
:controls "")))
;; Pass other link types to org-html-link
(_ (org-html-link link desc info)))))
(defmacro ennum-html-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-html-export-post (path desc backend)
(pcase backend
((or 'ennum-html 'html)
(xmlgen `(a :href ,(url-encode-url
(expand-file-name* path (ennum-setting :posts-directory)))
,desc)))))
(defun ennum-html-follow-post (path)
(ennum-html-follow (expand-file-name (concat path ".org")
(ennum-setting :posts-directory))))
(org-link-set-parameters
"post"
:export 'ennum-html-export-post
:follow 'ennum-html-follow-post)
(defun ennum-html-follow-image (path)
(ennum-html-follow (expand-file-name path (ennum-setting :images-directory))))
(org-link-set-parameters
"image" :follow 'ennum-html-follow-image)
(defun ennum-html-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 :image-thumbnail-width))
(ennum-setting :images-directory))))))))
(org-link-set-parameters
"thumbnail"
:export 'ennum-html-export-thumbnail
:follow 'ennum-html-follow-image)
(defun ennum-html-follow-video (path)
(ennum-html-follow (expand-file-name path
(ennum-setting :videos-directory))))
(org-link-set-parameters
"video"
:follow 'ennum-html-follow-video)
(defun ennum-html-export-pdf (path desc backend)
(pcase backend
((or 'ennum-html 'html)
(xmlgen
(let ((link-path (url-encode-url
(expand-file-name* path (ennum-setting :static-directory)))))
`(object :data ,link-path
:type "application/pdf"
:width ,(ennum-setting :pdf-width)
:height ,(ennum-setting :pdf-height)
"Download " (a :href ,link-path ,path)))))))
(org-link-set-parameters
"pdf" :export 'ennum-html-export-pdf)
(defun ennum-html-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-html-export-static)
(org-link-set-parameters
"tangle" :export 'ennum-html-export-static)
(defun ennum-html-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-html-export-tag)
(provide 'ennum-html)