transmit 창 메세지 리스트 저장불러오기 기능 추가, monitor 창 canspeed 유지기능 추가
This commit is contained in:
216
transmit.h
216
transmit.h
@@ -119,6 +119,10 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
|
||||
color: white;
|
||||
}
|
||||
.btn-warning {
|
||||
background: linear-gradient(135deg, #f2994a 0%, #f2c94c 100%);
|
||||
color: white;
|
||||
}
|
||||
.btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.3); }
|
||||
|
||||
.message-list {
|
||||
@@ -162,10 +166,6 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
font-size: 0.85em;
|
||||
word-break: break-all;
|
||||
}
|
||||
.message-interval {
|
||||
color: #888;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.message-controls {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
@@ -197,6 +197,63 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
}
|
||||
.status-bar span { font-weight: 600; }
|
||||
|
||||
.preset-manager {
|
||||
background: #fff3cd;
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 15px;
|
||||
border-left: 4px solid #f2994a;
|
||||
}
|
||||
.preset-controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.preset-controls input {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 8px;
|
||||
border: 2px solid #f2994a;
|
||||
border-radius: 5px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.preset-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.preset-item {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #f2c94c;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.preset-item:hover {
|
||||
transform: translateX(5px);
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.preset-name {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.preset-info {
|
||||
font-size: 0.75em;
|
||||
color: #666;
|
||||
margin-top: 3px;
|
||||
}
|
||||
.preset-buttons {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
body { padding: 5px; }
|
||||
.header h1 { font-size: 1.5em; }
|
||||
@@ -218,17 +275,6 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
.message-controls {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.control-row {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.control-row > * {
|
||||
width: 100%;
|
||||
}
|
||||
.nav {
|
||||
padding: 8px;
|
||||
gap: 5px;
|
||||
}
|
||||
.nav a {
|
||||
padding: 8px 10px;
|
||||
font-size: 0.85em;
|
||||
@@ -241,6 +287,9 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
gap: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
.preset-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@@ -263,6 +312,17 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
<span id="tx-count">Sent: 0</span>
|
||||
</div>
|
||||
|
||||
<h2>Message List Presets</h2>
|
||||
<div class="preset-manager">
|
||||
<div class="preset-controls">
|
||||
<input type="text" id="preset-name" placeholder="Enter preset name...">
|
||||
<button class="btn btn-warning" onclick="savePreset()">Save Current List</button>
|
||||
</div>
|
||||
<div class="preset-list" id="preset-list">
|
||||
<p style="text-align: center; color: #666; font-size: 0.9em;">No saved presets</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Add CAN Message</h2>
|
||||
<div class="message-form">
|
||||
<div class="form-row">
|
||||
@@ -358,6 +418,127 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
};
|
||||
}
|
||||
|
||||
// 프리셋 관리
|
||||
function savePreset() {
|
||||
const presetName = document.getElementById('preset-name').value.trim();
|
||||
|
||||
if (!presetName) {
|
||||
alert('Please enter a preset name!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (messages.length === 0) {
|
||||
alert('No messages to save!');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let presets = JSON.parse(localStorage.getItem('tx_presets') || '{}');
|
||||
|
||||
if (presets[presetName] && !confirm('Preset "' + presetName + '" already exists. Overwrite?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
presets[presetName] = {
|
||||
messages: JSON.parse(JSON.stringify(messages)),
|
||||
savedAt: new Date().toISOString(),
|
||||
count: messages.length
|
||||
};
|
||||
|
||||
localStorage.setItem('tx_presets', JSON.stringify(presets));
|
||||
|
||||
document.getElementById('preset-name').value = '';
|
||||
loadPresetList();
|
||||
|
||||
alert('Preset "' + presetName + '" saved successfully!');
|
||||
} catch(e) {
|
||||
console.error('Failed to save preset:', e);
|
||||
alert('Failed to save preset!');
|
||||
}
|
||||
}
|
||||
|
||||
function loadPreset(presetName) {
|
||||
try {
|
||||
const presets = JSON.parse(localStorage.getItem('tx_presets') || '{}');
|
||||
const preset = presets[presetName];
|
||||
|
||||
if (!preset) {
|
||||
alert('Preset not found!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (messages.length > 0 && !confirm('Current message list will be replaced. Continue?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopAll();
|
||||
messages = JSON.parse(JSON.stringify(preset.messages));
|
||||
messages.forEach(msg => msg.active = false);
|
||||
|
||||
updateMessageList();
|
||||
alert('Loaded preset "' + presetName + '" with ' + preset.count + ' messages');
|
||||
} catch(e) {
|
||||
console.error('Failed to load preset:', e);
|
||||
alert('Failed to load preset!');
|
||||
}
|
||||
}
|
||||
|
||||
function deletePreset(presetName) {
|
||||
if (!confirm('Delete preset "' + presetName + '"?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let presets = JSON.parse(localStorage.getItem('tx_presets') || '{}');
|
||||
delete presets[presetName];
|
||||
localStorage.setItem('tx_presets', JSON.stringify(presets));
|
||||
loadPresetList();
|
||||
} catch(e) {
|
||||
console.error('Failed to delete preset:', e);
|
||||
alert('Failed to delete preset!');
|
||||
}
|
||||
}
|
||||
|
||||
function loadPresetList() {
|
||||
const presetListDiv = document.getElementById('preset-list');
|
||||
|
||||
try {
|
||||
const presets = JSON.parse(localStorage.getItem('tx_presets') || '{}');
|
||||
const presetNames = Object.keys(presets);
|
||||
|
||||
if (presetNames.length === 0) {
|
||||
presetListDiv.innerHTML = '<p style="text-align: center; color: #666; font-size: 0.9em;">No saved presets</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
presetListDiv.innerHTML = '';
|
||||
|
||||
presetNames.sort().forEach(name => {
|
||||
const preset = presets[name];
|
||||
const item = document.createElement('div');
|
||||
item.className = 'preset-item';
|
||||
|
||||
const savedDate = new Date(preset.savedAt);
|
||||
const dateStr = savedDate.toLocaleDateString() + ' ' + savedDate.toLocaleTimeString();
|
||||
|
||||
item.innerHTML =
|
||||
'<div>' +
|
||||
'<div class="preset-name">' + name + '</div>' +
|
||||
'<div class="preset-info">' + preset.count + ' messages | ' + dateStr + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="preset-buttons">' +
|
||||
'<button class="btn btn-success btn-small" onclick="loadPreset(\'' + name + '\')">Load</button>' +
|
||||
'<button class="btn btn-danger btn-small" onclick="deletePreset(\'' + name + '\')">Delete</button>' +
|
||||
'</div>';
|
||||
|
||||
presetListDiv.appendChild(item);
|
||||
});
|
||||
} catch(e) {
|
||||
console.error('Failed to load preset list:', e);
|
||||
presetListDiv.innerHTML = '<p style="text-align: center; color: #e74c3c; font-size: 0.9em;">Error loading presets</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function addMessage() {
|
||||
const id = document.getElementById('can-id').value.toUpperCase();
|
||||
const type = document.getElementById('msg-type').value;
|
||||
@@ -501,6 +682,11 @@ const char transmit_html[] PROGMEM = R"rawliteral(
|
||||
this.value = this.value.toUpperCase().replace(/[^0-9A-F]/g, '');
|
||||
});
|
||||
|
||||
// 페이지 로드 시 프리셋 목록 불러오기
|
||||
window.addEventListener('load', function() {
|
||||
loadPresetList();
|
||||
});
|
||||
|
||||
initWebSocket();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user