Selaa lähdekoodia

Merge pull request #1198 from openNAMU/beta

02
잉여개발기 (SPDV) 4 vuotta sitten
vanhempi
sitoutus
f78b87c6f3

+ 2 - 9
readme-en.md

@@ -1,19 +1,13 @@
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
+
 # openNAMU
-[![Up to Python 3.5](https://img.shields.io/badge/python->=%203.5-blue.svg)](https://python.org)
+[![Up to Python 3.6](https://img.shields.io/badge/python->=%203.6-blue.svg)](https://python.org)
 [![LICENSE](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)
 
 openNAMU is a Python-based wiki engine. 
 
-### Index
- * [Getting Started](#getting-started)
- * [Clone](#clone)
- * [Contribute](#contribute)
- * [License](#license)
- * [Etc.](#etc)
-
 ## Getting Started
 openNAMU is based upon Python, and it requires a Python environment.
 
@@ -37,7 +31,6 @@ openNAMU is protected by [BSD 3-Clause License](./LICNESE). Please refer to the
  * Quotes icon [Dave Gandy](http://www.flaticon.com/free-icon/quote-left_25672)
  * Syntax highlighting [highlightjs](https://highlightjs.org/)
  * Numerical expression [MathJax](https://www.mathjax.org/)
- * Handling Keyboard Shortcuts [shortcut.js](http://www.openjs.com/scripts/events/keyboard_shortcuts/)
 
 ## Etc.
  * Owner rights are granted to the first registor.

+ 3 - 11
readme.md

@@ -1,20 +1,13 @@
 [(en-US)](./readme-en.md) | [(ko-KR)](./readme.md)
+
 # 오픈나무
-[![Python 3.5 이상](https://img.shields.io/badge/python->=%203.5-blue.svg)](https://python.org)
+[![Python 3.6 이상](https://img.shields.io/badge/python->=%203.6-blue.svg)](https://python.org)
 [![라이선스](https://img.shields.io/badge/license-BSD%203--Clause-lightgrey.svg)](./LICENSE)
 
 ![](https://raw.githubusercontent.com/openNAMU/openNAMU/beta/.github/logo.png)
 
 오픈나무는 파이썬 기반의 위키 엔진입니다.
 
-### 목차
- * [시작하기](#시작하기)
- * [클론](#클론)
- * [기여](#기여)
- * [라이선스](#라이선스)
- * [지원 문법](#지원-문법)
- * [기타](#기타)
-
 ## 시작하기
 오픈나무는 파이썬 환경에서 동작하는 파이썬 애플리케이션으로, 파이썬 환경을 필요로 합니다.
 
@@ -38,13 +31,12 @@
  * Quotes icon - [Dave Gandy](http://www.flaticon.com/free-icon/quote-left_25672)
  * Syntax highlighting - [highlightjs](https://highlightjs.org/)
  * Numerical expression - [MathJax](https://www.mathjax.org/)
- * Handling Keyboard Shortcuts [shortcut.js](http://www.openjs.com/scripts/events/keyboard_shortcuts/)
 
 ### 도움을 주신 분들
  * [Team Croatia](https://github.com/TeamCroatia)
  * Basix
  * Efrit
- * 기타 채팅방 사람들
+ * 기타 여러 사람들
 
 ## 지원 문법
  * 나무마크 (NamuMark)

+ 11 - 8
route/edit.py

@@ -136,7 +136,8 @@ def edit_2(conn, name):
 
         data = re.sub(r'\n+$', '', data)
 
-        if flask.request.cookies.get('main_css_monaco', '0') == '1':
+        monaco_on = flask.request.cookies.get('main_css_monaco', '0')
+        if monaco_on == '1':
             editor_display = 'style="display: none;"'
             monaco_display = ''
             add_get_file = '''
@@ -155,7 +156,7 @@ def edit_2(conn, name):
                 require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs' }});
                 require(["vs/editor/editor.main"], function () {
                     window.editor = monaco.editor.create(document.getElementById('monaco_editor'), {
-                        value: document.getElementById('content').value,
+                        value: document.getElementById('textarea_edit_view').value,
                         language: 'plaintext',
                         theme: \'''' + monaco_thema + '''\'
                     });
@@ -181,20 +182,22 @@ def edit_2(conn, name):
                 <span   id="server_set"
                         style="display: none;">''' + json.dumps(server_set) + '''</span>
                 <form method="post">
-                    <div ''' + editor_display + '''>''' + edit_button() + '''</div>
+                    <div>''' + edit_button(monaco_on) + '''</div>
                     <div    id="monaco_editor"
                             class="content" 
                             ''' + monaco_display + '''></div>
-                    <textarea   id="content"
+                    <textarea   id="textarea_edit_view"
                                 ''' + editor_display + '''
-                                class="content" 
-                                placeholder="''' + p_text + '''" 
-                                name="content">''' + html.escape(data) + '''</textarea>
+                                class="content"
+                                placeholder="''' + p_text + '''">''' + html.escape(data) + '''</textarea>
                     <hr class="main_hr">
                     <input  placeholder="''' + load_lang('why') + '''" 
                             name="send">
                     <textarea   style="display: none;" 
                                 id="origin">''' + html.escape(data) + '''</textarea>
+                    <textarea   style="display: none;"
+                                name="content"
+                                id="content"></textarea>
                     <input  style="display: none;" 
                             name="ver" 
                             value="''' + doc_ver + '''">
@@ -210,7 +213,7 @@ def edit_2(conn, name):
                     <button id="preview" 
                             type="button" 
                             onclick="
-                                monaco_to_content(); 
+                                monaco_to_content();
                                 load_preview(\'''' + url_pas(name) + '''\');
                             ">''' + load_lang('preview') + '''</button>
                 </form>

+ 6 - 1
route/recent_discuss.py

@@ -33,7 +33,12 @@ def recent_discuss_2(conn):
         title = html.escape(data[0])
         sub = html.escape(data[1])
 
-        div += '<tr><td><a href="/thread/' + data[3] + '">' + sub + '</a> (' + title + ')</td><td>' + data[2] + '</td></tr>'
+        div += '' + \
+            '<tr>' + \
+                '<td><a href="/thread/' + data[3] + '">' + sub + '</a> <a href="/topic/' + url_pas(title) + '">(' + title + ')</a></td>' + \
+                '<td>' + data[2] + '</td>' + \
+            '</tr>' + \
+        ''
 
     div += '</tbody></table>'
 

+ 19 - 17
route/tool/func.py

@@ -84,7 +84,7 @@ if sys.version_info < (3, 6):
 global_lang = {}
 global_wiki_set = {}
 
-data_css_ver = '105'
+data_css_ver = '109'
 data_css = ''
 
 conn = ''
@@ -503,7 +503,7 @@ def load_random_key(long = 64):
         ) for i in range(long)
     )
 
-def edit_button():
+def edit_button(editor_display = '0'):
     insert_list = []
 
     curs.execute(db_change("select html, plus from html_filter where kind = 'edit_top'"))
@@ -515,7 +515,7 @@ def edit_button():
     for insert_data in insert_list:
         data += '' + \
             '<a href="' + \
-                'javascript:do_insert_data(\'content\', \'' + insert_data[0] + '\')' + \
+                'javascript:do_insert_data(\'textarea_edit_view\', \'' + insert_data[0] + '\', ' + editor_display + ')' + \
             '">(' + insert_data[1] + ')</a> ' + \
         ''
 
@@ -740,18 +740,13 @@ def wiki_css(data):
     return data
 
 def cut_100(data):
-    if re.search(r'^\/w\/', flask.request.path):
-        data = re.sub(r'<script>((\n*(((?!<\/script>).)+)\n*)+)<\/script>', '', data)
-        data = re.sub(r'<hr class="main_hr">((\n*((.+)\n*))+)$', '', data)
-        data = re.sub(r'<div id="cate_all">((\n*((.+)\n*))+)$', '', data)        
-
-        data = re.sub(r'<(((?!>).)*)>', ' ', data)
-        data = re.sub(r'\n', ' ', data)
-        data = re.sub(r'^ +', '', data)
-        data = re.sub(r' +$', '', data)
-        data = re.sub(r' {2,}', ' ', data)
-    
-        return data[0:100] + '...'
+    data = re.search(r'<pre style="display: none;" id="render_content_load">([^<>]+)<\/pre>', data)
+    if data:
+        data = data.group(1)
+        if len(data) > 100:
+            return data[0:100] + '...'
+        else:
+            return data[0:len(data)]
     else:
         return ''
 
@@ -803,7 +798,7 @@ def wiki_set(num = 1):
 
     return data_list
 
-def wiki_custom():
+def wiki_custom():    
     ip = ip_check()
     if ip_or_user(ip) == 0:
         user_icon = 1
@@ -846,6 +841,12 @@ def wiki_custom():
 
     curs.execute(db_change("select title from rd where title = ? and stop = ''"), ['user:' + ip])
     user_topic = '1' if curs.fetchall() else '0'
+    
+    split_path = flask.request.path.split('/')
+    if len(split_path) > 1:
+        split_path = split_path[1]
+    else:
+        split_path = 0
 
     return [
         '',
@@ -859,7 +860,8 @@ def wiki_custom():
         user_notice,
         user_acl_list,
         ip,
-        user_topic
+        user_topic,
+        split_path
     ]
 
 def load_skin(data = '', set_n = 0, default = 0):

+ 3 - 5
route/tool/func_mark.py

@@ -15,7 +15,7 @@ def load_conn2(data):
 def backlink_generate(data_markup, doc_data, doc_name):
     if data_markup == 'namumark':
         # Link
-        link_re = re.compile(r'\[\[(?!https?:\/\/)((?:(?!\[\[|\]\]|\|).)+)(?:\]\]|\|)', re.I)
+        link_re = re.compile(r'\[\[(?!https?:\/\/|inter:|외부:|out:|#)((?:(?!\[\[|\]\]|\|).)+)(?:\]\]|\|)', re.I)
         
         data_link = link_re.findall(doc_data)
         data_link = list(set(data_link))
@@ -29,9 +29,7 @@ def backlink_generate(data_markup, doc_data, doc_name):
         
         for i in data_link:
             data_link_in = i
-            if data_link_in[0] == '#':
-                continue
-            elif re.search(r'^(?:분류|category):', data_link_in):
+            if re.search(r'^(?:분류|category):', data_link_in):
                 data_link_in = re.sub(r'\\(.)', r'\1', data_link_in)
                 data_link_end['cat'] += [re.sub(r'^분류:', 'category:', data_link_in)]
             elif re.search(r'^(?:파일|file):', data_link_in):
@@ -153,7 +151,7 @@ def render_do(doc_name, doc_data, data_type, data_in):
     else:
         backlink = backlink_generate(
             rep_data, 
-            html.escape(doc_data), 
+            doc_data, 
             doc_name
         )
         

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
     "beta" : {
-        "r_ver" : "v3.4.0 (stable-01) (beta-02) (dev-14)",
+        "r_ver" : "v3.4.0-beta (stable2) (beta7) (dev23)",
         "c_ver" : "3400101",
-        "s_ver" : "12"
+        "s_ver" : "13"
     }
 }

+ 6 - 4
views/main_css/css/main.css

@@ -54,10 +54,12 @@ a {
 }
 
 #out_link::before {
-    background: green;
-    color: white;
-    content: "E";
-    margin-right: 2px;
+    content: '🅴';
+    
+    font-weight: lighter;
+    
+    background: transparent;
+    color: green;
 }
 
 input[type="checkbox"], input[type="radio"] {

+ 40 - 23
views/main_css/js/load_editor.js

@@ -1,27 +1,41 @@
-function do_insert_data(name, data) {
-    // https://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
-    if(document.selection) {
-        document.getElementById(name).focus();
-
-        var sel = document.selection.createRange();
-        sel.text = data;
-    } else if(
-        document.getElementById(name).selectionStart || 
-        document.getElementById(name).selectionStart == '0'
-    ) {
-        var startPos = document.getElementById(name).selectionStart;
-        var endPos = document.getElementById(name).selectionEnd;
-        var myPos = document.getElementById(name).value;
-
-        document.getElementById(name).value = myPos.substring(0, startPos) + data + myPos.substring(endPos, myPos.length);
+function do_insert_data(name, data, monaco = 0) {
+    if(monaco === 0) {
+        // https://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
+        if(document.selection) {
+            document.getElementById(name).focus();
+
+            var sel = document.selection.createRange();
+            sel.text = data;
+        } else if(
+            document.getElementById(name).selectionStart || 
+            document.getElementById(name).selectionStart == '0'
+        ) {
+            var startPos = document.getElementById(name).selectionStart;
+            var endPos = document.getElementById(name).selectionEnd;
+            var myPos = document.getElementById(name).value;
+
+            document.getElementById(name).value = myPos.substring(0, startPos) + data + myPos.substring(endPos, myPos.length);
+        } else {
+            document.getElementById(name).value += data;
+        }
     } else {
-        document.getElementById(name).value += data;
+        var selection = editor.getSelection();
+        var id = { major: 1, minor: 1 };             
+        var text = data;
+        var op = {
+            identifier: id, 
+            range: selection, 
+            text: text, 
+            forceMoveMarkers: true
+        };
+        
+        editor.executeEdits("my-source", [op]);
     }
 }
 
 function monaco_to_content() {
     try {
-        document.getElementById('content').innerHTML = window.editor.getValue();
+        document.getElementById('textarea_edit_view').value = window.editor.getValue();
     } catch(e) {}
 }
 
@@ -29,6 +43,7 @@ function do_not_out() {
     window.addEventListener('DOMContentLoaded', function() {
         window.onbeforeunload = function() {
             monaco_to_content();
+            section_edit_do();
             
             data = document.getElementById('content').value;
             origin = document.getElementById('origin').value;
@@ -116,7 +131,7 @@ function pasteListener(e) {
 
 function load_preview(name) {
     var s_data = new FormData();
-    s_data.append('data', document.getElementById('content').value);
+    s_data.append('data', document.getElementById('textarea_edit_view').value);
 
     var url = "/api/w/" + name;
     var url_2 = "/api/markup";
@@ -148,7 +163,7 @@ function section_edit_init() {
     );
     
     if(data_server['markup'] === 'namumark') {
-        var data = document.getElementById('content').value;
+        var data = document.getElementById('textarea_edit_view').value;
         var data_org = data;
         var data_section = Number(data_server['section']);
         var re_heading = /(^|\n)(={1,6})(#)? ?([^=]+) ?#?={1,6}(\n|$)/;
@@ -171,7 +186,7 @@ function section_edit_init() {
                 data = data_org.slice(start_point, end_point);
                 data = data.replace(/\n$/, '');
                 
-                document.getElementById('content').value = data;
+                document.getElementById('textarea_edit_view').value = data;
                 
                 data_server['start_point'] = start_point;
                 data_server['end_point'] = end_point;
@@ -195,12 +210,12 @@ function section_edit_do() {
     
     if(data_server['start_point'] !== undefined) {
         var data = document.getElementById('origin').value;
-        var data_section = document.getElementById('content').value;
+        var data_section = document.getElementById('textarea_edit_view').value;
         
         var start_point = data_server['start_point'];
         var end_point = data_server['end_point'];
         
-        if(data.length >= end_point) {            
+        if(data.length >= end_point) {
             var data_new = '';
             data_new += data.slice(0, start_point);
             data_new += data_section;
@@ -208,5 +223,7 @@ function section_edit_do() {
             
             document.getElementById('content').value = data_new;
         }
+    } else {
+        document.getElementById('content').value = document.getElementById('textarea_edit_view').value;
     }
 }

+ 35 - 0
views/main_css/js/load_shortcut.js

@@ -0,0 +1,35 @@
+let shortcut_key_list = [];
+document.onkeyup = function(e) {
+    delete shortcut_key_list[e.key];
+}
+
+document.onkeypress = function(e) {
+    let shortcut_check = event.target.tagName.toLowerCase();
+    if(
+        shortcut_check !== 'input' &&
+        shortcut_check !== 'textarea'
+    ) {
+        let doc_shortcut = /^\/(w|history|edit|acl|topic|xref)\//i;
+
+        shortcut_key_list[e.key] = 1;
+        if(shortcut_key_list['f'] === 1) {
+            window.location.href = '/';
+        } else if(shortcut_key_list['c'] === 1) {
+            window.location.href = '/recent_change';
+        } else if(shortcut_key_list['d'] === 1) {
+            window.location.href = '/recent_discuss';
+        } else if(shortcut_key_list['a'] === 1) {
+            window.location.href = '/random';
+        }
+
+        if(window.location.pathname.match(doc_shortcut)) {
+            if(shortcut_key_list['w'] === 1) {
+                window.location.pathname = window.location.pathname.replace(doc_shortcut, '/w/');
+            } else if(shortcut_key_list['e'] === 1) {
+                window.location.pathname = window.location.pathname.replace(doc_shortcut, '/edit/');
+            } else if(shortcut_key_list['h'] === 1) {
+                window.location.pathname = window.location.pathname.replace(doc_shortcut, '/history/');
+            }
+        }
+    }
+}

+ 29 - 2
views/main_css/js/load_skin_set.js

@@ -88,6 +88,13 @@ function main_css_get_post() {
         document.cookie = 'main_css_exter_link=0;';
     }
     
+    check = document.getElementById('main_css_link_delimiter');
+    if(check.checked) {
+        document.cookie = 'main_css_link_delimiter=1;';
+    } else {
+        document.cookie = 'main_css_link_delimiter=0;';
+    }
+    
     history.go(0);
 }
 
@@ -153,6 +160,13 @@ function main_css_skin_load() {
             '<link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=5">' +
         '';
     }
+    
+    if(
+        document.cookie.match(main_css_regex_data('main_css_link_delimiter')) &&
+        document.cookie.match(main_css_regex_data('main_css_link_delimiter'))[1] === '1'
+    ) {
+        head_data.innerHTML += '<style>#real_normal_link::before, #not_thing::before, #inside::before { content: \'🅸\'; font-weight: lighter; background: transparent; }</style>';
+    }
 }
 
 function main_css_load_lang(name) {
@@ -187,7 +201,8 @@ function main_css_load_lang(name) {
             "except_ie" : "Not supported for Internet Explorer",
             "use_monaco" : "Use monaco editor",
             "self_tab" : "Current tab",
-            "exter_link_open_method" : "External link"
+            "exter_link_open_method" : "External link",
+            "link_delimiter" : "Add link delimiter"
         }, "ko-KR" : {
             "default" : "기본값",
             "change_to_normal" : "일반 텍스트로 변경",
@@ -218,7 +233,8 @@ function main_css_load_lang(name) {
             "except_ie" : "인터넷 익스플로러에선 지원되지 않음",
             "use_monaco" : "모나코 에디터 사용",
             "self_tab" : "현재 탭",
-            "exter_link_open_method" : "외부 링크"
+            "exter_link_open_method" : "외부 링크",
+            "link_delimiter" : "링크 구분자 추가"
         }
     }
 
@@ -409,6 +425,15 @@ function main_css_skin_set() {
             set_data["exter_link"] += '<option value="' + exter_link_list[i][1] + '">' + exter_link_list[i][2] + '</option>';
         }
     }
+    
+    if(
+        document.cookie.match(main_css_regex_data('main_css_link_delimiter')) &&
+        document.cookie.match(main_css_regex_data('main_css_link_delimiter'))[1] === '1'
+    ) {
+        set_data["link_delimiter"] = "checked";
+    } else {
+        set_data["link_delimiter"] = "";
+    }
 
     document.getElementById("main_skin_set").innerHTML = ' \
         <h2>1. ' + main_css_load_lang('renderer') + '</h2> \
@@ -434,6 +459,8 @@ function main_css_skin_set() {
         </select> \
         <h3>1.6. ' + main_css_load_lang('other') + '</h3> \
         <input ' + set_data["include"] + ' type="checkbox" id="main_css_include" value="include"> ' + main_css_load_lang('include_link') + ' \
+        <hr class="main_hr"> \
+        <input ' + set_data["link_delimiter"] + ' type="checkbox" id="main_css_link_delimiter" value="link_delimiter"> ' + main_css_load_lang('link_delimiter') + '<sup>(1)</sup> \
         <h3>1.7. ' + main_css_load_lang('set_toc') + '</h3> \
         <select id="main_css_toc"> \
             ' + set_data["toc"] + ' \

+ 115 - 57
views/main_css/js/render_onmark.js

@@ -5,9 +5,13 @@ function do_url_change(data) {
     return encodeURIComponent(data);
 }
 
-function do_nowiki_change(data, data_nowiki) {
-    return data.replace(/<span id="((?:.*)(?:nowiki_(?:[^"]+)))"><\/span>/, function(x, x_1) {
-        return data_nowiki[x_1];
+function do_nowiki_change(data, data_nowiki, type = 'normal') {
+    return data.replace(/<span id="((?:[^"]*)(?:nowiki_(?:[^"]+)))"><\/span>/g, function(x, x_1) {
+        if(type === 'normal') {
+            return data_nowiki[x_1];
+        } else {
+            return '\\' + data_nowiki[x_1];
+        }
     });
 }
 
@@ -31,7 +35,19 @@ function do_link_change(data, data_nowiki, no_change) {
 }
 
 function do_darkmode_split(data) {
-    return data.split(',')[0];
+    if(
+        document.cookie.match(regex_data('main_css_darkmode')) &&
+        document.cookie.match(regex_data('main_css_darkmode'))[1] === '1'
+    ) {
+        let data_split = data.split(',');
+        if(data_split.length > 1) {
+            return data.split(',')[1];
+        } else {
+            return data.split(',')[0];
+        }
+    } else {
+        return data.split(',')[0];
+    }
 }
 
 function do_js_safe_change(data, br_on = 1) {
@@ -73,7 +89,11 @@ function do_all_try(data) {
 }
 
 function do_px_add(data) {
-    return data.match(/^[0-9]+$/) ? (data + 'px') : data;
+    if(data) {
+        return data.match(/^[0-9]+$/) ? (data + 'px') : data;
+    } else {
+        return '';
+    }
 }
 
 function do_return_date() {
@@ -97,6 +117,12 @@ function do_xss_change(data) {
     return data;
 }
 
+function do_end_br_replace(data) {
+    data = data.replace(/(\n| )+$/, '\n');
+    
+    return data;
+}
+
 // Sub
 function do_onmark_text_render(data) {    
     data = data.replace(/'''((?:(?!''').)+)'''/g, '<b>$1</b>');
@@ -185,7 +211,8 @@ function do_onmark_heading_render(data, name_doc, name_include) {
     
     if(toc_data !== '') {
         toc_data += '</div>';
-        data += '</div>';
+
+        data = do_end_br_replace(data) + '</div>';
     }
     
     var toc_auto_add = data.match(/\[(?:목차|toc)\(no\)\]/);
@@ -224,7 +251,9 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
 
             num_link += 1;
             var num_link_str = String(num_link - 1);
-            if(link_real.match(file_re)) {
+            if(link_real.match(/<|>/)) {
+                return '<link_s>' + x_1 + '<link_e>';
+            } else if(link_real.match(file_re)) {
                 var file_load_type = link_real.match(file_re)[1];
                 var file_name = link_real.replace(file_re, '');
 
@@ -247,29 +276,28 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
                 var file_align = '';
 
                 var file_set = link_out_2.split('&amp;');
-                var i = 0;
-                while(file_set[i]) {
+                for(let i = 0; file_set[i]; i++) {
                     var file_set_name = file_set[i].split('=');
                     var file_set_data = file_set_name[1];
                     file_set_name = file_set_name[0];
-
-                    if(file_set_name === 'width') {
-                        file_style += 'width:' + file_set_data + ';';
-                    } else if(file_set_name === 'height') {
-                        file_style += 'height:' + file_set_data + ';';
-                    } else if(file_set_name === 'bgcolor') {
-                        file_bgcolor += 'background:' + file_set_data + ';';
-                    } else if(file_set_name === 'alt') {
-                        file_alt += file_set_data;
-                    } else if(file_set_name === 'align') {
-                        if(file_set_data === 'center') {
-                            file_align = 'display: block; text-align: center;';
-                        } else {
-                            file_align = 'float: ' + file_set_data + ';';
+                    
+                    if(file_set_data) {
+                        if(file_set_name === 'width') {
+                            file_style += 'width:' + do_px_add(file_set_data) + ';';
+                        } else if(file_set_name === 'height') {
+                            file_style += 'height:' + do_px_add(file_set_data) + ';';
+                        } else if(file_set_name === 'bgcolor') {
+                            file_bgcolor += 'background:' + file_set_data + ';';
+                        } else if(file_set_name === 'alt') {
+                            file_alt += file_set_data;
+                        } else if(file_set_name === 'align') {
+                            if(file_set_data === 'center') {
+                                file_align = 'display: block; text-align: center;';
+                            } else {
+                                file_align = 'float: ' + file_set_data + ';';
+                            }
                         }
-                    } 
-
-                    i += 1;
+                    }
                 }
 
                 return '' +
@@ -375,11 +403,11 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
                     '';
 
                     return  '<a id="inside" ' +
-                            'class="' + name_include + 'link_finder" ' +
-                            'target="_blank" ' +
-                            'name="' + name_include + 'set_link_' + num_link_str + '" ' + 
-                            'title=""' +
-                            'href="">' + data_inter_logo + link_out + '</a>'; 
+                                'class="' + name_include + 'link_finder" ' +
+                                'target="_blank" ' +
+                                'name="' + name_include + 'set_link_' + num_link_str + '" ' + 
+                                'title=""' +
+                                'href="">' + data_inter_logo + link_out + '</a>'; 
                 } else {
                     return '';
                 }
@@ -419,12 +447,16 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
                 }
 
                 return  '<a class="' + name_include + 'link_finder" ' +
+                            'id="real_normal_link"' +
                             'name="' + name_include + 'set_link_' + num_link_str + '" ' +
                             'title="" ' +
                             'href="">' + link_out + '</a>';
             }
         });
     }
+    
+    data = data.replace(/<link_s>/, '[[');
+    data = data.replace(/<link_e>/, ']]');
 
     if(category_data !== '') {
         if(name_include === '') {
@@ -433,10 +465,10 @@ function do_onmark_link_render(data, data_js, name_doc, name_include, data_nowik
             category_data = '<div style="display: none;" id="cate_all"><div id="cate">Category : ' + category_data;
         }
         
-        data += category_data.replace(/\| $/, '') + '</div></div>';
+        category_data = category_data.replace(/\| $/, '') + '</div></div>';
     }
     
-    return [data, data_js];
+    return [data, data_js, category_data];
 }
 
 function do_onmark_footnote_render(data, name_include) {
@@ -498,7 +530,7 @@ function do_onmark_footnote_render(data, name_include) {
     }
     
     if(name_include === '' && footnote_end_data !== '') {
-        data += '<ul id="footnote_data">' + footnote_end_data + '</ul>';
+        data = do_end_br_replace(data) + '<ul id="footnote_data">' + footnote_end_data + '</ul>';
     }
     
     return data;
@@ -609,22 +641,26 @@ function do_onmark_middle_render(data, data_js, name_include, data_nowiki, name_
             }
 
             var middle_type = middle_data.match(
-                /^(?:(?:(?:(#|@)((?:[0-9a-f-A-F]{3}){1,2}))(?:,(?:#|@)(?:(?:[0-9a-f-A-F]{3}){1,2}))?|(#|@)([a-zA-Z]+))|(\+|-)([1-5])|#!(html|wiki|syntax|folding|html))$/i
+                /^(?:(?:(#|@)((?:[0-9a-f-A-F]{3}){1,2}|\w+))(?:,(?:(#|@)((?:[0-9a-f-A-F]{3}){1,2}|\w+)))?|(\+|-)([1-5])|#!(html|wiki|syntax|folding|html))$/i
             );
             if(middle_type) {
                 if(middle_data_x_1[middle_data_x_1.length - 1] === '\\') {
                     return middle_data_before + '{{{' + middle_data_x_1 + '<mid_e>';
                 } else if(middle_type[1]) {
-                    if(middle_type[1] === '@') {
-                        return middle_data_before + '<span style="background: #' + middle_type[2] + '">' + middle_data_all + '</span>';
-                    } else {
-                        return middle_data_before + '<span style="color: #' + middle_type[2] + '">' + middle_data_all + '</span>';
+                    let data_color = middle_type[2];
+                    if(middle_type[3]) {
+                        data_color = do_darkmode_split(middle_type[2] + ',' + middle_type[4])    
+                    }
+                    
+                    let data_sharp = '';
+                    if(data_color.match(/^(?:[0-9a-f-A-F]{3}){1,2}$/)) {
+                        data_sharp = '#';
                     }
-                } else if(middle_type[3]) {
-                    if(middle_type[3] === '@') {
-                        return middle_data_before + '<span style="background: ' + middle_type[4] + '">' + middle_data_all + '</span>';
+                    
+                    if(middle_type[1] === '@') {
+                        return middle_data_before + '<span style="background: ' + data_sharp + data_color + '">' + middle_data_all + '</span>';
                     } else {
-                        return middle_data_before + '<span style="color: ' + middle_type[4] + '">' + middle_data_all + '</span>';
+                        return middle_data_before + '<span style="color: ' + data_sharp + data_color + '">' + middle_data_all + '</span>';
                     }
                 } else if(middle_type[5]) {
                     if(middle_type[5] === '+') {
@@ -645,7 +681,7 @@ function do_onmark_middle_render(data, data_js, name_include, data_nowiki, name_
 
                         return middle_data_before + '<span id="' + name_include + 'nowiki_html_' + String(html_n) + '"></span>';
                     } else if(middle_type_sub === 'wiki') {
-                        var middle_wiki_re = /^(?:[^ ]+)(?: style=['"]([^\n'"]*)['"])?\n?/;
+                        var middle_wiki_re = /^(?:[^ ]+)(?: style=['"]([^\n'"]*)['"])?[^\n]*\n?/;
                         var middle_wiki = middle_data_x_1.match(middle_wiki_re);
                         middle_wiki = middle_wiki[1] ? middle_wiki[1] : '';
                         middle_wiki = middle_wiki.replace(/position/, '');
@@ -688,10 +724,11 @@ function do_onmark_middle_render(data, data_js, name_include, data_nowiki, name_
                     } else if(middle_type_sub === 'syntax') {
                         syntax_n += 1;
 
-                        var middle_syntax = middle_data_x_1.match(/^(?:[^ ]+) ([^\n]+)\n/);
+                        let middle_syntax_re = /^(?:[^ ]+) ([^\n]+)\n?/;
+                        var middle_syntax = middle_data_x_1.match(middle_syntax_re);
                         middle_syntax = middle_syntax ? middle_syntax[1] : 'python';
 
-                        middle_data_all = middle_data_x_1.replace(/^(?:[^ ]+) ([^\n]+)\n/, '');
+                        middle_data_all = middle_data_x_1.replace(middle_syntax_re, '');
 
                         data_nowiki[name_include + 'nowiki_syntax_' + String(syntax_n)] = middle_data_all;
                         data_js += do_data_try_insert(
@@ -732,7 +769,7 @@ function do_onmark_middle_render(data, data_js, name_include, data_nowiki, name_
     return [data, data_js, data_nowiki];
 }
 
-function do_onmark_last_render(data) {       
+function do_onmark_last_render(data, name_include, data_category) {       
     // middle_render 마지막 처리
     data = data.replace(/<wiki_s_[0-9] /g, '<div ');
     data = data.replace(/<wiki_e_[0-9]>/g, '</div>');
@@ -743,9 +780,13 @@ function do_onmark_last_render(data) {
     
     // br 마지막 처리
     data = data.replace(/^(\n| )+/, '');
-    data = data.replace(/(\n| )+$/, '');
+    data = do_end_br_replace(data);
     data = data.replace(/\n/g, '<br>');
     
+    if(name_include === '') {
+        data += data_category;
+    }
+    
     return data;
 }
 
@@ -915,9 +956,10 @@ function do_onmark_table_render_sub(data, data_col) {
                 
                 
             } else {
-                var table_option_data = data_option.replace(/"/g, '').match(/^((?:#[a-zA-Z0-9]{3}){1,2}|\w+)/);
+                var table_option_data = data_option.replace(/"/g, '')
+                table_option_data = table_option_data.match(/^((?:(?:#(?:[a-zA-Z0-9]{3}){1,2})|\w+)(?:,(?:(?:#(?:[a-zA-Z0-9]{3}){1,2})|\w+))?)/);
                 if(table_option_data) {
-                    data_option_all['td'] += 'background:' + table_option_data[1] + ';';
+                    data_option_all['td'] += 'background:' + do_darkmode_split(table_option_data[1]) + ';';
                 } else {
                     no_option = '<lt>' + data_option + '<gt>';
                 }
@@ -948,7 +990,7 @@ function do_onmark_table_render_sub(data, data_col) {
 }
 
 function do_onmark_table_render_main(data) {
-    var table_re = /\n((?:(?:\|\||\|\|\n|(?:\|\|)+(?!\n)(?:(?:(?!\|\|).)+))+)\|\|)\n/gs;
+    var table_re = /\n((?:(?:(?:(?:\|\|)+)|(?:\|[^|]+\|(?:\|\|)*))(?!\n)(?:(?:(?!\|\|).)+))(?:(?:\|\||\|\|\n|(?:\|\|)+(?!\n)(?:(?:(?!\|\|).)+))*)\|\|)\n/gs;
     data = data.replace(table_re, function(x, x_1) {
         var table_cel_re = /((?:\|\|)+)((?:(?!\|\|).)*)/gs;
         var table_data = '';
@@ -957,6 +999,14 @@ function do_onmark_table_render_main(data) {
         var table_col = 0;
         var table_col_data = {};
         var table_col_count = {};
+        
+        let table_caption_re = /^\|([^|]+)\|/;
+        let table_caption = '';
+        let table_caption_get = table_data_org.match(table_caption_re);
+        if(table_caption_get) {
+            table_caption = '<caption>' + table_caption_get[1] + '</caption>';
+            table_data_org = table_data_org.replace(table_caption_re, '||');
+        }
             
         table_data_org = table_data_org.replace(table_cel_re, function(x, x_1, x_2) {
             if(!table_col_data[table_col]) {
@@ -982,6 +1032,7 @@ function do_onmark_table_render_main(data) {
                 table_data += '' + 
                     '<div style="' + table_data_option['div'] + '">' +
                         '<table style="' + table_data_option['table'] + '">' +
+                            table_caption +
                 '';
             }
 
@@ -1076,11 +1127,13 @@ function do_onmark_list_sub_render(data) {
         });
 
         data = data.replace(quote_re, '' +
+            '\n<start_point>' +
             '<blockquote>' + 
                 '<end_point>\n' +
                 quote_end_data + 
                 '\n<start_point>' +
             '</blockquote>' +
+            '<end_point>\n' +
        '');
     }
     
@@ -1136,14 +1189,18 @@ function do_onmark_list_render(data) {
     return data;
 }
 
-function do_onmark_math_render(data, data_js, name_include) {
-    data = data.replace(/<math>((?:(?!<\/math>).)+)<\/math>/g, '[math($1)]');
+function do_onmark_math_render(data, data_js, name_include, data_nowiki) {
+    data = data.replace(/&lt;math&gt;((?:(?!&lt;\/math&gt;).)+)&lt;\/math&gt;/g, '[math($1)]');
     
     var i = 0;
     data = data.replace(/\[math\((((?!\)]).)+)\)]/g, function(x, x_1) {
         i += 1;
         
-        data_js += do_math_try_insert(name_include + 'math_' + String(i), do_js_safe_change(do_xss_change(x_1)));
+        data_js += do_math_try_insert(
+            name_include + 'math_' + String(i), 
+            do_js_safe_change(do_xss_change(do_nowiki_change(x_1, data_nowiki, 'math')))
+        );
+        
         return '<span id="' + name_include + 'math_' + String(i) + '"></span>';
     });
     
@@ -1189,7 +1246,7 @@ function do_onmark_redirect_render(data, data_js, name_doc) {
 }
 
 function do_onmark_remark_render(data) {
-    data = data.replace(/\n##([^\n]+)/, '');
+    data = data.replace(/\n##([^\n]+)/g, '');
     
     return data;
 }
@@ -1230,7 +1287,7 @@ function do_onmark_render(
         data_js = data_var[1];
         data_nowiki = data_var[2];
         
-        data_var = do_onmark_math_render(data, data_js, name_include);
+        data_var = do_onmark_math_render(data, data_js, name_include, data_nowiki);
         data = data_var[0];
         data_js = data_var[1];
 
@@ -1257,6 +1314,7 @@ function do_onmark_render(
         );
         data = data_var[0];
         data_js = data_var[1];
+        var data_category = data_var[2];
 
         data_var = do_onmark_macro_render(data, data_js);
         data = data_var[0];
@@ -1265,7 +1323,7 @@ function do_onmark_render(
         data = do_onmark_list_render(data);
         data = do_onmark_hr_render(data);
         data = do_onmark_footnote_render(data, name_include);
-        data = do_onmark_last_render(data, name_include);
+        data = do_onmark_last_render(data, name_include, data_category);
     }
     
     data_js += '' + 

+ 0 - 7
views/tenshi/css/main.css

@@ -420,13 +420,6 @@ select {
 }
 
 /* content */
-#out_link::before {
-    content: '🅴';
-    font-weight: lighter;
-    background: transparent;
-    color: green;
-}
-
 a:hover {
     text-decoration: underline;
 }

+ 3 - 1
views/tenshi/index.html

@@ -22,7 +22,9 @@
             <meta name="title" content="{{imp[0]}} - {{imp[1][0]}}">
         {% endif %}
         <meta name="keywords" content="{{imp[0]}}">
-        <meta name="description" content="{{data|cut_100}}">
+        {% if imp[2][12] != 0 and imp[2][12] == 'w' %}
+            <meta name="description" content="{{data|cut_100}}">
+        {% endif %}
         <meta name="viewport" content="width=device-width, initial-scale=1">
     </head>
     <body>