termites 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server.js +78 -1
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -590,7 +590,9 @@ class TermitesServer {
|
|
|
590
590
|
.header-title .host { color: var(--host-color, #859900); }
|
|
591
591
|
.header-title .sep { color: var(--sep-color, #657b83); }
|
|
592
592
|
.no-client { color: #888; font-style: italic; }
|
|
593
|
-
#terminal-container { flex: 1; padding: 4px; transition: background 0.3s; overflow: hidden; min-height: 0; }
|
|
593
|
+
#terminal-container { flex: 1; padding: 4px; transition: background 0.3s; overflow: hidden; min-height: 0; position: relative; }
|
|
594
|
+
#terminal-container.select-mode { cursor: text; }
|
|
595
|
+
#terminal-container.select-mode::after { content: 'Select Mode'; position: absolute; top: 8px; right: 8px; background: rgba(0,0,0,0.7); color: #fff; padding: 4px 8px; border-radius: 4px; font-size: 11px; pointer-events: none; }
|
|
594
596
|
.xterm { height: 100%; }
|
|
595
597
|
.overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.4); z-index: 99; opacity: 0; visibility: hidden; transition: all 0.3s; }
|
|
596
598
|
.overlay.open { opacity: 1; visibility: visible; }
|
|
@@ -725,6 +727,10 @@ class TermitesServer {
|
|
|
725
727
|
<button data-seq="\\x04">^D</button>
|
|
726
728
|
<button data-seq="\\x1a">^Z</button>
|
|
727
729
|
<button data-seq="\\x0c">^L</button>
|
|
730
|
+
<div class="sep"></div>
|
|
731
|
+
<button id="copy-btn">Copy</button>
|
|
732
|
+
<button id="paste-btn">Paste</button>
|
|
733
|
+
<button id="select-btn" class="mod-btn">Select</button>
|
|
728
734
|
</div>
|
|
729
735
|
|
|
730
736
|
<script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
|
|
@@ -1030,6 +1036,77 @@ class TermitesServer {
|
|
|
1030
1036
|
btn.addEventListener('touchstart', handler, { passive: false });
|
|
1031
1037
|
btn.addEventListener('click', handler);
|
|
1032
1038
|
});
|
|
1039
|
+
|
|
1040
|
+
// Copy button - copy selection or last line
|
|
1041
|
+
document.getElementById('copy-btn').addEventListener('click', async () => {
|
|
1042
|
+
const selection = term.getSelection();
|
|
1043
|
+
if (selection) {
|
|
1044
|
+
await navigator.clipboard.writeText(selection);
|
|
1045
|
+
term.clearSelection();
|
|
1046
|
+
}
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
// Paste button
|
|
1050
|
+
document.getElementById('paste-btn').addEventListener('click', async () => {
|
|
1051
|
+
try {
|
|
1052
|
+
const text = await navigator.clipboard.readText();
|
|
1053
|
+
if (text && ws?.readyState === WebSocket.OPEN && selectedClientId) {
|
|
1054
|
+
ws.send(JSON.stringify({ type: 'input', clientId: selectedClientId, text }));
|
|
1055
|
+
}
|
|
1056
|
+
} catch (e) {
|
|
1057
|
+
console.error('Paste failed:', e);
|
|
1058
|
+
}
|
|
1059
|
+
term.focus();
|
|
1060
|
+
});
|
|
1061
|
+
|
|
1062
|
+
// Select mode button - enables touch selection
|
|
1063
|
+
let selectMode = false;
|
|
1064
|
+
const selectBtn = document.getElementById('select-btn');
|
|
1065
|
+
const termContainer = document.getElementById('terminal-container');
|
|
1066
|
+
|
|
1067
|
+
selectBtn.addEventListener('click', () => {
|
|
1068
|
+
selectMode = !selectMode;
|
|
1069
|
+
selectBtn.classList.toggle('active', selectMode);
|
|
1070
|
+
termContainer.style.touchAction = selectMode ? 'none' : '';
|
|
1071
|
+
termContainer.style.userSelect = selectMode ? 'text' : '';
|
|
1072
|
+
if (selectMode) {
|
|
1073
|
+
// Enable selection overlay
|
|
1074
|
+
termContainer.classList.add('select-mode');
|
|
1075
|
+
} else {
|
|
1076
|
+
termContainer.classList.remove('select-mode');
|
|
1077
|
+
term.clearSelection();
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
|
|
1081
|
+
// Handle touch selection
|
|
1082
|
+
let touchStartPos = null;
|
|
1083
|
+
termContainer.addEventListener('touchstart', (e) => {
|
|
1084
|
+
if (selectMode && e.touches.length === 1) {
|
|
1085
|
+
const touch = e.touches[0];
|
|
1086
|
+
const rect = termContainer.getBoundingClientRect();
|
|
1087
|
+
touchStartPos = { x: touch.clientX - rect.left, y: touch.clientY - rect.top };
|
|
1088
|
+
}
|
|
1089
|
+
}, { passive: true });
|
|
1090
|
+
|
|
1091
|
+
termContainer.addEventListener('touchmove', (e) => {
|
|
1092
|
+
if (selectMode && touchStartPos && e.touches.length === 1) {
|
|
1093
|
+
e.preventDefault();
|
|
1094
|
+
const touch = e.touches[0];
|
|
1095
|
+
const rect = termContainer.getBoundingClientRect();
|
|
1096
|
+
const currentPos = { x: touch.clientX - rect.left, y: touch.clientY - rect.top };
|
|
1097
|
+
|
|
1098
|
+
// Convert pixel positions to terminal coordinates
|
|
1099
|
+
const cellWidth = term._core._renderService.dimensions.css.cell.width;
|
|
1100
|
+
const cellHeight = term._core._renderService.dimensions.css.cell.height;
|
|
1101
|
+
|
|
1102
|
+
const startCol = Math.floor(touchStartPos.x / cellWidth);
|
|
1103
|
+
const startRow = Math.floor(touchStartPos.y / cellHeight);
|
|
1104
|
+
const endCol = Math.floor(currentPos.x / cellWidth);
|
|
1105
|
+
const endRow = Math.floor(currentPos.y / cellHeight);
|
|
1106
|
+
|
|
1107
|
+
term.select(startCol, startRow, (endRow - startRow) * term.cols + (endCol - startCol) + 1);
|
|
1108
|
+
}
|
|
1109
|
+
}, { passive: false });
|
|
1033
1110
|
}
|
|
1034
1111
|
|
|
1035
1112
|
function updateClientList() {
|