storyblok-richtext-renderer 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +23 -15
  3. data/README.md +24 -5
  4. data/coverage/.last_run.json +5 -0
  5. data/coverage/.resultset.json +7 -0
  6. data/coverage/.resultset.json.lock +0 -0
  7. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc.png +0 -0
  8. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  9. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_both.png +0 -0
  10. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc.png +0 -0
  11. data/coverage/assets/0.12.3/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  12. data/coverage/assets/0.12.3/application.css +1 -0
  13. data/coverage/assets/0.12.3/application.js +7 -0
  14. data/coverage/assets/0.12.3/colorbox/border.png +0 -0
  15. data/coverage/assets/0.12.3/colorbox/controls.png +0 -0
  16. data/coverage/assets/0.12.3/colorbox/loading.gif +0 -0
  17. data/coverage/assets/0.12.3/colorbox/loading_background.png +0 -0
  18. data/coverage/assets/0.12.3/favicon_green.png +0 -0
  19. data/coverage/assets/0.12.3/favicon_red.png +0 -0
  20. data/coverage/assets/0.12.3/favicon_yellow.png +0 -0
  21. data/coverage/assets/0.12.3/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  22. data/coverage/assets/0.12.3/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  23. data/coverage/assets/0.12.3/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  24. data/coverage/assets/0.12.3/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  25. data/coverage/assets/0.12.3/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  26. data/coverage/assets/0.12.3/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  27. data/coverage/assets/0.12.3/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  28. data/coverage/assets/0.12.3/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  29. data/coverage/assets/0.12.3/images/ui-icons_222222_256x240.png +0 -0
  30. data/coverage/assets/0.12.3/images/ui-icons_2e83ff_256x240.png +0 -0
  31. data/coverage/assets/0.12.3/images/ui-icons_454545_256x240.png +0 -0
  32. data/coverage/assets/0.12.3/images/ui-icons_888888_256x240.png +0 -0
  33. data/coverage/assets/0.12.3/images/ui-icons_cd0a0a_256x240.png +0 -0
  34. data/coverage/assets/0.12.3/loading.gif +0 -0
  35. data/coverage/assets/0.12.3/magnify.png +0 -0
  36. data/coverage/index.html +93 -0
  37. data/lib/storyblok/richtext/html_renderer/marks/anchor.rb +17 -0
  38. data/lib/storyblok/richtext/html_renderer/marks/highlight.rb +20 -0
  39. data/lib/storyblok/richtext/html_renderer/marks/link.rb +14 -1
  40. data/lib/storyblok/richtext/html_renderer/marks/subscript.rb +14 -0
  41. data/lib/storyblok/richtext/html_renderer/marks/superscript.rb +14 -0
  42. data/lib/storyblok/richtext/html_renderer/marks/text_style.rb +20 -0
  43. data/lib/storyblok/richtext/html_renderer/nodes/emoji.rb +23 -0
  44. data/lib/storyblok/richtext/html_renderer.rb +34 -2
  45. data/lib/storyblok/richtext/version.rb +1 -1
  46. data/spec/richtext_spec.rb +288 -2
  47. metadata +45 -13
  48. data/.DS_Store +0 -0
  49. data/.ruby-version +0 -1
  50. data/lib/.DS_Store +0 -0
  51. data/lib/storyblok/.DS_Store +0 -0
  52. data/lib/storyblok/richtext/html_renderer/.DS_Store +0 -0
  53. data/lib/storyblok/richtext/html_renderer/nodes/.DS_Store +0 -0
Binary file
Binary file
@@ -0,0 +1,93 @@
1
+ <!DOCTYPE html>
2
+ <html xmlns='http://www.w3.org/1999/xhtml'>
3
+ <head>
4
+ <title>Code coverage for Storyblok-ruby-richtext-renderer</title>
5
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
6
+ <script src='./assets/0.12.3/application.js' type='text/javascript'></script>
7
+ <link href='./assets/0.12.3/application.css' media='screen, projection, print' rel='stylesheet' type='text/css' />
8
+ <link rel="shortcut icon" type="image/png" href="./assets/0.12.3/favicon_green.png" />
9
+ <link rel="icon" type="image/png" href="./assets/0.12.3/favicon.png" />
10
+ </head>
11
+
12
+ <body>
13
+ <div id="loading">
14
+ <img src="./assets/0.12.3/loading.gif" alt="loading"/>
15
+ </div>
16
+ <div id="wrapper" class="hide">
17
+ <div class="timestamp">Generated <abbr class="timeago" title="2023-04-18T11:07:52-03:00">2023-04-18T11:07:52-03:00</abbr></div>
18
+ <ul class="group_tabs"></ul>
19
+
20
+ <div id="content">
21
+ <div class="file_list_container" id="AllFiles">
22
+ <h2>
23
+ <span class="group_name">All Files</span>
24
+ (<span class="covered_percent">
25
+ <span class="green">
26
+ 100.0%
27
+ </span>
28
+
29
+ </span>
30
+ covered at
31
+ <span class="covered_strength">
32
+ <span class="red">
33
+ 0.0
34
+ </span>
35
+ </span> hits/line
36
+ )
37
+ </h2>
38
+
39
+ <a name="AllFiles"></a>
40
+
41
+ <div>
42
+ <b>0</b> files in total.
43
+ </div>
44
+
45
+ <div class="t-line-summary">
46
+ <b>0</b> relevant lines,
47
+ <span class="green"><b>0</b> lines covered</span> and
48
+ <span class="red"><b>0</b> lines missed. </span>
49
+ (<span class="green">
50
+ 100.0%
51
+ </span>
52
+ )
53
+ </div>
54
+
55
+
56
+
57
+ <div class="file_list--responsive">
58
+ <table class="file_list">
59
+ <thead>
60
+ <tr>
61
+ <th>File</th>
62
+ <th class="cell--number">% covered</th>
63
+ <th class="cell--number">Lines</th>
64
+ <th class="cell--number">Relevant Lines</th>
65
+ <th class="cell--number">Lines covered</th>
66
+ <th class="cell--number">Lines missed</th>
67
+ <th class="cell--number">Avg. Hits / Line</th>
68
+
69
+ </tr>
70
+ </thead>
71
+ <tbody>
72
+
73
+ </tbody>
74
+ </table>
75
+ </div>
76
+ </div>
77
+
78
+
79
+
80
+ </div>
81
+
82
+ <div id="footer">
83
+ Generated by <a href="https://github.com/simplecov-ruby/simplecov">simplecov</a> v0.22.0
84
+ and simplecov-html v0.12.3<br/>
85
+ using RSpec
86
+ </div>
87
+
88
+ <div class="source_files">
89
+
90
+ </div>
91
+ </div>
92
+ </body>
93
+ </html>
@@ -0,0 +1,17 @@
1
+ module Storyblok::Richtext
2
+ module Marks
3
+ class Anchor < Mark
4
+
5
+ def matching
6
+ @node['type'] === 'anchor'
7
+ end
8
+
9
+ def tag
10
+ [{
11
+ tag: "span",
12
+ attrs: @node['attrs']
13
+ }]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ module Storyblok::Richtext
2
+ module Marks
3
+ class Highlight < Mark
4
+
5
+ def matching
6
+ @node['type'] === 'highlight'
7
+ end
8
+
9
+ def tag
10
+ attrs = {
11
+ style: "background-color:#{@node['attrs']['color']};"
12
+ }
13
+ [{
14
+ tag: "span",
15
+ attrs: attrs
16
+ }]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -11,11 +11,24 @@ module Storyblok::Richtext
11
11
 
12
12
  if attrs['anchor'].is_a?(String) and !attrs['anchor'].empty?
13
13
  attrs['href'] = "#{attrs['href']}##{attrs['anchor']}"
14
+ attrs.delete('anchor')
15
+ end
16
+
17
+ if attrs['linktype'].is_a?(String) and attrs['linktype'] == 'email'
18
+ emailContainer = attrs['href']
19
+ attrs['href'] = "mailto:#{emailContainer}"
20
+ end
21
+
22
+ if attrs['custom'].is_a?(Hash)
23
+ for item in attrs['custom'] do
24
+ attrs[item[0]] = item[1]
25
+ end
26
+ attrs.delete('custom')
14
27
  end
15
28
 
16
29
  [{
17
30
  tag: "a",
18
- attrs: attrs.slice('href', 'target')
31
+ attrs: attrs
19
32
  }]
20
33
  end
21
34
  end
@@ -0,0 +1,14 @@
1
+ module Storyblok::Richtext
2
+ module Marks
3
+ class Subscript < Mark
4
+
5
+ def matching
6
+ @node['type'] === 'subscript'
7
+ end
8
+
9
+ def tag
10
+ 'sub'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Storyblok::Richtext
2
+ module Marks
3
+ class Superscript < Mark
4
+
5
+ def matching
6
+ @node['type'] === 'superscript'
7
+ end
8
+
9
+ def tag
10
+ 'sup'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Storyblok::Richtext
2
+ module Marks
3
+ class TextStyle < Mark
4
+
5
+ def matching
6
+ @node['type'] === 'textStyle'
7
+ end
8
+
9
+ def tag
10
+ attrs = {
11
+ style: "background-color:#{@node['attrs']['color']};"
12
+ }
13
+ [{
14
+ tag: "span",
15
+ attrs: attrs
16
+ }]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ module Storyblok::Richtext
2
+ module Nodes
3
+ class Emoji < Node
4
+
5
+ def matching
6
+ @node['type'] === 'emoji'
7
+ end
8
+
9
+ def tag
10
+ attrs = {
11
+ 'data-type' => 'emoji',
12
+ 'data-name' => @node['attrs']['name'],
13
+ 'emoji' => @node['attrs']['emoji']
14
+ }
15
+
16
+ [{
17
+ tag: "span",
18
+ attrs: attrs
19
+ }]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -11,6 +11,11 @@ module Storyblok
11
11
  require_relative "html_renderer/marks/italic"
12
12
  require_relative "html_renderer/marks/link"
13
13
  require_relative "html_renderer/marks/styled"
14
+ require_relative "html_renderer/marks/anchor"
15
+ require_relative "html_renderer/marks/highlight"
16
+ require_relative "html_renderer/marks/subscript"
17
+ require_relative "html_renderer/marks/superscript"
18
+ require_relative "html_renderer/marks/text_style"
14
19
  require_relative "html_renderer/nodes/node"
15
20
  require_relative "html_renderer/nodes/bullet_list"
16
21
  require_relative "html_renderer/nodes/code_block"
@@ -25,6 +30,7 @@ module Storyblok
25
30
  require_relative "html_renderer/nodes/horizontal_rule"
26
31
  require_relative "html_renderer/nodes/text"
27
32
  require_relative "html_renderer/nodes/blok"
33
+ require_relative "html_renderer/nodes/emoji"
28
34
 
29
35
  class HtmlRenderer
30
36
  def initialize
@@ -36,7 +42,12 @@ module Storyblok
36
42
  Storyblok::Richtext::Marks::Code,
37
43
  Storyblok::Richtext::Marks::Italic,
38
44
  Storyblok::Richtext::Marks::Link,
39
- Storyblok::Richtext::Marks::Styled
45
+ Storyblok::Richtext::Marks::Styled,
46
+ Storyblok::Richtext::Marks::Anchor,
47
+ Storyblok::Richtext::Marks::Highlight,
48
+ Storyblok::Richtext::Marks::Subscript,
49
+ Storyblok::Richtext::Marks::Superscript,
50
+ Storyblok::Richtext::Marks::TextStyle
40
51
  ]
41
52
  @nodes = [
42
53
  Storyblok::Richtext::Nodes::HorizontalRule,
@@ -50,7 +61,8 @@ module Storyblok
50
61
  Storyblok::Richtext::Nodes::OrderedList,
51
62
  Storyblok::Richtext::Nodes::Paragraph,
52
63
  Storyblok::Richtext::Nodes::Text,
53
- Storyblok::Richtext::Nodes::Blok
64
+ Storyblok::Richtext::Nodes::Blok,
65
+ Storyblok::Richtext::Nodes::Emoji
54
66
  ]
55
67
  end
56
68
 
@@ -99,6 +111,8 @@ module Storyblok
99
111
  html.push(render_tag(node.single_tag))
100
112
  elsif node and node.html
101
113
  html.push(node.html)
114
+ elsif item['type'] == 'emoji'
115
+ html.push(render_emoji(item))
102
116
  end
103
117
 
104
118
  html.push(render_closing_tag(node.tag)) if node and node.tag
@@ -159,6 +173,24 @@ module Storyblok
159
173
  end
160
174
  found.first
161
175
  end
176
+
177
+ def render_emoji(item)
178
+ if item['attrs']['emoji']
179
+ return item['attrs']['emoji']
180
+ end
181
+
182
+ emoji_image_container = [{
183
+ tag: 'img',
184
+ attrs: {
185
+ src: item['attrs']['fallbackImage'],
186
+ draggable: 'false',
187
+ loading: 'lazy',
188
+ align: 'absmiddle',
189
+ },
190
+ }]
191
+
192
+ render_tag(emoji_image_container, ' /')
193
+ end
162
194
  end
163
195
  end
164
196
  end
@@ -1,6 +1,6 @@
1
1
  module Storyblok
2
2
  module Richtext
3
3
  # Gem Version
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.8'
5
5
  end
6
6
  end
@@ -129,7 +129,7 @@ describe 'richtext' do
129
129
  }
130
130
 
131
131
  renderer = Storyblok::Richtext::HtmlRenderer.new
132
- expect(renderer.render(doc)).to eq('<a href="/link" target="_blank">link text</a>')
132
+ expect(renderer.render(doc)).to eq('<a href="/link" target="_blank" uuid="300aeadc-c82d-4529-9484-f3f8f09cf9f5">link text</a>')
133
133
  end
134
134
  end
135
135
 
@@ -178,6 +178,292 @@ describe 'richtext' do
178
178
  }
179
179
 
180
180
  renderer = Storyblok::Richtext::HtmlRenderer.new
181
- expect(renderer.render(doc)).to eq('<a href="/link#anchor-text" target="_blank">link text</a>')
181
+ expect(renderer.render(doc)).to eq('<a href="/link#anchor-text" target="_blank" uuid="300aeadc-c82d-4529-9484-f3f8f09cf9f5">link text</a>')
182
+ end
183
+ end
184
+
185
+ describe 'richtext' do
186
+ it 'link to generate a tag with an email' do
187
+ doc = {
188
+ 'type' => 'doc',
189
+ 'content' => [
190
+ {
191
+ 'text' => 'an email link',
192
+ 'type' => 'text',
193
+ 'marks' => [
194
+ {
195
+ 'type' => 'link',
196
+ 'attrs' => {
197
+ 'href' => 'email@client.com',
198
+ 'target' => '_blank',
199
+ 'uuid' => nil,
200
+ 'linktype' => 'email'
201
+ }
202
+ }
203
+ ]
204
+ }
205
+ ]
206
+ }
207
+
208
+ renderer = Storyblok::Richtext::HtmlRenderer.new
209
+ expect(renderer.render(doc)).to eq('<a href="mailto:email@client.com" target="_blank" linktype="email">an email link</a>')
210
+ end
211
+ end
212
+
213
+ describe 'richtext' do
214
+ it 'should render a custom attribute in a link tag' do
215
+ doc = {
216
+ 'type' => 'paragraph',
217
+ 'content' => [
218
+ {
219
+ 'text' => 'A nice link with custom attr',
220
+ 'type' => 'text',
221
+ 'marks' => [
222
+ {
223
+ 'type' => 'link',
224
+ 'attrs' => {
225
+ 'href' => 'www.storyblok.com',
226
+ 'uuid' => '300aeadc-c82d-4529-9484-f3f8f09cf9f5',
227
+ # 'anchor' => nil,
228
+ 'custom' => {
229
+ 'rel' => 'nofollow',
230
+ 'title' => 'nice test',
231
+ },
232
+ 'target' => '_blank',
233
+ 'linktype' => 'url'
234
+ }
235
+ }
236
+ ]
237
+ }
238
+ ]
239
+ }
240
+
241
+ renderer = Storyblok::Richtext::HtmlRenderer.new
242
+ expect(renderer.render(doc)).to eq('<a href="www.storyblok.com" uuid="300aeadc-c82d-4529-9484-f3f8f09cf9f5" target="_blank" linktype="url" rel="nofollow" title="nice test">A nice link with custom attr</a>')
243
+ end
244
+ end
245
+
246
+ describe 'richtext' do
247
+ it 'should render a subscript' do
248
+ doc = {
249
+ 'type' => 'paragraph',
250
+ 'content' => [
251
+ {
252
+ 'text' => 'A Subscript text',
253
+ 'type' => 'text',
254
+ 'marks' => [
255
+ {
256
+ 'type' => 'subscript'
257
+ }
258
+ ]
259
+ }
260
+ ]
261
+ }
262
+
263
+ renderer = Storyblok::Richtext::HtmlRenderer.new
264
+ expect(renderer.render(doc)).to eq('<sub>A Subscript text</sub>')
265
+ end
266
+ end
267
+
268
+ describe 'richtext' do
269
+ it 'should render a superscript' do
270
+ doc = {
271
+ 'type' => 'paragraph',
272
+ 'content' => [
273
+ {
274
+ 'text' => 'A Superscript text',
275
+ 'type' => 'text',
276
+ 'marks' => [
277
+ {
278
+ 'type' => 'superscript'
279
+ }
280
+ ]
281
+ }
282
+ ]
283
+ }
284
+
285
+ renderer = Storyblok::Richtext::HtmlRenderer.new
286
+ expect(renderer.render(doc)).to eq('<sup>A Superscript text</sup>')
287
+ end
288
+ end
289
+
290
+ describe 'richtext' do
291
+ it 'should render a anchor in the text' do
292
+ doc = {
293
+ "type" => "doc",
294
+ "content" => [
295
+ {
296
+ "type" => "paragraph",
297
+ "content" => [
298
+ {
299
+ "text" => "Paragraph with anchor in the midle",
300
+ "type" => "text",
301
+ "marks" => [
302
+ {
303
+ "type" => "anchor",
304
+ "attrs" => {
305
+ "id" => "test"
306
+ }
307
+ }
308
+ ]
309
+ }
310
+ ]
311
+ }
312
+ ]
313
+ }
314
+
315
+ renderer = Storyblok::Richtext::HtmlRenderer.new
316
+ expect(renderer.render(doc)).to eq('<p><span id="test">Paragraph with anchor in the midle</span></p>')
317
+ end
318
+ end
319
+
320
+ describe 'richtext' do
321
+ it 'should render a h1 title with a anchor in the middle of the text' do
322
+ doc = {
323
+ 'type' => 'doc',
324
+ 'content' => [
325
+ {
326
+ 'type' => 'heading',
327
+ 'attrs' => {
328
+ 'level' => '1'
329
+ },
330
+ 'content' => [
331
+ {
332
+ 'text' => 'Title with ',
333
+ 'type' => 'text'
334
+ },
335
+ {
336
+ 'text' => 'Anchor',
337
+ 'type' => 'text',
338
+ 'marks' => [
339
+ {
340
+ 'type' => 'anchor',
341
+ 'attrs' => {
342
+ 'id' => 'test1'
343
+ }
344
+ }
345
+ ]
346
+ },
347
+ {
348
+ 'text' => ' in the midle',
349
+ 'type' => 'text'
350
+ }
351
+ ]
352
+ }
353
+ ]
354
+ }
355
+
356
+ renderer = Storyblok::Richtext::HtmlRenderer.new
357
+ expect(renderer.render(doc)).to eq('<h1>Title with <span id="test1">Anchor</span> in the midle</h1>')
358
+ end
359
+ end
360
+
361
+ describe 'richtext' do
362
+ it 'should render a text with highlight color' do
363
+ doc = {
364
+ 'type' => 'doc',
365
+ 'content' => [
366
+ {
367
+ 'text' => 'Highlighted text',
368
+ 'type' => 'text',
369
+ 'marks' => [
370
+ {
371
+ 'type' => 'highlight',
372
+ 'attrs' => {
373
+ 'color' => '#E72929',
374
+ },
375
+ },
376
+ ],
377
+ },
378
+ ],
379
+ }
380
+
381
+ renderer = Storyblok::Richtext::HtmlRenderer.new
382
+ expect(renderer.render(doc)).to eq('<span style="background-color:#E72929;">Highlighted text</span>')
383
+ end
384
+ end
385
+
386
+ describe 'richtext' do
387
+ it 'should render a text with text color' do
388
+ doc = {
389
+ 'type' => 'doc',
390
+ 'content' => [
391
+ {
392
+ 'text' => 'Colored text',
393
+ 'type' => 'text',
394
+ 'marks' => [
395
+ {
396
+ 'type' => 'textStyle',
397
+ 'attrs' => {
398
+ 'color' => '#E72929',
399
+ },
400
+ },
401
+ ],
402
+ },
403
+ ],
404
+ }
405
+
406
+ renderer = Storyblok::Richtext::HtmlRenderer.new
407
+ expect(renderer.render(doc)).to eq('<span style="background-color:#E72929;">Colored text</span>')
408
+ end
409
+ end
410
+
411
+ describe 'richtext' do
412
+ it 'should render a text with a emoji' do
413
+ doc = {
414
+ 'type' => 'doc',
415
+ 'content' => [
416
+ {
417
+ 'type' => 'paragraph',
418
+ 'content' => [
419
+ {
420
+ 'text' => 'Text with a emoji in the end ',
421
+ 'type' => 'text'
422
+ },
423
+ {
424
+ 'type' => 'emoji',
425
+ 'attrs' => {
426
+ 'name' => 'smile',
427
+ 'emoji' => '😄',
428
+ 'fallbackImage' => 'https://cdn.jsdelivr.net/npm/emoji-datasource-apple/img/apple/64/1f604.png'
429
+ }
430
+ },
431
+ ]
432
+ }
433
+ ]
434
+ }
435
+
436
+ renderer = Storyblok::Richtext::HtmlRenderer.new
437
+ expect(renderer.render(doc)).to eq('<p>Text with a emoji in the end <span data-type="emoji" data-name="smile" emoji="😄">😄</span></p>')
438
+ end
439
+ end
440
+
441
+ describe 'richtext' do
442
+ it 'should render a emoji with falbackimage' do
443
+ doc = {
444
+ 'type' => 'doc',
445
+ 'content' => [
446
+ {
447
+ 'type' => 'paragraph',
448
+ 'content' => [
449
+ {
450
+ 'text' => 'Text with a emoji in the end ',
451
+ 'type' => 'text'
452
+ },
453
+ {
454
+ 'type' => 'emoji',
455
+ 'attrs' => {
456
+ 'name' => 'trollface',
457
+ 'emoji' => nil,
458
+ 'fallbackImage' => 'https://github.githubassets.com/images/icons/emoji/trollface.png'
459
+ }
460
+ },
461
+ ]
462
+ }
463
+ ]
464
+ }
465
+
466
+ renderer = Storyblok::Richtext::HtmlRenderer.new
467
+ expect(renderer.render(doc)).to eq('<p>Text with a emoji in the end <span data-type="emoji" data-name="trollface"><img src="https://github.githubassets.com/images/icons/emoji/trollface.png" draggable="false" loading="lazy" align="absmiddle" /></span></p>')
182
468
  end
183
469
  end