markdown.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. "use strict";
  2. class opennamu_render_markdown {
  3. // Init Part
  4. constructor(
  5. render_part_id,
  6. render_part_id_after,
  7. render_part_id_add,
  8. doc_name
  9. ) {
  10. this.doc_data = document.getElementById(render_part_id_add + render_part_id).innerHTML;
  11. render_part_id_add = render_part_id_add.replace(/_/g, '<underBar>');
  12. this.doc_data = this.doc_data.replace(/&amp;/g, '&');
  13. this.doc_data = '<brStart>\n' + this.doc_data + '\n<brEnd>';
  14. this.doc_data.replace(/\r/g, '');
  15. this.doc_name = doc_name;
  16. this.parser_data_temp = {};
  17. this.parser_data_temp_other = {};
  18. this.parser_data_temp_other['toc'] = '';
  19. this.parser_data_temp_other['footnote'] = '';
  20. this.parser_data_temp_other['category'] = '';
  21. this.parser_data_js = [];
  22. this.parser_count = {};
  23. this.parser_count['parser'] = 0;
  24. this.parser_count['nowiki'] = 0;
  25. this.render_part_id = render_part_id;
  26. this.render_part_id_add = render_part_id_add;
  27. this.render_part_id_after = render_part_id_after;
  28. }
  29. // Func Part
  30. do_func_parser_to_text(data, parser_type = 'parser') {
  31. let parser_data_temp = this.parser_data_temp;
  32. let parser_match;
  33. if(parser_type === 'nowiki') {
  34. parser_match = /<(\/?nowiki[0-9]+Span)>/;
  35. } else {
  36. parser_match = /<(\/?render[0-9]+Span)>/;
  37. }
  38. while(data.match(parser_match)) {
  39. data = data.replace(parser_match, function(match, x1) {
  40. return parser_data_temp[x1];
  41. });
  42. }
  43. return data;
  44. }
  45. do_func_xss_encode(data) {
  46. data = data.replace(/"/g, '&quot;');
  47. data = data.replace(/</g, '&lt;');
  48. data = data.replace(/</g, '&gt;');
  49. return data;
  50. }
  51. do_func_xss_decode(data) {
  52. data = data.replace(/&#x27;/g, '\'');
  53. data = data.replace(/&quot;/g, '"');
  54. data = data.replace(/&lt;/g, '<');
  55. data = data.replace(/&gt;/g, '<');
  56. return data;
  57. }
  58. // Render Part
  59. do_part_text() {
  60. let parser_count = this.parser_count['parser'];
  61. let parser_data_temp = this.parser_data_temp;
  62. this.doc_data = this.doc_data.replace(/~~((?:(?!~~).)+)~~/g, function(match, x1) {
  63. parser_count += 1;
  64. let parser_count_str = String(parser_count);
  65. parser_data_temp['render' + parser_count_str + 'Span'] = '<s>';
  66. parser_data_temp['/render' + parser_count_str + 'Span'] = '</s>';
  67. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  68. });
  69. this.doc_data = this.doc_data.replace(/\*\*((?:(?!\*\*).)+)\*\*/g, function(match, x1) {
  70. parser_count += 1;
  71. let parser_count_str = String(parser_count);
  72. parser_data_temp['render' + parser_count_str + 'Span'] = '<b>';
  73. parser_data_temp['/render' + parser_count_str + 'Span'] = '</b>';
  74. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  75. });
  76. this.doc_data = this.doc_data.replace(/__((?:(?!__).)+)__/g, function(match, x1) {
  77. parser_count += 1;
  78. let parser_count_str = String(parser_count);
  79. parser_data_temp['render' + parser_count_str + 'Span'] = '<b>';
  80. parser_data_temp['/render' + parser_count_str + 'Span'] = '</b>';
  81. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  82. });
  83. this.doc_data = this.doc_data.replace(/\*([^*]+)\*/g, function(match, x1) {
  84. parser_count += 1;
  85. let parser_count_str = String(parser_count);
  86. parser_data_temp['render' + parser_count_str + 'Span'] = '<i>';
  87. parser_data_temp['/render' + parser_count_str + 'Span'] = '</i>';
  88. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  89. });
  90. this.doc_data = this.doc_data.replace(/_([^_]+)_/g, function(match, x1) {
  91. parser_count += 1;
  92. let parser_count_str = String(parser_count);
  93. parser_data_temp['render' + parser_count_str + 'Span'] = '<i>';
  94. parser_data_temp['/render' + parser_count_str + 'Span'] = '</i>';
  95. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  96. });
  97. this.doc_data = this.doc_data.replace(/&lt;ins&gt;((?:(?!&lt;ins&gt;|&lt;\/ins&gt;).)+)&lt;\/ins&gt;/g, function(match, x1) {
  98. parser_count += 1;
  99. let parser_count_str = String(parser_count);
  100. parser_data_temp['render' + parser_count_str + 'Span'] = '<u>';
  101. parser_data_temp['/render' + parser_count_str + 'Span'] = '</u>';
  102. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  103. });
  104. this.doc_data = this.doc_data.replace(/&lt;sub&gt;((?:(?!&lt;sub&gt;|&lt;\/sub&gt;).)+)&lt;\/sub&gt;/g, function(match, x1) {
  105. parser_count += 1;
  106. let parser_count_str = String(parser_count);
  107. parser_data_temp['render' + parser_count_str + 'Span'] = '<sub>';
  108. parser_data_temp['/render' + parser_count_str + 'Span'] = '</sub>';
  109. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  110. });
  111. this.doc_data = this.doc_data.replace(/&lt;sup&gt;((?:(?!&lt;sup&gt;|&lt;\/sup&gt;).)+)&lt;\/sup&gt;/g, function(match, x1) {
  112. parser_count += 1;
  113. let parser_count_str = String(parser_count);
  114. parser_data_temp['render' + parser_count_str + 'Span'] = '<sup>';
  115. parser_data_temp['/render' + parser_count_str + 'Span'] = '</sup>';
  116. return '<render' + parser_count_str + 'Span>' + x1 + '</render' + parser_count_str + 'Span>';
  117. });
  118. this.parser_count['parser'] = parser_count;
  119. this.parser_data_temp = parser_data_temp;
  120. }
  121. do_part_heading() {
  122. let parser_count = this.parser_count['parser'];
  123. let parser_data_temp = this.parser_data_temp;
  124. let toc_data = '';
  125. let heading_n = 0;
  126. let heading_list = [0, 0, 0, 0, 0, 0];
  127. let heading_regex = /\n(#{1,6})([^\n]+)\n/;
  128. while(this.doc_data.match(heading_regex)) {
  129. this.doc_data = this.doc_data.replace(heading_regex, function(match, x1, x2) {
  130. let heading_level = x1.length - 1;
  131. let heading_level_str = String(heading_level + 1);
  132. heading_list[heading_level] += 1;
  133. for(let for_a = heading_level + 1; for_a < 6; for_a++) {
  134. heading_list[for_a] = 0;
  135. }
  136. let heading_list_str = '';
  137. for(let for_a = 0; for_a < 6; for_a++) {
  138. if(heading_list[for_a] !== 0) {
  139. heading_list_str += String(heading_list[for_a]) + '.'
  140. }
  141. }
  142. let heading_list_str_2 = heading_list_str.replace(/\.$/, '');
  143. heading_n += 1;
  144. let heading_n_str = String(heading_n);
  145. toc_data += '' +
  146. '<a href="#opennamuHeading' + heading_list_str_2 + '">' + heading_list_str + '</a> ' +
  147. '<span id="opennamuTOCcontent' + heading_n_str + '"></span>' +
  148. '<br>' +
  149. ''
  150. let heading_data = x2;
  151. heading_data = heading_data.replace(/^ /, '');
  152. return '' +
  153. '\n<brEnd>' +
  154. '<h' + heading_level_str + ' id="opennamuHeading' + heading_list_str_2 + '">' +
  155. '<a href="#opennamuTOC">' + heading_list_str + '</a> ' +
  156. '<span id="opennamuHeadingContent' + heading_n_str + '">' + heading_data + '</span>' +
  157. '</h' + heading_level_str + '>' +
  158. '<brStart>\n' +
  159. '';
  160. });
  161. }
  162. this.parser_data_temp_other['toc'] = toc_data;
  163. }
  164. do_part_image() {
  165. let render_main = this;
  166. let render_part_id_add = this.render_part_id_add;
  167. let parser_count = this.parser_count['parser'];
  168. let parser_data_temp = this.parser_data_temp;
  169. this.doc_data = this.doc_data.replace(/!\[([^\[\]]*)\]\(([^\(\)]*)\)/g, function(match, x1, x2) {
  170. if(x1 === '' && x2 === '') {
  171. return '<imageBlink>';
  172. } else {
  173. if(x2 !== '' && x2.match(/^https?:\/\//)) {
  174. parser_count += 1;
  175. let parser_count_str = String(parser_count);
  176. let image_src = render_main.do_func_xss_encode(x2);
  177. let image_alt;
  178. if(x1 !== '') {
  179. image_alt = render_main.do_func_xss_encode(x1);
  180. } else {
  181. image_alt = image_src;
  182. }
  183. parser_data_temp['render' + parser_count_str + 'Span'] = '<img alt="' + image_alt + '" src="' + image_src + '">';
  184. parser_data_temp['/render' + parser_count_str + 'Span'] = '';
  185. return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
  186. } else {
  187. parser_count += 1;
  188. let parser_count_str = String(parser_count);
  189. parser_data_temp['render' + parser_count_str + 'Span'] = '<img>';
  190. parser_data_temp['/render' + parser_count_str + 'Span'] = '';
  191. return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
  192. }
  193. }
  194. });
  195. this.doc_data = this.doc_data.replace(/<imageBlink>/g, '![]()');
  196. this.parser_count['parser'] = parser_count;
  197. this.parser_data_temp = parser_data_temp;
  198. }
  199. do_part_link() {
  200. let render_main = this;
  201. let render_part_id_add = this.render_part_id_add;
  202. let parser_count = this.parser_count['parser'];
  203. let parser_data_temp = this.parser_data_temp;
  204. this.doc_data = this.doc_data.replace(/\[([^\[\]]*)\]\(([^\(\)]*)\)/g, function(match, x1, x2) {
  205. if(x1 === '' && x2 === '') {
  206. return '<linkBlink>';
  207. } else {
  208. if(x2 !== '' && x2.match(/^https?:\/\//)) {
  209. parser_count += 1;
  210. let parser_count_str = String(parser_count);
  211. let link_main = render_main.do_func_xss_encode(x2);;
  212. let link_sub;
  213. if(x1 === '') {
  214. link_sub = x2;
  215. } else {
  216. link_sub = x1;
  217. }
  218. parser_data_temp['render' + parser_count_str + 'Span'] = '<a href="' + link_main + '">';
  219. parser_data_temp['/render' + parser_count_str + 'Span'] = '</a>';
  220. return '<render' + parser_count_str + 'Span>' + link_sub + '</render' + parser_count_str + 'Span>';
  221. } else {
  222. parser_count += 1;
  223. let parser_count_str = String(parser_count);
  224. let link_main;
  225. let link_sub;
  226. let link_title;
  227. if(x2 === '') {
  228. link_main = x1;
  229. link_sub = x1;
  230. } else if(x1 === '') {
  231. link_main = x2;
  232. link_sub = x2;
  233. } else {
  234. link_main = x2;
  235. link_sub = x1;
  236. }
  237. link_title = render_main.do_func_xss_encode(link_main);
  238. link_main = render_main.do_func_xss_decode(link_main);
  239. link_main = opennamu_do_url_encode(link_main);
  240. parser_data_temp['render' + parser_count_str + 'Span'] = '<a class="' + render_part_id_add + 'opennamuLink" title="' + link_title + '" href="/w/' + link_main + '">';
  241. parser_data_temp['/render' + parser_count_str + 'Span'] = '</a>';
  242. return '<render' + parser_count_str + 'Span>' + link_sub + '</render' + parser_count_str + 'Span>';
  243. }
  244. }
  245. });
  246. this.doc_data = this.doc_data.replace(/<linkBlink>/g, '[]()');
  247. this.parser_count['parser'] = parser_count;
  248. this.parser_data_temp = parser_data_temp;
  249. }
  250. do_part_footnote_list() {
  251. if(this.parser_data_temp_other['footnote'] !== '') {
  252. let footnote = '';
  253. footnote += '<ul id="footnote<underBar>data">';
  254. footnote += this.parser_data_temp_other['footnote'];
  255. footnote += '</ul>';
  256. this.parser_data_temp_other['footnote'] = '';
  257. return footnote;
  258. } else {
  259. return '';
  260. }
  261. }
  262. do_part_footnote() {
  263. let render_main = this;
  264. let parser_count = this.parser_count['parser'];
  265. let parser_data_temp = this.parser_data_temp;
  266. let parser_data_temp_other = this.parser_data_temp_other;
  267. let footnote_n = 0;
  268. let footnote_name_all = {};
  269. this.doc_data = this.doc_data.replace(/(?:\[\^((?:(?!\[\^| ).)*)(?: ((?:(?!\[\^|\]).)+))?\]|(\[fnote\(\)]))/g, function(match, x1, x2, x3) {
  270. if(x3 === undefined) {
  271. if(x1 === '' && x2 === undefined) {
  272. return '<footnoteBlink>';
  273. } else {
  274. footnote_n += 1;
  275. let footnote_name;
  276. let footnote_id = String(footnote_n);
  277. if(x1 === '') {
  278. footnote_name = footnote_id;
  279. } else {
  280. footnote_name = x1;
  281. }
  282. let footnote_content;
  283. if(x2 === undefined) {
  284. if(footnote_name_all[footnote_name]) {
  285. footnote_content = footnote_name_all[footnote_name];
  286. } else {
  287. footnote_content = '';
  288. footnote_name_all[footnote_name] = footnote_content;
  289. }
  290. } else {
  291. footnote_content = x2;
  292. footnote_name_all[footnote_name] = footnote_content;
  293. }
  294. let footnote_list = '';
  295. footnote_list += '<li>';
  296. footnote_list += '<a id="opennamuFnGo' + footnote_id + '" href="#opennamuFnIn' + footnote_id + '">'
  297. footnote_list += '(' + footnote_name + ')';
  298. footnote_list += '</a>';
  299. footnote_list += ' ';
  300. footnote_list += footnote_content;
  301. footnote_list += '</li>';
  302. parser_data_temp_other['footnote'] += footnote_list;
  303. parser_count += 1;
  304. let parser_count_str = String(parser_count);
  305. let footnote_data = '';
  306. footnote_data += '<sup>'
  307. footnote_data += '<a id="opennamuFnIn' + footnote_id + '" href="#opennamuFnGo' + footnote_id + '">';
  308. footnote_data += '(' + footnote_name + ')';
  309. footnote_data += '</a>';
  310. footnote_data += '</sup>';
  311. parser_data_temp['render' + parser_count_str + 'Span'] = footnote_data;
  312. parser_data_temp['/render' + parser_count_str + 'Span'] = '';
  313. return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>';
  314. }
  315. } else {
  316. return render_main.do_part_footnote_list();
  317. }
  318. });
  319. this.doc_data = this.doc_data.replace(/<footnoteBlink>/g, '[^]');
  320. this.doc_data += this.do_part_footnote_list();
  321. this.parser_count['parser'] = parser_count;
  322. this.parser_data_temp = parser_data_temp;
  323. this.parser_data_temp_other = parser_data_temp_other;
  324. }
  325. do_part_macro() {
  326. let render_main = this;
  327. let render_part_id_add = this.render_part_id_add;
  328. let parser_count = this.parser_count['parser'];
  329. let parser_data_temp = this.parser_data_temp;
  330. let parser_data_temp_other = this.parser_data_temp_other;
  331. this.doc_data = this.doc_data.replace(/\[([^\[\(<>]+)\(((?:(?!\(|\)\]|<|>).)*)\)\]/g, function(match, x1, x2) {
  332. if(x1 === 'anchor') {
  333. parser_count += 1;
  334. let parser_count_str = String(parser_count);
  335. let anchor_data = render_main.do_func_parser_to_text(x2, 'nowiki');
  336. anchor_data = render_main.do_func_xss_encode(anchor_data);
  337. parser_data_temp['render' + parser_count_str + 'Span'] = '<span id="' + anchor_data + '">';
  338. parser_data_temp['/render' + parser_count_str + 'Span'] = '</span>';
  339. return '<render' + parser_count_str + 'Span></render' + parser_count_str + 'Span>'
  340. } else if(x1 === 'category') {
  341. let category = x2.split(',');
  342. let category_data = render_main.do_func_parser_to_text(category[0], 'nowiki');
  343. let link_main = 'category:' + category_data;
  344. let link_title = render_main.do_func_xss_encode(link_main);
  345. link_main = render_main.do_func_xss_decode(link_main);
  346. link_main = opennamu_do_url_encode(link_main);
  347. parser_data_temp_other['category'] += '<a class="' + render_part_id_add + 'opennamuLink" title="' + link_title + '" href="/w/' + link_main + '">';
  348. parser_data_temp_other['category'] += category_data;
  349. parser_data_temp_other['category'] += '</a>';
  350. parser_data_temp_other['category'] += ' | ';
  351. return '';
  352. } else if(x1 === 'toc') {
  353. if(parser_data_temp_other['toc'] !== '') {
  354. return '' +
  355. '<div class="opennamuTOC">' +
  356. '<span class="opennamuTOCtitle">' +
  357. 'TOC' +
  358. '</span>' +
  359. '<br>' +
  360. '<br>' +
  361. parser_data_temp_other['toc'] +
  362. '</div>' +
  363. '';
  364. } else {
  365. return '';
  366. }
  367. }
  368. else {
  369. return '';
  370. }
  371. });
  372. this.parser_count['parser'] = parser_count;
  373. this.parser_data_temp = parser_data_temp;
  374. this.parser_data_temp_other = parser_data_temp_other;
  375. }
  376. do_part_final() {
  377. this.doc_data = this.doc_data.replace(/<brStart>\n?/g, '');
  378. this.doc_data = this.doc_data.replace(/\n?<brEnd>/g, '');
  379. this.doc_data = this.doc_data.replace(/<underBar>/g, '_');
  380. this.render_part_id_add = this.render_part_id_add.replace(/<underBar>/g, '_');
  381. this.doc_data = this.doc_data.replace(/\n/g, '<br>');
  382. if(this.parser_data_temp_other['category'] !== '') {
  383. let category = this.parser_data_temp_other['category'];
  384. category = category.replace(/ \| $/, '');
  385. this.doc_data += '<hr class="main_hr">';
  386. this.doc_data += '<div id="cate_all"><div id="cate">';
  387. this.doc_data += 'Category : ';
  388. this.doc_data += category;
  389. this.doc_data += '</div></div>';
  390. }
  391. }
  392. // Main Part
  393. do_main() {
  394. this.do_part_heading();
  395. this.do_part_footnote();
  396. this.do_part_macro();
  397. this.do_part_image();
  398. this.do_part_link();
  399. this.do_part_text();
  400. this.do_part_final();
  401. this.doc_data = this.do_func_parser_to_text(this.doc_data);
  402. document.getElementById(this.render_part_id_add + this.render_part_id_after).innerHTML = this.doc_data;
  403. document.getElementById(this.render_part_id_add + this.render_part_id).style.display = "none";
  404. document.getElementById(this.render_part_id_add + this.render_part_id_after).style.display = "";
  405. for(let x1 in this.parser_data_js) {
  406. eval(this.parser_data_js[x1]);
  407. }
  408. new opennamu_render_wiki(
  409. render_part_id_add = this.render_part_id_add
  410. ).do_main();
  411. }
  412. }