Просмотр исходного кода

Merge pull request #1754 from openNAMU/beta

fix
잉여개발기 (SPDV) 3 лет назад
Родитель
Сommit
a2db688f40
45 измененных файлов с 818 добавлено и 867 удалено
  1. 19 16
      app.py
  2. 1 17
      emergency_tool.py
  3. 16 7
      lang/en-US.json
  4. 12 5
      lang/ko-KR.json
  5. 1 1
      requirements.txt
  6. 5 0
      route/api_setting.py
  7. 4 10
      route/edit.py
  8. 2 0
      route/filter_inter_wiki_add.py
  9. 70 0
      route/give_user_fix.py
  10. 2 2
      route/login_login.py
  11. 1 1
      route/main_func_error_404.py
  12. 3 2
      route/main_setting.py
  13. 1 1
      route/main_setting_acl.py
  14. 7 5
      route/main_setting_external.py
  15. 1 1
      route/main_setting_head.py
  16. 1 1
      route/main_setting_main.py
  17. 1 1
      route/main_setting_main_logo.py
  18. 1 1
      route/main_setting_phrase.py
  19. 1 1
      route/main_setting_robot.py
  20. 1 1
      route/main_setting_sitemap.py
  21. 109 0
      route/main_setting_skin_set.py
  22. 1 1
      route/main_setting_top_menu.py
  23. 1 0
      route/main_tool_admin.py
  24. 0 0
      route/main_tool_guide.py
  25. 2 1
      route/main_tool_redirect.py
  26. 2 2
      route/main_view.py
  27. 2 2
      route/main_view_file.py
  28. 2 2
      route/main_view_image.py
  29. 65 58
      route/tool/func.py
  30. 2 1
      route/tool/func_render.py
  31. 117 85
      route/tool/func_render_namumark.py
  32. 16 1
      route/tool/func_tool.py
  33. 4 0
      route/topic.py
  34. 2 2
      route/user_setting.py
  35. 90 61
      route/user_setting_skin_set_main.py
  36. 2 2
      version.json
  37. 35 3
      views/main_css/css/main.css
  38. 5 1
      views/main_css/css/sub/dark.css
  39. 16 0
      views/main_css/js/func/func.js
  40. 1 0
      views/main_css/js/func/insert_user_info.js
  41. 0 444
      views/main_css/js/load_skin_set.js
  42. 0 107
      views/main_css/js/render_html.js
  43. 27 19
      views/main_css/js/route/editor.js
  44. 166 0
      views/main_css/js/route/render.js
  45. 1 2
      views/main_css/js/route/thread.js

+ 19 - 16
app.py

@@ -404,6 +404,8 @@ def give_admin_groups(name = None):
 def give_delete_admin_group(name = None):
 def give_delete_admin_group(name = None):
     return give_delete_admin_group_2(name)
     return give_delete_admin_group_2(name)
 
 
+app.route('/auth/give/fix/<user_name>', methods = ['POST', 'GET'])(give_user_fix)
+
 @app.route('/app_submit', methods = ['POST', 'GET'])
 @app.route('/app_submit', methods = ['POST', 'GET'])
 def recent_app_submit():
 def recent_app_submit():
     return recent_app_submit_2()
     return recent_app_submit_2()
@@ -646,21 +648,22 @@ app.route('/search_data/<int:num>/<everything:name>', defaults = { 'search_type'
 app.route('/goto', methods=['POST'])(main_search_goto)
 app.route('/goto', methods=['POST'])(main_search_goto)
 app.route('/goto/<everything:name>', methods=['POST'])(main_search_goto)
 app.route('/goto/<everything:name>', methods=['POST'])(main_search_goto)
 
 
-app.route('/setting')(main_func_setting)
-app.route('/setting/main', defaults = { 'db_set' : data_db_set['type'] }, methods = ['POST', 'GET'])(main_func_setting_main)
-app.route('/setting/main/logo', methods = ['POST', 'GET'])(main_func_setting_main_logo)
-app.route('/setting/top_menu', methods = ['POST', 'GET'])(main_func_setting_top_menu)
-app.route('/setting/phrase', methods = ['POST', 'GET'])(main_func_setting_phrase)
-app.route('/setting/head', defaults = { 'num' : 3 }, methods = ['POST', 'GET'])(main_func_setting_head)
-app.route('/setting/head/<skin_name>', defaults = { 'num' : 3 }, methods = ['POST', 'GET'])(main_func_setting_head)
-app.route('/setting/body/top', defaults = { 'num' : 4 }, methods = ['POST', 'GET'])(main_func_setting_head)
-app.route('/setting_preview/body/top', defaults = { 'num' : 4, 'set_preview' : 1 }, methods = ['POST'])(main_func_setting_head)
-app.route('/setting/body/bottom', defaults = { 'num' : 7 }, methods = ['POST', 'GET'])(main_func_setting_head)
-app.route('/setting_preview/body/bottom', defaults = { 'num' : 7, 'set_preview' : 1 }, methods = ['POST'])(main_func_setting_head)
-app.route('/setting/robot', methods = ['POST', 'GET'])(main_func_setting_robot)
-app.route('/setting/external', methods = ['POST', 'GET'])(main_func_setting_external)
-app.route('/setting/acl', methods = ['POST', 'GET'])(main_func_setting_acl)
-app.route('/setting/sitemap', methods = ['POST', 'GET'])(main_func_setting_sitemap)
+app.route('/setting')(main_setting)
+app.route('/setting/main', defaults = { 'db_set' : data_db_set['type'] }, methods = ['POST', 'GET'])(main_setting_main)
+app.route('/setting/main/logo', methods = ['POST', 'GET'])(main_setting_main_logo)
+app.route('/setting/top_menu', methods = ['POST', 'GET'])(main_setting_top_menu)
+app.route('/setting/phrase', methods = ['POST', 'GET'])(main_setting_phrase)
+app.route('/setting/head', defaults = { 'num' : 3 }, methods = ['POST', 'GET'])(main_setting_head)
+app.route('/setting/head/<skin_name>', defaults = { 'num' : 3 }, methods = ['POST', 'GET'])(main_setting_head)
+app.route('/setting/body/top', defaults = { 'num' : 4 }, methods = ['POST', 'GET'])(main_setting_head)
+app.route('/setting_preview/body/top', defaults = { 'num' : 4, 'set_preview' : 1 }, methods = ['POST'])(main_setting_head)
+app.route('/setting/body/bottom', defaults = { 'num' : 7 }, methods = ['POST', 'GET'])(main_setting_head)
+app.route('/setting_preview/body/bottom', defaults = { 'num' : 7, 'set_preview' : 1 }, methods = ['POST'])(main_setting_head)
+app.route('/setting/robot', methods = ['POST', 'GET'])(main_setting_robot)
+app.route('/setting/external', methods = ['POST', 'GET'])(main_setting_external)
+app.route('/setting/acl', methods = ['POST', 'GET'])(main_setting_acl)
+app.route('/setting/sitemap', methods = ['POST', 'GET'])(main_setting_sitemap)
+app.route('/setting/skin_set', methods = ['POST', 'GET'])(main_setting_skin_set)
 
 
 app.route('/easter_egg')(main_func_easter_egg)
 app.route('/easter_egg')(main_func_easter_egg)
 
 
@@ -675,7 +678,7 @@ app.route('/shutdown', methods = ['POST', 'GET'])(main_sys_shutdown)
 app.route('/restart', methods = ['POST', 'GET'])(main_sys_restart)
 app.route('/restart', methods = ['POST', 'GET'])(main_sys_restart)
 app.route('/update', methods = ['POST', 'GET'])(main_sys_update)
 app.route('/update', methods = ['POST', 'GET'])(main_sys_update)
 
 
-app.errorhandler(404)(main_error_404)
+app.errorhandler(404)(main_func_error_404)
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     waitress.serve(
     waitress.serve(

+ 1 - 17
emergency_tool.py

@@ -139,28 +139,12 @@ elif what_i_do == '6':
 
 
     curs.execute(db_change("update other set data = ? where name = 'skin'"), [skin])
     curs.execute(db_change("update other set data = ? where name = 'skin'"), [skin])
 elif what_i_do == '7':
 elif what_i_do == '7':
-    print('----')
-    print('1. sha256')
-    print('2. sha3')
-
-    print('----')
-    what_i_do = input('Select : ')
-
     print('----')
     print('----')
     user_name = input('User name : ')
     user_name = input('User name : ')
 
 
     print('----')
     print('----')
     user_pw = input('User password : ')
     user_pw = input('User password : ')
-
-    if what_i_do == '1':
-        hashed = hashlib.sha256(bytes(user_pw, 'utf-8')).hexdigest()
-    elif what_i_do == '2':
-        if sys.version_info < (3, 6):
-            hashed = sha3.sha3_256(bytes(user_pw, 'utf-8')).hexdigest()
-        else:
-            hashed = hashlib.sha3_256(bytes(user_pw, 'utf-8')).hexdigest()
-    else:
-        raise ValueError(what_i_do)
+    hashed = pw_encode(user_pw)
 
 
     curs.execute(db_change("update user_set set data = ? where id = ? and name = 'pw'"), [
     curs.execute(db_change("update user_set set data = ? where id = ? and name = 'pw'"), [
         hashed,
         hashed,

+ 16 - 7
lang/en-US.json

@@ -110,7 +110,11 @@
         "example" : "Example",
         "example" : "Example",
         "reset" : "Reset",
         "reset" : "Reset",
         "top" : "Top",
         "top" : "Top",
+        "bottom" : "Bottom",
         "use" : "Use",
         "use" : "Use",
+        "spread" : "Speard",
+        "popup" : "Popup",
+        "popover" : "Popover",
         "_comment_1.1_" : "Time",
         "_comment_1.1_" : "Time",
             "second" : "Second(s)",
             "second" : "Second(s)",
             "hour" : "Hour(s)",
             "hour" : "Hour(s)",
@@ -215,6 +219,7 @@
         "simple_check" : "Simple check",
         "simple_check" : "Simple check",
         "add_user" : "Add user",
         "add_user" : "Add user",
         "2fa" : "2FA",
         "2fa" : "2FA",
+        "2fa_off" : "2FA disabled",
         "2fa_password" : "2FA password",
         "2fa_password" : "2FA password",
         "2fa_password_change" : "Change 2FA password",
         "2fa_password_change" : "Change 2FA password",
         "history_reset" : "Document history reset",
         "history_reset" : "Document history reset",
@@ -234,6 +239,7 @@
         "document_set" : "Document settings",
         "document_set" : "Document settings",
         "user_added_menu" : "User added menu",
         "user_added_menu" : "User added menu",
         "move_redirect_make" : "Redirect document generation (Only if possible)",
         "move_redirect_make" : "Redirect document generation (Only if possible)",
+        "user_fix" : "Fix user",
         "_comment_" : "Edit",
         "_comment_" : "Edit",
             "load" : "Load another document",
             "load" : "Load another document",
             "turn_off_monaco" : "Turn off monaco editor",
             "turn_off_monaco" : "Turn off monaco editor",
@@ -288,7 +294,7 @@
                 "image_license_add" : "Add image license",
                 "image_license_add" : "Add image license",
                 "extension_filter_add" : "Add extension filter",
                 "extension_filter_add" : "Add extension filter",
                 "document_filter_add" : "Add document filter",
                 "document_filter_add" : "Add document filter",
-        "_comment_2.2_" : "Setting",
+        "_comment_" : "Setting",
             "setting" : "Setting",
             "setting" : "Setting",
             "restart_required" : "Restart required",
             "restart_required" : "Restart required",
             "adsense_setting" : "Adsense settings",
             "adsense_setting" : "Adsense settings",
@@ -296,15 +302,16 @@
             "skin_setting" : "Skin settings",
             "skin_setting" : "Skin settings",
             "main_acl_setting" : "Default ACL settings",
             "main_acl_setting" : "Default ACL settings",
             "top_menu_setting" : "Added menu setting",
             "top_menu_setting" : "Added menu setting",
-            "enter_top_menu_setting" : "Enter name in the upper line and URL in the lower line.",
-            "_comment_2.2.1_" : "List",
+            "main_skin_set_default" : "Main skin setting(s) default",
+
+            "_comment_" : "List",
                 "main_setting" : "Main settings",
                 "main_setting" : "Main settings",
                 "text_setting" : "Text settings",
                 "text_setting" : "Text settings",
                 "main_head" : "Global <HEAD>",
                 "main_head" : "Global <HEAD>",
                 "main_body" : "Top of body",
                 "main_body" : "Top of body",
                 "main_bottom_body" : "Bottom of body",
                 "main_bottom_body" : "Bottom of body",
                 "ext_api_req_set" : "External API required setting",
                 "ext_api_req_set" : "External API required setting",
-            "_comment_2.2.2_" : "Main",
+            "_comment_" : "Main",
                 "basic_set" : "Basic settings",
                 "basic_set" : "Basic settings",
                 "design_set" : "Design-related settings",
                 "design_set" : "Design-related settings",
                 "login_set" : "Login-related settings",
                 "login_set" : "Login-related settings",
@@ -345,7 +352,7 @@
                 "set_wiki_access_password_need" : "Password required for wiki access",
                 "set_wiki_access_password_need" : "Password required for wiki access",
                 "set_wiki_access_password" : "Wiki access password",
                 "set_wiki_access_password" : "Wiki access password",
                 "set_history_recording_off" : "Stop recording history",
                 "set_history_recording_off" : "Stop recording history",
-            "_comment_2.2.3_" : "Text",
+            "_comment_" : "Text",
                 "register_text" : "Terms of sign-up",
                 "register_text" : "Terms of sign-up",
                 "non_login_alert" : "Non-login alert",
                 "non_login_alert" : "Non-login alert",
                 "edit_bottom_text" : "Editing textarea bottom notice",
                 "edit_bottom_text" : "Editing textarea bottom notice",
@@ -365,13 +372,13 @@
                 "phrase_user_page_admin" : "Administrator user page phrase",
                 "phrase_user_page_admin" : "Administrator user page phrase",
                 "phrase_user_page_owner" : "Onwer user page phrase",
                 "phrase_user_page_owner" : "Onwer user page phrase",
                 "phrase_old_page_warring" : "Warning on previous revision document visit",
                 "phrase_old_page_warring" : "Warning on previous revision document visit",
-            "_comment_2.2.4_" : "Ext_API",
+            "_comment_" : "Ext_API",
                 "recaptcha" : "reCAPTCHA",
                 "recaptcha" : "reCAPTCHA",
                 "hcaptcha" : "hCAPTCHA",
                 "hcaptcha" : "hCAPTCHA",
                 "captcha" : "CAPTCHA",
                 "captcha" : "CAPTCHA",
                 
                 
                 "email_setting" : "Email settings",
                 "email_setting" : "Email settings",
-                "_comment_2.2.4.1_" : "SMTP",
+                "_comment_" : "SMTP",
                     "smtp_setting" : "Email SMTP settings",
                     "smtp_setting" : "Email SMTP settings",
                     "smtp_server" : "SMTP Server address",
                     "smtp_server" : "SMTP Server address",
                     "smtp_security": "SMTP Connection security",
                     "smtp_security": "SMTP Connection security",
@@ -382,6 +389,8 @@
                 "oauth" : "OAuth",
                 "oauth" : "OAuth",
                 "_comment_2.2.4.2_" : "OAuth",
                 "_comment_2.2.4.2_" : "OAuth",
                     "oauth_client_id" : "OAuth client ID",
                     "oauth_client_id" : "OAuth client ID",
+            "_comment_" : "Top",
+                "enter_top_menu_setting" : "Enter name in the upper line and URL in the lower line.",
             "_comment_" : "Sitemap",
             "_comment_" : "Sitemap",
                 "sitemap_management" : "sitemap.xml management",
                 "sitemap_management" : "sitemap.xml management",
                 "stiemap_exclude_domain" : "Exclude domain",
                 "stiemap_exclude_domain" : "Exclude domain",

+ 12 - 5
lang/ko-KR.json

@@ -492,12 +492,13 @@
     "namumark_fully_compatible_mode": "나무마크 디자인 호환 모드",
     "namumark_fully_compatible_mode": "나무마크 디자인 호환 모드",
     "added_menu": "추가 메뉴",
     "added_menu": "추가 메뉴",
     "top_menu_setting": "추가 메뉴 설정",
     "top_menu_setting": "추가 메뉴 설정",
-    "user_added_menu" : "사용자 추가 메뉴",
+    "user_added_menu": "사용자 추가 메뉴",
     "enter_top_menu_setting": "윗 줄에는 이름을 쓰고 아랫 줄에는 URL을 입력하세요.",
     "enter_top_menu_setting": "윗 줄에는 이름을 쓰고 아랫 줄에는 URL을 입력하세요.",
     "not_support_skin_warning": "이 기능을 미지원하는 스킨에서는 작동하지 않습니다.",
     "not_support_skin_warning": "이 기능을 미지원하는 스킨에서는 작동하지 않습니다.",
     "acl_thread_change": "스레드 ACL 변경",
     "acl_thread_change": "스레드 ACL 변경",
     "new_application": "새로운 가입 신청이 있습니다.",
     "new_application": "새로운 가입 신청이 있습니다.",
     "top": "상단",
     "top": "상단",
+    "bottom": "하단",
     "use": "사용",
     "use": "사용",
     "change_to_normal": "일반 글자로 변경",
     "change_to_normal": "일반 글자로 변경",
     "change_to_link": "링크로 변경",
     "change_to_link": "링크로 변경",
@@ -519,8 +520,14 @@
     "font_size": "글자 크기",
     "font_size": "글자 크기",
     "image_paste": "이미지 붙여넣기 (컨트롤 C + V로)",
     "image_paste": "이미지 붙여넣기 (컨트롤 C + V로)",
     "monaco_editor": "모나코 에디터",
     "monaco_editor": "모나코 에디터",
-    "document_set" : "문서 설정",
-    "move_redirect_make" : "리다이렉트 문서 생성 (가능한 경우에만)",
-    "slow_edit_acl" : "편집 속도 제한 시간 제외 대상 ACL",
-    "edit_bottom_compulsion_acl": "편집 사유 필수 제외 대상 ACL"
+    "document_set": "문서 설정",
+    "move_redirect_make": "리다이렉트 문서 생성 (가능한 경우에만)",
+    "slow_edit_acl": "편집 속도 제한 시간 제외 대상 ACL",
+    "edit_bottom_compulsion_acl": "편집 사유 필수 제외 대상 ACL",
+    "main_skin_set_default": "기본 스킨 설정 기본값",
+    "spread": "펼침",
+    "popup": "팝업",
+    "popover": "팝오버",
+    "user_fix" : "사용자 수정",
+    "2fa_off" : "2FA 끄기"
 }
 }

+ 1 - 1
requirements.txt

@@ -1,10 +1,10 @@
 flask
 flask
-
 waitress
 waitress
 
 
 requests
 requests
 
 
 pymysql
 pymysql
+whoosh
 
 
 diff-match-patch
 diff-match-patch
 
 

+ 5 - 0
route/api_setting.py

@@ -1,10 +1,15 @@
 from .tool.func import *
 from .tool.func import *
+from .user_setting_skin_set_main import user_setting_skin_set_main_set_list
 
 
 def api_setting(name = 'markup'):
 def api_setting(name = 'markup'):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
         
         
+        # from other
         ok_list_1 = ['markup']
         ok_list_1 = ['markup']
+        ok_list_1 += [for_a for for_a in user_setting_skin_set_main_set_list()]
+
+        # from html_filter
         ok_list_2 = ['inter_wiki']
         ok_list_2 = ['inter_wiki']
         
         
         if name in ok_list_1:
         if name in ok_list_1:

+ 4 - 10
route/edit.py

@@ -228,21 +228,15 @@ def edit(name = 'Test', section = 0, do_type = ''):
             sql_d = curs.fetchall()
             sql_d = curs.fetchall()
             p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
             p_text = html.escape(sql_d[0][0]) if sql_d and sql_d[0][0] != '' else load_lang('default_edit_help')
             
             
-            if ip_or_user(ip) == 0:
-                curs.execute(db_change('select data from user_set where name = "main_css_monaco" and id = ?'), [ip])
-                db_data = curs.fetchall()
-                monaco_on = db_data[0][0] if db_data else 'normal'
-            else:
-                monaco_on = flask.session['main_css_monaco'] if 'main_css_monaco' in flask.session else 'normal'
-            
+            monaco_on = get_main_skin_set(curs, flask.session, 'main_css_monaco', ip)
             if monaco_on == 'use':
             if monaco_on == 'use':
                 editor_display = 'style="display: none;"'
                 editor_display = 'style="display: none;"'
                 monaco_display = ''
                 monaco_display = ''
                 add_get_file = '''
                 add_get_file = '''
                     <link   rel="stylesheet"
                     <link   rel="stylesheet"
                             data-name="vs/editor/editor.main" 
                             data-name="vs/editor/editor.main" 
-                            href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/editor/editor.main.min.css">
-                    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs/loader.min.js"></script>
+                            href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/editor/editor.main.min.css">
+                    <script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs/loader.min.js"></script>
                 '''
                 '''
 
 
                 editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
                 editor_top_text += ' <a href="javascript:opennamu_edit_turn_off_monaco();">(' + load_lang('turn_off_monaco') + ')</a>'
@@ -253,7 +247,7 @@ def edit(name = 'Test', section = 0, do_type = ''):
                     monaco_thema = ''
                     monaco_thema = ''
                 
                 
                 add_script = '''
                 add_script = '''
-                    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.1/min/vs' }});
+                    require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.37.1/min/vs' }});
                     require.config({ 'vs/nls': { availableLanguages: { '*': 'ko' } }});
                     require.config({ 'vs/nls': { availableLanguages: { '*': 'ko' } }});
                     require(["vs/editor/editor.main"], function () {
                     require(["vs/editor/editor.main"], function () {
                         window.editor = monaco.editor.create(document.getElementById('opennamu_monaco_editor'), {
                         window.editor = monaco.editor.create(document.getElementById('opennamu_monaco_editor'), {

+ 2 - 0
route/filter_inter_wiki_add.py

@@ -101,6 +101,8 @@ def filter_inter_wiki_add(tool, name = None):
 
 
             return redirect('/' + re.sub(r'^plus_', '', tool))
             return redirect('/' + re.sub(r'^plus_', '', tool))
         else:
         else:
+            # 추가 편집 구분 필요
+            # 각 파일 별로 분리 필요
             get_sub = 0
             get_sub = 0
             stat = 'disabled' if admin_check() != 1 else ''
             stat = 'disabled' if admin_check() != 1 else ''
 
 

+ 70 - 0
route/give_user_fix.py

@@ -0,0 +1,70 @@
+from .tool.func import *
+
+def give_user_fix(user_name = ''):
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        curs.execute(db_change("select data from user_set where id = ? and name = 'pw'"), [user_name])
+        if not curs.fetchall():
+            return re_error('/error/2')
+
+        if admin_check() != 1:
+            return re_error('/error/3')
+
+        if flask.request.method == 'POST':
+            select = flask.request.form.get('select', '')
+            if select == 'password_change':
+                password = flask.request.form.get('new_password', '')
+                check_password = flask.request.form.get('password_check', '')
+
+                if password == check_password:
+                    hashed = pw_encode(password)
+                    curs.execute(db_change("update user_set set data = ? where id = ? and name = 'pw'"), [
+                        hashed,
+                        user_name
+                    ])
+                else:
+                    return re_error('/error/20')
+            elif select == '2fa_password_change':
+                password = flask.request.form.get('new_password', '')
+                check_password = flask.request.form.get('password_check', '')
+
+                if password == check_password:
+                    hashed = pw_encode(password)
+                    curs.execute(db_change('select data from user_set where name = "2fa_pw" and id = ?'), [user_name])
+                    if curs.fetchall():
+                        curs.execute(db_change("update user_set set data = ? where name = '2fa_pw' and id = ?"), [hashed, user_name])
+                    else:
+                        curs.execute(db_change("insert into user_set (name, id, data) values ('2fa_pw', ?, ?)"), [user_name, hashed])
+                else:
+                    return re_error('/error/20')
+            elif select == '2fa_off':
+                curs.execute(db_change('select data from user_set where name = "2fa" and id = ?'), [user_name])
+                if curs.fetchall():
+                    curs.execute(db_change("update user_set set data = '' where name = '2fa' and id = ?"), [user_name])
+
+            conn.commit()
+
+            return redirect('/user/' + url_pas(user_name))
+        else:
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('user_fix'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
+                data = '''
+                    <form method="post">
+                        <select name="select">
+                            <option value="password_change">''' + load_lang('password_change') + '''</option>
+                            <option value="2fa_password_change">''' + load_lang('2fa_password_change') + '''</option>
+                            <option value="2fa_off">''' + load_lang('2fa_off') + '''</option>
+                        </select>
+                        <hr class="main_hr">
+                        ''' + load_lang('password_change') + ''' | ''' + load_lang('2fa_password_change') + '''
+                        <hr class="main_hr">
+                        <input placeholder="''' + load_lang('new_password') + '''" name="new_password" type="password">
+                        <hr class="main_hr">
+                        <input placeholder="''' + load_lang('password_confirm') + '''" name="password_check" type="password">
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('go') + '''</button>
+                    </form>
+                ''',
+                menu = [['manager', load_lang('return')]]
+            ))

+ 2 - 2
route/login_login.py

@@ -64,8 +64,8 @@ def login_login_2():
                             <hr class="main_hr">
                             <hr class="main_hr">
                             <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
                             <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
                             <hr class="main_hr">
                             <hr class="main_hr">
-                            <!-- <input type="checkbox" name="auto_login"> ''' + load_lang('auto_login') + ''' (''' + load_lang('not_working') + ''') -->
-                            <hr class="main_hr">
+                            <!-- <input type="checkbox" name="auto_login"> ''' + load_lang('auto_login') + ''' (''' + load_lang('not_working') + ''')
+                            <hr class="main_hr"> -->
                             ''' + captcha_get() + '''
                             ''' + captcha_get() + '''
                             <button type="submit">''' + load_lang('login') + '''</button>
                             <button type="submit">''' + load_lang('login') + '''</button>
                             ''' + http_warning() + '''
                             ''' + http_warning() + '''

+ 1 - 1
route/main_error_404.py → route/main_func_error_404.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_error_404(e = ''):
+def main_func_error_404(e = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
         
         

+ 3 - 2
route/main_func_setting.py → route/main_setting.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting():
+def main_setting():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         li_list = [
         li_list = [
             ['main', load_lang('main_setting')],
             ['main', load_lang('main_setting')],
@@ -11,7 +11,8 @@ def main_func_setting():
             ['body/top', load_lang('main_body')],
             ['body/top', load_lang('main_body')],
             ['body/bottom', load_lang('main_bottom_body')],
             ['body/bottom', load_lang('main_bottom_body')],
             ['sitemap', load_lang('sitemap_management')],
             ['sitemap', load_lang('sitemap_management')],
-            ['top_menu', load_lang('top_menu_setting') + ' (' + load_lang('beta') + ')']
+            ['top_menu', load_lang('top_menu_setting')],
+            ['skin_set', load_lang('main_skin_set_default')],
         ]
         ]
 
 
         li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])
         li_data = ''.join(['<li><a href="/setting/' + str(li[0]) + '">' + li[1] + '</a></li>' for li in li_list])

+ 1 - 1
route/main_func_setting_acl.py → route/main_setting_acl.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_acl():
+def main_setting_acl():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 7 - 5
route/main_func_setting_external.py → route/main_setting_external.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_external():
+def main_setting_external():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 
@@ -93,11 +93,13 @@ def main_func_setting_external():
                             ''' + re_ver + '''
                             ''' + re_ver + '''
                         </select>
                         </select>
 
 
-                        <h2>''' + load_lang('email_setting') + '''</h1>
-                        <input type="checkbox" name="email_have" ''' + ('checked' if d_list[9] != '' else '')  + '''> ''' + \
-                             load_lang('email_required') + '''
+                        <h2>''' + load_lang('email_setting') + '''</h2>
+                        <a href="/setting/phrase#s-6">(''' + load_lang('text_setting') + ''')</a>
+                        <hr class="main_hr">
+
+                        <input type="checkbox" name="email_have" ''' + ('checked' if d_list[9] != '' else '')  + '''> ''' + load_lang('email_required') + '''
 
 
-                        <h2>''' + load_lang('smtp_setting') + '''</h1>
+                        <h3>''' + load_lang('smtp_setting') + '''</h3>
                         <a href="https://support.google.com/mail/answer/7126229">(Google)</a>
                         <a href="https://support.google.com/mail/answer/7126229">(Google)</a>
                         <hr class="main_hr">
                         <hr class="main_hr">
 
 

+ 1 - 1
route/main_func_setting_head.py → route/main_setting_head.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_head(num, skin_name = '', set_preview = 0):
+def main_setting_head(num, skin_name = '', set_preview = 0):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 1 - 1
route/main_func_setting_main.py → route/main_setting_main.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_main(db_set):
+def main_setting_main(db_set):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 1 - 1
route/main_func_setting_main_logo.py → route/main_setting_main_logo.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_main_logo():
+def main_setting_main_logo():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
         
         

+ 1 - 1
route/main_func_setting_phrase.py → route/main_setting_phrase.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_phrase():
+def main_setting_phrase():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 1 - 1
route/main_func_setting_robot.py → route/main_setting_robot.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_robot():
+def main_setting_robot():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 1 - 1
route/main_func_setting_sitemap.py → route/main_setting_sitemap.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_sitemap():
+def main_setting_sitemap():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 109 - 0
route/main_setting_skin_set.py

@@ -0,0 +1,109 @@
+from .tool.func import *
+from .user_setting_skin_set_main import user_setting_skin_set_main_set_list
+
+def main_setting_skin_set():
+    with get_db_connect() as conn:
+        curs = conn.cursor()
+
+        ip = ip_check()
+        if ban_check(ip) == 1:
+            return re_error('/ban')
+            
+        set_list = user_setting_skin_set_main_set_list()
+
+        if flask.request.method == 'POST':
+            for for_b in set_list:
+                curs.execute(db_change('select data from other where name = ?'), [for_b])
+                if curs.fetchall():
+                    curs.execute(db_change("update other set data = ? where name = ?"), [
+                        flask.request.form.get(for_b, set_list[for_b][0][0]),
+                        for_b
+                    ])
+                else:
+                    curs.execute(db_change('insert into other (name, data, coverage) values (?, ?, "")'), [
+                        for_b, 
+                        flask.request.form.get(for_b, set_list[for_b][0][0])
+                    ])
+            
+            conn.commit()
+
+            admin_check(None, 'edit_set (skin_set)')
+
+            return redirect('/setting/skin_set')
+        else:
+            set_data = {}
+            for for_b in set_list:
+                set_data[for_b] = ''
+
+                curs.execute(db_change('select data from other where name = ?'), [for_b])
+                db_data = curs.fetchall()
+                get_data = db_data[0][0] if db_data else ''
+
+                for for_a in set_list[for_b]:
+                    if get_data == for_a[0]:
+                        set_data[for_b] = '<option value="' + for_a[0] + '">' + for_a[1] + '</option>' + set_data[for_b]
+                    else:
+                        set_data[for_b] += '<option value="' + for_a[0] + '">' + for_a[1] + '</option>'
+
+            return easy_minify(flask.render_template(skin_check(),
+                imp = [load_lang('main_skin_set_default'), wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('beta') + ')', 0])],
+                data = render_simple_set('''
+                    <form method="post">
+                        <h2>''' + load_lang("render") + '''</h2>
+                        <h3>''' + load_lang("strike") + '''</h3>
+                        <select name="main_css_strike">
+                            ''' + set_data["main_css_strike"] + '''
+                        </select>
+                        <h3>''' + load_lang("bold") + '''</h3>
+                        <select name="main_css_bold">
+                            ''' + set_data["main_css_bold"] + '''
+                        </select>
+                        <h3>''' + load_lang("category") + '''</h3>
+                        <select name="main_css_category_set">
+                            ''' + set_data["main_css_category_set"] + '''
+                        </select>
+                        <h3>''' + load_lang("footnote") + '''</h3>
+                        <select name="main_css_footnote_set">
+                            ''' + set_data["main_css_footnote_set"] + '''
+                        </select>
+                        <h3>''' + load_lang("include_link") + '''</h3>
+                        <select name="main_css_include_link">
+                            ''' + set_data["main_css_include_link"] + '''
+                        </select>
+                        <h3>''' + load_lang("image") + '''</h3>
+                        <select name="main_css_image_set">
+                            ''' + set_data["main_css_image_set"] + '''
+                        </select>
+                        <h3>''' + load_lang("toc") + '''</h3>
+                        <select name="main_css_toc_set">
+                            ''' + set_data["main_css_toc_set"] + '''
+                        </select>
+                        <h3>''' + load_lang("exter_link") + '''</h3>
+                        <select name="main_css_exter_link">
+                            ''' + set_data["main_css_exter_link"] + '''
+                        </select>
+                        <h3>''' + load_lang("link_delimiter") + '''</h3>
+                        <select name="main_css_link_delimiter">
+                            ''' + set_data["main_css_link_delimiter"] + '''
+                        </select>
+                        <h3>''' + load_lang("force_darkmode") + ''' (''' + load_lang("not_working") + ''')</h3>
+                        <select name="main_css_darkmode">
+                            ''' + set_data["main_css_darkmode"] + '''
+                        </select>
+                        <h2>''' + load_lang("edit") + '''</h2>
+                        <h3>''' + load_lang("image_paste") + '''</h3>
+                        <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>
+                        <hr class="main_hr">
+                        <select name="main_css_image_paste">
+                            ''' + set_data["main_css_image_paste"] + '''
+                        </select>
+                        <h3>''' + load_lang("monaco_editor") + '''</h3>
+                        <select name="main_css_monaco">
+                            ''' + set_data["main_css_monaco"] + '''
+                        </select>
+                        <hr class="main_hr">
+                        <button type="submit">''' + load_lang('save') + '''</button>
+                    </form>
+                '''),
+                menu = [['setting', load_lang('return')]]
+            ))

+ 1 - 1
route/main_func_setting_top_menu.py → route/main_setting_top_menu.py

@@ -1,6 +1,6 @@
 from .tool.func import *
 from .tool.func import *
 
 
-def main_func_setting_top_menu():
+def main_setting_top_menu():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
 
 

+ 1 - 0
route/main_tool_admin.py

@@ -21,6 +21,7 @@ def main_tool_admin():
                     <li><a href="/app_submit">''' + load_lang('application_list') + '''</a></li>
                     <li><a href="/app_submit">''' + load_lang('application_list') + '''</a></li>
                     <li><a href="/register">''' + load_lang('add_user') + '''</a></li>
                     <li><a href="/register">''' + load_lang('add_user') + '''</a></li>
                     <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
                     <li><a href="/setting">''' + load_lang('setting') + '''</a></li>
+                    <li><a href="/manager/18">''' + load_lang('user_fix') + '''</a></li>
                 </ul>
                 </ul>
                 <h3>''' + load_lang('filter') + '''</h3>
                 <h3>''' + load_lang('filter') + '''</h3>
                 <ul class="opennamu_ul">
                 <ul class="opennamu_ul">

+ 0 - 0
route/main_tool_guide.py


+ 2 - 1
route/main_tool_redirect.py

@@ -18,7 +18,8 @@ def main_tool_redirect(num = 1, add_2 = ''):
             12 : [load_lang('compare_target'), 'check', load_lang('compare_target')],
             12 : [load_lang('compare_target'), 'check', load_lang('compare_target')],
             13 : [load_lang('document_name'), 'edit', load_lang('load')],
             13 : [load_lang('document_name'), 'edit', load_lang('load')],
             14 : [load_lang('document_name'), 'star_doc', load_lang('add_star_doc')],
             14 : [load_lang('document_name'), 'star_doc', load_lang('add_star_doc')],
-            15 : [load_lang('name_or_ip_or_regex'), 'auth/give/ban', load_lang('release')]
+            15 : [load_lang('name_or_ip_or_regex'), 'auth/give/ban', load_lang('release')],
+            16 : [0, 'auth/give/fix', load_lang('user_fix')],
         }
         }
         
         
         if num == 1:
         if num == 1:

+ 2 - 2
route/main_view.py

@@ -1,11 +1,11 @@
 from .tool.func import *
 from .tool.func import *
-from .main_error_404 import main_error_404
+from .main_func_error_404 import main_func_error_404
 
 
 def main_view(name = ''):
 def main_view(name = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         file_name = re.search(r'([^/]+)$', name)
         file_name = re.search(r'([^/]+)$', name)
         if not file_name:
         if not file_name:
-            return main_error_404()
+            return main_func_error_404()
         else:
         else:
             file_name = file_name.group(1)
             file_name = file_name.group(1)
             dir_name = './views/' + re.sub(r'\.{2,}', '', re.sub(r'([^/]+)$', '', name))
             dir_name = './views/' + re.sub(r'\.{2,}', '', re.sub(r'([^/]+)$', '', name))

+ 2 - 2
route/main_view_file.py

@@ -1,5 +1,5 @@
 from .tool.func import *
 from .tool.func import *
-from .main_error_404 import main_error_404
+from .main_func_error_404 import main_func_error_404
 
 
 def main_view_file(data = ''):
 def main_view_file(data = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
@@ -23,4 +23,4 @@ def main_view_file(data = ''):
             else:
             else:
                 return flask.send_from_directory('./', data, mimetype = 'text/xml')
                 return flask.send_from_directory('./', data, mimetype = 'text/xml')
         else:
         else:
-            return main_error_404()
+            return main_func_error_404()

+ 2 - 2
route/main_view_image.py

@@ -1,5 +1,5 @@
 from .tool.func import *
 from .tool.func import *
-from .main_error_404 import main_error_404
+from .main_func_error_404 import main_func_error_404
 
 
 def main_view_image(name = ''):
 def main_view_image(name = ''):
     with get_db_connect() as conn:
     with get_db_connect() as conn:
@@ -14,4 +14,4 @@ def main_view_image(name = ''):
                 mimetype = 'image/' + mime_type
                 mimetype = 'image/' + mime_type
             )
             )
         else:
         else:
-            return main_error_404()
+            return main_func_error_404()

+ 65 - 58
route/tool/func.py

@@ -67,7 +67,8 @@ else:
 print('----')
 print('----')
 
 
 # Init-Load
 # Init-Load
-from .func_render import *
+from .func_tool import *
+from .func_render import class_do_render
 
 
 from diff_match_patch import diff_match_patch
 from diff_match_patch import diff_match_patch
 
 
@@ -182,6 +183,9 @@ class get_db_connect:
         load_conn(self.conn_sub)
         load_conn(self.conn_sub)
         self.conn.close()
         self.conn.close()
 
 
+# class get_whoosh_connect:
+    
+
 class class_check_json:
 class class_check_json:
     def do_check_set_json():
     def do_check_set_json():
         if os.getenv('NAMU_DB') or os.getenv('NAMU_DB_TYPE'):
         if os.getenv('NAMU_DB') or os.getenv('NAMU_DB_TYPE'):
@@ -596,15 +600,6 @@ def update(ver_num, set_data):
             for for_b in db_table_list[for_a]:
             for for_b in db_table_list[for_a]:
                 curs.execute(db_change("update " + for_a + " set " + for_b + " = '' where " + for_b + " is null"))
                 curs.execute(db_change("update " + for_a + " set " + for_b + " = '' where " + for_b + " is null"))
                 
                 
-    if ver_num < 3500112:
-        # curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
-        curs.execute(db_change('select id from user_set where name = "email"'))
-        for db_data in curs.fetchall():
-            if ip_or_user(db_data[0]) == 1:
-                curs.execute(db_change(
-                    'delete from user_set where id = ? and name = "email"'
-                ), [db_data[0]])
-                
     if ver_num < 3500113:
     if ver_num < 3500113:
         db_table_list = get_db_table_list()
         db_table_list = get_db_table_list()
         for for_a in db_table_list:
         for for_a in db_table_list:
@@ -660,9 +655,19 @@ def update(ver_num, set_data):
 
 
         print("Update 3500360 complete")
         print("Update 3500360 complete")
 
 
+    if ver_num < 3500361:
+        # curs.execute(db_change('select id from user_set where name = "email" and data = ?'), [user_email])
+        curs.execute(db_change('select id from user_set where name = "email"'))
+        for db_data in curs.fetchall():
+            if ip_or_user(db_data[0]) == 1:
+                curs.execute(db_change(
+                    'delete from user_set where id = ? and name = "email"'
+                ), [db_data[0]])
+
+#    if ver_num < 3500361:
+
+
     conn.commit()
     conn.commit()
-    
-    # 아이피 상태인 이메일 제거 예정
 
 
     print('Update completed')
     print('Update completed')
 
 
@@ -1105,8 +1110,9 @@ def wiki_css(data):
     # Route JS + Defer
     # Route JS + Defer
     data_css += '<script defer src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
     data_css += '<script defer src="/views/main_css/js/route/thread.js?ver=' + data_css_ver + '"></script>'
     
     
-    # 레거시 일반 JS
-    data_css += '<script src="/views/main_css/js/load_editor.js?ver=' + data_css_ver + '"></script>'
+    # Route JS
+    data_css += '<script src="/views/main_css/js/route/editor.js?ver=' + data_css_ver + '"></script>'
+    data_css += '<script src="/views/main_css/js/route/render.js?ver=' + data_css_ver + '"></script>'
     
     
     # Main CSS
     # Main CSS
     data_css += '<link rel="stylesheet" href="/views/main_css/css/main.css?ver=' + data_css_ver + '">'
     data_css += '<link rel="stylesheet" href="/views/main_css/css/main.css?ver=' + data_css_ver + '">'
@@ -1115,8 +1121,8 @@ def wiki_css(data):
     data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/styles/default.min.css">'
     data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/styles/default.min.css">'
     data_css += '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/highlight.min.js"></script>'
     data_css += '<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.5.0/build/highlight.min.js"></script>'
     
     
-    data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.css" integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous">'
-    data_css += '<script src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script>'
+    data_css += '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css" integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">'
+    data_css += '<script src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js" integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>'
 
 
     data = data[0:2] + ['', data_css] + data[2:]
     data = data[0:2] + ['', data_css] + data[2:]
 
 
@@ -1486,51 +1492,52 @@ def render_simple_set(data):
 def send_email(who, title, data):
 def send_email(who, title, data):
     curs = conn.cursor()
     curs = conn.cursor()
 
 
-    try:
-        curs.execute(db_change('' + \
-            'select name, data from other ' + \
-            'where name = "smtp_email" or name = "smtp_pass" or name = "smtp_server" or name = "smtp_port" or name = "smtp_security"' + \
-        ''))
-        rep_data = curs.fetchall()
+    curs.execute(db_change('' + \
+        'select name, data from other ' + \
+        'where name = "smtp_email" or name = "smtp_pass" or name = "smtp_server" or name = "smtp_port" or name = "smtp_security"' + \
+    ''))
+    rep_data = curs.fetchall()
 
 
-        smtp_email = ''
-        smtp_pass = ''
-        smtp_server = ''
-        smtp_security = ''
-        smtp_port = ''
-        smtp = ''
-
-        for i in rep_data:
-            if i[0] == 'smtp_email':
-                smtp_email = i[1]
-            elif i[0] == 'smtp_pass':
-                smtp_pass = i[1]
-            elif i[0] == 'smtp_server':
-                smtp_server = i[1]
-            elif i[0] == 'smtp_security':
-                smtp_security = i[1]
-            elif i[0] == 'smtp_port':
-                smtp_port = i[1]
-        
-        smtp_port = int(smtp_port)
-        if smtp_security == 'plain':
-            smtp = smtplib.SMTP(smtp_server, smtp_port)
-        elif smtp_security == 'starttls':
-            smtp = smtplib.SMTP(smtp_server, smtp_port)
-            smtp.starttls()
-        else:
-            # if smtp_security == 'tls':
-            smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
+    smtp_email = ''
+    smtp_pass = ''
+    smtp_server = ''
+    smtp_security = ''
+    smtp_port = ''
+    smtp = ''
+
+    for i in rep_data:
+        if i[0] == 'smtp_email':
+            smtp_email = i[1]
+        elif i[0] == 'smtp_pass':
+            smtp_pass = i[1]
+        elif i[0] == 'smtp_server':
+            smtp_server = i[1]
+        elif i[0] == 'smtp_security':
+            smtp_security = i[1]
+        elif i[0] == 'smtp_port':
+            smtp_port = i[1]
+    
+    smtp_port = int(number_check(smtp_port))
+    if smtp_security == 'plain':
+        smtp = smtplib.SMTP(smtp_server, smtp_port)
+    elif smtp_security == 'starttls':
+        smtp = smtplib.SMTP(smtp_server, smtp_port)
+        smtp.starttls()
+    else:
+        # if smtp_security == 'tls':
+        smtp = smtplib.SMTP_SSL(smtp_server, smtp_port)
         
         
-        smtp.login(smtp_email, smtp_pass)
+    domain = load_domain()
+    wiki_name = wiki_set()[0]
+    
+    msg = email.mime.text.MIMEText(data)
 
 
-        domain = load_domain()
-        wiki_name = wiki_set()[0]
-        
-        msg = email.mime.text.MIMEText(data)
-        msg['Subject'] = title
-        msg['From'] = 'openNAMU <noreply@' + domain + '>'
-        msg['To'] = who
+    msg['Subject'] = title
+    msg['From'] = wiki_name + ' <noreply@' + domain + '>'
+    msg['To'] = who
+
+    try:
+        smtp.login(smtp_email, smtp_pass)
         
         
         smtp.sendmail('openNAMU@' + domain, who, msg.as_string())
         smtp.sendmail('openNAMU@' + domain, who, msg.as_string())
         smtp.quit()
         smtp.quit()

+ 2 - 1
route/tool/func_render.py

@@ -1,4 +1,5 @@
-from .func_render_namumark import *
+from .func_tool import *
+from .func_render_namumark import class_do_render_namumark
 
 
 # 커스텀 마크 언젠간 다시 추가 예정
 # 커스텀 마크 언젠간 다시 추가 예정
 
 

+ 117 - 85
route/tool/func_render_namumark.py

@@ -16,7 +16,7 @@ class class_do_render_namumark:
             self.ip = '0.0.0.0'
             self.ip = '0.0.0.0'
 
 
         try:
         try:
-            if 'main_css_bold' in self.flask_session:
+            if 'main_css_bold' in flask.session:
                 pass    
                 pass    
                 
                 
             self.flask_session = flask.session
             self.flask_session = flask.session
@@ -25,6 +25,8 @@ class class_do_render_namumark:
 
 
         try:
         try:
             self.darkmode = flask.request.cookies.get('main_css_darkmode', '0')
             self.darkmode = flask.request.cookies.get('main_css_darkmode', '0')
+            if self.darkmode == 'default':
+                self.darkmode = '0'
         except:
         except:
             self.darkmode = '0'
             self.darkmode = '0'
 
 
@@ -161,7 +163,7 @@ class class_do_render_namumark:
             else:
             else:
                 data += '<a id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '" href="#' + self.doc_include + 'rfn_' + self.data_footnote[for_a]['list'][0] + '">(' + for_a + ') </a> '
                 data += '<a id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '" href="#' + self.doc_include + 'rfn_' + self.data_footnote[for_a]['list'][0] + '">(' + for_a + ') </a> '
 
 
-            data += '<footnote_title target="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '">' + self.data_footnote[for_a]['data'] + '</footnote_title>'
+            data += '<footnote_title id="' + self.doc_include + 'fn_' + self.data_footnote[for_a]['list'][0] + '_title">' + self.data_footnote[for_a]['data'] + '</footnote_title>'
 
 
         if data != '':
         if data != '':
             data += '</div>'
             data += '</div>'
@@ -188,21 +190,16 @@ class class_do_render_namumark:
 
 
     def do_render_text(self):
     def do_render_text(self):
         # <b> function
         # <b> function
-        if ip_or_user(self.ip) == 0:
-            self.curs.execute(db_change('select data from user_set where name = "main_css_bold" and id = ?'), [self.ip])
-            db_data = self.curs.fetchall()
-            bold_user_set = db_data[0][0] if db_data else 'normal'
-        else:
-            bold_user_set = self.flask_session['main_css_bold'] if 'main_css_bold' in self.flask_session else 'normal'
+        bold_user_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_bold', self.ip)
 
 
         def do_render_text_bold(match):
         def do_render_text_bold(match):
             data = match.group(1)
             data = match.group(1)
-            if bold_user_set == 'normal':
-                data_name = self.get_tool_data_storage('<b>', '</b>', match.group(0))
+            if bold_user_set == 'delete':
+                return ''
             elif bold_user_set == 'change':
             elif bold_user_set == 'change':
                 data_name = self.get_tool_data_storage('', '', match.group(0))
                 data_name = self.get_tool_data_storage('', '', match.group(0))
             else:
             else:
-                return ''
+                data_name = self.get_tool_data_storage('<b>', '</b>', match.group(0))
             
             
             return '<' + data_name + '>' + data + '</' + data_name + '>'
             return '<' + data_name + '>' + data + '</' + data_name + '>'
 
 
@@ -254,21 +251,16 @@ class class_do_render_namumark:
         self.render_data = re.sub(r",,((?:(?!,,).)+),,", do_render_text_sub, self.render_data)
         self.render_data = re.sub(r",,((?:(?!,,).)+),,", do_render_text_sub, self.render_data)
 
 
         # <s> function
         # <s> function
-        if ip_or_user(self.ip) == 0:
-            self.curs.execute(db_change('select data from user_set where name = "main_css_strike" and id = ?'), [self.ip])
-            db_data = self.curs.fetchall()
-            strike_user_set = db_data[0][0] if db_data else 'normal'
-        else:
-            strike_user_set = self.flask_session['main_css_strike'] if 'main_css_strike' in self.flask_session else 'normal'
+        strike_user_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_strike', self.ip)
 
 
         def do_render_text_strike(match):
         def do_render_text_strike(match):
             data = match.group(1)
             data = match.group(1)
-            if strike_user_set == 'normal':
-                data_name = self.get_tool_data_storage('<s>', '</s>', match.group(0))
+            if strike_user_set == 'delete':
+                return ''
             elif strike_user_set == 'change':
             elif strike_user_set == 'change':
                 data_name = self.get_tool_data_storage('', '', match.group(0))
                 data_name = self.get_tool_data_storage('', '', match.group(0))
             else:
             else:
-                return ''
+                data_name = self.get_tool_data_storage('<s>', '</s>', match.group(0))
             
             
             return '<' + data_name + '>' + data + '</' + data_name + '>'
             return '<' + data_name + '>' + data + '</' + data_name + '>'
         
         
@@ -335,26 +327,6 @@ class class_do_render_namumark:
 
 
                     toc_list += [['', heading_data_text]]
                     toc_list += [['', heading_data_text]]
 
 
-                    self.render_data_js += '''
-                        function opennamu_heading_folding(data, element = '') {
-                            let fol = document.getElementById(data);
-                            if(fol.style.display === '' || fol.style.display === 'inline-block' || fol.style.display === 'block') {
-                                document.getElementById(data).style.display = 'none';
-                            } else {
-                                document.getElementById(data).style.display = 'block';
-                            }
-                            
-                            if(element !== '') {
-                                console.log(element.innerHTML);
-                                if(element.innerHTML !== '⊖') {
-                                    element.innerHTML = '⊖';
-                                } else {
-                                    element.innerHTML = '⊕';
-                                }
-                            }
-                        }\n
-                    '''
-
                     heading_folding = ['⊖', 'block']
                     heading_folding = ['⊖', 'block']
                     if heading_data[2]:
                     if heading_data[2]:
                         heading_folding = ['⊕', 'none']
                         heading_folding = ['⊕', 'none']
@@ -667,7 +639,7 @@ class class_do_render_namumark:
             data = html.unescape(data)
             data = html.unescape(data)
             data = self.get_tool_js_safe(data)
             data = self.get_tool_js_safe(data)
 
 
-            name_ob = 'opennamu_math_' + str(self.data_math_count)
+            name_ob = self.doc_include + 'opennamu_math_' + str(self.data_math_count)
 
 
             data_name = self.get_tool_data_storage('<span id="' + name_ob + '">' + data_html, '</span>', match.group(0))
             data_name = self.get_tool_data_storage('<span id="' + name_ob + '">' + data_html, '</span>', match.group(0))
 
 
@@ -686,10 +658,14 @@ class class_do_render_namumark:
             return '<' + data_name + '></' + data_name + '>'
             return '<' + data_name + '></' + data_name + '>'
 
 
         math_regex = re.compile('\[math\(((?:(?!\[math\(|\)\]).|\n)+)\)\]', re.I)
         math_regex = re.compile('\[math\(((?:(?!\[math\(|\)\]).|\n)+)\)\]', re.I)
+        math_regex_2 = re.compile('&lt;math&gt;((?:(?!&lt;math&gt;|&lt;\/math&gt;).)+)&lt;\/math&gt;', re.I)
+
+        self.render_data = re.sub(math_regex_2, do_render_math_sub, self.render_data)
         self.render_data = re.sub(math_regex, do_render_math_sub, self.render_data)
         self.render_data = re.sub(math_regex, do_render_math_sub, self.render_data)
 
 
     def do_render_link(self):
     def do_render_link(self):
         link_regex = r'\[\[((?:(?!\[\[|\]\]|\||<|>).|<slash_[0-9]+>)+)(?:\|((?:(?!\[\[|\]\]|\|).)+))?\]\]'
         link_regex = r'\[\[((?:(?!\[\[|\]\]|\||<|>).|<slash_[0-9]+>)+)(?:\|((?:(?!\[\[|\]\]|\|).)+))?\]\]'
+        image_count = 0
         link_count_all = len(re.findall(link_regex, self.render_data)) * 4
         link_count_all = len(re.findall(link_regex, self.render_data)) * 4
         while 1:
         while 1:
             if not re.search(link_regex, self.render_data):
             if not re.search(link_regex, self.render_data):
@@ -794,12 +770,18 @@ class class_do_render_namumark:
                     if file_bgcolor != '':
                     if file_bgcolor != '':
                         file_bgcolor = 'background:' + self.get_tool_css_safe(file_bgcolor) + ';'
                         file_bgcolor = 'background:' + self.get_tool_css_safe(file_bgcolor) + ';'
 
 
-                    file_end = '<img style="' + file_width + file_height + file_align_style + file_bgcolor + '" alt="' + link_sub + '" src="' + link_main + '">'
+
+                    image_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_image_set', self.ip)
+                    if image_set == 'new_click' or image_set == 'click':
+                        file_end = '<img style="' + file_width + file_height + file_align_style + file_bgcolor + '" id="opennamu_image_' + str(image_count) + '" alt="' + link_sub + '" src="">'
+                    else:
+                        file_end = '<img style="' + file_width + file_height + file_align_style + file_bgcolor + '" alt="' + link_sub + '" src="' + link_main + '">'
+
                     if file_align == 'center':
                     if file_align == 'center':
                         file_end = '<div style="text-align:center;">' + file_end + '</div>'
                         file_end = '<div style="text-align:center;">' + file_end + '</div>'
 
 
                     if link_exist != '':
                     if link_exist != '':
-                        data_name = self.get_tool_data_storage('<a class="' + link_exist + '" title="' + link_sub + '" href="/upload?name=' + url_pas(link_main_org) + '">' + link_sub, '</a>', link_data_full)
+                        data_name = self.get_tool_data_storage('<a class="' + link_exist + '" title="' + link_sub + '" href="/upload?name=' + url_pas(link_main_org) + '">(' + link_sub, ')</a>', link_data_full)
                         self.render_data = re.sub(link_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
                         self.render_data = re.sub(link_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
                     else:
                     else:
                         file_pass = 0
                         file_pass = 0
@@ -813,9 +795,23 @@ class class_do_render_namumark:
 
 
                         if file_pass == 1:
                         if file_pass == 1:
                             if file_out == 0:
                             if file_out == 0:
-                                data_name = self.get_tool_data_storage('<a title="' + link_sub + '" href="/w/file:' + url_pas(link_main_org) + '.' + url_pas(link_extension) + '">' + file_end, '</a>', link_data_full)
+                                file_link = '/w/file:' + url_pas(link_main_org) + '.' + url_pas(link_extension)
+                            else:
+                                file_link = link_main
+
+                            if image_set == 'new_click':
+                                data_name = self.get_tool_data_storage('<a title="' + link_sub + '" id="opennamu_image_' + str(image_count) + '_link" href="javascript:void(0);">' + file_end, '</a>', link_data_full)
+                                self.render_data_js += '''
+                                    document.getElementById("opennamu_image_''' + str(image_count) + '''_link").addEventListener("click", function(e) {
+                                        document.getElementById("opennamu_image_''' + str(image_count) + '''").src = "''' + self.get_tool_js_safe(link_main) + '''";
+                                        setTimeout(function() {
+                                            document.getElementById("opennamu_image_''' + str(image_count) + '''_link").href = "''' + self.get_tool_js_safe(file_link) + '''";
+                                        }, 100);
+                                    });\n
+                                '''
+                                image_count += 1
                             else:
                             else:
-                                data_name = self.get_tool_data_storage('<a title="' + link_sub + '" href="' + link_main + '">' + file_end, '</a>', link_data_full)
+                                data_name = self.get_tool_data_storage('<a title="' + link_sub + '" href="' + file_link + '">' + file_end, '</a>', link_data_full)
                         else:
                         else:
                             data_name = self.get_tool_data_storage('', '', link_data_full)
                             data_name = self.get_tool_data_storage('', '', link_data_full)
                         
                         
@@ -1069,6 +1065,7 @@ class class_do_render_namumark:
                     return slash_add + match[2]
                     return slash_add + match[2]
 
 
         include_num = 0
         include_num = 0
+        include_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_include_link', self.ip)
         include_regex = re.compile('\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\]', re.I)
         include_regex = re.compile('\[include\(((?:(?!\[include\(|\)\]|<\/div>).)+)\)\]', re.I)
         include_count_max = len(re.findall(include_regex, self.render_data)) * 2
         include_count_max = len(re.findall(include_regex, self.render_data)) * 2
         include_change_list = {}
         include_change_list = {}
@@ -1122,13 +1119,6 @@ class class_do_render_namumark:
                         include_data = db_data[0][0].replace('\r', '')
                         include_data = db_data[0][0].replace('\r', '')
 
 
                         # include link func
                         # include link func
-                        if ip_or_user(self.ip) == 0:
-                            self.curs.execute(db_change('select data from user_set where name = "main_css_include_link" and id = ?'), [self.ip])
-                            db_data = self.curs.fetchall()
-                            include_set_data = db_data[0][0] if db_data else 'normal'
-                        else:
-                            include_set_data = self.flask_session['main_css_include_link'] if 'main_css_include_link' in self.flask_session else 'normal'
-
                         include_link = ''
                         include_link = ''
                         if include_set_data == 'use':
                         if include_set_data == 'use':
                             include_link = '<div><a href="/w/' + url_pas(include_name) + '">(' + include_name_org + ')</a></div>'
                             include_link = '<div><a href="/w/' + url_pas(include_name) + '">(' + include_name_org + ')</a></div>'
@@ -1159,6 +1149,7 @@ class class_do_render_namumark:
 
 
     def do_redner_footnote(self):
     def do_redner_footnote(self):
         footnote_num = 0
         footnote_num = 0
+        footnote_set = get_main_skin_set(self.curs, self.flask_session, 'main_css_footnote_set', self.ip)
         footnote_regex = re.compile('(?:\[\*((?:(?!\[\*|\]| ).)+)?(?: ((?:(?!\[\*|\]).)+))?\]|\[(각주|footnote)\])', re.I)
         footnote_regex = re.compile('(?:\[\*((?:(?!\[\*|\]| ).)+)?(?: ((?:(?!\[\*|\]).)+))?\]|\[(각주|footnote)\])', re.I)
         footnote_count_all = len(re.findall(footnote_regex, self.render_data)) * 4
         footnote_count_all = len(re.findall(footnote_regex, self.render_data)) * 4
         while 1:
         while 1:
@@ -1189,21 +1180,63 @@ class class_do_render_namumark:
                     else:
                     else:
                         footnote_text_data = footnote_data[1]
                         footnote_text_data = footnote_data[1]
 
 
+                    fn = ''
+                    rfn = ''
+                    foot_v_name = ''
+
                     if footnote_name in self.data_footnote:
                     if footnote_name in self.data_footnote:
                         self.data_footnote[footnote_name]['list'] += [footnote_num_str]
                         self.data_footnote[footnote_name]['list'] += [footnote_num_str]
                         footnote_first = self.data_footnote[footnote_name]['list'][0]
                         footnote_first = self.data_footnote[footnote_name]['list'][0]
 
 
-                        data_name = self.get_tool_data_storage('<sup><a fn_target="' + self.doc_include + 'fn_' + footnote_first + '" id="' + self.doc_include + 'rfn_' + footnote_num_str + '" href="#' + self.doc_include + 'fn_' + footnote_first + '">(' + footnote_name + ' (' + footnote_num_str + ')' + ')</a></sup>', '', footnote_data_org)
-
-                        self.render_data = re.sub(footnote_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+                        fn = self.doc_include + 'fn_' + footnote_first
+                        rfn = self.doc_include + 'rfn_' + footnote_num_str
+                        foot_v_name = footnote_name + ' (' + footnote_num_str + ')'
                     else:
                     else:
                         self.data_footnote[footnote_name] = {}
                         self.data_footnote[footnote_name] = {}
                         self.data_footnote[footnote_name]['list'] = [footnote_num_str]
                         self.data_footnote[footnote_name]['list'] = [footnote_num_str]
                         self.data_footnote[footnote_name]['data'] = footnote_text_data
                         self.data_footnote[footnote_name]['data'] = footnote_text_data
 
 
-                        data_name = self.get_tool_data_storage('<sup><a fn_target="' + self.doc_include + 'fn_' + footnote_num_str + '" id="' + self.doc_include + 'rfn_' + footnote_num_str + '" href="#' + self.doc_include + 'fn_' + footnote_num_str + '">(' + footnote_name + footnote_name_add + ')</a></sup>', '', footnote_data_org)
+                        fn = self.doc_include + 'fn_' + footnote_num_str
+                        rfn = self.doc_include + 'rfn_' + footnote_num_str
+                        foot_v_name = footnote_name + footnote_name_add
+
+                    if footnote_set == 'spread':
+                        data_name = self.get_tool_data_storage(
+                            '<sup>' + \
+                                '<a fn_target="' + fn + '" id="' + rfn + '" href="javascript:void(0);">(' + foot_v_name + ')</a>' + \
+                            '</sup>' + \
+                            '<span class="opennamu_spead_footnote" id="' + rfn + '_load" style="display: none;"></span>',
+                            '',
+                            footnote_data_org
+                        )
+                        self.render_data_js += 'document.getElementById("' + rfn + '").addEventListener("click", function() { opennamu_do_footnote_spread("' + rfn + '", "' + fn + '"); });\n'
+                    elif footnote_set == 'popup':
+                        data_name = self.get_tool_data_storage(
+                            '<sup>' + \
+                                '<a fn_target="' + fn + '" id="' + rfn + '" href="javascript:void(0);">(' + foot_v_name + ')</a>' + \
+                            '</sup>' + \
+                            '<span class="opennamu_spead_footnote" id="' + rfn + '_load" style="display: none;"></span>',
+                            '',
+                            footnote_data_org
+                        )
+                        self.render_data_js += 'document.getElementById("' + rfn + '").addEventListener("click", function() { opennamu_do_footnote_spread("' + rfn + '", "' + fn + '"); });\n'
+                    elif footnote_set == 'popover':
+                        data_name = self.get_tool_data_storage(
+                            '<span id="' + rfn + '_over">' + \
+                                '<sup>' + \
+                                    '<a fn_target="' + fn + '" id="' + rfn + '" href="javascript:void(0);">(' + foot_v_name + ')</a>' + \
+                                '</sup>' + \
+                                '<span class="opennamu_popup_footnote" id="' + rfn + '_load" style="display: none;"></span>' + \
+                            '</span>',
+                            '',
+                            footnote_data_org
+                        )
+                        self.render_data_js += 'document.getElementById("' + rfn + '_over").addEventListener("mouseenter", function() { opennamu_do_footnote_popover("' + rfn + '", "' + fn + '"); });\n'
+                        self.render_data_js += 'document.getElementById("' + rfn + '_over").addEventListener("mouseleave", function() { opennamu_do_footnote_popover("' + rfn + '", "' + fn + '"); });\n'
+                    else:
+                        data_name = self.get_tool_data_storage('<sup><a fn_target="' + fn + '" id="' + rfn + '" href="#' + fn + '">(' + foot_v_name + ')</a></sup>', '', footnote_data_org)
 
 
-                        self.render_data = re.sub(footnote_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
+                    self.render_data = re.sub(footnote_regex, '<' + data_name + '></' + data_name + '>', self.render_data, 1)
 
 
             footnote_count_all -= 1
             footnote_count_all -= 1
 
 
@@ -1445,10 +1478,12 @@ class class_do_render_namumark:
             table_count_all -= 1
             table_count_all -= 1
     
     
     def do_render_middle(self):
     def do_render_middle(self):
-        middle_regex = r'{{{([^{](?:(?!{{{|}}}).|\n)*)?(?:}|<(\/?(?:slash)_(?:[0-9]+))>)}}'
         wiki_count = 0
         wiki_count = 0
+        html_count = 0
         syntax_count = 0
         syntax_count = 0
         folding_count = 0
         folding_count = 0
+
+        middle_regex = r'{{{([^{](?:(?!{{{|}}}).|\n)*)?(?:}|<(\/?(?:slash)_(?:[0-9]+))>)}}'
         middle_count_all = len(re.findall(middle_regex, self.render_data)) * 10
         middle_count_all = len(re.findall(middle_regex, self.render_data)) * 10
         while 1:
         while 1:
             middle_data = re.search(middle_regex, self.render_data)
             middle_data = re.search(middle_regex, self.render_data)
@@ -1503,12 +1538,19 @@ class class_do_render_namumark:
                         data_name = self.get_tool_data_storage('<div id="' + self.doc_include + 'opennamu_wiki_' + str(wiki_count) + '"></div>', '', middle_data_org)
                         data_name = self.get_tool_data_storage('<div id="' + self.doc_include + 'opennamu_wiki_' + str(wiki_count) + '"></div>', '', middle_data_org)
                         wiki_count += 1
                         wiki_count += 1
                     elif middle_name == '#!html':
                     elif middle_name == '#!html':
+                        html_data = re.sub(r'^#!html ', '', middle_data)
                         if middle_slash:
                         if middle_slash:
-                            middle_data_org = re.sub(r'<(\/?(?:slash)_(?:[0-9]+))>', '<temp_' + middle_slash + '>', middle_data_org)
-                            self.render_data = re.sub(middle_regex, lambda x : middle_data_org, self.render_data, 1)
-                            continue
+                            html_data += '\\'
 
 
-                        data_name = self.get_tool_data_storage('', '', middle_data_org)
+                        data_revert = self.get_tool_data_revert(html_data)
+                        data_revert = re.sub(r'^\n', '', data_revert)
+                        data_revert = re.sub(r'\n$', '', data_revert)
+                        data_revert = re.sub(r'&amp;nbsp;', '&nbsp;', data_revert)
+
+                        self.render_data_js += 'opennamu_do_render_html("' + self.doc_include + 'opennamu_wiki_' + str(html_count) + '");\n'
+
+                        data_name = self.get_tool_data_storage('<span id="' + self.doc_include + 'opennamu_wiki_' + str(html_count) + '">' + data_revert, '</span>', middle_data_org)
+                        html_count += 1
                     elif middle_name == '#!folding':
                     elif middle_name == '#!folding':
                         if middle_slash:
                         if middle_slash:
                             middle_data_org = re.sub(r'<(\/?(?:slash)_(?:[0-9]+))>', '<temp_' + middle_slash + '>', middle_data_org)
                             middle_data_org = re.sub(r'<(\/?(?:slash)_(?:[0-9]+))>', '<temp_' + middle_slash + '>', middle_data_org)
@@ -1664,8 +1706,8 @@ class class_do_render_namumark:
                             middle_data += '\\'
                             middle_data += '\\'
 
 
                         data_revert = self.get_tool_data_revert(middle_data)
                         data_revert = self.get_tool_data_revert(middle_data)
-                        data_revert = re.sub('^\n', '', data_revert)
-                        data_revert = re.sub('\n$', '', data_revert)
+                        data_revert = re.sub(r'^\n', '', data_revert)
+                        data_revert = re.sub(r'\n$', '', data_revert)
 
 
                         data_name = self.get_tool_data_storage(data_revert, '', middle_data_org)
                         data_name = self.get_tool_data_storage(data_revert, '', middle_data_org)
                 else:
                 else:
@@ -1673,8 +1715,8 @@ class class_do_render_namumark:
                         middle_data += '\\'
                         middle_data += '\\'
 
 
                     data_revert = self.get_tool_data_revert(middle_data)
                     data_revert = self.get_tool_data_revert(middle_data)
-                    data_revert = re.sub('^\n', '', data_revert)
-                    data_revert = re.sub('\n$', '', data_revert)
+                    data_revert = re.sub(r'^\n', '', data_revert)
+                    data_revert = re.sub(r'\n$', '', data_revert)
 
 
                     data_name = self.get_tool_data_storage(data_revert, '', middle_data_org)
                     data_name = self.get_tool_data_storage(data_revert, '', middle_data_org)
 
 
@@ -1770,14 +1812,8 @@ class class_do_render_namumark:
             if self.data_category != '':
             if self.data_category != '':
                 data_name = self.get_tool_data_storage(self.data_category, '</div>', '')
                 data_name = self.get_tool_data_storage(self.data_category, '</div>', '')
 
 
-                if ip_or_user(self.ip) == 0:
-                    self.curs.execute(db_change('select data from user_set where name = "main_css_category_set" and id = ?'), [self.ip])
-                    db_data = self.curs.fetchall()
-                    category_set_data = db_data[0][0] if db_data else 'normal'
-                else:
-                    category_set_data = self.flask_session['main_css_category_set'] if 'main_css_category_set' in self.flask_session else 'normal'
-
-                if category_set_data == 'normal':
+                category_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_category_set', self.ip)
+                if category_set_data == 'bottom':
                     if re.search(r'<footnote_category>', self.render_data):
                     if re.search(r'<footnote_category>', self.render_data):
                         self.render_data = re.sub(r'<footnote_category>', '<hr><' + data_name + '></' + data_name + '>', self.render_data, 1)
                         self.render_data = re.sub(r'<footnote_category>', '<hr><' + data_name + '></' + data_name + '>', self.render_data, 1)
                     else:
                     else:
@@ -1852,26 +1888,22 @@ class class_do_render_namumark:
             self.data_toc = toc_data
             self.data_toc = toc_data
             self.data_toc = re.sub(r'<toc_inside>((?:(?!<toc_inside>|<\/toc_inside>).)*)<\/toc_inside>', do_render_last_toc, self.data_toc)
             self.data_toc = re.sub(r'<toc_inside>((?:(?!<toc_inside>|<\/toc_inside>).)*)<\/toc_inside>', do_render_last_toc, self.data_toc)
 
 
-            if ip_or_user(self.ip) == 0:
-                self.curs.execute(db_change('select data from user_set where name = "main_css_toc_set" and id = ?'), [self.ip])
-                db_data = self.curs.fetchall()
-                toc_set_data = db_data[0][0] if db_data else 'normal'
-            else:
-                toc_set_data = self.flask_session['main_css_toc_set'] if 'main_css_toc_set' in self.flask_session else 'normal'
+            toc_set_data = get_main_skin_set(self.curs, self.flask_session, 'main_css_toc_set', self.ip)
 
 
             self.render_data = re.sub(toc_search_regex, '', self.render_data)
             self.render_data = re.sub(toc_search_regex, '', self.render_data)
-            if toc_set_data != 'off':
+            if toc_set_data == 'off':
+                self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
+            else:
                 if re.search(r'<toc_need_part>', self.render_data):
                 if re.search(r'<toc_need_part>', self.render_data):
                     toc_data_on = 1
                     toc_data_on = 1
 
 
                 self.render_data = re.sub(r'<toc_need_part>', lambda x : (self.data_toc), self.render_data, 20)
                 self.render_data = re.sub(r'<toc_need_part>', lambda x : (self.data_toc), self.render_data, 20)
                 self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
                 self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
-            else:
-                self.render_data = re.sub(r'<toc_need_part>', '', self.render_data)
 
 
             if  self.doc_include != '' or \
             if  self.doc_include != '' or \
                 re.search(r'<toc_no_auto>', self.render_data) or \
                 re.search(r'<toc_no_auto>', self.render_data) or \
-                toc_set_data != 'normal' or \
+                toc_set_data == 'half_off' or \
+                toc_set_data == 'off' or \
                 toc_data_on == 1:
                 toc_data_on == 1:
                 self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
                 self.render_data = re.sub(r'<toc_no_auto>', '', self.render_data)
             else:
             else:
@@ -1883,7 +1915,7 @@ class class_do_render_namumark:
         def do_render_last_footnote(match):
         def do_render_last_footnote(match):
             match = match.group(1)
             match = match.group(1)
 
 
-            find_regex = re.compile('<footnote_title target="' + match + '">((?:(?!<footnote_title|<\/footnote_title>).)*)<\/footnote_title>')
+            find_regex = re.compile('<footnote_title id="' + match + '_title">((?:(?!<footnote_title|<\/footnote_title>).)*)<\/footnote_title>')
             find_data = re.search(find_regex, self.render_data)
             find_data = re.search(find_regex, self.render_data)
             if find_data:
             if find_data:
                 find_data = find_data.group(1)
                 find_data = find_data.group(1)

+ 16 - 1
route/tool/func_tool.py

@@ -68,4 +68,19 @@ def sha224_replace(data):
     return hashlib.sha224(bytes(data, 'utf-8')).hexdigest()
     return hashlib.sha224(bytes(data, 'utf-8')).hexdigest()
 
 
 def md5_replace(data):
 def md5_replace(data):
-    return hashlib.md5(data.encode()).hexdigest()
+    return hashlib.md5(data.encode()).hexdigest()
+
+def get_main_skin_set(curs, flask_session, set_name, ip):
+    if ip_or_user(ip) == 0:
+        curs.execute(db_change('select data from user_set where name = ? and id = ?'), [set_name, ip])
+        db_data = curs.fetchall()
+        set_data = db_data[0][0] if db_data else 'default'
+    else:
+        set_data = flask_session[set_name] if set_name in flask_session and flask_session[set_name] != '' else 'default'
+
+    if set_data == 'default':
+        curs.execute(db_change('select data from other where name = ?'), [set_name])
+        db_data = curs.fetchall()
+        set_data = db_data[0][0] if db_data and db_data[0][0] != '' else 'default'
+
+    return set_data

+ 4 - 0
route/topic.py

@@ -1,4 +1,8 @@
 from .tool.func import *
 from .tool.func import *
+from .api_topic import api_topic
+
+def topic_make(data, ip_first = ''):
+    data = ''
 
 
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
 def topic(topic_num = 0, do_type = '', doc_name = 'Test'):
     with get_db_connect() as conn:
     with get_db_connect() as conn:

+ 2 - 2
route/user_setting.py

@@ -18,15 +18,15 @@ def user_setting():
                     ['user_title', flask.request.form.get('user_title', '')]
                     ['user_title', flask.request.form.get('user_title', '')]
                 ]
                 ]
 
 
-                twofa_turn_on = 0 
                 twofa_on = flask.request.form.get('2fa', '')
                 twofa_on = flask.request.form.get('2fa', '')
                 if twofa_on != '':
                 if twofa_on != '':
-                    twofa_turn_on = 1
                     twofa_pw = flask.request.form.get('2fa_pw', '')
                     twofa_pw = flask.request.form.get('2fa_pw', '')
                     if twofa_pw != '':
                     if twofa_pw != '':
                         twofa_pw = pw_encode(twofa_pw)
                         twofa_pw = pw_encode(twofa_pw)
+
                         curs.execute(db_change("select data from user_set where id = ? and name = 'encode'"), [ip])
                         curs.execute(db_change("select data from user_set where id = ? and name = 'encode'"), [ip])
                         twofa_encode = curs.fetchall()[0][0]
                         twofa_encode = curs.fetchall()[0][0]
+                        
                         auto_list += [['2fa', 'on'], ['2fa_pw', twofa_pw], ['2fa_pw_encode', twofa_encode]]
                         auto_list += [['2fa', 'on'], ['2fa_pw', twofa_pw], ['2fa_pw_encode', twofa_encode]]
                     else:
                     else:
                         auto_list += [['2fa', 'on']]
                         auto_list += [['2fa', 'on']]

+ 90 - 61
route/user_setting_skin_set_main.py

@@ -1,5 +1,66 @@
 from .tool.func import *
 from .tool.func import *
 
 
+def user_setting_skin_set_main_set_list():
+    set_list = {
+        'main_css_strike' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['change', load_lang('change_to_normal')],
+            ['delete', load_lang('delete')]
+        ], 'main_css_bold' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['change', load_lang('change_to_normal')],
+            ['delete', load_lang('delete')]
+        ], 'main_css_include_link' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['use', load_lang('use')]
+        ], 'main_css_image_paste' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['use', load_lang('use')]
+        ], 'main_css_category_set' : [
+            ['default', load_lang('default')],
+            ['bottom', load_lang('bottom')],
+            ['top', load_lang('top')]
+        ], 'main_css_footnote_set' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('normal')],
+            ['spread', load_lang('spread')],
+            ['popup', load_lang('popup') + ' (' + load_lang('not_working') + ')'],
+            ['popover', load_lang('popover')]
+        ], 'main_css_image_set' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('normal')],
+            ['click', load_lang('change_to_link')],
+            ['new_click', load_lang('click_load')]
+        ], 'main_css_toc_set' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('normal')],
+            ['off', load_lang('all_off')],
+            ['half_off', load_lang('in_content')]
+        ], 'main_css_monaco' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['use', load_lang('use')]
+        ], 'main_css_exter_link' : [
+            ['default', load_lang('default')],
+            ['blank', load_lang('normal')],
+            ['self', load_lang('self_tab')]
+        ], 'main_css_link_delimiter' : [
+            ['default', load_lang('default')],
+            ['normal', load_lang('off')],
+            ['use', load_lang('use')]
+        ], 'main_css_darkmode' : [
+            ['default', load_lang('default')],
+            ['0', load_lang('off')],
+            ['1', load_lang('use')]
+        ]
+    }
+
+    return set_list
+
 def user_setting_skin_set_main():
 def user_setting_skin_set_main():
     with get_db_connect() as conn:
     with get_db_connect() as conn:
         curs = conn.cursor()
         curs = conn.cursor()
@@ -8,51 +69,7 @@ def user_setting_skin_set_main():
         if ban_check(ip) == 1:
         if ban_check(ip) == 1:
             return re_error('/ban')
             return re_error('/ban')
             
             
-        set_list = {
-            'main_css_strike' : [
-                ['normal', load_lang('default')],
-                ['change', load_lang('change_to_normal')],
-                ['delete', load_lang('delete')]
-            ], 'main_css_bold' : [
-                ['normal', load_lang('default')],
-                ['change', load_lang('change_to_normal')],
-                ['delete', load_lang('delete')]
-            ], 'main_css_include_link' : [
-                ['normal', load_lang('default')],
-                ['use', load_lang('use')]
-            ], 'main_css_image_paste' : [
-                ['normal', load_lang('default')],
-                ['use', load_lang('use')]
-            ], 'main_css_category_set' : [
-                ['bottom', load_lang('default')],
-                ['top', load_lang('top')]
-            ], 'main_css_footnote_set' : [
-                ['normal', load_lang('default')],
-                ['spread', load_lang('spread')]
-            ], 'main_css_image_set' : [
-                ['normal', load_lang('default')],
-                ['click', load_lang('change_to_link')],
-                ['new_click', load_lang('click_load')]
-            ], 'main_css_toc_set' : [
-                ['normal', load_lang('default')],
-                ['off', load_lang('all_off')],
-                ['half_off', load_lang('in_content')]
-            ], 'main_css_monaco' : [
-                ['normal', load_lang('default')],
-                ['use', load_lang('use')]
-            ], 'main_css_exter_link' : [
-                ['blank', load_lang('default')],
-                ['self', load_lang('self_tab')]
-            ], 'main_css_link_delimiter' : [
-                ['normal', load_lang('default')],
-                ['use', load_lang('use')]
-            ], 'main_css_darkmode' : [
-                ['0', load_lang('default')],
-                ['1', load_lang('use')]
-            ], 'main_css_font_size' : [
-                ['']
-            ]
-        }
+        set_list = user_setting_skin_set_main_set_list()
         use_cookie = ['main_css_image_paste', 'main_css_darkmode']
         use_cookie = ['main_css_image_paste', 'main_css_darkmode']
 
 
         if flask.request.method == 'POST':
         if flask.request.method == 'POST':
@@ -94,72 +111,84 @@ def user_setting_skin_set_main():
                 else:
                 else:
                     get_data = flask.session[for_b] if for_b in flask.session else ''
                     get_data = flask.session[for_b] if for_b in flask.session else ''
 
 
-                if set_list[for_b][0] == ['']:
-                    set_data[for_b] = get_data
-                else:
-                    for for_a in set_list[for_b]:
-                        if get_data == for_a[0]:
-                            set_data[for_b] = '<option value="' + for_a[0] + '">' + for_a[1] + '</option>' + set_data[for_b]
-                        else:
-                            set_data[for_b] += '<option value="' + for_a[0] + '">' + for_a[1] + '</option>'
+                for for_a in set_list[for_b]:
+                    if get_data == for_a[0]:
+                        set_data[for_b] = '<option value="' + for_a[0] + '">' + for_a[1] + '</option>' + set_data[for_b]
+                    else:
+                        set_data[for_b] += '<option value="' + for_a[0] + '">' + for_a[1] + '</option>'
+
+            set_data_main = {}
+            for for_b in set_list:
+                curs.execute(db_change('select data from other where name = ?'), [for_b])
+                db_data = curs.fetchall()
+                server_default = db_data[0][0] if db_data else 'default'
+                set_data_main[for_b] = load_lang('default') + ' : ' + ''.join([for_a[1] for for_a in set_list[for_b] if for_a[0] == server_default]) + '<hr class="main_hr">'
 
 
             return easy_minify(flask.render_template(skin_check(),
             return easy_minify(flask.render_template(skin_check(),
-                imp = [load_lang('main_skin_set'), wiki_set(), wiki_custom(), wiki_css(['(' + load_lang('beta') + ')', 0])],
+                imp = [load_lang('main_skin_set'), wiki_set(), wiki_custom(), wiki_css([0, 0])],
                 data = render_simple_set('''
                 data = render_simple_set('''
                     <form method="post">
                     <form method="post">
                         <h2>''' + load_lang("render") + '''</h2>
                         <h2>''' + load_lang("render") + '''</h2>
                         <h3>''' + load_lang("strike") + '''</h3>
                         <h3>''' + load_lang("strike") + '''</h3>
+                        ''' + set_data_main["main_css_strike"] + '''
                         <select name="main_css_strike">
                         <select name="main_css_strike">
                             ''' + set_data["main_css_strike"] + '''
                             ''' + set_data["main_css_strike"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("bold") + '''</h3>
                         <h3>''' + load_lang("bold") + '''</h3>
+                        ''' + set_data_main["main_css_bold"] + '''
                         <select name="main_css_bold">
                         <select name="main_css_bold">
                             ''' + set_data["main_css_bold"] + '''
                             ''' + set_data["main_css_bold"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("category") + '''</h3>
                         <h3>''' + load_lang("category") + '''</h3>
+                        ''' + set_data_main["main_css_category_set"] + '''
                         <select name="main_css_category_set">
                         <select name="main_css_category_set">
                             ''' + set_data["main_css_category_set"] + '''
                             ''' + set_data["main_css_category_set"] + '''
                         </select>
                         </select>
-                        <h3>''' + load_lang("footnote") + '''</h3>
+                        <h3>''' + load_lang("footnote") + ''' (''' + load_lang('beta') + ''')</h3>
+                        ''' + set_data_main["main_css_footnote_set"] + '''
                         <select name="main_css_footnote_set">
                         <select name="main_css_footnote_set">
                             ''' + set_data["main_css_footnote_set"] + '''
                             ''' + set_data["main_css_footnote_set"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("include_link") + '''</h3>
                         <h3>''' + load_lang("include_link") + '''</h3>
+                        ''' + set_data_main["main_css_include_link"] + '''
                         <select name="main_css_include_link">
                         <select name="main_css_include_link">
                             ''' + set_data["main_css_include_link"] + '''
                             ''' + set_data["main_css_include_link"] + '''
                         </select>
                         </select>
-                        <h3>''' + load_lang("image") + ''' (''' + load_lang("not_working") + ''')</h3>
+                        <h3>''' + load_lang("image") + ''' (''' + load_lang('beta') + ''')</h3>
+                        ''' + set_data_main["main_css_image_set"] + '''
                         <select name="main_css_image_set">
                         <select name="main_css_image_set">
                             ''' + set_data["main_css_image_set"] + '''
                             ''' + set_data["main_css_image_set"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("toc") + '''</h3>
                         <h3>''' + load_lang("toc") + '''</h3>
+                        ''' + set_data_main["main_css_toc_set"] + '''
                         <select name="main_css_toc_set">
                         <select name="main_css_toc_set">
                             ''' + set_data["main_css_toc_set"] + '''
                             ''' + set_data["main_css_toc_set"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("exter_link") + '''</h3>
                         <h3>''' + load_lang("exter_link") + '''</h3>
+                        ''' + set_data_main["main_css_exter_link"] + '''
                         <select name="main_css_exter_link">
                         <select name="main_css_exter_link">
                             ''' + set_data["main_css_exter_link"] + '''
                             ''' + set_data["main_css_exter_link"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("link_delimiter") + '''</h3>
                         <h3>''' + load_lang("link_delimiter") + '''</h3>
+                        ''' + set_data_main["main_css_link_delimiter"] + '''
                         <select name="main_css_link_delimiter">
                         <select name="main_css_link_delimiter">
                             ''' + set_data["main_css_link_delimiter"] + '''
                             ''' + set_data["main_css_link_delimiter"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("force_darkmode") + '''</h3>
                         <h3>''' + load_lang("force_darkmode") + '''</h3>
+                        ''' + set_data_main["main_css_darkmode"] + '''
                         <select name="main_css_darkmode">
                         <select name="main_css_darkmode">
                             ''' + set_data["main_css_darkmode"] + '''
                             ''' + set_data["main_css_darkmode"] + '''
                         </select>
                         </select>
-                        <h3>''' + load_lang("font_size") + '''</h3>
-                        (EX : 11) (''' + load_lang('off') + ''' : ''' + load_lang('empty') + ''')
-                        <hr class="main_hr">
-                        <input id="main_css_font_size" value="''' + set_data["main_css_font_size"] + '''">
-                        <h2>''' + load_lang("editor") + '''</h2>
+                        <h2>''' + load_lang("edit") + '''</h2>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <h3>''' + load_lang("image_paste") + '''</h3>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>
                         <sup>''' + load_lang('only_korean') + '''</sup> <sup>''' + load_lang('unavailable_in_monaco') + '''</sup>
                         <hr class="main_hr">
                         <hr class="main_hr">
+                        ''' + set_data_main["main_css_image_paste"] + '''
                         <select name="main_css_image_paste">
                         <select name="main_css_image_paste">
                             ''' + set_data["main_css_image_paste"] + '''
                             ''' + set_data["main_css_image_paste"] + '''
                         </select>
                         </select>
                         <h3>''' + load_lang("monaco_editor") + '''</h3>
                         <h3>''' + load_lang("monaco_editor") + '''</h3>
+                        ''' + set_data_main["main_css_monaco"] + '''
                         <select name="main_css_monaco">
                         <select name="main_css_monaco">
                             ''' + set_data["main_css_monaco"] + '''
                             ''' + set_data["main_css_monaco"] + '''
                         </select>
                         </select>

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
 {
     "beta" : {
     "beta" : {
-        "c_ver" : "3500360",
-        "r_ver" : "v3.4.6-RC3-dev151",
+        "r_ver" : "v3.4.6-RC3-dev161",
+        "c_ver" : "3500361",
         "s_ver" : "3500111"
         "s_ver" : "3500111"
     }
     }
 }
 }

+ 35 - 3
views/main_css/css/main.css

@@ -196,6 +196,12 @@ pre, #redirect {
 
 
 pre {    
 pre {    
     white-space: pre-wrap;
     white-space: pre-wrap;
+
+    margin: 0;
+}
+
+#syntax {
+    padding: 0;
 }
 }
 
 
 .opennamu_textarea_500 {
 .opennamu_textarea_500 {
@@ -213,6 +219,26 @@ pre {
     border: 1px solid #cecece;
     border: 1px solid #cecece;
 }
 }
 
 
+.opennamu_popup_footnote {
+    position: absolute;
+
+    z-index: 10000;
+
+    max-width: 50%;
+
+    padding: 10px;
+
+    background-color: #efefef;
+    
+    border: 1px solid #cecece;
+}
+
+@media ( max-width: 768px ) {
+    .opennamu_popup_footnote {
+        max-width: 100%;
+    }
+}
+
 hr {
 hr {
     border: 0;
     border: 0;
     border-top: 1px solid gainsboro;
     border-top: 1px solid gainsboro;
@@ -247,9 +273,6 @@ s, strike, del {
 }
 }
 
 
 s:hover, strike:hover, del:hover {
 s:hover, strike:hover, del:hover {
-    color: gray;
-    background-color: gainsboro;
-    
     text-decoration: none;
     text-decoration: none;
 }
 }
 
 
@@ -293,3 +316,12 @@ s:hover, strike:hover, del:hover {
 .change_space {
 .change_space {
     white-space: pre-line;
     white-space: pre-line;
 }
 }
+
+.katex {
+    max-width: 100%;
+
+    display: inline-block;
+
+    overflow-x: scroll;
+    overflow-y: hidden;
+}

+ 5 - 1
views/main_css/css/sub/dark.css

@@ -57,7 +57,11 @@ blockquote {
     border-left: 5px solid #eee;
     border-left: 5px solid #eee;
 }
 }
 
 
-.spead_footnote {
+.opennamu_spead_footnote {
     background-color: black;
     background-color: black;
     color: white;
     color: white;
 }
 }
+
+.opennamu_popup_footnote {
+    background-color: black;
+}

+ 16 - 0
views/main_css/js/func/func.js

@@ -14,4 +14,20 @@ function opennamu_do_url_encode(data) {
 
 
 function opennamu_cookie_split_regex(data) {
 function opennamu_cookie_split_regex(data) {
     return new RegExp('(?:^|; )' + data + '=([^;]*)');
     return new RegExp('(?:^|; )' + data + '=([^;]*)');
+}
+
+function opennamu_get_main_skin_set(set_name) {
+    return fetch("/api/setting/" + opennamu_do_url_encode(set_name)).then(function(res) {
+        return res.json();
+    }).then(function(text) {
+        if(
+            document.cookie.match(opennamu_cookie_split_regex(set_name)) &&
+            document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== '' &&
+            document.cookie.match(opennamu_cookie_split_regex(set_name))[1] !== 'default'
+        ) {
+            return document.cookie.match(opennamu_cookie_split_regex(set_name))[1];
+        } else {
+            return text[set_name][0][0];
+        }
+    });
 }
 }

+ 1 - 0
views/main_css/js/func/insert_user_info.js

@@ -1,5 +1,6 @@
 "use strict";
 "use strict";
 
 
+// 폐지하고 다시 SSR 방식으로 전환 예정
 function do_insert_user_info() {
 function do_insert_user_info() {
     if(document.getElementById('opennamu_get_user_info')) {
     if(document.getElementById('opennamu_get_user_info')) {
         let name = document.getElementById('opennamu_get_user_info').innerHTML;
         let name = document.getElementById('opennamu_get_user_info').innerHTML;

+ 0 - 444
views/main_css/js/load_skin_set.js

@@ -1,444 +0,0 @@
-function main_css_get_post() {    
-    var check = document.getElementById('main_css_strike');
-    if(check.value === 'normal') {
-        document.cookie = 'main_css_del_strike=0; path=/;';
-    } else if(check.value === 'change') {
-        document.cookie = 'main_css_del_strike=1; path=/;';
-    } else {
-        document.cookie = 'main_css_del_strike=2; path=/;';
-    }
-
-    check = document.getElementById('main_css_bold');
-    if(check.value === 'normal') {
-        document.cookie = 'main_css_del_bold=0; path=/;';
-    } else if(check.value === 'change') {
-        document.cookie = 'main_css_del_bold=1; path=/;';
-    } else {
-        document.cookie = 'main_css_del_bold=2; path=/;';
-    }
-
-    check = document.getElementById('main_css_include');
-    if(check.checked) {
-        document.cookie = 'main_css_include_link=1; path=/;';
-    } else {
-        document.cookie = 'main_css_include_link=0; path=/;';
-    }
-
-    check = document.getElementById('main_css_category');
-    if(check.value === 'bottom') {
-        document.cookie = 'main_css_category_set=0; path=/;';
-    } else {
-        document.cookie = 'main_css_category_set=1; path=/;';
-    }
-
-    check = document.getElementById('main_css_footnote');
-    if(check.value === 'spread') {
-        document.cookie = 'main_css_footnote_set=1; path=/;';
-    } else {
-        document.cookie = 'main_css_footnote_set=0; path=/;';
-    }
-
-    check = document.getElementById('main_css_image');
-    if(check.value === 'new_click') {
-        document.cookie = 'main_css_image_set=2; path=/;';
-    } else if(check.value === 'click') {
-        document.cookie = 'main_css_image_set=1; path=/;';
-    } else {
-        document.cookie = 'main_css_image_set=0; path=/;';
-    }
-
-    check = document.getElementById('main_css_image_paste');
-    if(check.checked) {
-        document.cookie = 'main_css_image_paste=1; path=/;';
-    } else {
-        document.cookie = 'main_css_image_paste=0; path=/;';
-    }
-
-    check = document.getElementById('main_css_toc');
-    if(check.value === 'on') {
-        document.cookie = 'main_css_toc_set=2; path=/;';
-    } else if(check.value === 'off') {
-        document.cookie = 'main_css_toc_set=1; path=/;';
-    } else {
-        document.cookie = 'main_css_toc_set=0; path=/;';
-    }
-    
-    check = document.getElementById('main_css_font_size');
-    if(check.value.match(/^[0-9]+$/)) {
-        document.cookie = 'main_css_font_size=' + check.value + '; path=/;';
-    } else {
-        document.cookie = 'main_css_font_size=; path=/;';
-    }
-
-    check = document.getElementById('main_css_monaco');
-    if(check.checked) {
-        document.cookie = 'main_css_monaco=1; path=/;';
-    } else {
-        document.cookie = 'main_css_monaco=0; path=/;';
-    }
-    
-    check = document.getElementById('main_css_exter_link');
-    if(check.value === 'self') {
-        document.cookie = 'main_css_exter_link=1; path=/;';
-    } else {
-        document.cookie = 'main_css_exter_link=0; path=/;';
-    }
-    
-    check = document.getElementById('main_css_link_delimiter');
-    if(check.checked) {
-        document.cookie = 'main_css_link_delimiter=1; path=/;';
-    } else {
-        document.cookie = 'main_css_link_delimiter=0; path=/;';
-    }
-    
-    history.go(0);
-}
-
-function main_css_skin_load() {    
-    var head_data = document.querySelector('head');
-    if(document.cookie.match(opennamu_cookie_split_regex('main_css_toc_set'))) {
-        if(document.cookie.match(opennamu_cookie_split_regex('main_css_toc_set'))[1] === '2') {
-            head_data.innerHTML += '<style>#auto_toc { display: none; }</style>';
-        } else if(document.cookie.match(opennamu_cookie_split_regex('main_css_toc_set'))[1] === '1') {
-            head_data.innerHTML += '<style>#toc { display: none; }</style>';
-        }
-    }
-    
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_font_size')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_font_size'))[1] !== ''
-    ) {
-        head_data.innerHTML += '<style>body, input, textarea { font-size: ' + document.cookie.match(opennamu_cookie_split_regex('main_css_font_size'))[1] + 'px; }</style>';
-    }
-    
-    /* 개편 필요 */
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_link_delimiter')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_link_delimiter'))[1] === '1'
-    ) {
-        head_data.innerHTML += '<style>#real_normal_link::before, #not_thing::before, #inside::before { content: \'🅸\'; font-weight: lighter; background: transparent; }</style>';
-    }
-}
-
-function main_css_load_lang(name) {
-    var set_language = {
-        "en-US" : {
-            "default" : "Default",
-            "change_to_normal" : "Change to normal text",
-            "delete" : "Delete",
-            "include_link" : "Using include link",
-            "save" : "Save",
-            "strike" : "Strike",
-            "bold" : "Bold",
-            "other" : "Other",
-            "where_category" : "Set category location",
-            "bottom" : "Bottom",
-            "top" : "Top",
-            "set_footnote" : "Set footnote",
-            "renderer" : "Renderer",
-            "spread" : "Spread",
-            "set_image" : "Set image",
-            "set_toc" : "Set TOC",
-            "click_load" : "Load on click",
-            "in_content" : "Only when TOC is in the document",
-            "all_off" : "Always off",
-            "set_font_size" : "Set font size",
-            "change_to_link" : "Change to link",
-            "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",
-            "self_tab" : "Current tab",
-            "exter_link_open_method" : "External link",
-            "link_delimiter" : "Add link delimiter"
-        }, "ko-KR" : {
-            "default" : "기본값",
-            "change_to_normal" : "일반 텍스트로 변경",
-            "delete" : "삭제",
-            "include_link" : "틀 링크 사용",
-            "save" : "저장",
-            "strike" : "취소선",
-            "bold" : "볼드체",
-            "other" : "기타",
-            "where_category" : "분류 위치 설정",
-            "bottom" : "아래",
-            "top" : "위",
-            "set_footnote" : "각주 설정",
-            "renderer" : "렌더러",
-            "spread" : "펼치기",
-            "set_image" : "이미지 설정",
-            "set_toc" : "목차 설정",
-            "click_load" : "클릭시 불러오기",
-            "in_content" : "문서 안에 있을 때만",
-            "all_off" : "항상 끔",
-            "set_font_size" : "글자 크기 설정",
-            "change_to_link" : "링크로 변경",
-            "font_size" : "글자 크기",
-            "editor" : "편집기",
-            "main" : "메인",
-            "clipboard_upload" : "클립보드 파일 올리기",
-            "only_korean" : "한국어로만 지원됨",
-            "except_ie" : "인터넷 익스플로러에선 지원되지 않음",
-            "use_monaco" : "모나코 에디터 사용",
-            "self_tab" : "현재 탭",
-            "exter_link_open_method" : "외부 링크",
-            "link_delimiter" : "링크 구분자 추가"
-        }
-    }
-
-    var server_language = document.cookie.match(opennamu_cookie_split_regex('language'))[1];
-    var user_language = document.cookie.match(opennamu_cookie_split_regex('user_language'))[1];
-    if(user_language in set_language) {
-        language = user_language;
-    } else {
-        if(server_language in set_language) {
-            language = server_language;
-        } else {
-            language = 'en-US';
-        }
-    }
-
-    if(name in set_language[language]) {
-        return set_language[language][name];
-    } else {
-        return name + ' (' + language + ')';
-    }
-}
-
-function main_css_skin_set() {    
-    var set_data = {};
-    var strike_list = [
-        ['0', 'normal', main_css_load_lang('default')],
-        ['1', 'change', main_css_load_lang('change_to_normal')],
-        ['2', 'delete', main_css_load_lang('delete')]
-    ];
-    set_data["strike"] = '';
-    var i = 0;
-    while(strike_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_del_strike')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_del_strike'))[1] === strike_list[i][0]
-        ) {
-            set_data["strike"] = '<option value="' + strike_list[i][1] + '">' + strike_list[i][2] + '</option>' + set_data["strike"];
-        } else {
-            set_data["strike"] += '<option value="' + strike_list[i][1] + '">' + strike_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    var bold_list = [
-        ['0', 'normal', main_css_load_lang('default')],
-        ['1', 'change', main_css_load_lang('change_to_normal')],
-        ['2', 'delete', main_css_load_lang('delete')]
-    ];
-    set_data["bold"] = '';
-    i = 0;
-    while(bold_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_del_bold')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_del_bold'))[1] === bold_list[i][0]
-        ) {
-            set_data["bold"] = '<option value="' + bold_list[i][1] + '">' + bold_list[i][2] + '</option>' + set_data["bold"];
-        } else {
-            set_data["bold"] += '<option value="' + bold_list[i][1] + '">' + bold_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_include_link')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_include_link'))[1] === '1'
-    ) {
-        set_data["include"] = "checked";
-    } else {
-        set_data["include"] = "";
-    }
-
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_image_paste')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_image_paste'))[1] === '1'
-    ) {
-        set_data["image_paste"] = "checked";
-    } else {
-        set_data["image_paste"] = "";
-    }
-
-    var category_list = [
-        ['0', 'bottom', main_css_load_lang('bottom')],
-        ['1', 'top', main_css_load_lang('top')],
-    ];
-    set_data["category"] = '';
-    i = 0;
-    while(category_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_category_set')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_category_set'))[1] === category_list[i][0]
-        ) {
-            set_data["category"] = '<option value="' + category_list[i][1] + '">' + category_list[i][2] + '</option>' + set_data["category"];
-        } else {
-            set_data["category"] += '<option value="' + category_list[i][1] + '">' + category_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    var footnote_list = [
-        ['0', 'normal', main_css_load_lang('default')],
-        ['1', 'spread', main_css_load_lang('spread')]
-    ];
-    set_data["footnote"] = '';
-    i = 0;
-    while(footnote_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_footnote_set')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_footnote_set'))[1] === footnote_list[i][0]
-        ) {
-            set_data["footnote"] = '<option value="' + footnote_list[i][1] + '">' + footnote_list[i][2] + '</option>' + set_data["footnote"];
-        } else {
-            set_data["footnote"] += '<option value="' + footnote_list[i][1] + '">' + footnote_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    var image_list = [
-        ['0', 'normal', main_css_load_lang('default')],
-        ['1', 'click', main_css_load_lang('change_to_link')],
-        ['2', 'new_click', main_css_load_lang('click_load')]
-    ];
-    set_data["image"] = '';
-    i = 0;
-    while(image_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_image_set')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_image_set'))[1] === image_list[i][0]
-        ) {
-            set_data["image"] = '<option value="' + image_list[i][1] + '">' + image_list[i][2] + '</option>' + set_data["image"];
-        } else {
-            set_data["image"] += '<option value="' + image_list[i][1] + '">' + image_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    var toc_list = [
-        ['0', 'normal', main_css_load_lang('default')],
-        ['1', 'off', main_css_load_lang('all_off')],
-        ['2', 'on', main_css_load_lang('in_content')]
-    ];
-    set_data["toc"] = '';
-    i = 0;
-    while(toc_list[i]) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_toc_set')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_toc_set'))[1] === toc_list[i][0]
-        ) {
-            set_data["toc"] = '<option value="' + toc_list[i][1] + '">' + toc_list[i][2] + '</option>' + set_data["toc"];
-        } else {
-            set_data["toc"] += '<option value="' + toc_list[i][1] + '">' + toc_list[i][2] + '</option>';
-        }
-
-        i += 1;
-    }
-
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_monaco')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_monaco'))[1] === '1'
-    ) {
-        set_data["monaco"] = "checked";
-    } else {
-        set_data["monaco"] = "";
-    }
-    
-    if(document.cookie.match(opennamu_cookie_split_regex('main_css_font_size'))) {
-        set_data["font_size"] = document.cookie.match(opennamu_cookie_split_regex('main_css_font_size'))[1];
-    } else {
-        set_data["font_size"] = '';
-    }
-    
-    let exter_link_list = [
-        ['0', 'blank', main_css_load_lang('default')],
-        ['1', 'self', main_css_load_lang('self_tab')]
-    ];
-    set_data["exter_link"] = '';
-    for(let i = 0; exter_link_list[i]; i++) {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_exter_link')) && 
-            document.cookie.match(opennamu_cookie_split_regex('main_css_exter_link'))[1] === exter_link_list[i][0]
-        ) {
-            set_data["exter_link"] = '<option value="' + exter_link_list[i][1] + '">' + exter_link_list[i][2] + '</option>' + set_data["exter_link"];
-        } else {
-            set_data["exter_link"] += '<option value="' + exter_link_list[i][1] + '">' + exter_link_list[i][2] + '</option>';
-        }
-    }
-    
-    if(
-        document.cookie.match(opennamu_cookie_split_regex('main_css_link_delimiter')) &&
-        document.cookie.match(opennamu_cookie_split_regex('main_css_link_delimiter'))[1] === '1'
-    ) {
-        set_data["link_delimiter"] = "checked";
-    } else {
-        set_data["link_delimiter"] = "";
-    }
-
-    document.getElementById("main_skin_set").innerHTML = ' \
-        <div id="opennamu_simple_render"> \
-            <h2>1. ' + main_css_load_lang('renderer') + '</h2> \
-            <h3>1.1. ' + main_css_load_lang('strike') + '</h3> \
-            <select id="main_css_strike"> \
-                ' + set_data["strike"] + ' \
-            </select> \
-            <h3>1.2. ' + main_css_load_lang('bold') + '</h3> \
-            <select id="main_css_bold"> \
-                ' + set_data["bold"] + ' \
-            </select> \
-            <h3>1.3. ' + main_css_load_lang('where_category') + '</h3> \
-            <select id="main_css_category"> \
-                ' + set_data["category"] + ' \
-            </select> \
-            <h3>1.4. ' + main_css_load_lang('set_footnote') + '</h3> \
-            <select id="main_css_footnote"> \
-                ' + set_data["footnote"] + ' \
-            </select> \
-            <h3>1.5. ' + main_css_load_lang('set_image') + '</h3> \
-            <select id="main_css_image"> \
-                ' + set_data["image"] + ' \
-            </select> \
-            <h3>1.6. ' + main_css_load_lang('other') + '</h3> \
-            <input ' + set_data["include"] + ' type="checkbox" id="main_css_include" value="include"> ' + main_css_load_lang('include_link') + ' \
-            <hr class="main_hr"> \
-            <input ' + set_data["link_delimiter"] + ' type="checkbox" id="main_css_link_delimiter" value="link_delimiter"> ' + main_css_load_lang('link_delimiter') + '<sup>(1)</sup> \
-            <h3>1.7. ' + main_css_load_lang('set_toc') + '</h3> \
-            <select id="main_css_toc"> \
-                ' + set_data["toc"] + ' \
-            </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') + ' (EX : 11)" value="' + set_data["font_size"] + '"> \
-            <h3>1.9. ' + main_css_load_lang('exter_link_open_method') + '</h3> \
-            <select id="main_css_exter_link"> \
-                ' + set_data["exter_link"] + ' \
-            </select> \
-            <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> \
-        </div> \
-    ';
-}
-
-document.addEventListener("DOMContentLoaded", main_css_skin_load);

+ 0 - 107
views/main_css/js/render_html.js

@@ -1,107 +0,0 @@
-function render_html(name = '') {
-    var num = 0;
-    while(1) {
-        num += 1;
-
-        if(document.getElementById(name + '_' + String(num))) {
-            data = document.getElementById(name + '_' + String(num)).innerHTML;
-
-            var src_list = ['www.youtube.com', 'www.google.com', 'play-tv.kakao.com'];
-            var t_data = [
-                'b', 'i', 's', 'del', 'strong', 'bold', 'em', 'sub', 'sup', 
-                'div', 'span', 
-                'a',
-                'iframe'
-            ];
-            for(var key in t_data) {
-                patt = new RegExp(
-                    '&lt;' + t_data[key] + '( (?:(?:(?!&gt;).)+))?&gt;((?:(?!&lt;\/' + t_data[key] + '&gt;).)*)&lt;\/' + t_data[key] + '&gt;',
-                    'ig'
-                );
-                
-                data = data.replace(patt, function(full, in_data, in_data_2) {
-                    if(['b', 'i', 's', 'del', 'strong', 'bold', 'em', 'sub', 'sup'].includes(t_data[key])) {
-                        return '<' + t_data[key] + '>' + in_data_2 + '</' + t_data[key] + '>'
-                    } else if(t_data[key] === 'div' || t_data[key] === 'span') {
-                        var style_data = in_data.match(/ style=['"]([^'"]*)['"]/);
-                        if(style_data) {
-                            style_data = style_data[1].replace(/position/ig, '');
-                        } else {
-                            style_data = '';
-                        }
-
-                        return '<' + t_data[key] + ' style="' + style_data + '">' + in_data_2 + '</' + t_data[key] + '>';
-                    } else if(t_data[key] === 'a') {
-                        var link_data = in_data.match(/ href=['"]([^'"]*)['"]/);
-                        if(link_data) {
-                            link_data = link_data[1].replace(/^javascript:/ig, '');
-                        } else {
-                            link_data = '';
-                        }
-
-                        return '<' + t_data[key] + ' id="out_link" href="' + link_data + '">' + in_data_2 + '</' + t_data[key] + '>';
-                    } else if(t_data[key] === 'iframe') {
-                        var src_data = in_data.match(/ src=['"]([^'"]*)['"]/);
-                        if(src_data) {
-                            src_data = src_data[1];
-
-                            var src_check = src_data.match(/^http(?:s)?:\/\/([^/]+)/);
-                            if(src_check) { 
-                                if(!src_list.includes(src_check[1])) {
-                                    src_data = '';
-                                }
-                            } else {
-                                src_data = '';
-                            }
-                        } else {
-                            src_data = '';
-                        }
-
-                        var width_data = in_data.match(/ width=['"]([^'"]*)['"]/);
-                        if(width_data) {
-                            width_data = width_data[1];
-                        } else {
-                            width_data = '';
-                        }
-
-                        var height_data = in_data.match(/ height=['"]([^'"]*)['"]/);
-                        if(height_data) {
-                            height_data = height_data[1];
-                        } else {
-                            height_data = '';
-                        }
-
-                        return '<' + t_data[key] + ' src="' + src_data + '" width="' + width_data + '" height="' + height_data + '" allowfullscreen frameborder="0">' + in_data_2 + '</' + t_data[key] + '>';
-                    } else {
-                        var src_data = in_data.match(/ src=['"]([^'"]*)['"]/);
-                        if(src_data) {
-                            src_data = src_data[1];
-                        } else {
-                            src_data = '';
-                        }
-
-                        var width_data = in_data.match(/ width=['"]([^'"]*)['"]/);
-                        if(width_data) {
-                            width_data = width_data[1];
-                        } else {
-                            width_data = '';
-                        }
-
-                        var height_data = in_data.match(/ height=['"]([^'"]*)['"]/);
-                        if(height_data) {
-                            height_data = height_data[1];
-                        } else {
-                            height_data = '';
-                        }
-
-                        return '<' + t_data[key] + ' controls src="' + src_data + '" width="' + width_data + '" height="' + height_data + '">' + in_data_2 + '</' + t_data[key] + '>';
-                    }
-                });
-            }
-
-            document.getElementById(name + '_' + String(num)).innerHTML = data;
-        } else {
-            break;
-        }
-    }
-}

+ 27 - 19
views/main_css/js/load_editor.js → views/main_css/js/route/editor.js

@@ -1,28 +1,30 @@
+"use strict";
+
 function do_insert_data(name, data, monaco_name) {
 function do_insert_data(name, data, monaco_name) {
     if(!document.getElementById(monaco_name)) {
     if(!document.getElementById(monaco_name)) {
         // https://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
         // https://stackoverflow.com/questions/11076975/insert-text-into-textarea-at-cursor-position-javascript
         if(document.selection) {
         if(document.selection) {
             document.getElementById(name).focus();
             document.getElementById(name).focus();
 
 
-            var sel = document.selection.createRange();
+            let sel = document.selection.createRange();
             sel.text = data;
             sel.text = data;
         } else if(
         } else if(
             document.getElementById(name).selectionStart || 
             document.getElementById(name).selectionStart || 
             document.getElementById(name).selectionStart == '0'
             document.getElementById(name).selectionStart == '0'
         ) {
         ) {
-            var startPos = document.getElementById(name).selectionStart;
-            var endPos = document.getElementById(name).selectionEnd;
-            var myPos = document.getElementById(name).value;
+            let startPos = document.getElementById(name).selectionStart;
+            let endPos = document.getElementById(name).selectionEnd;
+            let myPos = document.getElementById(name).value;
 
 
             document.getElementById(name).value = myPos.substring(0, startPos) + data + myPos.substring(endPos, myPos.length);
             document.getElementById(name).value = myPos.substring(0, startPos) + data + myPos.substring(endPos, myPos.length);
         } else {
         } else {
             document.getElementById(name).value += data;
             document.getElementById(name).value += data;
         }
         }
     } else {
     } else {
-        var selection = editor.getSelection();
-        var id = { major: 1, minor: 1 };             
-        var text = data;
-        var op = {
+        let selection = editor.getSelection();
+        let id = { major: 1, minor: 1 };             
+        let text = data;
+        let op = {
             identifier: id, 
             identifier: id, 
             range: selection, 
             range: selection, 
             text: text, 
             text: text, 
@@ -35,16 +37,17 @@ function do_insert_data(name, data, monaco_name) {
 
 
 // 아직 개편이 더 필요함
 // 아직 개편이 더 필요함
 function do_paste_image(name, monaco_name) {
 function do_paste_image(name, monaco_name) {
-    window.addEventListener('DOMContentLoaded', function() {
-        if(
-            document.cookie.match(opennamu_cookie_split_regex('main_css_image_paste')) &&
-            document.cookie.match(opennamu_cookie_split_regex('main_css_image_paste'))[1] === 'use'
-        ) {
+    window.addEventListener('DOMContentLoaded', async function() {
+        let set = await opennamu_get_main_skin_set("main_css_image_paste");
+        if(set === 'use') {
             let textarea;
             let textarea;
-            if(!document.getElementById(monaco_name)) {
-                textarea = document.getElementById(monaco_name);   
+            if(
+                document.getElementById(monaco_name) !== null &&
+                document.getElementById(monaco_name) !== undefined
+            ) {
+                textarea = document.getElementById(monaco_name);
             } else {
             } else {
-                textarea = document.getElementById(name);   
+                textarea = document.getElementById(name);
             }
             }
 
 
             if(textarea) {
             if(textarea) {
@@ -58,20 +61,25 @@ function pasteListener(e) {
     // find file
     // find file
     if(e.clipboardData && e.clipboardData.items) {
     if(e.clipboardData && e.clipboardData.items) {
         const items = e.clipboardData.items;
         const items = e.clipboardData.items;
-        let haveImageInClipboard = false;
         const formData = new FormData();
         const formData = new FormData();
+
+        let haveImageInClipboard = false;
+        let file_name = '';
+        
         for(let i = 0; i < items.length; i++) {
         for(let i = 0; i < items.length; i++) {
             if(items[i].type.indexOf("image") !== -1) {
             if(items[i].type.indexOf("image") !== -1) {
                 const file = items[i].getAsFile();
                 const file = items[i].getAsFile();
                 const customName = prompt("파일 이름 (확장자 제외)");
                 const customName = prompt("파일 이름 (확장자 제외)");
                 
                 
-                if (!customName) {
+                if(!customName) {
                     return alert("파일 이름 없음");
                     return alert("파일 이름 없음");
                 }
                 }
                 
                 
-                var file_name = customName + ".png";
+                file_name = customName + ".png";
+                
                 const customFile = new File([file], file_name, { type: file.type });
                 const customFile = new File([file], file_name, { type: file.type });
                 formData.append("f_data[]", customFile);
                 formData.append("f_data[]", customFile);
+                
                 haveImageInClipboard = true;
                 haveImageInClipboard = true;
                 e.preventDefault();
                 e.preventDefault();
                 
                 

+ 166 - 0
views/main_css/js/route/render.js

@@ -0,0 +1,166 @@
+"use strict";
+
+function opennamu_heading_folding(data, element = '') {
+    let fol = document.getElementById(data);
+    if(fol.style.display === '' || fol.style.display === 'inline-block' || fol.style.display === 'block') {
+        document.getElementById(data).style.display = 'none';
+    } else {
+        document.getElementById(data).style.display = 'block';
+    }
+    
+    if(element !== '') {
+        console.log(element.innerHTML);
+        if(element.innerHTML !== '⊖') {
+            element.innerHTML = '⊖';
+        } else {
+            element.innerHTML = '⊕';
+        }
+    }
+}
+
+function opennamu_do_render_html(name = '') {
+    if(document.getElementById(name)) {
+        let data = document.getElementById(name).innerHTML;
+
+        let src_list = ['www.youtube.com', 'www.google.com', 'play-tv.kakao.com'];
+        let t_data = [
+            'b', 'i', 's', 'del', 'strong', 'bold', 'em', 'sub', 'sup', 
+            'div', 'span', 
+            'a',
+            'iframe'
+        ];
+        for(let key in t_data) {
+            let patt = new RegExp(
+                '&lt;' + t_data[key] + '( (?:(?:(?!&gt;).)+))?&gt;((?:(?!&lt;\/' + t_data[key] + '&gt;).)*)&lt;\/' + t_data[key] + '&gt;',
+                'ig'
+            );
+            
+            data = data.replace(patt, function(full, in_data, in_data_2) {
+                if(['b', 'i', 's', 'del', 'strong', 'bold', 'em', 'sub', 'sup'].includes(t_data[key])) {
+                    return '<' + t_data[key] + '>' + in_data_2 + '</' + t_data[key] + '>'
+                } else if(t_data[key] === 'div' || t_data[key] === 'span') {
+                    let style_data = in_data.match(/ style=['"]([^'"]*)['"]/);
+                    if(style_data) {
+                        style_data = style_data[1].replace(/position/ig, '');
+                    } else {
+                        style_data = '';
+                    }
+
+                    return '<' + t_data[key] + ' style="' + style_data + '">' + in_data_2 + '</' + t_data[key] + '>';
+                } else if(t_data[key] === 'a') {
+                    let link_data = in_data.match(/ href=['"]([^'"]*)['"]/);
+                    if(link_data) {
+                        link_data = link_data[1].replace(/^javascript:/ig, '');
+                    } else {
+                        link_data = '';
+                    }
+
+                    return '<' + t_data[key] + ' id="out_link" href="' + link_data + '">' + in_data_2 + '</' + t_data[key] + '>';
+                } else if(t_data[key] === 'iframe') {
+                    let src_data = in_data.match(/ src=['"]([^'"]*)['"]/);
+                    if(src_data) {
+                        src_data = src_data[1];
+
+                        let src_check = src_data.match(/^http(?:s)?:\/\/([^/]+)/);
+                        if(src_check) { 
+                            if(!src_list.includes(src_check[1])) {
+                                src_data = '';
+                            }
+                        } else {
+                            src_data = '';
+                        }
+                    } else {
+                        src_data = '';
+                    }
+
+                    let width_data = in_data.match(/ width=['"]([^'"]*)['"]/);
+                    if(width_data) {
+                        width_data = width_data[1];
+                    } else {
+                        width_data = '';
+                    }
+
+                    let height_data = in_data.match(/ height=['"]([^'"]*)['"]/);
+                    if(height_data) {
+                        height_data = height_data[1];
+                    } else {
+                        height_data = '';
+                    }
+
+                    return '<' + t_data[key] + ' src="' + src_data + '" width="' + width_data + '" height="' + height_data + '" allowfullscreen frameborder="0">' + in_data_2 + '</' + t_data[key] + '>';
+                } else {
+                    let src_data = in_data.match(/ src=['"]([^'"]*)['"]/);
+                    if(src_data) {
+                        src_data = src_data[1];
+                    } else {
+                        src_data = '';
+                    }
+
+                    let width_data = in_data.match(/ width=['"]([^'"]*)['"]/);
+                    if(width_data) {
+                        width_data = width_data[1];
+                    } else {
+                        width_data = '';
+                    }
+
+                    let height_data = in_data.match(/ height=['"]([^'"]*)['"]/);
+                    if(height_data) {
+                        height_data = height_data[1];
+                    } else {
+                        height_data = '';
+                    }
+
+                    return '<' + t_data[key] + ' controls src="' + src_data + '" width="' + width_data + '" height="' + height_data + '">' + in_data_2 + '</' + t_data[key] + '>';
+                }
+            });
+        }
+
+        document.getElementById(name).innerHTML = data;
+    }
+}
+
+function opennamu_do_footnote_spread(set_name, load_name) {
+    if(document.getElementById(set_name + '_load').style.display === 'none') {
+        console.log(set_name, load_name);
+        document.getElementById(set_name).title = '';
+        document.getElementById(set_name + '_load').innerHTML = '<a href="#' + load_name + '">(Go)</a> ' + document.getElementById(load_name + '_title').innerHTML;
+        document.getElementById(set_name + '_load').style.display = "inline-block";
+    } else {
+        document.getElementById(set_name + '_load').style.display = "none";
+    }
+}
+
+function opennamu_do_footnote_popover(set_name, load_name) {
+    if(document.getElementById(set_name + '_load').style.display === 'none') {
+        console.log(set_name, load_name);
+        document.getElementById(set_name).title = '';
+        document.getElementById(set_name + '_load').innerHTML = '<a href="#' + load_name + '">(Go)</a> ' + document.getElementById(load_name + '_title').innerHTML;
+        document.getElementById(set_name + '_load').style.display = "inline-block";
+
+        let width = document.getElementById(set_name + '_load').clientWidth;
+        let screen_width = window.innerWidth;
+        let left = document.getElementById(set_name).getBoundingClientRect().left;
+        let left_org = document.getElementById(set_name + '_load').getBoundingClientRect().left;
+        let top = document.getElementById(set_name).getBoundingClientRect().top;
+        console.log(width, screen_width, left, left_org);
+        console.log(screen_width - (left + width));
+        if(screen_width - (left + width) < 50) {
+            console.log("test");
+            if(left > 350) {
+                document.getElementById(set_name + '_load').style.left = String(left - 300) + "px";
+            } else {
+                document.getElementById(set_name + '_load').style.left = "0px";
+            }
+
+            left = document.getElementById(set_name + '_load').getBoundingClientRect().left;
+            width = document.getElementById(set_name + '_load').clientWidth;
+            if(300 > width) {
+                document.getElementById(set_name + '_load').style.left = String(left + (300 - width)) + "px";
+            } else {
+                document.getElementById(set_name + '_load').style.marginTop = "20px";
+            }
+        }
+    } else {
+        document.getElementById(set_name + '_load').style.display = "none";
+    }
+}

+ 1 - 2
views/main_css/js/route/thread.js

@@ -1,5 +1,4 @@
-// 좀 더 개선 필요
-// use strict 적용 필요 (eval 동작에 문제 있음)
+// 폐지하고 다시 SSR 방식으로 전환 예정
 function opennamu_do_thread_make(topic_num, type_do = 'top', some = '', where = 'top_topic') {
 function opennamu_do_thread_make(topic_num, type_do = 'top', some = '', where = 'top_topic') {
     let url = '';
     let url = '';
     if(type_do === 'top') {
     if(type_do === 'top') {