1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
;; -*- 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
"<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 (ennum-post-translations (plist-get info :ennum-post)))
(format "<p>In other languages: %s</p>"
(mapconcat
(pcase-lambda (`(,lang . ,slug))
(replace-regexp-in-string
"<a " (format "<a hreflang=\"%s\" " lang)
(ennum-html-export-post
slug
(map-elt ennum--iso-639-1-alist lang)
(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-html-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-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 "<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 :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)
|