소스 검색

아 뭐 걍 합쳐도 별 문제 없겠지

Dev
잉여개발기 (SPDV) 5 년 전
부모
커밋
32a7054bbc
69개의 변경된 파일1362개의 추가작업 그리고 587개의 파일을 삭제
  1. 8 4
      app.py
  2. 5 2
      language/en-US.json
  3. 5 2
      language/ko-KR.json
  4. 1 1
      route/alarm.py
  5. 6 2
      route/api_raw.py
  6. 2 6
      route/api_skin_info.py
  7. 6 2
      route/api_w.py
  8. 17 19
      route/applications.py
  9. 86 66
      route/edit.py
  10. 3 3
      route/edit_delete.py
  11. 1 1
      route/edit_many_delete.py
  12. 2 5
      route/func_title_random.py
  13. 1 1
      route/give_acl.py
  14. 22 51
      route/give_admin_groups.py
  15. 14 10
      route/give_delete_admin_group.py
  16. 15 20
      route/give_user_ban.py
  17. 1 1
      route/give_user_check.py
  18. 1 1
      route/inter_wiki.py
  19. 1 1
      route/list_acl.py
  20. 1 1
      route/list_admin.py
  21. 1 1
      route/list_admin_use.py
  22. 1 1
      route/list_give.py
  23. 1 1
      route/list_image_file.py
  24. 24 0
      route/list_long_page.py
  25. 1 1
      route/list_not_close_topic.py
  26. 1 1
      route/list_old_page.py
  27. 2 5
      route/list_please.py
  28. 10 12
      route/list_title_index.py
  29. 1 1
      route/list_user.py
  30. 2 12
      route/login.py
  31. 2 9
      route/login_2fa.py
  32. 3 10
      route/login_check_key.py
  33. 11 16
      route/login_pw_change.py
  34. 5 5
      route/main_manager.py
  35. 6 4
      route/main_other.py
  36. 5 2
      route/main_views.py
  37. 1 1
      route/recent_history_tool.py
  38. 4 4
      route/search_deep.py
  39. 1 1
      route/server_now_update.py
  40. 16 13
      route/setting.py
  41. 67 50
      route/tool/func.py
  42. 1 1
      route/tool/init.py
  43. 7 0
      route/tool/mark.py
  44. 13 15
      route/tool/set_mark/namumark.py
  45. 3 1
      route/tool/set_mark/tool.py
  46. 28 55
      route/topic.py
  47. 3 3
      route/topic_admin.py
  48. 3 3
      route/topic_tool.py
  49. 1 1
      route/user_count_edit.py
  50. 4 3
      route/user_info.py
  51. 49 7
      route/user_setting.py
  52. 2 2
      route/user_tool.py
  53. 1 1
      route/view_down.py
  54. 7 7
      route/view_read.py
  55. 1 1
      route/view_xref.py
  56. 1 1
      route/vote.py
  57. 1 1
      route/vote_end.py
  58. 1 1
      route/watch_list.py
  59. 2 2
      version.json
  60. 257 53
      views/main_css/css/main.css
  61. 51 12
      views/main_css/css/sub/dark.css
  62. 39 11
      views/main_css/js/load_editor.js
  63. 411 0
      views/main_css/js/load_onmark_render.js
  64. 0 27
      views/main_css/js/load_preview.js
  65. 102 5
      views/main_css/js/load_skin_set.js
  66. 0 8
      views/marisa/css/main.css
  67. 2 2
      views/marisa/index.html
  68. 2 8
      views/marisa/js/main.js
  69. 7 7
      views/marisa/js/skin_set.js

+ 8 - 4
app.py

@@ -118,11 +118,11 @@ if set_data['db_type'] == 'mysql':
     curs = conn.cursor()
 
     try:
-        curs.execute(db_change('create database ? default character set utf8mb4;')%pymysql.escape_string(set_data['db']))
+        curs.execute(db_change('create database ? default character set utf8mb4;'), set_data['db'])
     except:
         pass
 
-    curs.execute(db_change('use ?')%pymysql.escape_string(set_data['db']))
+    conn.select_db(set_data['db'])
 else:
     conn = sqlite3.connect(set_data['db'] + '.db')
     curs = conn.cursor()
@@ -131,7 +131,7 @@ load_conn(conn)
 
 # DB init
 create_data = {}
-create_data['data'] = ['title', 'data']
+create_data['data'] = ['title', 'data', 'type']
 create_data['cache_data'] = ['title', 'data', 'id']
 create_data['history'] = ['id', 'title', 'data', 'date', 'ip', 'send', 'leng', 'hide', 'type']
 create_data['rc'] = ['id', 'title', 'date', 'type']
@@ -604,6 +604,10 @@ def func_upload():
 def user_info():
     return user_info_2(conn)
 
+@app.route('/<regex("long_page|short_page"):tool>')
+def list_long_page(tool = 'long_page'):
+    return list_long_page_2(conn, tool)
+
 @app.route('/<regex("watch_list|star_doc"):tool>')
 def watch_list(tool = 'star_doc'):
     return watch_list_2(conn, tool)
@@ -741,4 +745,4 @@ if __name__ == "__main__":
     http_server = tornado.httpserver.HTTPServer(tornado.wsgi.WSGIContainer(app))
     http_server.listen(int(server_set['port']), address = server_set['host'])
 
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.instance().start()

+ 5 - 2
language/en-US.json

@@ -267,6 +267,7 @@
                 "requires_approval" : "Requires approval for register",
                 "approval_question": "Registeration questions",
                 "backup_where" : "Backup location",
+                "ua_get_off" : "Turn off members information collection",
             "_comment_2.2.3_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
@@ -301,6 +302,8 @@
             "all_document_list" : "All document(s) list",
             "watchlist" : "Watchlist",
             "image_file_list" : "Image file(s) list",
+            "short_page" : "Short page(s) list",
+            "long_page" : "Long page(s) list",
             "_comment_2.3.1_" : "ACL document list",
                 "acl_document_list" : "ACL document(s) list",
                 "acl_required" : "Required ACL",
@@ -335,7 +338,7 @@
             "before_acl" : "Only those who have edited this document before",
             "ban_acl" : "Include blocked users",
             "ban_admin_acl" : "Blocked users and administrators",
-            "30_day_acl" : "Only members 30 days after register",
+            "30_day_acl" : "Only members 30 days after sign up",
             "_comment_2.6_1_" : "Set",
                 "document_acl" : "Document ACL",
                 "discussion_acl" : "Discussion(s) ACL",
@@ -373,7 +376,7 @@
         "oauth_settings_not_found" : "The administrator has not provided any data about using this feature.",
         "oauth_disabled" : "The administrator has disabled this feature.",
         "http_warring" : "Warning: If you are not on HTTPS connection, Your information can be leaked. We won't response to that.",
-        "user_head_warring" : "User <HEAD> will be deleted if you close the browser or when you sign in.",
+        "user_head_warring" : "User data will be deleted if you close the browser or when you sign in.",
         "no_login_warring" : "You are not logged in. The IP address will be logged when editing or discussing with non-login.",
         "user_reset_sign" : "Your account information has changed like this.",
         "update_warring" : "Manual updates are recommended if your version is 0.2 or lower than the latest version. For Windows, the contents of the route folder disappear.",

+ 5 - 2
language/ko-KR.json

@@ -271,7 +271,7 @@
     "other": "기타",
     "edit": "편집",
     "open_discussion_list": "열린 토론 목록",
-    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자가 지정한 <HEAD>는 삭제됩니다.",
+    "user_head_warring": "비로그인시 브라우저를 닫거나 로그인시 사용자가 지정한 정보는 삭제됩니다.",
     "email_required": "이메일 필요",
     "1_day": "1일",
     "regex_error": "정규표현식에 오류가 있습니다.",
@@ -397,5 +397,8 @@
     "upload_help" : "파일 올리기 문구",
     "upload_default" : "파일 기타란 기본값",
     "same_email_error" : "동일한 이메일을 사용하는 사용자가 있습니다.",
-    "input_email_error" : "입력 값에 문제가 있습니다."
+    "input_email_error" : "입력 값에 문제가 있습니다.",
+    "short_page" : "짧은 문서 목록",
+    "long_page" : "긴 문서 목록",
+    "ua_get_off" : "가입자 정보 수집 끄기"
 }

+ 1 - 1
route/alarm.py

@@ -9,7 +9,7 @@ def alarm_2(conn):
     else:
         sql_num = 0
 
-    data = '<ul>'
+    data = '<ul class="inside_ul">'
 
     curs.execute(db_change("select data, date from alarm where name = ? order by date desc limit ?, 50"), [ip_check(), sql_num])
     data_list = curs.fetchall()

+ 6 - 2
route/api_raw.py

@@ -4,11 +4,15 @@ def api_raw_2(conn, name):
     curs = conn.cursor()
 
     if acl_check(name, 'render') != 1:
-        curs.execute(db_change("select data from data where title = ?"), [name])
+        rev = flask.request.args.get('num', '')
+        if rev != '':
+            curs.execute(db_change("select data from history where title = ? and id = ?"), [name, rev])
+        else:
+            curs.execute(db_change("select data from data where title = ?"), [name])
         data = curs.fetchall()
         if data:
             json_data = { "title" : name, "data" : render_set(title = name, data = data[0][0], s_data = 1) }
 
             return flask.jsonify(json_data)
         
-    return flask.jsonify({})
+    return flask.jsonify({})

+ 2 - 6
route/api_skin_info.py

@@ -2,12 +2,8 @@ from .tool.func import *
 
 def api_skin_info_2(conn, name):
     curs = conn.cursor()
-
-    if name == '':
-        name = skin_check()
-    else:
-        name = './views/' + name + '/index.html'
-
+    name = skin_check() if name == '' else './views/' + name + '/index.html'
+    
     if not flask.request.args.get('all', None):
         json_address = re.sub(r"(((?!\.|\/).)+)\.html$", "info.json", name)
         try:

+ 6 - 2
route/api_w.py

@@ -15,7 +15,11 @@ def api_w_2(conn, name):
 
                 return flask.jsonify({ "title" : name, "data" : g_data[0], "js_data" : g_data[1] })
             else:
-                curs.execute(db_change("select data from data where title = ?"), [name])
+                rev = flask.request.args.get('num', '')
+                if rev != '':
+                    curs.execute(db_change("select data from history where title = ? and id = ?"), [name, rev])
+                else:
+                    curs.execute(db_change("select data from data where title = ?"), [name])
                 data = curs.fetchall()
                 if data:
                     json_data = data[0][0]
@@ -43,4 +47,4 @@ def api_w_2(conn, name):
 
                     return flask.jsonify({ "title" : name, "data" : g_data[0], "js_data" : g_data[1] })
 
-    return flask.jsonify({})
+    return flask.jsonify({})

+ 17 - 19
route/applications.py

@@ -4,9 +4,8 @@ def applications_2(conn):
     curs = conn.cursor()
 
     div = ''
-    admin = admin_check()
 
-    if admin != 1:
+    if admin_check() != 1:
         return re_error('/ban')
 
     curs.execute(db_change('select data from other where name = "requires_approval"'))
@@ -26,10 +25,13 @@ def applications_2(conn):
                 email = application[5]
                 if not question:
                     question = ''
+
                 if not answer:
                     answer = ''
+                
                 if not email:
                     email = ''
+                
                 div += '''
                     <form method=\"post\">
                         <table>
@@ -41,7 +43,7 @@ def applications_2(conn):
                                     <td>''' + load_lang('application_time') + '''</td><td>''' + application[1] + '''</td>
                                 </tr>
                                 <tr>
-                                    <td>''' + load_lang('approval_question') + '''</td><td>''' + question + '''</td>
+                                    <td>''' + load_lang('approval_question') + '''</td><td>''' + html.escape(question) + '''</td>
                                 </tr>
                                 <tr>
                                     <td>''' + load_lang('answer') + '''</td><td>''' + html.escape(answer) + '''</td>
@@ -62,9 +64,17 @@ def applications_2(conn):
                 '''
         else:
             div += load_lang('no_applications_now')
+
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang('application_list'), wiki_set(), custom(), other2([0, 0])],
+            data = div,
+            menu = [['other', load_lang('return')]]
+        ))
     else:
         if flask.request.form.get('approve', '') != '':
-            curs.execute(db_change('select id, pw, date, encode, question, answer, ip, ua, email from user_application where token = ?'), [flask.request.form.get('approve', '')])
+            curs.execute(db_change('select id, pw, date, encode, question, answer, ip, ua, email from user_application where token = ?'), [
+                flask.request.form.get('approve', '')
+            ])
             application = curs.fetchall()
             if not application:
                 return re_error('/error/26')
@@ -83,26 +93,14 @@ def applications_2(conn):
             ])
             curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question', ?, ?)"), [application[0], application[4]])
             curs.execute(db_change("insert into user_set (name, id, data) values ('approval_question_answer', ?, ?)"), [application[0], application[5]])
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-                application[0], 
-                application[6], 
-                application[7], 
-                application[2]
-            ])
+            ua_plus(application[0], application[6], application[7], application[2])
             if application[8] and application[8] != '':
                 curs.execute(db_change("insert into user_set (name, id, data) values ('email', ?, ?)"), [application[0], application[8]])
+            
             curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('approve', '')])
- 
-
             conn.commit()
         elif flask.request.form.get('decline', '') != '':
             curs.execute(db_change('delete from user_application where token = ?'), [flask.request.form.get('decline', '')])
             conn.commit()
 
-        return redirect('/applications')
-
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang('application_list'), wiki_set(), custom(), other2([0, 0])],
-        data = div,
-        menu = [['other', load_lang('return')]]
-    ))
+        return redirect('/applications')

+ 86 - 66
route/edit.py

@@ -29,12 +29,14 @@ def edit_2(conn, name):
     if acl_check(name) == 1:
         return re_error('/ban')
     
+    curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
+    doc_ver = curs.fetchall()
+    doc_ver = doc_ver[0][0] if doc_ver else '0'
+
     edit_repeat = 0
     if flask.request.method == 'POST':
         edit_repeat = 1
-        curs.execute(db_change("select id from history where title = ? order by id + 0 desc"), [name])
-        old = curs.fetchall()
-        if old and flask.request.form.get('ver', '') != old[0][0]:
+        if flask.request.form.get('ver', '') != doc_ver:
             edit_repeat = 2
     
     if edit_repeat == 1:
@@ -48,10 +50,6 @@ def edit_2(conn, name):
 
         today = get_time()
         content = flask.request.form.get('content', '').replace('\r\n', '\n')
-        o_content = flask.request.form.get('o_content', '').replace('\r\n', '\n')
-
-        if o_content == content:
-            return redirect('/w/' + url_pas(name))
         
         if edit_filter_do(content) == 1:
             return re_error('/error/21')
@@ -90,11 +88,7 @@ def edit_2(conn, name):
 
         curs.execute(db_change("select user from scan where title = ? and type = ''"), [name])
         for scan_user in curs.fetchall():
-            curs.execute(db_change("insert into alarm (name, data, date) values (?, ?, ?)"), [
-                scan_user[0],
-                ip + ' | <a href="/w/' + url_pas(name) + '">' + name + '</a> | Edit', 
-                today
-            ])
+            add_alarm(scan_user[0], ip + ' | <a href="/w/' + url_pas(name) + '">' + name + '</a> | Edit')
                 
         history_plus(
             name,
@@ -118,64 +112,47 @@ def edit_2(conn, name):
         
         return redirect('/w/' + url_pas(name) + (('#edit_load_' + str(section)) if section else ''))
     else:
-        curs.execute(db_change("select data, id from history where title = ? order by id + 0 desc"), [name])
-        old = curs.fetchall()
-        if old:
-            if section:
-                data = html.escape('\n' + old[0][0].replace('\r\n', '\n'))
-                data = re.sub(r'\n(?P<in>={1,6})', '<br>\g<in>', data)
-
-                section_data = re.findall(r'<br>((?:(?:(?!<br>).)*\n*)*)', data)
-                if len(section_data) >= section:
-                    data = html.unescape(section_data[section - 1])
-                else:
-                    return redirect('/edit/' + url_pas(name))
+        editor_top_text = ''
+        if edit_repeat != 2:
+            load_title = flask.request.args.get('plus', None)
+            if load_title:
+                curs.execute(db_change("select data from data where title = ?"), [load_title])
+                get_data = curs.fetchall()
+                data = get_data[0][0] if get_data else ''
             else:
-                data = old[0][0].replace('\r\n', '\n')
+                curs.execute(db_change("select data, id from history where title = ? order by id + 0 desc"), [name])
+                old = curs.fetchall()
+                old = old if old else [['']]
+                if section:
+                    data = html.escape('\n' + old[0][0].replace('\r\n', '\n'))
+                    data = re.sub(r'\n(?P<in>={1,6})', '<br>\g<in>', data)
+
+                    section_data = re.findall(r'<br>((?:(?:(?!<br>).)*\n*)*)', data)
+                    if len(section_data) >= section:
+                        data = html.unescape(section_data[section - 1])
+                    else:
+                        return redirect('/edit/' + url_pas(name))
+                else:
+                    data = old[0][0].replace('\r\n', '\n')
+                    editor_top_text += '<a href="/manager/15?plus=' + url_pas(name) + '">(' + load_lang('load') + ')</a> '
         else:
-            data = ''
-            
-        data_old = data
-        if edit_repeat == 2:
             data = flask.request.form.get('content', '')
-        
             warring_edit = load_lang('exp_edit_conflict') + ' '
 
             if flask.request.form.get('ver', '0') == '0':
-                warring_edit += '<a href="/raw/' + url_pas(name) + '">(r' + old[0][1] + ')</a>'
+                warring_edit += '<a href="/raw/' + url_pas(name) + '">(r' + doc_ver + ')</a>'
             else:
                 warring_edit += '' + \
-                    '<a href="/diff/' + url_pas(name) + '?first=' + flask.request.form.get('ver', '1') + '&second=' + old[0][1] + '">(r' + old[0][1] + ')</a>' + \
+                    '<a href="/diff/' + url_pas(name) + '?first=' + flask.request.form.get('ver', '1') + '&second=' + doc_ver + '">(r' + doc_ver + ')</a>' + \
                 ''
 
             warring_edit += '<hr class="main_hr">'
-        else:
-            warring_edit = ''
+            editor_top_text = warring_edit + editor_top_text
 
-        get_name = ''
-        if not section and not flask.request.args.get('plus', None):
-            get_name += '' + \
-                '<a href="/manager/15?plus=' + url_pas(name) + '">(' + load_lang('load') + ')</a> ' + \
-            ''
-            
-        get_name += '' + \
+        editor_top_text += '' + \
             '<a href="/edit_filter">(' + load_lang('edit_filter_rule') + ')</a>' + \
             '<hr class="main_hr">' + \
         ''
-            
-        if flask.request.args.get('plus', None):
-            curs.execute(db_change("select data from data where title = ?"), [flask.request.args.get('plus', 'test')])
-            get_data = curs.fetchall()
-            if get_data:
-                data = get_data[0][0]
-
-        save_button = load_lang('save')
-        menu_plus = [
-            ['delete/' + url_pas(name), load_lang('delete')], 
-            ['move/' + url_pas(name), load_lang('move')], 
-            ['upload', load_lang('upload')]
-        ]
-        sub = load_lang('edit')
 
         curs.execute(db_change('select data from other where name = "edit_bottom_text"'))
         sql_d = curs.fetchall()
@@ -197,31 +174,74 @@ def edit_2(conn, name):
         p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
 
         data = re.sub(r'\n+$', '', data)
-        data_old = re.sub(r'\n+$', '', data_old)
+
+        if flask.request.cookies.get('main_css_monaco', '0') == '1':
+            editor_display = 'style="display: none;"'
+            monaco_display = ''
+            add_get_file = '''
+                <link   rel="stylesheet"
+                        data-name="vs/editor/editor.main" 
+                        href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/editor/editor.main.min.css">
+                <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.20.0/min/vs/loader.min.js"></script>
+            '''
+            add_script = '''
+                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,
+                        language: 'plaintext',
+                        theme: 'vs-dark'
+                    });
+                });
+
+                function monaco_to_content() {
+                    document.getElementById('content').innerHTML = window.editor.getValue();
+                }
+            '''
+        else:
+            editor_display = ''
+            monaco_display = 'style="display: none;"'
+            add_get_file = ''
+            add_script = 'function monaco_to_content() {}'
 
         return easy_minify(flask.render_template(skin_check(), 
-            imp = [name, wiki_set(), custom(), other2(['(' + sub + ')', 0])],
-            data =  get_name + '''
+            imp = [name, wiki_set(), custom(), other2(['(' + load_lang('edit') + ')', 0])],
+            data =  editor_top_text + add_get_file + '''
                 <form method="post">
                     <script>
                         do_paste_image();
                         do_not_out();
+                        ''' + add_script + '''
                     </script>
-                    ''' + edit_button() + '''
-                    ''' + warring_edit + '''
-                    <textarea id="content" class="content" placeholder="''' + p_text + '''" name="content">''' + html.escape(data) + '''</textarea>
-                    <textarea id="origin" name="o_content">''' + html.escape(data_old) + '''</textarea>
+                    <div ''' + editor_display + '''>''' + edit_button() + '''</div>
+                    <div    id="monaco_editor"
+                            class="content" 
+                            ''' + monaco_display + '''></div>
+                    <textarea   id="content"
+                                ''' + editor_display + '''
+                                class="content" 
+                                placeholder="''' + p_text + '''" 
+                                name="content">''' + html.escape(data) + '''</textarea>
                     <hr class="main_hr">
                     <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                    <input id="origin" name="ver" value="''' + (old[0][1] if old else '0') + '''">
+                    <input id="origin" name="ver" value="''' + doc_ver + '''">
                     <hr class="main_hr">
                     ''' + captcha_get() + ip_warring() + cccb_text + '''
-                    <button id="save" type="submit" onclick="save_stop_exit();">''' + save_button + '''</button>
-                    <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
+                    <button id="save"
+                            type="submit" 
+                            onclick="monaco_to_content(); save_stop_exit();">''' + load_lang('save') + '''</button>
+                    <button id="preview" 
+                            type="button" 
+                            onclick="monaco_to_content(); load_preview(\'''' + url_pas(name) + '\');">' + load_lang('preview') + '''</button>
                 </form>
                 ''' + b_text + '''
                 <hr class="main_hr">
                 <div id="see_preview"></div>
             ''',
-            menu = [['w/' + url_pas(name), load_lang('return')]] + menu_plus
+            menu = [
+                ['w/' + url_pas(name), load_lang('return')],
+                ['delete/' + url_pas(name), load_lang('delete')], 
+                ['move/' + url_pas(name), load_lang('move')], 
+                ['upload', load_lang('upload')]
+            ]
         ))

+ 3 - 3
route/edit_delete.py

@@ -50,9 +50,9 @@ def edit_delete_2(conn, name, app_var):
             )
             if os.path.exists(file_directory):
                 os.remove(file_directory)
-
-        curs.execute(db_change('select data from other where name = "count_all_title"'))
-        curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])
+        else:
+            curs.execute(db_change('select data from other where name = "count_all_title"'))
+            curs.execute(db_change("update other set data = ? where name = 'count_all_title'"), [str(int(curs.fetchall()[0][0]) - 1)])
 
         return redirect('/w/' + url_pas(name))
     else:

+ 1 - 1
route/edit_many_delete.py

@@ -13,7 +13,7 @@ def edit_many_delete_2(conn, app_var):
         for name in all_title:
             edit_delete.edit_delete_2(conn, name, app_var)
 
-            return redirect('/recent_changes')
+        return redirect('/recent_changes')
     else:
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('many_delete'), wiki_set(), custom(), other2([0, 0])],

+ 2 - 5
route/func_title_random.py

@@ -5,11 +5,8 @@ def func_title_random_2(conn):
 
     curs.execute(db_change("" + \
         "select title from data " + \
-        "where title not like 'user:%' and title not like 'category:%' and title not like 'file:%'" + \
+        "where title not like 'user:%' and title not like 'category:%' and title not like 'file:%' " + \
         "order by random() limit 1" + \
     ""))
     data = curs.fetchall()
-    if data:
-        return redirect('/w/' + url_pas(data[0][0]))
-    else:
-        return redirect()
+    return redirect('/w/' + url_pas(data[0][0])) if data else redirect()

+ 1 - 1
route/give_acl.py

@@ -127,7 +127,7 @@ def give_acl_2(conn, name):
                 </select>
                 <hr class="main_hr">
                 <h2 id="exp">''' + load_lang('explanation') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li>normal : ''' + load_lang('unset') + '''</li>
                     <li>admin : ''' + load_lang('admin_acl') + '''</li>
                     <li>user : ''' + load_lang('member_acl') + '''</li>

+ 22 - 51
route/give_admin_groups.py

@@ -3,79 +3,50 @@ from .tool.func import *
 def give_admin_groups_2(conn, name):
     curs = conn.cursor()
 
+    acl_name_list = ['ban', 'nothing', 'toron', 'check', 'acl', 'hidel', 'give', 'owner']
+    
     if flask.request.method == 'POST':
         if admin_check(None, 'admin_plus (' + name + ')') != 1:
             return re_error('/error/3')
 
         curs.execute(db_change("delete from alist where name = ?"), [name])
-
-        if flask.request.form.get('ban', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'ban')"), [name])
-
-        if flask.request.form.get('toron', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'toron')"), [name])
-
-        if flask.request.form.get('check', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'check')"), [name])
-
-        if flask.request.form.get('acl', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'acl')"), [name])
-
-        if flask.request.form.get('hidel', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'hidel')"), [name])
-
-        if flask.request.form.get('give', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'give')"), [name])
-
-        if flask.request.form.get('owner', 0) != 0:
-            curs.execute(db_change("insert into alist (name, acl) values (?, 'owner')"), [name])
+        for i in acl_name_list:
+            if flask.request.form.get(i, 0) != 0:
+                curs.execute(db_change("insert into alist (name, acl) values (?, ?)"), [name, i])
 
         conn.commit()
 
         return redirect('/admin_plus/' + url_pas(name))
     else:
-        data = '<ul>'
-
+        data = ''
         exist_list = ['', '', '', '', '', '', '', '']
+        state = 'disabled' if admin_check() != 1 else ''
 
         curs.execute(db_change('select acl from alist where name = ?'), [name])
         acl_list = curs.fetchall()
         for go in acl_list:
-            if go[0] == 'ban':
-                exist_list[0] = 'checked="checked"'
-            elif go[0] == 'toron':
-                exist_list[2] = 'checked="checked"'
-            elif go[0] == 'check':
-                exist_list[3] = 'checked="checked"'
-            elif go[0] == 'acl':
-                exist_list[4] = 'checked="checked"'
-            elif go[0] == 'hidel':
-                exist_list[5] = 'checked="checked"'
-            elif go[0] == 'give':
-                exist_list[6] = 'checked="checked"'
-            elif go[0] == 'owner':
-                exist_list[7] = 'checked="checked"'
-
-        if admin_check() != 1:
-            state = 'disabled'
-        else:
-            state = ''
-
-        acl_name_list = ['ban', 'nothing', 'toron', 'check', 'acl', 'hidel', 'give', 'owner']
+            exist_list[acl_name_list.index(go[0])] = 'checked="checked"'
+            
         for i in range(0, 8):
             if i != 1:
-                data += '<li><input type="checkbox" ''' + state +  ' name="' + acl_name_list[i] + '" ' + exist_list[i] + '> ' + acl_name_list[i] + '</li>'
+                data += '' + \
+                    '<input type="checkbox" ' + \
+                            state + ' ' + \
+                            'name="' + acl_name_list[i] + '" ' + \
+                            exist_list[i] + '> ' + acl_name_list[i] + \
+                    '<hr class="main_hr">' + \
+                ''
 
-        data += '</ul>'
+        data += ''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('admin_group') + ')', 0])],
-            data =  '''
+            data = '''
                 <form method="post">
                     ''' + data + '''
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <h2>''' + load_lang('explanation') + '''</h2>
-                    <ul>
+                    <ul class="inside_ul">
                         <li>ban : ''' + load_lang('ban_authority') + '''</li>
                         <li>toron : ''' + load_lang('discussion_authority') + '''</li>
                         <li>check : ''' + load_lang('user_check_authority') + '''</li>
@@ -84,9 +55,9 @@ def give_admin_groups_2(conn, name):
                         <li>give : ''' + load_lang('authorization_authority') + '''</li>
                         <li>owner : ''' + load_lang('owner_authority') + '''</li>
                     </ul>
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button ''' + state +  ''' type="submit">''' + load_lang('save') + '''</button>
                 </form>
             ''',
             menu = [['give_log', load_lang('return')]]
-        ))     
+        ))

+ 14 - 10
route/give_delete_admin_group.py

@@ -8,16 +8,20 @@ def delete_admin_group_2(conn, name):
     
     if flask.request.method == 'POST':
         admin_check(None, 'alist del ' + name)
+
         curs.execute(db_change("delete from alist where name = ?"), [name])
+        curs.execute(db_change("update user set acl = 'user' where acl = ?"), [name])
+
+        conn.commit()
 
         return redirect('/give_log')
-    
-    return easy_minify(flask.render_template(skin_check(),
-        imp = [load_lang("delete_admin_group"), wiki_set(), custom(), other2(['(' + name + ')', 0])],
-        data = '''
-            <form method=post>
-                <button type=submit>''' + load_lang('start') + '''</button>
-            </form>
-        ''',
-        menu = [['give_log', load_lang('return')]]
-    ))  
+    else:
+        return easy_minify(flask.render_template(skin_check(),
+            imp = [load_lang("delete_admin_group"), wiki_set(), custom(), other2(['(' + name + ')', 0])],
+            data = '''
+                <form method=post>
+                    <button type=submit>''' + load_lang('start') + '''</button>
+                </form>
+            ''',
+            menu = [['give_log', load_lang('return')]]
+        ))  

+ 15 - 20
route/give_user_ban.py

@@ -4,19 +4,13 @@ def give_user_ban_2(conn, name):
     curs = conn.cursor()
 
     band = flask.request.args.get('type', '')
-    if band == '':
-        if name and ip_or_user(name) == 0:
-            curs.execute(db_change("select acl from user where id = ?"), [name])
-            user = curs.fetchall()
-            if not user:
-                return re_error('/error/2')
-
-            if user and user[0][0] != 'user':
-                if admin_check() != 1:
-                    return re_error('/error/4')
-
-    if ban_check(ip = ip_check(), tool = 'login') == 1:
-        return re_error('/ban')
+    ip = ip_check()
+    if ban_check(ip = ip, tool = 'login') == 1:
+    	if ip_or_user(ip) == 1 or admin_check('all', None, ip) == 0:
+            return re_error('/ban')
+    else:
+    	if admin_check(1, None, ip) !=1:
+    	    return re_error('/error/3')
 
     if flask.request.method == 'POST':
         end = flask.request.form.get('second', '0')
@@ -40,8 +34,12 @@ def give_user_ban_2(conn, name):
             if admin_check(None, 'ban' + (' ' + type_d if type_d else '') + ' (' + name + ')') != 1:
                 return re_error('/error/3')
         else:
-            if admin_check(1, 'ban (' + name + ')') != 1:
-                return re_error('/error/3')
+            if name == ip:
+                if admin_check('all', 'ban (' + name + ')') != 1:
+                    return re_error('/error/3')
+            else:
+            	if admin_check(1, 'ban (' + name + ')') != 1:
+                    return re_error('/error/3')
 
         ban_insert(
             name,
@@ -54,9 +52,6 @@ def give_user_ban_2(conn, name):
 
         return redirect('/block_log')
     else:
-        if admin_check(1) != 1:
-            return re_error('/error/3')
-
         curs.execute(db_change("select end, why from rb where block = ? and ongoing = '1' and band = ?"), [name, band])
         end = curs.fetchall()
         if end:
@@ -66,9 +61,9 @@ def give_user_ban_2(conn, name):
             action = 'action="/ban/' + url_pas(name) + ('?type=' + band if band != '' else '') + '"'
 
             if end[0][0] == '':
-                data = '<ul><li>' + load_lang('limitless') + '</li>'
+                data = '<ul class="inside_ul"><li>' + load_lang('limitless') + '</li>'
             else:
-                data = '<ul><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
+                data = '<ul class="inside_ul"><li>' + load_lang('period') + ' : ' + end[0][0] + '</li>'
 
             curs.execute(db_change("select block from rb where block = ? and login = 'O' and ongoing = '1'"), [name])
             if curs.fetchall():

+ 1 - 1
route/give_user_check.py

@@ -157,7 +157,7 @@ def give_user_check_2(conn, name):
             div += '<li><a href="/check/' + url_pas(i[0]) + '?type=simple">' + i[0] + '</a></li>'
 
         if div != '':
-            div = '<ul>' + div + '</ul>'
+            div = '<ul class="inside_ul">' + div + '</ul>'
             div += next_fix(
                 '/check/' + url_pas(name) + '?type=' + check_type + '&num=', 
                 num, 

+ 1 - 1
route/inter_wiki.py

@@ -72,7 +72,7 @@ def inter_wiki_2(conn, tools):
 
     db_data = curs.fetchall()
     if db_data:
-        div += '<ul>'
+        div += '<ul class="inside_ul">'
 
         for data in db_data:
             if tools == 'inter_wiki':

+ 1 - 1
route/list_acl.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_acl_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select title, why from acl where decu != '' or dis != '' or view != '' order by title desc"))
     list_data = curs.fetchall()

+ 1 - 1
route/list_admin.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_admin_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select id, acl, date from user where not acl = 'user' order by date desc"))
     for data in curs.fetchall():

+ 1 - 1
route/list_admin_use.py

@@ -12,7 +12,7 @@ def list_admin_use_2(conn):
     if flask.request.method == 'POST':
         return redirect('/admin_log?search=' + flask.request.form.get('search', 'normal'))
     else:
-        list_data = '<ul>'
+        list_data = '<ul class="inside_ul">'
 
         if flask.request.args.get('search', 'normal') == 'normal':
             curs.execute(db_change("select who, what, time from re_admin order by time desc limit ?, 50"), [sql_num])

+ 1 - 1
route/list_give.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_give_2(conn):
     curs = conn.cursor()
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
     back = ''
 
     curs.execute(db_change("select distinct name from alist order by name asc"))

+ 1 - 1
route/list_image_file.py

@@ -9,7 +9,7 @@ def list_image_file_2(conn):
     else:
         sql_num = 0
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
     back = ''
 
     curs.execute(db_change("select title from data where title like 'file:%' limit ?, 50"), [sql_num])

+ 24 - 0
route/list_long_page.py

@@ -0,0 +1,24 @@
+from .tool.func import *
+
+def list_long_page_2(conn, tool):
+    curs = conn.cursor()
+
+    curs.execute(db_change('select data from other where name = "count_all_title"'))
+    if int(curs.fetchall()[0][0]) > 30000:
+        return re_error('/error/25')
+
+    div = '<ul class="inside_ul">'
+    select_data = 'desc' if tool == 'long_page' else 'asc'
+    title = 'long_page' if tool == 'long_page' else 'short_page'
+
+    curs.execute(db_change("select title, length(data) from data order by length(data) " + select_data + " limit 50"))
+    for data in curs.fetchall():
+        div += '<li>' + str(data[1]) + ' : <a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
+
+    div += '</ul>'
+
+    return easy_minify(flask.render_template(skin_check(),
+        imp = [load_lang(title), wiki_set(), custom(), other2([0, 0])],
+        data = div,
+        menu = [['other', load_lang('return')]]
+    ))

+ 1 - 1
route/list_not_close_topic.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def list_not_close_topic_2(conn):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change('select title, sub, date, code from rd where stop != "O" order by date desc'))
     n_list = curs.fetchall()

+ 1 - 1
route/list_old_page.py

@@ -13,7 +13,7 @@ def list_old_page_2(conn):
     if int(curs.fetchall()[0][0]) > 30000:
         return re_error('/error/25')
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change('' + \
         'select title, date from history h ' + \

+ 2 - 5
route/list_please.py

@@ -4,16 +4,13 @@ def list_please_2(conn):
     curs = conn.cursor()
 
     num = int(number_check(flask.request.args.get('num', '1')))
-    if num * 50 > 0:
-        sql_num = num * 50 - 50
-    else:
-        sql_num = 0
+    sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
     curs.execute(db_change('select data from other where name = "count_all_title"'))
     if int(curs.fetchall()[0][0]) > 30000:
         return re_error('/error/25')
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select distinct title from back where type = 'no' order by title asc limit ?, 50"), [sql_num])
     data_list = curs.fetchall()

+ 10 - 12
route/list_title_index.py

@@ -5,10 +5,7 @@ def list_title_index_2(conn):
 
     page = int(number_check(flask.request.args.get('page', '1')))
     num = int(number_check(flask.request.args.get('num', '100')))
-    if page * num > 0:
-        sql_num = page * num - num
-    else:
-        sql_num = 0
+    sql_num = (page * num - num) if page * num > 0 else 0
 
     all_list = sql_num + 1
 
@@ -20,7 +17,7 @@ def list_title_index_2(conn):
     curs.execute(db_change("select title from data order by title asc limit ?, ?"), [sql_num, num])
     title_list = curs.fetchall()
     if title_list:
-        data += '<hr class=\"main_hr\"><ul>'
+        data += '<hr class="main_hr"><ul class="inside_ul">'
 
     for list_data in title_list:
         data += '<li>' + str(all_list) + '. <a href="/w/' + url_pas(list_data[0]) + '">' + list_data[0] + '</a></li>'
@@ -30,7 +27,8 @@ def list_title_index_2(conn):
         count_end = []
 
         curs.execute(db_change('select data from other where name = "count_all_title"'))
-        if int(curs.fetchall()[0][0]) < 30000:
+        all_title = curs.fetchall()
+        if int(all_title[0][0]) < 30000:
             curs.execute(db_change("select count(*) from data"))
             count = curs.fetchall()
             if count:
@@ -51,12 +49,12 @@ def list_title_index_2(conn):
 
             data += '''
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('all') + ' : ' + str(count_end[0]) + '''</li>
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('category') + ' : ' + str(count_end[1]) + '''</li>
                     <li>''' + load_lang('user_document') + ' : ' + str(count_end[2]) + '''</li>
                     <li>''' + load_lang('file') + ' : ' + str(count_end[3]) + '''</li>
@@ -65,8 +63,8 @@ def list_title_index_2(conn):
         else:
             data += '''
                 </ul>
-                <hr class=\"main_hr\">
-                <ul>
+                <hr class="main_hr">
+                <ul class="inside_ul">
                     <li>''' + load_lang('all') + ' : ' + all_title[0][0] + '''</li>
             '''
 

+ 1 - 1
route/list_user.py

@@ -6,7 +6,7 @@ def list_user_2(conn):
     num = int(number_check(flask.request.args.get('num', '1')))
     sql_num = (num * 50 - 50) if num * 50 > 0 else 0
 
-    list_data = '<ul>'
+    list_data = '<ul class="inside_ul">'
 
     curs.execute(db_change("select id, date from user order by date desc limit ?, 50"), [sql_num])
     user_list = curs.fetchall()

+ 2 - 12
route/login.py

@@ -16,7 +16,7 @@ def login_2(conn):
         else:
             captcha_post('', 0)
 
-        agent = flask.request.headers.get('User-Agent')
+        user_agent = flask.request.headers.get('User-Agent', '')
         user_id = flask.request.form.get('id', '')
 
         curs.execute(db_change("select pw, encode from user where id = ?"), [user_id])
@@ -33,26 +33,16 @@ def login_2(conn):
         if pw_check_d != 1:
             return re_error('/error/10')
 
-        curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [user_id])
-        css_data = curs.fetchall()
-
         curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_id])
         fa_data = curs.fetchall()
         if fa_data and fa_data[0][0] != '':
-            flask.session['b_head'] = css_data[0][0] if css_data else ''
             flask.session['b_id'] = user_id
 
             return redirect('/2fa_login')
         else:
-            flask.session['head'] = css_data[0][0] if css_data else ''
             flask.session['id'] = user_id
 
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-                user_id, 
-                ip, 
-                agent, 
-                get_time()
-            ])
+            ua_plus(user_id, ip, user_agent, get_time())
             conn.commit()
 
             return redirect('/user')

+ 2 - 9
route/login_2fa.py

@@ -19,7 +19,7 @@ def login_2fa_2(conn):
         else:
             captcha_post('', 0)
 
-        agent = flask.request.headers.get('User-Agent')
+        user_agent = flask.request.headers.get('User-Agent', '')
         user_id = flask.session['b_id']
 
         curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_id])
@@ -38,19 +38,12 @@ def login_2fa_2(conn):
             if pw_check_d != 1:
                 return re_error('/error/10')
 
-        flask.session['head'] = flask.session['b_head']
         flask.session['id'] = user_id
 
-        curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-            user_id, 
-            ip, 
-            agent, 
-            get_time()
-        ])
+        ua_plus(user_id, ip, user_agent, get_time())
         conn.commit()
 
         flask.session.pop('b_id', None)
-        flask.session.pop('b_head', None)
 
         return redirect('/user')
     else:

+ 3 - 10
route/login_check_key.py

@@ -3,7 +3,6 @@ from .tool.func import *
 def login_check_key_2(conn, tool):
     curs = conn.cursor()
 
-    # 난잡한 코드 정리 필요
     if  flask.request.method == 'POST' or \
         ('c_key' in flask.session and flask.session['c_key'] == 'email_pass'):
         re_set_list = ['c_id', 'c_pw', 'c_ans', 'c_que', 'c_key', 'c_type', 'c_email']
@@ -11,7 +10,6 @@ def login_check_key_2(conn, tool):
         input_key = flask.request.form.get('key', '')
         user_agent = flask.request.headers.get('User-Agent', '')
 
-
         if  'c_type' in flask.session and \
             flask.session['c_type'] == 'pass_find' and \
             flask.session['c_key'] == input_key:
@@ -51,14 +49,14 @@ def login_check_key_2(conn, tool):
 
                 curs.execute(db_change("select id from user where id = ?"), [flask.session['c_id']])
                 if curs.fetchall():
-                    for i in re_set_lire:
+                    for i in re_set_list:
                         flask.session.pop(i, None)
 
                     return re_error('/error/6')
             
                 curs.execute(db_change("select id from user_application where id = ?"), [flask.session['c_id']])
                 if curs.fetchall():
-                    for i in re_set_lire:
+                    for i in re_set_list:
                         flask.session.pop(i, None)
 
                     return re_error('/error/6')
@@ -101,12 +99,7 @@ def login_check_key_2(conn, tool):
                     flask.session['c_id'],
                     flask.session['c_email']
                 ])
-                curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [
-                    flask.session['c_id'],
-                    ip,
-                    user_agent,
-                    get_time()
-                ])
+                ua_plus(flask.session['c_id'], ip, user_agent, get_time())
 
                 flask.session['id'] = flask.session['c_id']
                 flask.session['head'] = ''

+ 11 - 16
route/login_pw_change.py

@@ -11,8 +11,11 @@ def login_pw_change_2(conn):
         return redirect('/login')
 
     if flask.request.method == 'POST':
-        if flask.request.form.get('pw4', None) and flask.request.form.get('pw2', None):
-            if flask.request.form.get('pw2', None) != flask.request.form.get('pw3', None):
+        now_pw = flask.request.form.get('pw4', None)
+        new_pw = flask.request.form.get('pw2', None)
+        re_pw = flask.request.form.get('pw3', None)
+        if now_pw and new_pw and re_pw:
+            if new_pw != re_pw:
                 return re_error('/error/20')
 
             curs.execute(db_change("select pw, encode from user where id = ?"), [flask.session['id']])
@@ -20,31 +23,23 @@ def login_pw_change_2(conn):
             if not user:
                 return re_error('/error/2')
 
-            pw_check_d = pw_check(
-                flask.request.form.get('pw4', ''),
-                user[0][0],
-                user[0][1],
-                ip
-            )
-            if pw_check_d != 1:
+            if pw_check(now_pw, user[0][0], user[0][1], ip) != 1:
                 return re_error('/error/10')
 
-            hashed = pw_encode(flask.request.form.get('pw2', None))
+            curs.execute(db_change("update user set pw = ? where id = ?"), [pw_encode(new_pw), ip])
 
-            curs.execute(db_change("update user set pw = ? where id = ?"), [hashed, ip])
-
-            return redirect('/user')
+        return redirect('/user')
     else:
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('password_change'), wiki_set(), custom(), other2([0, 0])],
             data = '''
                 <form method="post">
                     <input placeholder="''' + load_lang('now_password') + '''" name="pw4" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('new_password') + '''" name="pw2" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password_confirm') + '''" name="pw3" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button type="submit">''' + load_lang('save') + '''</button>
                 </form>
             ''',

+ 5 - 5
route/main_manager.py

@@ -27,7 +27,7 @@ def main_manager_2(conn, num, r_ver):
             imp = [load_lang('admin_tool'), wiki_set(), custom(), other2([0, 0])],
             data = '''
                 <h2>''' + load_lang('admin') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/manager/2">''' + load_lang('acl_change') + '''</a></li>
                     <li><a href="/manager/3">''' + load_lang('check_user') + '''</a></li>
                     <li><a href="/ban">''' + load_lang('ban') + '''</a></li>
@@ -36,7 +36,7 @@ def main_manager_2(conn, num, r_ver):
                 </ul>
                 <br>
                 <h2>''' + load_lang('owner') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/give_log">''' + load_lang('admin_group_list') + '''</a></li>
                     <li><a href="/many_delete">''' + load_lang('many_delete') + '''</a></li>
                     <li><a href="/applications">''' + load_lang('application_list') + '''</a></li>
@@ -45,7 +45,7 @@ def main_manager_2(conn, num, r_ver):
                     <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
                 </ul>
                 <h3>''' + load_lang('filter') + '''</h3>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/edit_filter">''' + load_lang('edit_filter_list') + '''</a></li>
                     <li><a href="/inter_wiki">''' + load_lang('interwiki_list') + '''</a></li>
                     <li><a href="/edit_top">''' + load_lang('edit_tool_list') + '''</a></li>
@@ -57,13 +57,13 @@ def main_manager_2(conn, num, r_ver):
                 </ul>
                 <br>
                 <h2>''' + load_lang('server') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/restart">''' + load_lang('wiki_restart') + '''</a></li>
                     <li><a href="/update">''' + load_lang('update') + '''</a></li>
                 </ul>
                 <br>
                 <h2>''' + load_lang('version') + '''</h2>
-                <ul>
+                <ul class="inside_ul">
                     <li><a href="/api/skin_info?all=true">''' + load_lang('skin_info') + '''</a></li>
                     <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                     <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>

+ 6 - 4
route/main_other.py

@@ -7,13 +7,13 @@ def main_other_2(conn):
         imp = [load_lang('other_tool'), wiki_set(), custom(), other2([0, 0])],
         data = '''
             <h2>''' + load_lang('record') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/manager/6">''' + load_lang('edit_record') + '''</a></li>
                 <li><a href="/manager/7">''' + load_lang('discussion_record') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('list') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/recent_changes">''' + load_lang('recent_change') + '''</a></li>
                 <li><a href="/recent_discuss">''' + load_lang('recent_discussion') + '''</a></li>
                 <li><a href="/admin_list">''' + load_lang('admin_list') + '''</a></li>
@@ -27,16 +27,18 @@ def main_other_2(conn):
                 <li><a href="/old_page">''' + load_lang('old_page') + '''</a></li>
                 <li><a href="/image_file_list">''' + load_lang('image_file_list') + '''</a></li>
                 <li><a href="/vote">''' + load_lang('vote_list') + '''</a></li>
+                <li><a href="/long_page">''' + load_lang('long_page') + '''</a></li>
+                <!-- <li><a href="/short_page">''' + load_lang('short_page') + '''</a></li> -->
             </ul>
             <br>
             <h2>''' + load_lang('other') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/upload">''' + load_lang('upload') + '''</a></li>
                 <li><a href="/manager/10">''' + load_lang('search') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('admin') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/manager/1">''' + load_lang('admin_tool') + '''</a></li>
             </ul>
         ''',

+ 5 - 2
route/main_views.py

@@ -24,11 +24,14 @@ def main_views_2(conn, name):
             if mime_type in image_type:
                 mime_type = 'image/' + mime_type
             else:
-                mime_type = 'text/' + mime_type
+                if mime_type == 'js':
+                    mime_type = 'text/javascript'
+                else:
+                    mime_type = 'text/' + mime_type
         else:
             mime_type = 'text/plain'
 
         return flask.send_from_directory(
             dir_name, file_name, 
             mimetype = mime_type
-        )
+        )

+ 1 - 1
route/recent_history_tool.py

@@ -7,7 +7,7 @@ def recent_history_tool_2(conn, name):
 
     data = '' + \
         '<h2>' + load_lang('tool') + '</h2>' + \
-        '<ul>' + \
+        '<ul class="inside_ul">' + \
             '<li><a href="/raw/' + url_pas(name) + '?num=' + num + '">' + load_lang('raw') + '</a></li>' + \
     ''
 

+ 4 - 4
route/search_deep.py

@@ -12,7 +12,7 @@ def search_deep_2(conn, name):
     else:
         sql_num = 0
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     div_plus = ''
     test = ''
@@ -24,13 +24,13 @@ def search_deep_2(conn, name):
         link_id = 'id="not_thing"'
 
     div = '''
-        <ul>
+        <ul class="inside_ul">
             <li>
                 <a ''' + link_id + ' href="/w/' + url_pas(name) + '">' + html.escape(name) + '''</a>
             </li>
         </ul>
         <hr class=\"main_hr\">
-        <ul>
+        <ul class="inside_ul">
     '''
 
     curs.execute(db_change('select data from other where name = "count_all_title"'))
@@ -48,7 +48,7 @@ def search_deep_2(conn, name):
 
             for data in all_list:
                 if data[1] != test:
-                    div_plus += '</ul><hr class=\"main_hr\"><ul>'
+                    div_plus += '</ul><hr class=\"main_hr\"><ul class="inside_ul">'
 
                     test = data[1]
 

+ 1 - 1
route/server_now_update.py

@@ -46,7 +46,7 @@ def server_now_update_2(conn, r_ver):
             imp = [load_lang('update'), wiki_set(), custom(), other2([0, 0])],
             data = load_lang('update_warring') + '''
                 <hr class=\"main_hr\">
-                <ul>
+                <ul class="inside_ul">
                     <li>''' + load_lang('version') + ' : ' + r_ver + '''</li>
                     <li id="ver_send" style="display: none;">''' + load_lang('lastest') + ''' : </li>
                 </ul>

+ 16 - 13
route/setting.py

@@ -28,7 +28,7 @@ def setting_2(conn, num, db_set):
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('setting'), wiki_set(), custom(), other2([0, 0])],
-            data = '<h2>' + load_lang('list') + '</h2><ul>' + li_data + '</ul>',
+            data = '<h2>' + load_lang('list') + '</h2><ul class="inside_ul">' + li_data + '</ul>',
             menu = [['manager', load_lang('return')]]
         ))
     elif num == 1:
@@ -50,7 +50,8 @@ def setting_2(conn, num, db_set):
             19 : 'slow_edit',
             20 : 'requires_approval',
             21 : 'backup_where',
-            22 : 'domain'
+            22 : 'domain',
+            23 : 'ua_get'
         }
         n_list = {
             0 : 'Wiki',
@@ -70,7 +71,8 @@ def setting_2(conn, num, db_set):
             19 : '0',
             20 : '',
             21 : '',
-            22 : flask.request.host_url
+            22 : flask.request.host_url,
+            23 : ''
         }
 
         if flask.request.method == 'POST':
@@ -108,16 +110,18 @@ def setting_2(conn, num, db_set):
                 else:
                     acl_div[0] += '<option value="' + acl_data + '">' + acl_data + '</option>'
 
-            check_box_div = ['', '', '', '']
-            for i in range(0, 4):
+            check_box_div = ['', '', '', '', '']
+            for i in range(0, len(check_box_div)):
                 if i == 0:
                     acl_num = 7
                 elif i == 1:
                     acl_num = 8
                 elif i == 2:
                     acl_num = 13
-                else:
+                elif i == 3:
                     acl_num = 20
+                else:
+                    acl_num = 23
 
                 if d_list[acl_num]:
                     check_box_div[i] = 'checked="checked"'
@@ -130,10 +134,7 @@ def setting_2(conn, num, db_set):
                 else:
                     branch_div += '<option value="' + i + '">' + i + '</option>'
 
-            if db_set != 'sqlite':
-                sqlite_only = 'style="display:none;"'
-            else:
-                sqlite_only = ''
+            sqlite_only = 'style="display:none;"' if db_set != 'sqlite' else ''
 
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('main_setting'), wiki_set(), custom(), other2([0, 0])],
@@ -179,6 +180,8 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <input type="checkbox" name="requires_approval" ''' + check_box_div[3] + '''> ''' + load_lang('requires_approval') + '''
                         <hr class="main_hr">
+                        <input type="checkbox" name="ua_get" ''' + check_box_div[4] + '''> ''' + load_lang('ua_get_off') + '''
+                        <hr class="main_hr">
                         <span>''' + load_lang('wiki_host') + '''</span>
                         <hr class="main_hr">
                         <input name="host" value="''' + html.escape(d_list[16]) + '''">
@@ -310,7 +313,7 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[11] + '''">''' + html.escape(d_list[11]) + '''</textarea>
                         <hr class="main_hr">
-                        <span>''' + load_lang('approval_question') + '''</span><sup><a href="#rfn-1" id="fn-1">(1)</a></sup>
+                        <span>''' + load_lang('approval_question') + '''</span><sup><a href="#note_1_end" id="note_1">(1)</a></sup>
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[12] + '''">''' + html.escape(d_list[12]) + '''</textarea>
                         <hr class="main_hr">
@@ -328,8 +331,8 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                         <hr class="main_hr">
-                        <ul>
-                            <li><a href="#fn-1" id="rfn-1">(1)</a> <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''</span></li>
+                        <ul id="footnote_data">
+                            <li><a href="#note_1" id="note_1_end">(1)</a> <span>''' + load_lang('approval_question_visible_only_when_approval_on') + '''</span></li>
                         </ul>
                     </form>
                 ''',

+ 67 - 50
route/tool/func.py

@@ -191,6 +191,8 @@ def render_set(title = '', data = '', num = 0, s_data = 0, include = None, acl =
         return data
     else:
         if data != None:
+            darkmode = flask.request.cookies.get('main_css_darkmode', '0')
+            
             return render_do(title, data, num, include)
         else:
             return 'HTTP Request 404'
@@ -333,7 +335,7 @@ def set_init():
         for i in [['smtp_server', 'smtp.gmail.com'], ['smtp_port', '587'], ['smtp_security', 'starttls']]:
             curs.execute(db_change("insert into other (name, data) values (?, ?)"), [i[0], i[1]])
 
-def pw_encode(data, data2 = '', type_d = ''):
+def pw_encode(data, type_d = ''):
     if type_d == '':
         curs.execute(db_change('select data from other where name = "encode"'))
         set_data = curs.fetchall()
@@ -360,16 +362,15 @@ def pw_check(data, data2, type_d = 'no', id_d = ''):
     else:
         set_data = db_data[0][0]
 
-    if pw_encode(data = data, type_d = set_data) == data2:
-        re_data = 1
-    else:
-        re_data = 0
-
+    re_data = 1 if pw_encode(data, set_data) == data2 else 0
     if db_data[0][0] != set_data and re_data == 1 and id_d != '':
         curs.execute(db_change("update user set pw = ?, encode = ? where id = ?"), [pw_encode(data), db_data[0][0], id_d])
 
     return re_data
 
+def add_alarm(who, context):
+    curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [who, context, get_time()])
+
 def captcha_get():
     data = ''
 
@@ -426,32 +427,33 @@ def captcha_post(re_data, num = 1):
     else:
         pass
 
+def ua_plus(id, ip, ua, time):
+    curs.execute(db_change("select data from other where name = 'ua_get'"))
+    rep_data = curs.fetchall()
+    if rep_data and rep_data[0][0] != '':
+        pass
+    else:
+        curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [id, ip, ua, time])
+
 def load_lang(data, num = 2, safe = 0):
     global global_lang
 
-    if num == 1:
-        curs.execute(db_change("select data from other where name = 'language'"))
-        rep_data = curs.fetchall()
-        if rep_data:
-            try:
-                if not rep_data[0][0] in global_lang:
-                    lang = json.loads(open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read())
-                    global_lang[rep_data[0][0]] = lang
-                else:
-                    lang = global_lang[rep_data[0][0]]
-            except:
-                return html.escape(data + ' (' + rep_data[0][0] + ')')
-
-            if data in lang:
-                return lang[data] if safe == 1 else html.escape(lang[data])
+    for i in range(0, 2):
+        if i == 0:
+            ip = ip_check()
+            if ip_or_user(ip) == 0:
+                curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip])
+                rep_data = curs.fetchall()
             else:
-                return html.escape(data + ' (' + rep_data[0][0] + ')')
+                if 'lang' in flask.session:
+                    rep_data = [[flask.session['lang']]]
+                else:
+                    continue
         else:
-            return html.escape(data + ' (' + rep_data[0][0] + ')')
-    else:
-        curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip_check()])
-        rep_data = curs.fetchall()
-        if rep_data and rep_data != '' and rep_data != 'default':
+            curs.execute(db_change("select data from other where name = 'language'"))
+            rep_data = curs.fetchall()
+        
+        if rep_data and rep_data[0][0] != '' and rep_data[0][0] != 'default':
             try:
                 if not rep_data[0][0] in global_lang:
                     lang = json.loads(open(os.path.join('language', rep_data[0][0] + '.json'), encoding='utf8').read())
@@ -459,14 +461,16 @@ def load_lang(data, num = 2, safe = 0):
                 else:
                     lang = global_lang[rep_data[0][0]]
             except:
-                return load_lang(data, 1, safe)
+                continue
 
             if data in lang:
                 return lang[data] if safe == 1 else html.escape(lang[data])
             else:
-                return load_lang(data, 1, safe)
+                continue
         else:
-            return load_lang(data, 1, safe)
+            continue
+    
+    return html.escape(data + ' (' + rep_data[0][0] + ')')
 
 def ip_or_user(data = ''):
     if data == '':
@@ -515,18 +519,27 @@ def ip_warring():
 
 def skin_check(set_n = 0):
     skin_list = load_skin('marisa', 1)
-
-    curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip_check()])
-    skin_exist = curs.fetchall()
-    if skin_exist and skin_exist[0][0] != '' and skin_exist[0][0] in skin_list:
-        skin = skin_exist[0][0]
-    else:
-        curs.execute(db_change('select data from other where name = "skin"'))
+    skin = skin_list[0]
+    check_list = []
+    ip = ip_check()
+    
+    if ip_or_user(ip) == 0:
+        curs.execute(db_change('select data from user_set where name = "skin" and id = ?'), [ip])
         skin_exist = curs.fetchall()
-        if skin_exist and skin_exist[0][0] != '' and skin_exist[0][0] in skin_list:
-            skin = skin_exist[0][0]
-        else:
-            skin = skin_list[0]
+        check_list += skin_exist
+    else:
+        if 'skin' in flask.session:
+            check_list += [[flask.session['skin']]]
+            
+    curs.execute(db_change('select data from other where name = "skin"'))
+    skin_exist = curs.fetchall()
+    check_list += skin_exist
+    
+    for i in check_list:
+        if i[0] != '' and i[0] in skin_list:
+            skin = i[0]
+            
+            break
 
     return './views/' + skin + '/index.html' if set_n == 0 else skin
 
@@ -554,7 +567,7 @@ def next_fix(link, num, page, end = 50):
 
 def other2(data):
     global req_list
-    main_css_ver = '56'
+    main_css_ver = '59'
     data += ['' for _ in range(0, 3 - len(data))]
 
     if req_list == '':
@@ -577,8 +590,7 @@ def other2(data):
                 integrity="sha384-g7c+Jr9ZivxKLnZTDUhnkOnsh30B4H0rpLUpJ4jAIKs4fnJI+sEnkvrMWph2EDg4"
                 crossorigin="anonymous"></script>
         <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/highlight.min.js"></script>
-        <script>window.addEventListener('DOMContentLoaded', function() { main_css_skin_load(); });</script>
-    ''' + req_list] + data[2:]
+    ''' + req_list + '<script>window.addEventListener(\'DOMContentLoaded\', main_css_skin_load);</script>'] + data[2:]
 
     return data
 
@@ -641,6 +653,8 @@ def wiki_set(num = 1):
         curs.execute(db_change('select data from other where name = "upload"'))
         db_data = curs.fetchall()
         data_list = db_data[0][0] if db_data and db_data[0][0] != '' else '2'
+    else:
+        data_list = ''
 
     return data_list
 
@@ -734,13 +748,15 @@ def ip_pas(raw_ip, type_d = 0):
     return ip if return_ip == 1 else end_ip
 
 def custom():
-    user_head = flask.session['head'] if 'head' in flask.session else ''
-
     ip = ip_check()
     if ip_or_user(ip) == 0:
         user_icon = 1
         user_name = ip
 
+        curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
+        user_head = curs.fetchall()
+        user_head = user_head[0][0] if user_head else ''
+        
         curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
         email = curs.fetchall()
         email = email[0][0] if email else ''
@@ -770,6 +786,7 @@ def custom():
         user_admin = '0'
         user_acl_list = '0'
         user_notice = '0'
+        user_head = flask.session['head'] if 'head' in flask.session else ''
 
     curs.execute(db_change("select title from rd where title = ? and stop = ''"), ['user:' + ip])
     user_topic = '1' if curs.fetchall() else '0'
@@ -1200,7 +1217,7 @@ def edit_filter_do(data):
     return 0
 
 def redirect(data = '/'):
-    return flask.redirect(data)
+    return '<script>window.location.href = "' + data.replace('"', '\\"') + '";</script>'
 
 def get_acl_list(type_d = 'normal'):
     if type_d == 'user':
@@ -1215,7 +1232,7 @@ def re_error(data):
         if ban_check() == 1:
             end = '<div id="get_user_info"></div><script>load_user_info("' + ip_check() + '");</script>'
         else:
-            end = '<ul><li>' + load_lang('authority_error') + '</li></ul>'
+            end = '<ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('error'), wiki_set(1), custom(), other2([0, 0])],
@@ -1304,7 +1321,7 @@ def re_error(data):
                 data = '' + \
                     '<div id="main_skin_set">' + \
                         '<h2>' + load_lang('error') + '</h2>' + \
-                        '<ul>' + \
+                        '<ul class="inside_ul">' + \
                             '<li>' + data + ' <a href="/main_skin_set">(' + load_lang('main_skin_set') + ')</a></li>' + \
                         '</ul>' + \
                     '</div>' + \
@@ -1314,6 +1331,6 @@ def re_error(data):
         else:
             return easy_minify(flask.render_template(skin_check(),
                 imp = [load_lang('error'), wiki_set(1), custom(), other2([0, 0])],
-                data = '<h2>' + load_lang('error') + '</h2><ul><li>' + data + '</li></ul>',
+                data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + data + '</li></ul>',
                 menu = 0
             )), 400

+ 1 - 1
route/tool/init.py

@@ -29,7 +29,7 @@ server_set_var = {
         'display' : 'Markup',
         'require' : 'select',
         'default' : 'namumark',
-        'list' : ['namumark', 'markdown', 'custom', 'raw']
+        'list' : ['namumark', 'markdown', 'custom', 'js_onmark', 'raw']
     },
     'encode' : {
         'display' : 'Encryption method',

+ 7 - 0
route/tool/mark.py

@@ -56,6 +56,13 @@ def render_do(title, data, num, include):
         data = markdown(conn, data, title, include)
     elif rep_data[0][0] == 'custom':
         data = custom_mark(conn, data, title, include)
+    elif rep_data[0][0] == 'js_onmark':
+        include = (include + '_') if include else ''
+        data = [
+            '<div id="' + include + 'render_contect">' + html.escape(data) + '</div>', 
+            'do_onmark_render("' + include + 'render_contect");',
+            []
+        ]
     elif rep_data[0][0] == 'raw':
         data = [data, '', []]
     else:

+ 13 - 15
route/tool/set_mark/namumark.py

@@ -401,17 +401,16 @@ def middle_parser(data):
                         ''
                         data = re.sub(
                             r'{{{#!folding ?((?:(?!\n).)*)\n?', '' + \
-                            '<div>' + \
-                                '<div style="display: inline-block;">' + \
-                                    '<b>' + \
-                                        '<a href="javascript:void(0);" ' + \
-                                            'onclick="do_open_folding(\'' + include_name + 'folding_' + str(folding_num) + '\');" ' + \
-                                            'id="get_' + include_name + 'folding_' + str(folding_num) + '">' + \
-                                        '</a>' + \
-                                    '</b>' + \
-                                '</div_2>' + \
-                                '<div id="' + include_name + 'folding_' + str(folding_num) + '" style="display: none;">' + \
-                                    '<div_1 style="">\n',
+                            '<div style="display: inline-block;">' + \
+                                '<b>' + \
+                                    '<a href="javascript:void(0);" ' + \
+                                        'onclick="do_open_folding(\'' + include_name + 'folding_' + str(folding_num) + '\');" ' + \
+                                        'id="get_' + include_name + 'folding_' + str(folding_num) + '">' + \
+                                    '</a>' + \
+                                '</b>' + \
+                            '</div_2>' + \
+                            '<div id="' + include_name + 'folding_' + str(folding_num) + '" style="display: none;">' + \
+                                '<div_1 style="">\n',
                             data,
                             1
                         )
@@ -449,7 +448,7 @@ def middle_parser(data):
                         middle_num -= 1
 
                     if middle_list[middle_num] == 'div_dd':
-                        data = middle_re.sub('</div_1></div_2></div_2>', data, 1)
+                        data = middle_re.sub('</div_1></div_2>', data, 1)
                     elif middle_list[middle_num] == 'pre':
                         data = middle_re.sub('</code></pre>', data, 1)
                     else:
@@ -470,8 +469,8 @@ def middle_parser(data):
                 if middle_num > 0:
                     middle_num -= 1
 
-                if middle_list[middle_num] == '2div':
-                    data += '</div_1></div_2></div_2>'
+                if middle_list[middle_num] == 'div_dd':
+                    data += '</div_1></div_2>'
                 elif middle_list[middle_num] == 'pre':
                     data += '</code></pre>'
                 else:
@@ -1042,7 +1041,6 @@ def namumark(conn, data, title, include_num):
                     main_link = category_re.sub('category:', main_link)
                     link_id = ''
 
-                    curs.execute(tool.db_change("select title from data where title = ?"), [main_link])
                     if re.search(r'#blur', main_link):
                         link_id = ' hidden_link'
                         main_link = main_link.replace('#blur', '')

+ 3 - 1
route/tool/set_mark/tool.py

@@ -4,6 +4,8 @@ import hashlib
 import flask
 import re
 
+set_data = ''
+
 def get_time():
     return str(datetime.datetime.today().strftime("%Y-%m-%d %H:%M:%S"))
 
@@ -44,4 +46,4 @@ def sha224_replace(data):
     return hashlib.sha224(bytes(data, 'utf-8')).hexdigest()
 
 def md5_replace(data):
-    return hashlib.md5(data.encode()).hexdigest()
+    return hashlib.md5(data.encode()).hexdigest()

+ 28 - 55
route/topic.py

@@ -2,8 +2,6 @@ from .tool.func import *
 
 def topic_2(conn, topic_num):
     curs = conn.cursor()
-
-    admin = admin_check(3)
     topic_num = str(topic_num)
 
     if flask.request.method == 'POST':
@@ -37,38 +35,30 @@ def topic_2(conn, topic_num):
 
         curs.execute(db_change("select id from topic where code = ? order by id + 0 desc limit 1"), [topic_num])
         old_num = curs.fetchall()
-        if old_num:
-            num = int(old_num[0][0]) + 1
-        else:
-            num = 1
-
-        num = str(num)
+        num = str((int(old_num[0][0]) + 1) if old_num else 1)
 
         match = re.search(r'^user:([^/]+)', name)
         if match:
+            match = match.group(1)
             y_check = 0
-            if ip_or_user(match.group(1)) == 1:
-                curs.execute(db_change("select ip from history where ip = ? limit 1"), [match.group(1)])
+            if ip_or_user(match) == 1:
+                curs.execute(db_change("select ip from history where ip = ? limit 1"), [match])
                 u_data = curs.fetchall()
                 if u_data:
                     y_check = 1
                 else:
-                    curs.execute(db_change("select ip from topic where ip = ? limit 1"), [match.group(1)])
+                    curs.execute(db_change("select ip from topic where ip = ? limit 1"), [match])
                     u_data = curs.fetchall()
                     if u_data:
                         y_check = 1
             else:
-                curs.execute(db_change("select id from user where id = ?"), [match.group(1)])
+                curs.execute(db_change("select id from user where id = ?"), [match])
                 u_data = curs.fetchall()
                 if u_data:
                     y_check = 1
 
             if y_check == 1:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    match.group(1),
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(match, ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         cate_re = re.compile(r'\[\[((?:분류|category):(?:(?:(?!\]\]).)*))\]\]', re.I)
         data = cate_re.sub('[br]', flask.request.form.get('content', 'Test').replace('\r', ''))
@@ -77,11 +67,7 @@ def topic_2(conn, topic_num):
             curs.execute(db_change("select ip from topic where code = ? and id = ?"), [topic_num, rd_data])
             ip_data = curs.fetchall()
             if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    ip_data[0][0],
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         for rd_data in re.findall(r"(?: |\n|^)@((?:[^ ]+))(?: |\n|$)", data):
             curs.execute(db_change("select ip from history where ip = ? limit 1"), [rd_data])
@@ -91,11 +77,7 @@ def topic_2(conn, topic_num):
                 ip_data = curs.fetchall()
 
             if ip_data and ip_or_user(ip_data[0][0]) == 0:
-                curs.execute(db_change('insert into alarm (name, data, date) values (?, ?, ?)'), [
-                    ip_data[0][0],
-                    ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>',
-                    today
-                ])
+                add_alarm(ip_data[0][0], ip + ' | <a href="/thread/' + topic_num + '#' + num + '">' + name + ' | ' + sub + ' | #' + num + '</a>')
 
         data = re.sub(r"( |\n|^)(#(?:[0-9]+))( |\n|$)", '\g<1><topic_a>\g<2></topic_a>\g<3>', data)
         data = re.sub(r"( |\n|^)(@(?:[^ ]+))( |\n|$)", '\g<1><topic_call>\g<2></topic_call>\g<3>', data)
@@ -112,37 +94,28 @@ def topic_2(conn, topic_num):
 
         return redirect('/thread/' + topic_num + '#' + num)
     else:
-        data = ''
-
-        if ban == 1:
-            display = 'display: none;'
-        else:
-            display = ''
-
-        data += '''
-            <div id="top_topic"></div>
-            <div id="main_topic"></div>
-            <div id="plus_topic"></div>
-            <script>topic_top_load("''' + topic_num + '''");</script>
-            <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
-            <hr class=\"main_hr\">
-            <form style="''' + display + '''" method="post">
-                <textarea id="content" class="topic_content" placeholder="''' + load_lang('content') + '''" name="content"></textarea>
-                <hr class=\"main_hr\">
-                ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
-                <input style="display: none;" name="topic" value="''' + name + '''">
-                <input style="display: none;" name="title" value="''' + sub + '''">
-                <button id="save" type="submit">''' + load_lang('send') + '''</button>
-                <button id="preview" type="button" onclick="load_preview(\'\')">''' + load_lang('preview') + '''</button>
-            </form>
-            <hr class=\"main_hr\">
-            <div id="see_preview"></div>
-        '''
-
+        display = 'display: none;' if ban == 1 else ''
         return easy_minify(flask.render_template(skin_check(),
             imp = [name, wiki_set(), custom(), other2(['(' + load_lang('discussion') + ')', 0])],
             data = '''
                 <h2 id="topic_top_title">''' + html.escape(sub) + '''</h2>
-                ''' + data,
+                <div id="top_topic"></div>
+                <div id="main_topic"></div>
+                <div id="plus_topic"></div>
+                <script>topic_top_load("''' + topic_num + '''");</script>
+                <a href="/thread/''' + topic_num + '/tool">(' + load_lang('topic_tool') + ''')</a>
+                <hr class="main_hr">
+                <form style="''' + display + '''" method="post">
+                    <textarea id="content" class="topic_content" placeholder="''' + load_lang('content') + '''" name="content"></textarea>
+                    <hr class="main_hr">
+                    ''' + captcha_get() + (ip_warring() if display == '' else '') + '''
+                    <input style="display: none;" name="topic" value="''' + name + '''">
+                    <input style="display: none;" name="title" value="''' + sub + '''">
+                    <button id="save" type="submit">''' + load_lang('send') + '''</button>
+                    <button id="preview" type="button" onclick="load_preview(\'\')">''' + load_lang('preview') + '''</button>
+                </form>
+                <hr class="main_hr">
+                <div id="see_preview"></div>
+            ''',
             menu = [['topic/' + url_pas(name), load_lang('list')]]
         ))

+ 3 - 3
route/topic_admin.py

@@ -13,13 +13,13 @@ def topic_admin_2(conn, topic_num, num):
 
     ban = '''
         <h2>''' + load_lang('state') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>''' + load_lang('writer') + ' : ''' + ip_pas(data[0][1]) + '''</li>
             <li>''' + load_lang('time') + ' : ' + data[0][2] + '''</li>
         </ul>
         <br>
         <h2>''' + load_lang('other_tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>
                 <a href="/thread/''' + topic_num + '/raw/' + num + '''">''' + load_lang('raw') + '''</a>
             </li>
@@ -36,7 +36,7 @@ def topic_admin_2(conn, topic_num, num):
         ban += '''
             <br>
             <h2>''' + load_lang('admin_tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li>
                     <a href="/ban/''' + url_pas(data[0][1]) + '''">
                         ''' + (load_lang('release') if user_ban_d else load_lang('ban')) + '''

+ 3 - 3
route/topic_tool.py

@@ -24,14 +24,14 @@ def topic_tool_2(conn, topic_num):
     if admin_check(3) == 1:
         data = '''
             <h2>''' + load_lang('admin_tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/thread/''' + topic_num + '/setting">' + load_lang('topic_setting') + '''</a></li>
                 <li><a href="/thread/''' + topic_num + '/acl">' + load_lang('topic_acl_setting') + '''</a></li>
             </ul>
         '''
     data += '''
         <h2>''' + load_lang('tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li>''' + load_lang('topic_state') + ''' : ''' + t_state + '' + (' (Agree)' if close_data and (close_data[0][1] == 'O') else '') + '''</li>
             <li>''' + load_lang('topic_acl') + ''' : <a href="/acl/TEST#exp">''' + ('Normal' if not topic_acl_get or (topic_acl_get[0][0] == '') else topic_acl_get[0][0]) + '''</a></li>
         </ul>
@@ -40,7 +40,7 @@ def topic_tool_2(conn, topic_num):
     if admin_check(None) == 1:
         data += '''
             <h2>''' + load_lang('owner') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li>
                     <a href="/thread/''' + topic_num + '''/delete">
                         ''' + load_lang('topic_delete') + '''

+ 1 - 1
route/user_count_edit.py

@@ -25,7 +25,7 @@ def user_count_edit_2(conn, name):
     return easy_minify(flask.render_template(skin_check(),
         imp = [load_lang('count'), wiki_set(), custom(), other2([0, 0])],
         data = '''
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/record/''' + url_pas(that) + '''">''' + load_lang('edit_record') + '''</a> : ''' + str(data) + '''</li>
                 <li><a href="/topic_record/''' + url_pas(that) + '''">''' + load_lang('discussion_record') + '''</a> : ''' + str(t_data) + '''</a></li>
             </ul>

+ 4 - 3
route/user_info.py

@@ -25,6 +25,7 @@ def user_info_2(conn):
         plus = '''
             <li><a href="/login">''' + load_lang('login') + '''</a></li>
             <li><a href="/register">''' + load_lang('register') + '''</a></li>
+            <li><a href="/change">''' + load_lang('user_setting') + '''</a></li>
         '''
         plus3 = ''
 
@@ -41,18 +42,18 @@ def user_info_2(conn):
             <script>load_user_info("''' + ip + '''");</script>
             <br>
             <h2>''' + load_lang('login') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 ''' + plus + '''
             </ul>
             <br>
             <h2>''' + load_lang('tool') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 ''' + plus3 + '''
                 <li><a href="/custom_head">''' + load_lang('user_head') + '''</a></li>
             </ul>
             <br>
             <h2>''' + load_lang('other') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
             ''' + plus2 + '''
             <li>
                 <a href="/count">''' + load_lang('count') + '''</a>

+ 49 - 7
route/user_setting.py

@@ -42,18 +42,14 @@ def user_setting_2(conn, server_init):
         else:
             curs.execute(db_change('select data from user_set where name = "email" and id = ?'), [ip])
             data = curs.fetchall()
-            if data:
-                email = data[0][0]
-            else:
-                email = '-'
+            email = data[0][0] if data else '-'
 
             div2 = load_skin('', 0, 1)
             div3 = ''
 
             curs.execute(db_change('select data from user_set where name = "lang" and id = ?'), [ip_check()])
             data = curs.fetchall()
-            if not data:
-                data = [['default']]
+            data = [['default']] if not data else data
 
             for lang_data in support_language:
                 see_data = lang_data if lang_data != 'default' else load_lang('default')
@@ -105,4 +101,50 @@ def user_setting_2(conn, server_init):
                 menu = [['user', load_lang('return')]]
             ))
     else:
-        return redirect('/login')
+        if flask.request.method == 'POST':
+            flask.session['skin'] = flask.request.form.get('skin', '')
+            flask.session['lang'] = flask.request.form.get('lang', '')
+            
+            return redirect('/change')
+        else:
+            div2 = load_skin(('' if not 'skin' in flask.session else flask.session['skin']), 0, 1)
+            div3 = ''
+
+            data = [['default']] if not 'lang' in flask.session else [[flask.session['lang']]]
+
+            for lang_data in support_language:
+                see_data = lang_data if lang_data != 'default' else load_lang('default')
+                
+                if data and data[0][0] == lang_data:
+                    div3 = '<option value="' + lang_data + '">' + see_data + '</option>' + div3
+                else:
+                    div3 += '<option value="' + lang_data + '">' + see_data + '</option>'
+                    
+            http_warring = '' + \
+                '<hr class="main_hr">' + \
+                '<span>' + load_lang('http_warring') + '</span>' + \
+                '<hr class="main_hr">' + \
+                '<span>' + load_lang('user_head_warring') + '</span>' + \
+            ''
+            
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('user_setting'), wiki_set(), custom(), other2([0, 0])],
+                data = '''
+                    <form method="post">
+                        <span>''' + load_lang('id') + ''' : ''' + ip_pas(ip) + '''</span>
+                        <hr class="main_hr">
+                        <h2>''' + load_lang('main') + '''</h2>
+                        <span>''' + load_lang('skin') + '''</span>
+                        <hr class="main_hr">
+                        <select name="skin">''' + div2 + '''</select>
+                        <hr class="main_hr">
+                        <span>''' + load_lang('language') + '''</span>
+                        <hr class="main_hr">
+                        <select name="lang">''' + div3 + '''</select>
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                        ''' + http_warring + '''
+                    </form>
+                ''',
+                menu = [['user', load_lang('return')]]
+            ))

+ 2 - 2
route/user_tool.py

@@ -5,7 +5,7 @@ def user_tool_2(conn, name):
 
     data = '''
         <h2>''' + load_lang('tool') + '''</h2>
-        <ul>
+        <ul class="inside_ul">
             <li><a href="/record/''' + url_pas(name) + '''">''' + load_lang('record') + '''</a></li>
             <li><a href="/topic/user:''' + url_pas(name) + '''">''' + load_lang('user_discussion') + '''</a></li>
         </ul>
@@ -17,7 +17,7 @@ def user_tool_2(conn, name):
         
         data += '''
             <h2>''' + load_lang('admin') + '''</h2>
-            <ul>
+            <ul class="inside_ul">
                 <li><a href="/ban/''' + url_pas(name) + '''">''' + ban_name + '''</a></li>
                 <li><a href="/check/''' + url_pas(name) + '''">''' + load_lang('check') + '''</a></li>
             </ul>

+ 1 - 1
route/view_down.py

@@ -3,7 +3,7 @@ from .tool.func import *
 def view_down_2(conn, name):
     curs = conn.cursor()
 
-    div = '<ul>'
+    div = '<ul class="inside_ul">'
 
     curs.execute(db_change("select title from data where title like ?"), [name + '/%'])
     for data in curs.fetchall():

+ 7 - 7
route/view_read.py

@@ -40,7 +40,7 @@ def view_read_2(conn, name):
 
             for data in back:
                 if div == '':
-                    div = '<br><h2 id="cate_normal">' + load_lang('category_title') + '</h2><ul>'
+                    div = '<br><h2 id="cate_normal">' + load_lang('category_title') + '</h2><ul class="inside_ul">'
 
                 if re.search(r'^category:', data[0]):
                     u_div += '<li><a href="/w/' + url_pas(data[0]) + '">' + data[0] + '</a></li>'
@@ -56,7 +56,7 @@ def view_read_2(conn, name):
                 div += '</ul>'
 
             if u_div != '':
-                div += '<br><h2 id="cate_under">' + load_lang('under_category') + '</h2><ul>' + u_div + '</ul>'
+                div += '<br><h2 id="cate_under">' + load_lang('under_category') + '</h2><ul class="inside_ul">' + u_div + '</ul>'
 
 
     cache_data = None
@@ -106,18 +106,18 @@ def view_read_2(conn, name):
         curs.execute(db_change('select data from other where name = "error_401"'))
         sql_d = curs.fetchall()
         if sql_d and sql_d[0][0] != '':
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + sql_d[0][0] + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + sql_d[0][0] + '</li></ul>'
         else:
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('authority_error') + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + load_lang('authority_error') + '</li></ul>'
     elif end_data == 'HTTP Request 404':
         response_data = 404
 
         curs.execute(db_change('select data from other where name = "error_404"'))
         sql_d = curs.fetchall()
         if sql_d and sql_d[0][0] != '':
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + sql_d[0][0] + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + sql_d[0][0] + '</li></ul>'
         else:
-            end_data = '<h2>' + load_lang('error') + '</h2><ul><li>' + load_lang('decument_404_error') + '</li></ul>'
+            end_data = '<h2>' + load_lang('error') + '</h2><ul class="inside_ul"><li>' + load_lang('decument_404_error') + '</li></ul>'
 
         curs.execute(db_change('' + \
             'select ip, date, leng, send, id from history ' + \
@@ -125,7 +125,7 @@ def view_read_2(conn, name):
         ''), [name])
         sql_d = curs.fetchall()
         if sql_d:
-            end_data += '<h2>' + load_lang('history') + '</h2><ul>'
+            end_data += '<h2>' + load_lang('history') + '</h2><ul class="inside_ul">'
             for i in sql_d:
                 if re.search(r"\+", i[2]):
                     leng = '<span style="color:green;">(' + i[2] + ')</span>'

+ 1 - 1
route/view_xref.py

@@ -17,7 +17,7 @@ def view_xref_2(conn, name):
     else:
         div = '<a href="?change=1">(' + load_lang('normal') + ')</a><hr class="main_hr">'
 
-    div += '<ul>'
+    div += '<ul class="inside_ul">'
 
     if flask.request.args.get('change', '1') == '1':
         curs.execute(db_change("" + \

+ 1 - 1
route/vote.py

@@ -16,7 +16,7 @@ def vote_2(conn):
         sub = '(' + load_lang('closed') + ')'
         curs.execute(db_change('select name, id, type from vote where type = "close" or type = "n_close" limit ?, 50'), [sql_num])
 
-    data += '<ul>'
+    data += '<ul class="inside_ul">'
 
     data_list = curs.fetchall()
     for i in data_list:

+ 1 - 1
route/vote_end.py

@@ -28,7 +28,7 @@ def vote_end_2(conn, num):
     vote_data = re.findall(r'([^\n]+)', data_list[0][2].replace('\r\n', '\n'))
     for i in range(0, len(vote_data)):
         data += '<h2>' + vote_data[i] + '</h2>'
-        data += '<ul>'
+        data += '<ul class="inside_ul">'
         
         curs.execute(db_change('select user from vote where id = ? and user != "" and data = ?'), [num, str(i)])
         data_list_2 = curs.fetchall()

+ 1 - 1
route/watch_list.py

@@ -47,7 +47,7 @@ def watch_list_2(conn, tool):
         ''
 
     if data:
-        div = '<ul>' + div + '</ul><hr class=\"main_hr\">'
+        div = '<ul class="inside_ul">' + div + '</ul><hr class=\"main_hr\">'
 
     div += '<a href="/manager/' + ('13' if tool == 'watch_list' else '16') + '">(' + load_lang('add') + ')</a>'
 

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
     "beta" : {
-        "r_ver" : "v3.2.0-stable-13 (beta-40) (dev-2020-10-15-01)",
+        "r_ver" : "v3.2.0-stable-13 (beta-49) (dev-2021-02-14-01)",
         "c_ver" : "3203400",
-        "s_ver" : "10"
+        "s_ver" : "11"
     }
 }

+ 257 - 53
views/main_css/css/main.css

@@ -1,53 +1,257 @@
-body, html, video, table, div, iframe, input, textarea, img, hr, blockquote, pre { max-width: 100%;}
-textarea { width: 100%; }
-input { width: 100%; box-sizing: border-box; }
-#last { margin-top: 30px; }
-#toc { border: 1px solid; padding: 20px; width: fit-content; width: -moz-fit-content; clear: both; margin-top: 10px; }
-#toc-name { font-size: 18px; }
-table { border-collapse: collapse; }
-td { border: 1px solid; padding: 5px; }
-a { text-decoration: none; }
-#not_thing { color: red; }
-#inside, #out_link, #open { color: green; }
-#out_link::before { background: green; color: white; content: "E"; }
-input[type="checkbox"], input[type="radio"] { width: auto; }
-#list { padding: 10px; }
-#toron { width: 100%; }
-#toron_color_green { background: #99ffcd; }
-#toron_color_blue { background: #ffcbf9; }
-#toron_color_red { background: #fecabf; }
-#toron_color_grey { background: gainsboro; }
-#toron_color_not { display: none; }
-#cate { border: 1px solid; padding: 5px; margin-top: 20px; }
-blockquote { border: 1px solid; padding: 15px; margin: 0; margin-top: 10px; display: inline-block; }
-img, iframe { max-width: 100%; }
-pre { border: 1px solid; padding: 10px; white-space: pre-wrap; }
-#in { margin-left: 20px; }
-#out { margin-left: 5px; }
-s, strike, del { color: gray; }
-s:hover, strike:hover, del:hover { color: gray; background-color: gainsboro; text-decoration: none; }
-#main_table_set { width: 100%; text-align: center; }
-#main_table_width { width: 33.3%; }
-#main_table_width_half { width: 50%; }
-#main_table_width_quarter { width: 25%; }
-#redirect { border: 1px solid; padding: 10px; }
-body { word-break: break-all; overflow: auto; }
-.main_hr { border: none; margin-top: 8px; margin-bottom: 8px; }
-#include_link { display: none; }
-#toc_title { font-size: 18px; }
-blockquote { background-image: url(/views/main_css/file/quote.png); background-position: calc(100% - 10px) 10px; background-repeat: no-repeat; background-size: 25px; }
-#admin_log_search { width: 100px; }
-@media (max-width: 768px) { table { min-width: 100%; } .table_safe { min-width: 100%; }}
-#origin { display: none; }
-.all_in_data { display: block; width: 100%; white-space: pre-wrap; }
-.table_safe { max-width: 100%; }
-.change_space { white-space: pre-line; }
-#topic_scroll { max-height: 500px; overflow: scroll; -ms-overflow-style: none; scrollbar-width: none; }
-#topic_scroll::-webkit-scrollbar { display: none; }
-.hidden_link { filter: blur(3px); }
-.hidden_link:hover { filter: none; }
-.content { height: 500px; }
-.topic_content { height: 200px; }
-.spead_footnote { background-color: #efefef; color: #555; border: 1px solid #cecece; }
-#footnote_data { border-top: 1px solid gainsboro; padding-top: 10px; }
-a { color: dodgerblue; }
+body, html, video, table, div, iframe, input, textarea, img, hr, blockquote, pre {
+    max-width: 100%;
+}
+
+textarea {
+    width: 100%;
+}
+
+input {
+    width: 100%;
+    box-sizing: border-box;
+}
+
+#last {
+    margin-top: 30px;
+}
+
+#toc {
+    border: 1px solid;
+    padding: 20px;
+    width: fit-content;
+    width: -moz-fit-content;
+    clear: both;
+    margin-top: 10px;
+}
+
+#toc-name {
+    font-size: 18px;
+}
+
+table {
+    border-collapse: collapse;
+}
+
+td {
+    border: 1px solid;
+    padding: 5px;
+}
+
+a {
+    text-decoration: none;
+}
+
+.inside_ul li {
+    margin-left: 20px;
+}
+
+#not_thing {
+    color: red;
+}
+
+#inside, #out_link, #open {
+    color: green;
+}
+
+#out_link::before {
+    background: green;
+    color: white;
+    content: "E";
+    margin-right: 2px;
+}
+
+input[type="checkbox"], input[type="radio"] {
+    width: auto;
+}
+
+#list {
+    padding: 10px;
+}
+
+#toron {
+    width: 100%;
+}
+
+#toron_color_green {
+    background: #99ffcd;
+}
+
+#toron_color_blue {
+    background: #ffcbf9;
+}
+
+#toron_color_red {
+    background: #fecabf;
+}
+
+#toron_color_grey {
+    background: gainsboro;
+}
+
+#toron_color_not {
+    display: none;
+}
+
+#cate {
+    border: 1px solid;
+    padding: 5px;
+    margin-top: 20px;
+}
+
+img, iframe {
+    max-width: 100%;
+}
+
+pre {
+    border: 1px solid;
+    padding: 10px;
+    white-space: pre-wrap;
+}
+
+#in {
+    margin-left: 20px;
+}
+
+#out {
+    margin-left: 5px;
+}
+
+s, strike, del {
+    color: gray;
+}
+
+s:hover, strike:hover, del:hover {
+    color: gray;
+    background-color: gainsboro;
+    text-decoration: none;
+}
+
+#main_table_set {
+    width: 100%;
+    text-align: center;
+}
+
+#main_table_width {
+    width: 33.3%;
+}
+
+#main_table_width_half {
+    width: 50%;
+}
+
+#main_table_width_quarter {
+    width: 25%;
+}
+
+#redirect {
+    border: 1px solid;
+    padding: 10px;
+}
+
+body {
+    word-break: break-all;
+    overflow: auto;
+}
+
+.main_hr {
+    border: none;
+    margin-top: 8px;
+    margin-bottom: 8px;
+}
+
+#include_link {
+    display: none;
+}
+
+#toc_title {
+    font-size: 18px;
+}
+
+#admin_log_search {
+    width: 100px;
+}
+
+@media (max-width: 768px) {
+    table {
+    min-width: 100%;
+}
+ .table_safe {
+    min-width: 100%;
+}
+}
+#origin {
+    display: none;
+}
+
+.all_in_data {
+    display: block;
+    width: 100%;
+    white-space: pre-wrap;
+}
+
+.table_safe {
+    max-width: 100%;
+}
+
+.change_space {
+    white-space: pre-line;
+}
+
+#topic_scroll {
+    max-height: 500px;
+    overflow: scroll;
+    -ms-overflow-style: none;
+    scrollbar-width: none;
+}
+
+#topic_scroll::-webkit-scrollbar {
+    display: none;
+}
+
+.hidden_link {
+    filter: blur(3px);
+}
+
+.hidden_link:hover {
+    filter: none;
+}
+
+.content {
+    height: 500px;
+}
+
+.topic_content {
+    height: 200px;
+}
+
+.spead_footnote {
+    background-color: #efefef;
+    color: #555;
+    border: 1px solid #cecece;
+}
+
+#footnote_data {
+    border-top: 1px solid gainsboro;
+    padding-top: 10px;
+}
+
+a {
+    color: dodgerblue;
+}
+
+blockquote {
+    padding: 15px 40px 15px 15px;
+    margin: 15px 0 0;
+    display: table;
+    border: 2px solid #ccc;
+    border-left: 5px solid black;
+    background-image: url('/views/main_css/file/quote.png');
+    background-position: calc(100% - 10px) 10px;
+    background-repeat: no-repeat;
+    background-size: 25px;
+    font-size: inherit;
+}
+
+hr {
+    border-top: 1px solid lightgray;
+}

+ 51 - 12
views/main_css/css/sub/dark.css

@@ -1,12 +1,51 @@
-html { background: black; color: white; }
-textarea, input, button, select { background: #1f2023; color: white; }
-input::placeholder, textarea::placeholder, select::placeholder { color: white; }
-#toc, #cate, #redirect { background: #1f2023; }
-#toron_color_grey { background: #4a4a4a; }
-#toron_color_green { background: #2e4a2e; }
-#toron_color_red { background: #803737; }
-#toron_color_blue { background: #314c56; }
-pre#syntax, pre#syntax code { background: black; }
-.hljs, .hljs-subst { color: white; }
-blockquote { background-color: black; border-left: 5px solid #eee; }
-.spead_footnote { background-color: black; color: white; }
+html, body {
+    background: black;
+    color: white;
+}
+
+textarea, input, button, select {
+    background: #1f2023;
+    color: white;
+}
+
+input::placeholder, textarea::placeholder, select::placeholder {
+    color: white;
+}
+
+#toc, #cate, #redirect {
+    background: #1f2023;
+}
+
+#toron_color_grey {
+    background: #4a4a4a;
+}
+
+#toron_color_green {
+    background: #2e4a2e;
+}
+
+#toron_color_red {
+    background: #803737;
+}
+
+#toron_color_blue {
+    background: #314c56;
+}
+
+pre#syntax, pre#syntax code {
+    background: black;
+}
+
+.hljs, .hljs-subst {
+    color: white;
+}
+
+blockquote {
+    background-color: black;
+    border-left: 5px solid #eee;
+}
+
+.spead_footnote {
+    background-color: black;
+    color: white;
+}

+ 39 - 11
views/main_css/js/do_editor.js → views/main_css/js/load_editor.js

@@ -48,17 +48,17 @@ function do_paste_image() {
 
 function pasteListener(e) {
     // find file
-    if (e.clipboardData && e.clipboardData.items) {
+    if(e.clipboardData && e.clipboardData.items) {
         const items = e.clipboardData.items;
         let haveImageInClipboard = false;
         const formData = new FormData();
-        for (let i = 0; i < items.length; i++) {
+        for(let i = 0; i < items.length; i++) {
             if (items[i].type.indexOf("image") !== -1) {
                 const file = items[i].getAsFile();
-                const customName = prompt("파일 이름을 설정해주세요. (확장자는 생략)");
+                const customName = prompt("파일 이름 (확장자 제외)");
                 
                 if (!customName) {
-                    return alert("취소되었습니다.");
+                    return alert("파일 이름 없음");
                 }
                 
                 const customFile = new File([file], customName + ".png", { type: file.type });
@@ -69,7 +69,7 @@ function pasteListener(e) {
                 break;
             }
         }
-        if (!haveImageInClipboard) {
+        if(!haveImageInClipboard) {
             return;
         }
 
@@ -81,22 +81,50 @@ function pasteListener(e) {
             if (res.status === 200 || res.status === 201) {
                 const url = res.url;
                 alert(
-                    '클립보드의 이미지를 성공적으로 업로드했습니다. 아래 텍스트로 본문에 삽입할 수 있습니다. ' +
+                    '업로드 완료 : ' +
                     '[[' + decodeURIComponent(url.replace(/.*\/w\/file/, "file")) + ']]'
                 );
             } else {
                 console.error("[ERROR] PasteUpload Fail :", res.statusText);
                 if(res.status === 400) {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다. 파일 이름 중복일 수 있습니다.");
+                    alert("파일 이름 중복");
                 } else if(res.status === 401) {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다. 권한 부족일 수 있습니다.");    
+                    alert("권한 부족");    
                 } else {
-                    alert("클립보드의 이미지를 업로드하는데 실패했습니다.");        
+                    alert("업로드 실패");        
                 }
             }
         }).catch((err) => {
-            console.error("[ERROR] PasteUpload Fail :", JSON.stringify(err), err);
-            alert("클립보드의 이미지를 업로드하는데 실패했습니다. 서버가 응답하지 않습니다.");
+            console.error("오류 내역 :", JSON.stringify(err), err);
+            alert("업로드 실패");
         });
     }
+}
+
+function load_preview(name) {
+    var s_data = new FormData();
+    s_data.append('data', document.getElementById('content').value);
+
+    var url = "/api/w/" + name;
+    var url_2 = "/api/markup";
+
+    var xhr = new XMLHttpRequest();
+    xhr.open("POST", url, true);
+    xhr.send(s_data);
+
+    var xhr_2 = new XMLHttpRequest();
+    xhr_2.open("GET", url_2, true);
+    xhr_2.send(null);
+
+    xhr.onreadystatechange = function() {
+        if(xhr.readyState === 4 && xhr.status === 200) {
+            var o_p_data = JSON.parse(xhr.responseText);
+            document.getElementById('see_preview').innerHTML = o_p_data['data'];
+            eval(o_p_data['js_data'])
+        }
+    }
+}
+
+function load_raw_preview(name_1, name_2) {
+    document.getElementById(name_2).innerHTML = document.getElementById(name_1).value;
 }

+ 411 - 0
views/main_css/js/load_onmark_render.js

@@ -0,0 +1,411 @@
+// Tool
+function do_url_change(data) {
+    return encodeURIComponent(data);
+}
+
+function do_return_date() {
+    var today_data = new Date();
+
+    return '' +
+        String(today_data.getFullYear()) + '-' + 
+        ((today_data.getMonth() + 1) < 10 ? '0' : '') + String(today_data.getMonth() + 1) + '-' + 
+        (today_data.getDate() < 10 ? '0' : '') + String(today_data.getDate()) + ' ' + 
+        (today_data.getHours() < 10 ? '0' : '') + String(today_data.getHours()) + ':' + 
+        (today_data.getMinutes() < 10 ? '0' : '') + String(today_data.getMinutes()) + ':' + 
+        (today_data.getSeconds() < 10 ? '0' : '') + String(today_data.getSeconds()) +
+    '';
+}
+
+// Sub
+function do_onmark_text_render(data) {    
+    data = data.replace(/'''((?:(?!''').)+)'''/g, '<b>$1</b>');
+    data = data.replace(/''((?:(?!'').)+)''/g, '<i>$1</i>');
+    data = data.replace(/__((?:(?!__).)+)__/g, '<u>$1</u>');
+    data = data.replace(/\^\^((?:(?!\^\^).)+)\^\^/g, '<sup>$1</sup>');
+    data = data.replace(/,,((?:(?!,,).)+),,/g, '<sub>$1</sub>');
+    data = data.replace(/--((?:(?!--).)+)--/g, '<s>$1</s>');
+    data = data.replace(/~~((?:(?!~~).)+)~~/g, '<s>$1</s>');
+    
+    return data;
+}
+
+function do_onmark_heading_render(data) {
+    var heading_re = /<br>(={1,6}) ?([^=]+) ?={1,6}<br>/;
+    var heading_level_all = [0, 0, 0, 0, 0, 0];
+    var toc_data = '<div id="toc"><div id="toc_title">TOC</div><br>';
+    while(1) {        
+        var heading_data = data.match(heading_re);
+        if(!heading_data) {
+            break;
+        }
+          
+        var heading_level = heading_data[1].length;
+        heading_level_all[heading_level - 1] += 1;
+
+        var i = 6;
+        while(i > heading_level - 1) {
+            heading_level_all[i] = 0;
+
+            i -= 1;
+        }
+
+        heading_level = String(heading_level);
+        var heading_level_string = '';
+        i = 0;
+        while(i < 6) {
+            if(heading_level_all[i] !== 0) {
+                heading_level_string += String(heading_level_all[i]) + '.';
+            }
+
+            i += 1;
+        }
+        
+        var heading_level_string_no_end = heading_level_string.replace(/\.$/, '');
+
+        toc_data += '' +
+            '<span style="margin-left: ' + String((heading_level_string.match(/\./g).length - 1) * 10) + 'px;">' +
+                '<a href="#s-' + heading_level_string_no_end + '">' + 
+                    heading_level_string + ' ' +
+                '</a>' + heading_data[2] +
+            '</span>' +
+            '<br>' +
+        ''
+        data = data.replace(heading_re, 
+            '<h' + heading_level + ' id="s-' + heading_level_string_no_end + '">' + 
+                '<a href="#toc">' + heading_level_string + '</a> ' + heading_data[2] + 
+            '</h' + heading_level + '>' +
+            '<br>'
+       );
+    }
+    
+    data = data.replace(/(<\/h[0-9]>)<br>/g, '$1');
+    data = data.replace(/\[(?:toc|목차)\]/g, toc_data + '</div>');
+    
+    return data;
+}
+
+function do_onmark_link_render(data, data_js, name_doc, name_include) {
+    var link_num = 0;
+    data = data.replace(/\[\[(((?!\]\]).)+)\]\]/g, function(x, x_1) {
+        var link_split = x_1.split('|');
+        var link_real = link_split[0];
+        var link_out = link_split[1] ? link_split[1] : link_split[0];
+        
+        link_num += 1;
+        var link_num_str = String(link_num - 1);
+        
+        if(link_real.match(/^http(s)?:\/\//)) {
+            var i = 0;
+            while(i < 2) {
+                if(i === 0) {
+                    var var_link_type = 'href';
+                } else {
+                    var var_link_type = 'title';
+                }
+                
+                data_js += '' +
+                    'document.getElementsByName("' + name_include + 'set_link_' + link_num_str + '")[0].' + var_link_type + ' = ' + 
+                        '"' + link_real.replace(/"/g, '\\"') + '";' +
+                    '\n' +
+                '';
+                
+                i += 1;
+            }
+            
+            return  '<a id="out_link" ' +
+                        'name="' + name_include + 'set_link_' + link_num_str + '" ' + 
+                        'title=""' +
+                        'href="">' + link_out + '</a>';
+        } else {
+            var i = 0;
+            while(i < 2) {
+                if(i === 0) {
+                    var var_link_type = 'href';
+                    var var_link_data = '/w/' + do_url_change(link_real);
+                } else {
+                    var var_link_type = 'title';
+                    var var_link_data = link_real.replace(/"/g, '\\"');
+                }
+                
+                data_js += '' +
+                    'document.getElementsByName("' + name_include + 'set_link_' + link_num_str + '")[0].' + var_link_type + ' = ' + 
+                        '"' + var_link_data + '";' +
+                    '\n' +
+                '';
+                
+                i += 1;
+            }
+            
+            return  '<a class="' + name_include + 'link_finder" ' +
+                        'name="' + name_include + 'set_link_' + link_num_str + '" ' +
+                        'title="" ' +
+                        'href="">' + link_out + '</a>';
+        }
+    });
+    
+    return [data, data_js];
+}
+
+function do_onmark_footnote_render(data, name_include) {
+    var footnote_end_data = '';
+    var footnote_all_data = {};
+    var footnote_re = /(?:\[\*([^ \]]*)(?: ((?:(?!<br>|\]).)+))?\]|\[(footnote|각주)\])/;
+    var i = 1;
+    while(1) {
+        var footnote_data = data.match(footnote_re);
+        if(!footnote_data) {
+            break;
+        }
+        
+        if(!footnote_data[3]) {
+            if(!footnote_data[2]) {
+                var footnote_line_data = '';
+            } else {
+                var footnote_line_data = footnote_data[2];
+            }
+            
+            if(!footnote_data[1]) {
+                var footnote_name = String(i);
+            } else {
+                var footnote_name = footnote_data[1];
+            }
+            
+            if(!footnote_all_data[footnote_name]) {
+                footnote_all_data[footnote_name] = footnote_line_data;
+            }
+
+            footnote_line_data = footnote_all_data[footnote_name];
+            
+            footnote_end_data += '' +
+                '<li>' +
+                    '<a href="javascript:do_open_foot(\'' + name_include + 'fn-' + String(i) + '\', 1);" ' +
+                        'id="' + name_include + 'cfn-' + String(i) + '">' +
+                        '(' + footnote_name + ')' +
+                    '</a> <span id="' + name_include + 'fn-' + String(i) + '">' + footnote_line_data + '</span>' +
+                '</li>' +
+            '';
+            data = data.replace(footnote_re, '' +
+                '<sup>' +
+                    '<a href="javascript:do_open_foot(\'' + name_include + 'fn-' + String(i) + '\', 0);" ' +
+                        'id="' + name_include + 'rfn-' + String(i) + '">' +
+                        '(' + footnote_name + ')' +
+                    '</a>' +
+                '</sup><span id="' + name_include + 'dfn-' + String(i) + '"></span>' +
+           '');
+            
+            i += 1;
+        } else {
+            if(footnote_end_data !== '') {
+                data = data.replace(footnote_re, '<ul id="footnote_data">' + footnote_end_data + '</ul>');    
+            }
+            
+            footnote_end_data = '';
+        }
+    }
+    
+    if(footnote_end_data !== '') {
+        data += '<ul id="footnote_data">' + footnote_end_data + '</ul>';
+    }
+    
+    return data;
+}
+
+function do_onmark_macro_render(data) {
+    data = data.replace(/\[([^[\](]+)\(((?:(?!\)\]).)+)\)\]/g, function(x, x_1, x_2) {
+        x_1 = x_1.toLowerCase();
+        if(x_1 === 'youtube' || x_1 === 'kakaotv' || x_1 === 'nicovideo') {
+            var video_code = x_2.match(/^([^,]+)/);
+            video_code = video_code ? video_code[1] : '';
+            
+            var video_width = x_2.match(/,(?: *)width=([0-9]+)/);
+            video_width = video_width ? (video_width[1] + 'px') : '640px';
+            
+            var video_height = x_2.match(/,(?: *)height=([0-9]+)/);
+            video_height = video_height ? (video_height[1] + 'px') : '360px';
+            
+            if(x_1 === 'youtube') {
+                var video_start = x_2.match(/,(?: *)start=([0-9]+)/);
+                video_start = video_start ? ('?' + video_start[1]) : '';
+                
+                video_code = video_code.replace(/^https:\/\/www\.youtube\.com\/watch\?v=/, '');
+                video_code = video_code.replace(/^https:\/\/youtu\.be\//, '');
+                
+                var video_src = 'https://www.youtube.com/embed/' + video_code + video_start
+            } else if(x_1 === 'kakaotv') {
+                video_code = video_code.replace(/^https:\/\/tv\.kakao\.com\/channel\/9262\/cliplink\//, '');
+                video_code = video_code.replace(/^http:\/\/tv\.kakao\.com\/v\//, '');
+                
+                var video_src = 'https://tv.kakao.com/embed/player/cliplink/' + video_code +'?service=kakao_tv'
+            } else {
+                var video_src = 'https://embed.nicovideo.jp/watch/' + video_code
+            }
+            
+            return '<iframe style="width: ' + video_width + '; height: ' + video_height + ';" src="' + video_src + '" frameborder="0" allowfullscreen></iframe>';
+        } else if(x_1 === 'anchor') {
+            return '<span id="' + x_2 + '"></span>';
+        } else {
+            return '<macro_start>' + x_1 + '(' + x_2 + ')<macro_end>';
+        }
+    });
+    
+    data = data.replace(/\[([^[*()\]]+)\]/g, function(x, x_1) {
+        x_1 = x_1.toLowerCase();
+        if(x_1 === 'date') {
+            return do_return_date();
+        } else if(x_1 === 'clearfix') {
+            return '<div style="clear:both"></div>';
+        } else if(x_1 === 'br') { 
+            return '<br>';
+        } else {
+            return '<macro_start>' + x_1 + '<macro_end>';
+        }
+    });
+    
+    data = data.replace(/<macro_start>/g, '[');
+    data = data.replace(/<macro_end>/g, ']');
+    
+    return data;
+}
+
+function do_onmark_middle_render(data, data_js, name_include) {
+    var middle_stack = [];
+    var middle_re = /(?:{{{([^{} ]+)|(}}}))/;
+    
+    var syntax_on = 0;
+    
+    var html_n = 0;
+    
+    while(1) {
+        var middle_data = data.match(middle_re);
+        if(!middle_data) {
+            break;
+        }
+        
+        if(middle_data[2]) {
+            if(middle_stack.length === 0) {
+                data = data.replace(middle_re, '<middle_end>');   
+            } else {
+                data = data.replace(middle_re, middle_stack[middle_stack.length - 1]);    
+                middle_stack.pop();
+            }
+        } else {
+            if(middle_data[1].match(/^(?:(#(?:[0-9a-f-A-F]{3}){1,2})|#([a-zA-Z]+))/)) {
+                var color = middle_data[1].match(/^(?:(#(?:[0-9a-f-A-F]{3}){1,2})|#([a-zA-Z]+))/);
+                color = color[1] ? color[1] : color[2];
+                
+                data = data.replace(middle_re, '<span style="color: ' + color + ';">');
+                middle_stack.push('</span>');
+            } else if(middle_data[1].match(/^(\+|-)([1-5])/)) {
+                var font = middle_data[1].match(/^(\+|-)([1-5])/);
+                if(font[1] === '+') {
+                    var font_size = String(100 + (20 * Number(font[2]))) + '%';
+                } else {
+                    var font_size = String(100 - (10 * Number(font[2]))) + '%';
+                }
+                
+                data = data.replace(middle_re, '<span style="font-size: ' + font_size + ';">');
+                middle_stack.push('</span>');
+            } else if(middle_data[1] === '#!wiki') {
+                var wiki_re = /{{{#!wiki(?: style=["']([^"']*)["']<br>)?/;
+                
+                var wiki = data.match(wiki_re);
+                var wiki_style = wiki[1] ? wiki[1] : '';
+                
+                data = data.replace(wiki_re, '<div_wiki_start style="' + wiki_style + '">');  
+                middle_stack.push('<div_wiki_end>');
+            } else if(middle_data[1] === '#!html') {
+                html_n += 1;
+                
+                data = data.replace(middle_re, '<span id="' + name_include + 'render_contect_' + String(html_n) + '">');
+                middle_stack.push('</span>');
+            } else {
+                data = data.replace(middle_re, '<middle_start>' + middle_data[1]);   
+            }
+        }
+    }
+    
+    while(middle_stack.length !== 0) {
+        data += middle_stack[middle_stack.length - 1];
+        middle_stack.pop();
+    }
+    
+    data = data.replace(/<br><div_wiki_end>/g, '<div_wiki_end>');
+    
+    data = data.replace(/<middle_start>/g, '{{{');
+    data = data.replace(/<middle_end>/g, '}}}');
+    
+    return [data, data_js];
+}
+
+function do_onmark_last_render(data) {
+    // middle_render 마지막 처리
+    data = data.replace(/<div_wiki_start /g, '<div ');
+    data = data.replace(/<div_wiki_end>/g, '</div>');
+    
+    // br 마지막 처리
+    data = data.replace(/^(<br>| )+/, '');
+    data = data.replace(/(<br>| )+$/, '');
+    
+    return data;
+}
+
+function do_onmark_include_render(data, data_js) {
+    var include_re = /\[include\((((?!\)\]).)+)\)\]/;
+    while(1) {
+        var include_data = data.match(include_re);
+        if(!include_data) {
+            break;
+        }
+        
+        data = data.replace(include_re, '');
+    }
+    
+    return [data, data_js];
+}
+
+function do_onmark_nowiki_before_render(data, data_js) {
+    return [data, data_js];
+}
+
+function do_onmark_list_render(data) {
+    return data;
+}
+
+// Main
+function do_onmark_render(name_id, name_include = '', name_doc = '') {
+    var data = '<br>' + document.getElementById(name_id).innerHTML.replace(/\n/g, '<br>') + '<br>';
+    var data_js = '';
+    
+    var var_data = do_onmark_nowiki_before_render(data, data_js, name_include);
+    data = var_data[0];
+    data_js = var_data[1];
+    
+    var_data = do_onmark_include_render(data, data_js, name_include);
+    data = var_data[0];
+    data_js = var_data[1];
+    
+    var_data = do_onmark_middle_render(data, data_js, name_include);
+    data = var_data[0];
+    data_js = var_data[1];
+    
+    data = do_onmark_text_render(data);
+    data = do_onmark_heading_render(data);
+    
+    var_data = do_onmark_link_render(data, data_js, name_doc, name_include);
+    data = var_data[0];
+    data_js = var_data[1];
+    
+    data = do_onmark_macro_render(data);
+    data = do_onmark_list_render(data);
+    data = do_onmark_footnote_render(data, name_include);
+    data = do_onmark_last_render(data, name_include);
+    
+    data_js += '' + 
+        'get_link_state("' + name_include + '");\n' + 
+        'get_file_state("' + name_include + '");\n' + 
+    ''
+    data_js = 'render_html("' + name_include + 'render_contect");\n' + data_js
+    
+    document.getElementById(name_id).innerHTML = data;
+    eval(data_js);
+}

+ 0 - 27
views/main_css/js/load_preview.js

@@ -1,27 +0,0 @@
-function load_preview(name) {
-    var s_data = new FormData();
-    s_data.append('data', document.getElementById('content').value);
-
-    var url = "/api/w/" + name;
-    var url_2 = "/api/markup";
-
-    var xhr = new XMLHttpRequest();
-    xhr.open("POST", url, true);
-    xhr.send(s_data);
-
-    var xhr_2 = new XMLHttpRequest();
-    xhr_2.open("GET", url_2, true);
-    xhr_2.send(null);
-
-    xhr.onreadystatechange = function() {
-        if(xhr.readyState === 4 && xhr.status === 200) {
-            var o_p_data = JSON.parse(xhr.responseText);
-            document.getElementById('see_preview').innerHTML = o_p_data['data'];
-            eval(o_p_data['js_data'])
-        }
-    }
-}
-
-function load_raw_preview(name_1, name_2) {
-    document.getElementById(name_2).innerHTML = document.getElementById(name_1).value;
-}

+ 102 - 5
views/main_css/js/load_skin_set.js

@@ -74,6 +74,13 @@ function main_css_get_post() {
         document.cookie = 'main_css_font_size=;';
     }
 
+    check = document.getElementById('main_css_monaco');
+    if(check.checked) {
+        document.cookie = 'main_css_monaco=1;';
+    } else {
+        document.cookie = 'main_css_monaco=0;';
+    }
+
     history.go(0);
 }
 
@@ -156,7 +163,13 @@ function main_css_load_lang(name) {
             "all_off" : "Always off",
             "set_font_size" : "Set font size",
             "change_to_link" : "Change to link",
-            "font_size" : "font size"
+            "font_size" : "font size",
+            "editor" : "Editor",
+            "main" : "Main",
+            "clipboard_upload" : "Clipboard upload",
+            "only_korean" : "Supported in korean only",
+            "except_ie" : "Not supported for Internet Explorer",
+            "use_monaco" : "Use monaco editor"
         }, "ko-KR" : {
             "default" : "기본값",
             "change_to_normal" : "일반 텍스트로 변경",
@@ -179,7 +192,13 @@ function main_css_load_lang(name) {
             "all_off" : "항상 끔",
             "set_font_size" : "글자 크기 설정",
             "change_to_link" : "링크로 변경",
-            "font_size" : "글자 크기"
+            "font_size" : "글자 크기",
+            "editor" : "편집기",
+            "main" : "메인",
+            "clipboard_upload" : "클립보드 파일 올리기",
+            "only_korean" : "한국어로만 지원됨",
+            "except_ie" : "인터넷 익스플로러에선 지원되지 않음",
+            "use_monaco" : "모나코 에디터 사용"
         }
     }
 
@@ -346,6 +365,15 @@ function main_css_skin_set() {
         set_data["font_size"] = '';
     }
 
+    if(
+        document.cookie.match(main_css_regex_data('main_css_monaco')) &&
+        document.cookie.match(main_css_regex_data('main_css_monaco'))[1] === '1'
+    ) {
+        set_data["monaco"] = "checked";
+    } else {
+        set_data["monaco"] = "";
+    }
+
     document.getElementById("main_skin_set").innerHTML = ' \
         <h2>1. ' + main_css_load_lang('renderer') + '</h2> \
         <h3>1.1. ' + main_css_load_lang('strike') + '</h3> \
@@ -370,15 +398,84 @@ 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["image_paste"] + ' type="checkbox" id="main_css_image_paste" value="image_paste"> 클립보드 이미지 업로드 (ko-KR) \
         <h3>1.7. ' + main_css_load_lang('set_toc') + '</h3> \
         <select id="main_css_toc"> \
             ' + set_data["toc"] + ' \
         </select> \
         <h3>1.8. ' + main_css_load_lang('set_font_size') + '</h3> \
-        <input id="main_css_font_size" placeholder="' + main_css_load_lang('font_size') + '" value="' + set_data["font_size"] + '"> \
+        <input id="main_css_font_size" placeholder="' + main_css_load_lang('font_size') + ' (EX : 11)" value="' + set_data["font_size"] + '"> \
+        <h2>2. ' + main_css_load_lang('editor') + '</h2> \
+        <h3>2.1. ' + main_css_load_lang('main') + '</h3> \
+        <input ' + set_data["monaco"] + ' type="checkbox" id="main_css_monaco" value="monaco"> ' + main_css_load_lang('use_monaco') + '<sup>(1)</sup> \
+        <hr class="main_hr"> \
+        <input ' + set_data["image_paste"] + ' type="checkbox" id="main_css_image_paste" value="image_paste"> ' + 
+            main_css_load_lang('clipboard_upload') + '<sup>(ko-KR)</sup><sup>(1)</sup> \
         <hr class="main_hr"> \
         <button onclick="main_css_get_post();">' + main_css_load_lang('save') + '</button> \
+        <hr class="main_hr"> \
+        <ul id="footnote_data"> \
+            <li><a id="note_1_end" href="#note_1">(1)</a> ' + main_css_load_lang('except_ie') + '</li> \
+            <li><a href="#note_1_1">(1.1)</a></li> \
+            <li><a id="note_2_end" href="#note_2">(ko-KR)</a> ' + main_css_load_lang('only_korean') + '</li> \
+        </ul> \
     ';
+
+    // 목차 구현
+    var toc_all_data = '<div id="toc"><span id="toc_title">TOC</span><br>';
+    var skin_set_data = document.getElementById("main_skin_set").innerHTML;
+    var split_toc;
+    var toc_data;
+    i = 1;
+    while(1) {
+        toc_data = skin_set_data.match(/<h[1-6]>([^<>]+)<\/h[1-6]>/);
+        if(toc_data) {
+            split_toc = toc_data[1].match(/^([^ ]+)(.+)/);
+            toc_all_data += '' + 
+                '<br>' +
+                '<span style="margin-left: ' + String(((toc_data[1].match(/\./g) || []).length - 1) * 10) + 'px;">' +
+                    '<a href="#toc_' + String(i) + '">' + split_toc[1] + '</a>' + split_toc[2] +
+                '</span>' +
+            '';
+
+            skin_set_data = skin_set_data.replace(
+                /<(h[1-6])>([^<>]+)<\/h[1-6]>/, 
+                '<$1 id="toc_' + String(i) + '"><a href="#toc">' + split_toc[1] + '</a>' + split_toc[2] + '</$1>'
+            );
+            i += 1;
+        } else {
+            break;
+        }
+    }
+    document.getElementById("main_skin_set").innerHTML = toc_all_data + '</div>' + skin_set_data;
+
+    // 각주 구현
+    skin_set_data = document.getElementById("main_skin_set").innerHTML;
+    var note_list = {};
+    var plus_note;
+    i = 1;
+    while(1) {
+        toc_data = skin_set_data.match(/<sup>([^<>]+)<\/sup>/);
+        if(toc_data) {
+            if(!note_list[toc_data[1]]) {
+                note_list[toc_data[1]] = [String(i), 0];
+            } else {
+                note_list[toc_data[1]][1] += 1;
+            }
+
+            if(note_list[toc_data[1]][1] != 0) {
+                plus_note = '_' + String(note_list[toc_data[1]][1]);
+            } else {
+                plus_note = '';
+            }
+            
+            skin_set_data = skin_set_data.replace(
+                /<sup>([^<>]+)<\/sup>/, 
+                '<sup><a id="note_' + note_list[toc_data[1]][0] + plus_note + '" href="#note_' + note_list[toc_data[1]][0] + '_end">$1</a></sup>'
+            );
+            i += 1;
+        } else {
+            break;
+        }
+    }
+    document.getElementById("main_skin_set").innerHTML = skin_set_data;    
 }

+ 0 - 8
views/marisa/css/main.css

@@ -333,14 +333,6 @@ textarea, input {
     color: white;
 }
 
-blockquote {
-    padding: 1em calc(2em + 25px) 1em 1em;
-    margin: 1em 0em 0em;
-    background-color: #eeeeee;
-    border: 1px dashed #ccc;
-    border-left: 5px solid black;
-}
-
 #out_link::before {
     content: '🅴';
     font-weight: lighter;

+ 2 - 2
views/marisa/index.html

@@ -9,9 +9,9 @@
         {% endif %}
         {{imp[3][3]|safe}}
         <link rel="stylesheet" href="/views/marisa/css/main.css?ver=16">
-        <script src="/views/marisa/js/skin_set.js?ver=5"></script>
+        <script src="/views/marisa/js/skin_set.js?ver=6"></script>
         <script src="/views/marisa/js/main.js?ver=3"></script>
-        <script>main_load(); window.addEventListener('DOMContentLoaded', function() { skin_set(); });</script>
+        <script>main_load(); window.addEventListener('DOMContentLoaded', skin_set);</script>
         <script src="https://code.iconify.design/1/1.0.3/iconify.min.js"></script>
         <link rel="shortcut icon" href="/views/main_css/file/favicon.ico?ver=1">
         {{imp[1][5]|safe}}

+ 2 - 8
views/marisa/js/main.js

@@ -23,13 +23,7 @@ function opening(data) {
 }
 
 document.onclick = function(event) {
-    for(var node = event.target; node != document.body; node = node.parentNode) {
-        if(save_data !== '' && open == 0) {
-            if(node.id === save_data) {
-                break;
-            } else {
-                document.getElementById(save_data).style.display = 'none';
-            }
-        }
+    if(save_data !== '' && open == 0) {
+        document.getElementById(save_data).style.display = 'none';
     }
 }

+ 7 - 7
views/marisa/js/skin_set.js

@@ -1,9 +1,9 @@
 function get_post() {
     check = document.getElementById('invert');
     if(check.checked === true) {
-        document.cookie = 'invert=1;';
+        document.cookie = 'main_css_darkmode=1;';
     } else {
-        document.cookie = 'invert=0;';
+        document.cookie = 'main_css_darkmode=0;';
     }
 
     history.go(0);
@@ -12,11 +12,11 @@ function get_post() {
 function main_load() {
     var head_data = document.querySelector('head');
     if(
-        cookies.match(regex_data('invert')) &&
-        cookies.match(regex_data('invert'))[1] === '1'
+        cookies.match(regex_data('main_css_darkmode')) &&
+        cookies.match(regex_data('main_css_darkmode'))[1] === '1'
     ) {
         head_data.innerHTML += '' +
-            '<link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=1">' +
+            '<link rel="stylesheet" href="/views/main_css/css/sub/dark.css?ver=2">' +
             '<link rel="stylesheet" href="/views/marisa/css/dark.css?ver=6">' +
         '';
     }
@@ -53,8 +53,8 @@ function skin_set() {
         var set_data = {};
 
         if(
-            cookies.match(regex_data('invert')) &&
-            cookies.match(regex_data('invert'))[1] === '1'
+            cookies.match(regex_data('main_css_darkmode')) &&
+            cookies.match(regex_data('main_css_darkmode'))[1] === '1'
         ) {
             set_data["invert"] = "checked";
         }