fix: solve warnings on obsidian review

This commit is contained in:
moz 2026-07-18 13:33:10 +08:00
parent dcbca03695
commit 3fbd6287a2
6 changed files with 35 additions and 27 deletions

View file

@ -19,7 +19,7 @@ class IconWidget extends WidgetType {
constructor(readonly iconImage: string, readonly hideSuffix: boolean, readonly isBefore: boolean) { super(); }
toDOM(_view: EditorView): HTMLElement {
const span = activeDocument.createElement('span');
const span = createSpan();
span.className = 'external-links-icon-inline'
+ (this.hideSuffix ? ' external-links-icon-hide-suffix' : '')
+ (this.isBefore ? ' external-links-icon-position-before' : '');

View file

@ -9,6 +9,8 @@ import { ExternalLinksIconSettingTab } from './settings';
import { createLivePreviewExtension } from './live-preview';
import { setLanguage } from './lang/helper';
declare const process: { env: { NODE_ENV?: string } };
export default class ExternalLinksIcon extends Plugin {
settings!: ExternalLinksIconSettings;
private scanner: import('./scanner').Scanner | null = null;

View file

@ -29,21 +29,20 @@ function renderIconImage(
icon: IconItem,
isBuiltin: boolean
): void {
const doc = container.ownerDocument;
const hasDual = !!(icon.svgData && icon.themeDarkSvgData);
try {
if (hasDual) {
const lightPrepared = prepareSvgForSettings(icon.svgData || '', container);
const darkPrepared = prepareSvgForSettings(icon.themeDarkSvgData || '', container);
const imgLight = doc.createElement('img');
const imgLight = createEl('img');
setIconImgDataset(imgLight, icon, isBuiltin);
imgLight.dataset.iconVariant = 'light';
imgLight.dataset.dualVariant = 'true';
imgLight.src = `data:image/svg+xml;utf8,${encodeURIComponent(lightPrepared)}`;
imgLight.alt = getIconDisplayName(icon);
const imgDark = doc.createElement('img');
const imgDark = createEl('img');
setIconImgDataset(imgDark, icon, isBuiltin);
imgDark.dataset.iconVariant = 'dark';
imgDark.dataset.dualVariant = 'true';
@ -56,7 +55,7 @@ function renderIconImage(
const preferDark = preferDarkThemeFromDocument();
const svgSource = getSvgSourceForTheme(icon, preferDark);
const prepared = prepareSvgForSettings(svgSource, container);
const img = doc.createElement('img');
const img = createEl('img');
setIconImgDataset(img, icon, isBuiltin);
img.src = `data:image/svg+xml;utf8,${encodeURIComponent(prepared)}`;
img.alt = getIconDisplayName(icon);
@ -111,17 +110,16 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
desc: t('Add website or URL scheme icon. The icon name must be unique.'),
render: (setting) => {
const btnContainer = setting.controlEl.createDiv({ cls: 'add-buttons' });
const doc = btnContainer.ownerDocument;
const addWebsiteBtn = doc.createElement('button');
addWebsiteBtn.textContent = t('Add website');
addWebsiteBtn.onclick = () => {
const addWebsiteBtn = createEl('button');
addWebsiteBtn.textContent = t('Add website');
addWebsiteBtn.onclick = () => {
const modal = new NewIconModal(this.app, (data) => this.addIconWithData(data), 'url', this.plugin.settings.autoRemoveBackground, this.plugin.settings.autoFitIcon);
modal.open();
};
btnContainer.appendChild(addWebsiteBtn);
const addSchemeBtn = doc.createElement('button');
const addSchemeBtn = createEl('button');
addSchemeBtn.textContent = t('Add URL scheme');
addSchemeBtn.onclick = () => {
const modal = new NewIconModal(this.app, (data) => this.addIconWithData(data), 'scheme', this.plugin.settings.autoRemoveBackground, this.plugin.settings.autoFitIcon);
@ -281,7 +279,7 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
private async addIconWithData(data: { linkType: LinkType; name: string; target: string[]; svgData?: string; themeDarkSvgData?: string }) {
const { linkType, name, target, svgData, themeDarkSvgData } = data;
const id = name;
const customIcons = this.plugin.settings.customIcons || {};
const customIcons: Record<string, IconItem> = this.plugin.settings.customIcons || {};
if (customIcons[id]) {
new Notice(`Icon name "${name}" already exists. Please choose a unique name.`);
return;
@ -404,9 +402,14 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
}
}
private getCustomIconList(): IconItem[] {
const map: Record<string, IconItem> = this.plugin.settings.customIcons || {};
return Object.values(map);
}
private getSortedCustomIcons(): IconItem[] {
return Object.values(this.plugin.settings.customIcons || {})
.sort((a: IconItem, b: IconItem) => (a.order || 0) - (b.order || 0));
return this.getCustomIconList()
.sort((a, b) => (a.order || 0) - (b.order || 0));
}
private addIconPreview(settingItem: Setting, icon: IconItem): void {
@ -448,7 +451,7 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
}
private addControlButtons(settingItem: Setting, icon: IconItem): void {
const allCustom = Object.values(this.plugin.settings.customIcons || {});
const allCustom = this.getCustomIconList();
const groupSorted = allCustom
.filter(i => i.linkType === icon.linkType)
.sort((a, b) => (a.order || 0) - (b.order || 0));
@ -494,7 +497,7 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
}
private async moveIcon(icon: IconItem, direction: number): Promise<void> {
const allCustom = Object.values(this.plugin.settings.customIcons || {});
const allCustom = this.getCustomIconList();
const group = allCustom.filter(i => i.linkType === icon.linkType).sort((a, b) => (a.order || 0) - (b.order || 0));
const currentIndex = group.findIndex(i => i.id === icon.id);
const targetIndex = currentIndex + direction;
@ -507,7 +510,7 @@ export class ExternalLinksIconSettingTab extends PluginSettingTab {
arr.forEach((it, idx) => { it.order = idx; });
const newMap: Record<string, IconItem> = {};
Object.values(this.plugin.settings.customIcons || {}).forEach(it => {
this.getCustomIconList().forEach(it => {
if (it.linkType !== icon.linkType) {
newMap[it.id] = it;
}

View file

@ -103,7 +103,7 @@ function normalizeColor(color: string): string | null {
}
try {
if (!_normalizeCtx) {
const canvas = activeDocument.createElement('canvas');
const canvas = createEl('canvas');
canvas.width = 1;
canvas.height = 1;
_normalizeCtx = canvas.getContext('2d');
@ -112,6 +112,7 @@ function normalizeColor(color: string): string | null {
_normalizeCtx.fillStyle = '#abcdef'; // sentinel
_normalizeCtx.fillStyle = c;
const result = _normalizeCtx.fillStyle;
if (typeof result !== 'string') return null;
if (result === '#abcdef') return null; // invalid, kept previous
// Modern browsers return #rrggbb for opaque, rgba(...) for alpha < 1
const rgbaMatch = result.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)$/i);
@ -376,6 +377,7 @@ export function fitSvgToContent(
// Compute content bbox via native getBBox() — accurate for curves/transforms.
// Requires the SVG to be attached to a rendered DOM tree.
let contentBBox: { x: number; y: number; w: number; h: number };
// eslint-disable-next-line obsidianmd/prefer-create-el
const host = activeDocument.createElementNS('http://www.w3.org/2000/svg', 'svg');
host.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
host.setCssProps({

View file

@ -171,7 +171,7 @@ function createIconUploadSection(options: IconUploadSectionOptions): {
onRemove?.(false);
};
const input = createFileInput(doc, (content, fileName) => {
const input = createFileInput((content, fileName) => {
let processed = content;
if (autoRemoveBackground) {
const result = removeBackground(content);
@ -189,7 +189,7 @@ function createIconUploadSection(options: IconUploadSectionOptions): {
newSvgData = processed;
clearRemoveState();
badge.classList.remove('external-links-icon-badge-empty');
renderPreview(doc, preview, processed, fileName);
renderPreview(preview, processed, fileName);
});
if (hiddenInputs) hiddenInputs.push(input);
doc.body.appendChild(input);
@ -202,7 +202,7 @@ function createIconUploadSection(options: IconUploadSectionOptions): {
newSvgData = svgData;
clearRemoveState();
badge.classList.remove('external-links-icon-badge-empty');
renderPreview(doc, preview, svgData, 'copied');
renderPreview(preview, svgData, 'copied');
},
controlRow: row,
};
@ -473,8 +473,8 @@ export class EditIconModal extends Modal {
}
}
function createFileInput(doc: Document, onValid: (content: string, fileName: string) => void): HTMLInputElement {
const input = doc.createElement('input');
function createFileInput(onValid: (content: string, fileName: string) => void): HTMLInputElement {
const input = createEl('input');
input.type = 'file';
input.accept = '.svg,image/svg+xml';
input.classList.add('external-links-icon-hidden-input');
@ -501,9 +501,9 @@ function createFileInput(doc: Document, onValid: (content: string, fileName: str
return input;
}
function renderPreview(doc: Document, previewDiv: HTMLElement, content: string, fileName: string): void {
function renderPreview(previewDiv: HTMLElement, content: string, fileName: string): void {
try {
const img = doc.createElement('img');
const img = createEl('img');
img.src = encodeSvgData(content);
img.alt = fileName;
while (previewDiv.firstChild) previewDiv.removeChild(previewDiv.firstChild);
@ -518,7 +518,7 @@ function downloadSvg(svgData: string, fileName: string): void {
const blob = new Blob([svgData], { type: 'image/svg+xml' });
const url = URL.createObjectURL(blob);
try {
const a = doc.createElement('a');
const a = createEl('a');
a.href = url;
a.download = fileName;
doc.body.appendChild(a);
@ -550,7 +550,7 @@ function createBadgeWithPreview(
if (svgData) {
try {
const prepared = prepareSvgForSettings(svgData, preview);
const img = badge.ownerDocument.createElement('img');
const img = createEl('img');
img.src = encodeSvgData(prepared);
img.alt = variant === 'light' ? 'current' : 'current dark';
preview.appendChild(img);

View file

@ -15,7 +15,8 @@
"DOM",
"ES5",
"ES6",
"ES7"
"ES7",
"ES2017"
]
},
"include": [