1+ local kAfterBody = " after-body"
2+ local kInHeader = " in-header"
3+ local kBeforeBody = " before-body"
4+
5+ local kUsePackages = " packages"
6+
7+ local urlPattern = " (https?://[%w%$%-%_%.%+%!%*%'%(%)%:%%]+/)(.+)"
8+
9+ -- TODO: Support alignment
10+ -- margin-left: auto; margin-right: auto; display: block;
11+
12+ -- TODO: Place a link for non-html output
13+
14+ local alignmentStyles = [[
15+ <style>
16+ .linkedin-post,
17+ .text-post-media,
18+ .pinterest-rendered,
19+ .twitter-tweet-rendered,
20+ .instagram-media,
21+ .mastodon-embed {
22+ display: block;
23+ margin-left: auto !important;
24+ margin-right: auto !important;
25+ }
26+ </style>
27+ ]]
28+
29+ local function parseUrl (url )
30+ local baseUrl , urlPath = url :match (urlPattern )
31+ return {
32+ url = url ,
33+ base = baseUrl ,
34+ path = urlPath
35+ }
36+ end
37+
38+
39+ local function makeBox (text , url , icon , color )
40+ return pandoc .Div (pandoc .List ({
41+ pandoc .RawInline (' latex' , ' \\ begin{centering}\\ begin{tcolorbox}[hbox,\n colframe=lightgray,\n colback=white]\n ' ),
42+ pandoc .RawInline (' latex' , ' \\ textcolor{' .. color .. ' }{{\\ Large {' .. icon .. ' }}} %' ),
43+ pandoc .Link (pandoc .RawInline (" latex" , ' \\ raisebox{0.1 em}{' .. text .. ' }' ),url ),
44+ pandoc .RawInline (' latex' , ' \n\\ end{tcolorbox}\\ end{centering}\n\\ vspace{1em}' )
45+ }))
46+ end
47+
48+ local boxPackages = {
49+ " tcolorbox" ,
50+ " fontawesome5"
51+ }
52+
53+ local threads = {
54+ canHandle = function (urlData )
55+ return urlData .base :find (" threads.net" )
56+ end ,
57+ handle = {
58+ html = function (urlData )
59+ local iframe = ' <blockquote class="text-post-media" data-text-post-permalink="' .. urlData .url .. ' " data-text-post-version="0"><a href="' .. urlData .url .. ' "></a></blockquote>'
60+ return {
61+ block = pandoc .RawBlock (" html" , iframe ),
62+ [kAfterBody ] = ' <script async defer src="https://www.threads.net/embed.js"></script>' ,
63+ [kInHeader ] = alignmentStyles
64+ }
65+ end ,
66+ latex = function (urlData )
67+ return {
68+ block = makeBox (" Click to view embedded Threads post." , urlData .url , " \\ faShareSquare" , " black" ),
69+ [kUsePackages ] = boxPackages
70+ }
71+ end ,
72+ other = function (urlData )
73+ return {
74+ block = pandoc .Link (" Click to view embedded Threads post." , urlData .url )
75+ }
76+ end
77+ }
78+ }
79+
80+ local instagram = {
81+ canHandle = function (urlData )
82+ return urlData .base :find (" instagram.com" )
83+ end ,
84+ handle = {
85+ html = function (urlData )
86+ local iframe = ' <blockquote class="instagram-media" data-instgrm-version="7" ><a href="' .. urlData .url .. ' "></a></blockquote>'
87+ return {
88+ block = pandoc .RawBlock (" html" , iframe ),
89+ [kAfterBody ] = ' <script async defer src="//platform.instagram.com/en_US/embeds.js"></script>'
90+ }
91+ end ,
92+ latex = function (urlData )
93+ return {
94+ block = makeBox (" Click to view embedded Instagram post." , urlData .url , " \\ faInstagram" , " RubineRed" ),
95+ [kUsePackages ] = boxPackages
96+
97+ }
98+ end ,
99+ other = function (urlData )
100+ return {
101+ block = pandoc .Link (" Click to view embedded Instagram post." , urlData .url )
102+ }
103+ end
104+ }
105+ }
106+
107+ local twitter = {
108+ canHandle = function (urlData )
109+ return urlData .base :find (" twitter.com" )
110+ end ,
111+ handle = {
112+ html = function (urlData )
113+ local iframe = ' <blockquote class="twitter-tweet" id="foobar123"><a href="' .. urlData .url .. ' "></a></blockquote>'
114+ return {
115+ block = pandoc .RawBlock (" html" , iframe ),
116+ [kAfterBody ] = ' <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>'
117+ }
118+ end ,
119+ latex = function (urlData )
120+ return {
121+ block = makeBox (" Click to view embedded Twitter post." , urlData .url , " \\ faTwitterSquare" , " ProcessBlue" ),
122+ [kUsePackages ] = boxPackages
123+ }
124+ end ,
125+ other = function (urlData )
126+ return {
127+ block = pandoc .Link (" Click to view embedded Twitter post." , urlData .url )
128+ }
129+ end
130+ }
131+ }
132+
133+ local pinterest = {
134+ canHandle = function (urlData )
135+ return urlData .base :find (" pinterest.com" )
136+ end ,
137+ handle = {
138+ html = function (urlData )
139+ local id = urlData .path :gsub (" pin/" , " " )
140+ if id :match (" /$" ) then
141+ id = id :sub (1 , - 2 )
142+ end
143+ local iframe = ' <iframe class="pinterest-rendered" src="https://assets.pinterest.com/ext/embed.html?id=' .. id .. ' " height="316" width="345" frameborder="0" scrolling="no" style=""></iframe>'
144+ return {
145+ block = pandoc .RawBlock (" html" , iframe ),
146+ }
147+ end ,
148+ latex = function (urlData )
149+ return {
150+ block = makeBox (" Click to view embedded Pinterest post." , urlData .url , " \\ faPinterestSquare" , " red" ),
151+ [kUsePackages ] = boxPackages
152+ }
153+ end ,
154+ other = function (urlData )
155+ return {
156+ block = pandoc .Link (" Click to view embedded Pinterest post." , urlData .url )
157+ }
158+ end
159+ }
160+ }
161+
162+ local linkedin = {
163+ canHandle = function (urlData )
164+ return urlData .base :find (" linkedin.com" )
165+ end ,
166+ handle = {
167+ html = function (urlData )
168+ local pattern = " (%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d+)"
169+ local id = urlData .path :match (pattern )
170+ if (id ) then
171+ -- https://www.linkedin.com/posts/posit-software_quarto-quarto-14-activity-7156030921387778049-dHKD?utm_source=share&utm_medium=member_desktop
172+ local iframe = ' <iframe class="linkedin-post" src="https://www.linkedin.com/embed/feed/update/urn:li:activity:' .. id .. ' " height="1062" width="504" frameborder="0" allowfullscreen="" title="Embedded post"></iframe>'
173+ return {
174+ block = pandoc .RawBlock (" html" , iframe ),
175+ [kAfterBody ] = ' <script src="' .. urlData .base .. ' embed.js" async="async"></script>' ,
176+ [kInHeader ] = alignmentStyles
177+ }
178+ else
179+ return nil
180+ end
181+ end ,
182+ latex = function (urlData )
183+ return {
184+ block = makeBox (" Click to view embedded LinkedIn post." , urlData .url , " \\ faLinkedin" , " RoyalBlue" ),
185+ [kUsePackages ] = boxPackages
186+ }
187+ end ,
188+ other = function (urlData )
189+ return {
190+ block = pandoc .Link (" Click to view embedded LinkedIn post." , urlData .url )
191+ }
192+ end
193+ }
194+ }
195+
196+ local mastodon = {
197+ canHandle = function (urlData )
198+ return urlData .path :find (" @[%w._-]+/%d%d%d%d%d%d*" )
199+ end ,
200+ handle = {
201+ html = function (urlData )
202+ local iframe = ' <iframe src="' .. urlData .url .. ' /embed" class="mastodon-embed" style="max-width: 100%; border: 0;" width="400" allowfullscreen="allowfullscreen"></iframe>'
203+ return {
204+ block = pandoc .RawBlock (" html" , iframe ),
205+ [kAfterBody ] = ' <script src="' .. urlData .base .. ' embed.js" async="async"></script>' ,
206+ [kInHeader ] = alignmentStyles
207+ }
208+ end ,
209+ latex = function (urlData )
210+ return {
211+ block = makeBox (" Click to view embedded Mastodon post." , urlData .url , " \\ faMastodon" , " Orchid" ),
212+ [kUsePackages ] = boxPackages
213+ }
214+ end ,
215+ other = function (urlData )
216+ return {
217+ block = pandoc .Link (" Click to view embedded Mastodon post." , urlData .url )
218+ }
219+ end
220+ }
221+ }
222+
223+ local handlers = {
224+ threads ,
225+ instagram ,
226+ twitter ,
227+ pinterest ,
228+ linkedin ,
229+ mastodon
230+ }
231+
232+ return {
233+ [' share-post' ] = function (args , kwargs , meta )
234+ local result_block
235+ local url = args [1 ]
236+ -- html output
237+ local urlData = parseUrl (url )
238+ for i ,handler in ipairs (handlers ) do
239+
240+ if handler .canHandle (urlData ) then
241+
242+ local make_result = handler .handle .other
243+ if quarto .doc .is_format (" html" ) then
244+ make_result = handler .handle .html
245+ elseif quarto .doc .is_format (" pdf" ) then
246+ make_result = handler .handle .latex
247+ end
248+
249+ -- return the raw html block
250+ local result = make_result (urlData )
251+ result_block = result .block
252+
253+ -- inject dependencies
254+ if result [kInHeader ] ~= nil then
255+ quarto .doc .include_text (kInHeader , result [kInHeader ])
256+ end
257+ if result [kBeforeBody ] ~= nil then
258+ quarto .doc .include_text (kBeforeBody , result [kBeforeBody ])
259+ end
260+ if result [kAfterBody ] ~= nil then
261+ quarto .doc .include_text (kAfterBody , result [kAfterBody ])
262+ end
263+ if result [kUsePackages ] ~= nil then
264+ for _i ,v in ipairs (result [kUsePackages ]) do
265+ quarto .doc .use_latex_package (v )
266+ end
267+ end
268+ end
269+ end
270+ if result_block == nil then
271+ quarto .log .warning (" Unable to resolve post url " .. url .. " \n No post was embedded." )
272+ end
273+ return result_block or {}
274+ end
275+ }
0 commit comments