|
|
|
|
@ -26,6 +26,10 @@
|
|
|
|
|
<link rel="stylesheet" type="text/css" href="easyui.css"> |
|
|
|
|
<link rel="stylesheet" href="css/sweetalert2.min.css"> |
|
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.7/codemirror.min.css"> |
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.7/codemirror.min.js"></script> |
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.7/mode/python/python.min.js"></script> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
|
window.onerror = function (message, url, linenumber) { |
|
|
|
|
@ -116,27 +120,41 @@
|
|
|
|
|
max-height: 70vh; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
.container { |
|
|
|
|
display: flex; |
|
|
|
|
height: 100vh; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#editor-container { |
|
|
|
|
/*負責裝按鈕的 container*/ |
|
|
|
|
#editor-container { |
|
|
|
|
flex-grow: 1; |
|
|
|
|
display: flex; |
|
|
|
|
flex-direction: column; |
|
|
|
|
height: 120%; |
|
|
|
|
height: 100vh; /* 確保編輯器容器填滿整個視窗的高度 */ |
|
|
|
|
width: 100%; /* 填滿視窗的寬度 */ |
|
|
|
|
background-color: #f9f9f9; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*Program container*/ |
|
|
|
|
#code-editor { |
|
|
|
|
flex-grow: 1; |
|
|
|
|
display: flex; |
|
|
|
|
flex-direction: column; |
|
|
|
|
margin-bottom: 10px; |
|
|
|
|
|
|
|
|
|
flex-grow: 1; /* 讓編輯器占據剩餘的空間 */ |
|
|
|
|
width: 100%; /* 宽度充满容器 */ |
|
|
|
|
height: 100%; /* 高度填滿容器 */ |
|
|
|
|
margin-bottom: 10px; /* 可調整底部間距 */ |
|
|
|
|
} |
|
|
|
|
/*Program textarea*/ |
|
|
|
|
#code-textarea { |
|
|
|
|
width: 100%; |
|
|
|
|
height: 100%; /* 讓編輯器的大小隨著容器調整 */ |
|
|
|
|
font-size: 1vw; /* 可以適當調整字體大小,讓它看起來更清楚 */ |
|
|
|
|
resize: none; /* 禁用手動調整大小,以便由容器控制 */ |
|
|
|
|
} |
|
|
|
|
/*Messege textarea*/ |
|
|
|
|
#console { |
|
|
|
|
height: 50vh; |
|
|
|
|
padding: 10px; |
|
|
|
|
border: 2px solid #ccc; |
|
|
|
|
font-size: 1vw; |
|
|
|
|
overflow-x: auto; |
|
|
|
|
overflow-y: auto; |
|
|
|
|
flex-grow: 1; |
|
|
|
|
} |
|
|
|
|
#code-editor, #console { |
|
|
|
|
flex-grow: 1; /* 讓這些元素自動根據剩餘空間調整大小 */ |
|
|
|
|
} |
|
|
|
|
.editor-container { |
|
|
|
|
font-size: 1vw; |
|
|
|
|
@ -144,8 +162,12 @@
|
|
|
|
|
margin-left: 15px; |
|
|
|
|
margin-top: 10px; |
|
|
|
|
line-height: normal; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.container { |
|
|
|
|
display: flex; |
|
|
|
|
height: 100vh; |
|
|
|
|
} |
|
|
|
|
.console-container { |
|
|
|
|
font-size: 1vw; |
|
|
|
|
font-weight: normal; |
|
|
|
|
@ -153,32 +175,6 @@
|
|
|
|
|
margin-bottom: 5px; |
|
|
|
|
line-height: normal; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#code-textarea { |
|
|
|
|
flex-grow: 1; |
|
|
|
|
width: 100%; |
|
|
|
|
border: 2px solid #ccc; |
|
|
|
|
margin: 0; |
|
|
|
|
padding: 10px; |
|
|
|
|
font-family: 'Courier New', Courier, monospace; |
|
|
|
|
font-size: 1vw; |
|
|
|
|
|
|
|
|
|
white-space: pre; |
|
|
|
|
overflow-x: auto; |
|
|
|
|
overflow-y: auto; |
|
|
|
|
resize: none; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#console { |
|
|
|
|
height: auto; |
|
|
|
|
padding: 10px; |
|
|
|
|
border: 2px solid #ccc; |
|
|
|
|
font-size: 1vw; |
|
|
|
|
overflow-x: auto; |
|
|
|
|
overflow-y: auto; |
|
|
|
|
flex-grow: 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</style> |
|
|
|
|
</head> |
|
|
|
|
@ -196,6 +192,7 @@
|
|
|
|
|
<input type="text" id="search-box" placeholder="Search" |
|
|
|
|
style="width: 108%; height: 40px; border-radius: 5px; border: 1px solid #ccc;margin-right: 0; align-self: start; position: relative; left: -10px;"> |
|
|
|
|
</div> |
|
|
|
|
<div id="file-results"></div> |
|
|
|
|
<div style="display: flex; justify-content: space-between;"> |
|
|
|
|
<button id="uploadfile-button" |
|
|
|
|
style="color: white; border: none; text-align: center; cursor: pointer;" |
|
|
|
|
@ -273,10 +270,11 @@
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
|
var fileArray = []; |
|
|
|
|
var BufferSize = 512; // Buffer 最大 Row 數 |
|
|
|
|
var getPythonBufferIntervalTime = 50; |
|
|
|
|
var getPythonStatusIntervalTime = 50; |
|
|
|
|
var receivedCountThreshold = 37500 / getPythonStatusIntervalTime |
|
|
|
|
var receivedCountThreshold = 37500 / getPythonStatusIntervalTime // 約等於 15 秒 |
|
|
|
|
var dataReceivedCount = 0; |
|
|
|
|
var getPythonBufferSize = 64; |
|
|
|
|
var getBufferStatusTemp = null; |
|
|
|
|
@ -312,7 +310,28 @@
|
|
|
|
|
func_getPythonStatus(); |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
// 初始化 CodeMirror |
|
|
|
|
var editor = CodeMirror.fromTextArea(document.getElementById('code-textarea'), { |
|
|
|
|
lineNumbers: true, |
|
|
|
|
mode: "python", |
|
|
|
|
theme: "default", |
|
|
|
|
lineWrapping: true, |
|
|
|
|
indentUnit: 4, |
|
|
|
|
matchBrackets: true |
|
|
|
|
}); |
|
|
|
|
// 動態調整大小,使其適應容器 |
|
|
|
|
function resizeEditor() { |
|
|
|
|
editor.setSize("100%", "100%"); |
|
|
|
|
} |
|
|
|
|
// 動態設置編輯器的樣式 |
|
|
|
|
editor.getWrapperElement().style.fontSize = '1.0vw'; // 使用相對單位 'vw' 來設定字體大小,隨著視窗大小改變 |
|
|
|
|
// 初次加載時調整大小 |
|
|
|
|
resizeEditor(); |
|
|
|
|
|
|
|
|
|
// 當視窗大小改變時自動調整編輯器大小 |
|
|
|
|
window.addEventListener('resize', function() { |
|
|
|
|
resizeEditor(); |
|
|
|
|
}); |
|
|
|
|
// 取得資料夾中的所有檔案名稱 |
|
|
|
|
function func_getFileList(pyFileName) { |
|
|
|
|
console.log('in get file list'); |
|
|
|
|
@ -325,20 +344,17 @@
|
|
|
|
|
}, |
|
|
|
|
success: function (retdata) { |
|
|
|
|
var data; |
|
|
|
|
|
|
|
|
|
if (typeof retdata === 'string') { |
|
|
|
|
data = JSON.parse(retdata); |
|
|
|
|
} else { |
|
|
|
|
data = retdata; |
|
|
|
|
} |
|
|
|
|
var fileList = data.file_list; |
|
|
|
|
var dataForGrid = fileList.map(function (filename) { |
|
|
|
|
return { |
|
|
|
|
filename: filename, |
|
|
|
|
lastModified: 'Not available' |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
$('#file-data-grid').datagrid('loadData', dataForGrid); |
|
|
|
|
fileArray = Object.values(fileList); // 儲存所有 python 檔名 |
|
|
|
|
|
|
|
|
|
updateDataGrid(fileArray); // 更新顯示的檔案列表 |
|
|
|
|
|
|
|
|
|
if (pyFileName != null) { |
|
|
|
|
selectFileInDataGrid(pyFileName); // 此時 fileList 已包含新文件 |
|
|
|
|
} |
|
|
|
|
@ -348,11 +364,28 @@
|
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 更新 Files 列表 |
|
|
|
|
function updateDataGrid(files) { |
|
|
|
|
var dataForGrid = files.map(function (filename) { |
|
|
|
|
return { |
|
|
|
|
filename: filename, |
|
|
|
|
lastModified: 'Not available' |
|
|
|
|
}; |
|
|
|
|
}); |
|
|
|
|
$('#file-data-grid').datagrid('loadData', dataForGrid); |
|
|
|
|
} |
|
|
|
|
// 查看 Search box 有無輸入 |
|
|
|
|
document.getElementById('search-box').addEventListener('input', function () { |
|
|
|
|
var searchTerm = this.value.toLowerCase(); // 將輸入的內容轉為小寫 |
|
|
|
|
var filteredFiles = fileArray.filter(function (file) { |
|
|
|
|
return file.toLowerCase().includes(searchTerm); // 根據輸入進行過濾 |
|
|
|
|
}); |
|
|
|
|
updateDataGrid(filteredFiles); |
|
|
|
|
}); |
|
|
|
|
// 取得文件內容 |
|
|
|
|
function func_FileGet(file_name) { |
|
|
|
|
var reqFileNmae = file_name; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$.ajax({ |
|
|
|
|
url: "/pythonget?file=" + reqFileNmae, |
|
|
|
|
type: "GET", |
|
|
|
|
@ -362,17 +395,19 @@
|
|
|
|
|
xmlHttp.setRequestHeader("Cache-Control", "no-cache"); |
|
|
|
|
}, |
|
|
|
|
success: function (retdata) { |
|
|
|
|
$('#code-editor textarea').val(retdata); |
|
|
|
|
editor.setValue(retdata); |
|
|
|
|
}, |
|
|
|
|
error: function (retdata) { |
|
|
|
|
console.warn(retdata); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 儲存文件內容 |
|
|
|
|
function func_FileSave(file_name) { |
|
|
|
|
var pyFileName = file_name; |
|
|
|
|
pythoncode = $('#code-editor textarea').val(); |
|
|
|
|
pythoncode = editor.getValue(); |
|
|
|
|
var encoded = encodeURIComponent(pythoncode); |
|
|
|
|
console.log("func_FileSave pyFileName ---------- ",pyFileName) |
|
|
|
|
$.ajax({ |
|
|
|
|
@ -478,20 +513,12 @@
|
|
|
|
|
json_data += '}'; |
|
|
|
|
func_setconfigfile(json_data); |
|
|
|
|
|
|
|
|
|
var rows = $('#file-data-grid').datagrid('getRows'); // 取得所有行的資料 |
|
|
|
|
rows.forEach(function (row, index) { |
|
|
|
|
var $row = $('#file-data-grid').datagrid('getPanel').find('tr[datagrid-row-index="' + index + '"]'); |
|
|
|
|
$row.find('td[field="filename"] img').attr('src', './images/py.png'); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
$.ajax({ |
|
|
|
|
url: "/stoppython", |
|
|
|
|
method: "GET", |
|
|
|
|
async: true, |
|
|
|
|
success: function (retdata) { |
|
|
|
|
clearInterval(Status_intervalId); |
|
|
|
|
// 在請求完成後重新啟用「Run」 |
|
|
|
|
// $("#run-button").prop("disabled", false); |
|
|
|
|
|
|
|
|
|
$('#console').append(' '); // 換行 |
|
|
|
|
$('#console').append(retdata.replace(/\n/g, '<br>')); |
|
|
|
|
@ -501,7 +528,7 @@
|
|
|
|
|
var textarea = $('#console')[0]; |
|
|
|
|
textarea.scrollTop = textarea.scrollHeight; |
|
|
|
|
} |
|
|
|
|
// displayDataCounter = 1; |
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
error: function (retdata) { |
|
|
|
|
console.warn(retdata); |
|
|
|
|
@ -616,8 +643,6 @@
|
|
|
|
|
// 取得 Python 結果 |
|
|
|
|
function func_getPythonBuffer() { |
|
|
|
|
console.log("func_getPythonBuffer() start"); |
|
|
|
|
var python_content = $('#code-textarea').val(); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
$.ajax({ |
|
|
|
|
url: "/pythongetbuffer?buffersize=" + getPythonBufferSize.toString(), |
|
|
|
|
@ -635,17 +660,8 @@
|
|
|
|
|
|
|
|
|
|
console.log("Get displayData",JSON.stringify(displayData)); |
|
|
|
|
$('#console').append(displayData); |
|
|
|
|
/*if (dataReceivedCount == 0) |
|
|
|
|
{ |
|
|
|
|
$('#console').html(displayData); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
$('#console').append(displayData); |
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
// dataReceivedCount++; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根據 autoScroll 開關自動滾動 Ming 2024-08-29 |
|
|
|
|
if (autoScroll) { |
|
|
|
|
var textarea = $('#console')[0]; |
|
|
|
|
@ -700,7 +716,7 @@
|
|
|
|
|
func_setconfigfile(json_data); |
|
|
|
|
console.log("func_runPython"); |
|
|
|
|
autoScroll = true; |
|
|
|
|
var python_content = $('#code-textarea').val(); |
|
|
|
|
var python_content = editor.getValue(); |
|
|
|
|
var json_data = "lifile_liname=" + file_name; |
|
|
|
|
|
|
|
|
|
console.log(file_name); |
|
|
|
|
@ -784,14 +800,14 @@
|
|
|
|
|
$('#console').append(' '); // 換行 |
|
|
|
|
$('#console').append("Running..."); |
|
|
|
|
$('#console').append(' '); // 換行 |
|
|
|
|
console.log("找到可執行 Python 檔案 !!!!!!!!!!!!!! "); |
|
|
|
|
console.log("find enable python file !!!!!!!!!!!!!! "); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
console.log("未找到可執行 Python 檔案 !!!!!!!!!!!!!! "); |
|
|
|
|
console.log("not found enable python file !!!!!!!!!!!!!! "); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
console.log("未找到 enable_python_file 設置"); |
|
|
|
|
console.log("not found enable python setting"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
@ -893,38 +909,35 @@
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 按 Ctrl + S |
|
|
|
|
$(document).keydown(function (event) { |
|
|
|
|
// Ctrl + S 保存 |
|
|
|
|
editor.on('keydown', function (instance, event) { |
|
|
|
|
if (event.ctrlKey && event.which === 83) { |
|
|
|
|
event.preventDefault(); |
|
|
|
|
func_FileSave(currentFileName); // 使用現在的文件名稱進行上傳 |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
// 按 SHIFT + ENTER 執行 |
|
|
|
|
$(document).keydown(function (event) { |
|
|
|
|
|
|
|
|
|
// Shift + Enter 執行 |
|
|
|
|
editor.on('keydown', function (instance, event) { |
|
|
|
|
if (event.shiftKey && event.which === 13) { |
|
|
|
|
event.preventDefault(); |
|
|
|
|
console.log("----------------Now Runing :",currentFileName) |
|
|
|
|
console.log("Now Running:", currentFileName); |
|
|
|
|
// 禁用「Run」,防止連續點擊 |
|
|
|
|
$("#run-button").prop("disabled", true); |
|
|
|
|
func_runPython(currentFileName); // 使用現在的文件名稱執行 Python |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
// 設定 Textarea 可使用 Tab |
|
|
|
|
$('#code-textarea').on('keydown', function(e) { |
|
|
|
|
if (e.key === 'Tab') { |
|
|
|
|
e.preventDefault(); |
|
|
|
|
var start = this.selectionStart; |
|
|
|
|
var end = this.selectionEnd; |
|
|
|
|
|
|
|
|
|
this.value = this.value.substring(0, start) + ' ' + ' ' + ' ' + ' ' + this.value.substring(end); |
|
|
|
|
|
|
|
|
|
this.selectionStart = this.selectionEnd = start + 4; |
|
|
|
|
editor.setOption("extraKeys", { |
|
|
|
|
Tab: function(cm) { |
|
|
|
|
cm.replaceSelection(" ", "end"); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$('#console').on('mousedown', function() { |
|
|
|
|
isUserScrolling = true; |
|
|
|
|
}); |
|
|
|
|
@ -1012,8 +1025,8 @@
|
|
|
|
|
}).then((result) => { |
|
|
|
|
if (result.isConfirmed) { |
|
|
|
|
// 清空 textarea 的内容 |
|
|
|
|
var textarea = document.getElementById('code-textarea'); |
|
|
|
|
textarea.value = ''; |
|
|
|
|
//var codeContent = editor.getValue(); |
|
|
|
|
editor.setValue(""); |
|
|
|
|
func_FileUpload(currentFileName); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|