Files
op-packages/luci-app-openclash/luasrc/view/openclash/log.htm
T

947 lines
29 KiB
HTML

<%+cbi/valueheader%>
<style type="text/css">
*{margin: 0;padding: 0;}
ul{
list-style: none;
}
#tab{
width: 100%;
height: 100%;
border: 1px solid #ddd;
box-shadow: 0 0 2px #ddd;
overflow: hidden;
}
#tab-header {
display: flex;
align-items: center;
justify-content: flex-start;
padding: 16px 20px;
border-bottom: 1px solid var(--border-light, #e2e8f0);
background: var(--bg-gray, #f1f5f9);
min-width: 0;
box-shadow: none;
position: relative;
z-index: 1;
}
#tab-header ul.cbi-tabmenu {
display: flex;
width: 100%;
background: #f1f5f9;
border-radius: 8px;
border-bottom: none !important;
border: none !important;
gap: 5px;
margin: 0;
padding: 0;
}
#tab-header ul.cbi-tabmenu li {
flex: 1 1 0;
min-width: 0;
width: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 0;
height: 40px;
font-size: 15px;
font-weight: 500;
color: #64748b;
background: transparent;
border: 1px solid #e2e8f0;
border-radius: 8px;
cursor: pointer;
transition: all 0.18s;
margin: 0;
user-select: none;
position: relative;
box-sizing: border-box;
}
#tab-header ul.cbi-tabmenu li.cbi-tab {
background: #3b82f6;
color: #fff;
font-weight: 600;
z-index: 2;
border-radius: 6px;
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.03);
}
#tab-header ul.cbi-tabmenu li.cbi-tab a {
color: #fff !important;
font-weight: 600;
}
#tab-header ul.cbi-tabmenu li.cbi-tab-disabled {
color: #fff;
background: #f9f9f9;
opacity: 0.7;
cursor: pointer;
}
#tab-header ul.cbi-tabmenu li.cbi-tab-disabled a {
color: #000 !important;
}
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover,
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus {
color: #3b82f6;
background: rgba(59,130,246,0.10);
}
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover a,
#tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus a {
color: #3b82f6 !important;
}
#tab-header ul.cbi-tabmenu li a {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
text-align: center;
text-decoration: none;
background: none;
border: none;
outline: none;
font: inherit;
color: inherit;
cursor: inherit;
padding: 0;
margin: 0;
user-select: none;
transition: color 0.18s;
}
#tab-content .dom{
display: none;
}
#tab-content .dom ul li{
float: left;
margin: 15px 10px;
width: 225px;
}
.radio-button {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background: #f1f5f9;
border-radius: 6px;
padding: 6px 10px;
margin: 10px auto;
width: 100%;
max-width: 500px;
flex-wrap: wrap;
box-sizing: border-box;
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.05);
}
.radio-button input[type="radio"] {
display: none;
}
.radio-button label {
display: flex;
align-items: center;
justify-content: center;
padding: 6px 18px;
font-size: 15px;
color: #64748b;
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
font-weight: 500;
min-width: 60px;
user-select: none;
}
.radio-button label:hover {
color: #3b82f6;
border-color: #3b82f6;
background: #f0f6ff;
}
.radio-button input[type="radio"]:checked + label {
background: #3b82f6;
color: #fff;
border-color: #3b82f6;
box-shadow: 0 1px 2px 0 rgba(59,130,246,0.08);
}
.btn-group {
display: flex;
justify-content: space-between;
width: 80%;
margin: 10px auto;
}
:root[data-darkmode="true"] #tab-header {
background: #374151;
border-bottom: 1px solid #374151;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu {
background: #374151;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li {
background: #1f2937;
color: #a1a1aa;
border-color: #374151;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab {
background: #2563eb;
color: #fff;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab a {
color: #fff !important;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab-disabled {
color: #1f2937;
background: #1f2937;
opacity: 0.7;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li.cbi-tab-disabled a {
color: #fff !important;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover,
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus {
color: #3b82f6;
border-color: #3b82f6;
background: #22304a;
}
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):hover a,
:root[data-darkmode="true"] #tab-header ul.cbi-tabmenu li:not(.cbi-tab):focus a {
color: #60a5fa !important;
}
:root[data-darkmode="true"] {
.radio-button {
background: #374151;
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.15);
}
.radio-button label {
background: #1f2937;
color: #d1d5db;
border-color: #4b5563;
}
.radio-button label:hover {
color: #3b82f6;
border-color: #3b82f6;
background: #22304a;
}
.radio-button input[type="radio"]:checked + label {
background: #3b82f6;
color: #fff;
border-color: #3b82f6;
box-shadow: 0 1px 2px 0 rgba(59,130,246,0.18);
}
}
</style>
<body>
<div id="tab" class="cbi-section">
<div id="tab-header">
<ul class="cbi-tabmenu">
<li name="tab-header" class="cbi-tab"><a href="#"><%:OpenClash Log%></a></li>
<li name="tab-header" class="cbi-tab-disabled"><a href="#"><%:Core Log%></a></li>
</ul>
</div>
<div id="tab-content">
<div class="dom" style="display: block;">
<textarea id="cbid.openclash.config.clog" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
</div>
<div class="dom">
<textarea id="core_log" class="cbi-input-textarea" style="width: 100%;display:inline" data-update="change" rows="32" cols="60" readonly="readonly" ></textarea>
<div class="radio-button">
<input type="radio" id="info" name="radios" value="info" checked onclick="return switch_log_level(this.value)"/>
<label for="info"><%:Info%></label>
<input type="radio" id="warning" name="radios" value="warning" onclick="return switch_log_level(this.value)"/>
<label for="warning"><%:Warning%></label>
<input type="radio" id="error" name="radios" value="error" onclick="return switch_log_level(this.value)"/>
<label for="error"><%:Error%></label>
<input type="radio" id="debug" name="radios" value="debug" onclick="return switch_log_level(this.value)"/>
<label for="debug"><%:Debug%></label>
<input type="radio" id="silent" name="radios" value="silent" onclick="return switch_log_level(this.value)"/>
<label for="silent"><%:Silent%></label>
</div>
</div>
</div>
</div>
<fieldset style="text-align: center; width: 100%" class="cbi-section">
<div class="btn-group">
<input type="button" class="btn cbi-button cbi-button-apply" id="stop_refresh_button" value="<%:Stop Refresh%>" onclick=" return stop_refresh() "/>
<input type="button" class="btn cbi-button cbi-button-apply" id="start_refresh_button" value="<%:Start Refresh%>" onclick=" return start_refresh() "/>
<input type="button" class="btn cbi-button cbi-button-apply" id="del_log_button" value="<%:Clean%>" onclick=" return del_log() " />
<input type="button" class="btn cbi-button cbi-button-apply" id="down_log_button" value="<%:Download Log%>" onclick=" return download_log() " />
</div>
</fieldset>
</body>
<script type="text/javascript">//<![CDATA[
var r;
var s;
var log_len = 0;
var lv = document.getElementById('cbid.openclash.config.clog');
var cl = document.getElementById('core_log');
var animatingOC = false;
var animatingCore = false;
var coreWebSocket = null;
var coreLogBuffer = [];
var currentLogLevel = 'info';
var wsRetryDelay = 2000;
var wsRetryTimer = null;
var isPolling = false;
var core_refresh = true;
function setLogTab(log_level) {
var radio = document.getElementsByName("radios");
for (i=0; i<radio.length; i++) {
if (radio[i].value == log_level && ! radio[i].checked) {
radio[i].checked = true;
}
}
};
function get_log_level() {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "log_level")%>', null, function(x, status) {
if (x && x.status == 200 && status.log_level != "") {
currentLogLevel = status.log_level;
setLogTab(currentLogLevel);
coreLogWebSocket();
}
});
};
function switch_log_level(value)
{
if (!coreWebSocket || coreWebSocket.readyState !== WebSocket.OPEN) {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "switch_log")%>', {log_level: value}, function(x, status) {
if (!x || x.status != 200) {
alert(' <%:Log Level%>: ' + value + ' <%:switching failed!%>');
return
}
});
}
currentLogLevel = value;
setLogTab(currentLogLevel);
coreLogWebSocket();
};
function stop_refresh() {
clearTimeout(r);
coreLogWebSocketStop();
return
};
function start_refresh() {
clearTimeout(r);
coreLogWebSocket();
r=setTimeout("poll_log()",1000);
return
};
function createAndDownloadFile(fileName, content) {
var aTag = document.createElement('a');
var blob = new Blob([content]);
aTag.download = fileName;
aTag.href = URL.createObjectURL(blob);
aTag.click();
URL.revokeObjectURL(blob);
};
function download_log(){
var dt = new Date();
var timestamp = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+"-"+dt.getHours()+"-"+dt.getMinutes()+"-"+dt.getSeconds();
var oc_content = "";
if (typeof editor_oc !== 'undefined' && editor_oc) {
oc_content = editor_oc.getValue();
} else if (lv && lv.value) {
oc_content = lv.value;
} else if (lv && lv.innerHTML) {
oc_content = lv.innerHTML;
}
var core_content = "";
if (typeof editor_core !== 'undefined' && editor_core) {
core_content = editor_core.getValue();
} else if (cl && cl.value) {
core_content = cl.value;
} else if (cl && cl.innerHTML) {
core_content = cl.innerHTML;
}
oc_content = oc_content.split('\n').filter(function(line) {
return line.indexOf("】<%:Downloading URL%>【") === -1;
}).join('\n');
if (!oc_content.trim() && !core_content.trim()) {
return;
}
var downloadContent = "";
if (oc_content.trim()) {
downloadContent += "<%:OpenClash Log%>:\n" + oc_content + "\n\n";
}
if (core_content.trim()) {
downloadContent += "<%:Core Log%>:\n" + core_content;
}
createAndDownloadFile("OpenClash-"+timestamp+".log", downloadContent);
return;
};
function del_log() {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "del_log")%>',null,function(x, data){
lv.innerHTML="";
cl.innerHTML="";
coreLogBuffer = [];
log_len = 0;
editor_oc.setValue(lv.value);
editor_core.setValue(cl.value);
editor_core.refresh();
editor_oc.refresh();
});
return
};
function p(s) {
return s < 10 ? '0' + s: s;
};
function getWebSocketConnectionInfo(callback) {
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "status")%>', null, function(x, status) {
if (x && x.status == 200 && status) {
callback(status);
} else {
callback(null);
}
});
}
function coreLogWebSocketStop() {
if (wsRetryTimer) {
clearTimeout(wsRetryTimer);
wsRetryTimer = null;
}
var ws = coreWebSocket;
coreWebSocket = null;
if (!ws) return;
["onopen", "onmessage", "onerror", "onclose"].forEach(function(event) {
try {
ws[event] = null;
} catch (e) {}
});
try {
if (ws.readyState !== WebSocket.CLOSED && ws.readyState !== WebSocket.CLOSING) {
ws.close();
}
} catch (e) {}
coreLogBuffer = [];
}
function coreLogWebSocketRetry() {
wsRetryTimer = setTimeout(function() {
coreLogWebSocket();
}, wsRetryDelay);
}
function coreLogWebSocket() {
coreLogWebSocketStop();
getWebSocketConnectionInfo(function(status) {
if (!status || !status.daip || !status.cn_port || !status.clash) {
return;
}
var protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
var host, port;
if (status.daip && window.location.hostname === status.daip) {
host = status.daip;
port = status.cn_port;
} else if (status.daip && window.location.hostname !== status.daip &&
status.db_foward_domain && status.db_foward_port) {
host = status.db_foward_domain;
port = status.db_foward_port;
} else {
host = status.daip;
port = status.cn_port;
}
var token = status.dase;
var level = currentLogLevel;
var wsUrl = protocol + host + ":" + port + "/logs?token=" + token + "&level=" + level;
try {
coreWebSocket = new WebSocket(wsUrl);
coreWebSocket.onopen = function() {
coreLogBuffer = [];
};
coreWebSocket.onmessage = function(event) {
if (event.data) {
try {
var msgData = JSON.parse(event.data);
if (msgData && msgData.payload) {
var now = new Date();
var timestamp = now.getFullYear() + "-" + p(now.getMonth() + 1) + "-" + p(now.getDate()) + " " +
p(now.getHours()) + ":" + p(now.getMinutes()) + ":" + p(now.getSeconds());
var type = msgData.type || 'info';
var translatedType = levelTranslations[type] || type;
coreLogBuffer.push(timestamp + " [" + translatedType + "] " + msgData.payload);
}
} catch (e) {
coreLogWebSocketRetry();
}
}
};
coreWebSocket.onerror = function(error) {
coreLogWebSocketRetry();
};
coreWebSocket.onclose = function(event) {
coreWebSocket = null;
if (!event.wasClean) {
coreLogWebSocketRetry();
}
};
} catch (e) {
coreLogWebSocketRetry();
}
});
}
function line_tolocal(str) {
var trans_local = new Array();
var local_count = 0;
str.trim().split('\n').forEach(function(v, i) {
var regex = /(time=)"([^"]*)"/g;
var res = regex.exec(v);
try {
if (res) {
var dt = new Date(res[2]);
if (!isNaN(dt.getTime())) {
var timestamp = dt.getFullYear() + "-" + p(dt.getMonth() + 1) + "-" + p(dt.getDate()) + " " +
p(dt.getHours()) + ":" + p(dt.getMinutes()) + ":" + p(dt.getSeconds());
var levelMatch = v.match(/level=(\w+)/);
var level = levelMatch ? levelMatch[1] : 'info';
var translatedLevel = levelTranslations[level] || level;
var msgMatch = v.match(/msg="(.*)"/);
var msg = msgMatch ? msgMatch[1] : '';
trans_local[local_count] = timestamp + " [" + translatedLevel + "] " + msg;
local_count++;
} else {
trans_local[local_count] = v;
local_count++;
}
} else {
try {
var dtt = new Date(v.substring(0, 19));
if (!isNaN(dtt.getTime()) && v.substring(0, 19).match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/)) {
trans_local[local_count] = v;
local_count++;
} else {
trans_local[local_count] = v;
local_count++;
}
} catch (e) {
trans_local[local_count] = v;
local_count++;
}
}
} catch (e) {
trans_local[local_count] = v;
local_count++;
}
});
return trans_local;
};
function smoothlyDisplayLogs(newLines, target, isEditor, currentContent, isActiveTab) {
var scrollPosition = null;
var isAtTop = false;
var cursorPos = null;
var selectionRange = null;
var isFirstLoad = !currentContent || currentContent.trim() === "";
if (isEditor && target) {
scrollPosition = target.getScrollInfo();
isAtTop = (scrollPosition.top < 20);
if (target.hasFocus()) {
cursorPos = target.getCursor();
if (cursorPos.line === 0) {
cursorPos = null;
selectionRange = null;
} else if (target.somethingSelected()) {
selectionRange = {
from: target.getCursor(true),
to: target.getCursor(false)
};
} else {
selectionRange = null;
}
} else {
cursorPos = null;
selectionRange = null;
}
} else if (!isEditor && target) {
scrollPosition = target.scrollTop;
isAtTop = (target.scrollTop < 20);
}
if ((target === editor_oc && animatingOC) || (target === editor_core && animatingCore) || !isActiveTab) {
var content = "";
var lines = newLines.slice().reverse();
for (var i = 0; i < lines.length; i++) {
content += lines[i] + "\n";
}
content = content + (currentContent || "");
var allLines = content.split("\n");
if (allLines.length > 2000) {
allLines = allLines.slice(0, 1999);
allLines.push("...");
content = allLines.join("\n");
}
if (isEditor) {
var addedLines = lines.length;
target.setValue(content);
if (!isAtTop && scrollPosition) {
if (cursorPos) {
cursorPos.line += addedLines;
target.setCursor(cursorPos);
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
} else {
target.scrollTo(scrollPosition.left, scrollPosition.top);
}
if (selectionRange) {
selectionRange.from.line += addedLines;
selectionRange.to.line += addedLines;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
}
} else if (isAtTop) {
target.scrollTo(0, 0);
if (isFirstLoad) {
target.setCursor({line: 0, ch: 0});
}
}
target.refresh();
} else {
var oldScrollTop = scrollPosition;
target.innerHTML = content;
if (!isAtTop && oldScrollTop) {
target.scrollTop = oldScrollTop;
}
}
return;
}
if (target === editor_oc || target === lv) {
animatingOC = true;
} else {
animatingCore = true;
}
var totalLines = newLines.length;
var batchSize, interval;
if (totalLines <= 10) {
batchSize = 2;
interval = 90;
} else if (totalLines <= 50) {
batchSize = 10;
interval = 60;
} else if (totalLines <= 200) {
batchSize = 30;
interval = 35;
} else if (totalLines <= 500) {
batchSize = 60;
interval = 25;
} else if (totalLines <= 1000) {
batchSize = 120;
interval = 15;
} else if (totalLines <= 1500) {
batchSize = 180;
interval = 10;
} else {
batchSize = 250;
interval = 5;
}
var displayedContent = currentContent || "";
var logLines = newLines.slice();
var currentBatchCount = 0;
var accumulatedContent = "";
function displayNextBatch() {
if (currentBatchCount >= logLines.length) {
if (target === editor_oc || target === lv) {
animatingOC = false;
} else {
animatingCore = false;
}
if (isEditor && !isAtTop && cursorPos) {
cursorPos.line += logLines.length;
target.setCursor(cursorPos);
if (selectionRange) {
selectionRange.from.line += logLines.length;
selectionRange.to.line += logLines.length;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
} else {
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
}
}
return;
}
var nextBatchSize = Math.min(batchSize, logLines.length - currentBatchCount);
var batchLines = logLines.slice(currentBatchCount, currentBatchCount + nextBatchSize).reverse();
currentBatchCount += nextBatchSize;
if (accumulatedContent) {
accumulatedContent = batchLines.join("\n") + "\n" + accumulatedContent;
} else {
accumulatedContent = batchLines.join("\n");
}
var content = accumulatedContent + (displayedContent ? "\n" + displayedContent : "");
var contentLines = content.split("\n");
if (contentLines.length > 2000) {
contentLines = contentLines.slice(0, 1999);
contentLines.push("...");
content = contentLines.join("\n");
}
if (isEditor) {
var currentScrollInfo = isAtTop ? null : target.getScrollInfo();
target.setValue(content);
if (!isAtTop && currentScrollInfo) {
target.scrollTo(currentScrollInfo.left, currentScrollInfo.top);
}
target.refresh();
} else {
var currentScrollTop = isAtTop ? null : target.scrollTop;
target.innerHTML = content;
if (!isAtTop && currentScrollTop !== null) {
target.scrollTop = currentScrollTop;
}
}
if (currentBatchCount < logLines.length) {
setTimeout(displayNextBatch, interval);
} else {
if (target === editor_oc || target === lv) {
animatingOC = false;
} else {
animatingCore = false;
}
if (isEditor && !isAtTop && cursorPos) {
cursorPos.line += logLines.length;
target.setCursor(cursorPos);
if (selectionRange) {
selectionRange.from.line += logLines.length;
selectionRange.to.line += logLines.length;
target.setSelection(selectionRange.from, selectionRange.to);
target.scrollIntoView({
from: selectionRange.from,
to: selectionRange.to
}, 300);
} else {
target.scrollIntoView({line: cursorPos.line, ch: cursorPos.ch}, 300);
}
}
}
}
displayNextBatch();
}
function poll_log(){
var activeTabId = 0;
var titles = document.getElementsByName('tab-header');
var core_logs = [];
var oc_logs = [];
var currentCoreContent = "";
var currentContent = "";
var bufferToProcess = [];
for(var i=0; i<titles.length; i++){
if(titles[i].className === 'cbi-tab') {
activeTabId = i;
break;
}
}
if (coreWebSocket && coreWebSocket.readyState == WebSocket.OPEN) {
if (coreLogBuffer.length > 0) {
core_refresh = false;
bufferToProcess = coreLogBuffer;
coreLogBuffer = [];
core_logs = line_tolocal(bufferToProcess.join('\n'));
if (editor_core) {
currentCoreContent = editor_core.getValue();
smoothlyDisplayLogs(core_logs, editor_core, true, currentCoreContent, activeTabId === 1);
} else if (cl) {
currentCoreContent = cl.innerHTML;
smoothlyDisplayLogs(core_logs, cl, false, currentCoreContent, activeTabId === 1);
}
}
}
if (isPolling) {
r = setTimeout("poll_log()", 1000);
return;
}
isPolling = true;
XHR.get('<%=luci.dispatcher.build_url("admin", "services", "openclash", "refresh_log")%>',
{
log_len: log_len, core_refresh: core_refresh
},
function(x, status) {
if (x && x.status == 200) {
if (status) {
if (!status.update) {
isPolling = false;
r = setTimeout("poll_log()", 1000);
return;
}
if (status.len) {
log_len = status.len;
}
if (status.oc_log && status.oc_log !== "") {
oc_logs = line_tolocal(status.oc_log);
if (oc_logs.length > 0) {
if (editor_oc) {
currentContent = editor_oc.getValue();
smoothlyDisplayLogs(oc_logs, editor_oc, true, currentContent, activeTabId === 0);
} else if (lv) {
currentContent = lv.innerHTML;
smoothlyDisplayLogs(oc_logs, lv, false, currentContent, activeTabId === 0);
}
}
}
if (status.core_log && status.core_log !== "") {
core_logs = line_tolocal(status.core_log);
if (core_logs.length > 0) {
if (editor_core) {
currentCoreContent = editor_core.getValue();
smoothlyDisplayLogs(core_logs, editor_core, true, currentCoreContent, activeTabId === 1);
} else if (cl) {
currentCoreContent = cl.innerHTML;
smoothlyDisplayLogs(core_logs, cl, false, currentCoreContent, activeTabId === 1);
}
}
}
}
}
isPolling = false;
r = setTimeout("poll_log()", 1000);
}
);
};
window.onload = function(){
var titles = document.getElementsByName('tab-header');
var divs = document.getElementsByClassName('dom');
if(titles.length != divs.length) return;
for(var i=0; i<titles.length; i++){
var li = titles[i];
li.id = i;
function handleTabSwitch(tab) {
return function(e) {
if (tab.className === 'cbi-tab') return;
for(var j=0; j<titles.length; j++){
titles[j].className = 'cbi-tab-disabled';
divs[j].style.display = 'none';
}
tab.className = 'cbi-tab';
divs[tab.id].style.display = 'block';
if(tab.id == 0 && typeof editor_oc !== 'undefined') {
setTimeout(function(){
editor_oc.refresh();
}, 10);
} else if(tab.id == 1 && typeof editor_core !== 'undefined') {
setTimeout(function(){
editor_core.refresh();
}, 10);
}
};
}
li.onclick = handleTabSwitch(li);
li.ontouchstart = handleTabSwitch(li);
}
get_log_level();
poll_log();
};
//]]>
</script>
<%+cbi/valuefooter%>