Change log: https://roxy-wi.org/changelog.py#6_1_4
pull/334/head
Pavel Loginov 2022-08-15 11:50:29 +03:00
parent 74862811b2
commit f3de2ec64d
74 changed files with 4103 additions and 1034 deletions

View File

@ -10,8 +10,8 @@ print('Content-type: text/html\n')
funct.check_login()
form = funct.form
serv = form.getvalue('serv')
service = form.getvalue('service')
serv = funct.is_ip_or_dns(form.getvalue('serv'))
service = funct.checkAjaxInput(form.getvalue('service'))
is_serv_protected = False
try:
config_file_name = form.getvalue('config_file_name').replace('92', '/')
@ -22,40 +22,31 @@ cfg = ""
stderr = ""
error = ""
aftersave = ""
is_restart = ''
try:
user, user_id, role, token, servers, user_services = funct.get_users_params()
except Exception as e:
print(str(e))
if service == 'keepalived':
if funct.check_login(service=3):
title = "Working with Keepalived configuration files"
action = "config.py?service=keepalived"
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f"Working with {service_desc.service} configuration files"
action = f"config.py?service={service_desc.slug}"
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
file_format = 'conf'
servers = sql.get_dick_permit(keepalived=1)
elif service == 'nginx':
if funct.check_login(service=2):
title = "Working with NGINX configuration files"
action = "config.py?service=nginx"
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
file_format = 'conf'
servers = sql.get_dick_permit(nginx=1)
elif service == 'apache':
if funct.check_login(service=4):
title = "Working with Apache configuration files"
action = "config.py?service=apache"
configs_dir = funct.get_config_var('configs', 'apache_save_configs_dir')
file_format = 'conf'
servers = sql.get_dick_permit(apache=1)
servers = sql.get_dick_permit(serivce=service_desc.service)
if service in ('haproxy', 'nginx', 'apache'):
configs_dir = funct.get_config_var('configs', f'{service_desc.service}_save_configs_dir')
else:
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
if service == 'haproxy':
file_format = 'cfg'
else:
if funct.check_login(service=1):
title = "Working with HAProxy configuration files"
action = "config.py"
configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
file_format = 'cfg'
servers = sql.get_dick_permit(haproxy=1)
print('<meta http-equiv="refresh" content="0; url=/app/overview.py">')
if serv is not None:
if service == 'nginx' or service == 'apache':
@ -67,6 +58,8 @@ if serv is not None:
if serv is not None and form.getvalue('open') is not None and form.getvalue('new_config') is None:
funct.check_is_server_in_group(serv)
is_serv_protected = sql.is_serv_protected(serv)
server_id = sql.select_server_id_by_ip(serv)
is_restart = sql.select_service_setting(server_id, service, 'restart')
if service == 'keepalived':
error = funct.get_config(serv, cfg, keepalived=1)
@ -142,7 +135,7 @@ if serv is not None and form.getvalue('config') is not None:
template = template.render(
h2=1, title=title, role=role, action=action, user=user, select_id="serv", serv=serv, aftersave=aftersave,
config=config_read, cfg=cfg, selects=servers, stderr=stderr, error=error, service=service,
config=config_read, cfg=cfg, selects=servers, stderr=stderr, error=error, service=service, is_restart=is_restart,
user_services=user_services, config_file_name=config_file_name, is_serv_protected=is_serv_protected, token=token
)
print(template)

View File

@ -181,16 +181,21 @@ def default_values():
print(str(e))
data_source = [
{'service_id': 1, 'service': 'HAProxy'},
{'service_id': 2, 'service': 'NGINX'},
{'service_id': 3, 'service': 'Keepalived'},
{'service_id': 4, 'service': 'Apache'},
{'service_id': 1, 'service': 'HAProxy', 'slug': 'haproxy'},
{'service_id': 2, 'service': 'NGINX', 'slug': 'nginx'},
{'service_id': 3, 'service': 'Keepalived', 'slug': 'keepalived'},
{'service_id': 4, 'service': 'Apache', 'slug': 'apache'},
]
try:
Services.insert_many(data_source).on_conflict_ignore().execute()
except Exception as e:
print(str(e))
except Exception:
Services.drop_table()
Services.create_table()
try:
Services.insert_many(data_source).on_conflict_ignore().execute()
except Exception as e:
print(str(e))
data_source = [
{'param': 'aws', 'name': 'AWS', 'optgroup': 'aws', 'section': 'provider', 'provider': 'aws', 'image': '/inc/images/provisioning/providers/aws.svg'},
@ -962,8 +967,25 @@ def update_db_v_6_1_3(**kwargs):
pass
def update_db_v_6_1_4():
servers = Server.select()
services = Services.select()
for server in servers:
for service in services:
service_name = service.service.lower()
setting = 'restart'
if service_name == 'keepalived':
continue
try:
ServiceSetting.insert(
server_id=server.server_id, service=service_name, setting=setting, value=1
).on_conflict_ignore().execute()
except Exception:
pass
def update_ver():
query = Version.update(version='6.1.3.0')
query = Version.update(version='6.1.4.0')
try:
query.execute()
except Exception:
@ -991,6 +1013,7 @@ def update_all():
update_db_v_6_0_1()
update_db_v_6_1_0()
update_db_v_6_1_3()
update_db_v_6_1_4()
update_ver()
@ -1014,6 +1037,7 @@ def update_all_silent():
update_db_v_6_0(silent=1)
update_db_v_6_0_1(silent=1)
update_db_v_6_1_3(silent=1)
update_db_v_6_1_4()
update_ver()

View File

@ -502,6 +502,7 @@ class SystemInfo(BaseModel):
class Services(BaseModel):
service_id = IntegerField(null=True)
service = CharField(null=True)
slug = CharField(null=True)
class Meta:
table_name = 'services'

View File

@ -753,6 +753,7 @@ def install_haproxy(server_ip, **kwargs):
if docker == '1':
server_id = sql.select_server_id_by_ip(server_ip)
sql.insert_or_update_service_setting(server_id, 'haproxy', 'dockerized', '1')
sql.insert_or_update_service_setting(server_id, 'haproxy', 'restart', '1')
os.system("rm -f %s" % script)
@ -876,6 +877,7 @@ def install_nginx(server_ip, **kwargs):
if docker == '1':
server_id = sql.select_server_id_by_ip(server_ip)
sql.insert_or_update_service_setting(server_id, 'nginx', 'dockerized', '1')
sql.insert_or_update_service_setting(server_id, 'nginx', 'restart', '1')
os.system("rm -f %s" % script)
@ -986,6 +988,7 @@ def upload_and_restart(server_ip, cfg, **kwargs):
tmp_file = sql.get_setting('tmp_config_path') + "/" + get_data('config') + ".cfg"
is_docker = sql.select_service_setting(server_id, service, 'dockerized')
if is_docker == '1':
service_cont_name = service + '_container_name'
container_name = sql.get_setting(service_cont_name)
@ -1011,6 +1014,7 @@ def upload_and_restart(server_ip, cfg, **kwargs):
action = 'reload'
reload_or_restart_command = reload_command
else:
is_not_allowed_to_restart(server_id, service)
action = 'restart'
reload_or_restart_command = restart_command
@ -2090,6 +2094,15 @@ def is_restarted(server_ip, action):
sys.exit()
def is_not_allowed_to_restart(server_id: int, service: str) -> bool:
import sql
is_restart = sql.select_service_setting(server_id, service, 'restart')
if int(is_restart) == 1:
print('warning: this service is not allowed to be restarted')
sys.exit()
def return_user_status():
import sql

View File

@ -17,62 +17,32 @@ user, user_id, role, token, servers, user_services = funct.get_users_params()
form = funct.form
serv = funct.is_ip_or_dns(form.getvalue('serv'))
service = form.getvalue('service')
service = funct.checkAjaxInput(form.getvalue('service'))
autorefresh = 0
servers_waf = ()
title = "HAProxy servers overview"
cmd = "ps ax |grep -e 'keep_alive.py' |grep -v grep |wc -l"
keep_alive, stderr = funct.subprocess_execute(cmd)
is_restart = ''
restart_settings = ''
if service == 'nginx':
if funct.check_login(service=2):
title = 'NGINX servers overview'
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f'{service_desc.service} servers overview'
if serv:
if funct.check_is_server_in_group(serv):
servers = sql.select_servers(server=serv)
autorefresh = 1
server_id = sql.select_server_id_by_ip(serv)
service_settings = sql.select_docker_service_settings(server_id, service)
docker_settings = sql.select_docker_service_settings(server_id, service_desc.service)
restart_settings = sql.select_restart_service_settings(server_id, service_desc.service)
else:
servers = sql.get_dick_permit(virt=1, nginx=1)
service_settings = sql.select_docker_services_settings(service)
elif service == 'keepalived':
if funct.check_login(service=3):
title = 'Keepalived servers overview'
if serv:
if funct.check_is_server_in_group(serv):
servers = sql.select_servers(server=serv)
autorefresh = 1
server_id = sql.select_server_id_by_ip(serv)
service_settings = sql.select_docker_service_settings(server_id, service)
else:
servers = sql.get_dick_permit(virt=1, keepalived=1)
service_settings = sql.select_docker_services_settings(service)
elif service == 'apache':
if funct.check_login(service=4):
title = 'Apache servers overview'
if serv:
if funct.check_is_server_in_group(serv):
servers = sql.select_servers(server=serv)
autorefresh = 1
server_id = sql.select_server_id_by_ip(serv)
service_settings = sql.select_docker_service_settings(server_id, service)
else:
servers = sql.get_dick_permit(virt=1, apache=1)
service_settings = sql.select_docker_services_settings(service)
servers = sql.get_dick_permit(virt=1, service=service_desc.slug)
docker_settings = sql.select_docker_services_settings(service_desc.service)
restart_settings = sql.select_restart_services_settings(service_desc.service)
else:
if funct.check_login(service=1):
service = 'haproxy'
if serv:
if funct.check_is_server_in_group(serv):
servers = sql.select_servers(server=serv)
autorefresh = 1
server_id = sql.select_server_id_by_ip(serv)
servers_waf = sql.select_waf_servers_metrics(user_id.value)
service_settings = sql.select_docker_service_settings(server_id, service)
else:
servers = sql.get_dick_permit(virt=1, haproxy=1)
service_settings = sql.select_docker_services_settings(service)
print('<meta http-equiv="refresh" content="0; url=/app/overview.py">')
services_name = {'roxy-wi-checker': 'Master backends checker service',
'roxy-wi-keep_alive': 'Auto start service',
@ -106,7 +76,7 @@ for s in servers:
cmd = [
"/usr/sbin/nginx -v 2>&1|awk '{print $3}' && systemctl status nginx |grep -e 'Active' |awk "
"'{print $2, $9$10$11$12$13}' && ps ax |grep nginx:|grep -v grep |wc -l"]
for service_set in service_settings:
for service_set in docker_settings:
if service_set.server_id == s[0] and service_set.setting == 'dockerized' and service_set.value == '1':
container_name = sql.get_setting('nginx_container_name')
cmd = [
@ -206,7 +176,7 @@ except Exception as e:
template = template.render(
h2=1, autorefresh=autorefresh, title=title, role=role, user=user, servers=servers_with_status1,
keep_alive=''.join(keep_alive), serv=serv, service=service, services=services, user_services=user_services,
service_settings=service_settings, user_status=user_status, user_plan=user_plan, servers_waf=servers_waf,
token=token
docker_settings=docker_settings, user_status=user_status, user_plan=user_plan, servers_waf=servers_waf,
restart_settings=restart_settings, token=token
)
print(template)

View File

@ -21,47 +21,15 @@ serv = funct.is_ip_or_dns(form.getvalue('serv'))
service = form.getvalue('service')
user_id = form.getvalue('user_id')
if service == 'nginx':
if funct.check_login(service=2):
title = 'Nginx service history'
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(
server_id,
service
)
elif service == 'keepalived':
if funct.check_login(service=3):
title = 'Keepalived service history'
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(
server_id,
service
)
elif service == 'apache':
if funct.check_login(service=4):
title = 'Apache service history'
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(
server_id,
service
)
elif service == 'haproxy':
if funct.check_login(service=1):
title = "HAProxy service history"
if serv:
if funct.check_is_server_in_group(serv):
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(
server_id,
service
)
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f'{service_desc.service} service history'
server_id = sql.select_server_id_by_ip(serv)
history = sql.select_action_history_by_server_id_and_service(
server_id,
service_desc.service
)
elif service == 'server':
if serv:
title = serv + ' history'

View File

@ -26,7 +26,7 @@ hour1 = form.getvalue('hour1')
minut = form.getvalue('minut')
minut1 = form.getvalue('minut1')
waf = form.getvalue('waf')
service = form.getvalue('service')
service = funct.checkAjaxInput(form.getvalue('service'))
remote_file = form.getvalue('file')
print('Content-type: text/html\n')
@ -37,22 +37,17 @@ try:
except Exception:
pass
if service == 'nginx':
if funct.check_login(service=2):
title = "NGINX`s logs"
servers = sql.get_dick_permit(nginx=1)
elif service == 'apache':
if funct.check_login(service=4):
title = "Apache's logs"
servers = sql.get_dick_permit(apache=1)
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f"{service_desc.service}`s logs"
servers = sql.get_dick_permit(service=service_desc.slug)
elif waf == '1':
if funct.check_login(service=1):
title = "WAF logs"
servers = sql.get_dick_permit(haproxy=1)
else:
if funct.check_login(service=1):
title = "HAProxy`s logs"
servers = sql.get_dick_permit(haproxy=1)
print('<meta http-equiv="refresh" content="0; url=/app/overview.py">')
template = template.render(
h2=1, autorefresh=1, title=title, role=role, user=user, select_id="serv", selects=servers,

View File

@ -443,6 +443,10 @@ if form.getvalue('action_hap') is not None and serv is not None:
if funct.check_haproxy_config(serv):
server_id = sql.select_server_id_by_ip(server_ip=serv)
if action == 'restart':
funct.is_not_allowed_to_restart(server_id, 'haproxy')
is_docker = sql.select_service_setting(server_id, 'haproxy', 'dockerized')
if is_docker == '1':
@ -471,7 +475,11 @@ if form.getvalue('action_nginx') is not None and serv is not None:
if funct.check_nginx_config(serv):
server_id = sql.select_server_id_by_ip(server_ip=serv)
if action == 'restart':
funct.is_not_allowed_to_restart(server_id, 'nginx')
is_docker = sql.select_service_setting(server_id, 'nginx', 'dockerized')
if is_docker == '1':
container_name = sql.get_setting('nginx_container_name')
commands = ["sudo docker %s %s" % (action, container_name)]
@ -540,6 +548,10 @@ if form.getvalue('action_apache') is not None and serv is not None:
funct.is_restarted(serv, action)
server_id = sql.select_server_id_by_ip(serv)
if action == 'restart':
funct.is_not_allowed_to_restart(server_id, 'apache')
is_docker = sql.select_service_setting(server_id, 'apache', 'dockerized')
if is_docker == '1':
container_name = sql.get_setting('apache_container_name')
@ -1207,7 +1219,7 @@ if form.getvalue('servaction') is not None:
if enable != "show":
funct.logging(serv, 'Has been ' + enable + 'ed ' + backend, login=1, keep_history=1, service='haproxy')
print(
'<center><h3>You %s %s on HAProxy %s. <a href="viewsttats.py?serv=%s" title="View stat" target="_blank">Look it</a> or <a href="runtimeapi.py" title="Runtime API">Edit something else</a></h3><br />' % (enable, backend, serv, serv))
'<center><h3>You %s %s on HAProxy %s. <a href="statsview.py?serv=%s" title="View stat" target="_blank">Look it</a> or <a href="runtimeapi.py" title="Runtime API">Edit something else</a></h3><br />' % (enable, backend, serv, serv))
print(funct.ssh_command(serv, command, show_log="1"))
action = 'runtimeapi.py ' + enable + ' ' + backend
@ -1894,33 +1906,45 @@ if form.getvalue('metrics_waf'):
sql.update_waf_metrics_enable(form.getvalue('metrics_waf'), form.getvalue('enable'))
if form.getvalue('table_metrics'):
service = form.getvalue('service')
if service in ('nginx', 'apache'):
metrics = sql.select_service_table_metrics(service)
else:
metrics = sql.select_table_metrics()
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/ajax'), autoescape=True)
template = env.get_template('table_metrics.html')
template = template.render(table_stat=sql.select_table_metrics())
template = template.render(table_stat=metrics, service=service)
print(template)
if form.getvalue('metrics_hapwi_ram'):
import json
ip = form.getvalue('ip')
metrics = {'chartData': {}}
rams = ''
if ip == '1':
cmd = "free -m |grep Mem |awk '{print $2,$3,$4,$5,$6,$7}'"
metric, error = funct.subprocess_execute(cmd)
import psutil
rams_list = psutil.virtual_memory()
rams += str(round(rams_list.total/1048576, 2)) + ' '
rams += str(round(rams_list.used/1048576, 2)) + ' '
rams += str(round(rams_list.free/1048576, 2)) + ' '
rams += str(round(rams_list.shared/1048576, 2)) + ' '
rams += str(round(rams_list.cached/1048576, 2)) + ' '
rams += str(round(rams_list.available/1048576, 2)) + ' '
else:
commands = ["free -m |grep Mem |awk '{print $2,$3,$4,$5,$6,$7}'"]
metric, error = funct.subprocess_execute(commands[0])
for i in metric:
rams = i
for i in metric:
rams = i
metrics['chartData']['rams'] = rams
import json
print(json.dumps(metrics))
if form.getvalue('metrics_hapwi_cpu'):
@ -1929,15 +1953,26 @@ if form.getvalue('metrics_hapwi_cpu'):
cpus = ''
if ip == '1':
cmd = "top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'"
metric, error = funct.subprocess_execute(cmd)
# cmd = "top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'"
# metric, error = funct.subprocess_execute(cmd)
import psutil
cpus_list = psutil.cpu_times_percent(interval=1, percpu=False)
cpus += str(cpus_list.user) + ' '
cpus += str(cpus_list.system) + ' '
cpus += str(cpus_list.nice) + ' '
cpus += str(cpus_list.idle) + ' '
cpus += str(cpus_list.iowait) + ' '
cpus += str(cpus_list.irq) + ' '
cpus += str(cpus_list.softirq) + ' '
cpus += str(cpus_list.steal) + ' '
else:
commands = [
"top -b -n 1 |grep Cpu |awk -F':' '{print $2}'|awk -F' ' 'BEGIN{ORS=\" \";} { for (i=1;i<=NF;i+=2) print $i}'"]
metric, error = funct.subprocess_execute(commands[0])
for i in metric:
cpus = i
for i in metric:
cpus = i
metrics['chartData']['cpus'] = cpus
@ -4334,6 +4369,9 @@ if form.getvalue('serverSettingsSave') is not None:
haproxy_dockerized = form.getvalue('serverSettingshaproxy_dockerized')
nginx_dockerized = form.getvalue('serverSettingsnginx_dockerized')
apache_dockerized = form.getvalue('serverSettingsapache_dockerized')
haproxy_restart = form.getvalue('serverSettingsHaproxyrestart')
nginx_restart = form.getvalue('serverSettingsNginxrestart')
apache_restart = form.getvalue('serverSettingsApache_restart')
server_ip = sql.select_server_ip_by_id(server_id)
if service == 'haproxy':
@ -4353,6 +4391,14 @@ if form.getvalue('serverSettingsSave') is not None:
else:
funct.logging(server_ip, 'Service has been flagged as a system service', haproxywi=1, login=1,
keep_history=1, service=service)
if sql.insert_or_update_service_setting(server_id, service, 'restart', haproxy_restart):
print('Ok')
if haproxy_restart == '1':
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
else:
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
if service == 'nginx':
if sql.insert_or_update_service_setting(server_id, service, 'dockerized', nginx_dockerized):
@ -4363,6 +4409,14 @@ if form.getvalue('serverSettingsSave') is not None:
else:
funct.logging(server_ip, 'Service has been flagged as a system service', haproxywi=1, login=1,
keep_history=1, service=service)
if sql.insert_or_update_service_setting(server_id, service, 'restart', nginx_dockerized):
print('Ok')
if nginx_restart == '1':
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
else:
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
if service == 'apache':
if sql.insert_or_update_service_setting(server_id, service, 'dockerized', apache_dockerized):
@ -4373,6 +4427,14 @@ if form.getvalue('serverSettingsSave') is not None:
else:
funct.logging(server_ip, 'Service has been flagged as a system service', haproxywi=1, login=1,
keep_history=1, service=service)
if sql.insert_or_update_service_setting(server_id, service, 'restart', nginx_dockerized):
print('Ok')
if apache_restart == '1':
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
else:
funct.logging(server_ip, 'Restart option is disabled for this service', haproxywi=1, login=1,
keep_history=1, service=service)
if act == 'showListOfVersion':
service = form.getvalue('service')
@ -4380,27 +4442,21 @@ if act == 'showListOfVersion':
for_delver = form.getvalue('for_delver')
style = form.getvalue('style')
users = sql.select_users()
service_desc = sql.select_service(service)
if service == 'keepalived':
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
files = funct.get_files(dir=configs_dir, format='conf')
configs = sql.select_config_version(serv, service)
action = 'versions.py?service=keepalived'
elif service == 'nginx':
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
files = funct.get_files(dir=configs_dir, format='conf')
configs = sql.select_config_version(serv, service)
action = 'versions.py?service=nginx'
elif service == 'apache':
configs_dir = funct.get_config_var('configs', 'apache_save_configs_dir')
files = funct.get_files(dir=configs_dir, format='conf')
configs = sql.select_config_version(serv, service)
action = 'versions.py?service=apache'
else:
service = 'haproxy'
files = funct.get_files()
configs = sql.select_config_version(serv, service)
action = "versions.py"
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
configs = sql.select_config_version(serv, service_desc.service)
action = f'versions.py?service={service_desc.slug}'
if service in ('haproxy', 'nginx', 'apache'):
configs_dir = funct.get_config_var('configs', f'{service_desc.service}_save_configs_dir')
else:
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
if service == 'haproxy':
files = funct.get_files()
else:
files = funct.get_files(dir=configs_dir, format='conf')
from jinja2 import Environment, FileSystemLoader

View File

@ -1947,6 +1947,131 @@ def select_table_metrics():
return cursor.fetchall()
def select_service_table_metrics(service):
cursor = conn.cursor()
group_id = funct.get_user_group(id=1)
if service in ('nginx', 'apache'):
metrics_table = '{}_metrics'.format(service)
if funct.check_user_group():
if group_id == 1:
groups = ""
else:
groups = "and servers.groups = '{group}' ".format(group=group_id)
if mysql_enable == '1':
sql = """
select ip.ip, hostname, avg_cur_1h, avg_cur_24h, avg_cur_3d, max_con_1h, max_con_24h, max_con_3d from
(select servers.ip from servers where {metrics} = 1 ) as ip,
(select servers.ip, servers.hostname as hostname from servers left join {metrics} as metr on servers.ip = metr.serv where servers.{metrics} = 1 {groups}) as hostname,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_1h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -1 HOUR)
group by servers.ip) as avg_cur_1h,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_24h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR)
group by servers.ip) as avg_cur_24h,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_3d from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -3 DAY)
group by servers.ip ) as avg_cur_3d,
(select servers.ip,max(metr.conn) as max_con_1h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -1 HOUR)
group by servers.ip) as max_con_1h,
(select servers.ip,max(metr.conn) as max_con_24h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -24 HOUR)
group by servers.ip) as max_con_24h,
(select servers.ip,max(metr.conn) as max_con_3d from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= now() and metr.date >= DATE_ADD(NOW(),INTERVAL -3 DAY)
group by servers.ip ) as max_con_3d
where ip.ip=hostname.ip
and ip.ip=avg_cur_1h.ip
and ip.ip=avg_cur_24h.ip
and ip.ip=avg_cur_3d.ip
and ip.ip=max_con_1h.ip
and ip.ip=max_con_24h.ip
and ip.ip=max_con_3d.ip
group by hostname.ip """.format(metrics=metrics_table, groups=groups)
else:
sql = """
select ip.ip, hostname, avg_cur_1h, avg_cur_24h, avg_cur_3d, max_con_1h, max_con_24h, max_con_3d from
(select servers.ip from servers where {metrics} = 1 ) as ip,
(select servers.ip, servers.hostname as hostname from servers left join {metrics} as metr on servers.ip = metr.serv where servers.{metrics} = 1 {groups}) as hostname,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_1h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime')
group by servers.ip) as avg_cur_1h,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_24h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime')
group by servers.ip) as avg_cur_24h,
(select servers.ip,round(avg(metr.conn), 1) as avg_cur_3d from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime')
group by servers.ip ) as avg_cur_3d,
(select servers.ip,max(metr.conn) as max_con_1h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-1 hours', 'localtime')
group by servers.ip) as max_con_1h,
(select servers.ip,max(metr.conn) as max_con_24h from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-24 hours', 'localtime')
group by servers.ip) as max_con_24h,
(select servers.ip,max(metr.conn) as max_con_3d from servers
left join {metrics} as metr on metr.serv = servers.ip
where servers.{metrics} = 1 and
metr.date <= datetime('now', 'localtime') and metr.date >= datetime('now', '-3 days', 'localtime')
group by servers.ip ) as max_con_3d
where ip.ip=hostname.ip
and ip.ip=avg_cur_1h.ip
and ip.ip=avg_cur_24h.ip
and ip.ip=avg_cur_3d.ip
and ip.ip=max_con_1h.ip
and ip.ip=max_con_24h.ip
and ip.ip=max_con_3d.ip
group by hostname.ip """.format(metrics=metrics_table, groups=groups)
try:
cursor.execute(sql)
except Exception as e:
out_error(e)
else:
return cursor.fetchall()
def get_setting(param, **kwargs):
try:
user_group = funct.get_user_group(id=1)
@ -3159,6 +3284,33 @@ def select_docker_services_settings(service: str) -> str:
return query_res
def select_restart_service_settings(server_id: int, service: str) -> str:
query = ServiceSetting.select().where(
(ServiceSetting.server_id == server_id)
& (ServiceSetting.service == service)
& (ServiceSetting.setting == 'restart')
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_restart_services_settings(service: str) -> str:
query = ServiceSetting.select().where(
(ServiceSetting.service == service)
& (ServiceSetting.setting == 'restart')
)
try:
query_res = query.execute()
except Exception as e:
out_error(e)
else:
return query_res
def select_service_setting(server_id: int, service: str, setting: str) -> str:
try:
result = ServiceSetting.get(
@ -3603,3 +3755,13 @@ def select_provisioning_params():
return
else:
return query_res
def select_service(slug: str) -> str:
try:
query_res = Services.get(Services.slug == slug)
except Exception as e:
out_error(e)
return 'there is no service'
else:
return query_res

View File

@ -3,7 +3,7 @@ import funct
import sql
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
template = env.get_template('viewstats.html')
template = env.get_template('statsview.html')
form = funct.form
serv = form.getvalue('serv')
service = form.getvalue('service')
@ -22,17 +22,13 @@ try:
except Exception:
pass
if service == 'nginx':
if funct.check_login(service=2):
title = 'NGINX stats page'
servers = sql.get_dick_permit(nginx=1)
elif service == 'apache':
if funct.check_login(service=4):
title = 'Apache stats page'
servers = sql.get_dick_permit(apache=1)
if service in ('haproxy', 'nginx', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f'{service_desc.service} stats page'
sql.get_dick_permit(service=service_desc.slug)
else:
if funct.check_login(service=1):
title = 'HAProxy stats page'
print('<meta http-equiv="refresh" content="0; url=/app/overview.py">')
rendered_template = template.render(
h2=1, autorefresh=1, title=title, role=role, user=user, onclick="showStats()", select_id="serv",

View File

@ -29,16 +29,16 @@
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<script defer src="/inc/ion.sound.min.js"></script>
<link href="/inc/awesome.css" rel="stylesheet">
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/nprogress.css" rel="stylesheet">
<link href="/inc/jquery-ui.css" rel="stylesheet">
<link href="/inc/css/awesome.css" rel="stylesheet">
<link href="/inc/css/style.css" rel="stylesheet">
<link href="/inc/css/nprogress.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.css" rel="stylesheet">
<script src="/inc/jquery-1.12.4.js"></script>
<script src="/inc/jquery-ui.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<link href="/inc/toastr.css" rel="stylesheet"/>
<link href="/inc/css/toastr.css" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>
</head>
<body>

View File

@ -29,16 +29,16 @@
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<script defer src="/inc/ion.sound.min.js"></script>
<link href="/inc/awesome.css" rel="stylesheet">
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/nprogress.css" rel="stylesheet">
<link href="/inc/jquery-ui.css" rel="stylesheet">
<link href="/inc/css/awesome.css" rel="stylesheet">
<link href="/inc/css/style.css" rel="stylesheet">
<link href="/inc/css/nprogress.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.css" rel="stylesheet">
<script src="/inc/jquery-1.12.4.js"></script>
<script src="/inc/jquery-ui.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<link href="/inc/toastr.css" rel="stylesheet"/>
<link href="/inc/css/toastr.css" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>
</head>
<body>

View File

@ -183,5 +183,5 @@
{% endfor %}
});
</script>
<link href="/inc/servers.css" rel="stylesheet"/>
<link href="/inc/css/servers.css" rel="stylesheet"/>
{% endblock %}

View File

@ -1,4 +1,4 @@
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
{% if action == "history" %}
{% set column_for_sort = 4 %}

View File

@ -234,7 +234,7 @@
{% endif %}
{%- set backend = line.split(' ') -%}
<span class="accordion-link">
<a href="/app/viewsttats.py?service=haproxy&serv={{-serv-}}#{{- backend[1]-}}" target="_blank">Stats</a>
<a href="/app/statsview.py?service=haproxy&serv={{-serv-}}#{{- backend[1]-}}" target="_blank">Stats</a>
</span>
{%- set backend = backend|join('_') -%}
{%- do section_name.update({i: backend}) -%}
@ -251,7 +251,7 @@
{% endif %}
{% set backend = line.split(' ') %}
<span class="accordion-link">
<a href="/app/viewsttats.py?serv={{serv}}#{{ backend[1]}}" target="_blank">Stats</a>
<a href="/app/statsview.py?serv={{serv}}#{{ backend[1]}}" target="_blank">Stats</a>
</span>
{% set backend = backend|join('_') %}
{% do section_name.update({i: backend}) %}
@ -268,7 +268,7 @@
{% endif %}
{% set backend = line.split(' ') %}
<span class="accordion-link">
<a href="/app/viewsttats.py?serv={{serv}}#{{ backend[1]}}" target="_blank">Stats</a>
<a href="/app/statsview.py?serv={{serv}}#{{ backend[1]}}" target="_blank">Stats</a>
</span>
</span><div>
{% continue %}

View File

@ -74,7 +74,7 @@
</td>
<td>
{% if waf_service == 'haproxy' %}
<a href="/app/logs.py?serv={{ service.1 }}&rows=10&grep=&hour=00&minut=00&hour1=24&minut1=00&waf=1" class="ui-button ui-widget ui-corner-all" title="View log">View</a>
<a href="/app/logs.py?service={{waf_service}}&serv={{ service.1 }}&rows=10&grep=&hour=00&minut=00&hour1=24&minut1=00&waf=1" class="ui-button ui-widget ui-corner-all" title="View log">View</a>
{% elif waf_service == 'nginx' %}
<a href="/app/logs.py?service={{waf_service}}&serv={{ service.1 }}&rows=10&grep=ModSecurity&hour=00&minut=00&hour1=24&minut1=00&file=error.log&waf=0" class="ui-button ui-widget ui-corner-all" title="View log">View</a>
{% endif %}

View File

@ -6,7 +6,7 @@
$('#table_version').on('page.dt')
.DataTable( {
"pageLength": 25,
"order": [ 6, "desc" ],
"order": [ 5, "desc" ],
stateSave: true,
"columnDefs": [
{

View File

@ -3,7 +3,6 @@
{% if service == 'haproxy' %}
{% if settings %}
{% for s in settings %}
{{s.dockerized}}
{% if s.haproxy_enterprise != '' and s.setting == 'haproxy_enterprise' %}
<tr>
<td class="padding20 help_cursor" style="width: 70%"
@ -30,6 +29,18 @@
</td>
</tr>
{% endif %}
{% if s.restart != '' and s.setting == 'restart' %}
<tr>
<td class="padding20 help_cursor" style="width: 70%" title="If enabled, the restart button disabled">Disable restart</td>
<td>
{% if s.value == '1' and s.setting == 'restart' %}
{{ checkbox('haproxy_restart', checked='checked', title='Restart option is disabled for this server') }}
{% elif s.setting == 'restart' %}
{{ checkbox('haproxy_restart', title='Only the reload button will be active') }}
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr>
@ -46,6 +57,13 @@
{{ checkbox('haproxy_dockerized', title='This server will be used as Docker container') }}
</td>
</tr>
<tr>
<td class="padding20 help_cursor" style="width: 70%"
title="If enabled, the restart button disabled">Disable restart</td>
<td>
{{ checkbox('haproxy_restart', title='Only the reload button will be active') }}
</td>
</tr>
{% endif %}
{% endif %}
{% if service == 'nginx' %}
@ -64,6 +82,18 @@
</td>
</tr>
{% endif %}
{% if s.restart != '' and s.setting == 'restart' %}
<tr>
<td class="padding20 help_cursor" style="width: 70%" title="If enabled, the restart button disabled">Disable restart</td>
<td>
{% if s.value == '1' and s.setting == 'restart' %}
{{ checkbox('nginx_restart', checked='checked', title='Restart option is disabled for this server') }}
{% elif s.setting == 'restart' %}
{{ checkbox('nginx_restart', title='Only the reload button will be active') }}
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr>
@ -73,6 +103,12 @@
{{ checkbox('nginx_dockerized', title='This server will be used as Docker container') }}
</td>
</tr>
<tr>
<td class="padding20 help_cursor" style="width: 70%" title="If enabled, the restart button disabled">Disable restart</td>
<td>
{{ checkbox('nginx_restart', title='Only the reload button will be active') }}
</td>
</tr>
{% endif %}
{% endif %}
{% if service == 'apache' %}
@ -91,6 +127,18 @@
</td>
</tr>
{% endif %}
{% if s.restart != '' and s.setting == 'restart' %}
<tr>
<td class="padding20 help_cursor" style="width: 70%" title="If enabled, the restart button disabled">Disable restart</td>
<td>
{% if s.value == '1' and s.setting == 'restart' %}
{{ checkbox('apache_restart', checked='checked', title='Restart option is disabled for this server') }}
{% elif s.setting == 'restart' %}
{{ checkbox('apache_restart', title='Only the reload button will be active') }}
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr>
@ -100,6 +148,12 @@
{{ checkbox('apache_dockerized', title='This server will be used as Docker container') }}
</td>
</tr>
<tr>
<td class="padding20 help_cursor" style="width: 70%" title="If enabled, the restart button disabled">Disable restart</td>
<td>
{{ checkbox('apache_restart', title='Only the reload button will be active') }}
</td>
</tr>
{% endif %}
{% endif %}
</table>
</table>

View File

@ -30,20 +30,21 @@
<script defer src="/inc/fontawesome.min.js"></script>
<script>FontAwesomeConfig = { searchPseudoElements: true, observeMutations: false };</script>
<script defer src="/inc/ion.sound.min.js"></script>
<link href="/inc/awesome.css" rel="stylesheet">
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/nprogress.css" rel="stylesheet">
<link href="/inc/jquery-ui.min.css" rel="stylesheet">
<link href="/inc/jquery-ui.structure.min.css" rel="stylesheet">
<link href="/inc/css/awesome.css" rel="stylesheet">
<link href="/inc/css/style.css" rel="stylesheet">
<link href="/inc/css/nprogress.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.min.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.structure.min.css" rel="stylesheet">
<script src="/inc/jquery-3.6.0.min.js"></script>
<script src="/inc/jquery-ui.min.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/reconnecting-websocket.js"></script>
<link href="/inc/select2.css" rel="stylesheet" />
<script src="/inc/hotkeys.js"></script>
<link href="/inc/css/select2.css" rel="stylesheet" />
<script src="/inc/select2.js"></script>
<script src="/inc/script.js"></script>
<script src="/inc/nprogress.js"></script>
<link href="/inc/toastr.css" rel="stylesheet"/>
<link href="/inc/css/toastr.css" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>
</head>
<body>
@ -65,15 +66,15 @@
<li class="p_menu">
<a href="/app/hapservers.py" title="HAProxy servers overview" class="config-show">Haproxy</a>
<ul class="v_menu">
<li><a href="/app/hapservers.py" title="HAProxy servers overview" class="overview-link head-submenu">Overview</a> </li>
<li><a href="/app/config.py" title="Working with HAProxy configs" class="edit head-submenu">Configs</a></li>
<li><a href="/app/viewsttats.py" title="HAProxy statistics " class="stats head-submenu">Stats</a></li>
<li><a href="/app/logs.py" title="HAProxy logs " class="logs head-submenu">Logs</a></li>
<li><a href="/app/hapservers.py?service=haproxy" title="HAProxy servers overview" class="overview-link head-submenu">Overview</a> </li>
<li><a href="/app/config.py?service=haproxy" title="Working with HAProxy configs" class="edit head-submenu">Configs</a></li>
<li><a href="/app/statsview.py?service=haproxy" title="HAProxy statistics " class="stats head-submenu">Stats</a></li>
<li><a href="/app/logs.py?service=haproxy" title="HAProxy logs " class="logs head-submenu">Logs</a></li>
<li><a href="/app/runtimeapi.py" title="Runtime API - Roxy-WI" class="runtime head-submenu">Runtime API</a></li>
<li><a href="/app/metrics.py" title="HAProxy's metrics" class="metrics head-submenu">Metrics</a></li>
<li><a href="/app/metrics.py?service=haproxy" title="HAProxy's metrics" class="metrics head-submenu">Metrics</a></li>
{% if role <= 3 %}
<li><a href="/app/add.py#proxy" title="Add proxy: Create proxy - Roxy-WI" class="add-proxy head-submenu" id="add1">Add proxy</a></li>
<li><a href="/app/versions.py" title="Working with versions HAProxy configs" class="version head-submenu">Versions</a></li>
<li><a href="/app/versions.py?service=haproxy" title="Working with versions HAProxy configs" class="version head-submenu">Versions</a></li>
<li><a href="/app/add.py#ssl" title="Add proxy: Upload SSL certificates - Roxy-WI" class="cert head-submenu" id="add3">SSL</a></li>
<li><a href="/app/add.py#lists" title="Add proxy: Create and upload whitelists or blacklists - Roxy-WI" class="lists head-submenu" id="add7">Lists</a></li>
<li><a href="/app/waf.py?service=haproxy" title="Web application firewall" class="waf-menu head-submenu">WAF</a> </li>
@ -87,7 +88,7 @@
<ul class="v_menu">
<li><a href="/app/hapservers.py?service=nginx" title="Overview NGINX servers" class="overview-link head-submenu">Overview</a></li>
<li><a href="/app/config.py?service=nginx" title="Working with NGINX configs" class="edit head-submenu">Configs</a></li>
<li><a href="/app/viewsttats.py?service=nginx" title="NGINX statistics" class="stats head-submenu">Stats</a></li>
<li><a href="/app/statsview.py?service=nginx" title="NGINX statistics" class="stats head-submenu">Stats</a></li>
<li><a href="/app/logs.py?service=nginx" title="NGINX logs " class="logs head-submenu">Logs</a></li>
<li><a href="/app/metrics.py?service=nginx" title="NGINX's metrics" class="metrics head-submenu">Metrics</a></li>
{% if role <= 3 %}
@ -104,7 +105,7 @@
<ul class="v_menu">
<li><a href="/app/hapservers.py?service=apache" title="Overview Apache servers" class="overview-link head-submenu">Overview</a></li>
<li><a href="/app/config.py?service=apache" title="Working with Apache configs" class="edit head-submenu">Configs</a></li>
<li><a href="/app/viewsttats.py?service=apache" title="Apache statistics" class="stats head-submenu">Stats</a></li>
<li><a href="/app/statsview.py?service=apache" title="Apache statistics" class="stats head-submenu">Stats</a></li>
<li><a href="/app/logs.py?service=apache" title="Apache logs " class="logs head-submenu">Logs</a></li>
<li><a href="/app/metrics.py?service=apache" title="Apache's metrics" class="metrics head-submenu">Metrics</a></li>
{% if role <= 3 %}

View File

@ -1,14 +1,27 @@
{% extends "base.html" %}
{% block content %}
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
<link rel="stylesheet" href="/inc/codemirror/dialog.css">
<script src="/inc/codemirror/codemirror.js"></script>
<script src="/inc/codemirror/nginx.js"></script>
<script src="/inc/codemirror/haproxy.js"></script>
<script src="/inc/codemirror/dialog.js"></script>
<script src="/inc/codemirror/search.js"></script>
<script src="/inc/codemirror/searchcursor.js"></script>
<script src="/inc/codemirror/jump-to-line.js"></script>
<link rel="stylesheet" href="/inc/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="/inc/codemirror/addon/dialog/dialog.css">
<link rel="stylesheet" href="/inc/codemirror/addon/fold/foldgutter.css">
<script src="/inc/codemirror/lib/codemirror.js"></script>
<script src="/inc/codemirror/addon/search/search.js"></script>
<script src="/inc/codemirror/addon/search/searchcursor.js"></script>
<script src="/inc/codemirror/addon/search/jump-to-line.js"></script>
<script src="/inc/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="/inc/codemirror/addon/search/match-highlighter.js"></script>
<script src="/inc/codemirror/addon/dialog/dialog.js"></script>
<script src="/inc/codemirror/addon/edit/matchbrackets.js"></script>
<script src="/inc/codemirror/addon/edit/closebrackets.js"></script>
<script src="/inc/codemirror/addon/comment/comment.js"></script>
<script src="/inc/codemirror/addon/wrap/hardwrap.js"></script>
<script src="/inc/codemirror/addon/fold/foldcode.js"></script>
<script src="/inc/codemirror/addon/fold/foldgutter.js"></script>
<script src="/inc/codemirror/addon/fold/brace-fold.js"></script>
<script src="/inc/codemirror/addon/fold/comment-fold.js"></script>
<script src="/inc/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="/inc/codemirror/mode/nginx.js"></script>
<script src="/inc/codemirror/mode/haproxy.js"></script>
<script src="/inc/codemirror/keymap/sublime.js"></script>
<script src="/inc/configshow.js"></script>
{% if is_serv_protected and role > 2 %}
<meta http-equiv="refresh" content="0; url=/app/hapservers.py?service={{service}}">
@ -65,7 +78,9 @@
<button type="submit" value="test" name="save" class="btn btn-default" title="Check config without saving the config">Check config</button>
{% endif %}
<button type="submit" value="save" name="save" class="btn btn-default" title="Save config without reloading the service">Save</button>
{% if is_restart|int == 0 %}
<button type="submit" value="" name="" class="btn btn-default">Save and restart</button>
{% endif %}
<button type="submit" value="reload" name="save" class="btn btn-default">Save and reload</button>
{% if service != 'keepalived' %}
<div class="alert alert-info alert-two-rows"><b>Note:</b> When reconfiguring the master server, the slave will be reconfigured automatically</div>
@ -102,10 +117,49 @@
}
if (cur_url[1].split('&')[0] == 'service=haproxy' || cur_url[1].split('&')[0] == 'service=None') {
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
{mode: "haproxy", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true, autoCloseBrackets: true});
{
mode: "haproxy",
lineNumbers: true,
lineWrapping: true,
autocapitalize: true,
autocorrect: true,
spellcheck: true,
autoCloseBrackets: true,
keyMap: "sublime",
matchBrackets: true,
foldGutter: true,
showCursorWhenSelecting: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "breakpoints"],
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: true}
});
} else {
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
{mode: "nginx", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true, autoCloseBrackets: true});
{
mode: "nginx",
lineNumbers: true,
lineWrapping: true,
autocapitalize: true,
autocorrect: true,
spellcheck: true,
autoCloseBrackets: true,
keyMap: "sublime",
matchBrackets: true,
foldGutter: true,
showCursorWhenSelecting: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "breakpoints"],
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: true}
});
}
myCodeMirror.on("gutterClick", function(cm, n) {
var info = cm.lineInfo(n);
cm.setGutterMarker(n, "breakpoints", info.gutterMarkers ? null : makeMarker());
});
function makeMarker() {
var marker = document.createElement("div");
marker.style.color = "#822";
marker.innerHTML = "●";
return marker;
}
</script>
<style>

View File

@ -23,7 +23,7 @@
{% include 'include/errors.html' %}
{% else %}
<div class="alert alert-success">Config is ok</div>
<a href="viewsttats.py?serv={{ serv }}" target="_blank" title="View stats">Go to view stats</a>
<a href="statsview.py?serv={{ serv }}" target="_blank" title="View stats">Go to view stats</a>
{% endif %}
{% endif %}
</center>

View File

@ -4,7 +4,7 @@
{% if selects|length == 0 %}
{% include 'include/getstarted.html' %}
{% else %}
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<center>
<p>

View File

@ -3,7 +3,7 @@
{% from 'include/input_macros.html' import input, checkbox %}
<script src="/inc/users.js"></script>
<script src="/inc/ha.js"></script>
<link href="/inc/provisioning.css" rel="stylesheet">
<link href="/inc/css/provisioning.css" rel="stylesheet">
<style>
p {margin: 0;}
</style>

View File

@ -2,7 +2,7 @@
{% block content %}
{% from 'include/input_macros.html' import input, checkbox, select, copy_to_clipboard %}
<script src="/inc/overview.js"></script>
<link href="/inc/chart.min.css" rel="stylesheet">
<link href="/inc/css/chart.min.css" rel="stylesheet">
<script src="/inc/metrics.js"></script>
<script src="/inc/chart.min.js"></script>
{% if servers|length == 0 %} {% include 'include/getstarted.html' %} {% endif %}
@ -171,7 +171,7 @@
{% if s.8.0.20 == 1 %}
<span class="lock" title="This server is inaccessible for editing by everyone except the admin role"></span>
{% endif %}
{% for set in service_settings %}
{% for set in docker_settings %}
{% if set.server_id == s.0 and set.setting == 'dockerized' and set.value == '1' %}
<span class="box" title="This server is dockerized"></span>
{% endif %}
@ -181,12 +181,23 @@
<a id="start-{{ s.2 }}" class="start" title="Start {{service}} service">
<span class="service-start" onclick="confirmAjaxAction('start', '{{action_service}}', '{{s.2}}')"></span>
</a>
{% if service != 'keepalived' %}
<a id="reload-{{ s.2 }}" class="reload" title="Reload {{service}} service">
<span class="service-reload" onclick="confirmAjaxAction('reload', '{{action_service}}', '{{s.2}}', '{{s.1}}')"></span>
</a>
<a id="restart-{{ s.2 }}" class="restart" title="Restart {{service}} service">
<span class="service-reload service-restart" onclick="confirmAjaxAction('restart', '{{action_service}}', '{{s.2}}')"></span>
</a>
{% endif %}
{% for set in restart_settings %}
{% if set.server_id == s.0 and set.setting == 'restart' and set.value|int == 0 %}
<a id="restart-{{ s.2 }}" class="restart" title="Restart {{service}} service">
<span class="service-reload service-restart" onclick="confirmAjaxAction('restart', '{{action_service}}', '{{s.2}}')"></span>
</a>
{% endif %}
{% endfor %}
{% if restart_settings|length == 0 %}
<a id="restart-{{ s.2 }}" class="restart" title="Restart {{service}} service">
<span class="service-reload service-restart" onclick="confirmAjaxAction('restart', '{{action_service}}', '{{s.2}}')"></span>
</a>
{% endif %}
<a id="stop-{{ s.2 }}" class="stop" title="Stop {{service}} service">
<span class="service-stop" onclick="confirmAjaxAction('stop', '{{action_service}}', '{{s.2}}')"></span>
</a>
@ -285,8 +296,8 @@
{% if service != 'nginx' and service != 'keepalived' and service != 'apache' %}
<a href="/app/config.py?serv={{s.2}}&showMap" class="ui-button ui-widget ui-corner-all" title="Show map">Map</a>
{% endif %}
{% if service != 'keepalived' and service != 'apache' %}
<a href="/app/viewsttats.py?service={{service}}&serv={{s.2}}" class="ui-button ui-widget ui-corner-all" title="View {{service}} statistics">Stat</a>
{% if service != 'keepalived' %}
<a href="/app/statsview.py?service={{service}}&serv={{s.2}}" class="ui-button ui-widget ui-corner-all" title="View {{service}} statistics">Stats</a>
{% endif %}
<a href="/app/logs.py?service={{service}}&serv={{s.2}}&rows=10&grep=&hour=00&minut=00&hour1=24&minut1=00" class="ui-button ui-widget ui-corner-all" title="View {{service}} logs">Logs</a>
{% if role <= 2 %}

View File

@ -4,7 +4,7 @@
{% if user_status == 0 or user_plan == 'user' %}
{% include 'include/no_sub.html' %}
{% else %}
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script>
$(document).ready(function() {

View File

@ -1,4 +1,4 @@
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script>
$(document).ready(function() {

View File

@ -20,7 +20,7 @@ body, .container {
font-weight: bold !important;
}
#main_div {
margin-top: 15%;
margin-top: 10%;
background-color: #239dee;
}
@supports (-moz-osx-font-smoothing: auto) {
@ -34,7 +34,7 @@ body, .container {
{{error}}
<div id="login-form" style="padding-top: 40px; padding-bottom: 50px; height: 250px; color: #000;">
<span id="logo_span">
<img src="/inc/images/logo_login.png" width="330">
<img src="/inc/images/logo_login.png">
</span>
<form name="auth" id="auth" action="login.py" class="form-horizontal" method="post" style="margin-top: 40px;left: 0;float: left;margin-left: 93px;">
<br>

View File

@ -13,7 +13,7 @@
padding: 10px;
}
</style>
<link href="/inc/chart.min.css" rel="stylesheet">
<link href="/inc/css/chart.min.css" rel="stylesheet">
<script src="/inc/metrics.js"></script>
<script src="/inc/chart.min.js"></script>
{% if user_status == 0 %}

View File

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block content %}
{% from 'include/input_macros.html' import input, select, checkbox %}
<link href="/inc/provisioning.css" rel="stylesheet">
<link href="/inc/css/provisioning.css" rel="stylesheet">
<script src="/inc/users.js"></script>
<script src="/inc/fontawesome.min.js"></script>
{% include 'include/del_confirm.html' %}

View File

@ -1,7 +1,7 @@
{% extends "base.html" %}
{% block content %}
{% from 'include/input_macros.html' import input, checkbox %}
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script type="text/javascript" charset="utf8" src="/inc/runtimeapi.js"></script>
<div id="tabs">
@ -74,7 +74,7 @@
</script>
<div id="ajaxruntime"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read the description of all Run Time API <a href="https://roxy-wi.org/description.py?description=runtimeapi#commands" title="Run Time API description" target="_blank">here</a>
You can read the description of all Run Time API <a href="https://roxy-wi.org/description/runtimeapi#commands" title="Run Time API description" target="_blank">here</a>
</div>
</div>
{% if role <= 3 %}
@ -111,7 +111,7 @@
</table>
<div id="ajaxmaxconn"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://roxy-wi.org/description.py?description=runtimeapi#maxconn" title="Change Maxconn" target="_blank">here</a>
You can read how it works <a href="https://roxy-wi.org/description/runtimeapi#maxconn" title="Change Maxconn" target="_blank">here</a>
</div>
</div>
@ -157,7 +157,7 @@
</table>
<div id="ajaxip"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://roxy-wi.org/description.py?description=runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
You can read how it works <a href="https://roxy-wi.org/description/runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
</div>
</div>
<div id="table">
@ -189,7 +189,7 @@
</table>
<div id="ajaxtable"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://roxy-wi.org/description.py?description=runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
You can read how it works <a href="https://roxy-wi.org/description/runtimeapi#ip" title="Change IP and Port" target="_blank">here</a>
</div>
</div>
<div id="lists">
@ -221,7 +221,7 @@
</table>
<div id="ajaxlist"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://roxy-wi.org/description.py?description=runtimeapi#lists" title="Manage lists" target="_blank">here</a>
You can read how it works <a href="https://roxy-wi.org/description.py/runtimeapi#lists" title="Manage lists" target="_blank">here</a>
</div>
</div>
<div id="sessions">
@ -248,7 +248,7 @@
</table>
<div id="ajaxsessions"></div>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px;">
You can read how it works <a href="https://roxy-wi.org/description.py?description=runtimeapi#lists" title="Manage lists" target="_blank">here</a>
You can read how it works <a href="https://roxy-wi.org/description/runtimeapi#lists" title="Manage lists" target="_blank">here</a>
</div>
</div>
{% endif %}
@ -271,4 +271,4 @@ $( function() {
}
});
</script>
{% endblock %}
{% endblock %}

View File

@ -3,10 +3,28 @@
{% if is_serv_protected and role > 2 %}
<meta http-equiv="refresh" content="0; url=/app/hapservers.py?service={{service}}">
{% else %}
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
<script src="/inc/codemirror/codemirror.js"></script>
<script src="/inc/codemirror/nginx.js"></script>
<script src="/inc/codemirror/haproxy.js"></script>
<link rel="stylesheet" href="/inc/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="/inc/codemirror/addon/dialog/dialog.css">
<link rel="stylesheet" href="/inc/codemirror/addon/fold/foldgutter.css">
<script src="/inc/codemirror/lib/codemirror.js"></script>
<script src="/inc/codemirror/addon/search/search.js"></script>
<script src="/inc/codemirror/addon/search/searchcursor.js"></script>
<script src="/inc/codemirror/addon/search/jump-to-line.js"></script>
<script src="/inc/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="/inc/codemirror/addon/search/match-highlighter.js"></script>
<script src="/inc/codemirror/addon/dialog/dialog.js"></script>
<script src="/inc/codemirror/addon/edit/matchbrackets.js"></script>
<script src="/inc/codemirror/addon/edit/closebrackets.js"></script>
<script src="/inc/codemirror/addon/comment/comment.js"></script>
<script src="/inc/codemirror/addon/wrap/hardwrap.js"></script>
<script src="/inc/codemirror/addon/fold/foldcode.js"></script>
<script src="/inc/codemirror/addon/fold/foldgutter.js"></script>
<script src="/inc/codemirror/addon/fold/brace-fold.js"></script>
<script src="/inc/codemirror/addon/fold/comment-fold.js"></script>
<script src="/inc/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="/inc/codemirror/mode/nginx.js"></script>
<script src="/inc/codemirror/mode/haproxy.js"></script>
<script src="/inc/codemirror/keymap/sublime.js"></script>
<center>
<p>
<form action="{{ action }}" method="post">
@ -20,7 +38,7 @@
{% endif %}
{% endfor %}
</select>
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ serv }}" name="serv">
{% if role <= 3 %}
<button type="submit" value="open" name="open" class="btn btn-default" title="Edit running config">Edit</button>
{% endif %}
@ -31,8 +49,8 @@
<div id="config">
<h4>You are editing "{{section}}" section from server {{ serv }}</h4>
<form action="{{ action }}" name="saveconfig" method="post">
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ start_line }}" name="start_line">
<input type="hidden" value="{{ serv }}" name="serv">
<input type="hidden" value="{{ start_line }}" name="start_line">
<input type="hidden" value="{{ end_line }}" name="end_line">
<input type="hidden" value="{{ cfg }}.old" name="oldconfig">
<div style="margin-left: 23%;width: 60%; text-align: left">
@ -74,7 +92,7 @@
<div class="alert alert-warning">{{warning}}</div>
{% endif %}
<a href="config.py?serv={{ serv }}" title="Working with HAProxy config">Config</a> |
<a href="viewsttats.py?serv={{ serv }}" target="_blank" title="View stats">Go to stats</a>
<a href="statsview.py?serv={{ serv }}" target="_blank" title="View stats">Go to stats</a>
{% endif %}
<script>window.history.pushState("Config", "Config", cur_url[0])</script>
{% endif %}

View File

@ -210,5 +210,5 @@
{% endfor %}
});
</script>
<link href="/inc/servers.css" rel="stylesheet"/>
<link href="/inc/css/servers.css" rel="stylesheet"/>
{% endblock %}

View File

@ -8,7 +8,7 @@
<style>
</style>
<form style="padding-left: 5px;" action="viewsttats.py" method="post">
<form style="padding-left: 5px;" action="statsview.py" method="post">
<input type="hidden" id="service" value="{{service}}" />
<select autofocus required name="serv" id="serv">
<option disabled>------</option>
@ -152,6 +152,6 @@
showStats();
});
</script>
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/css/style.css" rel="stylesheet">
{% endif %}
{% endblock %}

View File

@ -46,10 +46,29 @@
</div>
{% elif waf_rule_file %}
<center>
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
<link rel="stylesheet" href="/inc/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="/inc/codemirror/addon/dialog/dialog.css">
<link rel="stylesheet" href="/inc/codemirror/addon/fold/foldgutter.css">
<script src="/inc/codemirror/lib/codemirror.js"></script>
<script src="/inc/codemirror/addon/search/search.js"></script>
<script src="/inc/codemirror/addon/search/searchcursor.js"></script>
<script src="/inc/codemirror/addon/search/jump-to-line.js"></script>
<script src="/inc/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="/inc/codemirror/addon/search/match-highlighter.js"></script>
<script src="/inc/codemirror/addon/dialog/dialog.js"></script>
<script src="/inc/codemirror/addon/edit/matchbrackets.js"></script>
<script src="/inc/codemirror/addon/edit/closebrackets.js"></script>
<script src="/inc/codemirror/addon/comment/comment.js"></script>
<script src="/inc/codemirror/addon/wrap/hardwrap.js"></script>
<script src="/inc/codemirror/addon/fold/foldcode.js"></script>
<script src="/inc/codemirror/addon/fold/foldgutter.js"></script>
<script src="/inc/codemirror/addon/fold/brace-fold.js"></script>
<script src="/inc/codemirror/addon/fold/comment-fold.js"></script>
<script src="/inc/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="/inc/codemirror/mode/nginx.js"></script>
<script src="/inc/codemirror/mode/haproxy.js"></script>
<script src="/inc/codemirror/keymap/sublime.js"></script>
<script src="/inc/configshow.js"></script>
<script src="/inc/codemirror/codemirror.js"></script>
<script src="/inc/codemirror/modsec.js"></script>
<h4>Config {{waf_rule_file}} from {{ serv }}</h4>
</center>
<form action="waf.py" name="saveconfig" id="saveconfig" method="post">
@ -83,7 +102,21 @@
</style>
<script>
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("config_text_area"),
{mode: "modsec", lineNumbers: true, autocapitalize: true, autocorrect: true, spellcheck: true});
{
mode: "modsec",
lineNumbers: true,
lineWrapping: true,
autocapitalize: true,
autocorrect: true,
spellcheck: true,
autoCloseBrackets: true,
keyMap: "sublime",
matchBrackets: true,
foldGutter: true,
showCursorWhenSelecting: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "breakpoints"],
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: true}
});
myCodeMirror.refresh();
</script>
{% else %}
@ -187,8 +220,8 @@
});
</script>
<div class="add-note addName alert-info" style="width: inherit; margin-right: 15px; clear: both;">
Read the description and watch a video about WAF <a href="https://roxy-wi.org/description.py?description=waf" class="link" title="WAF" target="_blank">here</a>
Read the description and watch a video about WAF <a href="https://roxy-wi.org/description/waf" class="link" title="WAF" target="_blank">here</a>
</div>
{% endif %}
{% endif %}
{% endblock %}
{% endblock %}

View File

@ -12,10 +12,10 @@ funct.check_login()
funct.page_for_admin(level=3)
form = funct.form
serv = form.getvalue('serv')
serv = funct.is_ip_or_dns(form.getvalue('serv'))
service = funct.checkAjaxInput(form.getvalue('service'))
Select = form.getvalue('del')
configver = form.getvalue('configver')
service = form.getvalue('service')
conf_format = 'cfg'
configs_dir = ''
stderr = ""
@ -30,34 +30,23 @@ try:
except Exception:
pass
if service == 'keepalived':
if funct.check_login(service=3):
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
title = "Working with versions Keepalived configs"
if service in ('haproxy', 'nginx', 'keepalived', 'apache'):
service_desc = sql.select_service(service)
if funct.check_login(service=service_desc.service_id):
title = f"Working with versions {service_desc.service} configs"
servers = sql.get_dick_permit(service=service_desc.slug)
action = f'versions.py?service={service_desc.slug}'
conf_format = 'conf'
servers = sql.get_dick_permit(keepalived=1)
action = 'versions.py?service=keepalived'
elif service == 'nginx':
if funct.check_login(service=2):
configs_dir = funct.get_config_var('configs', 'nginx_save_configs_dir')
title = "Working with versions NGINX configs"
conf_format = 'conf'
servers = sql.get_dick_permit(nginx=1)
action = 'versions.py?service=nginx'
elif service == 'apache':
if funct.check_login(service=4):
configs_dir = funct.get_config_var('configs', 'apache_save_configs_dir')
title = "Working with versions Apache configs"
conf_format = 'conf'
servers = sql.get_dick_permit(apache=1)
action = 'versions.py?service=apache'
if service in ('haproxy', 'nginx', 'apache'):
configs_dir = funct.get_config_var('configs', f'{service_desc.service}_save_configs_dir')
else:
configs_dir = funct.get_config_var('configs', 'kp_save_configs_dir')
if service == 'haproxy':
conf_format = 'cfg'
else:
service = 'haproxy'
if funct.check_login(service=1):
title = "Working with versions HAProxy configs"
configs_dir = funct.get_config_var('configs', 'haproxy_save_configs_dir')
servers = sql.get_dick_permit(haproxy=1)
action = "versions.py"
print('<meta http-equiv="refresh" content="0; url=/app/overview.py">')
if serv is not None and form.getvalue('del') is not None:
if Select is not None:

211
inc/codemirror/addon/comment/comment.js vendored Normal file
View File

@ -0,0 +1,211 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var noOptions = {};
var nonWS = /[^\s\u00a0]/;
var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos;
function firstNonWS(str) {
var found = str.search(nonWS);
return found == -1 ? 0 : found;
}
CodeMirror.commands.toggleComment = function(cm) {
cm.toggleComment();
};
CodeMirror.defineExtension("toggleComment", function(options) {
if (!options) options = noOptions;
var cm = this;
var minLine = Infinity, ranges = this.listSelections(), mode = null;
for (var i = ranges.length - 1; i >= 0; i--) {
var from = ranges[i].from(), to = ranges[i].to();
if (from.line >= minLine) continue;
if (to.line >= minLine) to = Pos(minLine, 0);
minLine = from.line;
if (mode == null) {
if (cm.uncomment(from, to, options)) mode = "un";
else { cm.lineComment(from, to, options); mode = "line"; }
} else if (mode == "un") {
cm.uncomment(from, to, options);
} else {
cm.lineComment(from, to, options);
}
}
});
// Rough heuristic to try and detect lines that are part of multi-line string
function probablyInsideString(cm, pos, line) {
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line)
}
function getMode(cm, pos) {
var mode = cm.getMode()
return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
}
CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var firstLine = self.getLine(from.line);
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
var commentString = options.lineComment || mode.lineComment;
if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) {
options.fullLines = true;
self.blockComment(from, to, options);
}
return;
}
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line;
self.operation(function() {
if (options.indent) {
var baseString = null;
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i);
var whitespace = line.search(nonWS) === -1 ? line : line.slice(0, firstNonWS(line));
if (baseString == null || baseString.length > whitespace.length) {
baseString = whitespace;
}
}
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i), cut = baseString.length;
if (!blankLines && !nonWS.test(line)) continue;
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
}
} else {
for (var i = from.line; i < end; ++i) {
if (blankLines || nonWS.test(self.getLine(i)))
self.replaceRange(commentString + pad, Pos(i, 0));
}
}
});
});
CodeMirror.defineExtension("blockComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) {
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
self.lineComment(from, to, options);
return;
}
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
var end = Math.min(to.line, self.lastLine());
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
var pad = options.padding == null ? " " : options.padding;
if (from.line > end) return;
self.operation(function() {
if (options.fullLines != false) {
var lastLineHasText = nonWS.test(self.getLine(end));
self.replaceRange(pad + endString, Pos(end));
self.replaceRange(startString + pad, Pos(from.line, 0));
var lead = options.blockCommentLead || mode.blockCommentLead;
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
if (i != end || lastLineHasText)
self.replaceRange(lead + pad, Pos(i, 0));
} else {
var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected()
self.replaceRange(endString, to);
if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to)
self.replaceRange(startString, from);
}
});
});
CodeMirror.defineExtension("uncomment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
// Try finding line comments
var lineString = options.lineComment || mode.lineComment, lines = [];
var pad = options.padding == null ? " " : options.padding, didSomething;
lineComment: {
if (!lineString) break lineComment;
for (var i = start; i <= end; ++i) {
var line = self.getLine(i);
var found = line.indexOf(lineString);
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
if (found == -1 && nonWS.test(line)) break lineComment;
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
lines.push(line);
}
self.operation(function() {
for (var i = start; i <= end; ++i) {
var line = lines[i - start];
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
if (pos < 0) continue;
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
didSomething = true;
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
}
});
if (didSomething) return true;
}
// Try block comments
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) return false;
var lead = options.blockCommentLead || mode.blockCommentLead;
var startLine = self.getLine(start), open = startLine.indexOf(startString)
if (open == -1) return false
var endLine = end == start ? startLine : self.getLine(end)
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1)
if (close == -1 ||
!/comment/.test(self.getTokenTypeAt(insideStart)) ||
!/comment/.test(self.getTokenTypeAt(insideEnd)) ||
self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1)
return false;
// Avoid killing block comments completely outside the selection.
// Positions of the last startString before the start of the selection, and the first endString after it.
var lastStart = startLine.lastIndexOf(startString, from.ch);
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
// Positions of the first endString after the end of the selection, and the last startString before it.
firstEnd = endLine.indexOf(endString, to.ch);
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
self.operation(function() {
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
Pos(end, close + endString.length));
var openEnd = open + startString.length;
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
if (lead) for (var i = start + 1; i <= end; ++i) {
var line = self.getLine(i), found = line.indexOf(lead);
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
var foundEnd = found + lead.length;
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
}
});
return true;
});
});

View File

@ -0,0 +1,201 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
var defaults = {
pairs: "()[]{}''\"\"",
closeBefore: ")]}'\":;>",
triples: "",
explode: "[]{}"
};
var Pos = CodeMirror.Pos;
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.removeKeyMap(keyMap);
cm.state.closeBrackets = null;
}
if (val) {
ensureBound(getOption(val, "pairs"))
cm.state.closeBrackets = val;
cm.addKeyMap(keyMap);
}
});
function getOption(conf, name) {
if (name == "pairs" && typeof conf == "string") return conf;
if (typeof conf == "object" && conf[name] != null) return conf[name];
return defaults[name];
}
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
function ensureBound(chars) {
for (var i = 0; i < chars.length; i++) {
var ch = chars.charAt(i), key = "'" + ch + "'"
if (!keyMap[key]) keyMap[key] = handler(ch)
}
}
ensureBound(defaults.pairs + "`")
function handler(ch) {
return function(cm) { return handleChar(cm, ch); };
}
function getConfig(cm) {
var deflt = cm.state.closeBrackets;
if (!deflt || deflt.override) return deflt;
var mode = cm.getModeAt(cm.getCursor());
return mode.closeBrackets || deflt;
}
function handleBackspace(cm) {
var conf = getConfig(cm);
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
var pairs = getOption(conf, "pairs");
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass;
var around = charsAround(cm, ranges[i].head);
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
}
for (var i = ranges.length - 1; i >= 0; i--) {
var cur = ranges[i].head;
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
}
}
function handleEnter(cm) {
var conf = getConfig(cm);
var explode = conf && getOption(conf, "explode");
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) return CodeMirror.Pass;
var around = charsAround(cm, ranges[i].head);
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
}
cm.operation(function() {
var linesep = cm.lineSeparator() || "\n";
cm.replaceSelection(linesep + linesep, null);
moveSel(cm, -1)
ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var line = ranges[i].head.line;
cm.indentLine(line, null, true);
cm.indentLine(line + 1, null, true);
}
});
}
function moveSel(cm, dir) {
var newRanges = [], ranges = cm.listSelections(), primary = 0
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i]
if (range.head == cm.getCursor()) primary = i
var pos = range.head.ch || dir > 0 ? {line: range.head.line, ch: range.head.ch + dir} : {line: range.head.line - 1}
newRanges.push({anchor: pos, head: pos})
}
cm.setSelections(newRanges, primary)
}
function contractSelection(sel) {
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
}
function handleChar(cm, ch) {
var conf = getConfig(cm);
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
var pairs = getOption(conf, "pairs");
var pos = pairs.indexOf(ch);
if (pos == -1) return CodeMirror.Pass;
var closeBefore = getOption(conf,"closeBefore");
var triples = getOption(conf, "triples");
var identical = pairs.charAt(pos + 1) == ch;
var ranges = cm.listSelections();
var opening = pos % 2 == 0;
var type;
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], cur = range.head, curType;
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
if (opening && !range.empty()) {
curType = "surround";
} else if ((identical || !opening) && next == ch) {
if (identical && stringStartsAfter(cm, cur))
curType = "both";
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
curType = "skipThree";
else
curType = "skip";
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) {
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass;
curType = "addFour";
} else if (identical) {
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur)
if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both";
else return CodeMirror.Pass;
} else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) {
curType = "both";
} else {
return CodeMirror.Pass;
}
if (!type) type = curType;
else if (type != curType) return CodeMirror.Pass;
}
var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
var right = pos % 2 ? ch : pairs.charAt(pos + 1);
cm.operation(function() {
if (type == "skip") {
moveSel(cm, 1)
} else if (type == "skipThree") {
moveSel(cm, 3)
} else if (type == "surround") {
var sels = cm.getSelections();
for (var i = 0; i < sels.length; i++)
sels[i] = left + sels[i] + right;
cm.replaceSelections(sels, "around");
sels = cm.listSelections().slice();
for (var i = 0; i < sels.length; i++)
sels[i] = contractSelection(sels[i]);
cm.setSelections(sels);
} else if (type == "both") {
cm.replaceSelection(left + right, null);
cm.triggerElectric(left + right);
moveSel(cm, -1)
} else if (type == "addFour") {
cm.replaceSelection(left + left + left + left, "before");
moveSel(cm, 1)
}
});
}
function charsAround(cm, pos) {
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
Pos(pos.line, pos.ch + 1));
return str.length == 2 ? str : null;
}
function stringStartsAfter(cm, pos) {
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
return /\bstring/.test(token.type) && token.start == pos.ch &&
(pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos)))
}
});

View File

@ -0,0 +1,160 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
(document.documentMode == null || document.documentMode < 8);
var Pos = CodeMirror.Pos;
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"};
function bracketRegex(config) {
return config && config.bracketRegex || /[(){}[\]]/
}
function findMatchingBracket(cm, where, config) {
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
var afterCursor = config && config.afterCursor
if (afterCursor == null)
afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className)
var re = bracketRegex(config)
// A cursor is defined as between two characters, but in in vim command mode
// (i.e. not insert mode), the cursor is visually represented as a
// highlighted box on top of the 2nd character. Otherwise, we allow matches
// from before or after the cursor.
var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) ||
re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)];
if (!match) return null;
var dir = match.charAt(1) == ">" ? 1 : -1;
if (config && config.strict && (dir > 0) != (pos == where.ch)) return null;
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style, config);
if (found == null) return null;
return {from: Pos(where.line, pos), to: found && found.pos,
match: found && found.ch == match.charAt(0), forward: dir > 0};
}
// bracketRegex is used to specify which type of bracket to scan
// should be a regexp, e.g. /[[\]]/
//
// Note: If "where" is on an open bracket, then this bracket is ignored.
//
// Returns false when no bracket was found, null when it reached
// maxScanLines and gave up
function scanForBracket(cm, where, dir, style, config) {
var maxScanLen = (config && config.maxScanLineLength) || 10000;
var maxScanLines = (config && config.maxScanLines) || 1000;
var stack = [];
var re = bracketRegex(config)
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
var line = cm.getLine(lineNo);
if (!line) continue;
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
if (line.length > maxScanLen) continue;
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
for (; pos != end; pos += dir) {
var ch = line.charAt(pos);
if (re.test(ch) && (style === undefined ||
(cm.getTokenTypeAt(Pos(lineNo, pos + 1)) || "") == (style || ""))) {
var match = matching[ch];
if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
else stack.pop();
}
}
}
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
}
function matchBrackets(cm, autoclear, config) {
// Disable brace matching in long lines, since it'll cause hugely slow updates
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000,
highlightNonMatching = config && config.highlightNonMatching;
var marks = [], ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++) {
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config);
if (match && (match.match || highlightNonMatching !== false) && cm.getLine(match.from.line).length <= maxHighlightLen) {
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
}
}
if (marks.length) {
// Kludge to work around the IE bug from issue #1193, where text
// input stops going to the textarea whenever this fires.
if (ie_lt8 && cm.state.focused) cm.focus();
var clear = function() {
cm.operation(function() {
for (var i = 0; i < marks.length; i++) marks[i].clear();
});
};
if (autoclear) setTimeout(clear, 800);
else return clear;
}
}
function doMatchBrackets(cm) {
cm.operation(function() {
if (cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
});
}
function clearHighlighted(cm) {
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) {
cm.state.matchBrackets.currentlyHighlighted();
cm.state.matchBrackets.currentlyHighlighted = null;
}
}
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.off("cursorActivity", doMatchBrackets);
cm.off("focus", doMatchBrackets)
cm.off("blur", clearHighlighted)
clearHighlighted(cm);
}
if (val) {
cm.state.matchBrackets = typeof val == "object" ? val : {};
cm.on("cursorActivity", doMatchBrackets);
cm.on("focus", doMatchBrackets)
cm.on("blur", clearHighlighted)
}
});
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){
// Backwards-compatibility kludge
if (oldConfig || typeof config == "boolean") {
if (!oldConfig) {
config = config ? {strict: true} : null
} else {
oldConfig.strict = config
config = oldConfig
}
}
return findMatchingBracket(this, pos, config)
});
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
return scanForBracket(this, pos, dir, style, config);
});
});

119
inc/codemirror/addon/fold/brace-fold.js vendored Normal file
View File

@ -0,0 +1,119 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function bracketFolding(pairs) {
return function(cm, start) {
var line = start.line, lineText = cm.getLine(line);
function findOpening(pair) {
var tokenType;
for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(pair[0], at - 1);
if (found == -1) {
if (pass == 1) break;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) break;
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
if (!/^(comment|string)/.test(tokenType)) return {ch: found + 1, tokenType: tokenType, pair: pair};
at = found - 1;
}
}
function findRange(found) {
var count = 1, lastLine = cm.lastLine(), end, startCh = found.ch, endCh
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(found.pair[0], pos), nextClose = text.indexOf(found.pair[1], pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == found.tokenType) {
if (pos == nextOpen) ++count;
else if (!--count) { end = i; endCh = pos; break outer; }
}
++pos;
}
}
if (end == null || line == end) return null
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
}
var found = []
for (var i = 0; i < pairs.length; i++) {
var open = findOpening(pairs[i])
if (open) found.push(open)
}
found.sort(function(a, b) { return a.ch - b.ch })
for (var i = 0; i < found.length; i++) {
var range = findRange(found[i])
if (range) return range
}
return null
}
}
CodeMirror.registerHelper("fold", "brace", bracketFolding([["{", "}"], ["[", "]"]]));
CodeMirror.registerHelper("fold", "brace-paren", bracketFolding([["{", "}"], ["[", "]"], ["(", ")"]]));
CodeMirror.registerHelper("fold", "import", function(cm, start) {
function hasImport(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type != "keyword" || start.string != "import") return null;
// Now find closing semicolon, return its position
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
var text = cm.getLine(i), semi = text.indexOf(";");
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
}
}
var startLine = start.line, has = hasImport(startLine), prev;
if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
return null;
for (var end = has.end;;) {
var next = hasImport(end.line + 1);
if (next == null) break;
end = next.end;
}
return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
});
CodeMirror.registerHelper("fold", "include", function(cm, start) {
function hasInclude(line) {
if (line < cm.firstLine() || line > cm.lastLine()) return null;
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
}
var startLine = start.line, has = hasInclude(startLine);
if (has == null || hasInclude(startLine - 1) != null) return null;
for (var end = startLine;;) {
var next = hasInclude(end + 1);
if (next == null) break;
++end;
}
return {from: CodeMirror.Pos(startLine, has + 1),
to: cm.clipPos(CodeMirror.Pos(end))};
});
});

View File

@ -0,0 +1,59 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
return mode.blockCommentStart && mode.blockCommentEnd;
}, function(cm, start) {
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
if (!startToken || !endToken) return;
var line = start.line, lineText = cm.getLine(line);
var startCh;
for (var at = start.ch, pass = 0;;) {
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
if (found == -1) {
if (pass == 1) return;
pass = 1;
at = lineText.length;
continue;
}
if (pass == 1 && found < start.ch) return;
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
(found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
startCh = found + startToken.length;
break;
}
at = found - 1;
}
var depth = 1, lastLine = cm.lastLine(), end, endCh;
outer: for (var i = line; i <= lastLine; ++i) {
var text = cm.getLine(i), pos = i == line ? startCh : 0;
for (;;) {
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
if (nextOpen < 0) nextOpen = text.length;
if (nextClose < 0) nextClose = text.length;
pos = Math.min(nextOpen, nextClose);
if (pos == text.length) break;
if (pos == nextOpen) ++depth;
else if (!--depth) { end = i; endCh = pos; break outer; }
++pos;
}
}
if (end == null || line == end && endCh == startCh) return;
return {from: CodeMirror.Pos(line, startCh),
to: CodeMirror.Pos(end, endCh)};
});
});

159
inc/codemirror/addon/fold/foldcode.js vendored Normal file
View File

@ -0,0 +1,159 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
function doFold(cm, pos, options, force) {
if (options && options.call) {
var finder = options;
options = null;
} else {
var finder = getOption(cm, options, "rangeFinder");
}
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
var minSize = getOption(cm, options, "minFoldSize");
function getRange(allowFolded) {
var range = finder(cm, pos);
if (!range || range.to.line - range.from.line < minSize) return null;
if (force === "fold") return range;
var marks = cm.findMarksAt(range.from);
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
if (!allowFolded) return null;
range.cleared = true;
marks[i].clear();
}
}
return range;
}
var range = getRange(true);
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
pos = CodeMirror.Pos(pos.line - 1, 0);
range = getRange(false);
}
if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(cm, options, range);
CodeMirror.on(myWidget, "mousedown", function(e) {
myRange.clear();
CodeMirror.e_preventDefault(e);
});
var myRange = cm.markText(range.from, range.to, {
replacedWith: myWidget,
clearOnEnter: getOption(cm, options, "clearOnEnter"),
__isFold: true
});
myRange.on("clear", function(from, to) {
CodeMirror.signal(cm, "unfold", cm, from, to);
});
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
}
function makeWidget(cm, options, range) {
var widget = getOption(cm, options, "widget");
if (typeof widget == "function") {
widget = widget(range.from, range.to);
}
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");
widget.appendChild(text);
widget.className = "CodeMirror-foldmarker";
} else if (widget) {
widget = widget.cloneNode(true)
}
return widget;
}
// Clumsy backwards-compatible interface
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
};
// New-style interface
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
doFold(this, pos, options, force);
});
CodeMirror.defineExtension("isFolded", function(pos) {
var marks = this.findMarksAt(pos);
for (var i = 0; i < marks.length; ++i)
if (marks[i].__isFold) return true;
});
CodeMirror.commands.toggleFold = function(cm) {
cm.foldCode(cm.getCursor());
};
CodeMirror.commands.fold = function(cm) {
cm.foldCode(cm.getCursor(), null, "fold");
};
CodeMirror.commands.unfold = function(cm) {
cm.foldCode(cm.getCursor(), { scanUp: false }, "unfold");
};
CodeMirror.commands.foldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "fold");
});
};
CodeMirror.commands.unfoldAll = function(cm) {
cm.operation(function() {
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "unfold");
});
};
CodeMirror.registerHelper("fold", "combine", function() {
var funcs = Array.prototype.slice.call(arguments, 0);
return function(cm, start) {
for (var i = 0; i < funcs.length; ++i) {
var found = funcs[i](cm, start);
if (found) return found;
}
};
});
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
var helpers = cm.getHelpers(start, "fold");
for (var i = 0; i < helpers.length; i++) {
var cur = helpers[i](cm, start);
if (cur) return cur;
}
});
var defaultOptions = {
rangeFinder: CodeMirror.fold.auto,
widget: "\u2194",
minFoldSize: 0,
scanUp: false,
clearOnEnter: true
};
CodeMirror.defineOption("foldOptions", null);
function getOption(cm, options, name) {
if (options && options[name] !== undefined)
return options[name];
var editorOptions = cm.options.foldOptions;
if (editorOptions && editorOptions[name] !== undefined)
return editorOptions[name];
return defaultOptions[name];
}
CodeMirror.defineExtension("foldOption", function(options, name) {
return getOption(this, options, name);
});
});

View File

@ -0,0 +1,20 @@
.CodeMirror-foldmarker {
color: blue;
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
font-family: arial;
line-height: .3;
cursor: pointer;
}
.CodeMirror-foldgutter {
width: .7em;
}
.CodeMirror-foldgutter-open,
.CodeMirror-foldgutter-folded {
cursor: pointer;
}
.CodeMirror-foldgutter-open:after {
content: "\25BE";
}
.CodeMirror-foldgutter-folded:after {
content: "\25B8";
}

169
inc/codemirror/addon/fold/foldgutter.js vendored Normal file
View File

@ -0,0 +1,169 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./foldcode"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./foldcode"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
cm.clearGutter(cm.state.foldGutter.options.gutter);
cm.state.foldGutter = null;
cm.off("gutterClick", onGutterClick);
cm.off("changes", onChange);
cm.off("viewportChange", onViewportChange);
cm.off("fold", onFold);
cm.off("unfold", onFold);
cm.off("swapDoc", onChange);
cm.off("optionChange", optionChange);
}
if (val) {
cm.state.foldGutter = new State(parseOptions(val));
updateInViewport(cm);
cm.on("gutterClick", onGutterClick);
cm.on("changes", onChange);
cm.on("viewportChange", onViewportChange);
cm.on("fold", onFold);
cm.on("unfold", onFold);
cm.on("swapDoc", onChange);
cm.on("optionChange", optionChange);
}
});
var Pos = CodeMirror.Pos;
function State(options) {
this.options = options;
this.from = this.to = 0;
}
function parseOptions(opts) {
if (opts === true) opts = {};
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
return opts;
}
function isFolded(cm, line) {
var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
for (var i = 0; i < marks.length; ++i) {
if (marks[i].__isFold) {
var fromPos = marks[i].find(-1);
if (fromPos && fromPos.line === line)
return marks[i];
}
}
}
function marker(spec) {
if (typeof spec == "string") {
var elt = document.createElement("div");
elt.className = spec + " CodeMirror-guttermarker-subtle";
return elt;
} else {
return spec.cloneNode(true);
}
}
function updateFoldInfo(cm, from, to) {
var opts = cm.state.foldGutter.options, cur = from - 1;
var minSize = cm.foldOption(opts, "minFoldSize");
var func = cm.foldOption(opts, "rangeFinder");
// we can reuse the built-in indicator element if its className matches the new state
var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
cm.eachLine(from, to, function(line) {
++cur;
var mark = null;
var old = line.gutterMarkers;
if (old) old = old[opts.gutter];
if (isFolded(cm, cur)) {
if (clsFolded && old && clsFolded.test(old.className)) return;
mark = marker(opts.indicatorFolded);
} else {
var pos = Pos(cur, 0);
var range = func && func(cm, pos);
if (range && range.to.line - range.from.line >= minSize) {
if (clsOpen && old && clsOpen.test(old.className)) return;
mark = marker(opts.indicatorOpen);
}
}
if (!mark && !old) return;
cm.setGutterMarker(line, opts.gutter, mark);
});
}
// copied from CodeMirror/src/util/dom.js
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
function updateInViewport(cm) {
var vp = cm.getViewport(), state = cm.state.foldGutter;
if (!state) return;
cm.operation(function() {
updateFoldInfo(cm, vp.from, vp.to);
});
state.from = vp.from; state.to = vp.to;
}
function onGutterClick(cm, line, gutter) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
if (gutter != opts.gutter) return;
var folded = isFolded(cm, line);
if (folded) folded.clear();
else cm.foldCode(Pos(line, 0), opts);
}
function optionChange(cm, option) {
if (option == "mode") onChange(cm)
}
function onChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
state.from = state.to = 0;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
}
function onViewportChange(cm) {
var state = cm.state.foldGutter;
if (!state) return;
var opts = state.options;
clearTimeout(state.changeUpdate);
state.changeUpdate = setTimeout(function() {
var vp = cm.getViewport();
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
updateInViewport(cm);
} else {
cm.operation(function() {
if (vp.from < state.from) {
updateFoldInfo(cm, vp.from, state.from);
state.from = vp.from;
}
if (vp.to > state.to) {
updateFoldInfo(cm, state.to, vp.to);
state.to = vp.to;
}
});
}
}, opts.updateViewportTimeSpan || 400);
}
function onFold(cm, from) {
var state = cm.state.foldGutter;
if (!state) return;
var line = from.line;
if (line >= state.from && line < state.to)
updateFoldInfo(cm, line, line + 1);
}
});

160
inc/codemirror/addon/fold/hardwrap.js vendored Normal file
View File

@ -0,0 +1,160 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var Pos = CodeMirror.Pos;
function findParagraph(cm, pos, options) {
var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
var line = cm.getLine(start);
if (startRE && startRE.test(line)) break;
if (!/\S/.test(line)) { ++start; break; }
}
var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
var line = cm.getLine(end);
if (endRE && endRE.test(line)) { ++end; break; }
if (!/\S/.test(line)) break;
}
return {from: start, to: end};
}
function findBreakPoint(text, column, wrapOn, killTrailingSpace, forceBreak) {
var at = column
while (at < text.length && text.charAt(at) == " ") at++
for (; at > 0; --at)
if (wrapOn.test(text.slice(at - 1, at + 1))) break;
if (!forceBreak && at <= text.match(/^[ \t]*/)[0].length) {
// didn't find a break point before column, in non-forceBreak mode try to
// find one after 'column'.
for (at = column + 1; at < text.length - 1; ++at) {
if (wrapOn.test(text.slice(at - 1, at + 1))) break;
}
}
for (var first = true;; first = false) {
var endOfText = at;
if (killTrailingSpace)
while (text.charAt(endOfText - 1) == " ") --endOfText;
if (endOfText == 0 && first) at = column;
else return {from: endOfText, to: at};
}
}
function wrapRange(cm, from, to, options) {
from = cm.clipPos(from); to = cm.clipPos(to);
var column = options.column || 80;
var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
var forceBreak = options.forceBreak !== false;
var killTrailing = options.killTrailingSpace !== false;
var changes = [], curLine = "", curNo = from.line;
var lines = cm.getRange(from, to, false);
if (!lines.length) return null;
var leadingSpace = lines[0].match(/^[ \t]*/)[0];
if (leadingSpace.length >= column) column = leadingSpace.length + 1
for (var i = 0; i < lines.length; ++i) {
var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
curLine += " ";
spaceInserted = 1;
}
var spaceTrimmed = "";
if (i) {
spaceTrimmed = text.match(/^\s*/)[0];
text = text.slice(spaceTrimmed.length);
}
curLine += text;
if (i) {
var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
findBreakPoint(curLine, column, wrapOn, killTrailing, forceBreak);
// If this isn't broken, or is broken at a different point, remove old break
if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
changes.push({text: [spaceInserted ? " " : ""],
from: Pos(curNo, oldLen),
to: Pos(curNo + 1, spaceTrimmed.length)});
} else {
curLine = leadingSpace + text;
++curNo;
}
}
while (curLine.length > column) {
var bp = findBreakPoint(curLine, column, wrapOn, killTrailing, forceBreak);
if (bp.from != bp.to ||
forceBreak && leadingSpace !== curLine.slice(0, bp.to)) {
changes.push({text: ["", leadingSpace],
from: Pos(curNo, bp.from),
to: Pos(curNo, bp.to)});
curLine = leadingSpace + curLine.slice(bp.to);
++curNo;
} else {
break;
}
}
}
if (changes.length) cm.operation(function() {
for (var i = 0; i < changes.length; ++i) {
var change = changes[i];
if (change.text || CodeMirror.cmpPos(change.from, change.to))
cm.replaceRange(change.text, change.from, change.to);
}
});
return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;
}
CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
options = options || {};
if (!pos) pos = this.getCursor();
var para = findParagraph(this, pos, options);
return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
});
CodeMirror.commands.wrapLines = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections(), at = cm.lastLine() + 1;
for (var i = ranges.length - 1; i >= 0; i--) {
var range = ranges[i], span;
if (range.empty()) {
var para = findParagraph(cm, range.head, {});
span = {from: Pos(para.from, 0), to: Pos(para.to - 1)};
} else {
span = {from: range.from(), to: range.to()};
}
if (span.to.line >= at) continue;
at = span.from.line;
wrapRange(cm, span.from, span.to, {});
}
});
};
CodeMirror.defineExtension("wrapRange", function(from, to, options) {
return wrapRange(this, from, to, options || {});
});
CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
options = options || {};
var cm = this, paras = [];
for (var line = from.line; line <= to.line;) {
var para = findParagraph(cm, Pos(line, 0), options);
paras.push(para);
line = para.to;
}
var madeChange = false;
if (paras.length) cm.operation(function() {
for (var i = paras.length - 1; i >= 0; --i)
madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
});
return madeChange;
});
});

View File

@ -0,0 +1,128 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineExtension("annotateScrollbar", function(options) {
if (typeof options == "string") options = {className: options};
return new Annotation(this, options);
});
CodeMirror.defineOption("scrollButtonHeight", 0);
function Annotation(cm, options) {
this.cm = cm;
this.options = options;
this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight");
this.annotations = [];
this.doRedraw = this.doUpdate = null;
this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
this.computeScale();
function scheduleRedraw(delay) {
clearTimeout(self.doRedraw);
self.doRedraw = setTimeout(function() { self.redraw(); }, delay);
}
var self = this;
cm.on("refresh", this.resizeHandler = function() {
clearTimeout(self.doUpdate);
self.doUpdate = setTimeout(function() {
if (self.computeScale()) scheduleRedraw(20);
}, 100);
});
cm.on("markerAdded", this.resizeHandler);
cm.on("markerCleared", this.resizeHandler);
if (options.listenForChanges !== false)
cm.on("changes", this.changeHandler = function() {
scheduleRedraw(250);
});
}
Annotation.prototype.computeScale = function() {
var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) /
cm.getScrollerElement().scrollHeight
if (hScale != this.hScale) {
this.hScale = hScale;
return true;
}
};
Annotation.prototype.update = function(annotations) {
this.annotations = annotations;
this.redraw();
};
Annotation.prototype.redraw = function(compute) {
if (compute !== false) this.computeScale();
var cm = this.cm, hScale = this.hScale;
var frag = document.createDocumentFragment(), anns = this.annotations;
var wrapping = cm.getOption("lineWrapping");
var singleLineH = wrapping && cm.defaultTextHeight() * 1.5;
var curLine = null, curLineObj = null;
function getY(pos, top) {
if (curLine != pos.line) {
curLine = pos.line
curLineObj = cm.getLineHandle(pos.line)
var visual = cm.getLineHandleVisualStart(curLineObj)
if (visual != curLineObj) {
curLine = cm.getLineNumber(visual)
curLineObj = visual
}
}
if ((curLineObj.widgets && curLineObj.widgets.length) ||
(wrapping && curLineObj.height > singleLineH))
return cm.charCoords(pos, "local")[top ? "top" : "bottom"];
var topY = cm.heightAtLine(curLineObj, "local");
return topY + (top ? 0 : curLineObj.height);
}
var lastLine = cm.lastLine()
if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i];
if (ann.to.line > lastLine) continue;
var top = nextTop || getY(ann.from, true) * hScale;
var bottom = getY(ann.to, false) * hScale;
while (i < anns.length - 1) {
if (anns[i + 1].to.line > lastLine) break;
nextTop = getY(anns[i + 1].from, true) * hScale;
if (nextTop > bottom + .9) break;
ann = anns[++i];
bottom = getY(ann.to, false) * hScale;
}
if (bottom == top) continue;
var height = Math.max(bottom - top, 3);
var elt = frag.appendChild(document.createElement("div"));
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: "
+ (top + this.buttonHeight) + "px; height: " + height + "px";
elt.className = this.options.className;
if (ann.id) {
elt.setAttribute("annotation-id", ann.id);
}
}
this.div.textContent = "";
this.div.appendChild(frag);
};
Annotation.prototype.clear = function() {
this.cm.off("refresh", this.resizeHandler);
this.cm.off("markerAdded", this.resizeHandler);
this.cm.off("markerCleared", this.resizeHandler);
if (this.changeHandler) this.cm.off("changes", this.changeHandler);
this.div.parentNode.removeChild(this.div);
};
});

View File

@ -0,0 +1,167 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// Highlighting text that matches the selection
//
// Defines an option highlightSelectionMatches, which, when enabled,
// will style strings that match the selection throughout the
// document.
//
// The option can be set to true to simply enable it, or to a
// {minChars, style, wordsOnly, showToken, delay} object to explicitly
// configure it. minChars is the minimum amount of characters that should be
// selected for the behavior to occur, and style is the token style to
// apply to the matches. This will be prefixed by "cm-" to create an
// actual CSS class name. If wordsOnly is enabled, the matches will be
// highlighted only if the selected text is a word. showToken, when enabled,
// will cause the current token to be highlighted when nothing is selected.
// delay is used to specify how much time to wait, in milliseconds, before
// highlighting the matches. If annotateScrollbar is enabled, the occurrences
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var defaults = {
style: "matchhighlight",
minChars: 2,
delay: 100,
wordsOnly: false,
annotateScrollbar: false,
showToken: false,
trim: true
}
function State(options) {
this.options = {}
for (var name in defaults)
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
this.overlay = this.timeout = null;
this.matchesonscroll = null;
this.active = false;
}
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
if (old && old != CodeMirror.Init) {
removeOverlay(cm);
clearTimeout(cm.state.matchHighlighter.timeout);
cm.state.matchHighlighter = null;
cm.off("cursorActivity", cursorActivity);
cm.off("focus", onFocus)
}
if (val) {
var state = cm.state.matchHighlighter = new State(val);
if (cm.hasFocus()) {
state.active = true
highlightMatches(cm)
} else {
cm.on("focus", onFocus)
}
cm.on("cursorActivity", cursorActivity);
}
});
function cursorActivity(cm) {
var state = cm.state.matchHighlighter;
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
}
function onFocus(cm) {
var state = cm.state.matchHighlighter
if (!state.active) {
state.active = true
scheduleHighlight(cm, state)
}
}
function scheduleHighlight(cm, state) {
clearTimeout(state.timeout);
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
}
function addOverlay(cm, query, hasBoundary, style) {
var state = cm.state.matchHighlighter;
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
var searchFor = hasBoundary ? new RegExp((/\w/.test(query.charAt(0)) ? "\\b" : "") +
query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") +
(/\w/.test(query.charAt(query.length - 1)) ? "\\b" : "")) : query;
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
{className: "CodeMirror-selection-highlight-scrollbar"});
}
}
function removeOverlay(cm) {
var state = cm.state.matchHighlighter;
if (state.overlay) {
cm.removeOverlay(state.overlay);
state.overlay = null;
if (state.matchesonscroll) {
state.matchesonscroll.clear();
state.matchesonscroll = null;
}
}
}
function highlightMatches(cm) {
cm.operation(function() {
var state = cm.state.matchHighlighter;
removeOverlay(cm);
if (!cm.somethingSelected() && state.options.showToken) {
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
while (start && re.test(line.charAt(start - 1))) --start;
while (end < line.length && re.test(line.charAt(end))) ++end;
if (start < end)
addOverlay(cm, line.slice(start, end), re, state.options.style);
return;
}
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (from.line != to.line) return;
if (state.options.wordsOnly && !isWord(cm, from, to)) return;
var selection = cm.getRange(from, to)
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
if (selection.length >= state.options.minChars)
addOverlay(cm, selection, false, state.options.style);
});
}
function isWord(cm, from, to) {
var str = cm.getRange(from, to);
if (str.match(/^\w+$/) !== null) {
if (from.ch > 0) {
var pos = {line: from.line, ch: from.ch - 1};
var chr = cm.getRange(pos, from);
if (chr.match(/\W/) === null) return false;
}
if (to.ch < cm.getLine(from.line).length) {
var pos = {line: to.line, ch: to.ch + 1};
var chr = cm.getRange(to, pos);
if (chr.match(/\W/) === null) return false;
}
return true;
} else return false;
}
function boundariesAround(stream, re) {
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
}
function makeOverlay(query, hasBoundary, style) {
return {token: function(stream) {
if (stream.match(query) &&
(!hasBoundary || boundariesAround(stream, hasBoundary)))
return style;
stream.next();
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
}};
}
});

View File

@ -0,0 +1,97 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
if (typeof options == "string") options = {className: options};
if (!options) options = {};
return new SearchAnnotation(this, query, caseFold, options);
});
function SearchAnnotation(cm, query, caseFold, options) {
this.cm = cm;
this.options = options;
var annotateOptions = {listenForChanges: false};
for (var prop in options) annotateOptions[prop] = options[prop];
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
this.annotation = cm.annotateScrollbar(annotateOptions);
this.query = query;
this.caseFold = caseFold;
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
this.matches = [];
this.update = null;
this.findMatches();
this.annotation.update(this.matches);
var self = this;
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
}
var MAX_MATCHES = 1000;
SearchAnnotation.prototype.findMatches = function() {
if (!this.gap) return;
for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
if (match.from.line >= this.gap.to) break;
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
}
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline});
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
while (cursor.findNext()) {
var match = {from: cursor.from(), to: cursor.to()};
if (match.from.line >= this.gap.to) break;
this.matches.splice(i++, 0, match);
if (this.matches.length > maxMatches) break;
}
this.gap = null;
};
function offsetLine(line, changeStart, sizeChange) {
if (line <= changeStart) return line;
return Math.max(changeStart, line + sizeChange);
}
SearchAnnotation.prototype.onChange = function(change) {
var startLine = change.from.line;
var endLine = CodeMirror.changeEnd(change).line;
var sizeChange = endLine - change.to.line;
if (this.gap) {
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
} else {
this.gap = {from: change.from.line, to: endLine + 1};
}
if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
var newTo = offsetLine(match.to.line, startLine, sizeChange);
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
}
clearTimeout(this.update);
var self = this;
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
};
SearchAnnotation.prototype.updateAfterChange = function() {
this.findMatches();
this.annotation.update(this.matches);
};
SearchAnnotation.prototype.clear = function() {
this.cm.off("change", this.changeHandler);
this.annotation.clear();
};
});

View File

@ -1,274 +0,0 @@
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(//themes.googleusercontent.com/static/fonts/sourcesanspro/v5/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff) format('woff');
}
body, html { margin: 0; padding: 0; height: 100%; }
section, article { display: block; padding: 0; }
body {
background: #f8f8f8;
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
line-height: 1.5;
}
p { margin-top: 0; }
h2, h3, h1 {
font-weight: normal;
margin-bottom: .7em;
}
h1 { font-size: 140%; }
h2 { font-size: 120%; }
h3 { font-size: 110%; }
article > h2:first-child, section:first-child > h2 { margin-top: 0; }
#nav h1 {
margin-right: 12px;
margin-top: 0;
margin-bottom: 2px;
color: #d30707;
letter-spacing: .5px;
}
a, a:visited, a:link, .quasilink {
color: #A21313;
}
em {
padding-right: 2px;
}
.quasilink {
cursor: pointer;
}
article {
max-width: 700px;
margin: 0 0 0 160px;
border-left: 2px solid #E30808;
border-right: 1px solid #ddd;
padding: 30px 50px 100px 50px;
background: white;
z-index: 2;
position: relative;
min-height: 100%;
box-sizing: border-box;
-moz-box-sizing: border-box;
}
#nav {
position: fixed;
padding-top: 30px;
max-height: 100%;
box-sizing: -moz-border-box;
box-sizing: border-box;
overflow-y: auto;
left: 0; right: none;
width: 160px;
text-align: right;
z-index: 1;
}
@media screen and (min-width: 1000px) {
article {
margin: 0 auto;
}
#nav {
right: 50%;
width: auto;
border-right: 349px solid transparent;
}
}
#nav ul {
display: block;
margin: 0; padding: 0;
margin-bottom: 32px;
}
#nav a {
text-decoration: none;
}
#nav li {
display: block;
margin-bottom: 4px;
}
#nav li ul {
font-size: 80%;
margin-bottom: 0;
display: none;
}
#nav li.active ul {
display: block;
}
#nav li li a {
padding-right: 20px;
display: inline-block;
}
#nav ul a {
color: black;
padding: 0 7px 1px 11px;
}
#nav ul a.active, #nav ul a:hover {
border-bottom: 1px solid #E30808;
margin-bottom: -1px;
color: #E30808;
}
#logo {
border: 0;
margin-right: 12px;
margin-bottom: 25px;
}
section {
border-top: 1px solid #E30808;
margin: 1.5em 0;
}
section.first {
border: none;
margin-top: 0;
}
#demo {
position: relative;
}
#demolist {
position: absolute;
right: 5px;
top: 5px;
z-index: 25;
}
.yinyang {
position: absolute;
top: -10px;
left: 0; right: 0;
margin: auto;
display: block;
height: 120px;
}
.actions {
margin: 1em 0 0;
min-height: 100px;
position: relative;
}
.actionspicture {
pointer-events: none;
position: absolute;
height: 100px;
top: 0; left: 0; right: 0;
}
.actionlink {
pointer-events: auto;
font-family: arial;
font-size: 80%;
font-weight: bold;
position: absolute;
top: 0; bottom: 0;
line-height: 1;
height: 1em;
margin: auto;
}
.actionlink.download {
color: white;
right: 50%;
margin-right: 13px;
text-shadow: -1px 1px 3px #b00, -1px -1px 3px #b00, 1px 0px 3px #b00;
}
.actionlink.fund {
color: #b00;
left: 50%;
margin-left: 15px;
}
.actionlink:hover {
text-decoration: underline;
}
.actionlink a {
color: inherit;
}
.actionsleft {
float: left;
}
.actionsright {
float: right;
text-align: right;
}
@media screen and (max-width: 800px) {
.actions {
padding-top: 120px;
}
.actionsleft, .actionsright {
float: none;
text-align: left;
margin-bottom: 1em;
}
}
th {
text-decoration: underline;
font-weight: normal;
text-align: left;
}
#features ul {
list-style: none;
margin: 0 0 1em;
padding: 0 0 0 1.2em;
}
#features li:before {
content: "-";
width: 1em;
display: inline-block;
padding: 0;
margin: 0;
margin-left: -1em;
}
.rel {
margin-bottom: 0;
}
.rel-note {
margin-top: 0;
color: #555;
}
pre {
padding-left: 15px;
border-left: 2px solid #ddd;
}
code {
padding: 0 2px;
}
strong {
text-decoration: underline;
font-weight: normal;
}
.field {
border: 1px solid #A21313;
}

720
inc/codemirror/keymap/sublime.js vendored Normal file
View File

@ -0,0 +1,720 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/5/LICENSE
// A rough approximation of Sublime Text's keybindings
// Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/edit/matchbrackets"));
else if (typeof define == "function" && define.amd) // AMD
define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var cmds = CodeMirror.commands;
var Pos = CodeMirror.Pos;
// This is not exactly Sublime's algorithm. I couldn't make heads or tails of that.
function findPosSubword(doc, start, dir) {
if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1));
var line = doc.getLine(start.line);
if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0));
var state = "start", type, startPos = start.ch;
for (var pos = startPos, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) {
var next = line.charAt(dir < 0 ? pos - 1 : pos);
var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o";
if (cat == "w" && next.toUpperCase() == next) cat = "W";
if (state == "start") {
if (cat != "o") { state = "in"; type = cat; }
else startPos = pos + dir
} else if (state == "in") {
if (type != cat) {
if (type == "w" && cat == "W" && dir < 0) pos--;
if (type == "W" && cat == "w" && dir > 0) { // From uppercase to lowercase
if (pos == startPos + 1) { type = "w"; continue; }
else pos--;
}
break;
}
}
}
return Pos(start.line, pos);
}
function moveSubword(cm, dir) {
cm.extendSelectionsBy(function(range) {
if (cm.display.shift || cm.doc.extend || range.empty())
return findPosSubword(cm.doc, range.head, dir);
else
return dir < 0 ? range.from() : range.to();
});
}
cmds.goSubwordLeft = function(cm) { moveSubword(cm, -1); };
cmds.goSubwordRight = function(cm) { moveSubword(cm, 1); };
cmds.scrollLineUp = function(cm) {
var info = cm.getScrollInfo();
if (!cm.somethingSelected()) {
var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local");
if (cm.getCursor().line >= visibleBottomLine)
cm.execCommand("goLineUp");
}
cm.scrollTo(null, info.top - cm.defaultTextHeight());
};
cmds.scrollLineDown = function(cm) {
var info = cm.getScrollInfo();
if (!cm.somethingSelected()) {
var visibleTopLine = cm.lineAtHeight(info.top, "local")+1;
if (cm.getCursor().line <= visibleTopLine)
cm.execCommand("goLineDown");
}
cm.scrollTo(null, info.top + cm.defaultTextHeight());
};
cmds.splitSelectionByLine = function(cm) {
var ranges = cm.listSelections(), lineRanges = [];
for (var i = 0; i < ranges.length; i++) {
var from = ranges[i].from(), to = ranges[i].to();
for (var line = from.line; line <= to.line; ++line)
if (!(to.line > from.line && line == to.line && to.ch == 0))
lineRanges.push({anchor: line == from.line ? from : Pos(line, 0),
head: line == to.line ? to : Pos(line)});
}
cm.setSelections(lineRanges, 0);
};
cmds.singleSelectionTop = function(cm) {
var range = cm.listSelections()[0];
cm.setSelection(range.anchor, range.head, {scroll: false});
};
cmds.selectLine = function(cm) {
var ranges = cm.listSelections(), extended = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
extended.push({anchor: Pos(range.from().line, 0),
head: Pos(range.to().line + 1, 0)});
}
cm.setSelections(extended);
};
function insertLine(cm, above) {
if (cm.isReadOnly()) return CodeMirror.Pass
cm.operation(function() {
var len = cm.listSelections().length, newSelection = [], last = -1;
for (var i = 0; i < len; i++) {
var head = cm.listSelections()[i].head;
if (head.line <= last) continue;
var at = Pos(head.line + (above ? 0 : 1), 0);
cm.replaceRange("\n", at, null, "+insertLine");
cm.indentLine(at.line, null, true);
newSelection.push({head: at, anchor: at});
last = head.line + 1;
}
cm.setSelections(newSelection);
});
cm.execCommand("indentAuto");
}
cmds.insertLineAfter = function(cm) { return insertLine(cm, false); };
cmds.insertLineBefore = function(cm) { return insertLine(cm, true); };
function wordAt(cm, pos) {
var start = pos.ch, end = start, line = cm.getLine(pos.line);
while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start;
while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end;
return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)};
}
cmds.selectNextOccurrence = function(cm) {
var from = cm.getCursor("from"), to = cm.getCursor("to");
var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel;
if (CodeMirror.cmpPos(from, to) == 0) {
var word = wordAt(cm, from);
if (!word.word) return;
cm.setSelection(word.from, word.to);
fullWord = true;
} else {
var text = cm.getRange(from, to);
var query = fullWord ? new RegExp("\\b" + text + "\\b") : text;
var cur = cm.getSearchCursor(query, to);
var found = cur.findNext();
if (!found) {
cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0));
found = cur.findNext();
}
if (!found || isSelectedRange(cm.listSelections(), cur.from(), cur.to())) return
cm.addSelection(cur.from(), cur.to());
}
if (fullWord)
cm.state.sublimeFindFullWord = cm.doc.sel;
};
cmds.skipAndSelectNextOccurrence = function(cm) {
var prevAnchor = cm.getCursor("anchor"), prevHead = cm.getCursor("head");
cmds.selectNextOccurrence(cm);
if (CodeMirror.cmpPos(prevAnchor, prevHead) != 0) {
cm.doc.setSelections(cm.doc.listSelections()
.filter(function (sel) {
return sel.anchor != prevAnchor || sel.head != prevHead;
}));
}
}
function addCursorToSelection(cm, dir) {
var ranges = cm.listSelections(), newRanges = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
var newAnchor = cm.findPosV(
range.anchor, dir, "line", range.anchor.goalColumn);
var newHead = cm.findPosV(
range.head, dir, "line", range.head.goalColumn);
newAnchor.goalColumn = range.anchor.goalColumn != null ?
range.anchor.goalColumn : cm.cursorCoords(range.anchor, "div").left;
newHead.goalColumn = range.head.goalColumn != null ?
range.head.goalColumn : cm.cursorCoords(range.head, "div").left;
var newRange = {anchor: newAnchor, head: newHead};
newRanges.push(range);
newRanges.push(newRange);
}
cm.setSelections(newRanges);
}
cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); };
cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); };
function isSelectedRange(ranges, from, to) {
for (var i = 0; i < ranges.length; i++)
if (CodeMirror.cmpPos(ranges[i].from(), from) == 0 &&
CodeMirror.cmpPos(ranges[i].to(), to) == 0) return true
return false
}
var mirror = "(){}[]";
function selectBetweenBrackets(cm) {
var ranges = cm.listSelections(), newRanges = []
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1);
if (!opening) return false;
for (;;) {
var closing = cm.scanForBracket(pos, 1);
if (!closing) return false;
if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) {
var startPos = Pos(opening.pos.line, opening.pos.ch + 1);
if (CodeMirror.cmpPos(startPos, range.from()) == 0 &&
CodeMirror.cmpPos(closing.pos, range.to()) == 0) {
opening = cm.scanForBracket(opening.pos, -1);
if (!opening) return false;
} else {
newRanges.push({anchor: startPos, head: closing.pos});
break;
}
}
pos = Pos(closing.pos.line, closing.pos.ch + 1);
}
}
cm.setSelections(newRanges);
return true;
}
cmds.selectScope = function(cm) {
selectBetweenBrackets(cm) || cm.execCommand("selectAll");
};
cmds.selectBetweenBrackets = function(cm) {
if (!selectBetweenBrackets(cm)) return CodeMirror.Pass;
};
function puncType(type) {
return !type ? null : /\bpunctuation\b/.test(type) ? type : undefined
}
cmds.goToBracket = function(cm) {
cm.extendSelectionsBy(function(range) {
var next = cm.scanForBracket(range.head, 1, puncType(cm.getTokenTypeAt(range.head)));
if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos;
var prev = cm.scanForBracket(range.head, -1, puncType(cm.getTokenTypeAt(Pos(range.head.line, range.head.ch + 1))));
return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head;
});
};
cmds.swapLineUp = function(cm) {
if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch),
head: Pos(range.head.line - 1, range.head.ch)});
if (range.to().ch == 0 && !range.empty()) --to;
if (from > at) linesToMove.push(from, to);
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
at = to;
}
cm.operation(function() {
for (var i = 0; i < linesToMove.length; i += 2) {
var from = linesToMove[i], to = linesToMove[i + 1];
var line = cm.getLine(from);
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
if (to > cm.lastLine())
cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine");
else
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
}
cm.setSelections(newSels);
cm.scrollIntoView();
});
};
cmds.swapLineDown = function(cm) {
if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
for (var i = ranges.length - 1; i >= 0; i--) {
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
if (range.to().ch == 0 && !range.empty()) from--;
if (from < at) linesToMove.push(from, to);
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
at = to;
}
cm.operation(function() {
for (var i = linesToMove.length - 2; i >= 0; i -= 2) {
var from = linesToMove[i], to = linesToMove[i + 1];
var line = cm.getLine(from);
if (from == cm.lastLine())
cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine");
else
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
}
cm.scrollIntoView();
});
};
cmds.toggleCommentIndented = function(cm) {
cm.toggleComment({ indent: true });
}
cmds.joinLines = function(cm) {
var ranges = cm.listSelections(), joined = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], from = range.from();
var start = from.line, end = range.to().line;
while (i < ranges.length - 1 && ranges[i + 1].from().line == end)
end = ranges[++i].to().line;
joined.push({start: start, end: end, anchor: !range.empty() && from});
}
cm.operation(function() {
var offset = 0, ranges = [];
for (var i = 0; i < joined.length; i++) {
var obj = joined[i];
var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head;
for (var line = obj.start; line <= obj.end; line++) {
var actual = line - offset;
if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1);
if (actual < cm.lastLine()) {
cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length));
++offset;
}
}
ranges.push({anchor: anchor || head, head: head});
}
cm.setSelections(ranges, 0);
});
};
cmds.duplicateLine = function(cm) {
cm.operation(function() {
var rangeCount = cm.listSelections().length;
for (var i = 0; i < rangeCount; i++) {
var range = cm.listSelections()[i];
if (range.empty())
cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0));
else
cm.replaceRange(cm.getRange(range.from(), range.to()), range.from());
}
cm.scrollIntoView();
});
};
function sortLines(cm, caseSensitive, direction) {
if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), toSort = [], selected;
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.empty()) continue;
var from = range.from().line, to = range.to().line;
while (i < ranges.length - 1 && ranges[i + 1].from().line == to)
to = ranges[++i].to().line;
if (!ranges[i].to().ch) to--;
toSort.push(from, to);
}
if (toSort.length) selected = true;
else toSort.push(cm.firstLine(), cm.lastLine());
cm.operation(function() {
var ranges = [];
for (var i = 0; i < toSort.length; i += 2) {
var from = toSort[i], to = toSort[i + 1];
var start = Pos(from, 0), end = Pos(to);
var lines = cm.getRange(start, end, false);
if (caseSensitive)
lines.sort(function(a, b) { return a < b ? -direction : a == b ? 0 : direction; });
else
lines.sort(function(a, b) {
var au = a.toUpperCase(), bu = b.toUpperCase();
if (au != bu) { a = au; b = bu; }
return a < b ? -direction : a == b ? 0 : direction;
});
cm.replaceRange(lines, start, end);
if (selected) ranges.push({anchor: start, head: Pos(to + 1, 0)});
}
if (selected) cm.setSelections(ranges, 0);
});
}
cmds.sortLines = function(cm) { sortLines(cm, true, 1); };
cmds.reverseSortLines = function(cm) { sortLines(cm, true, -1); };
cmds.sortLinesInsensitive = function(cm) { sortLines(cm, false, 1); };
cmds.reverseSortLinesInsensitive = function(cm) { sortLines(cm, false, -1); };
cmds.nextBookmark = function(cm) {
var marks = cm.state.sublimeBookmarks;
if (marks) while (marks.length) {
var current = marks.shift();
var found = current.find();
if (found) {
marks.push(current);
return cm.setSelection(found.from, found.to);
}
}
};
cmds.prevBookmark = function(cm) {
var marks = cm.state.sublimeBookmarks;
if (marks) while (marks.length) {
marks.unshift(marks.pop());
var found = marks[marks.length - 1].find();
if (!found)
marks.pop();
else
return cm.setSelection(found.from, found.to);
}
};
cmds.toggleBookmark = function(cm) {
var ranges = cm.listSelections();
var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []);
for (var i = 0; i < ranges.length; i++) {
var from = ranges[i].from(), to = ranges[i].to();
var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to);
for (var j = 0; j < found.length; j++) {
if (found[j].sublimeBookmark) {
found[j].clear();
for (var k = 0; k < marks.length; k++)
if (marks[k] == found[j])
marks.splice(k--, 1);
break;
}
}
if (j == found.length)
marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false}));
}
};
cmds.clearBookmarks = function(cm) {
var marks = cm.state.sublimeBookmarks;
if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear();
marks.length = 0;
};
cmds.selectBookmarks = function(cm) {
var marks = cm.state.sublimeBookmarks, ranges = [];
if (marks) for (var i = 0; i < marks.length; i++) {
var found = marks[i].find();
if (!found)
marks.splice(i--, 0);
else
ranges.push({anchor: found.from, head: found.to});
}
if (ranges.length)
cm.setSelections(ranges, 0);
};
function modifyWordOrSelection(cm, mod) {
cm.operation(function() {
var ranges = cm.listSelections(), indices = [], replacements = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (range.empty()) { indices.push(i); replacements.push(""); }
else replacements.push(mod(cm.getRange(range.from(), range.to())));
}
cm.replaceSelections(replacements, "around", "case");
for (var i = indices.length - 1, at; i >= 0; i--) {
var range = ranges[indices[i]];
if (at && CodeMirror.cmpPos(range.head, at) > 0) continue;
var word = wordAt(cm, range.head);
at = word.from;
cm.replaceRange(mod(word.word), word.from, word.to);
}
});
}
cmds.smartBackspace = function(cm) {
if (cm.somethingSelected()) return CodeMirror.Pass;
cm.operation(function() {
var cursors = cm.listSelections();
var indentUnit = cm.getOption("indentUnit");
for (var i = cursors.length - 1; i >= 0; i--) {
var cursor = cursors[i].head;
var toStartOfLine = cm.getRange({line: cursor.line, ch: 0}, cursor);
var column = CodeMirror.countColumn(toStartOfLine, null, cm.getOption("tabSize"));
// Delete by one character by default
var deletePos = cm.findPosH(cursor, -1, "char", false);
if (toStartOfLine && !/\S/.test(toStartOfLine) && column % indentUnit == 0) {
var prevIndent = new Pos(cursor.line,
CodeMirror.findColumn(toStartOfLine, column - indentUnit, indentUnit));
// Smart delete only if we found a valid prevIndent location
if (prevIndent.ch != cursor.ch) deletePos = prevIndent;
}
cm.replaceRange("", deletePos, cursor, "+delete");
}
});
};
cmds.delLineRight = function(cm) {
cm.operation(function() {
var ranges = cm.listSelections();
for (var i = ranges.length - 1; i >= 0; i--)
cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete");
cm.scrollIntoView();
});
};
cmds.upcaseAtCursor = function(cm) {
modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); });
};
cmds.downcaseAtCursor = function(cm) {
modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); });
};
cmds.setSublimeMark = function(cm) {
if (cm.state.sublimeMark) cm.state.sublimeMark.clear();
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
};
cmds.selectToSublimeMark = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) cm.setSelection(cm.getCursor(), found);
};
cmds.deleteToSublimeMark = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) {
var from = cm.getCursor(), to = found;
if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; }
cm.state.sublimeKilled = cm.getRange(from, to);
cm.replaceRange("", from, to);
}
};
cmds.swapWithSublimeMark = function(cm) {
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
if (found) {
cm.state.sublimeMark.clear();
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
cm.setCursor(found);
}
};
cmds.sublimeYank = function(cm) {
if (cm.state.sublimeKilled != null)
cm.replaceSelection(cm.state.sublimeKilled, null, "paste");
};
cmds.showInCenter = function(cm) {
var pos = cm.cursorCoords(null, "local");
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
};
function getTarget(cm) {
var from = cm.getCursor("from"), to = cm.getCursor("to");
if (CodeMirror.cmpPos(from, to) == 0) {
var word = wordAt(cm, from);
if (!word.word) return;
from = word.from;
to = word.to;
}
return {from: from, to: to, query: cm.getRange(from, to), word: word};
}
function findAndGoTo(cm, forward) {
var target = getTarget(cm);
if (!target) return;
var query = target.query;
var cur = cm.getSearchCursor(query, forward ? target.to : target.from);
if (forward ? cur.findNext() : cur.findPrevious()) {
cm.setSelection(cur.from(), cur.to());
} else {
cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0)
: cm.clipPos(Pos(cm.lastLine())));
if (forward ? cur.findNext() : cur.findPrevious())
cm.setSelection(cur.from(), cur.to());
else if (target.word)
cm.setSelection(target.from, target.to);
}
};
cmds.findUnder = function(cm) { findAndGoTo(cm, true); };
cmds.findUnderPrevious = function(cm) { findAndGoTo(cm,false); };
cmds.findAllUnder = function(cm) {
var target = getTarget(cm);
if (!target) return;
var cur = cm.getSearchCursor(target.query);
var matches = [];
var primaryIndex = -1;
while (cur.findNext()) {
matches.push({anchor: cur.from(), head: cur.to()});
if (cur.from().line <= target.from.line && cur.from().ch <= target.from.ch)
primaryIndex++;
}
cm.setSelections(matches, primaryIndex);
};
var keyMap = CodeMirror.keyMap;
keyMap.macSublime = {
"Cmd-Left": "goLineStartSmart",
"Shift-Tab": "indentLess",
"Shift-Ctrl-K": "deleteLine",
"Alt-Q": "wrapLines",
"Ctrl-Left": "goSubwordLeft",
"Ctrl-Right": "goSubwordRight",
"Ctrl-Alt-Up": "scrollLineUp",
"Ctrl-Alt-Down": "scrollLineDown",
"Cmd-L": "selectLine",
"Shift-Cmd-L": "splitSelectionByLine",
"Esc": "singleSelectionTop",
"Cmd-Enter": "insertLineAfter",
"Shift-Cmd-Enter": "insertLineBefore",
"Cmd-D": "selectNextOccurrence",
"Shift-Cmd-Space": "selectScope",
"Shift-Cmd-M": "selectBetweenBrackets",
"Cmd-M": "goToBracket",
"Cmd-Ctrl-Up": "swapLineUp",
"Cmd-Ctrl-Down": "swapLineDown",
"Cmd-/": "toggleCommentIndented",
"Cmd-J": "joinLines",
"Shift-Cmd-D": "duplicateLine",
"F5": "sortLines",
"Shift-F5": "reverseSortLines",
"Cmd-F5": "sortLinesInsensitive",
"Shift-Cmd-F5": "reverseSortLinesInsensitive",
"F2": "nextBookmark",
"Shift-F2": "prevBookmark",
"Cmd-F2": "toggleBookmark",
"Shift-Cmd-F2": "clearBookmarks",
"Alt-F2": "selectBookmarks",
"Backspace": "smartBackspace",
"Cmd-K Cmd-D": "skipAndSelectNextOccurrence",
"Cmd-K Cmd-K": "delLineRight",
"Cmd-K Cmd-U": "upcaseAtCursor",
"Cmd-K Cmd-L": "downcaseAtCursor",
"Cmd-K Cmd-Space": "setSublimeMark",
"Cmd-K Cmd-A": "selectToSublimeMark",
"Cmd-K Cmd-W": "deleteToSublimeMark",
"Cmd-K Cmd-X": "swapWithSublimeMark",
"Cmd-K Cmd-Y": "sublimeYank",
"Cmd-K Cmd-C": "showInCenter",
"Cmd-K Cmd-G": "clearBookmarks",
"Cmd-K Cmd-Backspace": "delLineLeft",
"Cmd-K Cmd-1": "foldAll",
"Cmd-K Cmd-0": "unfoldAll",
"Cmd-K Cmd-J": "unfoldAll",
"Ctrl-Shift-Up": "addCursorToPrevLine",
"Ctrl-Shift-Down": "addCursorToNextLine",
"Cmd-F3": "findUnder",
"Shift-Cmd-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",
"Shift-Cmd-[": "fold",
"Shift-Cmd-]": "unfold",
"Cmd-I": "findIncremental",
"Shift-Cmd-I": "findIncrementalReverse",
"Cmd-H": "replace",
"F3": "findNext",
"Shift-F3": "findPrev",
"fallthrough": "macDefault"
};
CodeMirror.normalizeKeyMap(keyMap.macSublime);
keyMap.pcSublime = {
"Shift-Tab": "indentLess",
"Shift-Ctrl-K": "deleteLine",
"Alt-Q": "wrapLines",
"Ctrl-T": "transposeChars",
"Alt-Left": "goSubwordLeft",
"Alt-Right": "goSubwordRight",
"Ctrl-Up": "scrollLineUp",
"Ctrl-Down": "scrollLineDown",
"Ctrl-L": "selectLine",
"Shift-Ctrl-L": "splitSelectionByLine",
"Esc": "singleSelectionTop",
"Ctrl-Enter": "insertLineAfter",
"Shift-Ctrl-Enter": "insertLineBefore",
"Ctrl-D": "selectNextOccurrence",
"Shift-Ctrl-Space": "selectScope",
"Shift-Ctrl-M": "selectBetweenBrackets",
"Ctrl-M": "goToBracket",
"Shift-Ctrl-Up": "swapLineUp",
"Shift-Ctrl-Down": "swapLineDown",
"Ctrl-/": "toggleCommentIndented",
"Ctrl-J": "joinLines",
"Shift-Ctrl-D": "duplicateLine",
"F9": "sortLines",
"Shift-F9": "reverseSortLines",
"Ctrl-F9": "sortLinesInsensitive",
"Shift-Ctrl-F9": "reverseSortLinesInsensitive",
"F2": "nextBookmark",
"Shift-F2": "prevBookmark",
"Ctrl-F2": "toggleBookmark",
"Shift-Ctrl-F2": "clearBookmarks",
"Alt-F2": "selectBookmarks",
"Backspace": "smartBackspace",
"Ctrl-K Ctrl-D": "skipAndSelectNextOccurrence",
"Ctrl-K Ctrl-K": "delLineRight",
"Ctrl-K Ctrl-U": "upcaseAtCursor",
"Ctrl-K Ctrl-L": "downcaseAtCursor",
"Ctrl-K Ctrl-Space": "setSublimeMark",
"Ctrl-K Ctrl-A": "selectToSublimeMark",
"Ctrl-K Ctrl-W": "deleteToSublimeMark",
"Ctrl-K Ctrl-X": "swapWithSublimeMark",
"Ctrl-K Ctrl-Y": "sublimeYank",
"Ctrl-K Ctrl-C": "showInCenter",
"Ctrl-K Ctrl-G": "clearBookmarks",
"Ctrl-K Ctrl-Backspace": "delLineLeft",
"Ctrl-K Ctrl-1": "foldAll",
"Ctrl-K Ctrl-0": "unfoldAll",
"Ctrl-K Ctrl-J": "unfoldAll",
"Ctrl-Alt-Up": "addCursorToPrevLine",
"Ctrl-Alt-Down": "addCursorToNextLine",
"Ctrl-F3": "findUnder",
"Shift-Ctrl-F3": "findUnderPrevious",
"Alt-F3": "findAllUnder",
"Shift-Ctrl-[": "fold",
"Shift-Ctrl-]": "unfold",
"Ctrl-I": "findIncremental",
"Shift-Ctrl-I": "findIncrementalReverse",
"Ctrl-H": "replace",
"F3": "findNext",
"Shift-F3": "findPrev",
"fallthrough": "pcDefault"
};
CodeMirror.normalizeKeyMap(keyMap.pcSublime);
var mac = keyMap.default == keyMap.macDefault;
keyMap.sublime = mac ? keyMap.macSublime : keyMap.pcSublime;
});

View File

@ -60,20 +60,13 @@
.cm-fat-cursor div.CodeMirror-cursors {
z-index: 1;
}
.cm-fat-cursor-mark {
background-color: rgba(20, 255, 20, 0.5);
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
}
.cm-animate-fat-cursor {
width: auto;
border: 0;
-webkit-animation: blink 1.06s steps(1) infinite;
-moz-animation: blink 1.06s steps(1) infinite;
animation: blink 1.06s steps(1) infinite;
background-color: #7e7;
}
.cm-fat-cursor .CodeMirror-line::selection,
.cm-fat-cursor .CodeMirror-line > span::selection,
.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
.cm-fat-cursor .CodeMirror-line::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
.cm-fat-cursor { caret-color: transparent; }
@-moz-keyframes blink {
0% {}
50% { background-color: transparent; }
@ -171,6 +164,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
height: 100%;
outline: none; /* Prevent dragging from highlighting the element */
position: relative;
z-index: 0;
}
.CodeMirror-sizer {
position: relative;
@ -184,6 +178,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
position: absolute;
z-index: 6;
display: none;
outline: none;
}
.CodeMirror-vscrollbar {
right: 0; top: 0;
@ -347,3 +342,12 @@ div.CodeMirror-dragcursors {
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
.breakpoints {width: .8em;}
.breakpoint { color: #822; }
.CodeMirror-focused .cm-matchhighlight {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
background-position: bottom;
background-repeat: repeat-x;
}
.cm-matchhighlight {background-color: lightgreen}
.CodeMirror-selection-highlight-scrollbar {background-color: green}

File diff suppressed because it is too large Load Diff

View File

@ -3,9 +3,9 @@
// Modified for HAProxy by Roxy-WI
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
mod(require("../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
define(["../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
@ -148,7 +148,8 @@ CodeMirror.defineMode("haproxy", function(config) {
return state.baseIndent + n * indentUnit;
},
electricChars: "}"
electricChars: "}",
lineComment: "#"
};
});
CodeMirror.defineMIME("text/x-haproxy-conf", "haproxy");

View File

@ -148,7 +148,8 @@ CodeMirror.defineMode("modsec", function(config) {
return state.baseIndent + n * indentUnit;
},
electricChars: "}"
electricChars: "}",
lineComment: "#"
};
});
CodeMirror.defineMIME("text/x-modsec-conf", "modsec");

File diff suppressed because one or more lines are too long

View File

@ -62,7 +62,7 @@ $( function() {
type: frm.attr('method'),
success: function( data ) {
data = data.replace(/\n/g, "<br>");
if (data.indexOf(service + ': command not found') != '-1') {
if (data.indexOf(service + ': command not found') != '-1') {
try {
var service = findGetParameter('service');
toastr.error('Cannot save config. There is no ' + service);
@ -73,6 +73,9 @@ $( function() {
toastr.clear();
returnNiceCheckingConfig(data);
}
if (data.indexOf('warning: ') != '-1') {
toastr.warning(data)
}
}
});
event.preventDefault();

File diff suppressed because one or more lines are too long

View File

@ -890,7 +890,8 @@ label {
height: 270px;
}
#logo_span img {
margin: auto 40px auto auto;
margin: auto 40px auto 100px;
width: 330px;
}
.chart-container, .chart-container_overview {
position: relative;
@ -994,10 +995,14 @@ label {
margin-left: 15%;
}
.wrong-login {
margin-right: -150px;
margin-left: 44%;
}
}
@media (max-width: 1600px) {
#logo_span img {
width: 300px;
margin: 25px 50px auto 85px;
}
.ajax-server {
clear: both !important;
margin-left: 20px !important;
@ -1006,6 +1011,10 @@ label {
}
}
@media (max-width: 1450px) {
#logo_span img {
width: 250px;
margin: 35px 30px auto 120px;
}
.ajax-server, .div-backends {
clear: both !important;
margin-left: 20px !important;
@ -1031,6 +1040,10 @@ label {
}
}
@media (max-width: 1280px) {
#logo_span img {
width: 250px;
margin: 30px 60px auto 70px;
}
.div-pannel {
height: 430px !important;
}
@ -1052,6 +1065,10 @@ label {
#logo_span {
margin-left: -5%;
}
#logo_span img {
width: 250px;
margin: 35px 0px auto 120px;
}
.wrong-login {
margin-right: -150px;
}
@ -1072,7 +1089,11 @@ label {
@media (max-width: 1080px) {
#logo_span {
margin-left: -5%;
}
}
#logo_span img {
width: 250px;
margin: 35px 60px auto 120px;
}
.chart-container {
position: relative;
height: 410px;
@ -1097,9 +1118,13 @@ label {
}
}
@media (max-width: 768px) {
#logo_span {
margin-left: -12%;
border: none;
#logo_span {
margin-left: -12%;
border: none;
}
#logo_span img {
width: 250px;
margin: 35px 0 auto 120px;
}
.wrong-login {
margin-right: -260px;
@ -1128,9 +1153,13 @@ label {
}
}
@media (max-width: 667px) {
#logo_span {
margin-left: -12%;
border: none;
#logo_span {
margin-left: -12%;
border: none;
}
#logo_span img {
width: 250px;
margin: 35px 0 auto 120px;
}
.wrong-login {
margin-right: -210px;

View File

@ -37,15 +37,15 @@ table.dataTable {
background-repeat: no-repeat;
background-position: center right; }
table.dataTable thead .sorting {
background-image: url("images/sort_both.png"); }
background-image: url("../images/sort_both.png"); }
table.dataTable thead .sorting_asc {
background-image: url("images/sort_asc.png"); }
background-image: url("../images/sort_asc.png"); }
table.dataTable thead .sorting_desc {
background-image: url("images/sort_desc.png"); }
background-image: url("../images/sort_desc.png"); }
table.dataTable thead .sorting_asc_disabled {
background-image: url("images/sort_asc_disabled.png"); }
background-image: url("../images/sort_asc_disabled.png"); }
table.dataTable thead .sorting_desc_disabled {
background-image: url("images/sort_desc_disabled.png"); }
background-image: url("../images/sort_desc_disabled.png"); }
table.dataTable tbody tr {
background-color: white; }
table.dataTable tbody tr.selected {

View File

@ -169,7 +169,11 @@ function ajaxActionNginxServers(action, id) {
if (data.indexOf('error:') != '-1') {
toastr.error(data);
} else if (cur_url[0] == "hapservers.py") {
location.reload()
if (data.indexOf('warning: ') != '-1') {
toastr.warning(data)
} else {
location.reload()
}
} else if (cur_url[0] == "waf.py") {
setTimeout(showOverviewWaf(ip, hostnamea), 2000)
} else {
@ -590,6 +594,9 @@ function serverSettingsSave(id, name, service, dialog_id) {
var haproxy_dockerized = 0;
var nginx_dockerized = 0;
var apache_dockerized = 0;
var haproxy_restart = 0;
var nginx_restart = 0;
var apache_restart = 0;
if ($('#haproxy_enterprise').is(':checked')) {
haproxy_enterprise = '1';
}
@ -602,6 +609,15 @@ function serverSettingsSave(id, name, service, dialog_id) {
if ($('#apache_dockerized').is(':checked')) {
apache_dockerized = '1';
}
if ($('#haproxy_restart').is(':checked')) {
haproxy_restart = '1';
}
if ($('#nginx_restart').is(':checked')) {
nginx_restart = '1';
}
if ($('#apache_restart').is(':checked')) {
apache_restart = '1';
}
$.ajax({
url: "options.py",
data: {
@ -611,6 +627,9 @@ function serverSettingsSave(id, name, service, dialog_id) {
serverSettingshaproxy_dockerized: haproxy_dockerized,
serverSettingsnginx_dockerized: nginx_dockerized,
serverSettingsapache_dockerized: apache_dockerized,
serverSettingsHaproxyrestart: haproxy_restart,
serverSettingsNginxrestart: nginx_restart,
serverSettingsApache_restart: apache_restart,
token: $('#token').val()
},
type: "POST",

View File

@ -34,27 +34,43 @@ $( function() {
}
if (cur_url[0] == link2 && cur_url[1].split('&')[0] != 'service=keepalived' && cur_url[1].split('&')[0] != 'service=nginx' && cur_url[1].split('&')[0] != 'service=apache') {
show_current_page($(this))
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'versions.py?service=keepalived'){
show_current_page($(this))
} else if(cur_url[0] == 'config.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'config.py?service=keepalived'){
show_current_page($(this))
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'versions.py?service=nginx'){
} else if(cur_url[0] == 'config.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'config.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'config.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'config.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'logs.py?service=nginx'){
} else if(cur_url[0] == 'config.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'config.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'logs.py?service=apache'){
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'versions.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'logs.py?service=keepalived'){
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'versions.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'versions.py?service=keepalived'){
show_current_page($(this))
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'versions.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'logs.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'logs.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'logs.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'logs.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'logs.py?service=keepalived'){
show_current_page($(this))
} else if(cur_url[0] == 'hapservers.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'hapservers.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'hapservers.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'hapservers.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'hapservers.py' && cur_url[1].split('&')[0] == 'service=keepalived' && link2 == 'hapservers.py?service=keepalived'){
show_current_page($(this))
} else if(cur_url[0] == 'viewsttats.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'viewsttats.py?service=nginx'){
} else if(cur_url[0] == 'hapservers.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'hapservers.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'viewsttats.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'viewsttats.py?service=apache'){
} else if(cur_url[0] == 'statsview.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'statsview.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'statsview.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'statsview.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'statsview.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'statsview.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'smon.py' && cur_url[1].split('&')[0] == 'action=view' && link2 == 'smon.py?action=view'){
show_current_page($(this))
@ -68,16 +84,12 @@ $( function() {
show_current_page($(this))
} else if(cur_url[0] == 'viewlogs.py' && cur_url[1].split('&')[0] == 'type=2' && link2 == 'viewlogs.py?type=2'){
show_current_page($(this))
} else if(cur_url[0] == 'metrics.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'metrics.py?service=haproxy'){
show_current_page($(this))
} else if(cur_url[0] == 'metrics.py' && cur_url[1].split('&')[0] == 'service=nginx' && link2 == 'metrics.py?service=nginx'){
show_current_page($(this))
} else if(cur_url[0] == 'metrics.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'metrics.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'hapservers.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'hapservers.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'versions.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'versions.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'config.py' && cur_url[1].split('&')[0] == 'service=apache' && link2 == 'config.py?service=apache'){
show_current_page($(this))
} else if(cur_url[0] == 'add.py' && cur_url[1].split('&')[0] == 'service=apache#ssl' && link2 == 'add.py?service=apache#ssl'){
show_current_page($(this))
} else if(cur_url[0] == 'waf.py' && cur_url[1].split('&')[0] == 'service=haproxy' && link2 == 'waf.py?service=haproxy'){
@ -105,7 +117,7 @@ window.onblur= function() {
if(sessionStorage.getItem('auto-refresh-pause') == "0" && sessionStorage.getItem('auto-refresh') > 5000) {
if (cur_url[0] == "logs.py") {
showLog();
} else if (cur_url[0] == "viewsttats.py") {
} else if (cur_url[0] == "statsview.py") {
showStats()
} else if (cur_url[0] == "overview.py") {
showOverview();
@ -207,7 +219,7 @@ function startSetInterval(interval) {
if (cur_url[0] == "logs.py") {
intervalId = setInterval('showLog()', interval);
showLog();
} else if (cur_url[0] == "viewsttats.py") {
} else if (cur_url[0] == "statsview.py") {
intervalId = setInterval('showStats()', interval);
showStats()
} else if (cur_url[0] == "overview.py") {
@ -298,9 +310,9 @@ function showStats() {
function openStats() {
var serv = $("#serv").val();
if (cur_url[1].split('&')[0] == "service=nginx") {
var url = "viewsttats.py?service=nginx&serv="+serv+"&open=open"
var url = "statsview.py?service=nginx&serv="+serv+"&open=open"
} else {
var url = "viewsttats.py?serv="+serv+"&open=open"
var url = "statsview.py?serv="+serv+"&open=open"
}
var win = window.open(url, '_blank');
win.focus();

View File

@ -26,32 +26,32 @@
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/inc/images/favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<link href="/inc/style.css" rel="stylesheet">
<link href="/inc/nprogress.css" rel="stylesheet">
<link href="/inc/provisioning.css" rel="stylesheet">
<link href="/inc/jquery-ui.min.css" rel="stylesheet">
<link href="/inc/jquery-ui.structure.min.css" rel="stylesheet">
<link href="/inc/css/style.css" rel="stylesheet">
<link href="/inc/css/nprogress.css" rel="stylesheet">
<link href="/inc/css/provisioning.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.min.css" rel="stylesheet">
<link href="/inc/css/jquery-ui.structure.min.css" rel="stylesheet">
<script src="/inc/jquery-3.6.0.min.js"></script>
<script src="/inc/jquery-ui.min.js"></script>
<script src="/inc/nprogress.js"></script>
<script defer src="/inc/fa-solid.min.js"></script>
<script defer src="/inc/fontawesome.min.js"></script>
<link href="/inc/awesome.css" rel="stylesheet">
<link href="/inc/chart.min.css" rel="stylesheet">
<link href="/inc/css/awesome.css" rel="stylesheet">
<link href="/inc/css/chart.min.css" rel="stylesheet">
<script src="/inc/metrics.js"></script>
<script src="/inc/chart.min.js"></script>
<link rel="stylesheet" href="/inc/codemirror/codemirror.css">
<script src="/inc/codemirror/codemirror.js"></script>
<script src="/inc/codemirror/nginx.js"></script>
<script src="/inc/codemirror/haproxy.js"></script>
<link href="/inc/toastr.css" rel="stylesheet"/>
<link href="/inc/css/toastr.css" rel="stylesheet"/>
<script src="/inc/toastr.js"></script>
<script defer src="/inc/ion.sound.min.js"></script>
<script src="/inc/provisioning.js"></script>
<link href="/inc/select2.css" rel="stylesheet" />
<link href="/inc/css/select2.css" rel="stylesheet" />
<script src="/inc/select2.js"></script>
<script src="/inc/reconnecting-websocket.js"></script>
<link href="/inc/table.css" rel="stylesheet" type="text/css">
<link href="/inc/css/table.css" rel="stylesheet" type="text/css">
<script type="text/javascript" charset="utf8" src="/inc/dataTables.min.js"></script>
<script src="/inc/js.cookie.min.js"></script>
<script src="/inc/script.js"></script>