@jinntec/jinn-codemirror
Version:
Source code editor component based on codemirror with language support for XML and Leiden+
97 lines (86 loc) • 3.58 kB
text/typescript
import { Completion } from "@codemirror/autocomplete";
import { AutocompleteCallback } from "./attribute-autocomplete";
import { XMLAttributeAutocomplete } from "./xml-attribute-autocomplete";
/**
* Abstract base class for creating XML attribute autocomplete instances.
* Subclasses should implement the createAutocomplete method to provide
* specific autocomplete configurations.
*/
export abstract class AttributeAutocompleteProvider {
abstract createAutocomplete(): XMLAttributeAutocomplete[];
}
/**
* Zotero-specific implementation of AttributeAutocompleteProvider.
* Creates autocomplete for <ref type="biblio"> target attribute using Zotero API.
*/
export class ZoteroAutocomplete extends AttributeAutocompleteProvider {
private baseUrl: string | null;
constructor(baseUrl: string | null = null) {
super();
this.baseUrl = baseUrl;
}
createAutocomplete(): XMLAttributeAutocomplete[] {
const callback = this.createZoteroAutocompleteCallback();
return [
new XMLAttributeAutocomplete({
elementName: 'ref',
attributeName: 'target',
conditionAttribute: { name: 'type', value: 'biblio' },
callback
}),
new XMLAttributeAutocomplete({
elementName: 'rdg',
attributeName: 'wit',
callback
})
];
}
/**
* Creates an AutocompleteCallback that fetches completions from the Zotero API.
*
* @param baseUrl - Optional base URL for the API. Defaults to empty string (relative URL).
* @returns A function that implements AutocompleteCallback
*/
private createZoteroAutocompleteCallback(): AutocompleteCallback {
return async (query?: string): Promise<Completion[]> => {
try {
// Build the URL with query parameter if provided
let url = `${this.baseUrl || ''}/api/zotero/items/suggest`;
if (query) {
url += `?q=${encodeURIComponent(query)}`;
}
const response = await fetch(url);
if (!response.ok) {
console.error('Failed to fetch Zotero suggestions:', response.status, response.statusText);
return [];
}
const data = await response.json();
let suggestions: Completion[] = [];
// Convert the API response to Completion[] format
if (Array.isArray(data)) {
suggestions = data.map((item: any) => {
return {
displayLabel: item.tag,
detail: item.title,
label: `#${item.tag}`,
type: 'text',
info: () => {
if (!item.bib) {
return null;
}
const span = document.createElement('span');
span.innerHTML = item.bib;
return span;
}
};
});
}
console.log('Zotero suggestions:', suggestions);
return suggestions;
} catch (error) {
console.error('Error fetching Zotero suggestions:', error);
return [];
}
};
}
}