termites 1.0.22 → 1.0.24

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.js +119 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termites",
3
- "version": "1.0.22",
3
+ "version": "1.0.24",
4
4
  "description": "Web terminal with server-client architecture for remote shell access",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -645,6 +645,13 @@ class TermitesServer {
645
645
  .mobile-toolbar button:active { opacity: 0.6; transform: scale(0.95); }
646
646
  .mobile-toolbar button.active { background: var(--btn-active, rgba(255,255,255,0.15)); }
647
647
  .mobile-toolbar .sep { width: 1px; background: currentColor; opacity: 0.2; margin: 0 4px; }
648
+ .sel-marker {
649
+ position: absolute; z-index: 50; padding: 4px 8px; border-radius: 4px;
650
+ font-size: 11px; font-weight: bold; cursor: grab; touch-action: none;
651
+ user-select: none; -webkit-user-select: none;
652
+ }
653
+ #sel-start-marker { background: #22c55e; color: #fff; }
654
+ #sel-end-marker { background: #ef4444; color: #fff; }
648
655
  </style>
649
656
  </head>
650
657
  <body>
@@ -721,10 +728,12 @@ class TermitesServer {
721
728
  <button data-key="ArrowDown">↓</button>
722
729
  <div class="sep"></div>
723
730
  <button data-seq="/">/</button>
724
- <button id="select-all-btn">SelAll</button>
731
+ <button id="sel-btn" class="mod-btn">Sel</button>
725
732
  <button id="copy-btn">Copy</button>
726
733
  <button id="paste-btn">Paste</button>
727
734
  </div>
735
+ <div id="sel-start-marker" class="sel-marker" style="display:none">▼Start</div>
736
+ <div id="sel-end-marker" class="sel-marker" style="display:none">▲End</div>
728
737
 
729
738
  <script src="https://cdn.jsdelivr.net/npm/xterm@5.3.0/lib/xterm.min.js"></script>
730
739
  <script src="https://cdn.jsdelivr.net/npm/xterm-addon-fit@0.8.0/lib/xterm-addon-fit.min.js"></script>
@@ -1060,14 +1069,116 @@ class TermitesServer {
1060
1069
  pasteBtn.addEventListener('touchstart', handlePaste, { passive: false });
1061
1070
  pasteBtn.addEventListener('click', handlePaste);
1062
1071
 
1063
- // Select All button
1064
- const selectAllBtn = document.getElementById('select-all-btn');
1065
- const handleSelectAll = (e) => {
1072
+ // Selection mode with draggable markers
1073
+ let selMode = false;
1074
+ let selStart = { col: 0, row: 0 };
1075
+ let selEnd = { col: 0, row: 0 };
1076
+ const selBtn = document.getElementById('sel-btn');
1077
+ const startMarker = document.getElementById('sel-start-marker');
1078
+ const endMarker = document.getElementById('sel-end-marker');
1079
+ const termContainer = document.getElementById('terminal-container');
1080
+
1081
+ function getCellSize() {
1082
+ try {
1083
+ return {
1084
+ width: term._core._renderService.dimensions.css.cell.width,
1085
+ height: term._core._renderService.dimensions.css.cell.height
1086
+ };
1087
+ } catch (e) {
1088
+ return { width: 9, height: 17 }; // fallback
1089
+ }
1090
+ }
1091
+
1092
+ function updateMarkerPositions() {
1093
+ const cell = getCellSize();
1094
+ const rect = termContainer.getBoundingClientRect();
1095
+ startMarker.style.left = (selStart.col * cell.width + 4) + 'px';
1096
+ startMarker.style.top = (selStart.row * cell.height) + 'px';
1097
+ endMarker.style.left = (selEnd.col * cell.width + 4) + 'px';
1098
+ endMarker.style.top = ((selEnd.row + 1) * cell.height) + 'px';
1099
+ }
1100
+
1101
+ function updateSelection() {
1102
+ const startOffset = selStart.row * term.cols + selStart.col;
1103
+ const endOffset = selEnd.row * term.cols + selEnd.col;
1104
+ const length = endOffset - startOffset + 1;
1105
+ if (length > 0) {
1106
+ term.select(selStart.col, selStart.row, length);
1107
+ }
1108
+ updateMarkerPositions();
1109
+ }
1110
+
1111
+ function toggleSelMode(e) {
1066
1112
  e.preventDefault();
1067
- term.selectAll();
1068
- };
1069
- selectAllBtn.addEventListener('touchstart', handleSelectAll, { passive: false });
1070
- selectAllBtn.addEventListener('click', handleSelectAll);
1113
+ selMode = !selMode;
1114
+ selBtn.classList.toggle('active', selMode);
1115
+ if (selMode) {
1116
+ // Enter selection mode
1117
+ const lastRow = term.buffer.active.cursorY;
1118
+ selStart = { col: 0, row: Math.max(0, lastRow - 2) };
1119
+ selEnd = { col: term.cols - 1, row: lastRow };
1120
+ startMarker.style.display = 'block';
1121
+ endMarker.style.display = 'block';
1122
+ updateSelection();
1123
+ } else {
1124
+ // Exit selection mode
1125
+ startMarker.style.display = 'none';
1126
+ endMarker.style.display = 'none';
1127
+ term.clearSelection();
1128
+ }
1129
+ }
1130
+ selBtn.addEventListener('touchstart', toggleSelMode, { passive: false });
1131
+ selBtn.addEventListener('click', toggleSelMode);
1132
+
1133
+ // Make markers draggable
1134
+ function setupDraggable(marker, isStart) {
1135
+ let dragging = false;
1136
+ let startX, startY;
1137
+
1138
+ const onStart = (e) => {
1139
+ e.preventDefault();
1140
+ dragging = true;
1141
+ const touch = e.touches ? e.touches[0] : e;
1142
+ startX = touch.clientX;
1143
+ startY = touch.clientY;
1144
+ marker.style.cursor = 'grabbing';
1145
+ };
1146
+
1147
+ const onMove = (e) => {
1148
+ if (!dragging) return;
1149
+ e.preventDefault();
1150
+ const touch = e.touches ? e.touches[0] : e;
1151
+ const cell = getCellSize();
1152
+ const rect = termContainer.getBoundingClientRect();
1153
+ const x = touch.clientX - rect.left - 4;
1154
+ const y = touch.clientY - rect.top;
1155
+
1156
+ const col = Math.max(0, Math.min(term.cols - 1, Math.floor(x / cell.width)));
1157
+ const row = Math.max(0, Math.floor(y / cell.height));
1158
+
1159
+ if (isStart) {
1160
+ selStart = { col, row };
1161
+ } else {
1162
+ selEnd = { col, row: Math.max(0, row - 1) };
1163
+ }
1164
+ updateSelection();
1165
+ };
1166
+
1167
+ const onEnd = () => {
1168
+ dragging = false;
1169
+ marker.style.cursor = 'grab';
1170
+ };
1171
+
1172
+ marker.addEventListener('touchstart', onStart, { passive: false });
1173
+ marker.addEventListener('touchmove', onMove, { passive: false });
1174
+ marker.addEventListener('touchend', onEnd);
1175
+ marker.addEventListener('mousedown', onStart);
1176
+ document.addEventListener('mousemove', onMove);
1177
+ document.addEventListener('mouseup', onEnd);
1178
+ }
1179
+
1180
+ setupDraggable(startMarker, true);
1181
+ setupDraggable(endMarker, false);
1071
1182
  }
1072
1183
 
1073
1184
  function updateClientList() {