codex-overleaf-link 2.3.5 → 2.4.0

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 (57) hide show
  1. package/README.md +63 -31
  2. package/README.zh-CN.md +543 -0
  3. package/extension/bootstrap/manifest.template.json +1 -1
  4. package/extension/src/background.js +7 -0
  5. package/extension/src/backgroundUpdateCoordinator.js +88 -4
  6. package/extension/src/content/activeTurnControl.js +1 -0
  7. package/extension/src/content/assetTransferBroker.js +2 -0
  8. package/extension/src/content/contentRuntime.js +77 -57
  9. package/extension/src/content/contextTray.js +4 -0
  10. package/extension/src/content/diagnosticsController.js +17 -3
  11. package/extension/src/content/diagnosticsPanel.js +129 -5
  12. package/extension/src/content/generated/content.bundle.js +1422 -348
  13. package/extension/src/content/generated/content.bundle.meta.json +7 -3
  14. package/extension/src/content/legacyGlobalRegistry.js +3 -0
  15. package/extension/src/content/modelPicker.js +21 -9
  16. package/extension/src/content/modelPickerSupport.js +38 -1
  17. package/extension/src/content/nativeCompatibilityController.js +4 -1
  18. package/extension/src/content/otWarmMirror.js +126 -92
  19. package/extension/src/content/otWarmMirrorController.js +122 -1
  20. package/extension/src/content/pageBridgeClient.js +2 -0
  21. package/extension/src/content/panelMaintenance.js +26 -15
  22. package/extension/src/content/providerSettingsCoordinator.js +1 -0
  23. package/extension/src/content/runFailureNotice.js +104 -0
  24. package/extension/src/content/runResultActions.js +16 -1
  25. package/extension/src/content/runScrollLayout.js +124 -0
  26. package/extension/src/content/runTimelineView.js +37 -11
  27. package/extension/src/content/sessionForkController.js +20 -11
  28. package/extension/src/content/settingsPanel.js +28 -11
  29. package/extension/src/content/trackedChangeCaptureController.js +153 -0
  30. package/extension/src/content/updateNotice.js +24 -4
  31. package/extension/src/content/writebackOrchestrator.js +31 -0
  32. package/extension/src/page/binaryAssetUploader.js +101 -29
  33. package/extension/src/page/overleafRealtimeObserver.js +120 -25
  34. package/extension/src/page/textFileCreator.js +493 -0
  35. package/extension/src/page/trackedChangeCapture.js +342 -0
  36. package/extension/src/page/trackedChangesLifecycle.js +145 -149
  37. package/extension/src/page/treeOperations.js +30 -2
  38. package/extension/src/page/writebackRouter.js +94 -48
  39. package/extension/src/pageBridge.js +62 -25
  40. package/extension/src/shared/compatibility.js +1 -1
  41. package/extension/src/shared/i18n.js +77 -37
  42. package/extension/src/shared/managedUpdateProjection.js +1 -1
  43. package/extension/src/shared/otText.js +0 -1
  44. package/extension/src/shared/pageRpcContract.js +2 -1
  45. package/extension/src/shared/sessionState.js +23 -23
  46. package/extension/src/shared/sessionTitle.js +120 -0
  47. package/extension/src/shared/storageDb.js +10 -12
  48. package/extension/src/shared/storageRunActions.js +29 -1
  49. package/extension/src/shared/updateRuntimeIdentity.js +32 -0
  50. package/extension/src/shared/writebackSettlement.js +19 -5
  51. package/extension/styles/panel.css +128 -24
  52. package/native-host/src/mirrorWorkspace.js +20 -1
  53. package/native-host/src/releaseProxy.js +177 -0
  54. package/native-host/src/releaseTransport.js +154 -0
  55. package/native-host/src/taskRunnerRuntime.js +25 -0
  56. package/native-host/src/updateManager.js +40 -39
  57. package/package.json +5 -1
@@ -10,7 +10,8 @@
10
10
  container,
11
11
  callbacks: options.callbacks || {},
12
12
  i18n: options.i18n || {},
13
- dismissInstalled: false
13
+ dismissInstalled: false,
14
+ cleanup: []
14
15
  };
15
16
 
16
17
  container.innerHTML = `
@@ -38,7 +39,7 @@
38
39
  <small data-i18n="diagnosticsSnapshotSubtitle">Full project, assets, read source</small>
39
40
  </button>
40
41
  <button type="button" data-diagnostics-ot>
41
- <span data-i18n="diagnosticsOtTitle">Check Experimental OT Mirror</span>
42
+ <span data-i18n="diagnosticsOtTitle">Check OT Mirror</span>
42
43
  <small data-i18n="diagnosticsOtSubtitle">Status, fresh files, fallback</small>
43
44
  </button>
44
45
  <button type="button" data-diagnostics-export>
@@ -99,6 +100,11 @@
99
100
  instance.callbacks.onBeforeOpen?.();
100
101
  }
101
102
  popover.hidden = !open;
103
+ if (open) {
104
+ openFloating(instance, popover, 300);
105
+ } else {
106
+ hideFloating(popover);
107
+ }
102
108
  button.dataset.active = open ? 'true' : 'false';
103
109
  button.setAttribute('aria-expanded', open ? 'true' : 'false');
104
110
  }
@@ -110,7 +116,7 @@
110
116
  if (!popover || !button) {
111
117
  return;
112
118
  }
113
- popover.hidden = true;
119
+ hideFloating(popover);
114
120
  button.dataset.active = 'false';
115
121
  button.setAttribute('aria-expanded', 'false');
116
122
  }
@@ -119,7 +125,7 @@
119
125
  const instance = target?._instance || target;
120
126
  const result = instance?.container?.querySelector('[data-diagnostics-result]');
121
127
  if (result) {
122
- result.hidden = true;
128
+ hideFloating(result);
123
129
  }
124
130
  }
125
131
 
@@ -181,6 +187,73 @@
181
187
  details.open = false;
182
188
  details.hidden = !technicalText;
183
189
  technical.textContent = technicalText;
190
+ closeMenu(instance);
191
+ openFloating(instance, root, 560);
192
+ }
193
+
194
+ // Keep DOM ownership (theme, locale and callbacks), but render above clipping
195
+ // ancestors where the browser supports the top layer. Fixed positioning is
196
+ // the viewport-based fallback for browsers without the Popover API.
197
+ function openFloating(instance, element, preferredWidth) {
198
+ if (element.isConnected === false) return;
199
+ element.hidden = false;
200
+ if (typeof element.showPopover === 'function') {
201
+ element.setAttribute('popover', 'manual');
202
+ try {
203
+ if (!element.matches(':popover-open')) element.showPopover();
204
+ } catch (_error) {
205
+ element.removeAttribute('popover');
206
+ }
207
+ }
208
+ positionFloating(instance, element, preferredWidth);
209
+ }
210
+
211
+ function hideFloating(element) {
212
+ if (!element) return;
213
+ if (typeof element.hidePopover === 'function' && element.getAttribute('popover') === 'manual') {
214
+ try {
215
+ if (element.matches(':popover-open')) element.hidePopover();
216
+ } catch (_error) {
217
+ element.removeAttribute('popover');
218
+ }
219
+ }
220
+ element.hidden = true;
221
+ }
222
+
223
+ function positionFloating(instance, element, preferredWidth) {
224
+ if (!element || element.hidden) return;
225
+ const button = instance.container.querySelector('[data-diagnostics-menu]');
226
+ if (!button?.getBoundingClientRect || !element.getBoundingClientRect) return;
227
+ if (button.getClientRects && !button.getClientRects().length) {
228
+ closeMenu(instance);
229
+ closeResult(instance);
230
+ return;
231
+ }
232
+ const doc = instance.container.ownerDocument || document;
233
+ const view = doc.defaultView || window;
234
+ const viewport = view.visualViewport;
235
+ const width = viewport?.width || view.innerWidth || doc.documentElement?.clientWidth;
236
+ const height = viewport?.height || view.innerHeight || doc.documentElement?.clientHeight;
237
+ if (!(width > 0 && height > 0)) return;
238
+ const margin = 12;
239
+ const gap = 8;
240
+ const leftEdge = (viewport?.offsetLeft || 0) + margin;
241
+ const topEdge = (viewport?.offsetTop || 0) + margin;
242
+ const rightEdge = leftEdge + Math.max(0, width - margin * 2);
243
+ const bottomEdge = topEdge + Math.max(0, height - margin * 2);
244
+ element.style.width = `${Math.min(preferredWidth, Math.max(0, width - margin * 2))}px`;
245
+ element.style.maxHeight = `${Math.min(640, Math.max(0, height - margin * 2))}px`;
246
+ const anchor = button.getBoundingClientRect();
247
+ const bounds = element.getBoundingClientRect();
248
+ const below = Math.max(0, bottomEdge - anchor.bottom - gap);
249
+ const above = Math.max(0, anchor.top - topEdge - gap);
250
+ const desiredTop = bounds.height > below && above > below
251
+ ? anchor.top - gap - bounds.height
252
+ : anchor.bottom + gap;
253
+ element.style.left = `${Math.max(leftEdge, Math.min(anchor.right - bounds.width, rightEdge - bounds.width))}px`;
254
+ element.style.top = `${Math.max(topEdge, Math.min(desiredTop, bottomEdge - bounds.height))}px`;
255
+ element.style.right = 'auto';
256
+ element.style.bottom = 'auto';
184
257
  }
185
258
 
186
259
  function renderInstallCommand(instance, container, command) {
@@ -272,13 +345,60 @@
272
345
  return;
273
346
  }
274
347
  instance.dismissInstalled = true;
275
- document.addEventListener('click', event => {
348
+ const doc = instance.container.ownerDocument || document;
349
+ const view = doc.defaultView || window;
350
+ const listen = (target, type, handler, options) => {
351
+ if (!target?.addEventListener) return;
352
+ target.addEventListener(type, handler, options);
353
+ instance.cleanup.push(() => target.removeEventListener(type, handler, options));
354
+ };
355
+ listen(doc, 'click', event => {
276
356
  const wrap = instance.container?.querySelector('.codex-diagnostics-wrap');
277
357
  if (!wrap || wrap.contains(event.target)) {
278
358
  return;
279
359
  }
280
360
  closeMenu(instance);
281
361
  }, true);
362
+ listen(doc, 'keydown', event => {
363
+ if (event.key !== 'Escape') return;
364
+ const menu = instance.container.querySelector('[data-diagnostics-popover]');
365
+ const result = instance.container.querySelector('[data-diagnostics-result]');
366
+ if (menu && !menu.hidden) closeMenu(instance);
367
+ else if (result && !result.hidden) closeResult(instance);
368
+ else return;
369
+ event.preventDefault();
370
+ event.stopPropagation();
371
+ instance.container.querySelector('[data-diagnostics-menu]')?.focus();
372
+ }, true);
373
+ let frame = null;
374
+ const reposition = () => {
375
+ frame = null;
376
+ positionFloating(instance, instance.container.querySelector('[data-diagnostics-popover]'), 300);
377
+ positionFloating(instance, instance.container.querySelector('[data-diagnostics-result]'), 560);
378
+ };
379
+ const schedule = () => {
380
+ if (frame !== null) return;
381
+ if (view.requestAnimationFrame) frame = view.requestAnimationFrame(reposition);
382
+ else reposition();
383
+ };
384
+ listen(view, 'resize', schedule);
385
+ listen(doc, 'scroll', schedule, true);
386
+ listen(view.visualViewport, 'resize', schedule);
387
+ listen(view.visualViewport, 'scroll', schedule);
388
+ if (typeof view.ResizeObserver === 'function') {
389
+ const observer = new view.ResizeObserver(schedule);
390
+ for (const node of [
391
+ instance.container.closest('#codex-overleaf-panel') || instance.container,
392
+ instance.container.querySelector('[data-diagnostics-popover]'),
393
+ instance.container.querySelector('[data-diagnostics-result]')
394
+ ]) {
395
+ if (node) observer.observe(node);
396
+ }
397
+ instance.cleanup.push(() => observer.disconnect());
398
+ }
399
+ instance.cleanup.push(() => {
400
+ if (frame !== null) view.cancelAnimationFrame?.(frame);
401
+ });
282
402
  }
283
403
 
284
404
  // Drive the trigger's health dot. `health` is one of ok / warn / fail /
@@ -450,6 +570,10 @@
450
570
  }
451
571
 
452
572
  function destroy(instance) {
573
+ closeMenu(instance);
574
+ closeResult(instance);
575
+ for (const cleanup of instance.cleanup || []) cleanup();
576
+ instance.cleanup = [];
453
577
  instance.container.textContent = '';
454
578
  }
455
579