Skip to content

Commit a23c4d9

Browse files
authored
Fix webview compliance issues (#11)
1 parent 15aaf54 commit a23c4d9

4 files changed

Lines changed: 85 additions & 107 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Thumbs.db
4646
*.swo
4747
*~
4848
.cursor/
49+
.claude/
50+
CLAUDE.md
4951

5052
# Temporary files
5153
*.tmp

src/commands/uploadWidget.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ function createUploadPanel(
246246
const presetsJson = JSON.stringify(provider.uploadPresets);
247247
const initScript = `
248248
initUploadWidget({
249-
cloudName: "${escapeHtml(cloudName)}",
249+
cloudName: ${JSON.stringify(cloudName)},
250250
presets: ${presetsJson}
251251
});
252252
`;

src/webview/client/upload-widget.ts

Lines changed: 82 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -297,15 +297,28 @@ function addToQueue(fileId: string, fileName: string): void {
297297

298298
const displayName = truncateString(fileName, 30, "middle");
299299

300-
item.innerHTML = `
301-
<span class="queue-item__name" title="${fileName}">${displayName}</span>
302-
<div class="queue-item__progress">
303-
<div class="progress">
304-
<div class="progress__bar" style="width: 0%"></div>
305-
</div>
306-
</div>
307-
<span class="queue-item__status">Pending...</span>
308-
`;
300+
const nameEl = document.createElement("span");
301+
nameEl.className = "queue-item__name";
302+
nameEl.title = fileName;
303+
nameEl.textContent = displayName;
304+
305+
const progressBar = document.createElement("div");
306+
progressBar.className = "progress__bar";
307+
progressBar.style.width = "0%";
308+
const progress = document.createElement("div");
309+
progress.className = "progress";
310+
progress.appendChild(progressBar);
311+
const progressWrapper = document.createElement("div");
312+
progressWrapper.className = "queue-item__progress";
313+
progressWrapper.appendChild(progress);
314+
315+
const statusEl = document.createElement("span");
316+
statusEl.className = "queue-item__status";
317+
statusEl.textContent = "Pending...";
318+
319+
item.appendChild(nameEl);
320+
item.appendChild(progressWrapper);
321+
item.appendChild(statusEl);
309322

310323
uploadQueue.appendChild(item);
311324
}
@@ -378,55 +391,80 @@ function renderUploadedAsset(asset: AssetData): void {
378391
const card = document.createElement("div");
379392
card.className = "asset-card";
380393

381-
const fileIcon =
382-
"<svg width='48' height='48' viewBox='0 0 24 24' fill='currentColor'><path d='M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2ZM18 20H6V4H13V9H18V20ZM9 13H15V15H9V13ZM9 17H15V19H9V17Z'/></svg>";
394+
// Static SVG icon — no user data
395+
const fileIconSvg = "<svg width='48' height='48' viewBox='0 0 24 24' fill='currentColor'><path d='M14 2H6C4.9 2 4 2.9 4 4V20C4 21.1 4.9 22 6 22H18C19.1 22 20 21.1 20 20V8L14 2ZM18 20H6V4H13V9H18V20ZM9 13H15V15H9V13ZM9 17H15V19H9V17Z'/></svg>";
396+
397+
// Thumbnail wrapper
398+
const thumbnailWrapper = document.createElement("div");
399+
thumbnailWrapper.className = "asset-card__thumbnail";
400+
thumbnailWrapper.setAttribute("data-asset-id", asset.public_id);
383401

384-
let mediaHtml: string;
385402
if (thumbnailUrl) {
386-
mediaHtml = `
387-
<div class="asset-card__thumbnail" data-asset-id="${asset.public_id}">
388-
<img class="asset-card__image" src="${thumbnailUrl}" alt="Thumbnail" />
389-
<div class="asset-card__icon fallback" style="display:none;">${fileIcon}</div>
390-
</div>
391-
`;
403+
const img = document.createElement("img");
404+
img.className = "asset-card__image";
405+
img.src = thumbnailUrl;
406+
img.alt = "Thumbnail";
407+
const fallbackEl = document.createElement("div");
408+
fallbackEl.className = "asset-card__icon fallback";
409+
fallbackEl.style.display = "none";
410+
fallbackEl.innerHTML = fileIconSvg;
411+
img.addEventListener("error", function () {
412+
this.style.display = "none";
413+
fallbackEl.style.display = "flex";
414+
});
415+
thumbnailWrapper.appendChild(img);
416+
thumbnailWrapper.appendChild(fallbackEl);
392417
} else {
393-
mediaHtml = `
394-
<div class="asset-card__thumbnail" data-asset-id="${asset.public_id}">
395-
<div class="asset-card__icon">${fileIcon}</div>
396-
</div>
397-
`;
418+
const iconEl = document.createElement("div");
419+
iconEl.className = "asset-card__icon";
420+
iconEl.innerHTML = fileIconSvg;
421+
thumbnailWrapper.appendChild(iconEl);
398422
}
399423

424+
// Folder
425+
const folderEl = document.createElement("div");
426+
folderEl.className = "asset-card__folder";
427+
const folderCode = document.createElement("code");
428+
folderCode.textContent = folderDisplay;
429+
folderEl.appendChild(document.createTextNode("📂 "));
430+
folderEl.appendChild(folderCode);
431+
432+
// Asset ID
400433
const displayId = truncateString(asset.public_id, 25, "start");
434+
const idEl = document.createElement("div");
435+
idEl.className = "asset-card__id";
436+
idEl.title = asset.public_id;
437+
idEl.textContent = displayId;
438+
439+
// Action buttons
440+
const actionsEl = document.createElement("div");
441+
actionsEl.className = "asset-card__actions";
442+
443+
const copyUrlBtn = document.createElement("button");
444+
copyUrlBtn.className = "btn btn--secondary btn--sm btn--copy";
445+
copyUrlBtn.setAttribute("data-copy", asset.secure_url);
446+
copyUrlBtn.textContent = "Copy URL";
401447

402-
card.innerHTML = `
403-
${mediaHtml}
404-
<div class="asset-card__folder">📂 <code>${folderDisplay}</code></div>
405-
<div class="asset-card__id" title="${asset.public_id}">${displayId}</div>
406-
<div class="asset-card__actions">
407-
<button class="btn btn--secondary btn--sm btn--copy" data-copy="${asset.secure_url}">Copy URL</button>
408-
<button class="btn btn--secondary btn--sm btn--copy" data-copy="${asset.public_id}">Copy ID</button>
409-
</div>
410-
`;
448+
const copyIdBtn = document.createElement("button");
449+
copyIdBtn.className = "btn btn--secondary btn--sm btn--copy";
450+
copyIdBtn.setAttribute("data-copy", asset.public_id);
451+
copyIdBtn.textContent = "Copy ID";
452+
453+
actionsEl.appendChild(copyUrlBtn);
454+
actionsEl.appendChild(copyIdBtn);
455+
456+
card.appendChild(thumbnailWrapper);
457+
card.appendChild(folderEl);
458+
card.appendChild(idEl);
459+
card.appendChild(actionsEl);
411460

412461
// Click thumbnail to preview
413-
const thumbnailWrapper = card.querySelector(".asset-card__thumbnail");
414-
if (thumbnailWrapper && vscode) {
462+
if (vscode) {
415463
thumbnailWrapper.addEventListener("click", () => {
416464
vscode.postMessage({ command: "openAsset", asset: asset });
417465
});
418466
}
419467

420-
// Handle image load errors
421-
const img = card.querySelector<HTMLImageElement>(".asset-card__image");
422-
if (img) {
423-
img.addEventListener("error", function () {
424-
this.style.display = "none";
425-
const fallback = this.parentElement?.querySelector<HTMLElement>(".fallback");
426-
if (fallback) {fallback.style.display = "flex";}
427-
});
428-
}
429-
430468
// Initialize copy buttons
431469
card.querySelectorAll<HTMLElement>(".btn--copy[data-copy]").forEach((btn) => {
432470
btn.addEventListener("click", async (e) => {

src/webview/index.ts

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export * from "./components";
5252

5353
// Utility scripts
5454
export * from "./utils";
55-
import { escapeHtml } from "./utils/helpers";
5655

5756
// Icons
5857
export {
@@ -115,65 +114,4 @@ export function getCompleteScripts(): string {
115114
].join("\n");
116115
}
117116

118-
/**
119-
* Creates a complete HTML document for a webview panel.
120-
*
121-
* @param options - Document configuration
122-
* @returns Complete HTML string
123-
*
124-
* @example
125-
* ```typescript
126-
* panel.webview.html = createWebviewDocument({
127-
* title: 'Upload to Cloudinary',
128-
* body: createPanel({ content: '...' }),
129-
* additionalStyles: '.custom { color: red; }',
130-
* additionalScripts: 'console.log("Hello");'
131-
* });
132-
* ```
133-
*/
134-
export function createWebviewDocument(options: {
135-
/** Document title */
136-
title: string;
137-
/** Body content (HTML string) */
138-
body: string;
139-
/** Additional CSS to include */
140-
additionalStyles?: string;
141-
/** Additional JavaScript to include */
142-
additionalScripts?: string;
143-
/** Whether to include all component scripts (default: true) */
144-
includeScripts?: boolean;
145-
}): string {
146-
const {
147-
title,
148-
body,
149-
additionalStyles = "",
150-
additionalScripts = "",
151-
includeScripts = true,
152-
} = options;
153-
154-
const styles = getCompleteStyles();
155-
const scripts = includeScripts ? getCompleteScripts() : "";
156-
157-
return `
158-
<!DOCTYPE html>
159-
<html lang="en">
160-
<head>
161-
<meta charset="UTF-8" />
162-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
163-
<title>${escapeHtml(title)}</title>
164-
<style>
165-
${styles}
166-
${additionalStyles}
167-
</style>
168-
</head>
169-
<body>
170-
${body}
171-
<script>
172-
${scripts}
173-
${additionalScripts}
174-
</script>
175-
</body>
176-
</html>
177-
`;
178-
}
179117

0 commit comments

Comments
 (0)