PmWiki recipe that lets you embed Pastebin pastes in a wikipage.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

pastebin-embed.php 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php if (!defined('PmWiki')) exit();
  2. $RecipeInfo['Pastebin Embed']['Version'] = '2017-12-27';
  3. ## (:pastebin-embed:)
  4. Markup('pastebin-embed', '<fulltext', '/\\(:pastebin-embed\\s+(.+)\\s*:\\)/', 'PastebinEmbed');
  5. SDV($PastebinEmbedHighlightStyle, "background-color: yellow;");
  6. function PastebinEmbed ($m) {
  7. static $id = 1;
  8. ## Parse arguments to the markup.
  9. $parsed = ParseArgs($m[1]);
  10. ## These are the "bare" arguments (ones which don't require a key, just value(s)).
  11. $args = $parsed[''];
  12. $paste_id = $args[0];
  13. $noJS = in_array('no-js', $args);
  14. $noFooter = in_array('nofooter', $args);
  15. $noLineNumbers = in_array('nolinenums', $args);
  16. $raw = in_array('raw', $args);
  17. $noPre = in_array('no-pre', $args);
  18. ## Convert the comma-delimited line ranges to an array containing each line to be
  19. ## included as values.
  20. ## Note that the line numbers will be zero-indexed (for use with raw text, etc.).
  21. $line_ranges = $parsed['lines'] ? explode(',', $parsed['lines']) : array();
  22. $line_numbers = array();
  23. $to_end_from = -1;
  24. foreach ($line_ranges as $key => $line_range) {
  25. if (preg_match("/([0-9]+)[-–]([0-9]+)/", $line_range, $m)) {
  26. $line_numbers = array_merge($line_numbers, range(--$m[1],--$m[2]));
  27. } else if (preg_match("/([0-9]+)[-–]$/", $line_range, $m)) {
  28. $line_numbers[] = $to_end_from = --$m[1];
  29. } else {
  30. $line_numbers[] = --$line_range;
  31. }
  32. }
  33. ## Same thing, but for highlighted line ranges.
  34. $hl_line_ranges = $parsed['hl'] ? explode(',', $parsed['hl']) : array();
  35. $hl_line_numbers = array();
  36. $hl_to_end_from = -1;
  37. foreach ($hl_line_ranges as $key => $hl_line_range) {
  38. if (preg_match("/([0-9]+)[-–]([0-9]+)/", $hl_line_range, $m)) {
  39. $hl_line_numbers = array_merge($hl_line_numbers, range(--$m[1],--$m[2]));
  40. } else if (preg_match("/([0-9]+)[-–]$/", $hl_line_range, $m)) {
  41. $hl_line_numbers[] = $hl_to_end_from = --$m[1];
  42. } else {
  43. $hl_line_numbers[] = --$hl_line_range;
  44. }
  45. }
  46. $embed_js_url = "https://pastebin.com/embed_js/$paste_id";
  47. $embed_iframe_url = "https://pastebin.com/embed_iframe/$paste_id";
  48. $embed_raw_url = "https://pastebin.com/raw/$paste_id";
  49. $out = "<span class='pastebin-embed-error'>Unknown error.</span>";
  50. ## There are three 'modes': raw (retrieve just the text, client-side, and insert it
  51. ## into the page), no-js (retrieve the HTML, server-side, and insert it into the
  52. ## page), and default (i.e., JS-based - insert the scriptlet, and let it retrieve and
  53. ## insert the HTML into the page, client-side & async).
  54. ## The mode is set by arguments to the (:pastebin-embed:) markup:
  55. ## - if neither the 'raw' nor the 'no-js' option is given, default (JS) mode is used
  56. ## - if the 'raw' option is given, raw mode is used
  57. ## - if the 'no-js' option is given, no-js mode is used
  58. if ($raw) {
  59. $raw_text = file_get_contents($embed_raw_url);
  60. if (!$raw_text) return Keep("<span class='pastebin-embed-error'>Could not retrieve paste!</span>");
  61. $raw_lines = explode("\n", $raw_text);
  62. ## Convert HTML entities.
  63. if (!$noPre) {
  64. foreach ($raw_lines as $line)
  65. $line = PVSE($line);
  66. }
  67. ## Highlighting only works if no-pre is NOT enabled.
  68. if (!empty($hl_line_numbers) && !$noPre) {
  69. if ($hl_to_end_from >= 0)
  70. $hl_line_numbers = array_merge($hl_line_numbers, range($hl_to_end_from, count($raw_lines) - 1));
  71. foreach ($hl_line_numbers as $l) {
  72. $raw_lines[$l] = "<span class='pastebin-embed-highlighted-line'>" . rtrim($raw_lines[$l]) . "</span>";
  73. }
  74. }
  75. ## Filter by line number ranges, if specified.
  76. if (!empty($line_numbers)) {
  77. if ($to_end_from >= 0)
  78. $line_numbers = array_merge($line_numbers, range($to_end_from, count($raw_lines) - 1));
  79. $raw_lines = array_intersect_key($raw_lines, array_flip($line_numbers));
  80. }
  81. $raw_text = implode("\n", $raw_lines);
  82. ## The 'no-pre' option means we shouldn't wrap the text in a <pre> tag.
  83. $out = $noPre ? $raw_text : Keep("<pre class='escaped embedPastebinRaw' id='pastebinEmbed_$id'>\n" . $raw_text . "\n</pre>\n");
  84. } else if ($noJS) {
  85. include_once('simple_html_dom.php');
  86. $content_html = file_get_html($embed_iframe_url);
  87. if (!$content_html) return Keep("<span class='pastebin-embed-error'>Could not retrieve paste!</span>");
  88. $content = $content_html->find(".embedPastebin", 0);
  89. $content->id = "pastebinEmbed_$id";
  90. $styles_html = file_get_html($embed_js_url);
  91. if (!$styles_html) return Keep("<span class='pastebin-embed-error'>Could not retrieve styles!</span>");
  92. $styles = $styles_html->find("style", 0);
  93. ## Filter specified line ranges (if any have been specified via the lines=
  94. ## parameter).
  95. if (!empty($line_numbers)) {
  96. $lines = $content_html->find(".embedPastebin > ol > li");
  97. if ($to_end_from >= 0)
  98. $line_numbers = array_merge($line_numbers, range($to_end_from, count($lines) - 1));
  99. foreach ($lines as $i => $line) {
  100. if (!in_array($i, $line_numbers))
  101. $line->outertext = '';
  102. else
  103. $line->value = ++$i;
  104. }
  105. }
  106. ## Highlight specified line ranges (if any have been specified via the hl=
  107. ## parameter).
  108. if (!empty($hl_line_numbers)) {
  109. $lines = $content_html->find(".embedPastebin > ol > li");
  110. if ($hl_to_end_from >= 0)
  111. $hl_line_numbers = array_merge($hl_line_numbers, range($hl_to_end_from, count($lines) - 1));
  112. foreach ($lines as $i => $line) {
  113. if (in_array($i, $hl_line_numbers)) {
  114. $line->children(0)->class .= " pastebin-embed-highlighted-line";
  115. }
  116. }
  117. }
  118. $out = Keep($styles.$content);
  119. } else {
  120. $out = Keep("<script id='pastebinEmbedScript_$id' src='$embed_js_url'></script>");
  121. if (!empty($hl_line_numbers) || !empty($line_numbers)) {
  122. $line_numbers_js = "[ ".implode(", ",$line_numbers)." ]";
  123. $hl_line_numbers_js = "[ ".implode(", ",$hl_line_numbers)." ]";
  124. $out .= Keep("
  125. <script>
  126. var num_lines = document.querySelector('#pastebinEmbedScript_$id').parentElement.nextSibling.querySelectorAll('.embedPastebin > ol > li').length;
  127. var line_numbers = $line_numbers_js;
  128. var to_end_from = $to_end_from;
  129. if (to_end_from >= 0)
  130. line_numbers = [...line_numbers, ...[...Array(num_lines - to_end_from)].map((_, i) => to_end_from + i)];
  131. var hl_line_numbers = $hl_line_numbers_js;
  132. var hl_to_end_from = $hl_to_end_from;
  133. if (hl_to_end_from >= 0)
  134. hl_line_numbers = [...hl_line_numbers, ...[...Array(num_lines - hl_to_end_from)].map((_, i) => hl_to_end_from + i)];
  135. document.querySelector('#pastebinEmbedScript_$id').parentElement.nextSibling.querySelectorAll('.embedPastebin > ol > li').forEach(function (line, i) {
  136. // Highlight specified line ranges (if any have been specified via the hl= parameter).
  137. if (hl_line_numbers.indexOf(i) != -1)
  138. line.firstChild.className += ' pastebin-embed-highlighted-line';
  139. // Filter specified line ranges (if any have been specified via the lines= parameter).
  140. if (line_numbers.length > 0) {
  141. if (line_numbers.indexOf(i) == -1)
  142. line.parentElement.removeChild(line);
  143. else
  144. line.value = ++i;
  145. }
  146. });
  147. </script>
  148. ");
  149. }
  150. PastebinEmbedAppendFooter();
  151. }
  152. global $HTMLStylesFmt;
  153. if (!$raw && $noFooter) {
  154. $HTMLStylesFmt['pastebin-embed'][] = "#pastebinEmbed_$id .embedFooter { display: none; }\n";
  155. }
  156. if (!$raw && $noLineNumbers) {
  157. $HTMLStylesFmt['pastebin-embed'][] = "#pastebinEmbed_$id > ol { padding-left: 5px; }\n";
  158. }
  159. PastebinEmbedInjectStyles();
  160. $id++;
  161. return $out;
  162. }
  163. function PastebinEmbedAppendFooter() {
  164. static $ran_once = false;
  165. if (!$ran_once) {
  166. global $HTMLFooterFmt;
  167. $HTMLFooterFmt[] =
  168. "<script>
  169. document.querySelectorAll('div.embedPastebin').forEach(function (embed) {
  170. if (embed.previousSibling && embed.previousSibling.tagName == 'P') {
  171. embed.id = 'pastebinEmbed_' + embed.previousSibling.firstChild.id.substring(20);
  172. }
  173. });
  174. </script>\n";
  175. }
  176. $ran_once = true;
  177. }
  178. function PastebinEmbedInjectStyles() {
  179. static $ran_once = false;
  180. if (!$ran_once) {
  181. global $HTMLStylesFmt, $PastebinEmbedHighlightStyle;
  182. $styles = "
  183. .embedPastebinRaw .pastebin-embed-highlighted-line { $PastebinEmbedHighlightStyle display: inline-block; width: calc(100% + 4px); padding-left: 4px; margin-left: -4px; }
  184. .embedPastebin li .pastebin-embed-highlighted-line { $PastebinEmbedHighlightStyle }
  185. ";
  186. $HTMLStylesFmt['pastebin-embed'][] = $styles;
  187. }
  188. $ran_once = true;
  189. }