Show clipboard file entries without inline video playback
This commit is contained in:
@@ -426,7 +426,7 @@ Item {
|
|||||||
spacing: Style.space(10)
|
spacing: Style.space(10)
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
visible: parent.parent.entryType === "image"
|
visible: parent.parent.previewImage.length > 0
|
||||||
width: visible ? parent.height : 0
|
width: visible ? parent.height : 0
|
||||||
height: parent.height
|
height: parent.height
|
||||||
source: parent.parent.previewImage
|
source: parent.parent.previewImage
|
||||||
@@ -436,13 +436,13 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
width: parent.width - (parent.parent.entryType === "image" ? parent.height + parent.spacing : 0)
|
width: parent.width - (parent.parent.previewImage.length > 0 ? parent.height + parent.spacing : 0)
|
||||||
height: parent.height
|
height: parent.height
|
||||||
text: parent.parent.previewText
|
text: parent.parent.previewText
|
||||||
color: parent.parent.hasCursor ? root.selectedText : root.foreground
|
color: parent.parent.hasCursor ? root.selectedText : root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: Style.font.title
|
font.pixelSize: Style.font.title
|
||||||
opacity: parent.parent.entryType === "image" ? 0.72 : 1.0
|
opacity: parent.parent.entryType === "image" || parent.parent.entryType === "file" ? 0.72 : 1.0
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
wrapMode: Text.NoWrap
|
wrapMode: Text.NoWrap
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
@@ -483,7 +483,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
visible: parent.activeRow && parent.activeRow.entryType === "text"
|
visible: parent.activeRow && !parent.activeRow.previewImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: root.contentMargin
|
anchors.leftMargin: root.contentMargin
|
||||||
anchors.rightMargin: 0
|
anchors.rightMargin: 0
|
||||||
@@ -499,7 +499,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
visible: parent.activeRow && parent.activeRow.entryType === "image"
|
visible: parent.activeRow && parent.activeRow.previewImage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: root.contentMargin
|
anchors.leftMargin: root.contentMargin
|
||||||
anchors.rightMargin: 0
|
anchors.rightMargin: 0
|
||||||
|
|||||||
@@ -92,7 +92,46 @@ function parseEntryJson(line) {
|
|||||||
function searchableText(entry) {
|
function searchableText(entry) {
|
||||||
if (!entry) return ""
|
if (!entry) return ""
|
||||||
if (entry.type === "image") return "image screenshot " + String(entry.mime || "") + " " + String(entry.capturedAt || "")
|
if (entry.type === "image") return "image screenshot " + String(entry.mime || "") + " " + String(entry.capturedAt || "")
|
||||||
return String(entry.text || "")
|
return String(entry.text || "") + " " + fileEntryText(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeFileUri(uri) {
|
||||||
|
var value = String(uri || "").trim()
|
||||||
|
if (value.indexOf("file://") !== 0) return ""
|
||||||
|
|
||||||
|
var path = value.substring(7)
|
||||||
|
if (path.indexOf("localhost/") === 0) path = path.substring(9)
|
||||||
|
if (path.charAt(0) !== "/") return ""
|
||||||
|
|
||||||
|
try { return decodeURIComponent(path) } catch (e) { return path }
|
||||||
|
}
|
||||||
|
|
||||||
|
function filePaths(entry) {
|
||||||
|
if (!entry || entry.type !== "text") return []
|
||||||
|
|
||||||
|
var lines = String(entry.text || "").split(/\r?\n/)
|
||||||
|
var paths = []
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
var path = decodeFileUri(lines[i])
|
||||||
|
if (path) paths.push(path)
|
||||||
|
}
|
||||||
|
return paths
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileName(path) {
|
||||||
|
var parts = String(path || "").split("/")
|
||||||
|
return parts.length > 0 ? parts[parts.length - 1] : String(path || "")
|
||||||
|
}
|
||||||
|
|
||||||
|
function isImagePath(path) {
|
||||||
|
return /\.(png|jpe?g|webp|gif|bmp|tiff?)$/i.test(String(path || ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileEntryText(entry) {
|
||||||
|
var paths = filePaths(entry)
|
||||||
|
if (paths.length === 0) return ""
|
||||||
|
if (paths.length === 1) return fileName(paths[0])
|
||||||
|
return paths.length + " files"
|
||||||
}
|
}
|
||||||
|
|
||||||
function imagePreviewText(entry) {
|
function imagePreviewText(entry) {
|
||||||
@@ -106,9 +145,18 @@ function imagePreviewText(entry) {
|
|||||||
function previewText(entry) {
|
function previewText(entry) {
|
||||||
if (!entry) return ""
|
if (!entry) return ""
|
||||||
if (entry.type === "image") return imagePreviewText(entry)
|
if (entry.type === "image") return imagePreviewText(entry)
|
||||||
|
var fileText = fileEntryText(entry)
|
||||||
|
if (fileText) return fileText
|
||||||
return String(entry.text || "").replace(/\s+/g, " ")
|
return String(entry.text || "").replace(/\s+/g, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fullText(entry) {
|
||||||
|
if (!entry) return ""
|
||||||
|
var paths = filePaths(entry)
|
||||||
|
if (paths.length > 0) return paths.join("\n")
|
||||||
|
return String(entry.text || "")
|
||||||
|
}
|
||||||
|
|
||||||
function displayRows(history, query, limit) {
|
function displayRows(history, query, limit) {
|
||||||
var values = Array.isArray(history) ? history : []
|
var values = Array.isArray(history) ? history : []
|
||||||
var needle = String(query || "").trim().toLowerCase()
|
var needle = String(query || "").trim().toLowerCase()
|
||||||
@@ -124,13 +172,16 @@ function displayRows(history, query, limit) {
|
|||||||
if (!entry) continue
|
if (!entry) continue
|
||||||
if (needle && searchableText(entry).toLowerCase().indexOf(needle) < 0) continue
|
if (needle && searchableText(entry).toLowerCase().indexOf(needle) < 0) continue
|
||||||
|
|
||||||
|
var paths = filePaths(entry)
|
||||||
|
var isFile = paths.length > 0
|
||||||
var isImage = entry.type === "image"
|
var isImage = entry.type === "image"
|
||||||
|
var previewPath = isImage ? String(entry.path || "") : (isFile && paths.length === 1 && isImagePath(paths[0]) ? paths[0] : "")
|
||||||
rows.push({
|
rows.push({
|
||||||
entryType: entry.type,
|
entryType: isFile ? "file" : entry.type,
|
||||||
fullText: isImage ? "" : String(entry.text || ""),
|
fullText: isImage ? "" : fullText(entry),
|
||||||
previewText: previewText(entry),
|
previewText: previewText(entry),
|
||||||
previewImage: isImage ? String(entry.path || "") : "",
|
previewImage: previewPath,
|
||||||
path: isImage ? String(entry.path || "") : "",
|
path: isImage ? String(entry.path || "") : (isFile && paths.length === 1 ? paths[0] : ""),
|
||||||
mime: isImage ? String(entry.mime || "image/png") : "text/plain",
|
mime: isImage ? String(entry.mime || "image/png") : "text/plain",
|
||||||
index: i
|
index: i
|
||||||
})
|
})
|
||||||
@@ -152,6 +203,9 @@ if (typeof module !== "undefined") {
|
|||||||
searchableText: searchableText,
|
searchableText: searchableText,
|
||||||
previewText: previewText,
|
previewText: previewText,
|
||||||
imagePreviewText: imagePreviewText,
|
imagePreviewText: imagePreviewText,
|
||||||
|
filePaths: filePaths,
|
||||||
|
fileEntryText: fileEntryText,
|
||||||
|
fullText: fullText,
|
||||||
displayRows: displayRows
|
displayRows: displayRows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,6 +95,32 @@ assertDeepEqual(
|
|||||||
'clipboard display rows collapse text whitespace'
|
'clipboard display rows collapse text whitespace'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assertDeepEqual(
|
||||||
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif\n' }], '', 50)[0],
|
||||||
|
{
|
||||||
|
entryType: 'file',
|
||||||
|
fullText: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
||||||
|
previewText: 'screenrecording-2026-05-29_13-56-43-720p.gif',
|
||||||
|
previewImage: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
||||||
|
path: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
||||||
|
mime: 'text/plain',
|
||||||
|
index: 0
|
||||||
|
},
|
||||||
|
'clipboard display rows show file uri entries as files'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDeepEqual(
|
||||||
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/One.txt\nfile:///home/dhh/Two.txt\n' }], '', 50)[0].previewText,
|
||||||
|
'2 files',
|
||||||
|
'clipboard display rows summarize multiple file uri entries'
|
||||||
|
)
|
||||||
|
|
||||||
|
assertDeepEqual(
|
||||||
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/Videos/demo.mp4\n' }], '', 50)[0].previewImage,
|
||||||
|
'',
|
||||||
|
'clipboard display rows do not preview video file uri entries inline'
|
||||||
|
)
|
||||||
|
|
||||||
assertDeepEqual(clipboard.displayRows(history, '', 0), [], 'clipboard display rows supports zero result limit')
|
assertDeepEqual(clipboard.displayRows(history, '', 0), [], 'clipboard display rows supports zero result limit')
|
||||||
assertDeepEqual(clipboard.addEntry(history, 'next', 0), [], 'clipboard addEntry supports zero history limit')
|
assertDeepEqual(clipboard.addEntry(history, 'next', 0), [], 'clipboard addEntry supports zero history limit')
|
||||||
JS
|
JS
|
||||||
|
|||||||
Reference in New Issue
Block a user