Przeglądaj źródła

Merge pull request #1024 from 2du/dev

Dev
잉여개발기 (SPDV) 5 lat temu
rodzic
commit
99772e9a31

+ 0 - 1
app.py

@@ -142,7 +142,6 @@ create_data['user_application'] = ['id', 'pw', 'date', 'encode', 'question', 'an
 create_data['topic'] = ['id', 'data', 'date', 'ip', 'block', 'top', 'code']
 create_data['rb'] = ['block', 'end', 'today', 'blocker', 'why', 'band', 'login', 'ongoing']
 create_data['back'] = ['title', 'link', 'type']
-create_data['custom'] = ['user', 'css']
 create_data['other'] = ['name', 'data', 'coverage']
 create_data['alist'] = ['name', 'acl']
 create_data['re_admin'] = ['who', 'what', 'time']

+ 1 - 0
language/en-US.json

@@ -282,6 +282,7 @@
                 "error_404" : "Missing document notice",
                 "edit_help" : "Editing textarea phrase",
                 "upload_help" : "File upload phrase",
+                "upload_default" : "File upload other Default",
             "_comment_2.2.4_" : "Google",
                 "recaptcha" : "reCAPTCHA",
                 "smtp_setting" : "Email SMTP setting",

+ 2 - 1
language/ko-KR.json

@@ -394,5 +394,6 @@
     "2fa_password" : "2차 비밀번호",
     "2fa_password_change" : "2차 비밀번호 변경",
     "vote_acl" : "투표 ACL",
-    "upload_help" : "파일 올리기 문구"
+    "upload_help" : "파일 올리기 문구",
+    "upload_default" : "파일 기타란 기본값"
 }

+ 10 - 12
readme.md

@@ -5,7 +5,7 @@
 
 ![](https://raw.githubusercontent.com/2du/openNAMU/beta/.github/logo.png)
 
-오픈나무는 파이썬 기반의 위키 엔진입니다. 파이썬과 그 의존성 모듈만 설치하면 사용할 수 있으며, 코드를 직접 수정하여 좀 더 주제에 특화된 위키를 만들 수 있습니다.
+오픈나무는 파이썬 기반의 위키 엔진입니다.
 
 ### 목차
  * [시작하기](#시작하기)
@@ -18,21 +18,21 @@
 ## 시작하기
 오픈나무는 파이썬 환경에서 동작하는 파이썬 애플리케이션으로, 파이썬 환경을 필요로 합니다.
 
-쉬운 오픈나무 설치를 위해 오픈나무 가이드를 따로 생성해두었으며, [이곳](https://2du.pythonanywhere.com/w/%EC%84%A4%EC%B9%98%EB%B2%95)에서 확인하실 수 있습니다.
+[여기](https://2du.pythonanywhere.com/w/설치법)를 눌러 설치 가이드를 볼 수 있습니다.
 
-## 클론
+### 클론
 아래 명령을 터미널(명령 프롬프트)에 입력하여 본 리포지토리를 클론할 수 있습니다.
- * `git clone -b stable https://github.com/2du/openNAMU.git`
- * `git clone -b beta https://github.com/2du/openNAMU.git`
- * `git clone -b dev https://github.com/2du/openNAMU.git`
+ * 일반: `git clone -b stable https://github.com/2du/openNAMU.git`
+ * 베타: `git clone -b beta https://github.com/2du/openNAMU.git`
+ * 개발: `git clone -b dev https://github.com/2du/openNAMU.git`
 
 ## 기여
-오픈나무에는 검증되지 않은 몇가지 버그가 존재할 수 있습니다. 당신의 오픈나무 사용과 버그 발견은 오픈나무의 발전을 돕습니다. [(이슈 생성하기)](https://github.com/2du/openNAMU/issues/new)
+오픈나무에는 확인되지 않은 버그가 존재할 수 있습니다. 이를 보고해주시면 오픈나무의 발전을 도울 수 있습니다. [여기](https://github.com/2du/openNAMU/issues/new)를 눌러 버그를 보고해주세요.
 
-오픈나무는 완전한 오픈소스 프로젝트입니다. 새로운 기능을 추가하고 Pull Request를 생성해보세요. [(Pull Request 생성하기)](https://github.com/2du/openNAMU/compare)
+오픈나무는 오픈소스 프로젝트입니다. 원한다면 직접 코드를 수정하고 Pull Request를 보낼 수 있습니다.
 
 ## 라이선스
-오픈나무 프로젝트는 [BSD 3-Clause License](./LICENSE)(이하 이용허락)의 보호를 받고 있으며, 오픈나무 프로젝트를 사용하고자 한다면 라이선스를 준수해야 합니다. 본 이용허락를 위반할 경우 개발자는 DMCA Takedown 등 관련 제재를 관계자에게 요청할 권리가 있으며, 그 책임은 모두 이용허락 위반 사용자에게 있습니다. 자세한 내용은 문서를 참고하세요.
+오픈나무 프로젝트는 [BSD 3-Clause License](./LICENSE)의 보호를 받고 있으며, 오픈나무 프로젝트를 사용하고자 한다면 라이선스를 준수해야 합니다. 본 라이선스를 위반할 경우 법적인 조치가 취해질 수 있습니다. 자세한 내용은 문서를 참고하세요.
 
 ### 포함된 외부 프로젝트
  * Quotes icon - [Dave Gandy](http://www.flaticon.com/free-icon/quote-left_25672)
@@ -40,9 +40,6 @@
  * Numerical expression - [MathJax](https://www.mathjax.org/)
  * Handling Keyboard Shortcuts [shortcut.js](http://www.openjs.com/scripts/events/keyboard_shortcuts/)
 
-### 기여자 목록
- * [참고](https://github.com/2DU/openNAMU/graphs/contributors)
-
 ### 도움을 주신 분들
  * [Team Croatia](https://github.com/TeamCroatia)
  * Basix
@@ -56,3 +53,4 @@
 ## 기타
  * 첫 가입자에게 소유자 권한이 부여됩니다.
  * [테스트 서버](http://2du.pythonanywhere.com)
+ * [기여자 목록](https://github.com/2DU/openNAMU/graphs/contributors)

+ 1 - 1
route/edit.py

@@ -194,7 +194,7 @@ def edit_2(conn, name):
 
         curs.execute(db_change('select data from other where name = "edit_help"'))
         sql_d = curs.fetchall()
-        p_text = 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')
 
         data = re.sub(r'\n+$', '', data)
         data_old = re.sub(r'\n+$', '', data_old)

+ 2 - 1
route/edit_delete.py

@@ -29,7 +29,8 @@ def edit_delete_2(conn, name, app_var):
                 ip,
                 flask.request.form.get('send', ''),
                 leng,
-                'delete'
+                t_check = 'delete',
+                mode = 'delete'
             )
 
             curs.execute(db_change("select title, link from back where title = ? and not type = 'cat' and not type = 'no'"), [name])

+ 6 - 3
route/edit_move.py

@@ -45,7 +45,8 @@ def edit_move_2(conn, name):
                     ip_check(),
                     flask.request.form.get('send', ''),
                     '0',
-                    'merge <a>' + name + '</a> - <a>' + move_title + '</a> move'
+                    t_check = 'merge <a>' + name + '</a> - <a>' + move_title + '</a> move',
+                    mode = 'move'
                 )
 
                 curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])
@@ -112,7 +113,8 @@ def edit_move_2(conn, name):
                         ip_check(),
                         flask.request.form.get('send', ''),
                         '0',
-                        '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move'
+                        t_check = '<a>' + (title_name[0] if title_name[0] != 'test ' + str(i) else name) + '</a> - <a>' + title_name[1] + '</a> move',
+                        mode = 'move'
                     )
 
                     curs.execute(db_change("update history set title = ? where title = ?"), [title_name[1], title_name[0]])
@@ -140,7 +142,8 @@ def edit_move_2(conn, name):
                 ip_check(),
                 flask.request.form.get('send', ''),
                 '0',
-                '<a>' + name + '</a> - <a>' + move_title + '</a> move'
+                t_check = '<a>' + name + '</a> - <a>' + move_title + '</a> move',
+                mode = 'move'
             )
 
             curs.execute(db_change("update back set type = 'no' where title = ? and not type = 'cat' and not type = 'no'"), [name])

+ 2 - 1
route/edit_revert.py

@@ -47,7 +47,8 @@ def edit_revert_2(conn, name):
                 ip_check(),
                 flask.request.form.get('send', ''),
                 leng,
-                'r' + str(num) + ''
+                t_check = 'r' + str(num),
+                mode = 'revert'
             )
 
             render_set(

+ 14 - 7
route/func_upload.py

@@ -75,19 +75,20 @@ def func_upload_2(conn, app_var):
                 file_d = '' + \
                     '[[file:' + name + ']]\n' + \
                     '{{{[[file:' + name + ']]}}}\n\n' + \
-                    (g_lice + '\n' if g_lice != '' else '') + \
                     flask.request.form.get('f_lice_sel', 'direct_input') + '\n' + \
                     (ip if ip_or_user(ip) != 0 else '[[user:' + ip + ']]') + '\n' + \
                     str(file_size) + ' Byte\n' + \
-                    '[[category:' + re.sub(r'\]', '_', flask.request.form.get('f_lice_sel', '')) + ']]' + \
+                    '[[category:' + re.sub(r'\]', '_', flask.request.form.get('f_lice_sel', '')) + ']]\n' + \
+                    (g_lice if g_lice != '' else '') + \
                 ''
             else:
                 file_d = '' + \
+                    'file:' + name + '\n' + \
                     '/image/' + e_data + '\n\n' + \
-                    (g_lice + '\n' if g_lice != '' else '') + \
                     flask.request.form.get('f_lice_sel', 'direct_input') + '\n' + \
                     ip + \
-                    str(file_size) + ' Byte\n' + \
+                    str(file_size) + ' Byte\n\n' + \
+                    (g_lice if g_lice != '' else '') + \
                 ''
 
             curs.execute(db_change("insert into data (title, data) values (?, ?)"), ['file:' + name, file_d])
@@ -106,7 +107,8 @@ def func_upload_2(conn, app_var):
                 ip,
                 ip,
                 '0',
-                'upload'
+                t_check = 'upload',
+                mode = 'upload'
             )
 
             if file_num:
@@ -117,6 +119,7 @@ def func_upload_2(conn, app_var):
         return redirect('/w/file:' + name)
     else:
         license_list = '<option value="direct_input">' + load_lang('direct_input') + '</option>'
+        file_name = flask.request.args.get('name', '')
 
         curs.execute(db_change("select html from html_filter where kind = 'image_license'"))
         db_data = curs.fetchall()
@@ -126,6 +129,10 @@ def func_upload_2(conn, app_var):
         db_data = curs.fetchall()
         upload_help = ('<hr class="main_hr">' + db_data[0][0]) if db_data and db_data[0][0] != '' else ''
 
+        curs.execute(db_change("select data from other where name = 'upload_default'"))
+        db_data = curs.fetchall()
+        upload_default = html.escape(db_data[0][0]) if db_data and db_data[0][0] != '' else ''
+
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('upload'), wiki_set(), custom(), other2([0, 0])],
             data = '''
@@ -137,13 +144,13 @@ def func_upload_2(conn, app_var):
                 <form method="post" enctype="multipart/form-data" accept-charset="utf8">
                     <input multiple="multiple" type="file" name="f_data[]">
                     <hr class="main_hr">
-                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" value="''' + flask.request.args.get('name', '') + '''">
+                    <input placeholder="''' + load_lang('file_name') + '''" name="f_name" value="''' + file_name + '''">
                     <hr class="main_hr">
                     <select name="f_lice_sel">
                         ''' + license_list + '''
                     </select>
                     <hr class="main_hr">
-                    <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice"></textarea>
+                    <textarea rows="10" placeholder="''' + load_lang('other') + '''" name="f_lice">''' + upload_default + '''</textarea>
                     <hr class="main_hr">
                     ''' + captcha_get() + '''
                     <button id="save" type="submit">''' + load_lang('save') + '''</button>

+ 6 - 20
route/give_history_add.py

@@ -21,6 +21,7 @@ def give_history_add_2(conn, name):
             'Add:' + flask.request.form.get('get_ip', ''),
             flask.request.form.get('send', ''),
             leng,
+            t_check = 'add',
             mode = 'add'
         )
 
@@ -28,37 +29,22 @@ def give_history_add_2(conn, name):
 
         return redirect('/history/' + url_pas(name))
     else:
-        curs.execute(db_change('select data from other where name = "edit_bottom_text"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            b_text = '<hr class=\"main_hr\">' + sql_d[0][0]
-        else:
-            b_text = ''
-
-        curs.execute(db_change('select data from other where name = "edit_help"'))
-        sql_d = curs.fetchall()
-        if sql_d and sql_d[0][0] != '':
-            p_text = sql_d[0][0]
-        else:
-            p_text = load_lang('default_edit_help')
-
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang('history_add'), wiki_set(), custom(), other2(['(' + name + ')', 0])],
             data = '''
                 <form method="post">
                     <script>do_stop_exit();</script>
                     ''' + edit_button() + '''
-                    <textarea rows="25" id="content" placeholder="''' + p_text + '''" name="content"></textarea>
-                    <hr class=\"main_hr\">
+                    <textarea rows="25" id="content" name="content"></textarea>
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('why') + '''" name="send" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('name') + '''" name="get_ip" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <button id="save" type="submit" onclick="go_save_zone = 1;">''' + load_lang('save') + '''</button>
                     <button id="preview" type="button" onclick="load_preview(\'''' + url_pas(name) + '\')">' + load_lang('preview') + '''</button>
                 </form>
-                ''' + b_text + '''
-                <hr class=\"main_hr\">
+                <hr class="main_hr">
                 <div id="see_preview"></div>
             ''',
             menu = [['history/' + url_pas(name), load_lang('return')]]

+ 32 - 37
route/login_register.py

@@ -23,53 +23,54 @@ def login_register_2(conn):
         else:
             captcha_post('', 0)
 
-        if flask.request.form.get('id', None) == '' or flask.request.form.get('pw', None) == '':
+        user_id = flask.request.form.get('id', '')
+        user_pw = flask.request.form.get('pw', '')
+        user_repeat = flask.request.form.get('pw2', '')
+        if user_id == '' or user_pw == '':
             return re_error('/error/27')
 
-        if flask.request.form.get('pw', None) != flask.request.form.get('pw2', None):
+        if user_pw != user_repeat:
             return re_error('/error/20')
 
-        if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', flask.request.form.get('id', None)):
+        if re.search(r'(?:[^A-Za-zㄱ-힣0-9])', user_id):
             return re_error('/error/8')
 
         curs.execute(db_change('select html from html_filter where kind = "name"'))
         set_d = curs.fetchall()
         for i in set_d:
             check_r = re.compile(i[0], re.I)
-            if check_r.search(flask.request.form.get('id', None)):
+            if check_r.search(user_id):
                 return re_error('/error/8')
 
-        if len(flask.request.form.get('id', None)) > 32:
+        if len(user_id) > 32:
             return re_error('/error/7')
 
-        curs.execute(db_change("select id from user where id = ?"), [flask.request.form.get('id', None)])
+        curs.execute(db_change("select id from user where id = ?"), [user_id])
         if curs.fetchall():
             return re_error('/error/6')
 
-        hashed = pw_encode(flask.request.form.get('pw', None))
+        hashed = pw_encode(user_pw)
+        ans_q = flask.request.form.get('approval_question_answer', '')
 
         curs.execute(db_change('select data from other where name = "requires_approval"'))
         requires_approval = curs.fetchall()
         requires_approval = requires_approval and requires_approval[0][0] == 'on'
         requires_approval = None if admin == 1 else requires_approval
-
-        approval_question = ''
         if requires_approval:
             curs.execute(db_change('select data from other where name = "approval_question"'))
             approval_question = curs.fetchall()
-            if approval_question and approval_question[0][0]:
-                approval_question = approval_question[0][0]
-            else:
-                approval_question = ''
+            approval_question = approval_question[0][0] if approval_question and approval_question[0][0] else ''
+        else:
+            approval_question = ''
 
         curs.execute(db_change('select data from other where name = "email_have"'))
         sql_data = curs.fetchall()
         if sql_data and sql_data[0][0] != '' and admin != 1:
-            flask.session['c_id'] = flask.request.form.get('id', None)
+            flask.session['c_id'] = user_id
             flask.session['c_pw'] = hashed
-            flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(16))
+            flask.session['c_key'] = ''.join(random.choice("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") for i in range(64))
             if requires_approval:
-                flask.session['c_ans'] = flask.request.form.get('approval_question_answer')
+                flask.session['c_ans'] = flask.request.form.get('approval_question_answer', '')
                 flask.session['c_question'] = approval_question
 
             return redirect('/need_email')
@@ -80,7 +81,7 @@ def login_register_2(conn):
             curs.execute(db_change("select id from user limit 1"))
             if not curs.fetchall():
                 curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'owner', ?, ?)"), [
-                    flask.request.form.get('id', None), 
+                    user_id, 
                     hashed, 
                     get_time(), 
                     db_data[0][0]
@@ -93,12 +94,12 @@ def login_register_2(conn):
                     curs.execute(db_change(
                         "insert into user_application (id, pw, date, encode, question, answer, token, ip, ua, email) values (?, ?, ?, ?, ?, ?, ?, ?, ?, '')"
                     ), [
-                        flask.request.form.get('id', None), 
+                        user_id, 
                         hashed, 
                         get_time(), 
                         db_data[0][0], 
                         approval_question, 
-                        flask.request.form.get('approval_question_answer', None), 
+                        ans_q, 
                         application_token, 
                         ip_check(), 
                         flask.request.headers.get('User-Agent')
@@ -107,33 +108,27 @@ def login_register_2(conn):
                     
                     return redirect('/application_submitted')
                 else:
-                    curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [flask.request.form.get('id', None), hashed, get_time(), db_data[0][0]])
+                    curs.execute(db_change("insert into user (id, pw, acl, date, encode) values (?, ?, 'user', ?, ?)"), [user_id, hashed, get_time(), db_data[0][0]])
 
                 first = 0
 
             ip = ip_check()
             agent = flask.request.headers.get('User-Agent')
 
-            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [flask.request.form.get('id', None), ip, agent, get_time()])
+            curs.execute(db_change("insert into ua_d (name, ip, ua, today, sub) values (?, ?, ?, ?, '')"), [user_id, ip, agent, get_time()])
 
-            flask.session['id'] = flask.request.form.get('id', None)
+            flask.session['id'] = user_id
             flask.session['head'] = ''
 
             conn.commit()
 
-            if first == 0:
-                return redirect('/change')
-            else:
-                return redirect('/setting')
+            return redirect('/change') if first == 0 else redirect('/setting')
     else:
-        contract = ''
-
         curs.execute(db_change('select data from other where name = "contract"'))
         data = curs.fetchall()
-        if data and data[0][0] != '':
-            contract = data[0][0] + '<hr class=\"main_hr\">'
+        contract = (data[0][0] + '<hr class="main_hr">') if data and data[0][0] != '' else ''
 
-        http_warring = '<hr class=\"main_hr\"><span>' + load_lang('http_warring') + '</span>'
+        http_warring = '<hr class="main_hr"><span>' + load_lang('http_warring') + '</span>'
         approval_question = ''
         
         curs.execute(db_change('select data from other where name = "requires_approval"'))
@@ -145,11 +140,11 @@ def login_register_2(conn):
             data = curs.fetchall()
             if data and data[0][0] != '':
                 approval_question = '''
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <span>''' + load_lang('approval_question') + ' : ' + data[0][0] + '''<span>
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('approval_question') + '''" name="approval_question_answer" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                 '''
 
         return easy_minify(flask.render_template(skin_check(),
@@ -158,11 +153,11 @@ def login_register_2(conn):
                 <form method="post">
                     ''' + contract + '''
                     <input placeholder="''' + load_lang('id') + '''" name="id" type="text">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password') + '''" name="pw" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     <input placeholder="''' + load_lang('password_confirm') + '''" name="pw2" type="password">
-                    <hr class=\"main_hr\">
+                    <hr class="main_hr">
                     ''' + approval_question + '''
                     ''' + captcha_get() + '''
                     <button type="submit">''' + load_lang('save') + '''</button>

+ 36 - 69
route/recent_changes.py

@@ -34,29 +34,24 @@ def recent_changes_2(conn, name, tool):
                     <td id="main_table_width">''' + load_lang('time') + '''</td>
                 '''
 
-                tool_select = flask.request.args.get('tool', 'normal')
-                if tool_select == 'move':
-                    plus_sql = 'where (send like ? or send like ?) and type = "" '
-                    plus_list = ['%(<a>' + name +'</a>%', '%<a>' + name + '</a> move)', sql_num]
-                    sub += ' (' + load_lang('move') + ')'
-                elif tool_select == 'delete':
-                    plus_sql = 'where send like "%(delete)" and title = ? and type = "" '
-                    plus_list = [name, sql_num]
-                    sub += ' (' + load_lang('delete') + ')'
-                elif tool_select == 'revert':
-                    plus_sql = 'where send like ? and title = ? and type = "" '
-                    plus_list = ['%(r%)', name, sql_num]
-                    sub += ' (' + load_lang('revert') + ')'
+                set_type = flask.request.args.get('set', 'normal')
+                set_type = '' if set_type == 'edit' else set_type
+
+                if set_type != 'normal':
+                    curs.execute(db_change('' + \
+                        'select id, title, date, ip, send, leng, hide from history ' + \
+                        'where title = ? and type = ? ' + \
+                        'order by id + 0 desc ' + \
+                        "limit ?, 50" + \
+                    ''), [name, set_type, sql_num])
                 else:
-                    plus_sql = 'where title = ? and type = "" '
-                    plus_list = [name, sql_num]
+                    curs.execute(db_change('' + \
+                        'select id, title, date, ip, send, leng, hide from history ' + \
+                        'where title = ? ' + \
+                        'order by id + 0 desc ' + \
+                        "limit ?, 50" + \
+                    ''), [name, sql_num])
 
-                curs.execute(db_change('' + \
-                    'select id, title, date, ip, send, leng, hide from history ' + \
-                    plus_sql + \
-                    'order by id + 0 desc ' + \
-                    "limit ?, 50" + \
-                ''), plus_list)
                 data_list = curs.fetchall()
             else:
                 div +=  '''
@@ -69,7 +64,7 @@ def recent_changes_2(conn, name, tool):
 
                 curs.execute(db_change('' + \
                     'select id, title, date, ip, send, leng, hide from history ' + \
-                    "where ip = ? and type = '' order by date desc limit ?, 50" + \
+                    "where ip = ? order by date desc limit ?, 50" + \
                 ''), [name, sql_num])
                 data_list = curs.fetchall()
         else:
@@ -80,41 +75,13 @@ def recent_changes_2(conn, name, tool):
             '''
             sub = ''
             set_type = flask.request.args.get('set', 'normal')
+            set_type = '' if set_type == 'edit' else set_type
 
-            if set_type != 'normal':
-                if set_type == 'move':
-                    plus_sql = 'where send like "%</a> move)" and '
-                    sub += ' (' + load_lang('move') + ')'
-                elif set_type == 'delete':
-                    plus_sql = 'where send like "%(delete)" and '
-                    sub += ' (' + load_lang('delete') + ')'
-                elif set_type == 'revert':
-                    plus_sql = 'where send like "%(r%)" and '
-                    sub += ' (' + load_lang('revert') + ')'
-                else:
-                    plus_sql = 'where '
-
-                plus_sql += 'type = "" '
-                
-                if set_type == 'user':
-                    plus_sql = 'where title like "user:%" '
-                    sub += ' (' + load_lang('user') + ')'
-                else:
-                    plus_sql += 'and not title like "user:%" '
-
-                curs.execute(db_change('' + \
-                    'select id, title, date, ip, send, leng, hide from history ' + \
-                    plus_sql + \
-                    'order by date desc ' + \
-                    'limit 50' + \
-                ''))
-                data_list = curs.fetchall()
-            else:
-                data_list = []
-                curs.execute(db_change('select id, title from rc order by date desc'))
-                for i in curs.fetchall():
-                    curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where id = ? and title = ?'), i)
-                    data_list += curs.fetchall()
+            data_list = []
+            curs.execute(db_change('select id, title from rc where type = ? order by date desc'), [set_type])
+            for i in curs.fetchall():
+                curs.execute(db_change('select id, title, date, ip, send, leng, hide from history where id = ? and title = ?'), i)
+                data_list += curs.fetchall()
 
         div += '</tr>'
 
@@ -186,14 +153,17 @@ def recent_changes_2(conn, name, tool):
 
         if name:
             if tool == 'history':
-                if tool_select == 'normal':
-                    div = '' + \
-                        '<a href="?tool=move">(' + load_lang('move') + ')</a> ' + \
-                        '<a href="?tool=delete">(' + load_lang('delete') + ')</a> ' + \
-                        '<a href="?tool=revert">(' + load_lang('revert') + ')</a>' + \
-                        '<hr class="main_hr">' + div + \
-                    ''
-
+                div = '' + \
+                    '<a href="?set=normal">(' + load_lang('normal') + ')</a> ' + \
+                    '<a href="?set=edit">(' + load_lang('edit') + ')</a> ' + \
+                    '<a href="?set=move">(' + load_lang('move') + ')</a> ' + \
+                    '<a href="?set=delete">(' + load_lang('delete') + ')</a> ' + \
+                    '<a href="?set=revert">(' + load_lang('revert') + ')</a>' + \
+                    '<hr class="main_hr">' + div + \
+                ''
+                menu = [['w/' + url_pas(name), load_lang('return')]]
+                
+                if set_type == 'normal':
                     div = '''
                         <form method="post">
                             <select name="a">''' + select + '''</select> <select name="b">''' + select + '''</select>
@@ -202,15 +172,11 @@ def recent_changes_2(conn, name, tool):
                         <hr class=\"main_hr\">
                     ''' + div
 
-                    menu = [['w/' + url_pas(name), load_lang('return')]]
-
                     if admin == 1:
                         menu += [['add_history/' + url_pas(name), load_lang('history_add')]]
-                else:
-                    menu = [['history/' + url_pas(name), load_lang('return')]]
 
                 title = name
-                div += next_fix('/history/' + url_pas(name) + '?tool=' + tool_select + '&num=', num, data_list)
+                div += next_fix('/history/' + url_pas(name) + '?tool=' + set_type + '&num=', num, data_list)
             else:
                 title = load_lang('edit_record')
                 menu = [['other', load_lang('other')], ['user', load_lang('user')], ['count/' + url_pas(name), load_lang('count')]]
@@ -218,6 +184,7 @@ def recent_changes_2(conn, name, tool):
         else:
             div = '' + \
                 '<a href="?set=normal">(' + load_lang('normal') + ')</a> ' + \
+                '<a href="?set=edit">(' + load_lang('edit') + ')</a> ' + \
                 '<a href="?set=user">(' + load_lang('user_document') + ')</a> ' + \
                 '<a href="?set=move">(' + load_lang('move') + ')</a> ' + \
                 '<a href="?set=delete">(' + load_lang('delete') + ')</a> ' + \

+ 7 - 2
route/setting.py

@@ -228,7 +228,8 @@ def setting_2(conn, num, db_set):
             'error_404',
             'approval_question',
             'edit_help',
-            'upload_help'
+            'upload_help',
+            'upload_default'
         ]
         if flask.request.method == 'POST':
             for i in i_list:
@@ -317,10 +318,14 @@ def setting_2(conn, num, db_set):
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[13] + '''">''' + html.escape(d_list[13]) + '''</textarea>
                         <hr class="main_hr">
-                        <span>''' + load_lang('upload_help') + '''</span>
+                        <span>''' + load_lang('upload_help') + ''' (HTML)</span>
                         <hr class="main_hr">
                         <textarea rows="3" name="''' + i_list[14] + '''">''' + html.escape(d_list[14]) + '''</textarea>
                         <hr class="main_hr">
+                        <span>''' + load_lang('upload_default') + '''</span>
+                        <hr class="main_hr">
+                        <textarea rows="3" name="''' + i_list[15] + '''">''' + html.escape(d_list[15]) + '''</textarea>
+                        <hr class="main_hr">
                         <button id="save" type="submit">''' + load_lang('save') + '''</button>
                         <hr class="main_hr">
                         <ul>

+ 37 - 8
route/tool/func.py

@@ -290,9 +290,17 @@ def update(ver_num, set_data):
                 i[2]
             ])
 
+    if ver_num < 3203400:
+        curs.execute(db_change("select user, css from custom"))
+        for i in curs.fetchall():
+            curs.execute(db_change("insert into user_set (name, id, data) values ('custom_css', ?, ?)"), [
+                re.sub(r' \(head\)$', '', i[0]), 
+                i[1]
+            ])
+
     conn.commit()
 
-    print('Update pass')
+    print('Update completed')
 
 def set_init():
     # 초기값 설정 함수    
@@ -532,7 +540,7 @@ def next_fix(link, num, page, end = 50):
 
 def other2(data):
     global req_list
-    main_css_ver = '53'
+    main_css_ver = '55'
     data += ['' for _ in range(0, 3 - len(data))]
 
     if req_list == '':
@@ -1104,7 +1112,7 @@ def rd_plus(topic_num, date, name = None, sub = None):
 
     conn.commit()
 
-def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', mode = ''):
+def history_plus(title, data, date, ip, send, leng, t_check = '', mode = ''):
     if mode == 'add':
         curs.execute(db_change("select id from history where title = ? and type = '' order by id + 0 asc limit 1"), [title])
         id_data = curs.fetchall()
@@ -1113,14 +1121,16 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', m
         curs.execute(db_change("select id from history where title = ? and type = '' order by id + 0 desc limit 1"), [title])
         id_data = curs.fetchall()
         id_data = str(int(id_data[0][0]) + 1) if id_data else '1'
+        
+        mode = mode if not re.search('^user:', title) else 'user'
 
     send = re.sub(r'\(|\)|<|>', '', send)
     send = send[:128] if len(send) > 128 else send
     send = send + ' (' + t_check + ')' if t_check != '' else send
 
-    if not re.search('^user:', title) and mode != 'add':
+    if mode != 'add' and mode != 'user':
         curs.execute(db_change("select count(*) from rc where type = 'normal'"))
-        if curs.fetchall()[0][0] > 49:
+        if curs.fetchall()[0][0] >= 200:
             curs.execute(db_change("select id, title from rc where type = 'normal' order by date asc limit 1"))
             rc_data = curs.fetchall()
             if rc_data:
@@ -1128,13 +1138,32 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', m
                     rc_data[0][0],
                     rc_data[0][1]
                 ])
-        
+    
         curs.execute(db_change("insert into rc (id, title, date, type) values (?, ?, ?, 'normal')"), [
             id_data,
             title,
             date
         ])
-
+    
+    if mode != 'add':
+        curs.execute(db_change("select count(*) from rc where type = ?"), [mode])
+        if curs.fetchall()[0][0] >= 200:
+            curs.execute(db_change("select id, title from rc where type = ? order by date asc limit 1"), [mode])
+            rc_data = curs.fetchall()
+            if rc_data:
+                curs.execute(db_change('delete from rc where id = ? and title = ? and type = ?'), [
+                    rc_data[0][0],
+                    rc_data[0][1],
+                    mode
+                ])
+    
+        curs.execute(db_change("insert into rc (id, title, date, type) values (?, ?, ?, ?)"), [
+            id_data,
+            title,
+            date,
+            mode
+        ])
+            
     curs.execute(db_change("insert into history (id, title, data, date, ip, send, leng, hide, type) values (?, ?, ?, ?, ?, ?, ?, '', ?)"), [
         id_data,
         title,
@@ -1143,7 +1172,7 @@ def history_plus(title, data, date, ip, send, leng, t_check = '', d_type = '', m
         ip,
         send,
         leng,
-        d_type
+        mode
     ])
 
 def leng_check(first, second):

+ 10 - 6
route/tool/set_mark/namumark.py

@@ -696,20 +696,21 @@ def namumark(conn, data, title, include_num):
         
         plus_data += '' + \
             'var get_link = window.location.search.match(/(?:\?|&)from=([^&]+)/);\n' + \
-            'var get_link_2 = window.location.pathname.match(/^\/w\//);' + \
+            'var get_link_2 = window.location.pathname.match(/^\/w\//);\n' + \
             'if(!get_link && get_link_2) {\n' + \
                 'window.location.href = "/w/' + tool.url_pas(main_link) + '?from=' + tool.url_pas(title) + other_link + '";\n' + \
             '}\n' + \
         ''
         data = redirect_re.sub('\nredirect to ' + html.escape(main_link) + other_link, data, 1)
 
-    no_toc_re = re.compile(r'\[(?:목차|toc)\((?:no)\)\]\n', re.I)
+    no_toc_re = re.compile(r'\[(?:목차|toc)\(no\)\]', re.I)
     toc_re = re.compile(r'\[(?:목차|toc)\]', re.I)
-    if not no_toc_re.search(data):
-        if not toc_re.search(data):
-            data = re.sub(r'(?P<in>\n(={1,6})(#)? ?((?:(?!(?: #=| =)).)+) ?#?(?:=+)\n)', '\n[toc]\g<in>', data, 1)
+    if not no_toc_re.search(data) and not toc_re.search(data):
+        data = re.sub(r'(?P<in>\n(={1,6})(#)? ?((?:(?!(?: #=| =)).)+) ?#?(?:=+)\n)', '\n[toc]\g<in>', data, 1)
+        auto_toc = 1
     else:
         data = no_toc_re.sub('', data)
+        auto_toc = 0
 
     data = '<div class="all_in_data" id="in_data_0">' + data
 
@@ -773,7 +774,10 @@ def namumark(conn, data, title, include_num):
             break
 
     toc_data += '</div>'
-    data = toc_re.sub(toc_data, data)
+    if auto_toc == 1:
+        data = toc_re.sub('<div id="auto_toc">' + toc_data + '</div>', data, 1)
+    else:
+        data = toc_re.sub(toc_data, data)
     
     macro_re = re.compile(r'\[([^[(]+)\(((?:(?!\[|\)]).)+)\)\]')
     macro_data = macro_re.findall(data)

+ 26 - 23
route/user_custom_head_view.py

@@ -8,11 +8,11 @@ def user_custom_head_view_2(conn):
     if flask.request.method == 'POST':
         get_data = flask.request.form.get('content', '')
         if ip_or_user(ip) == 0:
-            curs.execute(db_change("select user from custom where user = ?"), [ip + ' (head)'])
+            curs.execute(db_change("select id from user_set where id = ? and name = 'custom_css'"), [ip])
             if curs.fetchall():
-                curs.execute(db_change("update custom set css = ? where user = ?"), [get_data, ip + ' (head)'])
+                curs.execute(db_change("update user_set set data = ? where id = ? and name = 'custom_css'"), [get_data, ip])
             else:
-                curs.execute(db_change("insert into custom (user, css) values (?, ?)"), [ip + ' (head)', get_data])
+                curs.execute(db_change("insert into user_set (id, name, data) values (?, 'custom_css', ?)"), [ip, get_data])
 
             conn.commit()
 
@@ -23,30 +23,33 @@ def user_custom_head_view_2(conn):
         if ip_or_user(ip) == 0:
             start = ''
 
-            curs.execute(db_change("select css from custom where user = ?"), [ip + ' (head)'])
+            curs.execute(db_change("select data from user_set where id = ? and name = 'custom_css'"), [ip])
             head_data = curs.fetchall()
-            if head_data:
-                data = head_data[0][0]
-            else:
-                data = ''
+            data = head_data[0][0] if head_data else ''
         else:
-            start = '<span>' + load_lang('user_head_warring') + '</span><hr class=\"main_hr\">'
-
-            if 'head' in flask.session:
-                data = flask.session['head']
-            else:
-                data = ''
-
-        start += '<span>&lt;style&gt;CSS&lt;/style&gt;<br>&lt;script&gt;JS&lt;/script&gt;</span><hr class=\"main_hr\">'
+            start = '' + \
+                '<span>' + load_lang('user_head_warring') + '</span>' + \
+                '<hr class="main_hr">' + \
+            ''
+            data = flask.session['head'] if 'head' in flask.session else ''
+
+        start += '' + \
+            '<span>' + \
+                '&lt;style&gt;CSS&lt;/style&gt;' + \
+                '<br>' + \
+                '&lt;script&gt;JS&lt;/script&gt;' + \
+            '</span>' + \
+            '<hr class="main_hr">' + \
+        ''
 
         return easy_minify(flask.render_template(skin_check(),
             imp = [load_lang(data = 'user_head', safe = 1), wiki_set(), custom(), other2([0, 0])],
-            data =  start + '''
-                    <form method="post">
-                        <textarea rows="25" cols="100" name="content">''' + data + '''</textarea>
-                        <hr class=\"main_hr\">
-                        <button id="save" type="submit">''' + load_lang('save') + '''</button>
-                    </form>
-                    ''',
+            data = start + '''
+                <form method="post">
+                    <textarea rows="25" cols="100" name="content">''' + data + '''</textarea>
+                    <hr class="main_hr">
+                    <button id="save" type="submit">''' + load_lang('save') + '''</button>
+                </form>
+            ''',
             menu = [['user', load_lang('return')]]
         ))

+ 2 - 5
route/user_tool.py

@@ -13,11 +13,8 @@ def user_tool_2(conn, name):
 
     if admin_check(1) == 1:
         curs.execute(db_change("select block from rb where block = ? and ongoing = '1'"), [name])
-        if curs.fetchall():
-            ban_name = load_lang('release')
-        else:
-            ban_name = load_lang('ban')
-
+        ban_name = load_lang('release') if curs.fetchall() else load_lang('ban')
+        
         data += '''
             <h2>''' + load_lang('admin') + '''</h2>
             <ul>

+ 2 - 2
version.json

@@ -1,7 +1,7 @@
 {
     "beta" : {
-        "r_ver" : "v3.2.0-stable-13 (beta-32) (dev-2020-09-05-01)",
-        "c_ver" : "3202600",
+        "r_ver" : "v3.2.0-stable-13 (beta-36) (dev-2020-09-20-01)",
+        "c_ver" : "3203400",
         "s_ver" : "10"
     }
 }

+ 51 - 25
views/main_css/js/load_namumark.js

@@ -2,12 +2,8 @@ function get_link_state(data, i = 0) {
     var get_class = document.getElementsByClassName(data + 'link_finder')[i];
     if(get_class) {
         var xhr = new XMLHttpRequest();
-        xhr.open(
-            "GET", 
-            get_class.href.replace('/w/', '/api/w/').replace(/#([^#]*)/, '') + "?exist=1", 
-            true
-        );
-        xhr.send(null);
+        xhr.open("GET", get_class.href.replace('/w/', '/api/w/').replace(/#([^#]*)/, '') + "?exist=1");
+        xhr.send();
 
         xhr.onreadystatechange = function() {
             if(this.readyState === 4 && this.status === 200) {
@@ -23,6 +19,14 @@ function get_link_state(data, i = 0) {
     }
 }
 
+function load_image_link(data) {
+    data.innerHTML = '' +
+        '<img   style="' + data.getAttribute('under_style') + '" ' + 
+                'alt="' + data.getAttribute('under_alt') + '" ' + 
+                'src="' + data.getAttribute('under_src') + '">' +
+    '';
+}
+
 function get_file_state(data, i = 0) {       
     var get_class = document.getElementsByClassName(data + 'file_finder')[i];
     if(get_class) {            
@@ -32,9 +36,24 @@ function get_file_state(data, i = 0) {
                 document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '1'
             ) {
                 document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
-                    '<a href="' + get_class.getAttribute('under_src') + '">(' +
-                        get_class.getAttribute('under_src') +
-                    ')</a>' +
+                    '<a href="' + get_class.getAttribute('under_src') + '" ' +
+                        'title="' + get_class.getAttribute('under_src') + '">' + 
+                        '(External image link)' + 
+                    '</a>' +
+                '';
+            } else if(
+                document.cookie.match(main_css_regex_data('main_css_image_set')) &&
+                document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '2'
+            ) {
+                document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
+                    '<a href="javascript:void(0);" ' +
+                        'onclick="load_image_link(this); this.onclick = \'\';" ' + 
+                        'under_style="' + get_class.getAttribute('under_style') + '" ' +
+                        'under_alt="' + get_class.getAttribute('under_alt') + '" ' +
+                        'under_src="' + get_class.getAttribute('under_src') + '" ' +
+                        'title="' + get_class.getAttribute('under_src') + '">' + 
+                        '(External image load)' + 
+                    '</a>' +
                 '';
             } else {
                 document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
@@ -45,12 +64,8 @@ function get_file_state(data, i = 0) {
             }
         } else {
             var xhr = new XMLHttpRequest();
-            xhr.open(
-                "GET", 
-                get_class.getAttribute('under_src').replace('/image/', '/api/image/'), 
-                true
-            );
-            xhr.send(null);
+            xhr.open("GET", get_class.getAttribute('under_src').replace('/image/', '/api/image/'));
+            xhr.send();
             
             xhr.onreadystatechange = function() {
                 if(this.readyState === 4 && this.status === 200) {
@@ -58,7 +73,7 @@ function get_file_state(data, i = 0) {
                         document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
                             '<a href="' + get_class.getAttribute('under_href') + '" ' + 
                                 'id="not_thing">' +
-                                get_class.getAttribute('under_alt') +
+                                + '(' + get_class.getAttribute('under_alt') + ')' +
                             '</a>' +
                         '';
                     } else {
@@ -67,9 +82,22 @@ function get_file_state(data, i = 0) {
                             document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '1'
                         ) {
                             document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
-                                '<a href="' + get_class.getAttribute('under_src') + '">(' +
-                                    get_class.getAttribute('under_alt') +
-                                ')</a>' +
+                                '<a href="' + get_class.getAttribute('under_src') + '">' +
+                                    '(' + get_class.getAttribute('under_alt') + ')' +
+                                '</a>' +
+                            '';
+                        } else if(
+                            document.cookie.match(main_css_regex_data('main_css_image_set')) &&
+                            document.cookie.match(main_css_regex_data('main_css_image_set'))[1] === '2'
+                        ) {
+                            document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
+                                '<a href="javascript:void(0);" ' +
+                                    'onclick="load_image_link(this); this.onclick = \'\';" ' + 
+                                    'under_style="' + get_class.getAttribute('under_style') + '" ' +
+                                    'under_alt="' + get_class.getAttribute('under_alt') + '" ' +
+                                    'under_src="' + get_class.getAttribute('under_src') + '">' + 
+                                    '(' + get_class.getAttribute('under_alt') + ' load)' +
+                                '</a>' +
                             '';
                         } else {
                             document.getElementsByClassName(data + 'file_finder')[i].innerHTML = '' +
@@ -96,8 +124,8 @@ function load_include(title, name, p_data) {
     var url = "/api/w/" + encodeURI(title) + "?include=" + name + "&change=" + change;
 
     var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
+    xhr.open("GET", url);
+    xhr.send();
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {
@@ -106,9 +134,7 @@ function load_include(title, name, p_data) {
                 document.getElementsByClassName(name)[0].id = "not_thing";
             } else {
                 var o_p_data = JSON.parse(this.responseText);
-                
                 document.getElementById(name).innerHTML = o_p_data['data'];
-                
                 eval(o_p_data['js_data']);
             }
         }
@@ -119,8 +145,8 @@ function page_count() {
     var url = "/api/title_index";
 
     var xhr = new XMLHttpRequest();
-    xhr.open("GET", url, true);
-    xhr.send(null);
+    xhr.open("GET", url);
+    xhr.send();
 
     xhr.onreadystatechange = function() {
         if(this.readyState === 4 && this.status === 200) {

+ 131 - 41
views/main_css/js/load_skin_set.js

@@ -3,7 +3,7 @@ function main_css_regex_data(data) {
 }
 
 function main_css_get_post() {    
-    var check = document.getElementById('strike');
+    var check = document.getElementById('main_css_strike');
     if(check.value === 'normal') {
         document.cookie = 'main_css_del_strike=0;';
     } else if(check.value === 'change') {
@@ -12,7 +12,7 @@ function main_css_get_post() {
         document.cookie = 'main_css_del_strike=2;';
     }
 
-    check = document.getElementById('bold');
+    check = document.getElementById('main_css_bold');
     if(check.value === 'normal') {
         document.cookie = 'main_css_del_bold=0;';
     } else if(check.value === 'change') {
@@ -21,41 +21,59 @@ function main_css_get_post() {
         document.cookie = 'main_css_del_bold=2;';
     }
 
-    check = document.getElementById('include');
+    check = document.getElementById('main_css_include');
     if(check.checked) {
         document.cookie = 'main_css_include_link=1;';
     } else {
         document.cookie = 'main_css_include_link=0;';
     }
 
-    check = document.getElementById('category');
+    check = document.getElementById('main_css_category');
     if(check.value === 'bottom') {
         document.cookie = 'main_css_category_set=0;';
     } else {
         document.cookie = 'main_css_category_set=1;';
     }
 
-    check = document.getElementById('footnote');
+    check = document.getElementById('main_css_footnote');
     if(check.value === 'spread') {
         document.cookie = 'main_css_footnote_set=1;';
     } else {
         document.cookie = 'main_css_footnote_set=0;';
     }
 
-    check = document.getElementById('image');
-    if(check.value === 'click') {
+    check = document.getElementById('main_css_image');
+    if(check.value === 'new_click') {
+        document.cookie = 'main_css_image_set=2;';
+    } else if(check.value === 'click') {
         document.cookie = 'main_css_image_set=1;';
     } else {
         document.cookie = 'main_css_image_set=0;';
     }
 
-    check = document.getElementById('image_paste');
+    check = document.getElementById('main_css_image_paste');
     if(check.checked) {
         document.cookie = 'main_css_image_paste=1;';
     } else {
         document.cookie = 'main_css_image_paste=0;';
     }
 
+    check = document.getElementById('main_css_toc');
+    if(check.value === 'on') {
+        document.cookie = 'main_css_toc_set=2;';
+    } else if(check.value === 'off') {
+        document.cookie = 'main_css_toc_set=1;';
+    } else {
+        document.cookie = 'main_css_toc_set=0;';
+    }
+
+    check = document.getElementById('main_css_font_size');
+    if(check.value.match(/^[0-9]+$/)) {
+        document.cookie = 'main_css_font_size=' + check.value + ';';
+    } else {
+        document.cookie = 'main_css_font_size=;';
+    }
+
     history.go(0);
 }
 
@@ -97,9 +115,24 @@ function main_css_skin_load() {
             head_data.innerHTML += '<style>#cate { margin-top: 0px; margin-bottom: 20px; }</style>';
         }
     }
+
+    if(
+        document.cookie.match(main_css_regex_data('main_css_font_size')) &&
+        document.cookie.match(main_css_regex_data('main_css_font_size'))[1] !== ''
+    ) {
+        head_data.innerHTML += '<style>.all_in_data { font-size: ' + document.cookie.match(main_css_regex_data('main_css_font_size'))[1] + 'px; }</style>';
+    }
+
+    if(document.cookie.match(main_css_regex_data('main_css_toc_set'))) {
+        if(document.cookie.match(main_css_regex_data('main_css_toc_set'))[1] === '2') {
+            head_data.innerHTML += '<style>#auto_toc { display: none; }</style>';
+        } else if(document.cookie.match(main_css_regex_data('main_css_toc_set'))[1] === '1') {
+            head_data.innerHTML += '<style>#toc { display: none; }</style>';
+        }
+    }
 }
 
-function main_css_skin_set() {    
+function main_css_load_lang(name) {
     var set_language = {
         "en-US" : {
             "default" : "Default",
@@ -116,7 +149,14 @@ function main_css_skin_set() {
             "set_footnote" : "Set footnote",
             "renderer" : "Renderer",
             "spread" : "Spread",
-            "set_image" : "Set image"
+            "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"
         }, "ko-KR" : {
             "default" : "기본값",
             "change_to_normal" : "일반 텍스트로 변경",
@@ -132,25 +172,42 @@ function main_css_skin_set() {
             "set_footnote" : "각주 설정",
             "renderer" : "렌더러",
             "spread" : "펼치기",
-            "set_image" : "이미지 설정"
+            "set_image" : "이미지 설정",
+            "set_toc" : "목차 설정",
+            "click_load" : "클릭시 불러오기",
+            "in_content" : "문서 안에 있을 때만",
+            "all_off" : "항상 끔",
+            "set_font_size" : "글자 크기 설정",
+            "change_to_link" : "링크로 변경",
+            "font_size" : "글자 크기"
         }
     }
 
-    var language = document.cookie.match(main_css_regex_data('language'))[1];
+    var server_language = document.cookie.match(main_css_regex_data('language'))[1];
     var user_language = document.cookie.match(main_css_regex_data('user_language'))[1];
     if(user_language in set_language) {
         language = user_language;
+    } else {
+        if(server_language in set_language) {
+            language = language;
+        } else {
+            language = 'en-US';
+        }
     }
 
-    if(!language in set_language) {
-        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', set_language[language]['default']],
-        ['1', 'change', set_language[language]['change_to_normal']],
-        ['2', 'delete', set_language[language]['delete']]
+        ['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;
@@ -168,9 +225,9 @@ function main_css_skin_set() {
     }
 
     var bold_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'change', set_language[language]['change_to_normal']],
-        ['2', 'delete', set_language[language]['delete']]
+        ['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;
@@ -206,8 +263,8 @@ function main_css_skin_set() {
     }
 
     var category_list = [
-        ['0', 'bottom', set_language[language]['bottom']],
-        ['1', 'top', set_language[language]['top']],
+        ['0', 'bottom', main_css_load_lang('bottom')],
+        ['1', 'top', main_css_load_lang('top')],
     ];
     set_data["category"] = '';
     i = 0;
@@ -225,8 +282,8 @@ function main_css_skin_set() {
     }
 
     var footnote_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'spread', set_language[language]['spread']]
+        ['0', 'normal', main_css_load_lang('default')],
+        ['1', 'spread', main_css_load_lang('spread')]
     ];
     set_data["footnote"] = '';
     i = 0;
@@ -244,8 +301,9 @@ function main_css_skin_set() {
     }
 
     var image_list = [
-        ['0', 'normal', set_language[language]['default']],
-        ['1', 'click', 'click (beta)']
+        ['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;
@@ -262,33 +320,65 @@ function main_css_skin_set() {
         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(main_css_regex_data('main_css_toc_set')) && 
+            document.cookie.match(main_css_regex_data('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(main_css_regex_data('main_css_font_size'))) {
+        set_data["font_size"] = document.cookie.match(main_css_regex_data('main_css_font_size'))[1];
+    } else {
+        set_data["font_size"] = '';
+    }
+
     document.getElementById("main_skin_set").innerHTML = ' \
-        <h2>1. ' + set_language[language]['renderer'] + '</h2> \
-        <h3>1.1. ' + set_language[language]['strike'] + '</h3> \
-        <select id="strike" name="strike"> \
+        <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. ' + set_language[language]['bold'] + '</h3> \
-        <select id="bold" name="bold"> \
+        <h3>1.2. ' + main_css_load_lang('bold') + '</h3> \
+        <select id="main_css_bold"> \
             ' + set_data["bold"] + ' \
         </select> \
-        <h3>1.3. ' + set_language[language]['where_category'] + '</h3> \
-        <select id="category" name="category"> \
+        <h3>1.3. ' + main_css_load_lang('where_category') + '</h3> \
+        <select id="main_css_category"> \
             ' + set_data["category"] + ' \
         </select> \
-        <h3>1.4. ' + set_language[language]['set_footnote'] + '</h3> \
-        <select id="footnote" name="footnote"> \
+        <h3>1.4. ' + main_css_load_lang('set_footnote') + '</h3> \
+        <select id="main_css_footnote"> \
             ' + set_data["footnote"] + ' \
         </select> \
-        <h3>1.5. ' + set_language[language]['set_image'] + '</h3> \
-        <select id="image" name="image"> \
+        <h3>1.5. ' + main_css_load_lang('set_image') + '</h3> \
+        <select id="main_css_image"> \
             ' + set_data["image"] + ' \
         </select> \
-        <h3>1.6. ' + set_language[language]['other'] + '</h3> \
-        <input ' + set_data["include"] + ' type="checkbox" id="include" name="include" value="include"> ' + set_language[language]['include_link'] + ' \
+        <h3>1.6. ' + main_css_load_lang('other') + '</h3> \
+        <input ' + set_data["include"] + ' type="checkbox" id="main_css_include" value="include"> ' + main_css_load_lang('include_link') + ' \
         <hr class="main_hr"> \
-        <input ' + set_data["image_paste"] + ' type="checkbox" id="image_paste" name="image_paste" value="image_paste"> 클립보드 이미지 업로드 (ko-KR) \
+        <input ' + set_data["image_paste"] + ' type="checkbox" id="main_css_image_paste" value="image_paste"> 클립보드 이미지 업로드 (ko-KR) \
+        <h3>1.7. ' + main_css_load_lang('set_toc') + '</h3> \
+        <select id="main_css_toc"> \
+            ' + set_data["toc"] + ' \
+        </select> \
+        <h3>1.8. ' + main_css_load_lang('set_font_size') + '</h3> \
+        <input id="main_css_font_size" placeholder="' + main_css_load_lang('font_size') + '" value="' + set_data["font_size"] + '"> \
         <hr class="main_hr"> \
-        <button onclick="main_css_get_post();">' + set_language[language]['save'] + '</button> \
+        <button onclick="main_css_get_post();">' + main_css_load_lang('save') + '</button> \
     ';
 }