@ecency/render-helper 2.3.4 → 2.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecency/render-helper",
3
- "version": "2.3.4",
3
+ "version": "2.3.6",
4
4
  "description": "Markdown+Html Render helper",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -21,7 +21,15 @@ export const ALLOWED_ATTRIBUTES: XSSWhiteList = {
21
21
  'title',
22
22
  'data-id'
23
23
  ],
24
- 'img': ['src', 'alt', 'class'],
24
+ 'img': [
25
+ 'src',
26
+ 'alt',
27
+ 'class',
28
+ 'loading',
29
+ 'fetchpriority',
30
+ 'decoding',
31
+ 'itemprop'
32
+ ],
25
33
  'span': ['class'],
26
34
  'iframe': ['src', 'class', 'frameborder', 'allowfullscreen', 'webkitallowfullscreen', 'mozallowfullscreen', 'sandbox'],
27
35
  'div': ['class'],
@@ -35,12 +43,12 @@ export const ALLOWED_ATTRIBUTES: XSSWhiteList = {
35
43
  'blockquote': ['class'],
36
44
  'sup': [],
37
45
  'sub': [],
38
- 'h1': [],
39
- 'h2': [],
40
- 'h3': [],
41
- 'h4': [],
42
- 'h5': [],
43
- 'h6': [],
46
+ 'h1': ['dir'],
47
+ 'h2': ['dir'],
48
+ 'h3': ['dir'],
49
+ 'h4': ['dir'],
50
+ 'h5': ['dir'],
51
+ 'h6': ['dir'],
44
52
  'p': ['dir'],
45
53
  'center': [],
46
54
  'ul': [],
@@ -4,13 +4,13 @@ import { markdown2Html } from './markdown-2-html'
4
4
  const fs = require('fs')
5
5
  const path = require('path')
6
6
  const SNAPSHOT_JSON = {
7
- "markdown_2_html_test_files_1_should_catch_images_in_table": "<p dir=\"auto\"><span>Congratulations <a class=\"markdown-author-link\" data-author=\"dunsky\">@dunsky</a>! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :</span></p>\n<table><tr><td><span><img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/9RTqgyyu8sX2kxvHt3ueNhDJEActwvqfV9wXt7pGKpjnWxBVz6r6Lv5n7t2RYBogkr5EjvnLjk.png?format=match&amp;mode=fit\" /></span></td><td>You made more than 6000 upvotes. Your next target is to reach 7000 upvotes.</td></tr>\n<tr><td><span><img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/9RTqgyyu8sX2kxvHt3ueNhDJEActwvqfV9wXt7pGKpjnVKjKxTD5Xwi6jJqBW9PAmtMWvTCvPF.png?format=match&amp;mode=fit\" /></span></td><td>You published more than 250 posts. Your next target is to reach 300 posts.</td></tr>\n</table>\n<p dir=\"auto\"><sub><em><a class=\"markdown-external-link\" data-href=\"https://steemitboard.com/@dunsky\">Click here to view your Board of Honor</a></em></sub><br />\n<sub><em>If you no longer want to receive notifications, reply to this comment with the word</em> <code>STOP</code></sub></p>\n<p dir=\"auto\">To support your work, I also upvoted your post!</p>\n<blockquote>\n<p dir=\"auto\">Support <a class=\"markdown-external-link\" data-href=\"https://steemit.com/@steemitboard\">SteemitBoard's project</a>! <strong><a class=\"markdown-external-link\" data-href=\"https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&amp;approve=1\">Vote for its witness</a></strong> and <strong>get one more award</strong>!</p>\n</blockquote>",
7
+ "markdown_2_html_test_files_1_should_catch_images_in_table": "<p dir=\"auto\"><span>Congratulations <a class=\"markdown-author-link\" data-author=\"dunsky\">@dunsky</a>! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :</span></p>\n<table><tr><td><span><img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/9RTqgyyu8sX2kxvHt3ueNhDJEActwvqfV9wXt7pGKpjnWxBVz6r6Lv5n7t2RYBogkr5EjvnLjk.png?format=match&amp;mode=fit\" loading=\"eager\" fetchpriority=\"high\" itemprop=\"image\" /></span></td><td>You made more than 6000 upvotes. Your next target is to reach 7000 upvotes.</td></tr>\n<tr><td><span><img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/9RTqgyyu8sX2kxvHt3ueNhDJEActwvqfV9wXt7pGKpjnVKjKxTD5Xwi6jJqBW9PAmtMWvTCvPF.png?format=match&amp;mode=fit\" loading=\"eager\" fetchpriority=\"high\" itemprop=\"image\" /></span></td><td>You published more than 250 posts. Your next target is to reach 300 posts.</td></tr>\n</table>\n<p dir=\"auto\"><sub><em><a class=\"markdown-external-link\" data-href=\"https://steemitboard.com/@dunsky\">Click here to view your Board of Honor</a></em></sub><br />\n<sub><em>If you no longer want to receive notifications, reply to this comment with the word</em> <code>STOP</code></sub></p>\n<p dir=\"auto\">To support your work, I also upvoted your post!</p>\n<blockquote>\n<p dir=\"auto\">Support <a class=\"markdown-external-link\" data-href=\"https://steemit.com/@steemitboard\">SteemitBoard's project</a>! <strong><a class=\"markdown-external-link\" data-href=\"https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&amp;approve=1\">Vote for its witness</a></strong> and <strong>get one more award</strong>!</p>\n</blockquote>",
8
8
  "markdown_2_html_test_files_3_should_replace_busy_links_properly": "<p dir=\"auto\"><img src=\"https://.esteem.app/0x0/https://ipfs.busy.org/ipfs/QmPziJCkx8w62UZCz1TNxAMsgf1uTnPZdVKAYjLBWvMzeD\" alt=\"image.png\" /></p>\n<p dir=\"auto\"><a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-1-2\">Part 1 - 2</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-3\">Part 3</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-4\">Part 4</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-5\">Part 5</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-6\">Part 6</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-7\">Part 7</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-8\">Part 8</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-9\">Part 9</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-10\">Part 10</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-11\">Part 11</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-12\">Part 12</a></p>\n<p dir=\"auto\"><strong>Part 13</strong></p>\n<p dir=\"auto\">Members of the Yerşehir caravan have surrendered their weapons to imperial soldiers at the entrance of Istanbul by the agreement provided earlier. The imperial soldiers arrested them immediately after the surrender of the weapons, and they entered the city with their hands chained.</p>\n<p dir=\"auto\">“The Yerşehir administration will ask you the account of this disrespect,” said Tamra to the proud Commander Timor on the pony. Tamra was angry because an ordinary soldier pushed her.</p>\n<p dir=\"auto\">\"You should be thankful we didn't strip you naked and had you wandering the streets of the city,\" said Commander Timor.</p>\n<p dir=\"auto\">Doma turned to the commander and said, “That's not how we dealt with you. Still, I assume you're doing your duty. I ask you to inform your superiors as soon as possible.”</p>\n<p dir=\"auto\">”You may be executed for armed entry into the Imperial lands,\" said the commander.</p>\n<p dir=\"auto\">“You like to dramatize things,” Akman said. Although Commander Timor was angry with Akman's happy face, he chose to keep the sarcastic look on his face.</p>\n<p dir=\"auto\">When he was taken to the dungeon, Akman was watching the buildings on the road, the squares adorned with sculptures, statues, and facades reflecting the beauty of East Roman stone craftsmanship.</p>\n<p dir=\"auto\">After passing the Hippodrome, which is one of the rare works of the ancient world, they entered a narrow tunnel and went down a ladder descending by turning. The soldiers locked them in a large gallery and returned. The water was dripping from the high ceiling of the dungeon, and the air they breathed was quite damp. Akman saw two rats with the size of cats running to their holes, terrified by the sound of footsteps.</p>\n<p dir=\"auto\">”I don't think they're gonna keep us here for long,\" Akman said.</p>\n<p dir=\"auto\">Akman was wrong; they told stories to each other in the first few days while there was no authority to call and ask for them. One of the dungeon guards came once a day and left a cup of water and a disgusting wheat porridge in the cell. The amount of oatmeal brought by the guard was so small that it was even possible for them to starve if the situation went on like this.</p>\n<p dir=\"auto\">Akman was cheerful as if he was at the banquet table, not at the dungeon. His joy was so bizarre that the team members began to think he was out of his mind. As the days passed, he was weakened by malnutrition; his clothes were stained, and his face was blackened. Still, he didn't lose anything from his joy. When asked how it can be so enjoyable, he said, “peace and light are within us. Just let's call and find out.\"</p>\n<p dir=\"auto\">Days later, an officer finally appeared at the door of the dungeon. Now, even the sparkle in the eyes of Akman has been lost, and Doma was unable to get up from where he was sleeping because of his illness. “The emperor will meet with the two representatives of your choice in two days,” said Chlorus, who brought plenty of food with him. Chlorus was handling his business with care. He brought water and ash to the cell to make sure they didn't smell bad, and he arranged a basin for their clothes. After washing, a barber would cut off their hair and beard. When they talk to the emperor, they should not extend the word and that they should give satisfying answers to the questions asked.</p>\n<p dir=\"auto\">Akman and Doma were taken from prison by the guards to be brought to the emperor. They agreed to hold a reasonable discourse during the interview. They were ready to suffer the maltreatment for the well-being of their country. The Imperial Palace adjacent to the Hippodrome was quite magnificent. They couldn't retrieve their eyes from the mosaics on the floor, the tiles on the walls and the stained glass windows. They passed through the large gate of the palace and entered the inner courtyard, where they waited for a while and then came to the emperor's presence.</p>\n<p dir=\"auto\">Since Doma's disease has not passed yet, Akman was holding his arm. As a matter of fact, he hasn't been able to speak; he agreed to join the meeting to show The Emperor what a terrible treatment they had.</p>\n<p dir=\"auto\">As soon as Emperor Valens saw Doma, he noticed his discomfort and told the servants to bring him a chair to sit down.</p>\n<p dir=\"auto\">“You wanted to see me,” said the Emperor, sitting on a plain throne compared to the splendor of the palace.</p>\n<p dir=\"auto\">”In the name of my people, I share your sorrow,\" said Akman.</p>\n<p dir=\"auto\">The emperor looked at Akman with the eyes asking, \"what is it about?”</p>\n<p dir=\"auto\">“I think robots attack your stables,” Akman said. Doma, who saw the environment as blurry due to high fever, turned and looked at Akman with amazement.</p>\n<p dir=\"auto\">”Few people know that yet, \" said Emperor Valens. Akman heard the news from the two soldiers they encountered on the way to the dungeon; the soldiers thought others did not understand them because they were whispering. As the security of his country is concerned, Akman chose to transfer the incident to the emperor in a different manner.</p>\n<p dir=\"auto\">\"We came to Istanbul to warn you about this. When the imperial authorities said in the dungeon that we could finally come to your peace, I understood that the attack has occurred,” Akman said.</p>\n<p dir=\"auto\">“You speak our language very well,” said the emperor.</p>\n<p dir=\"auto\">“Master Doma is much better than me, I hoped he'd be able to talk, but I was wrong,\" Akman said.</p>\n<p dir=\"auto\">\"I give you my regards and my gratitude for showing us the grace of acceptance. Because of my illness, I beg forgiveness for the imperfections that I can handle,” Doma said.</p>\n<p dir=\"auto\">“I will ask without hesitation: what could we have done to draw the wrath of God upon us, and what should we do to be merciful to his forgiveness?”</p>\n<p dir=\"auto\">Akman did not tell the emperor that events had begun with Ordin rising to Earth. He didn't want him to think they were in charge of the activities. Moreover, there was no evidence that the attacks on the stables in Yerşehir and Istanbul were related to Ordin's action. It was more than three months ago, and it could have been a coincidence.</p>\n<p dir=\"auto\">“I do not think that what happened is related to any sin.”</p>\n<p dir=\"auto\">“Foreigners come to our city with magical weapons, and ten days later, such an attack is taking place. Is that a coincidence?”</p>\n<p dir=\"auto\">\"I suspect that your scientists have already studied our weapons and have partially solved their operational principles. I assure you, our weapons work in accordance with scientific rules. I don't know why we're being treated so hard in your country.”</p>\n<p dir=\"auto\">“Could it be because you closed your doors to our country with a unilateral decision you made two centuries ago? According to historical records, despite the insistence of our empire, we have not even been able to negotiate the matter.”</p>\n<p dir=\"auto\">“It was a great travesty that half of our people died because of the plague. But that's not a valid excuse. I think the decision we made on time was wrong. During the past, we have been deprived of the benefits that we can achieve mutually. Given that the tunnel system makes wars almost impossible, it is not reasonable for us to continue such a mistake,\" Akman said.</p>\n<p dir=\"auto\">“I haven't received a satisfactory answer to my questions yet?\" the emperor said, despite the tone of his voice, his eyes were warm to Akman.</p>\n<p dir=\"auto\">\"I have to admit I don't know the answer to your questions, even if it's embarrassing for a philosopher. We came to Istanbul to find the answer to this question together.”</p>\n<p dir=\"auto\">\"I want to learn the working principles and how to produce the weapons you bring with you. This is the only way we can initiate an equality-based relationship.”</p>\n<p dir=\"auto\">\"I am not authorized to make such a decision. But I don't think your offer will be rejected at a time when we need cooperation to defend our cities,\" Akman said.</p>\n<p dir=\"auto\">After the meeting with Emperor Valens, the Yerşehir delegation was removed from prison, their belongings were returned, and they were sent from Istanbul with a ceremony in accordance with diplomatic traditions.</p>\n<p dir=\"auto\">Image Source: pixabay.com</p>",
9
9
  "markdown_2_html_test_files_4_should_not_convert_markdown_links": "<p dir=\"auto\">lorem <a class=\"markdown-external-link\" data-href=\"https://images.ecency.com/0x0/https://d1vof77qrk4l5q.cloudfront.net/img/5752638e6965247789bc20cef34727263aaa41e1.png\">this error</a> ipsum</p>",
10
10
  "markdown_2_html_traversing_20_should_not_convert_markdown_links": "<p dir=\"auto\">lorem <a class=\"markdown-external-link\" data-href=\"https://images.ecency.com/0x0/https://d1vof77qrk4l5q.cloudfront.net/img/5752638e6965247789bc20cef34727263aaa41e1.png\">this error</a> ipsum</p>",
11
11
  "markdown_2_html_traversing_22_should_replace_busy_links_properly": "<p dir=\"auto\"><img src=\"https://images.ecency.com/p/7ohP4GDMGPrUMp8dW6yuJTR9MKNu8P8DCXDU9qmmhgT2GEFsgcwp6r41v9wnLUULgcVqE59AhpBJjFXHVP6KTGZbAszsNTZrVUY3.png?format=match&amp;mode=fit\" alt=\"image.png\" /></p>\n<p dir=\"auto\"><a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-1-2\">Part 1 - 2</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-3\">Part 3</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-4\">Part 4</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-5\">Part 5</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-6\">Part 6</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-7\">Part 7</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-8\">Part 8</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-9\">Part 9</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-10\">Part 10</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-11\">Part 11</a><br />\n<a class=\"markdown-post-link\" data-tag=\"post\" data-author=\"muratkbesiroglu\" data-permlink=\"sci-fi-novel-underground-city-part-12\">Part 12</a></p>\n<p dir=\"auto\"><strong>Part 13</strong></p>\n<p dir=\"auto\">Members of the Yerşehir caravan have surrendered their weapons to imperial soldiers at the entrance of Istanbul by the agreement provided earlier. The imperial soldiers arrested them immediately after the surrender of the weapons, and they entered the city with their hands chained.</p>\n<p dir=\"auto\">“The Yerşehir administration will ask you the account of this disrespect,” said Tamra to the proud Commander Timor on the pony. Tamra was angry because an ordinary soldier pushed her.</p>\n<p dir=\"auto\">\"You should be thankful we didn't strip you naked and had you wandering the streets of the city,\" said Commander Timor.</p>\n<p dir=\"auto\">Doma turned to the commander and said, “That's not how we dealt with you. Still, I assume you're doing your duty. I ask you to inform your superiors as soon as possible.”</p>\n<p dir=\"auto\">”You may be executed for armed entry into the Imperial lands,\" said the commander.</p>\n<p dir=\"auto\">“You like to dramatize things,” Akman said. Although Commander Timor was angry with Akman's happy face, he chose to keep the sarcastic look on his face.</p>\n<p dir=\"auto\">When he was taken to the dungeon, Akman was watching the buildings on the road, the squares adorned with sculptures, statues, and facades reflecting the beauty of East Roman stone craftsmanship.</p>\n<p dir=\"auto\">After passing the Hippodrome, which is one of the rare works of the ancient world, they entered a narrow tunnel and went down a ladder descending by turning. The soldiers locked them in a large gallery and returned. The water was dripping from the high ceiling of the dungeon, and the air they breathed was quite damp. Akman saw two rats with the size of cats running to their holes, terrified by the sound of footsteps.</p>\n<p dir=\"auto\">”I don't think they're gonna keep us here for long,\" Akman said.</p>\n<p dir=\"auto\">Akman was wrong; they told stories to each other in the first few days while there was no authority to call and ask for them. One of the dungeon guards came once a day and left a cup of water and a disgusting wheat porridge in the cell. The amount of oatmeal brought by the guard was so small that it was even possible for them to starve if the situation went on like this.</p>\n<p dir=\"auto\">Akman was cheerful as if he was at the banquet table, not at the dungeon. His joy was so bizarre that the team members began to think he was out of his mind. As the days passed, he was weakened by malnutrition; his clothes were stained, and his face was blackened. Still, he didn't lose anything from his joy. When asked how it can be so enjoyable, he said, “peace and light are within us. Just let's call and find out.\"</p>\n<p dir=\"auto\">Days later, an officer finally appeared at the door of the dungeon. Now, even the sparkle in the eyes of Akman has been lost, and Doma was unable to get up from where he was sleeping because of his illness. “The emperor will meet with the two representatives of your choice in two days,” said Chlorus, who brought plenty of food with him. Chlorus was handling his business with care. He brought water and ash to the cell to make sure they didn't smell bad, and he arranged a basin for their clothes. After washing, a barber would cut off their hair and beard. When they talk to the emperor, they should not extend the word and that they should give satisfying answers to the questions asked.</p>\n<p dir=\"auto\">Akman and Doma were taken from prison by the guards to be brought to the emperor. They agreed to hold a reasonable discourse during the interview. They were ready to suffer the maltreatment for the well-being of their country. The Imperial Palace adjacent to the Hippodrome was quite magnificent. They couldn't retrieve their eyes from the mosaics on the floor, the tiles on the walls and the stained glass windows. They passed through the large gate of the palace and entered the inner courtyard, where they waited for a while and then came to the emperor's presence.</p>\n<p dir=\"auto\">Since Doma's disease has not passed yet, Akman was holding his arm. As a matter of fact, he hasn't been able to speak; he agreed to join the meeting to show The Emperor what a terrible treatment they had.</p>\n<p dir=\"auto\">As soon as Emperor Valens saw Doma, he noticed his discomfort and told the servants to bring him a chair to sit down.</p>\n<p dir=\"auto\">“You wanted to see me,” said the Emperor, sitting on a plain throne compared to the splendor of the palace.</p>\n<p dir=\"auto\">”In the name of my people, I share your sorrow,\" said Akman.</p>\n<p dir=\"auto\">The emperor looked at Akman with the eyes asking, \"what is it about?”</p>\n<p dir=\"auto\">“I think robots attack your stables,” Akman said. Doma, who saw the environment as blurry due to high fever, turned and looked at Akman with amazement.</p>\n<p dir=\"auto\">”Few people know that yet, \" said Emperor Valens. Akman heard the news from the two soldiers they encountered on the way to the dungeon; the soldiers thought others did not understand them because they were whispering. As the security of his country is concerned, Akman chose to transfer the incident to the emperor in a different manner.</p>\n<p dir=\"auto\">\"We came to Istanbul to warn you about this. When the imperial authorities said in the dungeon that we could finally come to your peace, I understood that the attack has occurred,” Akman said.</p>\n<p dir=\"auto\">“You speak our language very well,” said the emperor.</p>\n<p dir=\"auto\">“Master Doma is much better than me, I hoped he'd be able to talk, but I was wrong,\" Akman said.</p>\n<p dir=\"auto\">\"I give you my regards and my gratitude for showing us the grace of acceptance. Because of my illness, I beg forgiveness for the imperfections that I can handle,” Doma said.</p>\n<p dir=\"auto\">“I will ask without hesitation: what could we have done to draw the wrath of God upon us, and what should we do to be merciful to his forgiveness?”</p>\n<p dir=\"auto\">Akman did not tell the emperor that events had begun with Ordin rising to Earth. He didn't want him to think they were in charge of the activities. Moreover, there was no evidence that the attacks on the stables in Yerşehir and Istanbul were related to Ordin's action. It was more than three months ago, and it could have been a coincidence.</p>\n<p dir=\"auto\">“I do not think that what happened is related to any sin.”</p>\n<p dir=\"auto\">“Foreigners come to our city with magical weapons, and ten days later, such an attack is taking place. Is that a coincidence?”</p>\n<p dir=\"auto\">\"I suspect that your scientists have already studied our weapons and have partially solved their operational principles. I assure you, our weapons work in accordance with scientific rules. I don't know why we're being treated so hard in your country.”</p>\n<p dir=\"auto\">“Could it be because you closed your doors to our country with a unilateral decision you made two centuries ago? According to historical records, despite the insistence of our empire, we have not even been able to negotiate the matter.”</p>\n<p dir=\"auto\">“It was a great travesty that half of our people died because of the plague. But that's not a valid excuse. I think the decision we made on time was wrong. During the past, we have been deprived of the benefits that we can achieve mutually. Given that the tunnel system makes wars almost impossible, it is not reasonable for us to continue such a mistake,\" Akman said.</p>\n<p dir=\"auto\">“I haven't received a satisfactory answer to my questions yet?\" the emperor said, despite the tone of his voice, his eyes were warm to Akman.</p>\n<p dir=\"auto\">\"I have to admit I don't know the answer to your questions, even if it's embarrassing for a philosopher. We came to Istanbul to find the answer to this question together.”</p>\n<p dir=\"auto\">\"I want to learn the working principles and how to produce the weapons you bring with you. This is the only way we can initiate an equality-based relationship.”</p>\n<p dir=\"auto\">\"I am not authorized to make such a decision. But I don't think your offer will be rejected at a time when we need cooperation to defend our cities,\" Akman said.</p>\n<p dir=\"auto\">After the meeting with Emperor Valens, the Yerşehir delegation was removed from prison, their belongings were returned, and they were sent from Istanbul with a ceremony in accordance with diplomatic traditions.</p>\n<p dir=\"auto\">Image Source: pixabay.com</p>",
12
12
  "markdown_2_html_traversing_54_should_highlight_code": "<pre><code><span class=\"ll-spc\"> </span><span class=\"ll-key\">def</span><span class=\"ll-spc\"> </span><span class=\"ll-nam\">factorial</span><span class=\"ll-pct\">(</span><span class=\"ll-nam\">n</span><span class=\"ll-pct\">)</span><span class=\"ll-pct\">:</span><span class=\"ll-spc\">\n </span><span class=\"ll-com\"># a comment</span><span class=\"ll-spc\">\n </span><span class=\"ll-key\">return</span><span class=\"ll-spc\"> </span><span class=\"ll-num\">1</span><span class=\"ll-spc\"> </span><span class=\"ll-key\">if</span><span class=\"ll-spc\"> </span><span class=\"ll-pct\">(</span><span class=\"ll-nam\">n</span><span class=\"ll-pct\">=</span><span class=\"ll-pct\">=</span><span class=\"ll-num\">1</span><span class=\"ll-spc\"> </span><span class=\"ll-key\">or</span><span class=\"ll-spc\"> </span><span class=\"ll-nam\">n</span><span class=\"ll-pct\">=</span><span class=\"ll-pct\">=</span><span class=\"ll-num\">0</span><span class=\"ll-pct\">)</span><span class=\"ll-spc\"> </span><span class=\"ll-key\">else</span><span class=\"ll-spc\"> </span><span class=\"ll-nam\">n</span><span class=\"ll-spc\"> </span><span class=\"ll-pct\">*</span><span class=\"ll-spc\"> </span><span class=\"ll-nam\">factorial</span><span class=\"ll-pct\">(</span><span class=\"ll-nam\">n</span><span class=\"ll-spc\"> </span><span class=\"ll-pct\">-</span><span class=\"ll-spc\"> </span><span class=\"ll-num\">1</span><span class=\"ll-pct\">)</span><span class=\"ll-spc\">\n </span><span class=\"ll-str\">``</span><span class=\"ll-unk\">`</span><span class=\"ll-spc\">\n</span></code></pre>",
13
- "markdown_2_html_webp_support_should_render_images_in_webp_format": "<p dir=\"auto\">lorem ipsum <img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/2BCfkBRHmbhyg7yeHaumxJq2oMZjKUDK5rv2tmGQzQHxPvTmaiv6Ar.webp?format=webp&amp;mode=fit\" /> dolor sit amet</p>"
13
+ "markdown_2_html_webp_support_should_render_images_in_webp_format": `<p dir=\"auto\">lorem ipsum <img class=\"markdown-img-link\" src=\"https://images.ecency.com/p/2BCfkBRHmbhyg7yeHaumxJq2oMZjKUDK5rv2tmGQzQHxPvTmaiv6Ar.webp?format=webp&amp;mode=fit\" loading=\"lazy\" decoding=\"async\" itemprop=\"image\" /> dolor sit amet</p>`
14
14
  }
15
15
 
16
16
  describe('Markdown2Html', () => {
@@ -22,7 +22,7 @@ describe('Markdown2Html', () => {
22
22
  last_update: '2019-05-10T09:15:21',
23
23
  body: 'https://img.esteem.ws/bbq3ob1idy.png'
24
24
  }
25
- const expected = '<p dir=\"auto\"><img class="markdown-img-link" src="https://images.ecency.com/p/o1AJ9qDyyJNSpZWhUgGYc3MngFqoAMwgbeMkkd8SVxyfRVjiN.png?format=match&amp;mode=fit" /></p>'
25
+ const expected = '<p dir=\"auto\"><img class="markdown-img-link" src="https://images.ecency.com/p/o1AJ9qDyyJNSpZWhUgGYc3MngFqoAMwgbeMkkd8SVxyfRVjiN.png?format=match&amp;mode=fit" loading="lazy" decoding="async" itemprop="image" /></p>'
26
26
 
27
27
  expect(markdown2Html(input)).toBe(expected)
28
28
  })
@@ -70,7 +70,7 @@ describe('Markdown2Html', () => {
70
70
  last_update: '2019-05-10T09:15:21',
71
71
  body: 'https://www.youtube.com/watch?v=qK3d1eoH-Qs'
72
72
  }
73
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/qK3d1eoH-Qs?autoplay=1" data-youtube="qK3d1eoH-Qs"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eMZRVYW6mkGBWKemLWWzXbRhNG7Z3h1qjGS.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
73
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/qK3d1eoH-Qs?autoplay=1" data-youtube="qK3d1eoH-Qs"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eMZRVYW6mkGBWKemLWWzXbRhNG7Z3h1qjGS.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
74
74
 
75
75
  expect(markdown2Html(input)).toBe(expected)
76
76
  })
@@ -94,7 +94,7 @@ describe('Markdown2Html', () => {
94
94
  last_update: '2019-05-10T09:15:21',
95
95
  body: '<a href="https://d.tube/#!/v/scottcbusiness/g04n2bbp" title="This link will take you away from steemit.com"><img src="https://images.ecency.com/640x0/https://ipfs.io/ipfs/QmPhb9HA1gASFiNAUPFqMdSidTAj17L5SSoV3zbXUx8M7t"></a>'
96
96
  }
97
- const expected = '<p dir=\"auto\"><a title="This link will take you away from steemit.com" class="markdown-video-link markdown-video-link-dtube" data-embed-src="https://emb.d.tube/#!/scottcbusiness/g04n2bbp"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/46aP2QbqUqBqwzwxM6L1P6uLNceBDDCM6xyDJFx6ANhENRd3gJWJH7TiVR91QZ1KBcdAdZruQE35PBpQ3jUvkNK4mJqZ.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
97
+ const expected = '<p dir=\"auto\"><a title="This link will take you away from steemit.com" class="markdown-video-link markdown-video-link-dtube" data-embed-src="https://emb.d.tube/#!/scottcbusiness/g04n2bbp"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/46aP2QbqUqBqwzwxM6L1P6uLNceBDDCM6xyDJFx6ANhENRd3gJWJH7TiVR91QZ1KBcdAdZruQE35PBpQ3jUvkNK4mJqZ.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
98
98
 
99
99
  expect(markdown2Html(input)).toBe(expected)
100
100
  })
@@ -424,7 +424,7 @@ describe('Markdown2Html', () => {
424
424
  last_update: '2019-05-10T09:15:21',
425
425
  body: '[![](https://img.3speakcontent.online/xrhjxocx/post.png?v2)](https://3speak.online/watch?v=wehmoen/xrhjxocx)'
426
426
  }
427
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.online/embed?v=wehmoen/xrhjxocx"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/2ufhwNgM3qHKBGVeU2TMMqPBjdB17MRuf4Q7vGrmGMtTn6yFtvW3Lt9t5v1c3so7UFhWDYh9B.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
427
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.online/embed?v=wehmoen/xrhjxocx"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/2ufhwNgM3qHKBGVeU2TMMqPBjdB17MRuf4Q7vGrmGMtTn6yFtvW3Lt9t5v1c3so7UFhWDYh9B.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
428
428
 
429
429
  expect(markdown2Html(input)).toBe(expected)
430
430
  })
@@ -436,7 +436,7 @@ describe('Markdown2Html', () => {
436
436
  last_update: '2029-05-10T09:15:21',
437
437
  body: '[![](https://img.3speakcontent.co/blnmdkjt/post.png)](https://3speak.co/watch?v=theycallmedan/blnmdkjt) [Watch on 3Speak](https://3speak.co/watch?v=theycallmedan/blnmdkjt)'
438
438
  }
439
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.co/embed?v=theycallmedan/blnmdkjt"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/CQdwDW6BZfWWtctopKyTJuDRdBH4KXwm9ijE6sZXe5MveWF3nUu4zXXBFUau8NS.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a> <a class="markdown-external-link" data-href="https://3speak.co/watch?v=theycallmedan/blnmdkjt">Watch on 3Speak</a></p>'
439
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.co/embed?v=theycallmedan/blnmdkjt"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/CQdwDW6BZfWWtctopKyTJuDRdBH4KXwm9ijE6sZXe5MveWF3nUu4zXXBFUau8NS.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a> <a class="markdown-external-link" data-href="https://3speak.co/watch?v=theycallmedan/blnmdkjt">Watch on 3Speak</a></p>'
440
440
 
441
441
  expect(markdown2Html(input)).toBe(expected)
442
442
  })
@@ -460,7 +460,7 @@ describe('Markdown2Html', () => {
460
460
  last_update: '2019-05-10T09:15:21',
461
461
  body: 'https://youtu.be/UuyS7YAkECA?t=295s'
462
462
  }
463
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
463
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
464
464
 
465
465
  expect(markdown2Html(input)).toBe(expected)
466
466
  })
@@ -520,7 +520,7 @@ describe('Markdown2Html', () => {
520
520
  last_update: '2019-05-10T09:15:21',
521
521
  body: 'this is link https://ipfs.io/ipfs/bafybeihbqfrcrbr6jkf77rdve3nbxjzkfgmeneaw2x5s43qdgpe26cha6q'
522
522
  }
523
- const expected = '<p dir=\"auto\">this is link <a data-href="https://ipfs.io/ipfs/bafybeihbqfrcrbr6jkf77rdve3nbxjzkfgmeneaw2x5s43qdgpe26cha6q" class="markdown-img-link"><img src="https://images.ecency.com/p/2923mN3pnd7PiPXAMdj9UuE6SsjvQJDHj5VpTTCNs3tkJu9JC9Pu9qXSi5Ys5PYtkaRx6ErTnFVzh1WQxWS45rvr6Q4rfUooAM242oyKeihwnx.png?format=match&amp;mode=fit" /></a></p>'
523
+ const expected = '<p dir=\"auto\">this is link <a data-href="https://ipfs.io/ipfs/bafybeihbqfrcrbr6jkf77rdve3nbxjzkfgmeneaw2x5s43qdgpe26cha6q" class="markdown-img-link"><img src="https://images.ecency.com/p/2923mN3pnd7PiPXAMdj9UuE6SsjvQJDHj5VpTTCNs3tkJu9JC9Pu9qXSi5Ys5PYtkaRx6ErTnFVzh1WQxWS45rvr6Q4rfUooAM242oyKeihwnx.png?format=match&amp;mode=fit" itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /></a></p>'
524
524
 
525
525
  expect(markdown2Html(input)).toBe(expected)
526
526
  })
@@ -722,7 +722,7 @@ describe('Markdown2Html', () => {
722
722
  last_update: '2021-05-10T09:15:49',
723
723
  body: '<a href="/@hivesql"><img src="https://i.imgur.com/EPN8RW6.png"></a>'
724
724
  }
725
- const expected = '<p dir=\"auto\"><a class=\"markdown-author-link\" data-author=\"hivesql\"><img src=\"https://images.ecency.com/p/2bP4pJr4wVimqCWjYimXJe2cnCgn8gbL3c5wQPJF23G.png?format=match&amp;mode=fit\" /></a></p>'
725
+ const expected = '<p dir=\"auto\"><a class=\"markdown-author-link\" data-author=\"hivesql\"><img src=\"https://images.ecency.com/p/2bP4pJr4wVimqCWjYimXJe2cnCgn8gbL3c5wQPJF23G.png?format=match&amp;mode=fit\" itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /></a></p>'
726
726
  expect(markdown2Html(input)).toBe(expected)
727
727
  })
728
728
 
@@ -898,7 +898,7 @@ describe('Markdown2Html', () => {
898
898
  last_update: '2019-05-10T09:15:21',
899
899
  body: 'https://www.youtube.com/embed/UuyS7YAkECA?start=295&autoplay=1'
900
900
  }
901
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
901
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
902
902
 
903
903
  expect(markdown2Html(input)).toBe(expected)
904
904
  })
@@ -958,7 +958,7 @@ describe('Markdown2Html', () => {
958
958
  last_update: '2019-05-10T09:15:21',
959
959
  body: 'https://www.youtube.com/shorts/IaehbZnsi4w'
960
960
  }
961
- const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/IaehbZnsi4w?autoplay=1" data-youtube="IaehbZnsi4w"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45e5VviwaTq13pYBZesC7Hh3idYK26Q1RMUHU.png?format=match&amp;mode=fit" /><span class="markdown-video-play"></span></a></p>'
961
+ const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/IaehbZnsi4w?autoplay=1" data-youtube="IaehbZnsi4w"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45e5VviwaTq13pYBZesC7Hh3idYK26Q1RMUHU.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
962
962
 
963
963
  expect(markdown2Html(input)).toBe(expected)
964
964
  })
@@ -1161,7 +1161,7 @@ describe('Markdown2Html', () => {
1161
1161
  last_update: '2019-05-10T09:15:21',
1162
1162
  body: 'https://img.esteem.ws/bbq3ob1idy.png <a href="https://steemit.com/esteem/@esteemapp/esteem-monthly-guest-curation-program-4">fooo</a> <a href="/esteem/@esteemapp/esteem-monthly-guest-curation-program-4">bar</a> <a href="http://external.com/loromoro">baz</a> #lorem @ipsum <a href=\'https://steemit.com/~witnesses\'>vote me</a>'
1163
1163
  }
1164
- const expected = '<p dir=\"auto\"><img class="markdown-img-link" src="https://images.ecency.com/p/o1AJ9qDyyJNSpZWhUgGYc3MngFqoAMwgbeMkkd8SVxyfRVjiN.png?format=match&amp;mode=fit" /> <a href="https://steemit.com/esteem/@esteemapp/esteem-monthly-guest-curation-program-4" class="markdown-external-link" target="_blank" rel="noopener">fooo</a> <a href="/esteem/@esteemapp/esteem-monthly-guest-curation-program-4" class="markdown-post-link">bar</a> <a href="http://external.com/loromoro" class="markdown-external-link" target="_blank" rel="noopener">baz</a><span> <a class="markdown-tag-link" href="/trending/lorem">#lorem</a> <a class="markdown-author-link" href="/@ipsum">@ipsum</a> </span><a href="https://steemit.com/~witnesses" class="markdown-external-link" target="_blank" rel="noopener">vote me</a></p>'
1164
+ const expected = '<p dir=\"auto\"><img class="markdown-img-link" src="https://images.ecency.com/p/o1AJ9qDyyJNSpZWhUgGYc3MngFqoAMwgbeMkkd8SVxyfRVjiN.png?format=match&amp;mode=fit" loading="lazy" decoding="async" itemprop="image" /> <a href="https://steemit.com/esteem/@esteemapp/esteem-monthly-guest-curation-program-4" class="markdown-external-link" target="_blank" rel="noopener">fooo</a> <a href="/esteem/@esteemapp/esteem-monthly-guest-curation-program-4" class="markdown-post-link">bar</a> <a href="http://external.com/loromoro" class="markdown-external-link" target="_blank" rel="noopener">baz</a><span> <a class="markdown-tag-link" href="/trending/lorem">#lorem</a> <a class="markdown-author-link" href="/@ipsum">@ipsum</a> </span><a href="https://steemit.com/~witnesses" class="markdown-external-link" target="_blank" rel="noopener">vote me</a></p>'
1165
1165
 
1166
1166
  expect(markdown2Html(input, false)).toBe(expected)
1167
1167
  })
@@ -31,6 +31,7 @@ import { getSerializedInnerHTML } from './get-inner-html.method'
31
31
  import { proxifyImageSrc } from '../proxify-image-src'
32
32
  import { removeChildNodes } from './remove-child-nodes.method'
33
33
  import { extractYtStartTime, isValidPermlink } from '../helper'
34
+ import {createImageHTML} from "./img.method";
34
35
 
35
36
 
36
37
  export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
@@ -61,11 +62,9 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
61
62
  href.trim().replace(/&amp;/g, '&') ===
62
63
  getSerializedInnerHTML(el).trim().replace(/&amp;/g, '&')
63
64
  ) {
64
- const attrs = forApp ? `data-href="${href}" class="markdown-img-link" src="${proxifyImageSrc(href, 0, 0, webp ? 'webp' : 'match')}"` : `class="markdown-img-link" src="${proxifyImageSrc(href, 0, 0, webp ? 'webp' : 'match')}"`
65
-
66
- const replaceNode = DOMParser.parseFromString(
67
- `<img ${attrs}/>`
68
- )
65
+ const isLCP = false; // LCP handled elsewhere
66
+ const imgHTML = createImageHTML(href, isLCP, webp);
67
+ const replaceNode = DOMParser.parseFromString(imgHTML);
69
68
 
70
69
  el.parentNode.replaceChild(replaceNode, el)
71
70
 
@@ -1,9 +1,6 @@
1
1
  import { proxifyImageSrc } from "../proxify-image-src";
2
2
 
3
- export function img(el: HTMLElement, webp: boolean): void {
4
- el.removeAttribute("width");
5
- el.removeAttribute("height");
6
-
3
+ export function img(el: HTMLElement, webp: boolean, state?: { firstImageFound: boolean }): void {
7
4
  let src = el.getAttribute("src") || "";
8
5
 
9
6
  // Normalize encoded characters
@@ -26,9 +23,20 @@ export function img(el: HTMLElement, webp: boolean): void {
26
23
  }
27
24
 
28
25
  // Sanitize any dynamic or low-res src-like attributes
29
- ["onerror", "dynsrc", "lowsrc"].forEach(attr => el.removeAttribute(attr));
26
+ ["onerror", "dynsrc", "lowsrc", "width", "height"].forEach(attr => el.removeAttribute(attr));
30
27
 
31
28
  el.setAttribute("itemprop", "image");
29
+ const isLCP = state && !state.firstImageFound;
30
+
31
+ if (isLCP) {
32
+ el.setAttribute("loading", "eager");
33
+ el.setAttribute("fetchpriority", "high");
34
+ state.firstImageFound = true;
35
+ } else {
36
+ el.setAttribute("loading", "lazy");
37
+ el.setAttribute("decoding", "async");
38
+ }
39
+
32
40
 
33
41
  const cls = el.getAttribute("class") || "";
34
42
  const shouldReplace = !cls.includes("no-replace");
@@ -39,3 +47,16 @@ export function img(el: HTMLElement, webp: boolean): void {
39
47
  el.setAttribute("src", proxified);
40
48
  }
41
49
  }
50
+
51
+ export function createImageHTML(src: string, isLCP: boolean, webp: boolean): string {
52
+ const loading = isLCP ? 'eager' : 'lazy';
53
+ const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
54
+ const proxified = proxifyImageSrc(src, 0, 0, webp ? 'webp' : 'match');
55
+ return `<img
56
+ class="markdown-img-link"
57
+ src="${proxified}"
58
+ loading="${loading}"
59
+ ${fetch}
60
+ itemprop="image"
61
+ />`;
62
+ }
@@ -1,6 +1,7 @@
1
1
  import { IMG_REGEX, SECTION_LIST } from '../consts'
2
2
  import { proxifyImageSrc } from '../proxify-image-src'
3
3
  import {isValidPermlink} from "../helper";
4
+ import {createImageHTML} from "./img.method";
4
5
 
5
6
  export function linkify(content: string, forApp: boolean, webp: boolean): string {
6
7
  // Tags
@@ -48,10 +49,13 @@ export function linkify(content: string, forApp: boolean, webp: boolean): string
48
49
  )
49
50
 
50
51
  // Image links
51
- content = content.replace(IMG_REGEX, imglink => {
52
- const attrs = forApp ? `data-href="${imglink}" class="markdown-img-link" src="${proxifyImageSrc(imglink, 0, 0, webp ? 'webp' : 'match')}"` : `class="markdown-img-link" src="${proxifyImageSrc(imglink, 0, 0, webp ? 'webp' : 'match')}"`
53
- return `<img ${attrs}/>`
54
- })
52
+ let firstImageUsed = false;
53
+
54
+ content = content.replace(IMG_REGEX, (imglink) => {
55
+ const isLCP = !firstImageUsed;
56
+ firstImageUsed = true;
57
+ return createImageHTML(imglink, isLCP, webp);
58
+ });
55
59
 
56
60
  return content
57
61
  }
@@ -2,6 +2,7 @@ import { IMG_REGEX, YOUTUBE_REGEX, WHITE_LIST, DOMParser, POST_REGEX, } from '.
2
2
  import { extractYtStartTime, isValidPermlink } from '../helper'
3
3
  import { proxifyImageSrc } from '../proxify-image-src'
4
4
  import { linkify } from './linkify.method'
5
+ import {createImageHTML} from "./img.method";
5
6
 
6
7
  export function text(node: HTMLElement, forApp: boolean, webp: boolean): void {
7
8
  if (['a', 'code'].includes(node.parentNode.nodeName)) {
@@ -20,12 +21,10 @@ export function text(node: HTMLElement, forApp: boolean, webp: boolean): void {
20
21
  }
21
22
 
22
23
  if (node.nodeValue.match(IMG_REGEX)) {
23
- const attrs = forApp ? `data-href="${node.nodeValue}" class="markdown-img-link" src="${proxifyImageSrc(node.nodeValue, 0, 0, webp ? 'webp' : 'match')}"` : `class="markdown-img-link" src="${proxifyImageSrc(node.nodeValue, 0, 0, webp ? 'webp' : 'match')}"`
24
- const replaceNode = DOMParser.parseFromString(
25
- `<img ${attrs}/>`
26
- )
27
-
28
- node.parentNode.replaceChild(replaceNode, node)
24
+ const isLCP = false; // Traverse handles LCP; no need to double-count
25
+ const imageHTML = createImageHTML(node.nodeValue, isLCP, webp);
26
+ const replaceNode = DOMParser.parseFromString(imageHTML);
27
+ node.parentNode.replaceChild(replaceNode, node);
29
28
  }
30
29
  // If a youtube video
31
30
  if (node.nodeValue.match(YOUTUBE_REGEX)) {
@@ -4,7 +4,7 @@ import { img } from './img.method'
4
4
  import { p } from './p.method'
5
5
  import { text } from './text.method'
6
6
 
7
- export function traverse(node: Node, forApp: boolean, depth = 0, webp = false): void {
7
+ export function traverse(node: Node, forApp: boolean, depth = 0, webp = false, state = { firstImageFound: false }): void {
8
8
  if (!node || !node.childNodes) {
9
9
  return
10
10
  }
@@ -22,12 +22,12 @@ export function traverse(node: Node, forApp: boolean, depth = 0, webp = false):
22
22
  text(<HTMLElement>child, forApp, webp)
23
23
  }
24
24
  if (child.nodeName.toLowerCase() === 'img') {
25
- img(<HTMLElement>child, webp)
25
+ img(<HTMLElement>child, webp, state)
26
26
  }
27
27
  if (child.nodeName.toLowerCase() === 'p') {
28
28
  p(<HTMLElement>child)
29
29
  }
30
30
 
31
- traverse(child, forApp, depth + 1, webp)
31
+ traverse(child, forApp, depth + 1, webp, state)
32
32
  })
33
33
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 10,
3
3
  "input": "Lorem ipsum dolor <img src=x onerror=alert(x)> sit amet.\n\n<a href=\"javascript:void(0)\">etiam ut sollicitudin neque</a>\n\n<a onclick=\"console.log('ss')\">Vivamus pulvinar semper porttitor</a>",
4
- "result": "<p dir=\"auto\">Lorem ipsum dolor <img /> sit amet.</p>\n<p dir=\"auto\"><a>etiam ut sollicitudin neque</a></p>\n<p dir=\"auto\"><a>Vivamus pulvinar semper porttitor</a></p>"
4
+ "result": "<p dir=\"auto\">Lorem ipsum dolor <img itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /> sit amet.</p>\n<p dir=\"auto\"><a>etiam ut sollicitudin neque</a></p>\n<p dir=\"auto\"><a>Vivamus pulvinar semper porttitor</a></p>"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 21,
3
3
  "input": "javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/\"/+/onmouseover=1/+/[*/[]/+alert(1)//'>\n\n<IMG SRC=\"javascript:alert('XSS');\"><img src=\"javascript:alert('XSS');\">\n\n<IMG SRC=javascript:alert('XSS')> <img src=javascript:alert('XSS')>",
4
- "result": "<p dir=\"auto\">javascript:/<em>--&gt;&lt;svg/onload='+/\"/+/onmouseover=1/+/[</em>/[]/+alert(1)//'&gt;</p>\n<p dir=\"auto\"><img /><img /></p>\n<p dir=\"auto\">&lt;IMG SRC=javascript:alert('XSS')&gt; &lt;img src=javascript:alert('XSS')&gt;</p>"
4
+ "result": "<p dir=\"auto\">javascript:/<em>--&gt;&lt;svg/onload='+/\"/+/onmouseover=1/+/[</em>/[]/+alert(1)//'&gt;</p>\n<p dir=\"auto\"><img itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /><img itemprop=\"image\" loading=\"lazy\" decoding=\"async\" /></p>\n<p dir=\"auto\">&lt;IMG SRC=javascript:alert('XSS')&gt; &lt;img src=javascript:alert('XSS')&gt;</p>"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 2112524,
3
3
  "input": "What do you think ? With <3 Steemers\n\n![GitHub Logo](https://freerubens.com/ShowReel-2017.jpg)\n\n<iframe src=\"https://player.vimeo.com/video/207439341\" width=\"640\" height=\"360\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>\n<p dir=\"auto\"><a href=\"https://vimeo.com/207439341\">ShowReel 2017</a> from <a href=\"https://vimeo.com/freerubens\">Rubens Ben</a> on <a href=\"https://vimeo.com\">Vimeo</a>.</p>",
4
- "result": "<p dir=\"auto\">What do you think ? With &lt;3 Steemers</p>\n<p dir=\"auto\"><img src=\"https://images.ecency.com/p/6C2W1azD1rBrx31MBKd8RJWSbPhKuu863DJHXqo7MppEjTQsPhXD81k.png?format=match&amp;mode=fit\" alt=\"GitHub Logo\" /></p>\n<iframe src=\"https://player.vimeo.com/video/207439341\" frameborder=\"0\" webkitallowfullscreen=\"webkitallowfullscreen\" mozallowfullscreen=\"mozallowfullscreen\" allowfullscreen=\"allowfullscreen\"></iframe>\n<p dir=\"auto\"><a class=\"markdown-external-link\" data-href=\"https://vimeo.com/207439341\">ShowReel 2017</a> from <a class=\"markdown-external-link\" data-href=\"https://vimeo.com/freerubens\">Rubens Ben</a> on <a class=\"markdown-external-link\" data-href=\"https://vimeo.com\">Vimeo</a>.</p>"
4
+ "result": "<p dir=\"auto\">What do you think ? With &lt;3 Steemers</p>\n<p dir=\"auto\"><img src=\"https://images.ecency.com/p/6C2W1azD1rBrx31MBKd8RJWSbPhKuu863DJHXqo7MppEjTQsPhXD81k.png?format=match&amp;mode=fit\" alt=\"GitHub Logo\" itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /></p>\n<iframe src=\"https://player.vimeo.com/video/207439341\" frameborder=\"0\" webkitallowfullscreen=\"webkitallowfullscreen\" mozallowfullscreen=\"mozallowfullscreen\" allowfullscreen=\"allowfullscreen\"></iframe>\n<p dir=\"auto\"><a class=\"markdown-external-link\" data-href=\"https://vimeo.com/207439341\">ShowReel 2017</a> from <a class=\"markdown-external-link\" data-href=\"https://vimeo.com/freerubens\">Rubens Ben</a> on <a class=\"markdown-external-link\" data-href=\"https://vimeo.com\">Vimeo</a>.</p>"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 22,
3
3
  "input": "<IMG SRC=JaVaScRiPt:alert('XSS')> <IMG SRC=javascript:alert(&quot;XSS&quot;)>\n<IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>\n<a onmouseover=\"alert(document.cookie)\">xxs link</a><a onmouseover=alert(document.cookie)>xxs link</a>\n<IMG \"\"\"><SCRIPT>alert(\"XSS\")</SCRIPT>\"><IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>\n <IMG SRC= onmouseover=\"alert('xxs')\">",
4
- "result": "<p dir=\"auto\">&lt;IMG SRC=JaVaScRiPt:alert('XSS')&gt; &lt;IMG SRC=javascript:alert(&quot;XSS&quot;)&gt;<br />\n&lt;IMG SRC=<code>javascript:alert(\"RSnake says, 'XSS'\")</code>&gt;<br />\n<a>xxs link</a><a>xxs link</a><br />\n&lt;IMG \"\"\"&gt;alert(&quot;XSS&quot;)\"&gt;<img /><br />\n&lt;IMG SRC= onmouseover=\"alert('xxs')\"&gt;</p>"
4
+ "result": "<p dir=\"auto\">&lt;IMG SRC=JaVaScRiPt:alert('XSS')&gt; &lt;IMG SRC=javascript:alert(&quot;XSS&quot;)&gt;<br />\n&lt;IMG SRC=<code>javascript:alert(\"RSnake says, 'XSS'\")</code>&gt;<br />\n<a>xxs link</a><a>xxs link</a><br />\n&lt;IMG \"\"\"&gt;alert(&quot;XSS&quot;)\"&gt;<img itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /><br />\n&lt;IMG SRC= onmouseover=\"alert('xxs')\"&gt;</p>"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 23,
3
3
  "input": "<IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"></img> <img src=x onerror=\"&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041\"> <IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;> <IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29> <IMG SRC=\" &#14; javascript:alert('XSS');\">",
4
- "result": "<p dir=\"auto\">&lt;IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"&gt; <img /> &lt;IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;&gt; <img /> <img /></p>"
4
+ "result": "<p dir=\"auto\">&lt;IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"&gt; <img itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /> &lt;IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;&gt; <img itemprop=\"image\" loading=\"lazy\" decoding=\"async\" /> <img itemprop=\"image\" loading=\"lazy\" decoding=\"async\" /></p>"
5
5
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "id": 26,
3
3
  "input": "<IMG DYNSRC=\"javascript:alert('XSS')\"> <IMG LOWSRC=\"javascript:alert('XSS')\"> <STYLE>li {list-style-image: url(\"javascript:alert('XSS')\");}</STYLE>",
4
- "result": "<p dir=\"auto\"><img /> <img /> </p>"
4
+ "result": "<p dir=\"auto\"><img itemprop=\"image\" loading=\"eager\" fetchpriority=\"high\" /> <img itemprop=\"image\" loading=\"lazy\" decoding=\"async\" /> </p>"
5
5
  }