Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quarto-dev
GitHub Repository: quarto-dev/quarto-cli
Path: blob/main/tests/docs/extensions/project/_extensions/quarto-ext/lightbox/lightbox.lua
3571 views
1
-- whether we're automatically lightboxing
2
local auto = false
3
4
-- whether we need lightbox dependencies added
5
local needsLightbox = false
6
7
-- a counter used to ensure each image is in its own gallery
8
local imgCount = 0
9
10
-- attributes to forward from the image to the newly created link
11
local kForwardedAttr = {
12
"title", "description", "desc-position",
13
"type", "effect", "width", "height", "zoomable", "draggable"
14
}
15
16
local kLightboxClass = "lightbox"
17
local kNoLightboxClass = "nolightbox"
18
local kGalleryPrefix = "quarto-lightbox-gallery-"
19
20
-- A list of images already within links that we can use to filter
21
local imagesWithinLinks = pandoc.List({})
22
23
return {
24
{
25
Meta = function(meta)
26
27
-- If the mode is auto, we need go ahead and
28
-- run if there are any images (ideally we would)
29
-- filter to images in the body, but that can be
30
-- left for future me to deal with
31
-- supports:
32
-- lightbox: auto
33
-- or
34
-- lightbox:
35
-- match: auto
36
local lbMeta = meta.lightbox
37
if lbMeta ~= nil and type(lbMeta) == 'table' then
38
if lbMeta[1] ~= nil then
39
lbMeta = lbMeta --[[@as any]]
40
if lbMeta[1].text == "auto" then
41
auto = true
42
end
43
elseif lbMeta.match ~= nil and pandoc.utils.stringify(lbMeta.match) == 'auto' then
44
auto = true
45
elseif lbMeta == true then
46
auto = true
47
end
48
end
49
end,
50
-- Find images that are already within links
51
-- we'll use this to filter out these images if
52
-- the most is auto
53
Link = function(linkEl)
54
pandoc.walk_inline(linkEl, {
55
Image = function(imageEl)
56
imagesWithinLinks[#imagesWithinLinks + 1] = imageEl
57
end
58
})
59
end
60
},
61
{
62
Image = function(imgEl)
63
if quarto.doc.isFormat("html:js") then
64
local isAlreadyLinked = imagesWithinLinks:includes(imgEl)
65
if (not isAlreadyLinked and auto and not imgEl.classes:includes(kNoLightboxClass))
66
or imgEl.classes:includes('lightbox') then
67
-- note that we need to include the dependency for lightbox
68
needsLightbox = true
69
imgCount = imgCount + 1
70
71
-- remove the class from the image
72
imgEl.attr.classes = imgEl.attr.classes:filter(function(clz)
73
return clz ~= kLightboxClass
74
end)
75
76
-- attributes for the link
77
local linkAttributes = {}
78
79
-- mark this image as a lightbox target
80
linkAttributes.class = kLightboxClass
81
82
-- get the alt text from image and use that as title
83
local title = nil
84
if imgEl.caption ~= nil and #imgEl.caption > 0 then
85
linkAttributes.title = pandoc.utils.stringify(imgEl.caption)
86
end
87
88
-- move a group attribute to the link, if present
89
if imgEl.attr.attributes.group ~= nil then
90
linkAttributes.gallery = imgEl.attr.attributes.group
91
imgEl.attr.attributes.group = nil
92
else
93
linkAttributes.gallery = kGalleryPrefix .. imgCount
94
end
95
96
-- forward any other known attributes
97
for i, v in ipairs(kForwardedAttr) do
98
if imgEl.attr.attributes[v] ~= nil then
99
-- forward the attribute
100
linkAttributes[v] = imgEl.attr.attributes[v]
101
102
-- clear the attribute
103
imgEl.attr.attributes[v] = nil
104
end
105
end
106
107
-- wrap decorated images in a link with appropriate attrs
108
local link = pandoc.Link({imgEl}, imgEl.src, nil, linkAttributes)
109
return link
110
end
111
end
112
end,
113
Meta = function(meta)
114
-- If we discovered lightbox-able images
115
-- we need to include the dependencies
116
if needsLightbox then
117
-- add the dependency
118
quarto.doc.addHtmlDependency({
119
name = 'glightbox',
120
scripts = {'resources/js/glightbox.min.js'},
121
stylesheets = {'resources/css/glightbox.min.css', 'lightbox.css'}
122
})
123
124
-- read lightbox options
125
local lbMeta = meta.lightbox
126
local lbOptions = {}
127
local readEffect = function(el)
128
local val = pandoc.utils.stringify(el)
129
if val == "fade" or val == "zoom" or val == "none" then
130
return val
131
else
132
error("Invalid effect " + val)
133
end
134
end
135
136
-- permitted options include:
137
-- lightbox:
138
-- effect: zoom | fade | none
139
-- desc-position: top | bottom | left |right
140
-- loop: true | false
141
-- class: <class-name>
142
local effect = "zoom"
143
local descPosition = "bottom"
144
local loop = true
145
local skin = nil
146
147
-- The selector controls which elements are targeted.
148
-- currently, it always targets .lightbox elements
149
-- and there is no way for the user to change this
150
local selector = "." .. kLightboxClass
151
152
if lbMeta ~= nil and type(lbMeta) == 'table' then
153
if lbMeta.effect ~= nil then
154
effect = readEffect(lbMeta.effect)
155
end
156
157
if lbMeta['desc-position'] ~= nil then
158
descPosition = pandoc.utils.stringify(lbMeta['desc-position'])
159
end
160
161
if lbMeta['css-class'] ~= nil then
162
skin = pandoc.utils.stringify(lbMeta['css-class'])
163
end
164
165
if lbMeta.loop ~= nil then
166
loop = lbMeta.loop
167
end
168
end
169
170
-- Generate the options to configure lightbox
171
local options = {
172
selector = selector,
173
closeEffect = effect,
174
openEffect = effect,
175
descPosition = descPosition,
176
loop = loop,
177
}
178
if skin ~= nil then
179
options.skin = skin
180
end
181
local optionsJson = quarto.json.encode(options)
182
183
-- generate the initialization script with the correct options
184
local scriptTag = "<script>var lightboxQuarto = GLightbox(" .. optionsJson .. ");</script>"
185
186
-- inject the rendering code
187
quarto.doc.includeText("after-body", scriptTag)
188
189
end
190
end
191
}}
192
193