From 5a6e82a6c8e32fe6589455006ef5604a2464571e Mon Sep 17 00:00:00 2001 From: Russel Torres Date: Fri, 6 Jun 2025 23:37:52 -0700 Subject: [PATCH 1/4] state: support state share copying for insecure (http) context --- src/datasource/state_share.ts | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/datasource/state_share.ts b/src/datasource/state_share.ts index dc21cc0092..4f07d3e755 100644 --- a/src/datasource/state_share.ts +++ b/src/datasource/state_share.ts @@ -6,6 +6,30 @@ import { bigintToStringJsonReplacer } from "#src/util/json.js"; import type { Viewer } from "#src/viewer.js"; import { makeIcon } from "#src/widget/icon.js"; + +function copyToClipboard(textToCopy) { + // navigator clipboard api needs a secure context (https) + if (navigator.clipboard && window.isSecureContext) { + return navigator.clipboard.writeText(textToCopy); + } else { + // text area method for insecure context (http) + const textArea = document.createElement("textarea"); + textArea.value = textToCopy; + // text area out of viewport + textArea.style.position = "fixed"; + textArea.style.left = "-999999px"; + textArea.style.top = "-999999px"; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + return new Promise((res, rej) => { + document.execCommand("copy") ? res() : rej(); + textArea.remove(); + }); + } +} + + type StateServer = { url: string; default?: boolean; @@ -104,8 +128,9 @@ export class StateShare extends RefCounted { stateUrlProtcol.length, ); const protocol = new URL(selectedStateServer).protocol; - const link = `${window.location.origin}/#!${protocol}${stateUrlWithoutProtocol}`; - navigator.clipboard.writeText(link).then(() => { + const link = `${window.location.origin}${window.location.pathname}#!${protocol}${stateUrlWithoutProtocol}`; + + copyToClipboard(link).then(() => { StatusMessage.showTemporaryMessage( "Share link copied to clipboard", ); From 08c20c1de26be760a5cfa6b33afbe994c8dafb72 Mon Sep 17 00:00:00 2001 From: Russel Torres Date: Tue, 29 Jul 2025 11:35:06 -0700 Subject: [PATCH 2/4] state_share: updating with setClipboard --- src/datasource/state_share.ts | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/src/datasource/state_share.ts b/src/datasource/state_share.ts index 4f07d3e755..c8d91acc59 100644 --- a/src/datasource/state_share.ts +++ b/src/datasource/state_share.ts @@ -3,33 +3,10 @@ import { joinBaseUrlAndPath } from "#src/kvstore/url.js"; import { StatusMessage } from "#src/status.js"; import { RefCounted } from "#src/util/disposable.js"; import { bigintToStringJsonReplacer } from "#src/util/json.js"; +import { setClipboard } from "#src/util/clipboard.js"; import type { Viewer } from "#src/viewer.js"; import { makeIcon } from "#src/widget/icon.js"; - -function copyToClipboard(textToCopy) { - // navigator clipboard api needs a secure context (https) - if (navigator.clipboard && window.isSecureContext) { - return navigator.clipboard.writeText(textToCopy); - } else { - // text area method for insecure context (http) - const textArea = document.createElement("textarea"); - textArea.value = textToCopy; - // text area out of viewport - textArea.style.position = "fixed"; - textArea.style.left = "-999999px"; - textArea.style.top = "-999999px"; - document.body.appendChild(textArea); - textArea.focus(); - textArea.select(); - return new Promise((res, rej) => { - document.execCommand("copy") ? res() : rej(); - textArea.remove(); - }); - } -} - - type StateServer = { url: string; default?: boolean; @@ -130,7 +107,7 @@ export class StateShare extends RefCounted { const protocol = new URL(selectedStateServer).protocol; const link = `${window.location.origin}${window.location.pathname}#!${protocol}${stateUrlWithoutProtocol}`; - copyToClipboard(link).then(() => { + setClipboard(link).then(() => { StatusMessage.showTemporaryMessage( "Share link copied to clipboard", ); From 62096be1ed7c872554470d06dc08929db097b8f8 Mon Sep 17 00:00:00 2001 From: Russel Torres Date: Tue, 29 Jul 2025 14:11:05 -0700 Subject: [PATCH 3/4] state_share: lint fix --- src/datasource/state_share.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datasource/state_share.ts b/src/datasource/state_share.ts index c8d91acc59..a75ba44085 100644 --- a/src/datasource/state_share.ts +++ b/src/datasource/state_share.ts @@ -1,9 +1,9 @@ import { ReadableHttpKvStore } from "#src/kvstore/http/common.js"; import { joinBaseUrlAndPath } from "#src/kvstore/url.js"; import { StatusMessage } from "#src/status.js"; +import { setClipboard } from "#src/util/clipboard.js"; import { RefCounted } from "#src/util/disposable.js"; import { bigintToStringJsonReplacer } from "#src/util/json.js"; -import { setClipboard } from "#src/util/clipboard.js"; import type { Viewer } from "#src/viewer.js"; import { makeIcon } from "#src/widget/icon.js"; From 7655d70ea99439631af588407de0b22eda59340d Mon Sep 17 00:00:00 2001 From: Russel Torres Date: Tue, 29 Jul 2025 14:28:59 -0700 Subject: [PATCH 4/4] state_server: add fail message and fix setClipboard type error --- src/datasource/state_share.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/datasource/state_share.ts b/src/datasource/state_share.ts index a75ba44085..12f4ef8c11 100644 --- a/src/datasource/state_share.ts +++ b/src/datasource/state_share.ts @@ -107,11 +107,12 @@ export class StateShare extends RefCounted { const protocol = new URL(selectedStateServer).protocol; const link = `${window.location.origin}${window.location.pathname}#!${protocol}${stateUrlWithoutProtocol}`; - setClipboard(link).then(() => { - StatusMessage.showTemporaryMessage( - "Share link copied to clipboard", - ); - }); + const result = setClipboard(link); + StatusMessage.showTemporaryMessage( + result + ? "Share link copied to clipboard" + : "Failed to copy share link to clipboard", + ); }) .catch(() => { StatusMessage.showTemporaryMessage(