mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
Update to 7.7.0
Since version 7.7.0, we recommend yours update python to 3.12. [+] Using nginx technology to load static files improves access speed [+] Refactor homepage, website, FTP, and database using vue3 [+] Table loading changed to skeleton screen [+] Add Website statistics-v2 professional plug-in [+] Add Home page - top 5 resource occupancy [+] Add protection for Files management (requires Tamper-proof for Enterprise 3.7) [+] Website, FTP, Databases page add program status [+] Add FTP log analysis (only supports Centos) [+] Add password-free login to phpMyAdmin [+] Add Proxy Project in Website (Supported when web service uses Nginx) [+] Add WP Toolkit (Pro version only) [+] Redesigned Docker module [+] Add WP Toolkit Protection [+] Add WP Toolkit Backup and Restore [+] Add WP Toolkit Migrated [+] Add WP Toolkit Clone site (supports new domain and subdomain) [+] Add WP Toolkit Create site from backup of other panel [+] Add WP Toolkit support for Cron automatic backup (only save Local disk) [+] Add WP Toolkit operation log [+] Add Integrity check for WP Toolkit [+] Add WP Toolkit plug-in management and themes management [*] Optimize phpMyAdmin formula access method [*] Optimize Home page PHP display problem [*] Optimize jump to the login interface after the login expires [*] Optimize automatic renewal of SSL at some times [*] Optimize Let's Encrypt to increase application success rate [-] Fix Logs Audit cannot be opened [-] Fix apache URL rewrite issue [-] Fix phpmyadmin installation problem [-] Fix the problem that some servers cannot install software [-] Fix upload file error [-] Fix left menu hiding problem [-] Fix aaPanel Mobile QR code display problem [-] Fix problem that third-party plug-ins are not displayed in the App Store [-] Fix issue where the menu bar is blank when opening new tabs [-] Fixed panel not being accessible in some cases [-] Fix the issue where Curl warning caused the inability to apply for SSL [-] Fix Quota issues for Website, FTP, Databases [-] Fix file interface display problem on mobile terminal
This commit is contained in:
@@ -1,26 +1,36 @@
|
||||
#!/www/server/panel/pyenv/bin/python
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# | aaPanel
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# | Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# | Author: hwliang <hwl@aapanel.com>
|
||||
# +-------------------------------------------------------------------
|
||||
from gevent import monkey
|
||||
|
||||
|
||||
monkey.patch_all()
|
||||
import os,sys,ssl,time,logging
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import ssl
|
||||
import time
|
||||
import logging
|
||||
import psutil
|
||||
|
||||
|
||||
_PATH = '/www/server/panel'
|
||||
os.chdir(_PATH)
|
||||
os.system("nohup ./pyenv/bin/python3 class/jobs.py &>/dev/null &")
|
||||
upgrade_file = 'script/upgrade_flask.sh'
|
||||
if os.path.exists(upgrade_file):
|
||||
os.system("nohup bash {} &>/dev/null &".format(upgrade_file))
|
||||
|
||||
upgrade_file = 'script/upgrade_gevent.sh'
|
||||
if os.path.exists(upgrade_file):
|
||||
os.system("nohup bash {} &>/dev/null &".format(upgrade_file))
|
||||
# upgrade_file = 'script/upgrade_flask.sh'
|
||||
# if os.path.exists(upgrade_file):
|
||||
# os.system("nohup bash {} &>/dev/null &".format(upgrade_file))
|
||||
#
|
||||
# upgrade_file = 'script/upgrade_gevent.sh'
|
||||
# if os.path.exists(upgrade_file):
|
||||
# os.system("nohup bash {} &>/dev/null &".format(upgrade_file))
|
||||
|
||||
upgrade_file = 'script/upgrade_telegram.sh'
|
||||
if os.path.exists(upgrade_file):
|
||||
@@ -44,13 +54,13 @@ def check_plugin_loader():
|
||||
machine = os.uname().machine
|
||||
except:
|
||||
pass
|
||||
plugin_loader_src_file = "class/PluginLoader.{}.Python3.7.so".format(machine)
|
||||
plugin_loader_src_file = "class/PluginLoader.{}.Python3.12.so".format(machine)
|
||||
if machine == 'x86_64':
|
||||
glibc_version = public.get_glibc_version()
|
||||
if glibc_version in ['2.14','2.13','2.12','2.11','2.10']:
|
||||
plugin_loader_src_file = "class/PluginLoader.{}.glibc214.Python3.7.so".format(machine)
|
||||
plugin_loader_src_file = "class/PluginLoader.{}.glibc214.Python3.12.so".format(machine)
|
||||
if os.path.exists(plugin_loader_src_file):
|
||||
os.system("\cp -f {} {}".format(plugin_loader_src_file, plugin_loader_file))
|
||||
os.system(r"\cp -f {} {}".format(plugin_loader_src_file, plugin_loader_file))
|
||||
|
||||
check_plugin_loader()
|
||||
|
||||
@@ -67,7 +77,8 @@ if is_debug:
|
||||
re.compile('{}/(tmp|temp)/.+'.format(_PATH)),
|
||||
re.compile('{}/pyenv/.+'.format(_PATH)),
|
||||
re.compile('{}/class/projectModel/.+'.format(_PATH)),
|
||||
re.compile('{}/class/databaseModel/.+'.format(_PATH))
|
||||
re.compile('{}/class/databaseModel/.+'.format(_PATH)),
|
||||
re.compile('{}/panel/data/mail/in_bulk/content/.+'.format(_PATH))
|
||||
]
|
||||
_lsat_time = 0
|
||||
|
||||
@@ -155,6 +166,29 @@ def daemon_task():
|
||||
run_task()
|
||||
continue
|
||||
|
||||
def get_process_count():
|
||||
'''
|
||||
@name 获取进程数量
|
||||
@return int
|
||||
'''
|
||||
|
||||
# 如果存在用户配置,则直接返回用户配置的进程数量
|
||||
process_count_file = "{}/data/process_count.pl".format(_PATH)
|
||||
if os.path.exists(process_count_file):
|
||||
str_count = public.readFile(process_count_file).strip()
|
||||
try:
|
||||
if str_count: return int(str_count)
|
||||
except: pass
|
||||
|
||||
# 否则根据内存和CPU核心数来决定启动进程数量
|
||||
memory = psutil.virtual_memory().total / 1024 / 1024
|
||||
cpu_count = psutil.cpu_count()
|
||||
if memory < 4000 or cpu_count < 4: return 1 # 内存小于4G或CPU核心小于4核,则只启动1个进程
|
||||
if memory < 8000 and cpu_count > 3: return 2 # 内存大于4G且小于8G,且CPU核心大于3核,则启动2个进程
|
||||
if memory > 14000 and cpu_count > 7: return 3 # 内存大于8G且14G,且CPU核心大于7核,则启动3个进程
|
||||
if memory > 30000 and cpu_count > 15: return 4 # 内存大于30G且CPU核心大于15核,则启动4个进程
|
||||
return 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
pid_file = "{}/logs/panel.pid".format(_PATH)
|
||||
if os.path.exists(pid_file):
|
||||
@@ -172,6 +206,8 @@ if __name__ == '__main__':
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
# 面板启动任务初始化
|
||||
os.system("nohup ./pyenv/bin/python3 class/jobs.py &>/dev/null &")
|
||||
|
||||
try:
|
||||
f = open('data/port.pl')
|
||||
@@ -199,8 +235,7 @@ if __name__ == '__main__':
|
||||
print(ex)
|
||||
|
||||
import threading
|
||||
task_thread = threading.Thread(target=daemon_task)
|
||||
task_thread.setDaemon(True)
|
||||
task_thread = threading.Thread(target=daemon_task, daemon=True)
|
||||
task_thread.start()
|
||||
|
||||
if is_ssl:
|
||||
@@ -232,18 +267,76 @@ if __name__ == '__main__':
|
||||
app.logger = logger
|
||||
|
||||
from gevent.pywsgi import WSGIServer
|
||||
try:
|
||||
import flask_sock
|
||||
import webserver
|
||||
|
||||
class BtWSGIServer(WSGIServer):
|
||||
def wrap_socket_and_handle(self, client_socket, address):
|
||||
try:
|
||||
return super(BtWSGIServer, self).wrap_socket_and_handle(client_socket, address)
|
||||
except OSError as e:
|
||||
pass
|
||||
# public.print_exc_stack(e)
|
||||
|
||||
def do_read(self):
|
||||
try:
|
||||
return super(BtWSGIServer, self).do_read()
|
||||
except OSError as e:
|
||||
pass
|
||||
# public.print_exc_stack(e)
|
||||
|
||||
webserver_obj = webserver.webserver()
|
||||
is_webserver = webserver_obj.run_webserver()
|
||||
# is_webserver = False
|
||||
|
||||
if is_webserver:
|
||||
from gevent import socket
|
||||
listener = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
unix_socket = '/tmp/panel.sock'
|
||||
if os.path.exists(unix_socket):
|
||||
os.remove(unix_socket)
|
||||
listener.bind(unix_socket)
|
||||
listener.listen(500)
|
||||
os.chmod(unix_socket, 0o777)
|
||||
try:
|
||||
import flask_sock
|
||||
http_server = BtWSGIServer(listener, app,log=app.logger)
|
||||
except:
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
http_server = BtWSGIServer(listener, app,handler_class=WebSocketHandler,log=app.logger)
|
||||
else:
|
||||
if is_ssl:
|
||||
http_server = WSGIServer((HOST, PORT), app,ssl_context = ssl_context,log=app.logger)
|
||||
else:
|
||||
http_server = WSGIServer((HOST, PORT), app,log=app.logger)
|
||||
except:
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
if is_ssl:
|
||||
http_server = WSGIServer((HOST, PORT), app,ssl_context = ssl_context,handler_class=WebSocketHandler,log=app.logger)
|
||||
else:
|
||||
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,log=app.logger)
|
||||
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
ssl_context.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||
if hasattr(ssl_context, "minimum_version"):
|
||||
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
|
||||
else:
|
||||
ssl_context.options = (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
|
||||
|
||||
ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE")
|
||||
is_ssl_verify = os.path.exists('/www/server/panel/data/ssl_verify_data.pl')
|
||||
if is_ssl_verify:
|
||||
crlfile = '/www/server/panel/ssl/crl.pem'
|
||||
rootcafile = '/www/server/panel/ssl/ca.pem'
|
||||
#注销列表
|
||||
# ssl_context.load_verify_locations(crlfile)
|
||||
# ssl_context.verify_flags |= ssl.VERIFY_CRL_CHECK_CHAIN
|
||||
#加载证书
|
||||
ssl_context.load_verify_locations(rootcafile)
|
||||
ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||
ssl_context.set_default_verify_paths()
|
||||
|
||||
try:
|
||||
import flask_sock
|
||||
if is_ssl:
|
||||
http_server = BtWSGIServer((HOST, PORT), app,ssl_context = ssl_context,log=app.logger)
|
||||
else:
|
||||
http_server = BtWSGIServer((HOST, PORT), app,log=app.logger)
|
||||
except:
|
||||
from geventwebsocket.handler import WebSocketHandler
|
||||
if is_ssl:
|
||||
http_server = BtWSGIServer((HOST, PORT), app,ssl_context = ssl_context,handler_class=WebSocketHandler,log=app.logger)
|
||||
else:
|
||||
http_server = BtWSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,log=app.logger)
|
||||
|
||||
|
||||
if is_debug:
|
||||
@@ -258,20 +351,58 @@ if __name__ == '__main__':
|
||||
try:
|
||||
http_server.serve_forever()
|
||||
except:
|
||||
pass
|
||||
from traceback import format_exc
|
||||
public.print_log(format_exc())
|
||||
app.run(host=HOST, port=PORT, threaded=True)
|
||||
else:
|
||||
http_server.start()
|
||||
from multiprocessing import Process
|
||||
|
||||
|
||||
def serve_forever():
|
||||
http_server.start_accepting()
|
||||
http_server._stop_event.wait()
|
||||
|
||||
process_count = 2
|
||||
for i in range(process_count):
|
||||
p = Process(target=serve_forever)
|
||||
p.daemon = True
|
||||
p.start()
|
||||
|
||||
# 获取最大进程数量,最小为2个
|
||||
process_count = get_process_count()
|
||||
if process_count < 2: process_count = 2
|
||||
|
||||
# 启动主进程
|
||||
main_p = Process(target=serve_forever)
|
||||
main_p.daemon = True
|
||||
main_p.start()
|
||||
main_psutil = psutil.Process(main_p.pid)
|
||||
|
||||
# 动态按需调整子进程数量
|
||||
process_dict = {}
|
||||
while 1:
|
||||
time.sleep(1000)
|
||||
t = time.time()
|
||||
# 当主进程CPU占用率超过90%时,尝试启动新的子进程协同处理
|
||||
cpu_percent = main_psutil.cpu_percent(interval=1)
|
||||
if cpu_percent > 90:
|
||||
is_alive = 0
|
||||
process_num = 0
|
||||
|
||||
# 检查是否存在空闲的子进程
|
||||
for i in process_dict.keys():
|
||||
process_num += 1
|
||||
if process_dict[i][2].cpu_percent(interval=1) > 0:
|
||||
is_alive += 1
|
||||
|
||||
# 如果没有空闲的子进程,且当前子进程数量小于最大进程数量,则启动新的子进程
|
||||
if process_num == is_alive and process_num < process_count:
|
||||
p = Process(target=serve_forever)
|
||||
p.daemon = True
|
||||
p.start()
|
||||
process_dict[p.pid] = [p, t, psutil.Process(p.pid)]
|
||||
|
||||
# 结束创建时间超过60秒,且连续空闲5秒钟以上的子进程
|
||||
keys = list(process_dict.keys())
|
||||
for i in keys:
|
||||
if t - process_dict[i][1] < 60: continue
|
||||
if process_dict[i][2].cpu_percent(interval=5) > 0: continue
|
||||
process_dict[i][0].kill()
|
||||
process_dict.pop(i)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#!/www/server/panel/pyenv/bin/python
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# | aaPanel
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# | Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# | Author: hwliang <hwl@aapanel.com>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import os,sys
|
||||
|
||||
+3846
-814
File diff suppressed because it is too large
Load Diff
+671
@@ -0,0 +1,671 @@
|
||||
# coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: hwliang <hwl@bt.cn>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import re
|
||||
import uuid
|
||||
import psutil
|
||||
|
||||
panel_path = '/www/server/panel'
|
||||
if not os.name in ['nt']:
|
||||
os.chdir(panel_path)
|
||||
if not 'class/' in sys.path:
|
||||
sys.path.insert(0, 'class/')
|
||||
if not 'class_v2/' in sys.path:
|
||||
sys.path.insert(0, 'class_v2/')
|
||||
from flask import Flask, session, render_template, send_file, request, redirect, g, make_response, \
|
||||
render_template_string, abort, stream_with_context, Response as Resp
|
||||
from cachelib import SimpleCache, SimpleCacheSession
|
||||
from werkzeug.wrappers import Response
|
||||
from werkzeug.routing import BaseConverter
|
||||
from flask_session import Session
|
||||
from flask_compress import Compress
|
||||
|
||||
cache = SimpleCache(5000)
|
||||
import public
|
||||
|
||||
# class RestrictedImportHook:
|
||||
# def __init__(self, allowed_modules):
|
||||
# self.allowed_modules = allowed_modules
|
||||
#
|
||||
# def find_spec(self, fullname, path, target=None):
|
||||
# # 判断当前导入是否是功能模块,如果是则禁止导入
|
||||
# if fullname in self.allowed_modules:
|
||||
# return None
|
||||
# return self
|
||||
#
|
||||
# def loader(self, fullname):
|
||||
# # 不禁止public模块的导入
|
||||
# if fullname == 'public':
|
||||
# pass
|
||||
#
|
||||
# # 其他功能模块 不能互相导入
|
||||
# # elif fullname in ['aaa', 'bbb', 'ccc']:
|
||||
# # return APIModuleLoader(self.allowed_module)
|
||||
# 设置导入钩子
|
||||
# sys.meta_path.insert(0, RestrictedImportHook(['panelPlugin', 'pay', 'ols', 'wxapp']))
|
||||
# sys.meta_path.insert(0, RestrictedImportHook(['wxapp']))
|
||||
# class APIModuleLoader:
|
||||
# def __init__(self, allowed_module):
|
||||
# self.allowed_module = allowed_module
|
||||
#
|
||||
# def exec_module(self, module):
|
||||
# if self.allowed_module != 'public':
|
||||
# raise ImportError(f"API module '{self.allowed_module}' cannot import other API modules")
|
||||
#
|
||||
# if module.__name__ != 'public':
|
||||
# module.__dict__['public'] = sys.modules['public']
|
||||
|
||||
# # 设置导入钩子
|
||||
# sys.meta_path.insert(0, RestrictedImportHook('public'))
|
||||
|
||||
# 初始化Flask应用
|
||||
app = Flask(__name__,
|
||||
template_folder="templates/{}".format(
|
||||
public.GetConfigValue('template')))
|
||||
Compress(app)
|
||||
try:
|
||||
from flask_sock import Sock
|
||||
except:
|
||||
from flask_sockets import Sockets as Sock
|
||||
|
||||
sockets = Sock(app)
|
||||
# 注册HOOK
|
||||
hooks = {}
|
||||
if not hooks:
|
||||
public.check_hooks()
|
||||
# import db
|
||||
dns_client = None
|
||||
app.config['DEBUG'] = os.path.exists('data/debug.pl')
|
||||
app.config['SSL'] = os.path.exists('data/ssl.pl')
|
||||
|
||||
# 设置BasicAuth
|
||||
basic_auth_conf = 'config/basic_auth.json'
|
||||
app.config['BASIC_AUTH_OPEN'] = False
|
||||
if os.path.exists(basic_auth_conf):
|
||||
try:
|
||||
ba_conf = json.loads(public.readFile(basic_auth_conf))
|
||||
app.config['BASIC_AUTH_USERNAME'] = ba_conf['basic_user']
|
||||
app.config['BASIC_AUTH_PASSWORD'] = ba_conf['basic_pwd']
|
||||
app.config['BASIC_AUTH_OPEN'] = ba_conf['open']
|
||||
except:
|
||||
pass
|
||||
|
||||
# 初始化SESSION服务
|
||||
app.secret_key = public.md5(
|
||||
str(os.uname()) +
|
||||
str(psutil.boot_time())) # uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
local_ip = None
|
||||
my_terms = {}
|
||||
app.config['SESSION_MEMCACHED'] = SimpleCacheSession(1000, 86400)
|
||||
app.config['SESSION_TYPE'] = 'memcached'
|
||||
app.config['SESSION_PERMANENT'] = True
|
||||
app.config['SESSION_USE_SIGNER'] = True
|
||||
app.config['SESSION_KEY_PREFIX'] = 'BT_:'
|
||||
app.config['SESSION_COOKIE_NAME'] = public.md5(app.secret_key)
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 * 30
|
||||
if app.config['SSL']:
|
||||
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
|
||||
app.config['SESSION_COOKIE_SECURE'] = True
|
||||
else:
|
||||
app.config['SESSION_COOKIE_SAMESITE'] = None
|
||||
|
||||
Session(app)
|
||||
|
||||
import common
|
||||
|
||||
# 初始化路由
|
||||
comm = common.panelAdmin()
|
||||
method_all = ['GET', 'POST']
|
||||
method_get = ['GET']
|
||||
method_post = ['POST']
|
||||
json_header = {'Content-Type': 'application/json; charset=utf-8'}
|
||||
text_header = {'Content-Type': 'text/plain; charset=utf-8'}
|
||||
cache.set('p_token', 'bmac_' + public.Md5(public.get_mac_address()))
|
||||
admin_path_file = 'data/admin_path.pl'
|
||||
admin_path = '/'
|
||||
if os.path.exists(admin_path_file):
|
||||
admin_path = public.readFile(admin_path_file).strip()
|
||||
admin_path_checks = [
|
||||
'/',
|
||||
'/san',
|
||||
'/bak',
|
||||
'/monitor',
|
||||
'/abnormal',
|
||||
'/close',
|
||||
'/task',
|
||||
'/login',
|
||||
'/config',
|
||||
'/site',
|
||||
'/sites',
|
||||
'/ftp',
|
||||
'/public',
|
||||
'/database',
|
||||
'/data',
|
||||
'/download_file',
|
||||
'/control',
|
||||
'/crontab',
|
||||
'/firewall',
|
||||
'/files',
|
||||
'/soft',
|
||||
'/ajax',
|
||||
'/system',
|
||||
'/panel_data',
|
||||
'/code',
|
||||
'/ssl',
|
||||
'/plugin',
|
||||
'/wxapp',
|
||||
'/hook',
|
||||
'/safe',
|
||||
'/yield',
|
||||
'/downloadApi',
|
||||
'/pluginApi',
|
||||
'/auth',
|
||||
'/download',
|
||||
'/cloud',
|
||||
'/webssh',
|
||||
'/connect_event',
|
||||
'/panel',
|
||||
'/acme',
|
||||
'/down',
|
||||
'/api',
|
||||
'/tips',
|
||||
'/message',
|
||||
'/warning',
|
||||
'/userRegister', # 面板内注册
|
||||
'/docker',
|
||||
'/btdocker',
|
||||
]
|
||||
if admin_path in admin_path_checks: admin_path = '/bt'
|
||||
if admin_path[-1] == '/': admin_path = admin_path[:-1]
|
||||
uri_match = re.compile(
|
||||
r"(^/static/[\w_\./\-]+\.(js|css|png|jpg|gif|ico|svg|woff|woff2|ttf|otf|eot|map)$|^/[\w_\./\-]*$)"
|
||||
)
|
||||
session_id_match = re.compile(r"^[\w\.\-]+$")
|
||||
|
||||
route_path = os.path.join(admin_path, '')
|
||||
if not route_path: route_path = '/'
|
||||
if route_path[-1] == '/': route_path = route_path[:-1]
|
||||
if route_path[0] != '/': route_path = '/' + route_path
|
||||
|
||||
route_v2 = '/v2' #v2版本路由前缀
|
||||
|
||||
# ======================公共方法区域START============================#
|
||||
|
||||
def error_500(e: Exception):
|
||||
if request.method not in ['GET', 'POST']: return
|
||||
if not session.get('login', None):
|
||||
g.auth_error = True
|
||||
return public.error_not_login()
|
||||
ss = '''404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
|
||||
During handling of the above exception, another exception occurred:'''
|
||||
error_info = public.get_error_info().strip().split(ss)[-1].strip()
|
||||
_form = request.form.to_dict()
|
||||
if 'username' in _form: _form['username'] = '******'
|
||||
if 'password' in _form: _form['password'] = '******'
|
||||
if 'phone' in _form: _form['phone'] = '******'
|
||||
request_info = '''REQUEST_DATE: {request_date}
|
||||
PAN_VERSION: {panel_version}
|
||||
OS_VERSION: {os_version}
|
||||
REMOTE_ADDR: {remote_addr}
|
||||
REQUEST_URI: {method} {full_path}
|
||||
REQUEST_FORM: {request_form}
|
||||
USER_AGENT: {user_agent}'''.format(
|
||||
request_date=public.getDate(),
|
||||
remote_addr=public.GetClientIp(),
|
||||
method=request.method,
|
||||
full_path=public.xsssec(request.full_path),
|
||||
request_form=public.xsssec(str(_form)),
|
||||
user_agent=public.xsssec(request.headers.get('User-Agent')),
|
||||
panel_version=public.version(),
|
||||
os_version=public.get_os_version())
|
||||
|
||||
result = public.readFile(
|
||||
public.get_panel_path() +
|
||||
'/BTPanel/templates/default/panel_error.html').format(
|
||||
error_title=error_info.split("\n")[-1],
|
||||
request_info=request_info,
|
||||
error_msg=error_info)
|
||||
return Resp(result, 500)
|
||||
|
||||
def get_dir_down(filename, token, find):
|
||||
# 获取分享目录信息
|
||||
import files
|
||||
args = public.dict_obj()
|
||||
args.path = filename
|
||||
args.share = True
|
||||
to_path = filename.replace(find['filename'], '').strip('/')
|
||||
|
||||
if request.args.get('play') == 'true':
|
||||
pdata = files.files().get_videos(args)
|
||||
return public.GetJson(pdata), json_header
|
||||
else:
|
||||
pdata = files.files().GetDir(args)
|
||||
pdata['token'] = token
|
||||
pdata['ps'] = find['ps']
|
||||
pdata['src_path'] = find['filename']
|
||||
pdata['to_path'] = to_path
|
||||
if find['expire'] < (time.time() + (86400 * 365 * 10)):
|
||||
pdata['expire'] = public.format_date(times=find['expire'])
|
||||
else:
|
||||
pdata['expire'] = public.get_msg_gettext('Never Expires')
|
||||
pdata['filename'] = (find['filename'].split('/')[-1] + '/' +
|
||||
to_path).strip('/')
|
||||
return render_template('down.html', data=pdata, to_size=public.to_size)
|
||||
|
||||
|
||||
def get_phpmyadmin_dir():
|
||||
# 获取phpmyadmin目录
|
||||
path = public.GetConfigValue('setup_path') + '/phpmyadmin'
|
||||
if not os.path.exists(path): return None
|
||||
phpport = '888'
|
||||
try:
|
||||
import re
|
||||
if session['webserver'] == 'nginx':
|
||||
filename = public.GetConfigValue(
|
||||
'setup_path') + '/nginx/conf/nginx.conf'
|
||||
conf = public.readFile(filename)
|
||||
rep = r"listen\s+([0-9]+)\s*;"
|
||||
rtmp = re.search(rep, conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
if session['webserver'] == 'apache':
|
||||
filename = public.GetConfigValue(
|
||||
'setup_path') + '/apache/conf/extra/httpd-vhosts.conf'
|
||||
conf = public.readFile(filename)
|
||||
rep = r"Listen\s+([0-9]+)\s*\n"
|
||||
rtmp = re.search(rep, conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
if session['webserver'] == 'openlitespeed':
|
||||
filename = public.GetConfigValue(
|
||||
'setup_path') + '/panel/vhost/openlitespeed/listen/888.conf'
|
||||
public.writeFile('/tmp/2', filename)
|
||||
conf = public.readFile(filename)
|
||||
rep = r"address\s*\*\:\s*(\d+)"
|
||||
rtmp = re.search(rep, conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
for filename in os.listdir(path):
|
||||
filepath = path + '/' + filename
|
||||
if os.path.isdir(filepath):
|
||||
if filename[0:10] == 'phpmyadmin':
|
||||
return str(filename), phpport
|
||||
return None
|
||||
|
||||
|
||||
class run_exec:
|
||||
# 模块访问对像
|
||||
def run(self, toObject, defs, get):
|
||||
result = None
|
||||
|
||||
if not get.action in defs:
|
||||
return public.ReturnJson(
|
||||
False, 'Specific parameters are invalid!'), json_header
|
||||
|
||||
result = getattr(toObject, get.action)(get)
|
||||
if not hasattr(get, 'html') and not hasattr(get, 's_module'):
|
||||
r_type = type(result)
|
||||
if r_type in [Response, Resp]: return result
|
||||
result = public.GetJson(result), json_header
|
||||
|
||||
if g.is_aes:
|
||||
result = public.aes_encrypt(result[0], g.aes_key), json_header
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def check_csrf():
|
||||
# CSRF校验
|
||||
if app.config['DEBUG']: return True
|
||||
http_token = request.headers.get('x-http-token')
|
||||
if not http_token: return False
|
||||
if http_token != public.get_csrf_sess_html_token_value(): return False
|
||||
return True
|
||||
|
||||
|
||||
def publicObject(toObject, defs, action=None, get=None, is_csrf=True):
|
||||
try:
|
||||
# 模块访问前置检查
|
||||
if is_csrf and public.get_csrf_sess_html_token_value() and session.get(
|
||||
'login', None):
|
||||
if not check_csrf():
|
||||
return public.ReturnJson(False, 'INIT_CSRF_ERR'), json_header
|
||||
|
||||
if not get: get = get_input()
|
||||
if action: get.action = action
|
||||
|
||||
if hasattr(get, 'path'):
|
||||
get.path = get.path.replace('//', '/').replace('\\', '/')
|
||||
if get.path.find('./') != -1:
|
||||
return public.ReturnJson(False, 'Unsafe path'), json_header
|
||||
if get.path.find('->') != -1:
|
||||
get.path = get.path.split('->')[0].strip()
|
||||
get.path = public.xssdecode(get.path)
|
||||
if hasattr(get, 'filename'):
|
||||
get.filename = public.xssdecode(get.filename)
|
||||
|
||||
if hasattr(get, 'sfile'):
|
||||
get.sfile = get.sfile.replace('//', '/').replace('\\', '/')
|
||||
get.sfile = public.xssdecode(get.sfile)
|
||||
if hasattr(get, 'dfile'):
|
||||
get.dfile = get.dfile.replace('//', '/').replace('\\', '/')
|
||||
get.dfile = public.xssdecode(get.dfile)
|
||||
|
||||
if hasattr(toObject, 'site_path_check'):
|
||||
if not toObject.site_path_check(get):
|
||||
return public.ReturnJson(
|
||||
False, "Overstepping one authority!"), json_header
|
||||
return run_exec().run(toObject, defs, get)
|
||||
except:
|
||||
return error_500(None)
|
||||
|
||||
|
||||
def check_login(http_token=None):
|
||||
# 检查是否登录面板
|
||||
if cache.get('dologin'): return False
|
||||
if 'login' in session:
|
||||
loginStatus = session['login']
|
||||
if loginStatus and http_token:
|
||||
if public.get_csrf_sess_html_token_value() != http_token:
|
||||
return False
|
||||
return loginStatus
|
||||
return False
|
||||
|
||||
|
||||
def get_pd():
|
||||
# 获取授权信息
|
||||
tmp = -1
|
||||
# try:
|
||||
# import panelPlugin
|
||||
# get = public.dict_obj()
|
||||
# # get.init = 1
|
||||
# tmp1 = panelPlugin.panelPlugin().get_cloud_list(get)
|
||||
# except:
|
||||
tmp1 = None
|
||||
if tmp1:
|
||||
tmp = tmp1[public.to_string([112, 114, 111])]
|
||||
ltd = tmp1.get('ltd', -1)
|
||||
else:
|
||||
ltd = -1
|
||||
tmp4 = cache.get(public.to_string([112, 95, 116, 111, 107, 101, 110]))
|
||||
if tmp4:
|
||||
tmp_f = public.to_string([47, 116, 109, 112, 47]) + tmp4
|
||||
if not os.path.exists(tmp_f): public.writeFile(tmp_f, '-1')
|
||||
tmp = public.readFile(tmp_f)
|
||||
if tmp: tmp = int(tmp)
|
||||
|
||||
if ltd < 1:
|
||||
if ltd == -2:
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
|
||||
116, 108, 116, 100, 45, 103, 114, 97, 121, 34, 62, 60, 115,
|
||||
112, 97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111,
|
||||
108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102,
|
||||
111, 110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98,
|
||||
111, 108, 100, 59, 109, 97, 114, 103, 105, 110, 45, 114, 105,
|
||||
103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807, 26399,
|
||||
60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115,
|
||||
115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99,
|
||||
108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46,
|
||||
117, 112, 100, 97, 116, 97, 95, 108, 116, 100, 40, 41, 34, 62,
|
||||
82, 69, 78, 69, 87, 60, 47, 97, 62, 60, 47, 115, 112, 97, 110,
|
||||
62
|
||||
])
|
||||
elif tmp == -1:
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
|
||||
116, 112, 114, 111, 45, 102, 114, 101, 101, 34, 32, 111, 110,
|
||||
99, 108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116,
|
||||
46, 114, 101, 110, 101, 119, 95, 112, 114, 111, 40, 41, 34, 32,
|
||||
116, 105, 116, 108, 101, 61, 34, 67, 108, 105, 99, 107, 32,
|
||||
116, 111, 32, 103, 101, 116, 32, 80, 82, 79, 34, 62, 20813,
|
||||
36153, 29256, 60, 47, 115, 112, 97, 110, 62
|
||||
])
|
||||
elif tmp == -2:
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
|
||||
116, 112, 114, 111, 45, 103, 114, 97, 121, 34, 62, 60, 115,
|
||||
112, 97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111,
|
||||
108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102,
|
||||
111, 110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98,
|
||||
111, 108, 100, 59, 109, 97, 114, 103, 105, 110, 45, 114, 105,
|
||||
103, 104, 116, 58, 53, 112, 120, 34, 62, 24050, 36807, 26399,
|
||||
60, 47, 115, 112, 97, 110, 62, 60, 97, 32, 99, 108, 97, 115,
|
||||
115, 61, 34, 98, 116, 108, 105, 110, 107, 34, 32, 111, 110, 99,
|
||||
108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116, 46,
|
||||
114, 101, 110, 101, 119, 95, 112, 114, 111, 40, 41, 34, 62, 82,
|
||||
69, 78, 69, 87, 60, 47, 97, 62, 60, 47, 115, 112, 97, 110, 62
|
||||
])
|
||||
if tmp >= 0 and ltd in [-1, -2]:
|
||||
if tmp == 0:
|
||||
tmp2 = public.to_string([27704, 20037, 25480, 26435])
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34,
|
||||
98, 116, 112, 114, 111, 34, 62, 123, 48, 125, 60, 115, 112,
|
||||
97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111, 108,
|
||||
111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102,
|
||||
111, 110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32,
|
||||
98, 111, 108, 100, 59, 34, 62, 123, 49, 125, 60, 47, 115,
|
||||
112, 97, 110, 62, 60, 47, 115, 112, 97, 110, 62
|
||||
]).format(
|
||||
public.to_string([21040, 26399, 26102, 38388, 65306]),
|
||||
tmp2)
|
||||
else:
|
||||
tmp2 = time.strftime(
|
||||
public.to_string([37, 89, 45, 37, 109, 45, 37, 100]),
|
||||
time.localtime(tmp))
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34,
|
||||
98, 116, 112, 114, 111, 34, 62, 69, 120, 112, 105, 114,
|
||||
101, 58, 32, 60, 115, 112, 97, 110, 32, 115, 116, 121, 108,
|
||||
101, 61, 34, 99, 111, 108, 111, 114, 58, 32, 35, 102, 99,
|
||||
54, 100, 50, 54, 59, 102, 111, 110, 116, 45, 119, 101, 105,
|
||||
103, 104, 116, 58, 32, 98, 111, 108, 100, 59, 109, 97, 114,
|
||||
103, 105, 110, 45, 114, 105, 103, 104, 116, 58, 53, 112,
|
||||
120, 34, 62, 123, 48, 125, 60, 47, 115, 112, 97, 110, 62,
|
||||
60, 97, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108,
|
||||
105, 110, 107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61,
|
||||
34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110,
|
||||
101, 119, 95, 112, 114, 111, 40, 41, 34, 62, 82, 69, 78,
|
||||
69, 87, 60, 47, 97, 62, 60, 47, 115, 112, 97, 110, 62
|
||||
]).format(tmp2)
|
||||
else:
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
|
||||
116, 112, 114, 111, 45, 103, 114, 97, 121, 34, 32, 111, 110,
|
||||
99, 108, 105, 99, 107, 61, 34, 98, 116, 46, 115, 111, 102, 116,
|
||||
46, 114, 101, 110, 101, 119, 95, 112, 114, 111, 40, 41, 34, 32,
|
||||
116, 105, 116, 108, 101, 61, 34, 67, 108, 105, 99, 107, 32,
|
||||
116, 111, 32, 103, 101, 116, 32, 80, 82, 79, 34, 62, 70, 82,
|
||||
69, 69, 60, 47, 115, 112, 97, 110, 62
|
||||
])
|
||||
else:
|
||||
tmp3 = public.to_string([
|
||||
60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
|
||||
108, 116, 100, 34, 62, 69, 120, 112, 105, 114, 101, 58, 32, 60,
|
||||
115, 112, 97, 110, 32, 115, 116, 121, 108, 101, 61, 34, 99, 111,
|
||||
108, 111, 114, 58, 32, 35, 102, 99, 54, 100, 50, 54, 59, 102, 111,
|
||||
110, 116, 45, 119, 101, 105, 103, 104, 116, 58, 32, 98, 111, 108,
|
||||
100, 59, 109, 97, 114, 103, 105, 110, 45, 114, 105, 103, 104, 116,
|
||||
58, 53, 112, 120, 34, 62, 123, 125, 60, 47, 115, 112, 97, 110, 62,
|
||||
60, 97, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 105, 110,
|
||||
107, 34, 32, 111, 110, 99, 108, 105, 99, 107, 61, 34, 98, 116, 46,
|
||||
115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95, 112, 114, 111,
|
||||
40, 41, 34, 62, 82, 69, 78, 69, 87, 60, 47, 97, 62, 60, 47, 115,
|
||||
112, 97, 110, 62
|
||||
]).format(
|
||||
time.strftime(public.to_string([37, 89, 45, 37, 109, 45, 37, 100]),
|
||||
time.localtime(ltd)))
|
||||
|
||||
return tmp3, tmp, ltd
|
||||
|
||||
|
||||
def send_authenticated():
|
||||
# 发送http认证信息
|
||||
request_host = public.GetHost()
|
||||
result = Response(
|
||||
'', 401,
|
||||
{'WWW-Authenticate': 'Basic realm="%s"' % request_host.strip()})
|
||||
if not 'login' in session and not 'admin_auth' in session: session.clear()
|
||||
return result
|
||||
|
||||
|
||||
# 取端口
|
||||
def FtpPort():
|
||||
# 获取FTP端口
|
||||
if session.get('port'): return
|
||||
import re
|
||||
try:
|
||||
file = public.GetConfigValue(
|
||||
'setup_path') + '/pure-ftpd/etc/pure-ftpd.conf'
|
||||
conf = public.readFile(file)
|
||||
rep = r"\n#?\s*Bind\s+[0-9]+\.[0-9]+\.[0-9]+\.+[0-9]+,([0-9]+)"
|
||||
port = re.search(rep, conf).groups()[0]
|
||||
except:
|
||||
port = '21'
|
||||
session['port'] = port
|
||||
|
||||
|
||||
def is_login(result):
|
||||
# 判断是否登录2
|
||||
if 'login' in session:
|
||||
if session['login'] == True:
|
||||
# result = make_response(result)
|
||||
# request_token = public.GetRandomString(48)
|
||||
# request_token_key = public.get_csrf_cookie_token_key()
|
||||
# session[request_token_key] = request_token
|
||||
# samesite = app.config['SESSION_COOKIE_SAMESITE']
|
||||
# secure = app.config['SESSION_COOKIE_SECURE']
|
||||
# if app.config['SSL'] and request.full_path.find('/login?tmp_token=') == 0:
|
||||
# samesite = 'None'
|
||||
# secure = True
|
||||
# result.set_cookie(request_token_key, request_token,
|
||||
# max_age=86400 * 30,
|
||||
# samesite= samesite,
|
||||
# secure=secure
|
||||
# )
|
||||
pass
|
||||
return result
|
||||
|
||||
|
||||
# js随机数模板使用,用于不更新版本号时更新前端文件不需要用户强制刷新浏览器
|
||||
def get_js_random():
|
||||
js_random = public.readFile('data/js_random.pl')
|
||||
if not js_random or js_random == '1':
|
||||
js_random = public.GetRandomString(16)
|
||||
public.writeFile('data/js_random.pl', js_random)
|
||||
return js_random
|
||||
|
||||
|
||||
# 获取输入数据
|
||||
def get_input():
|
||||
data = public.dict_obj()
|
||||
exludes = ['blob']
|
||||
for key in request.args.keys():
|
||||
data.set(key, str(request.args.get(key, '')))
|
||||
try:
|
||||
for key in request.form.keys():
|
||||
if key in exludes:
|
||||
continue
|
||||
data.set(key, str(request.form.get(key, '')))
|
||||
|
||||
except Exception as ex:
|
||||
# public.print_log("error1 {}".format(ex))
|
||||
|
||||
try:
|
||||
post = request.form.to_dict()
|
||||
for key in post.keys():
|
||||
if key in exludes: continue
|
||||
data.set(key, str(post[key]))
|
||||
except:
|
||||
pass
|
||||
|
||||
if 'form_data' in g:
|
||||
for k in g.form_data.keys():
|
||||
data.set(k, str(g.form_data[k]))
|
||||
|
||||
if not hasattr(data, 'data'):
|
||||
data.data = []
|
||||
return data
|
||||
|
||||
|
||||
# 取数据对象
|
||||
def get_input_data(data):
|
||||
pdata = public.dict_obj()
|
||||
for key in data.keys():
|
||||
pdata[key] = str(data[key])
|
||||
return pdata
|
||||
|
||||
|
||||
# 检查Token
|
||||
def check_token(data):
|
||||
# 已作废
|
||||
pluginPath = 'plugin/safelogin/token.pl'
|
||||
if not os.path.exists(pluginPath): return False
|
||||
from urllib import unquote
|
||||
from binascii import unhexlify
|
||||
from json import loads
|
||||
|
||||
result = unquote(unhexlify(data))
|
||||
token = public.readFile(pluginPath).strip()
|
||||
|
||||
result = loads(result)
|
||||
if not result: return False
|
||||
if result['token'] != token: return False
|
||||
return result
|
||||
|
||||
|
||||
# ======================公共方法区域END============================#
|
||||
|
||||
|
||||
# ======================自定义路由URL匹配规则转换器Begin===================== #
|
||||
|
||||
class RegexConverter(BaseConverter):
|
||||
"""
|
||||
自定义URL匹配正则表达式
|
||||
"""
|
||||
|
||||
def __init__(self, map, regex):
|
||||
super(RegexConverter, self).__init__(map)
|
||||
self.regex = regex
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
路由匹配时,匹配成功后传递给视图函数中参数的值
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
return value
|
||||
|
||||
def to_url(self, value):
|
||||
"""
|
||||
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
|
||||
:param value:
|
||||
:return:
|
||||
"""
|
||||
val = super(RegexConverter, self).to_url(value)
|
||||
return val
|
||||
|
||||
|
||||
# 添加到flask中
|
||||
app.url_map.converters.update({
|
||||
'regex': RegexConverter
|
||||
})
|
||||
|
||||
# ======================自定义路由URL匹配规则转换器End===================== #
|
||||
@@ -0,0 +1,194 @@
|
||||
# ===================================Flask HOOK========================#
|
||||
from BTPanel.app import *
|
||||
|
||||
# Flask请求勾子
|
||||
@app.before_request
|
||||
def request_check():
|
||||
if request.method not in ['GET', 'POST']: return abort(404)
|
||||
|
||||
# 获取客户端真实IP
|
||||
x_real_ip = request.headers.get('X-Real-Ip')
|
||||
if x_real_ip:
|
||||
request.remote_addr = x_real_ip
|
||||
request.environ.setdefault('REMOTE_PORT', public.get_remote_port())
|
||||
|
||||
g.request_time = time.time()
|
||||
g.return_message = False
|
||||
# 路由和URI长度过滤
|
||||
if len(request.path) > 256: return abort(403)
|
||||
if len(request.url) > 1024: return abort(403)
|
||||
# URI过滤
|
||||
if not uri_match.match(request.path): return abort(403)
|
||||
# POST参数过滤
|
||||
if request.path in [
|
||||
'/login',
|
||||
'/safe',
|
||||
# '/v2_safe',
|
||||
'/hook',
|
||||
'/public',
|
||||
'/down',
|
||||
'/get_app_bind_status',
|
||||
'/check_bind',
|
||||
'/userRegister',
|
||||
]:
|
||||
pdata = request.form.to_dict()
|
||||
for k in pdata.keys():
|
||||
if len(k) > 48: return abort(403)
|
||||
if len(pdata[k]) > 256: return abort(403)
|
||||
# SESSIONID过滤
|
||||
session_id = request.cookies.get(app.config['SESSION_COOKIE_NAME'], '')
|
||||
if session_id and not session_id_match.match(session_id): return abort(403)
|
||||
|
||||
# 请求头过滤
|
||||
# if not public.filter_headers():
|
||||
# return abort(403)
|
||||
|
||||
if session.get('debug') == 1: return
|
||||
g.get_csrf_html_token_key = public.get_csrf_html_token_key()
|
||||
|
||||
if app.config['BASIC_AUTH_OPEN']:
|
||||
if request.path in [
|
||||
'/public', '/download', '/mail_sys', '/hook', '/down',
|
||||
'/check_bind', '/get_app_bind_status'
|
||||
]:
|
||||
return
|
||||
auth = request.authorization
|
||||
if not comm.get_sk(): return
|
||||
if not auth: return send_authenticated()
|
||||
tips = '_bt.cn'
|
||||
if public.md5(auth.username.strip() + tips) != app.config['BASIC_AUTH_USERNAME'] \
|
||||
or public.md5(auth.password.strip() + tips) != app.config['BASIC_AUTH_PASSWORD']:
|
||||
return send_authenticated()
|
||||
|
||||
if not request.path in [
|
||||
'/safe',
|
||||
# '/v2_safe',
|
||||
'/hook',
|
||||
'/public',
|
||||
'/mail_sys',
|
||||
'/down'
|
||||
]:
|
||||
ip_check = public.check_ip_panel()
|
||||
if ip_check: return ip_check
|
||||
|
||||
if request.path.startswith('/static/') or request.path == '/code':
|
||||
if not 'login' in session and not 'admin_auth' in session and not 'down' in session:
|
||||
return abort(401)
|
||||
domain_check = public.check_domain_panel()
|
||||
if domain_check: return domain_check
|
||||
if public.is_local():
|
||||
not_networks = ['uninstall_plugin', 'install_plugin', 'UpdatePanel']
|
||||
if request.args.get('action') in not_networks:
|
||||
return public.returnJson(
|
||||
False,
|
||||
'This feature cannot be used in offline mode!'), json_header
|
||||
|
||||
if request.path in [
|
||||
'/site', '/ftp', '/database', '/soft', '/control', '/firewall',
|
||||
'/files', '/xterm', '/crontab', '/config'
|
||||
]:
|
||||
if public.is_error_path():
|
||||
return redirect('/error', 302)
|
||||
if not request.path in ['/config']:
|
||||
if session.get('password_expire', False):
|
||||
return redirect('/modify_password', 302)
|
||||
|
||||
|
||||
# Flask 请求结束勾子
|
||||
@app.teardown_request
|
||||
def request_end(reques=None):
|
||||
if request.method not in ['GET', 'POST']: return
|
||||
if not request.path.startswith('/static/'):
|
||||
public.write_request_log(reques)
|
||||
#当路由为/plugin时,不检测g.return_message
|
||||
# if not request.path.startswith('/plugin'):
|
||||
if request.path.startswith('/sitetest'):
|
||||
if 'return_message' in g:
|
||||
if not g.return_message:
|
||||
public.print_log("当前为网站路由,且未使用统一响应函数public.return_message")
|
||||
return abort(403)
|
||||
# return public.returnJson(
|
||||
# False, 'Request failed!Request not using unified response!'
|
||||
# ), json_header
|
||||
else:
|
||||
g.return_message = False
|
||||
public.print_log("当前为网站路由,且已使用统一响应函数public.return_message")
|
||||
if 'api_request' in g:
|
||||
if g.api_request:
|
||||
session.clear()
|
||||
|
||||
|
||||
# Flask 404页面勾子
|
||||
@app.errorhandler(404)
|
||||
def error_404(e):
|
||||
if request.method not in ['GET', 'POST']: return
|
||||
if not session.get('login', None):
|
||||
g.auth_error = True
|
||||
return public.error_not_login()
|
||||
errorStr = '''<html>
|
||||
<head><title>404 Not Found</title></head>
|
||||
<body>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>nginx</center>
|
||||
</body>
|
||||
</html>'''
|
||||
headers = {"Content-Type": "text/html"}
|
||||
return Response(errorStr, status=404, headers=headers)
|
||||
|
||||
|
||||
# Flask 403页面勾子
|
||||
@app.errorhandler(403)
|
||||
def error_403(e):
|
||||
if request.method not in ['GET', 'POST']: return
|
||||
if not session.get('login', None):
|
||||
g.auth_error = True
|
||||
return public.error_not_login()
|
||||
errorStr = '''<html>
|
||||
<head><title>403 Forbidden</title></head>
|
||||
<body>
|
||||
<center><h1>403 Forbidden</h1></center>
|
||||
<hr><center>nginx</center>
|
||||
</body>
|
||||
</html>'''
|
||||
headers = {"Content-Type": "text/html"}
|
||||
return Response(errorStr, status=403, headers=headers)
|
||||
|
||||
|
||||
# Flask 500页面勾子
|
||||
@app.errorhandler(500)
|
||||
def error_500(e):
|
||||
if request.method not in ['GET', 'POST']: return
|
||||
if not session.get('login', None):
|
||||
g.auth_error = True
|
||||
return public.error_not_login()
|
||||
ss = '''404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
|
||||
|
||||
During handling of the above exception, another exception occurred:'''
|
||||
error_info = public.get_error_info().strip().split(ss)[-1].strip()
|
||||
_form = request.form.to_dict()
|
||||
if 'username' in _form: _form['username'] = '******'
|
||||
if 'password' in _form: _form['password'] = '******'
|
||||
if 'phone' in _form: _form['phone'] = '******'
|
||||
request_info = '''REQUEST_DATE: {request_date}
|
||||
PAN_VERSION: {panel_version}
|
||||
OS_VERSION: {os_version}
|
||||
REMOTE_ADDR: {remote_addr}
|
||||
REQUEST_URI: {method} {full_path}
|
||||
REQUEST_FORM: {request_form}
|
||||
USER_AGENT: {user_agent}'''.format(
|
||||
request_date=public.getDate(),
|
||||
remote_addr=public.GetClientIp(),
|
||||
method=request.method,
|
||||
full_path=public.xsssec(request.full_path),
|
||||
request_form=public.xsssec(str(_form)),
|
||||
user_agent=public.xsssec(request.headers.get('User-Agent')),
|
||||
panel_version=public.version(),
|
||||
os_version=public.get_os_version())
|
||||
|
||||
result = public.readFile(
|
||||
public.get_panel_path() +
|
||||
'/BTPanel/templates/default/panel_error.html').format(
|
||||
error_title=error_info.split("\n")[-1],
|
||||
request_info=request_info,
|
||||
error_msg=error_info)
|
||||
return Resp(result, 500)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1303
-1135
File diff suppressed because it is too large
Load Diff
Vendored
+2992
-3166
File diff suppressed because it is too large
Load Diff
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
CKEditor 4
|
||||
==========
|
||||
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
http://ckeditor.com - See LICENSE.md for license information.
|
||||
|
||||
CKEditor is a text editor to be used inside web pages. It's not a replacement
|
||||
for desktop text editors like Word or OpenOffice, but a component to be used as
|
||||
part of web applications and websites.
|
||||
|
||||
## Documentation
|
||||
|
||||
The full editor documentation is available online at the following address:
|
||||
http://docs.ckeditor.com
|
||||
|
||||
## Installation
|
||||
|
||||
Installing CKEditor is an easy task. Just follow these simple steps:
|
||||
|
||||
1. **Download** the latest version from the CKEditor website:
|
||||
http://ckeditor.com. You should have already completed this step, but be
|
||||
sure you have the very latest version.
|
||||
2. **Extract** (decompress) the downloaded file into the root of your website.
|
||||
|
||||
**Note:** CKEditor is by default installed in the `ckeditor` folder. You can
|
||||
place the files in whichever you want though.
|
||||
|
||||
## Checking Your Installation
|
||||
|
||||
The editor comes with a few sample pages that can be used to verify that
|
||||
installation proceeded properly. Take a look at the `samples` directory.
|
||||
|
||||
To test your installation, just call the following page at your website:
|
||||
|
||||
http://<your site>/<CKEditor installation path>/samples/index.html
|
||||
|
||||
For example:
|
||||
|
||||
http://www.example.com/ckeditor/samples/index.html
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
(function(a){if("undefined"==typeof a)throw Error("jQuery should be loaded before CKEditor jQuery adapter.");if("undefined"==typeof CKEDITOR)throw Error("CKEditor should be loaded before CKEditor jQuery adapter.");CKEDITOR.config.jqueryOverrideVal="undefined"==typeof CKEDITOR.config.jqueryOverrideVal?!0:CKEDITOR.config.jqueryOverrideVal;a.extend(a.fn,{ckeditorGet:function(){var a=this.eq(0).data("ckeditorInstance");if(!a)throw"CKEditor is not initialized yet, use ckeditor() with a callback.";return a},
|
||||
ckeditor:function(g,d){if(!CKEDITOR.env.isCompatible)throw Error("The environment is incompatible.");if(!a.isFunction(g)){var m=d;d=g;g=m}var k=[];d=d||{};this.each(function(){var b=a(this),c=b.data("ckeditorInstance"),f=b.data("_ckeditorInstanceLock"),h=this,l=new a.Deferred;k.push(l.promise());if(c&&!f)g&&g.apply(c,[this]),l.resolve();else if(f)c.once("instanceReady",function(){setTimeout(function(){c.element?(c.element.$==h&&g&&g.apply(c,[h]),l.resolve()):setTimeout(arguments.callee,100)},0)},
|
||||
null,null,9999);else{if(d.autoUpdateElement||"undefined"==typeof d.autoUpdateElement&&CKEDITOR.config.autoUpdateElement)d.autoUpdateElementJquery=!0;d.autoUpdateElement=!1;b.data("_ckeditorInstanceLock",!0);c=a(this).is("textarea")?CKEDITOR.replace(h,d):CKEDITOR.inline(h,d);b.data("ckeditorInstance",c);c.on("instanceReady",function(d){var e=d.editor;setTimeout(function(){if(e.element){d.removeListener();e.on("dataReady",function(){b.trigger("dataReady.ckeditor",[e])});e.on("setData",function(a){b.trigger("setData.ckeditor",
|
||||
[e,a.data])});e.on("getData",function(a){b.trigger("getData.ckeditor",[e,a.data])},999);e.on("destroy",function(){b.trigger("destroy.ckeditor",[e])});e.on("save",function(){a(h.form).submit();return!1},null,null,20);if(e.config.autoUpdateElementJquery&&b.is("textarea")&&a(h.form).length){var c=function(){b.ckeditor(function(){e.updateElement()})};a(h.form).submit(c);a(h.form).bind("form-pre-serialize",c);b.bind("destroy.ckeditor",function(){a(h.form).unbind("submit",c);a(h.form).unbind("form-pre-serialize",
|
||||
c)})}e.on("destroy",function(){b.removeData("ckeditorInstance")});b.removeData("_ckeditorInstanceLock");b.trigger("instanceReady.ckeditor",[e]);g&&g.apply(e,[h]);l.resolve()}else setTimeout(arguments.callee,100)},0)},null,null,9999)}});var f=new a.Deferred;this.promise=f.promise();a.when.apply(this,k).then(function(){f.resolve()});this.editor=this.eq(0).data("ckeditorInstance");return this}});CKEDITOR.config.jqueryOverrideVal&&(a.fn.val=CKEDITOR.tools.override(a.fn.val,function(g){return function(d){if(arguments.length){var m=
|
||||
this,k=[],f=this.each(function(){var b=a(this),c=b.data("ckeditorInstance");if(b.is("textarea")&&c){var f=new a.Deferred;c.setData(d,function(){f.resolve()});k.push(f.promise());return!0}return g.call(b,d)});if(k.length){var b=new a.Deferred;a.when.apply(this,k).done(function(){b.resolveWith(m)});return b.promise()}return f}var f=a(this).eq(0),c=f.data("ckeditorInstance");return f.is("textarea")&&c?c.getData():g.call(f)}}))})(window.jQuery);
|
||||
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
* For licensing, see LICENSE.md or https://ckeditor.com/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file was added automatically by CKEditor builder.
|
||||
* You may re-use it at any time to build CKEditor again.
|
||||
*
|
||||
* If you would like to build CKEditor online again
|
||||
* (for example to upgrade), visit one the following links:
|
||||
*
|
||||
* (1) https://ckeditor.com/cke4/builder
|
||||
* Visit online builder to build CKEditor from scratch.
|
||||
*
|
||||
* (2) https://ckeditor.com/cke4/builder/c3fc0dcaa9c80d707aab3e60fdcddbfb
|
||||
* Visit online builder to build CKEditor, starting with the same setup as before.
|
||||
*
|
||||
* (3) https://ckeditor.com/cke4/builder/download/c3fc0dcaa9c80d707aab3e60fdcddbfb
|
||||
* Straight download link to the latest version of CKEditor (Optimized) with the same setup as before.
|
||||
*
|
||||
* NOTE:
|
||||
* This file is not used by CKEditor, you may remove it.
|
||||
* Changing this file will not change your CKEditor configuration.
|
||||
*/
|
||||
|
||||
var CKBUILDER_CONFIG = {
|
||||
skin: 'moono-lisa',
|
||||
preset: 'full',
|
||||
ignore: [
|
||||
'.DS_Store',
|
||||
'.bender',
|
||||
'.editorconfig',
|
||||
'.gitattributes',
|
||||
'.gitignore',
|
||||
'.idea',
|
||||
'.jscsrc',
|
||||
'.jshintignore',
|
||||
'.jshintrc',
|
||||
'.mailmap',
|
||||
'.npm',
|
||||
'.travis.yml',
|
||||
'bender-err.log',
|
||||
'bender-out.log',
|
||||
'bender.ci.js',
|
||||
'bender.js',
|
||||
'dev',
|
||||
'gruntfile.js',
|
||||
'less',
|
||||
'node_modules',
|
||||
'package.json',
|
||||
'tests'
|
||||
],
|
||||
plugins : {
|
||||
'a11yhelp' : 1,
|
||||
'about' : 1,
|
||||
'basicstyles' : 1,
|
||||
'bidi' : 1,
|
||||
'blockquote' : 1,
|
||||
'clipboard' : 1,
|
||||
'colorbutton' : 1,
|
||||
'colordialog' : 1,
|
||||
'contextmenu' : 1,
|
||||
'copyformatting' : 1,
|
||||
'dialogadvtab' : 1,
|
||||
'div' : 1,
|
||||
'elementspath' : 1,
|
||||
'enterkey' : 1,
|
||||
'entities' : 1,
|
||||
'filebrowser' : 1,
|
||||
'find' : 1,
|
||||
'flash' : 1,
|
||||
'floatingspace' : 1,
|
||||
'font' : 1,
|
||||
'format' : 1,
|
||||
'forms' : 1,
|
||||
'horizontalrule' : 1,
|
||||
'htmlwriter' : 1,
|
||||
'iframe' : 1,
|
||||
'image' : 1,
|
||||
'indentblock' : 1,
|
||||
'indentlist' : 1,
|
||||
'justify' : 1,
|
||||
'language' : 1,
|
||||
'link' : 1,
|
||||
'list' : 1,
|
||||
'liststyle' : 1,
|
||||
'magicline' : 1,
|
||||
'maximize' : 1,
|
||||
'newpage' : 1,
|
||||
'pagebreak' : 1,
|
||||
'pastefromword' : 1,
|
||||
'pastetext' : 1,
|
||||
'preview' : 1,
|
||||
'print' : 1,
|
||||
'removeformat' : 1,
|
||||
'resize' : 1,
|
||||
'save' : 1,
|
||||
'scayt' : 1,
|
||||
'selectall' : 1,
|
||||
'showblocks' : 1,
|
||||
'showborders' : 1,
|
||||
'smiley' : 1,
|
||||
'sourcearea' : 1,
|
||||
'specialchar' : 1,
|
||||
'stylescombo' : 1,
|
||||
'tab' : 1,
|
||||
'table' : 1,
|
||||
'tableselection' : 1,
|
||||
'tabletools' : 1,
|
||||
'templates' : 1,
|
||||
'toolbar' : 1,
|
||||
'undo' : 1,
|
||||
'uploadimage' : 1,
|
||||
'wsc' : 1,
|
||||
'wysiwygarea' : 1
|
||||
},
|
||||
languages : {
|
||||
'af' : 1,
|
||||
'ar' : 1,
|
||||
'az' : 1,
|
||||
'bg' : 1,
|
||||
'bn' : 1,
|
||||
'bs' : 1,
|
||||
'ca' : 1,
|
||||
'cs' : 1,
|
||||
'cy' : 1,
|
||||
'da' : 1,
|
||||
'de' : 1,
|
||||
'de-ch' : 1,
|
||||
'el' : 1,
|
||||
'en' : 1,
|
||||
'en-au' : 1,
|
||||
'en-ca' : 1,
|
||||
'en-gb' : 1,
|
||||
'eo' : 1,
|
||||
'es' : 1,
|
||||
'es-mx' : 1,
|
||||
'et' : 1,
|
||||
'eu' : 1,
|
||||
'fa' : 1,
|
||||
'fi' : 1,
|
||||
'fo' : 1,
|
||||
'fr' : 1,
|
||||
'fr-ca' : 1,
|
||||
'gl' : 1,
|
||||
'gu' : 1,
|
||||
'he' : 1,
|
||||
'hi' : 1,
|
||||
'hr' : 1,
|
||||
'hu' : 1,
|
||||
'id' : 1,
|
||||
'is' : 1,
|
||||
'it' : 1,
|
||||
'ja' : 1,
|
||||
'ka' : 1,
|
||||
'km' : 1,
|
||||
'ko' : 1,
|
||||
'ku' : 1,
|
||||
'lt' : 1,
|
||||
'lv' : 1,
|
||||
'mk' : 1,
|
||||
'mn' : 1,
|
||||
'ms' : 1,
|
||||
'nb' : 1,
|
||||
'nl' : 1,
|
||||
'no' : 1,
|
||||
'oc' : 1,
|
||||
'pl' : 1,
|
||||
'pt' : 1,
|
||||
'pt-br' : 1,
|
||||
'ro' : 1,
|
||||
'ru' : 1,
|
||||
'si' : 1,
|
||||
'sk' : 1,
|
||||
'sl' : 1,
|
||||
'sq' : 1,
|
||||
'sr' : 1,
|
||||
'sr-latn' : 1,
|
||||
'sv' : 1,
|
||||
'th' : 1,
|
||||
'tr' : 1,
|
||||
'tt' : 1,
|
||||
'ug' : 1,
|
||||
'uk' : 1,
|
||||
'vi' : 1,
|
||||
'zh' : 1,
|
||||
'zh-cn' : 1
|
||||
}
|
||||
};
|
||||
Vendored
+1337
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
* For licensing, see https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
|
||||
CKEDITOR.editorConfig = function( config ) {
|
||||
// Define changes to default configuration here. For example:
|
||||
config.language = 'en';
|
||||
config.height = 330;
|
||||
// config.uiColor = '#AADC6E';
|
||||
};
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
|
||||
body
|
||||
{
|
||||
/* Font */
|
||||
/* Emoji fonts are added to visualise them nicely in Internet Explorer. */
|
||||
font-family: sans-serif, Arial, Verdana, "Trebuchet MS", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 12px;
|
||||
|
||||
/* Text color */
|
||||
color: #333;
|
||||
|
||||
/* Remove the background color to make it transparent. */
|
||||
background-color: #fff;
|
||||
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.cke_editable
|
||||
{
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
|
||||
/* Fix for missing scrollbars with RTL texts. (#10488) */
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
blockquote
|
||||
{
|
||||
font-style: italic;
|
||||
font-family: Georgia, Times, "Times New Roman", serif;
|
||||
padding: 2px 0;
|
||||
border-style: solid;
|
||||
border-color: #ccc;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.cke_contents_ltr blockquote
|
||||
{
|
||||
padding-left: 20px;
|
||||
padding-right: 8px;
|
||||
border-left-width: 5px;
|
||||
}
|
||||
|
||||
.cke_contents_rtl blockquote
|
||||
{
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
border-right-width: 5px;
|
||||
}
|
||||
|
||||
a
|
||||
{
|
||||
color: #0782C1;
|
||||
}
|
||||
|
||||
ol,ul,dl
|
||||
{
|
||||
/* IE7: reset rtl list margin. (#7334) */
|
||||
*margin-right: 0px;
|
||||
/* Preserved spaces for list items with text direction different than the list. (#6249,#8049)*/
|
||||
padding: 0 40px;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6
|
||||
{
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
border: 0px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
img.right
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: right;
|
||||
margin-left: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
img.left
|
||||
{
|
||||
border: 1px solid #ccc;
|
||||
float: left;
|
||||
margin-right: 15px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
pre
|
||||
{
|
||||
white-space: pre-wrap; /* CSS 2.1 */
|
||||
word-wrap: break-word; /* IE7 */
|
||||
-moz-tab-size: 4;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
.marker
|
||||
{
|
||||
background-color: Yellow;
|
||||
}
|
||||
|
||||
span[lang]
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
figure
|
||||
{
|
||||
text-align: center;
|
||||
outline: solid 1px #ccc;
|
||||
background: rgba(0,0,0,0.05);
|
||||
padding: 10px;
|
||||
margin: 10px 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
figure > figcaption
|
||||
{
|
||||
text-align: center;
|
||||
display: block; /* For IE8 */
|
||||
}
|
||||
|
||||
a > img {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
border: none;
|
||||
outline: 1px solid #0782C1;
|
||||
}
|
||||
|
||||
/* Widget Styles */
|
||||
.code-featured
|
||||
{
|
||||
border: 5px solid red;
|
||||
}
|
||||
|
||||
.math-featured
|
||||
{
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 2px rgba(200, 0, 0, 1);
|
||||
background-color: rgba(255, 0, 0, 0.05);
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.image-clean
|
||||
{
|
||||
border: 0;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.image-clean > figcaption
|
||||
{
|
||||
font-size: .9em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.image-grayscale
|
||||
{
|
||||
background-color: white;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.image-grayscale img, img.image-grayscale
|
||||
{
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.embed-240p
|
||||
{
|
||||
max-width: 426px;
|
||||
max-height: 240px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-360p
|
||||
{
|
||||
max-width: 640px;
|
||||
max-height: 360px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-480p
|
||||
{
|
||||
max-width: 854px;
|
||||
max-height: 480px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-720p
|
||||
{
|
||||
max-width: 1280px;
|
||||
max-height: 720px;
|
||||
margin:0 auto;
|
||||
}
|
||||
|
||||
.embed-1080p
|
||||
{
|
||||
max-width: 1920px;
|
||||
max-height: 1080px;
|
||||
margin:0 auto;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.dialog.add("a11yHelp",function(f){function m(a){for(var b,c,h=[],d=0;d<g.length;d++)c=g[d],b=a/g[d],1<b&&2>=b&&(a-=c,h.push(e[c]));h.push(e[a]||String.fromCharCode(a));return h.join("+")}function t(a,b){var c=f.getCommandKeystroke(b,!0);return c.length?CKEDITOR.tools.array.map(c,m).join(" / "):a}var a=f.lang.a11yhelp,b=f.lang.common.keyboard,p=CKEDITOR.tools.getNextId(),q=/\$\{(.*?)\}/g,g=[CKEDITOR.ALT,CKEDITOR.SHIFT,CKEDITOR.CTRL],e={8:b[8],9:a.tab,13:b[13],16:b[16],17:b[17],18:b[18],19:a.pause,
|
||||
20:a.capslock,27:a.escape,33:a.pageUp,34:a.pageDown,35:b[35],36:b[36],37:a.leftArrow,38:a.upArrow,39:a.rightArrow,40:a.downArrow,45:a.insert,46:b[46],91:a.leftWindowKey,92:a.rightWindowKey,93:a.selectKey,96:a.numpad0,97:a.numpad1,98:a.numpad2,99:a.numpad3,100:a.numpad4,101:a.numpad5,102:a.numpad6,103:a.numpad7,104:a.numpad8,105:a.numpad9,106:a.multiply,107:a.add,109:a.subtract,110:a.decimalPoint,111:a.divide,112:a.f1,113:a.f2,114:a.f3,115:a.f4,116:a.f5,117:a.f6,118:a.f7,119:a.f8,120:a.f9,121:a.f10,
|
||||
122:a.f11,123:a.f12,144:a.numLock,145:a.scrollLock,186:a.semiColon,187:a.equalSign,188:a.comma,189:a.dash,190:a.period,191:a.forwardSlash,192:a.graveAccent,219:a.openBracket,220:a.backSlash,221:a.closeBracket,222:a.singleQuote};e[CKEDITOR.ALT]=b[18];e[CKEDITOR.SHIFT]=b[16];e[CKEDITOR.CTRL]=CKEDITOR.env.mac?b[224]:b[17];return{title:a.title,minWidth:600,minHeight:400,contents:[{id:"info",label:f.lang.common.generalTab,expand:!0,elements:[{type:"html",id:"legends",style:"white-space:normal;",focus:function(){this.getElement().focus()},
|
||||
html:function(){for(var b='\x3cdiv class\x3d"cke_accessibility_legend" role\x3d"document" aria-labelledby\x3d"'+p+'_arialbl" tabIndex\x3d"-1"\x3e%1\x3c/div\x3e\x3cspan id\x3d"'+p+'_arialbl" class\x3d"cke_voice_label"\x3e'+a.contents+" \x3c/span\x3e",e=[],c=a.legend,h=c.length,d=0;d<h;d++){for(var f=c[d],g=[],r=f.items,m=r.length,n=0;n<m;n++){var k=r[n],l=CKEDITOR.env.edge&&k.legendEdge?k.legendEdge:k.legend,l=l.replace(q,t);l.match(q)||g.push("\x3cdt\x3e%1\x3c/dt\x3e\x3cdd\x3e%2\x3c/dd\x3e".replace("%1",
|
||||
k.name).replace("%2",l))}e.push("\x3ch1\x3e%1\x3c/h1\x3e\x3cdl\x3e%2\x3c/dl\x3e".replace("%1",f.name).replace("%2",g.join("")))}return b.replace("%1",e.join(""))}()+'\x3cstyle type\x3d"text/css"\x3e.cke_accessibility_legend{width:600px;height:400px;padding-right:5px;overflow-y:auto;overflow-x:hidden;}.cke_browser_quirks .cke_accessibility_legend,{height:390px}.cke_accessibility_legend *{white-space:normal;}.cke_accessibility_legend h1{font-size: 20px;border-bottom: 1px solid #AAA;margin: 5px 0px 15px;}.cke_accessibility_legend dl{margin-left: 5px;}.cke_accessibility_legend dt{font-size: 13px;font-weight: bold;}.cke_accessibility_legend dd{margin:10px}\x3c/style\x3e'}]}],
|
||||
buttons:[CKEDITOR.dialog.cancelButton]}});
|
||||
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
|
||||
cs.js Found: 30 Missing: 0
|
||||
cy.js Found: 30 Missing: 0
|
||||
da.js Found: 12 Missing: 18
|
||||
de.js Found: 30 Missing: 0
|
||||
el.js Found: 25 Missing: 5
|
||||
eo.js Found: 30 Missing: 0
|
||||
fa.js Found: 30 Missing: 0
|
||||
fi.js Found: 30 Missing: 0
|
||||
fr.js Found: 30 Missing: 0
|
||||
gu.js Found: 12 Missing: 18
|
||||
he.js Found: 30 Missing: 0
|
||||
it.js Found: 30 Missing: 0
|
||||
mk.js Found: 5 Missing: 25
|
||||
nb.js Found: 30 Missing: 0
|
||||
nl.js Found: 30 Missing: 0
|
||||
no.js Found: 30 Missing: 0
|
||||
pt-br.js Found: 30 Missing: 0
|
||||
ro.js Found: 6 Missing: 24
|
||||
tr.js Found: 30 Missing: 0
|
||||
ug.js Found: 27 Missing: 3
|
||||
vi.js Found: 6 Missing: 24
|
||||
zh-cn.js Found: 30 Missing: 0
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","af",{title:"Toeganglikheid instruksies",contents:"Hulp inhoud. Druk ESC om toe te maak.",legend:[{name:"Algemeen",items:[{name:"Bewerker balk",legend:"Druk ${toolbarFocus} om op die werkbalk te land. Beweeg na die volgende en voorige wekrbalkgroep met TAB and SHIFT+TAB. Beweeg na die volgende en voorige werkbalkknop met die regter of linker pyl. Druk SPASIE of ENTER om die knop te bevestig."},{name:"Bewerker dialoog",legend:"Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively."},
|
||||
{name:"Bewerkerinhoudmenu",legend:"Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC."},{name:"Editor List Box",legend:"Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box."},
|
||||
{name:"Editor Element Path Bar",legend:"Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor."}]},{name:"Commands",items:[{name:" Undo command",legend:"Press ${undo}"},{name:" Redo command",legend:"Press ${redo}"},{name:" Bold command",legend:"Press ${bold}"},{name:" Italic command",legend:"Press ${italic}"},{name:" Underline command",
|
||||
legend:"Press ${underline}"},{name:" Link command",legend:"Press ${link}"},{name:" Toolbar Collapse command",legend:"Press ${toolbarCollapse}"},{name:" Access previous focus space command",legend:"Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},{name:" Access next focus space command",legend:"Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},
|
||||
{name:" Accessibility Help",legend:"Press ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pouse",capslock:"Hoofletterslot",escape:"Ontsnap",pageUp:"Blaaiop",pageDown:"Blaaiaf",leftArrow:"Linkspyl",upArrow:"Oppyl",rightArrow:"Regterpyl",downArrow:"Afpyl",insert:"Toevoeg",leftWindowKey:"Left Windows key",rightWindowKey:"Right Windows key",selectKey:"Select key",numpad0:"Nommerblok 0",numpad1:"Nommerblok 1",
|
||||
numpad2:"Nommerblok 2",numpad3:"Nommerblok 3",numpad4:"Nommerblok 4",numpad5:"Nommerblok 5",numpad6:"Nommerblok 6",numpad7:"Nommerblok 7",numpad8:"Nommerblok 8",numpad9:"Nommerblok 9",multiply:"Maal",add:"Plus",subtract:"Minus",decimalPoint:"Desimaalepunt",divide:"Gedeeldeur",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Nommervergrendel",scrollLock:"Rolvergrendel",semiColon:"Kommapunt",equalSign:"Isgelykaan",comma:"Komma",dash:"Koppelteken",
|
||||
period:"Punt",forwardSlash:"Skuinsstreep",graveAccent:"Aksentteken",openBracket:"Oopblokhakkie",backSlash:"Trustreep",closeBracket:"Toeblokhakkie",singleQuote:"Enkelaanhaalingsteken"});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","ar",{title:"Accessibility Instructions",contents:"Help Contents. To close this dialog press ESC.",legend:[{name:"عام",items:[{name:"Editor Toolbar",legend:"Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button."},{name:"Editor Dialog",legend:"Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively."},
|
||||
{name:"Editor Context Menu",legend:"Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC."},{name:"Editor List Box",legend:"Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box."},
|
||||
{name:"Editor Element Path Bar",legend:"Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor."}]},{name:"Commands",items:[{name:" Undo command",legend:"Press ${undo}"},{name:" Redo command",legend:"Press ${redo}"},{name:" Bold command",legend:"Press ${bold}"},{name:" Italic command",legend:"Press ${italic}"},{name:" Underline command",
|
||||
legend:"Press ${underline}"},{name:" Link command",legend:"Press ${link}"},{name:" Toolbar Collapse command",legend:"Press ${toolbarCollapse}"},{name:" Access previous focus space command",legend:"Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},{name:" Access next focus space command",legend:"Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},
|
||||
{name:" Accessibility Help",legend:"Press ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Caps Lock",escape:"Escape",pageUp:"Page Up",pageDown:"Page Down",leftArrow:"Left Arrow",upArrow:"Up Arrow",rightArrow:"Right Arrow",downArrow:"Down Arrow",insert:"Insert",leftWindowKey:"Left Windows key",rightWindowKey:"Right Windows key",selectKey:"Select key",numpad0:"Numpad 0",numpad1:"Numpad 1",
|
||||
numpad2:"Numpad 2",numpad3:"Numpad 3",numpad4:"Numpad 4",numpad5:"Numpad 5",numpad6:"Numpad 6",numpad7:"Numpad 7",numpad8:"Numpad 8",numpad9:"Numpad 9",multiply:"Multiply",add:"إضافة",subtract:"Subtract",decimalPoint:"Decimal Point",divide:"تقسيم",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num Lock",scrollLock:"Scroll Lock",semiColon:"Semicolon",equalSign:"Equal Sign",comma:"فاصلة",dash:"Dash",period:"نقطة",forwardSlash:"Forward Slash",
|
||||
graveAccent:"Grave Accent",openBracket:"Open Bracket",backSlash:"Backslash",closeBracket:"Close Bracket",singleQuote:"Single Quote"});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","az",{title:"Əlillərə dəstək üzrə təlimat",contents:"Kömək. Pəncərəni bağlamaq üçün ESC basın.",legend:[{name:"Əsas",items:[{name:"Düzəliş edənin alətlər çubuğu",legend:"Panelə keçmək üçün ${toolbarFocus} basın. Növbəti panelə TAB, əvvəlki panelə isə SHIFT+TAB düyməsi vasitəsi ilə keçə bilərsiz. Paneldəki düymələr arasında sol və sağ ox düyməsi ilə keçid edə bilərsiz. Seçilmiş düyməsi SPACE və ya ENTER ilə işlədə bilərsiniz."},{name:"Redaktorun pəncərəsi",legend:"Pəncərə içində növbəti element seçmək üçün TAB düyməni basın, əvvəlki isə - SHIFT+TAB. Təsdiq edilməsi üçün ENTER, imtina edilməsi isə ESC diymələri istifadə edin. Pəncərədə bir neçə vərəq olanda olnarın siyahı ALT+F10 ilə aça bilərsiz. Vərəqlərin siyahı fokus altında olanda ox düymələr vasitəsi ilə onların arasında keçid edə bilərsiz."},
|
||||
{name:"Redaktorun seçimlərin menyusu",legend:"Seçimləri redaktə etmək üçün ${contextMenu} ya da APPLICATION KEY basın. Növbəti seçimə keçmək üçün TAB ya AŞAĞI OX düyməsini basın, əvvəlki isə - SHIFT+TAB ya YUXARI OX. Seçimi arımaq SPACE ya ENTER düymələri istifadə edin. Alt menyunu açmaq üçün SPACE, ENTER ya SAĞA OX basın. ESC ya SOLA OX ilə geriyə qayıda bilərsiz. Bütün menyunu ESC ilə bağlıyın."},{name:"Düzəliş edənin siyahı qutusu",legend:"Siyahı qutusu içində növbəti bənd seçmək üçün TAB ya AŞAĞI OX, əvvəlki isə SHIFT+TAB ya YUXARI OX basın. Seçimi arımaq SPACE ya ENTER düymələri istifadə edin. Siyahı qutusu ESC ilə bağlıyın."},
|
||||
{name:"Redaktor elementin cığır paneli",legend:"Elementin cığır paneli seçmək üçün ${elementsPathFocus} basın. Növbəti element seçmək üçün TAB ya SAĞA OX, əvvəlki isə SHIFT+TAB ya SOLA OX istifadə edin. Elementi arımaq SPACE ya ENTER düymələri mövcuddur."}]},{name:"Əmrlər",items:[{name:"Əmri geri qaytar",legend:"${undo} basın"},{name:"Geri əmri",legend:"${redo} basın"},{name:"Qalın əmri",legend:"${bold} basın"},{name:"Kursiv əmri",legend:"${italic} basın"},{name:"Altdan xətt əmri",legend:"${underline} basın"},
|
||||
{name:"Link əmri",legend:"${link} basın"},{name:"Paneli gizlət əmri",legend:"${toolbarCollapse} basın"},{name:"Əvvəlki fokus sahəsi seç əmrı",legend:"Kursordan əvvəl ən yaxın əlçatmaz yerə dəymək üçün ${accessPreviousSpace} basın, misal üçün: iki dal-badal HR teg. Uzaq yerlərə dəymək üçün bir neçə dəfə basın."},{name:"Növbəti fokus sahəsi seç əmrı",legend:"Kursordan sonra ən yaxın əlçatmaz yerə dəymək üçün ${accessNextSpace} basın, misal üçün: iki dal-badal HR teg. Uzaq yerlərə dəymək üçün bir neçə dəfə basın."},
|
||||
{name:"Hərtərəfli Kömək",legend:"${a11yHelp} basın"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Caps Lock",escape:"Escape",pageUp:"Page Up",pageDown:"Page Down",leftArrow:"Sola ox işarəsi",upArrow:"Yuxarı ox işarəsi",rightArrow:"Sağa ox işarəsi",downArrow:"Aşağı ox işarəsi",insert:"Insert",leftWindowKey:"Soldaki Windows düyməsi",rightWindowKey:"Sağdaki Windows düyməsi",selectKey:"Düyməni seçin",
|
||||
numpad0:"Numpad 0",numpad1:"Numpad 1",numpad2:"Numpad 2",numpad3:"Numpad 3",numpad4:"Numpad 4",numpad5:"Numpad 5",numpad6:"Numpad 6",numpad7:"Numpad 7",numpad8:"Numpad 8",numpad9:"Numpad 9",multiply:"Vurma",add:"Əlavə et",subtract:"Çıxma",decimalPoint:"Onluq kəsri tam ədəddən ayıran nöqtə",divide:"Bölüşdürmə",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num Lock",scrollLock:"Scroll Lock",semiColon:"Nöqtəli verqül",equalSign:"Barəbərlik işarəsi",
|
||||
comma:"Vergül",dash:"Defis",period:"Nöqtə",forwardSlash:"Çəp xətt",graveAccent:"Vurğu işarəsi",openBracket:"Açılan mötərizə",backSlash:"Tərs çəpəki xətt",closeBracket:"Bağlanan mötərizə",singleQuote:"Tək dırnaq"});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","bg",{title:"Инструкции за достъпност",contents:"Съдържание на помощта. За да затворите този диалогов прозорец, натиснете ESC.",legend:[{name:"Общо",items:[{name:"Лента с инструменти за редактора",legend:"Press ${toolbarFocus} to navigate to the toolbar. Move to the next and previous toolbar group with TAB and SHIFT+TAB. Move to the next and previous toolbar button with RIGHT ARROW or LEFT ARROW. Press SPACE or ENTER to activate the toolbar button."},{name:"Диалог на редактора",
|
||||
legend:"Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively."},{name:"Контекстно меню на редактора",legend:"Press ${contextMenu} or APPLICATION KEY to open context-menu. Then move to next menu option with TAB or DOWN ARROW. Move to previous option with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the menu option. Open sub-menu of current option with SPACE or ENTER or RIGHT ARROW. Go back to parent menu item with ESC or LEFT ARROW. Close context menu with ESC."},
|
||||
{name:"Списъчно меню на редактора",legend:"Inside a list-box, move to next list item with TAB OR DOWN ARROW. Move to previous list item with SHIFT+TAB or UP ARROW. Press SPACE or ENTER to select the list option. Press ESC to close the list-box."},{name:"Лента с път на елемент на редактора",legend:"Press ${elementsPathFocus} to navigate to the elements path bar. Move to next element button with TAB or RIGHT ARROW. Move to previous button with SHIFT+TAB or LEFT ARROW. Press SPACE or ENTER to select the element in editor."}]},
|
||||
{name:"Команди",items:[{name:"Команда за отмяна",legend:"Натисни ${undo}"},{name:"Команда за пренаправяне",legend:"Натисни ${redo}"},{name:" Bold command",legend:"Press ${bold}"},{name:" Italic command",legend:"Press ${italic}"},{name:" Underline command",legend:"Press ${underline}"},{name:" Link command",legend:"Press ${link}"},{name:" Toolbar Collapse command",legend:"Press ${toolbarCollapse}"},{name:" Access previous focus space command",legend:"Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},
|
||||
{name:" Access next focus space command",legend:"Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},{name:" Accessibility Help",legend:"Press ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Caps Lock",escape:"Escape",pageUp:"Page Up",pageDown:"Page Down",
|
||||
leftArrow:"Left Arrow",upArrow:"Up Arrow",rightArrow:"Right Arrow",downArrow:"Down Arrow",insert:"Insert",leftWindowKey:"Left Windows key",rightWindowKey:"Right Windows key",selectKey:"Select key",numpad0:"Numpad 0",numpad1:"Numpad 1",numpad2:"Numpad 2",numpad3:"Numpad 3",numpad4:"Numpad 4",numpad5:"Numpad 5",numpad6:"Numpad 6",numpad7:"Numpad 7",numpad8:"Numpad 8",numpad9:"Numpad 9",multiply:"Multiply",add:"Add",subtract:"Subtract",decimalPoint:"Decimal Point",divide:"Divide",f1:"F1",f2:"F2",f3:"F3",
|
||||
f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num Lock",scrollLock:"Scroll Lock",semiColon:"Semicolon",equalSign:"Equal Sign",comma:"Comma",dash:"Dash",period:"Period",forwardSlash:"Forward Slash",graveAccent:"Grave Accent",openBracket:"Open Bracket",backSlash:"Backslash",closeBracket:"Close Bracket",singleQuote:"Single Quote"});
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","ca",{title:"Instruccions d'Accessibilitat",contents:"Continguts de l'Ajuda. Per tancar aquest quadre de diàleg premi ESC.",legend:[{name:"General",items:[{name:"Editor de barra d'eines",legend:"Premi ${toolbarFocus} per desplaçar-se per la barra d'eines. Vagi en el següent i anterior grup de barra d'eines amb TAB i SHIFT+TAB. Vagi en el següent i anterior botó de la barra d'eines amb RIGHT ARROW i LEFT ARROW. Premi SPACE o ENTER per activar el botó de la barra d'eines."},
|
||||
{name:"Editor de quadre de diàleg",legend:"Dins d'un quadre de diàleg, premi la tecla TAB per desplaçar-se fins al següent element del quadre de diàleg, premi la tecla Shift + TAB per desplaçar-se a l'anterior element del quadre de diàleg, premi la tecla ENTER per confirmar el quadre de diàleg, premi la tecla ESC per cancel·lar el quadre de diàleg. Quan un quadre de diàleg té diverses pestanyes, la llista de pestanyes pot ser assolit ja sigui amb ALT + F10 o TAB, com a part de l'ordre de tabulació del quadre de diàleg. Amb la llista de pestanyes seleccionada, pot anar a la fitxa següent i anterior amb la tecla FLETXA DRETA i ESQUERRA, respectivament."},
|
||||
{name:"Editor de menú contextual",legend:"Premi ${contextMenu} o APPLICATION KEY per obrir el menú contextual. Després desplacis a la següent opció del menú amb TAB o DOWN ARROW. Desplacis a l'anterior opció amb SHIFT+TAB o UP ARROW. Premi SPACE o ENTER per seleccionar l'opció del menú. Obri el submenú de l'actual opció utilitzant SPACE o ENTER o RIGHT ARROW. Pot tornar a l'opció del menú pare amb ESC o LEFT ARROW. Tanqui el menú contextual amb ESC."},{name:"Editor de caixa de llista",legend:"Dins d'un quadre de llista, desplacis al següent element de la llista amb TAB o DOWN ARROW. Desplacis a l'anterior element de la llista amb SHIFT+TAB o UP ARROW. Premi SPACE o ENTER per seleccionar l'opció de la llista. Premi ESC per tancar el quadre de llista."},
|
||||
{name:"Editor de barra de ruta de l'element",legend:"Premi ${elementsPathFocus} per anar als elements de la barra de ruta. Desplacis al botó de l'element següent amb TAB o RIGHT ARROW. Desplacis a l'anterior botó amb SHIFT+TAB o LEFT ARROW. Premi SPACE o ENTER per seleccionar l'element a l'editor."}]},{name:"Ordres",items:[{name:"Desfer ordre",legend:"Premi ${undo}"},{name:"Refer ordre",legend:"Premi ${redo}"},{name:"Ordre negreta",legend:"Premi ${bold}"},{name:"Ordre cursiva",legend:"Premi ${italic}"},
|
||||
{name:"Ordre subratllat",legend:"Premi ${underline}"},{name:"Ordre enllaç",legend:"Premi ${link}"},{name:"Ordre amagar barra d'eines",legend:"Premi ${toolbarCollapse}"},{name:"Ordre per accedir a l'anterior espai enfocat",legend:"Premi ${accessPreviousSpace} per accedir a l'enfocament d'espai més proper inabastable abans del símbol d'intercalació, per exemple: dos elements HR adjacents. Repetiu la combinació de tecles per arribar a enfocaments d'espais distants."},{name:"Ordre per accedir al següent espai enfocat",
|
||||
legend:"Premi ${accessNextSpace} per accedir a l'enfocament d'espai més proper inabastable després del símbol d'intercalació, per exemple: dos elements HR adjacents. Repetiu la combinació de tecles per arribar a enfocaments d'espais distants."},{name:"Ajuda d'accessibilitat",legend:"Premi ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tabulació",pause:"Pausa",capslock:"Bloqueig de majúscules",escape:"Escape",pageUp:"Pàgina Amunt",
|
||||
pageDown:"Pàgina Avall",leftArrow:"Fletxa Esquerra",upArrow:"Fletxa Amunt",rightArrow:"Fletxa Dreta",downArrow:"Fletxa Avall",insert:"Inserir",leftWindowKey:"Tecla Windows Esquerra",rightWindowKey:"Tecla Windows Dreta",selectKey:"Tecla Seleccionar",numpad0:"Teclat Numèric 0",numpad1:"Teclat Numèric 1",numpad2:"Teclat Numèric 2",numpad3:"Teclat Numèric 3",numpad4:"Teclat Numèric 4",numpad5:"Teclat Numèric 5",numpad6:"Teclat Numèric 6",numpad7:"Teclat Numèric 7",numpad8:"Teclat Numèric 8",numpad9:"Teclat Numèric 9",
|
||||
multiply:"Multiplicació",add:"Suma",subtract:"Resta",decimalPoint:"Punt Decimal",divide:"Divisió",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Bloqueig Teclat Numèric",scrollLock:"Bloqueig de Desplaçament",semiColon:"Punt i Coma",equalSign:"Símbol Igual",comma:"Coma",dash:"Guió",period:"Punt",forwardSlash:"Barra Diagonal",graveAccent:"Accent Obert",openBracket:"Claudàtor Obert",backSlash:"Barra Invertida",closeBracket:"Claudàtor Tancat",
|
||||
singleQuote:"Cometa Simple"});
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","cs",{title:"Instrukce pro přístupnost",contents:"Obsah nápovědy. Pro uzavření tohoto dialogu stiskněte klávesu ESC.",legend:[{name:"Obecné",items:[{name:"Panel nástrojů editoru",legend:"Stiskněte${toolbarFocus} k procházení panelu nástrojů. Přejděte na další a předchozí skupiny pomocí TAB a SHIFT+TAB. Přechod na další a předchozí tlačítko panelu nástrojů je pomocí ŠIPKA VPRAVO nebo ŠIPKA VLEVO. Stisknutím mezerníku nebo klávesy ENTER tlačítko aktivujete."},{name:"Dialogové okno editoru",
|
||||
legend:"Uvnitř dialogového okna stiskněte TAB pro přesunutí na další prvek okna, stiskněte SHIFT+TAB pro přesun na předchozí prvek okna, stiskněte ENTER pro odeslání dialogu, stiskněte ESC pro jeho zrušení. Pro dialogová okna, která mají mnoho karet stiskněte ALT+F10 pro zaměření seznamu karet, nebo TAB, pro posun podle pořadí karet.Při zaměření seznamu karet se můžete jimi posouvat pomocí ŠIPKY VPRAVO a VLEVO."},{name:"Kontextové menu editoru",legend:"Stiskněte ${contextMenu} nebo klávesu APPLICATION k otevření kontextového menu. Pak se přesuňte na další možnost menu pomocí TAB nebo ŠIPKY DOLŮ. Přesuňte se na předchozí možnost pomocí SHIFT+TAB nebo ŠIPKY NAHORU. Stiskněte MEZERNÍK nebo ENTER pro zvolení možnosti menu. Podmenu současné možnosti otevřete pomocí MEZERNÍKU nebo ENTER či ŠIPKY DOLEVA. Kontextové menu uzavřete stiskem ESC."},
|
||||
{name:"Rámeček seznamu editoru",legend:"Uvnitř rámečku seznamu se přesunete na další položku menu pomocí TAB nebo ŠIPKA DOLŮ. Na předchozí položku se přesunete SHIFT+TAB nebo ŠIPKA NAHORU. Stiskněte MEZERNÍK nebo ENTER pro zvolení možnosti seznamu. Stiskněte ESC pro uzavření seznamu."},{name:"Lišta cesty prvku v editoru",legend:"Stiskněte ${elementsPathFocus} pro procházení lišty cesty prvku. Na další tlačítko prvku se přesunete pomocí TAB nebo ŠIPKA VPRAVO. Na předchozí tlačítko se přesunete pomocí SHIFT+TAB nebo ŠIPKA VLEVO. Stiskněte MEZERNÍK nebo ENTER pro vybrání prvku v editoru."}]},
|
||||
{name:"Příkazy",items:[{name:" Příkaz Zpět",legend:"Stiskněte ${undo}"},{name:" Příkaz Znovu",legend:"Stiskněte ${redo}"},{name:" Příkaz Tučné",legend:"Stiskněte ${bold}"},{name:" Příkaz Kurzíva",legend:"Stiskněte ${italic}"},{name:" Příkaz Podtržení",legend:"Stiskněte ${underline}"},{name:" Příkaz Odkaz",legend:"Stiskněte ${link}"},{name:" Příkaz Skrýt panel nástrojů",legend:"Stiskněte ${toolbarCollapse}"},{name:"Příkaz pro přístup k předchozímu prostoru zaměření",legend:"Stiskněte ${accessPreviousSpace} pro přístup k nejbližšímu nedosažitelnému prostoru zaměření před stříškou, například: dva přilehlé prvky HR. Pro dosažení vzdálených prostorů zaměření tuto kombinaci kláves opakujte."},
|
||||
{name:"Příkaz pro přístup k dalšímu prostoru zaměření",legend:"Stiskněte ${accessNextSpace} pro přístup k nejbližšímu nedosažitelnému prostoru zaměření po stříšce, například: dva přilehlé prvky HR. Pro dosažení vzdálených prostorů zaměření tuto kombinaci kláves opakujte."},{name:" Nápověda přístupnosti",legend:"Stiskněte ${a11yHelp}"},{name:"Vložit jako čistý text",legend:"Stiskněte ${pastetext}",legendEdge:"Stiskněte ${pastetext} a pak ${paste}"}]}],tab:"Tabulátor",pause:"Pauza",capslock:"Caps lock",
|
||||
escape:"Escape",pageUp:"Stránka nahoru",pageDown:"Stránka dolů",leftArrow:"Šipka vlevo",upArrow:"Šipka nahoru",rightArrow:"Šipka vpravo",downArrow:"Šipka dolů",insert:"Vložit",leftWindowKey:"Levá klávesa Windows",rightWindowKey:"Pravá klávesa Windows",selectKey:"Vyberte klávesu",numpad0:"Numerická klávesa 0",numpad1:"Numerická klávesa 1",numpad2:"Numerická klávesa 2",numpad3:"Numerická klávesa 3",numpad4:"Numerická klávesa 4",numpad5:"Numerická klávesa 5",numpad6:"Numerická klávesa 6",numpad7:"Numerická klávesa 7",
|
||||
numpad8:"Numerická klávesa 8",numpad9:"Numerická klávesa 9",multiply:"Numerická klávesa násobení",add:"Přidat",subtract:"Numerická klávesa odečítání",decimalPoint:"Desetinná tečka",divide:"Numerická klávesa dělení",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num lock",scrollLock:"Scroll lock",semiColon:"Středník",equalSign:"Rovnítko",comma:"Čárka",dash:"Pomlčka",period:"Tečka",forwardSlash:"Lomítko",graveAccent:"Přízvuk",openBracket:"Otevřená hranatá závorka",
|
||||
backSlash:"Obrácené lomítko",closeBracket:"Uzavřená hranatá závorka",singleQuote:"Jednoduchá uvozovka"});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","cy",{title:"Canllawiau Hygyrchedd",contents:"Cynnwys Cymorth. I gau y deialog hwn, pwyswch ESC.",legend:[{name:"Cyffredinol",items:[{name:"Bar Offer y Golygydd",legend:"Pwyswch $ {toolbarFocus} i fynd at y bar offer. Symudwch i'r grŵp bar offer nesaf a blaenorol gyda TAB a SHIFT+TAB. Symudwch i'r botwm bar offer nesaf a blaenorol gyda SAETH DDE neu SAETH CHWITH. Pwyswch SPACE neu ENTER i wneud botwm y bar offer yn weithredol."},{name:"Deialog y Golygydd",legend:"Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively."},
|
||||
{name:"Dewislen Cyd-destun y Golygydd",legend:"Pwyswch $ {contextMenu} neu'r ALLWEDD 'APPLICATION' i agor y ddewislen cyd-destun. Yna symudwch i'r opsiwn ddewislen nesaf gyda'r TAB neu'r SAETH I LAWR. Symudwch i'r opsiwn blaenorol gyda SHIFT+TAB neu'r SAETH I FYNY. Pwyswch SPACE neu ENTER i ddewis yr opsiwn ddewislen. Agorwch is-dewislen yr opsiwn cyfredol gyda SPACE neu ENTER neu SAETH DDE. Ewch yn ôl i'r eitem ar y ddewislen uwch gydag ESC neu SAETH CHWITH. Ceuwch y ddewislen cyd-destun gydag ESC."},
|
||||
{name:"Blwch Rhestr y Golygydd",legend:"Tu mewn y blwch rhestr, ewch i'r eitem rhestr nesaf gyda TAB neu'r SAETH I LAWR. Symudwch i restr eitem flaenorol gyda SHIFT+TAB neu SAETH I FYNY. Pwyswch SPACE neu ENTER i ddewis yr opsiwn o'r rhestr. Pwyswch ESC i gau'r rhestr."},{name:"Bar Llwybr Elfen y Golygydd",legend:"Pwyswch ${elementsPathFocus} i fynd i'r bar llwybr elfennau. Symudwch i fotwm yr elfen nesaf gyda TAB neu SAETH DDE. Symudwch i fotwm blaenorol gyda SHIFT+TAB neu SAETH CHWITH. Pwyswch SPACE neu ENTER i ddewis yr elfen yn y golygydd."}]},
|
||||
{name:"Gorchmynion",items:[{name:"Gorchymyn dadwneud",legend:"Pwyswch ${undo}"},{name:"Gorchymyn ailadrodd",legend:"Pwyswch ${redo}"},{name:"Gorchymyn Bras",legend:"Pwyswch ${bold}"},{name:"Gorchymyn italig",legend:"Pwyswch ${italig}"},{name:"Gorchymyn tanlinellu",legend:"Pwyso ${underline}"},{name:"Gorchymyn dolen",legend:"Pwyswch ${link}"},{name:"Gorchymyn Cwympo'r Dewislen",legend:"Pwyswch ${toolbarCollapse}"},{name:"Myned i orchymyn bwlch ffocws blaenorol",legend:"Pwyswch ${accessPreviousSpace} i fyned i'r \"blwch ffocws sydd methu ei gyrraedd\" cyn y caret, er enghraifft: dwy elfen HR drws nesaf i'w gilydd. AIladroddwch y cyfuniad allwedd i gyrraedd bylchau ffocws pell."},
|
||||
{name:"Ewch i'r gorchymyn blwch ffocws nesaf",legend:"Pwyswch ${accessNextSpace} i fyned i'r blwch ffocws agosaf nad oes modd ei gyrraedd ar ôl y caret, er enghraifft: dwy elfen HR drws nesaf i'w gilydd. Ailadroddwch y cyfuniad allwedd i gyrraedd blychau ffocws pell."},{name:"Cymorth Hygyrchedd",legend:"Pwyswch ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Caps Lock",escape:"Escape",
|
||||
pageUp:"Page Up",pageDown:"Page Down",leftArrow:"Left Arrow",upArrow:"Up Arrow",rightArrow:"Right Arrow",downArrow:"Down Arrow",insert:"Insert",leftWindowKey:"Left Windows key",rightWindowKey:"Right Windows key",selectKey:"Select key",numpad0:"Numpad 0",numpad1:"Numpad 1",numpad2:"Numpad 2",numpad3:"Numpad 3",numpad4:"Numpad 4",numpad5:"Numpad 5",numpad6:"Numpad 6",numpad7:"Numpad 7",numpad8:"Numpad 8",numpad9:"Numpad 9",multiply:"Multiply",add:"Add",subtract:"Subtract",decimalPoint:"Decimal Point",
|
||||
divide:"Divide",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num Lock",scrollLock:"Scroll Lock",semiColon:"Semicolon",equalSign:"Equal Sign",comma:"Comma",dash:"Dash",period:"Period",forwardSlash:"Forward Slash",graveAccent:"Grave Accent",openBracket:"Open Bracket",backSlash:"Backslash",closeBracket:"Close Bracket",singleQuote:"Single Quote"});
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","da",{title:"Tilgængelighedsinstrukser",contents:"Onlinehjælp. For at lukke dette vindue klik ESC",legend:[{name:"Generelt",items:[{name:"Editor værktøjslinje",legend:"Tryk ${toolbarFocus} for at navigere til værktøjslinjen. Flyt til næste eller forrige værktøjsline gruppe ved hjælp af TAB eller SHIFT+TAB. Flyt til næste eller forrige værktøjslinje knap med venstre- eller højre piltast. Tryk på SPACE eller ENTER for at aktivere værktøjslinje knappen."},{name:"Editor dialogboks",
|
||||
legend:"Inde i en dialogboks kan du, trykke på TAB for at navigere til næste element, trykke på SHIFT+TAB for at navigere til forrige element, trykke på ENTER for at afsende eller trykke på ESC for at lukke dialogboksen.\r\nNår en dialogboks har flere faner, fanelisten kan tilgås med ALT+F10 eller med TAB. Hvis fanelisten er i fokus kan du skifte til næste eller forrige tab, med højre- og venstre piltast."},{name:"Redaktør kontekstmenu",legend:"Tryk ${contextMenu} eller APPLICATION KEY for at åbne kontekstmenuen. Flyt derefter til næste menuvalg med TAB eller PIL NED. Flyt til forrige valg med SHIFT+TAB eller PIL OP. Tryk MELLEMRUM eller RETUR for at vælge menu-muligheder. Åben under-menu af aktuelle valg med MELLEMRUM eller RETUR eller HØJRE PIL. Gå tilbage til overliggende menu-emne med ESC eller VENSTRE PIL. Luk kontekstmenu med ESC."},
|
||||
{name:"Redaktør listeboks",legend:"Flyt til næste emne med TAB eller PIL NED inde i en listeboks. Flyt til forrige listeemne med SHIFT+TAB eller PIL OP. Tryk MELLEMRUM eller RETUR for at vælge liste-muligheder. Tryk ESC for at lukke liste-boksen."},{name:"Redaktør elementsti-bar",legend:"Tryk ${elementsPathFocus} for at navigere til elementernes sti-bar. Flyt til næste element-knap med TAB eller HØJRE PIL. Flyt til forrige knap med SHIFT+TAB eller VENSTRE PIL. Klik MELLEMRUM eller RETUR for at vælge element i editoren."}]},
|
||||
{name:"Kommandoer",items:[{name:"Fortryd kommando",legend:"Klik på ${undo}"},{name:"Gentag kommando",legend:"Klik ${redo}"},{name:"Fed kommando",legend:"Klik ${bold}"},{name:"Kursiv kommando",legend:"Klik ${italic}"},{name:"Understregnings kommando",legend:"Klik ${underline}"},{name:"Link kommando",legend:"Klik ${link}"},{name:"Klap værktøjslinje sammen kommando ",legend:"Klik ${toolbarCollapse}"},{name:"Adgang til forrige fokusområde kommando",legend:"Press ${accessPreviousSpace} to access the closest unreachable focus space before the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},
|
||||
{name:" Access next focus space command",legend:"Press ${accessNextSpace} to access the closest unreachable focus space after the caret, for example: two adjacent HR elements. Repeat the key combination to reach distant focus spaces."},{name:"Tilgængelighedshjælp",legend:"Kilk ${a11yHelp}"},{name:"Indsæt som ren tekst",legend:"Klik ${pastetext}",legendEdge:"Klik ${pastetext}, efterfult af ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Caps Lock",escape:"Escape",pageUp:"Page Up",pageDown:"Page Down",
|
||||
leftArrow:"Venstre pil",upArrow:"Pil op",rightArrow:"Højre pil",downArrow:"Pil ned",insert:"Insert",leftWindowKey:"Venstre Windows tast",rightWindowKey:"Højre Windows tast",selectKey:"Select-knap",numpad0:"Numpad 0",numpad1:"Numpad 1",numpad2:"Numpad 2",numpad3:"Numpad 3",numpad4:"Numpad 4",numpad5:"Numpad 5",numpad6:"Numpad 6",numpad7:"Numpad 7",numpad8:"Numpad 8",numpad9:"Numpad 9",multiply:"Gange",add:"Plus",subtract:"Minus",decimalPoint:"Komma",divide:"Divider",f1:"F1",f2:"F2",f3:"F3",f4:"F4",
|
||||
f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Num Lock",scrollLock:"Scroll Lock",semiColon:"Semikolon",equalSign:"Lighedstegn",comma:"Komma",dash:"Bindestreg",period:"Punktum",forwardSlash:"Skråstreg",graveAccent:"Accent grave",openBracket:"Start klamme",backSlash:"Omvendt skråstreg",closeBracket:"Slut klamme",singleQuote:"Enkelt citationstegn"});
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","de-ch",{title:"Barrierefreiheitinformationen",contents:"Hilfeinhalt. Um den Dialog zu schliessen die Taste ESC drücken.",legend:[{name:"Allgemein",items:[{name:"Editorwerkzeugleiste",legend:"Drücken Sie ${toolbarFocus} auf der Symbolleiste. Gehen Sie zur nächsten oder vorherigen Symbolleistengruppe mit TAB und SHIFT+TAB. Gehen Sie zur nächsten oder vorherigen Symbolleiste auf die Schaltfläche mit dem RECHTS- oder LINKS-Pfeil. Drücken Sie die Leertaste oder Eingabetaste, um die Schaltfläche in der Symbolleiste aktivieren."},
|
||||
{name:"Editordialog",legend:"Inside a dialog, press TAB to navigate to the next dialog element, press SHIFT+TAB to move to the previous dialog element, press ENTER to submit the dialog, press ESC to cancel the dialog. When a dialog has multiple tabs, the tab list can be reached either with ALT+F10 or with TAB as part of the dialog tabbing order. With tab list focused, move to the next and previous tab with RIGHT and LEFT ARROW, respectively."},{name:"Editor-Kontextmenü",legend:"Dürcken Sie ${contextMenu} oder die Anwendungstaste um das Kontextmenü zu öffnen. Man kann die Pfeiltasten zum Wechsel benutzen. Mit der Leertaste oder der Enter-Taste kann man den Menüpunkt aufrufen. Schliessen Sie das Kontextmenü mit der ESC-Taste."},
|
||||
{name:"Editor-Listenbox",legend:"Innerhalb einer Listenbox kann man mit der TAB-Taste oder den Pfeilrunter-Taste den nächsten Menüeintrag wählen. Mit der SHIFT+TAB Tastenkombination oder der Pfeilhoch-Taste gelangt man zum vorherigen Menüpunkt. Mit der Leertaste oder Enter kann man den Menüpunkt auswählen. Drücken Sie ESC zum Verlassen des Menüs."},{name:"Editor-Elementpfadleiste",legend:"Drücken Sie ${elementsPathFocus} um sich durch die Pfadleiste zu bewegen. Um zum nächsten Element zu gelangen drücken Sie TAB oder die Pfeilrechts-Taste. Zum vorherigen Element gelangen Sie mit der SHIFT+TAB oder der Pfeillinks-Taste. Drücken Sie die Leertaste oder Enter um das Element auszuwählen."}]},
|
||||
{name:"Befehle",items:[{name:"Rückgängig-Befehl",legend:"Drücken Sie ${undo}"},{name:"Wiederherstellen-Befehl",legend:"Drücken Sie ${redo}"},{name:"Fettschrift-Befehl",legend:"Drücken Sie ${bold}"},{name:"Kursiv-Befehl",legend:"Drücken Sie ${italic}"},{name:"Unterstreichen-Befehl",legend:"Drücken Sie ${underline}"},{name:"Link-Befehl",legend:"Drücken Sie ${link}"},{name:"Werkzeugleiste einklappen-Befehl",legend:"Drücken Sie ${toolbarCollapse}"},{name:"Zugang bisheriger Fokussierung Raumbefehl ",legend:"Drücken Sie ${accessPreviousSpace} auf den am nächsten nicht erreichbar Fokus-Abstand vor die Einfügemarke zugreifen: zwei benachbarte HR-Elemente. Wiederholen Sie die Tastenkombination um entfernte Fokusräume zu erreichen. "},
|
||||
{name:"Zugang nächster Schwerpunkt Raumbefehl ",legend:"Drücken Sie $ { accessNextSpace }, um den nächsten unerreichbar Fokus Leerzeichen nach dem Cursor zum Beispiel auf: zwei benachbarten HR Elemente. Wiederholen Sie die Tastenkombination zum fernen Fokus Bereiche zu erreichen. "},{name:"Eingabehilfen",legend:"Drücken Sie ${a11yHelp}"},{name:" Paste as plain text",legend:"Press ${pastetext}",legendEdge:"Press ${pastetext}, followed by ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Feststell",escape:"Escape",
|
||||
pageUp:"Bild auf",pageDown:"Bild ab",leftArrow:"Linke Pfeiltaste",upArrow:"Obere Pfeiltaste",rightArrow:"Rechte Pfeiltaste",downArrow:"Untere Pfeiltaste",insert:"Einfügen",leftWindowKey:"Linke Windowstaste",rightWindowKey:"Rechte Windowstaste",selectKey:"Taste auswählen",numpad0:"Ziffernblock 0",numpad1:"Ziffernblock 1",numpad2:"Ziffernblock 2",numpad3:"Ziffernblock 3",numpad4:"Ziffernblock 4",numpad5:"Ziffernblock 5",numpad6:"Ziffernblock 6",numpad7:"Ziffernblock 7",numpad8:"Ziffernblock 8",numpad9:"Ziffernblock 9",
|
||||
multiply:"Multiplizieren",add:"Addieren",subtract:"Subtrahieren",decimalPoint:"Punkt",divide:"Dividieren",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Ziffernblock feststellen",scrollLock:"Rollen",semiColon:"Semikolon",equalSign:"Gleichheitszeichen",comma:"Komma",dash:"Bindestrich",period:"Punkt",forwardSlash:"Schrägstrich",graveAccent:"Gravis",openBracket:"Öffnende eckige Klammer",backSlash:"Rückwärtsgewandter Schrägstrich",closeBracket:"Schliessende eckige Klammer",
|
||||
singleQuote:"Einfaches Anführungszeichen"});
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
|
||||
For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
CKEDITOR.plugins.setLang("a11yhelp","de",{title:"Barrierefreiheitinformationen",contents:"Hilfeinhalt. Um den Dialog zu schliessen die Taste ESC drücken.",legend:[{name:"Allgemein",items:[{name:"Editorwerkzeugleiste",legend:"Drücken Sie ${toolbarFocus} auf der Symbolleiste. Gehen Sie zur nächsten oder vorherigen Symbolleistengruppe mit TAB und SHIFT+TAB. Gehen Sie zur nächsten oder vorherigen Symbolleiste auf die Schaltfläche mit dem RECHTS- oder LINKS-Pfeil. Drücken Sie die Leertaste oder Eingabetaste, um die Schaltfläche in der Symbolleiste aktivieren."},
|
||||
{name:"Editordialog",legend:"Drücke innerhalb eines Dialogs TAB, um zum nächsten Element zu springen. Drücke SHIFT+TAB, um zum vorigen Element zu springen, drücke ENTER um das Formular im Dialog abzusenden, drücke ESC, um den Dialog zu schließen. Hat der Dialog mehrere Tabs, dann kannst du durch ALT+F10 die Tab-Liste aufrufen or mittels TAB als Teil der Dialog-Tab-Reihenfolge. Ist die Tab-Liste fokussiert, dann mithilfe der Pfeiltasten (LINKS und RECHTS) zwischen den Tabs gewechselt werden."},{name:"Editor-Kontextmenü",
|
||||
legend:"Dürcken Sie ${contextMenu} oder die Anwendungstaste um das Kontextmenü zu öffnen. Man kann die Pfeiltasten zum Wechsel benutzen. Mit der Leertaste oder der Enter-Taste kann man den Menüpunkt aufrufen. Schliessen Sie das Kontextmenü mit der ESC-Taste."},{name:"Editor-Listenbox",legend:"Innerhalb einer Listenbox kann man mit der TAB-Taste oder den Pfeilrunter-Taste den nächsten Menüeintrag wählen. Mit der SHIFT+TAB Tastenkombination oder der Pfeilhoch-Taste gelangt man zum vorherigen Menüpunkt. Mit der Leertaste oder Enter kann man den Menüpunkt auswählen. Drücken Sie ESC zum Verlassen des Menüs."},
|
||||
{name:"Editor-Elementpfadleiste",legend:"Drücken Sie ${elementsPathFocus} um sich durch die Pfadleiste zu bewegen. Um zum nächsten Element zu gelangen drücken Sie TAB oder die Pfeilrechts-Taste. Zum vorherigen Element gelangen Sie mit der SHIFT+TAB oder der Pfeillinks-Taste. Drücken Sie die Leertaste oder Enter um das Element auszuwählen."}]},{name:"Befehle",items:[{name:"Rückgängig-Befehl",legend:"Drücken Sie ${undo}"},{name:"Wiederherstellen-Befehl",legend:"Drücken Sie ${redo}"},{name:"Fettschrift-Befehl",
|
||||
legend:"Drücken Sie ${bold}"},{name:"Kursiv-Befehl",legend:"Drücken Sie ${italic}"},{name:"Unterstreichen-Befehl",legend:"Drücken Sie ${underline}"},{name:"Link-Befehl",legend:"Drücken Sie ${link}"},{name:"Werkzeugleiste einklappen-Befehl",legend:"Drücken Sie ${toolbarCollapse}"},{name:"Zugang bisheriger Fokussierung Raumbefehl ",legend:"Drücken Sie ${accessPreviousSpace} auf den am nächsten nicht erreichbar Fokus-Abstand vor die Einfügemarke zugreifen: zwei benachbarte HR-Elemente. Wiederholen Sie die Tastenkombination um entfernte Fokusräume zu erreichen. "},
|
||||
{name:"Zugang nächster Schwerpunkt Raumbefehl ",legend:"Drücken Sie $ { accessNextSpace }, um den nächsten unerreichbar Fokus Leerzeichen nach dem Cursor zum Beispiel auf: zwei benachbarten HR Elemente. Wiederholen Sie die Tastenkombination zum fernen Fokus Bereiche zu erreichen. "},{name:"Eingabehilfen",legend:"Drücken Sie ${a11yHelp}"},{name:"Einfügen als unformatierter Text. ",legend:"Drücke ${pastetext}",legendEdge:"Drücke ${pastetext} und anschließend ${paste}"}]}],tab:"Tab",pause:"Pause",capslock:"Feststell",
|
||||
escape:"Escape",pageUp:"Bild auf",pageDown:"Bild ab",leftArrow:"Linke Pfeiltaste",upArrow:"Obere Pfeiltaste",rightArrow:"Rechte Pfeiltaste",downArrow:"Untere Pfeiltaste",insert:"Einfügen",leftWindowKey:"Linke Windowstaste",rightWindowKey:"Rechte Windowstaste",selectKey:"Taste auswählen",numpad0:"Ziffernblock 0",numpad1:"Ziffernblock 1",numpad2:"Ziffernblock 2",numpad3:"Ziffernblock 3",numpad4:"Ziffernblock 4",numpad5:"Ziffernblock 5",numpad6:"Ziffernblock 6",numpad7:"Ziffernblock 7",numpad8:"Ziffernblock 8",
|
||||
numpad9:"Ziffernblock 9",multiply:"Multiplizieren",add:"Addieren",subtract:"Subtrahieren",decimalPoint:"Punkt",divide:"Dividieren",f1:"F1",f2:"F2",f3:"F3",f4:"F4",f5:"F5",f6:"F6",f7:"F7",f8:"F8",f9:"F9",f10:"F10",f11:"F11",f12:"F12",numLock:"Ziffernblock feststellen",scrollLock:"Rollen",semiColon:"Semikolon",equalSign:"Gleichheitszeichen",comma:"Komma",dash:"Bindestrich",period:"Punkt",forwardSlash:"Schrägstrich",graveAccent:"Gravis",openBracket:"Öffnende eckige Klammer",backSlash:"Rückwärtsgewandter Schrägstrich",
|
||||
closeBracket:"Schließende eckige Klammer",singleQuote:"Einfaches Anführungszeichen"});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user