2
0

func.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. "use strict";
  2. function opennamu_xss_filter(str) {
  3. return str.replace(/[&<>"']/g, function(match) {
  4. switch(match) {
  5. case '&':
  6. return '&amp;';
  7. case '<':
  8. return '&lt;';
  9. case '>':
  10. return '&gt;';
  11. case "'":
  12. return '&#x27;';
  13. case '"':
  14. return '&quot;';
  15. }
  16. });
  17. }
  18. function opennamu_xss_filter_decode(str) {
  19. return str.replace(/&amp;|&lt;|&gt;|&#x27;|&quot;/g, function(match) {
  20. switch(match) {
  21. case '&amp;':
  22. return '&';
  23. case '&lt;':
  24. return '<';
  25. case '&gt;':
  26. return '>';
  27. case '&#x27;':
  28. return "'";
  29. case '&quot;':
  30. return '"';
  31. }
  32. });
  33. }
  34. function renderSimpleSet(data) {
  35. let tocData = '';
  36. const tocRegexAll = /<h([1-6])>([^<>]+)<\/h[1-6]>/g;
  37. const tocRegex = /<h([1-6])>([^<>]+)<\/h[1-6]>/;
  38. const tocSearchData = [...data.matchAll(tocRegexAll)];
  39. let headingStack = [0, 0, 0, 0, 0, 0];
  40. if (tocSearchData.length > 0) {
  41. tocData += `
  42. <div class="opennamu_TOC" id="toc">
  43. <span class="opennamu_TOC_title">TOC</span>
  44. <br>
  45. `;
  46. }
  47. tocSearchData.forEach((tocSearchIn) => {
  48. const headingLevel = parseInt(tocSearchIn[1]);
  49. const headingLevelStr = headingLevel.toString();
  50. headingStack[headingLevel - 1] += 1;
  51. for (let i = headingLevel; i < 6; i++) {
  52. headingStack[i] = 0;
  53. }
  54. const headingStackStr = headingStack
  55. .map((val) => (val !== 0 ? val + '.' : ''))
  56. .join('')
  57. .replace(/\.$/, '');
  58. tocData += `
  59. <br>
  60. <span class="opennamu_TOC_list">
  61. ${'<span style="margin-left: 10px;"></span>'.repeat(headingStackStr.split('.').length - 1)}
  62. <a href="#s-${headingStackStr}">${headingStackStr}.</a>
  63. ${tocSearchIn[2]}
  64. </span>
  65. `;
  66. data = data.replace(
  67. tocRegex,
  68. `<h${tocSearchIn[1]} id="s-${headingStackStr}"><a href="#toc">${headingStackStr}.</a> ${tocSearchIn[2]}</h${tocSearchIn[1]}>`
  69. );
  70. });
  71. if (tocData !== '') {
  72. tocData += '</div><hr class="main_hr">';
  73. }
  74. let footnoteData = '';
  75. const footnoteRegex = /<sup>((?:(?!<sup>|<\/sup>).)+)<\/sup>/g;
  76. const footnoteSearchData = [...data.matchAll(footnoteRegex)];
  77. let footnoteCount = 1;
  78. if (footnoteSearchData.length > 0) {
  79. footnoteData += '<div class="opennamu_footnote">';
  80. }
  81. footnoteSearchData.forEach((footnoteSearch) => {
  82. const footnoteCountStr = footnoteCount.toString();
  83. if (footnoteCount !== 1) {
  84. footnoteData += '<br>';
  85. }
  86. footnoteData += `<a id="fn-${footnoteCountStr}" href="#rfn-${footnoteCountStr}">(${footnoteCountStr})</a> ${footnoteSearch[1]}`;
  87. data = data.replace(
  88. footnoteRegex,
  89. `<sup id="rfn-${footnoteCountStr}"><a href="#fn-${footnoteCountStr}">(${footnoteCountStr})</a></sup>`
  90. );
  91. footnoteCount += 1;
  92. });
  93. if (footnoteData !== '') {
  94. footnoteData += '</div>';
  95. }
  96. data = tocData + data + footnoteData;
  97. return data;
  98. }
  99. function opennamu_do_id_check(data) {
  100. if(data.match(/\.|\:/)) {
  101. return 0;
  102. } else {
  103. return 1;
  104. }
  105. }
  106. function opennamu_do_ip_click(obj) {
  107. if (obj.id === "") {
  108. let user_name = obj.name;
  109. fetch('/api/v2/ip_menu/' + user_name)
  110. .then(response => {
  111. if (!response.ok) {
  112. throw new Error(`API 호출 실패: ${response.status}`);
  113. }
  114. return response.json();
  115. })
  116. .then(data => {
  117. data = data["data"];
  118. let data_html = '';
  119. for (let key in data) {
  120. for (let for_a = 0; for_a < data[key].length; for_a++) {
  121. data_html += '<a href="' + data[key][for_a][0] + '">' + data[key][for_a][1] + '</a> | ';
  122. }
  123. }
  124. data_html = data_html.replace(/ \| $/g, '');
  125. let for_a;
  126. for (for_a = 0; document.getElementById("opennamu_ip_render_" + String(for_a) + "_load"); for_a++) {}
  127. let popup_html = '<span class="opennamu_popup_footnote" id="opennamu_ip_render_' + String(for_a) + '_load" style="display: none;"></span>';
  128. popup_html += '<span style="display: none;" id="opennamu_ip_tool_' + String(for_a) + '">';
  129. popup_html += data_html;
  130. popup_html += '</span>';
  131. obj.innerHTML += popup_html;
  132. obj.id = 'opennamu_ip_render_' + String(for_a);
  133. obj.onclick = '';
  134. document.getElementById('opennamu_ip_render_' + String(for_a)).addEventListener("click", function () {
  135. opennamu_do_footnote_popover('opennamu_ip_render_' + String(for_a), '', 'opennamu_ip_tool_' + String(for_a), 'open');
  136. });
  137. document.addEventListener("click", function () {
  138. opennamu_do_footnote_popover('opennamu_ip_render_' + String(for_a), '', 'opennamu_ip_tool_' + String(for_a), 'close');
  139. });
  140. obj.click();
  141. })
  142. .catch(err => {
  143. console.error('IP 메뉴 호출 중 오류 발생:', err);
  144. obj.innerHTML = 'IP 정보를 불러오는 데 실패했습니다.';
  145. });
  146. }
  147. }
  148. function opennamu_do_ip_render() {
  149. for (let for_a = 0; for_a < document.getElementsByClassName('opennamu_render_ip').length; for_a++) {
  150. let ip = document.getElementsByClassName('opennamu_render_ip')[for_a].innerHTML.replace(/&amp;/g, '&');
  151. fetch('/api/v2/ip/' + opennamu_do_url_encode(ip))
  152. .then(response => {
  153. if (!response.ok) {
  154. throw new Error(`API 호출 실패: ${response.status}`);
  155. }
  156. return response.json();
  157. })
  158. .then(data => {
  159. if (document.getElementsByClassName('opennamu_render_ip')[for_a].id !== "opennamu_render_end") {
  160. document.getElementsByClassName('opennamu_render_ip')[for_a].innerHTML = data["data"];
  161. document.getElementsByClassName('opennamu_render_ip')[for_a].id = "opennamu_render_end";
  162. }
  163. })
  164. .catch(err => {
  165. console.error('IP 렌더링 호출 중 오류 발생:', err);
  166. document.getElementsByClassName('opennamu_render_ip')[for_a].innerHTML = 'IP 정보를 불러오는 데 실패했습니다.';
  167. });
  168. }
  169. }
  170. function opennamu_do_url_encode(data) {
  171. return encodeURIComponent(data);
  172. }
  173. function opennamu_cookie_split_regex(data) {
  174. return new RegExp('(?:^|; )' + data + '=([^;]*)');
  175. }
  176. function opennamu_send_render(data) {
  177. if(data === '&lt;br&gt;' || data === '' || data.match(/^ +$/)) {
  178. data = '<br>';
  179. } else {
  180. data = data.replace(/( |^)(https?:\/\/(?:[^ ]+))/g, function(m0, m1, m2) {
  181. let link_main = m2;
  182. link_main = link_main.replace('"', '&quot;');
  183. return m1 + '<a href="' + link_main + '">' + link_main + '</a>';
  184. });
  185. data = data.replace(/&lt;a(?:(?:(?!&gt;).)*)&gt;((?:(?!&lt;\/a&gt;).)+)&lt;\/a&gt;/g, function(m0, m1) {
  186. let data_unescape = opennamu_xss_filter_decode(m1)
  187. return '<a href="/w/' + opennamu_do_url_encode(data_unescape) + '">' + m1 + '</a>'
  188. })
  189. }
  190. return data;
  191. }
  192. function opennamu_insert_v(name, data) {
  193. document.getElementById(name).value = data;
  194. }
  195. function opennamu_do_trace_spread() {
  196. if(document.getElementsByClassName('opennamu_trace')) {
  197. document.getElementsByClassName('opennamu_trace')[0].innerHTML = '' +
  198. '<style>.opennamu_trace_button { display: none; } .opennamu_trace { white-space: pre-wrap; overflow-x: unset; text-overflow: unset; }</style>' +
  199. '' + document.getElementsByClassName('opennamu_trace')[0].innerHTML
  200. }
  201. }
  202. function opennamu_page_control(url, page, data_length, data_length_max = 50) {
  203. let next = function() {
  204. if(data_length_max === data_length) {
  205. return '<a href="' + url.replace('{}', String(page + 1)) + '">(+)</a>';
  206. } else {
  207. return '';
  208. }
  209. };
  210. let back = function() {
  211. if(page !== 1) {
  212. return '<a href="' + url.replace('{}', String(page - 1)) + '">(-)</a>';
  213. } else {
  214. return '';
  215. }
  216. };
  217. return (back() + ' ' + next()).replace(/^ /, '');
  218. }
  219. function opennamu_list_hidden_remove() {
  220. const style = document.querySelector('#opennamu_list_hidden_style');
  221. if(style !== null) {
  222. if(style.innerHTML !== "") {
  223. style.innerHTML = '';
  224. } else {
  225. style.innerHTML = '.opennamu_list_hidden { display: none; }';
  226. }
  227. }
  228. }
  229. function opennamu_make_list(left = '', right = '', bottom = '', class_name = '') {
  230. let data_html = '<span class="' + class_name + '">';
  231. data_html += '<div class="opennamu_recent_change">';
  232. data_html += left;
  233. data_html += '<div style="float: right;">';
  234. data_html += right;
  235. data_html += '</div>'
  236. data_html += '<div style="clear: both;"></div>';
  237. if(bottom !== "") {
  238. data_html += '<hr>'
  239. data_html += bottom;
  240. }
  241. data_html += '</div>';
  242. data_html += '<hr class="main_hr">';
  243. data_html += '</span>';
  244. return data_html;
  245. }