Testen Sie Scrivito 30 Tage lang kostenlos
Testen Sie Scrivito 30 Tage lang kostenlos

Eigene Komponenten für Seiten- und Widget-Eigenschaften nutzen

Eigene Komponenten für Seiten- und Widget-Eigenschaften nutzen

Example App: Icon picker extension

Mit Scrivito können Sie die Bearbeitung von Seiten- und Widget-Eigenschaften um Funktionalität ergänzen, die Sie selber bereitstellen. Die eingebauten Tools, mit denen Texte, Zahlen, Bilder usw. bearbeitet werden können, erfüllen zwar auch gehobene Ansprüche, jedoch sind auch Anwendungsfälle denkbar, in denen Spezialfunktionalität für die Bearbeitung von Inhalten wünschenswert oder erforderlich ist. In solchen Situationen trifft es sich gut, dass die Bedienschnittstelle von Scrivito erweiterbar ist. So enthält beispielsweise die Example App als Scrivito-Erweiterung ein schickes Icon-Widget mit einem leicht zu bedienenden Auswahlmechanismus.

In diesem Tutorial entwickeln wir eine Instagram-Stil-Auswahl als Erweiterung für das ImageWidget der Example App. Damit lässt sich ein Bild in einem ImageWidget mit einem von zahlreichen Instagram-„Filtern“ versehen, um interessante optische Farbeffekte zu erzielen.

Bei Scrivito kann man einen Benutzer eine von mehreren Optionen mittels eines Attributs vom Typ enum wählen lassen. Zwar verfügt Scrivito über ein Bearbeitungselement für enum-Werte, jedoch wird der Eigenschaften-Dialog mit einer zunehmenden Anzahl von Optionen schnell unübersichtlich, so dass es naheliegend ist, dafür eine Erweiterung zu implementieren. Darüber hinaus würden wir gern eine Vorschau des Bildes mit dem anzuwendenden Stil anzeigen.

Das CSS herunterladen und der App zur Verfügung stellen

Zu Beginn benötigen wir die Stile, die bei Bildern auswählbar sein sollen. Sie stammen von Yan Zhu, und Sie können die CSS-Datei direkt bei GitHub herunterladen.

Speichern Sie die CSS-Datei im Verzeichnis „src/assets/stylesheets“ Ihrer App. Öffnen Sie anschließend die Datei „index.scss“ im selben Verzeichnis und fügen Sie die CSS-Datei zu den „imports“ hinzu:

src/assets/stylesheets/index.scss
// ... /* imports ================================================== */ @import "_colors"; @import "bootstrap/bootstrap"; @import "_social_cards"; @import "_grid_layout_editor"; @import "_icon_editor"; @import "instagram"; // ...

Das war es schon! Die Stile können nun verwendet werden.

Ein Attribut zur Image-Widget-Klasse hinzufügen

Um den Namen des ausgewählten Instagram-„Filters“ in Image-Widget-Instanzen speichern zu können, benötigen wir ein Attribut. Öffnen Sie also bitte „src/Widgets/ImageWidget/ImageWidgetClass.js“ und fügen Sie ein Attribut vom Typ enum hinzu. Wir haben es hier instagramStyle genannt und mit den CSS-Klassennamen aus dem Repository belegt:

src/Widgets/ImageWidget/ImageWidgetClass.js
import * as Scrivito from 'scrivito'; const ImageWidget = Scrivito.provideWidgetClass('ImageWidget', { attributes: { image: 'reference', alignment: ['enum', { values: ['left', 'center', 'right'] }], alternativeText: 'string', link: 'link', instagramStyle: ['enum', { values: [ 'filter-1977', 'filter-aden', 'filter-amaro', 'filter-ashby', 'filter-brannan', 'filter-brooklyn', 'filter-charmes', 'filter-clarendon', 'filter-crema', 'filter-dogpatch', 'filter-earlybird', 'filter-gingham', 'filter-ginza', 'filter-hefe', 'filter-helena', 'filter-hudson', 'filter-inkwell', 'filter-kelvin', 'filter-juno', 'filter-lark', 'filter-lofi', 'filter-ludwig', 'filter-maven', 'filter-mayfair', 'filter-moon', 'filter-nashville', 'filter-perpetua', 'filter-poprocket', 'filter-reyes', 'filter-rise', 'filter-sierra', 'filter-skyline', 'filter-slumber', 'filter-stinson', 'filter-sutro', 'filter-toaster', 'filter-valencia', 'filter-vesper', 'filter-walden', 'filter-willow', 'filter-xpro-ii', ] }], }, }); export default ImageWidget;

Der Attributtyp enum stellt sicher, dass in der noch zu schreibenden Komponente nur ein einziger Wert ausgewählt werden kann.

Die Eigenschaften des Image-Widgets erweitern

Die Eigenschaften eines Widgets (oder einer Seite) können mit einem Aufruf von Scrivito.provideEditingConfig in der entsprechenden Datei „*EditingConfig.js“ konfiguriert werden. Lassen Sie uns also die noch nicht existierende Komponente für die Instagram-Stil-Auswahl in die Eigenschaften von Image-Widgets aufnehmen: Fügen Sie ein propertiesGroups-Array mit einem einzelnen Element auf oberster Ebene der Konfiguration ein, so wie hier (unterhalb von properties) gezeigt:

src/Widgets/ImageWidget/ImageWidgetEditingConfig.js
import * as React from 'react'; import { InstagramStyleTab } from 'src/Components/ScrivitoExtensions/InstagramStyleTab' // ... // For attributes on the 'General' tab use: properties: [ 'alignment', 'alternativeText', 'link', ], // For a component rendered on an additional tab use: propertiesGroups: (widget) => [ { title: 'Instagram style', key: 'instagram-style-tab', component: () => <InstagramStyleTab widget={widget} />, }, ],

Jedes vom propertiesGroups-Callback zurückgegebene Element fügt einen Reiter zum Eigenschaften-Dialog hinzu. Neben den Schlüsselwörtern title und key können Sie die zu verwendende Komponente (component) oder die auf dem Reiter bearbeitbaren Attribute (properties) angeben.

Analog zum obigen instagramStyle-Attribut haben wir unsere Komponente InstagramStyleTab genannt. Wenn man eine component für einen Reiter angibt, muss sie sich um sämtliche Bearbeitungsfunktionen darauf kümmern, wohingegen properties von Scrivito gehandhabt werden. (Wenn also ein Widget oder eine Seite mit einer Vielzahl von Attributen ausgestattet ist, können diese auf mehrere Reiter aufgeteilt werden, anstatt den Reiter „Allgemein“ mittels properties auf oberster Ebene zu überfrachten.)

Die Stil-Auswahl-Komponente bereitstellen

Bei der Example App befinden sich die Erweiterungen der Bedienschnittstelle im Verzeichnis „src/Components/ScrivitoExtensions“, wo wir auch unsere Komponente für die Instagram-Stil-Auswahl abgelegt haben:

src/Components/ScrivitoExtensions/InstagramStyleTab.js
import * as React from 'react'; import * as Scrivito from 'scrivito'; export class InstagramStyleTab extends React.Component { constructor(props) { super(props); this.setInstagramStyle = this.setInstagramStyle.bind(this); } setInstagramStyle(event) { const style = event.target.value; this.props.widget.update({ instagramStyle: style === '' ? null : style }); } render() { const InstagramStyles = [ { value: '', title: 'None' }, { value: 'filter-1977', title: '1977' }, { value: 'filter-aden', title: 'Aden' }, { value: 'filter-amaro', title: 'Amaro' }, { value: 'filter-ashby', title: 'Ashby' }, { value: 'filter-brannan', title: 'Brannan' }, { value: 'filter-brooklyn', title: 'Brooklyn' }, { value: 'filter-charmes', title: 'Charmes' }, { value: 'filter-clarendon', title: 'Clarendon' }, { value: 'filter-crema', title: 'Crema' }, { value: 'filter-dogpatch', title: 'Dogpatch' }, { value: 'filter-earlybird', title: 'Earlybird' }, { value: 'filter-gingham', title: 'Gingham' }, { value: 'filter-ginza', title: 'Ginza' }, { value: 'filter-hefe', title: 'Hefe' }, { value: 'filter-helena', title: 'Helena' }, { value: 'filter-hudson', title: 'Hudson' }, { value: 'filter-inkwell', title: 'Inkwell' }, { value: 'filter-kelvin', title: 'Kelvin' }, { value: 'filter-juno', title: 'Kuno' }, { value: 'filter-lark', title: 'Lark' }, { value: 'filter-lofi', title: 'Lo-Fi' }, { value: 'filter-ludwig', title: 'Ludwig' }, { value: 'filter-maven', title: 'Maven' }, { value: 'filter-mayfair', title: 'Mayfair' }, { value: 'filter-moon', title: 'Moon' }, { value: 'filter-nashville', title: 'Nashville' }, { value: 'filter-perpetua', title: 'Perpetua' }, { value: 'filter-poprocket', title: 'Poprocket' }, { value: 'filter-reyes', title: 'Reyes' }, { value: 'filter-rise', title: 'Rise' }, { value: 'filter-sierra', title: 'Sierra' }, { value: 'filter-skyline', title: 'Skyline' }, { value: 'filter-slumber', title: 'Slumber' }, { value: 'filter-stinson', title: 'Stinson' }, { value: 'filter-sutro', title: 'Sutro' }, { value: 'filter-toaster', title: 'Toaster' }, { value: 'filter-valencia', title: 'Valencia' }, { value: 'filter-vesper', title: 'Vesper' }, { value: 'filter-walden', title: 'Walden' }, { value: 'filter-willow', title: 'Willow' }, { value: 'filter-xpro-ii', title: 'X-Pro II' }, ]; const widget = this.props.widget; return ( <div className="scrivito_tab_content"> <div className="scrivito_tab_pane active"> <div className='group'> <div className="scrivito_detail_content"> <div className="scrivito_detail_label"> <span>Style</span> </div> <div className="item_content"> <select value={ widget.get('instagramStyle') || '' } onChange={ this.setInstagramStyle }> { InstagramStyles.map(style => { return ( <option key={ style.value } value={ style.value }> { style.title } </option> ); }) } </select> </div> </div> <div className="scrivito_detail_content"> <div className="item_content"> <Scrivito.ImageTag content={ widget } attribute="image" className={ widget.get('instagramStyle') } /> </div> </div> </div> </div> </div> ); } }

Die Liste der Filternamen befindet sich direkt in der Komponente, jedoch könnten Sie sie auch importieren, um den Code übersichtlich zu halten. Die render-Methode iteriert diese Liste, um daraus option-Elemente innerhalb eines select-Elements zu erzeugen. Jedes option-Tag erhält einen value für die jeweilige wählbare Option, und das select-Tag hat ein onChange-Attribut mit dem bei der Auswahl aufzurufenden Event-Handler.

Der Event-Handler setInstagramStyle aktualisiert das instagramStyle-Attribut des Widgets. Er konvertiert die leere Zeichenkette, die für „Nichts“ steht, zu null, dem Äquivalent für „nichts ausgewählt“ bei enum-Attributen. Im select-Tag wird der aktuelle Wert über die umgekehrte Zuweisung gesetzt, d.h. null wird zur leeren Zeichenkette.

Beachten Sie bitte, dass die Komponente keinen state benötigt, da der ausgewählte Wert direkt in das Widget geschrieben wird, wodurch Scrivito die Widget-Instanz auf der Seite sofort aktualisiert.

Nachdem das select-Element erzeugt wurde, zeigt die render-Methode das Image-Widget unter Verwendung des ausgewählten Stils an, wodurch der Benutzer das Ergebnis seiner Auswahl unmittelbar sehen kann.

Für das Styling des Reiters haben wir die CSS-Klassen des „Social cards“-Reiters der Example App verwendet.

Es geht noch mehr …

Anstatt die Stile mit einem select-Element anzubieten und den ausgewählten Stil auf ein Vorschaubild anzuwenden, könnten Sie für jeden Filter ein klickbares Miniaturbild rendern, damit der Benutzer einen Eindruck von der ganzen Palette der verfügbaren Stile gewinnen kann.

In der obigen Komponente wird Scrivito.ImageTag verwendet, um die Vorschau des Bildes im Widget zu rendern. Im Bearbeitungsmodus wird das Bild dadurch im Content Browser auswählbar. Wenn Sie dies nicht möchten, können Sie stattdessen ein gewöhnliches <img>-Element verwenden:

<img src={ widget.get('image').contentUrl() } className={ widget.get('instagramStyle') } />