Icons-Panelwindow.EasySvgPanel.registerCollections

window.EasySvgPanel.registerCollections()

Lässt ein Add-on eigene Icon-Sammlungen im Tab Icon-Bibliothek neben den Icons der Site auflisten und sie wahlweise verschieben, umbenennen oder exportieren.

JavaScript · Easy SVG · Status: Stabil

Mit registerCollections() zeigt dein Add-on seine eigenen Icons im Tab Icon-Bibliothek von Easy SVG. Du übergibst einen Anbieter: ein Objekt mit einer ID und einer load-Funktion, die deine Sammlungen liefert. Die Bibliothek listet sie in ihrer Seitenleiste, packt ihre Icons ins selbe Raster und in dieselbe Suche wie die Icons der Site und bietet Bearbeitungsaktionen nur für das an, was dein Anbieter umsetzt.

Verwendung

window.EasySvgPanel.registerCollections( {
	id: 'myaddon', // Pflicht
	load: ( { signal } ) => Promise.resolve( collections ), // Pflicht

	// Alles optional:
	move, create, rename, trash,
	relabel, remove, add, recolour, replaceDrawing,
	importFile, addMedia,
	history, restoreVersion,
	exportIcons, exportMax,
	hint,
} );

Wann du es brauchst

  • Dein Add-on hat eigene Icons (einen Theme-Ordner, ein mitgeliefertes Icon-Set, Sets in einem eigenen Beitragstyp), und die Leute sollen sie dort finden, wo sie ohnehin nach Icons suchen.
  • Du willst Suche, Raster und Kopierknöpfe der Bibliothek für diese Icons, ohne einen eigenen Tab zu bauen.
  • Dein Add-on soll auch auf Sites mit dem freien Plugin allein laufen. Anders als bei registerTab() hängen Sammlungen nicht an einer Lizenz von Easy SVG Pro.

Wann nicht:

  • Um Icons im Frontend auszugeben. Das machen easy_svg_icon() und der Filter easy_svg_icon_markup in PHP. Das Panel zeigt nur an, was du ihm gibst.
  • Um die eigenen Bibliotheks-Icons der Site zu ändern. Dafür sind die REST-Routen von Easy SVG zuständig.
  • Wenn das Panel älter als Vertragsstufe 3 ist: Dort gibt es die Methode nicht.

Parameter

body
provider.idstring
Required

Eine eindeutige ID für deinen Anbieter. Ein zweiter Aufruf mit derselben ID ersetzt den Anbieter. Stell ihr den Slug deines Add-ons voran.

body
provider.loadfunction
Required

Wird als load( { signal } ) aufgerufen und muss ein Array von Sammlungen liefern, oder ein Promise darauf. signal ist ein AbortSignal; gib es an fetch() weiter, denn die Bibliothek bricht ein laufendes Laden ab, wenn sie ein neues startet oder der Tab schließt. Jede Sammlung ist ein Objekt mit:

  • id (String, Pflicht): eindeutig über alle Anbieter. Nimm nicht all oder library, das sind die eigenen Ansichten der Bibliothek.
  • label (String): der Name in der Seitenleiste. Ohne Angabe die ID.
  • readonly (Boolean): ist es wahr, wird für diese Sammlung und ihre Icons keine Aktion angeboten.
  • icons (Array, Pflicht): die Icons, jedes mit key (eindeutiger Schlüssel der Kachel, ohne Angabe ref), slug, ref (die Adresse, die ein Template nutzt, in der Form sammlung/slug), label und content (das SVG-Markup, von dir schon bereinigt und gehärtet).

Weitere Felder, die du einer Sammlung mitgibst, etwa eine Beitrags-ID, bekommst du im Argument collection der optionalen Methoden unverändert zurück.

body
provider.movefunction

move( { refs, to } ), aufgerufen, wenn Kacheln auf einer deiner nicht schreibgeschützten Sammlungen abgelegt oder über das Kachelmenü dorthin geschickt werden. refs ist ein Array mit bis zu 25 Refs (größere Auswahlen kommen in Portionen), to die ID der Zielsammlung. Lös auf mit { message, undo }; undo ist optional und liefert ein Promise auf { message }.

body
provider.create, rename, trashfunction

Sammlungen über die Seitenleiste verwalten. create( { label } ) löst mit { id, message } auf, und die Bibliothek wechselt zur neuen ID. rename( { id, label, collection } ) löst mit { message } auf. trash( { id, collection } ) löst mit { message, undo } auf. Nur der erste Anbieter mit create bekommt das Bedienelement für eine neue Sammlung.

body
provider.relabel, remove, add, recolour, replaceDrawingfunction

Arbeiten an den Icons innerhalb einer Sammlung. relabel( { ref, label, collection } ), remove( { refs, collection } ) (mit Rückgängig statt Rückfrage), add( { icons, to, collection } ), wobei icons eine Liste aus name und markup ist (Dateien, die bei offener Sammlung abgelegt, gewählt oder eingefügt werden, landen hier), recolour( { refs, collection } ) und replaceDrawing( { ref, markup, collection } ). Jede löst mit { message } auf, wahlweise mit undo; add darf zusätzlich rows liefern, eine Liste pro Datei aus file, ok und message.

body
provider.importFile, addMediafunction

importFile( { file, collection } ) bekommt ein ZIP oder eine SVG-Schrift (eine Datei mit glyph-Elementen), die auf einer offenen Sammlung abgelegt wird. addMedia( { ids, collection } ) bekommt Anhang-IDs aus der Mediathek. Beide lösen auf wie add.

body
provider.history, restoreVersionfunction

Frühere Zeichnungen eines Icons. history( { ref, collection } ) löst mit { versions, note } auf, jede Version mit id, date, since, markup und current. restoreVersion( { ref, version, collection } ) löst mit { message } auf. Beide müssen da sein, damit die Aktion erscheint. Bei Icons aus der eigenen Bibliothek der Site ist collection gleich null, und gefragt wird der erste Anbieter mit beiden Methoden.

body
provider.exportIcons, exportMaxfunction, number

exportIcons( { refs } ) exportiert die gewählten Kacheln aus beliebigen Sammlungen und liefert die Datei selbst aus; lös mit { message } auf. Mit einem endlichen exportMax wird Export nicht angeboten, wenn mehr Kacheln gewählt sind. Genutzt wird nur der erste Anbieter mit exportIcons.

body
provider.hintobject

Ein Hinweis in der Seitenleiste, etwa wenn eine Funktion, die deine Sammlungen brauchen, ausgeschaltet ist: { text, action: { label, run } }, wobei run ein Promise liefert. Die Aktion ist optional.

Rückgabewert

returnundefined

Nichts. Ein Anbieter ohne id oder ohne load-Funktion wird still ignoriert.

Standardwert

Das freie Plugin registriert keine Anbieter. Ohne readonly gilt eine Sammlung als beschreibbar, die Bibliothek bietet aber trotzdem nur die Aktionen an, deren Methoden existieren.

Beispiele

Eine schreibgeschützte Sammlung aus festen Daten

Das Minimum: eine Sammlung, zwei Icons, nichts bearbeitbar. Das Markup ist hier fest und schon sauber.

( function () {
	const panel = window.EasySvgPanel;
	if ( ! panel || 'function' !== typeof panel.registerCollections ) {
		return;
	}

	const icons = [
		{
			key: 'myaddon-brand/logo',
			slug: 'logo',
			ref: 'myaddon-brand/logo',
			label: 'Logo',
			content: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/></svg>',
		},
		{
			key: 'myaddon-brand/mark',
			slug: 'mark',
			ref: 'myaddon-brand/mark',
			label: 'Mark',
			content: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 20 12 4l8 16z"/></svg>',
		},
	];

	panel.registerCollections( {
		id: 'myaddon',
		load: () => [ { id: 'myaddon-brand', label: 'Brand', readonly: true, icons } ],
	} );
} )();

Sammlungen von deiner REST-Route laden

Ein echter Anbieter fragt den Server, reicht das Abbruchsignal weiter und hält die Antwort im Cache, denn load() läuft jedes Mal, wenn die Bibliothek öffnet, und jedes Mal, wenn irgendetwas registriert wird.

( function () {
	const panel = window.EasySvgPanel;
	if ( ! panel || 'function' !== typeof panel.registerCollections ) {
		return;
	}

	const config = window.EasySvgPanelData || {};
	let cache = null;

	function request( path, options = {} ) {
		return fetch( config.restRoot + 'myaddon/v1' + path, {
			credentials: 'same-origin',
			...options,
			headers: {
				'Content-Type': 'application/json',
				'X-WP-Nonce': config.nonce,
			},
		} ).then( ( response ) =>
			response.json().then( ( data ) =>
				response.ok ? data : Promise.reject( new Error( data.message || response.statusText ) )
			)
		);
	}

	panel.registerCollections( {
		id: 'myaddon',
		load: ( { signal } ) => {
			if ( cache ) {
				return Promise.resolve( cache );
			}
			return request( '/collections', { signal } ).then( ( list ) => {
				cache = list;
				return list;
			} );
		},
		relabel: ( { ref, label } ) => {
			cache = null;
			return request( '/relabel', {
				method: 'POST',
				body: JSON.stringify( { ref, label } ),
			} );
		},
	} );
} )();

window.EasySvgPanelData sind die lokalisierten Daten des Panels selbst; liest du restRoot und nonce daraus, musst du sie nicht noch einmal lokalisieren. Deine Routen müssen bei Aktionen { message } antworten und die Berechtigungen selbst prüfen.

Verschieben annehmen, mit Rückgängig

move() bekommt Refs von Kacheln aus der ganzen Bibliothek. Gib ein undo zurück, wenn du das Verschieben umkehren kannst.

window.EasySvgPanel.registerCollections( {
	id: 'myaddon',
	load: myaddonLoad,
	move: async ( { refs, to } ) => {
		const done = await myaddonPost( '/move', { refs, to } );
		return {
			message: done.message,
			undo: () => myaddonPost( '/move-back', { token: done.token } ),
		};
	},
} );

Defensiv: nur ab Vertragsstufe 3

( function () {
	const panel = window.EasySvgPanel;
	const level = panel ? Number( panel.api || 1 ) : 0;

	if ( 3 > level || 'function' !== typeof panel.registerCollections ) {
		return; // Älteres Panel: keine Sammlungen in der Bibliothek.
	}

	panel.registerCollections( { id: 'myaddon', load: () => [] } );
} )();

So funktioniert es

Die ganze Arbeit macht der Tab Icon-Bibliothek (src/panel/tabs/Library.jsx):

  1. Wann er lädt. Beim Einhängen und bei jeder Benachrichtigung der Registry (jeder Aufruf von registerTab() oder registerCollections()) bricht der Tab das vorige Laden ab und ruft load( { signal } ) bei jedem Anbieter auf, eingepackt in Promise.resolve().
  2. Was er behält. Ein Ergebnis, das kein Array ist, zählt als keine Sammlungen, ein abgelehntes Promise wird genauso verschluckt. Sammlungen ohne id oder ohne icons-Array fallen weg. Jede behaltene Sammlung merkt sich ihren Anbieter.
  3. Die Seitenleiste. Sie erscheint, sobald es eine Sammlung, einen Anbieter mit create oder einen hint gibt. Sie listet Alle Icons, Icon-Bibliothek und dann jede Sammlung mit ihrer Icon-Zahl. Ein hint irgendeines Anbieters wird dort gezeigt.
  4. Raster und Suche. Unter Alle Icons teilen sich die Icons der Bibliothek und die aller Sammlungen ein Raster; wählst du eine Sammlung, siehst du nur ihre Icons. Die Suche filtert deine Icons im Browser nach label, slug und ref. Kacheln werden nach key geschlüsselt, sonst nach ref.
  5. Zeichnen. Dein content wird als Markup gezeichnet, nach einem zweiten Durchlauf durch DOMPurify mit dessen SVG-Profil, als zusätzliche Absicherung.
  6. Aktionen. Eine Aktion erscheint nur, wenn dein Anbieter die Methode hat und die Sammlung nicht readonly ist. Die Bibliothek wartet auf dein Promise, zeigt seine message (oder „Erledigt.“), bietet Rückgängig an, wenn du undo geliefert hast, zeigt error.message, wenn du abgelehnt hast, und lädt danach alle Sammlungen neu.

Den Tab Icon-Bibliothek sehen nur Benutzer mit seiner Berechtigung (standardmäßig manage_options), und sein Inhalt erscheint nur, solange die Icon-Bibliothek eingeschaltet ist. Ist sie aus, zeigt der Tab stattdessen einen Hinweis. Dein load() wird beim Öffnen des Tabs trotzdem aufgerufen, von seiner Antwort ist aber nichts zu sehen.

Stolperfallen

  • load() läuft oft. Jedes Mal, wenn die Bibliothek öffnet, und jedes Mal, wenn irgendein Add-on etwas registriert. Nutz einen Cache und gib signal an deine Anfragen weiter.
  • Fehler in load() verschwinden. Eine Ablehnung zeigt einfach keine Sammlungen. Log den Fehler beim Entwickeln selbst.
  • Sammlungs-IDs müssen eindeutig sein, über alle Anbieter hinweg, und dürfen nicht all oder library heißen.
  • Halte Refs in der Form sammlung/slug. Beim Verschieben werden Refs, die schon mit der Ziel-ID und einem Schrägstrich beginnen, als „schon dort“ übersprungen.
  • Bereinige auf dem Server. Der DOMPurify-Durchlauf des Panels ist ein Sicherheitsnetz, nicht dein Sanitizer. Säubere Markup mit easy_svg_sanitizer(), bevor du es schickst.
  • readonly schaltet alles ab für diese Sammlung, auch das Verschieben hinein.
  • Ein Exporteur, ein Ersteller. Setzen mehrere Anbieter exportIcons oder create um, wird nur der zuerst registrierte genutzt.
  • Aus heißt aus. Ist die Icon-Bibliothek unter Einstellungen ausgeschaltet, werden deine Sammlungen gar nicht gezeigt und dein hint auch nicht, obwohl load() weiter läuft.

Markup, das du als content, markup oder in Versionen von history lieferst, wird in eine Admin-Seite eingefügt. Gib nur SVG weiter, das durch den Sanitizer der Site gelaufen ist, und lass jeden Endpunkt hinter move, add, remove und den anderen Methoden current_user_can() und die wp_rest-Nonce prüfen. Die Bibliothek bietet eine Aktion anhand deines JavaScripts an, Berechtigungen prüft sie für dich nicht.

Siehe auch