astember
Returning Observer

Absätze im ContentCreator seitenübergreifend kopieren über DAP

Hallo zusammen,

soweit mir bekannt ist gibt es bisher im ContentCreator noch keine Funktion um existierende Absätze seitenübergreifend aus der Inhalteverwaltung zu kopieren oder zu referenzieren.

Ich habe nun die Idee über ein Data Access Plugin den Nutzer eine Liste von Standardabsätzen oder eine Suchfunktion, die Absatzinhalte unterstützt, bereitzustellen. Mit Hilfe von Drag&Drop können die Absätze dann in unterstützte Inhaltsbereiche eingefügt werden. In der ersten Ausbaustufe reicht dies als Kopie. In der zweiten Ausbaustufe würde ich noch eine Art Auswahldialog implementieren, ob eine Kopie oder Referenz des Absatz in den Inhaltsbereich eingefügt werden soll.

Gibt es ggf. bereits Codebeispiele, welches das Data Access Plugin im Zusammenspiel mit Absatzinhalten verwenden? Die Beispiele die ich bisher gefunden habe wenden DAP eher auf Basis von Fremdinhalten, REST-APIs oder Datenquellen an.

0 Kudos
5 Replies
bIT_sosswald
Returning Responder

Hallo Andre,

wenn der Redakteur einen Absatz als "Master" markiert geht das.

300411_pastedImage_1.png300412_pastedImage_2.png

Auf einer anderen Seite kannst du dann den Master wieder einfügen.

300413_pastedImage_3.png

Oder meinst du evtl. doch etwas anderes?

Grüße

Sandro

0 Kudos

Danke für die Info. Das Feature (Bei mir lediglich im Tooltip als "Bookmark" bezeichnet) hatte ich bisher noch gar nicht in diesem Zusammenhang genutzt (wieder was dazugelernt Smiley Happy). Laut meinen Tests lässt sich der Anwendungsfall für das Kopieren von Absatz-Inhalten aus einer Art Vorlagen-Seite mit dieser Möglichkeit gut umsetzen. Referenzierte Absätze lassen sich jedoch damit m.E. trotzdem nicht abbilden. (oder muss die "Master"-Funktion speziell konfiguriert werden?) Eine DAP wäre damit aus meiner Sicht gar nicht notwendig. Die Frage wäre ob und wie man das Standardverhalten des Buttons "Add section" erweitern/anpassen kann, so dass der Absatz (siehe Screen) als "Referenzvorlage" o.ä. erscheint. Alternativ müsste man vermutlich einen benutzerdefinierten Button entwicklen, welcher das gewünschte Verhalten ("Absatz als Referenz einfügen") simuliert

300414_pastedImage_1.png

0 Kudos

Hallo Andre,

zum Thema „referenzieren“: Sowas habe ich schon öfters genutzt, ist eigentlich recht schnell gemacht. Grundlage ist dabei auch der von Sandro erwähnte Favoriten-Mechanismus, das Anlegen von Absätzen bzw Absatzreferenzen passiert dann aber über den normalerweise auf der Seite vorhandenen FS_BUTTON - siehe  Online Dokumentation FirstSpirit - ContentCreator – Voraussetzungen. Wenn man auf den einen Absatz aus dem Favoritenreport zieht, wird eine Kopie erstellt - dazu muss das Beispiel (der Button) aus der Doku nur erweitert werden um

ondrop="class:NewSection". Als Droptype muss man wenn ich mich richtig erinnere einen IDProvider eintragen (da bin ich mir aus dem Kopf gerade nicht mehr sicher).

Das zeigt, dass das mitgelieferte Executable das „Kopieren“ sogar schon kann.

Die Idee ist jetzt, beim ondrop eben nicht direkt die eingebaute Funktion zu nutzen, sondern ein eigenes Executable quasi „dazwischenzuschalten“, das du statt „class:NewSection“ beim ondrop hinterlegst. Hier kannst du recht einfach eine kleine Abfrage einbauen, ob überhaupt ein Absatz gedroppt wurde und wennja, ob der Absatz als Kopie oder Referenz eingefügt werden soll (RequestOperation mit einem Button für „als Kopie“ und einem für „als Referenz“). Du musst dann nur den Fall „als Referenz“ selber implementieren, für den Fall „als Kopie“ (bzw. technisch eher „nimm den Default“) gibt es seit einiger Zeit  NewSectionOperation#delegateContext:

NewSectionOperation (FirstSpirit Developer-API)

Die ist genau für solche Fälle gedacht, einen eigenen Sonderfall (hier eben die Möglichkeit auch eine Referenz zu erzeugen) „dazwischenzuhängen“, wenn der aber nicht zutrifft alles 1:1 an die Standardfunktion zu delegieren.

Vorteil von delegateContext ist hier, dass die Standardfunktion auch dann nicht kaputt geht bzw. du auch später keinen weiteren Glue-Code hinzufügen musst, wenn es zukünftig mal weitere Parameter für die Standardfunktion geben sollte.

Wichtig ist natürlich genau darum, auch in allen anderen Fällen - also wenn kein Absatz gedroppt wurde - zu delegieren (Stichwort DropEditor wie z.B. zum Anlegen von Absätzen durch drop von Medien oder anderen Elementen).

Viele Grüße

Michael

0 Kudos

Klingt auf jeden Fall nach einen stabilen Lösungsvorschlag. Sobald ich Zeit finde werde ich das mal genauer in unserer Sandbox ausprobieren.

0 Kudos

Hallo zusammen,

ich bin mir noch unschlüssig, wie ich das interface "NewSectionOperation" richtig benutze.

Ich habe mal folgenden Beispielcode zum Ausprobieren im ContentCreator als ausführbares Beanshell-Script angelegt:

import de.espirit.firstspirit.agency.StoreAgent;

import de.espirit.firstspirit.agency.OperationAgent;

import de.espirit.firstspirit.agency.OperationType;

import de.espirit.firstspirit.webedit.server.NewSectionOperation;

import de.espirit.firstspirit.access.store.Store;

OperationAgent operationAgent = context.requireSpecialist(OperationAgent.TYPE);

NewSectionOperation newSectionOperation = operationAgent.getOperation(NewSectionOperation.TYPE);

if (sectionId == void)

  throw new IllegalArgumentException("Missing Parameter 'sectionId'");

sectionId = Long.parseLong("" + sectionId);

section = context.requireSpecialist(StoreAgent.TYPE)

            .getStore(Store.Type.PAGESTORE)

            .getStoreElement(sectionId);

newSectionOperation.delegateContext(context);

Beim Aufruf aus dem OCM ContentCreator Button, erhalte ich folgende Fehlermeldung:

Called from method: __execute

        at bsh.BSHMethodInvocation.eval(BSHMethodInvocation.java:78) ~[fs-isolated-webrt.jar:78859]

        at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:102) ~[fs-isolated-webrt.jar:78859]

        at bsh.BSHPrimaryExpression.eval(BSHPrimaryExpression.java:47) ~[fs-isolated-webrt.jar:78859]

        at bsh.BSHBlock.evalBlock(BSHBlock.java:130) ~[fs-isolated-webrt.jar:78859]

        at bsh.BSHBlock.eval(BSHBlock.java:80) ~[fs-isolated-webrt.jar:78859]

        at bsh.BshMethod.invokeImpl(BshMethod.java:371) ~[fs-isolated-webrt.jar:78859]

        at bsh.BshMethod.invoke(BshMethod.java:267) ~[fs-isolated-webrt.jar:78859]

        at bsh.BshMethod.invoke(BshMethod.java:170) ~[fs-isolated-webrt.jar:78859]

        at bsh.PreparsedScript.invoke(PreparsedScript.java:66) ~[fs-isolated-webrt.jar:78859]

        at de.espirit.firstspirit.server.script.BeanshellScriptEngine$BeanshellExecutable.execute(BeanshellScriptEngine.java:100) ~[fs-isolated-webrt.jar:78859]

        ... 21 common frames omitted

Caused by: bsh.ReflectError: Method delegateContext(de.espirit.firstspirit.webedit.server.workflow.WebeditScriptContextImpl) not found in class'de.espirit.firstspirit.webedit.server.operations.NewSectionOperationImpl'

        at bsh.Reflect.resolveExpectedJavaMethod(Reflect.java:414) ~[fs-isolated-webrt.jar:78859]

        at bsh.Reflect.invokeObjectMethod(Reflect.java:116) ~[fs-isolated-webrt.jar:78859]

        at bsh.Name.invokeMethod(Name.java:858) ~[fs-isolated-webrt.jar:78859]

        at bsh.BSHMethodInvocation.eval(BSHMethodInvocation.java:75) ~[fs-isolated-webrt.jar:78859]

        ... 30 common frames omitted

Wenn ich es richtig verstehe gilt der "context" in Zusammenhang mit der "delegateContext"-Methode nur im Zusammenspiel mit einem FS_BUTTON.

Im Falle des Omnichannel-Managers wird der "Button" aber über die TPP_SNAP API bereitgestellt:

Folgendes Beispiel funktioniert.

          TPP_SNAP.registerButton({

            "label": "add reference section",

            "css": "tpp-icon-add-section",

            isVisible: ({ status }) => status.custom === null && status.elementType === 'Section',

            isEnabled: async ({ $node }) => {

              const siblings = await findFsSections($node.parentNode);

              const index = siblings.findIndex(({ $el }) => $el === $node);

              return index !== siblings.length - 1;

            },

            execute: async () => TPP_SNAP.execute('class:NewSection', {page: "standard_page_text_image", body: "content_main", store: "pagestore", reload: "content_main"}),

          });

Ich würde gern probeweise das "execute" mit einem Beanshell Script koppeln und die entsprechenden Parameter per "delegate" an die Standardfunktionalität "NewSection" binden. Reicht es dafür die Parameter aus dem o.g. Beispiel per Java Map zu übergeben?

Update:

Leider lässt sich der Ansatz mit "onDrop" im OCM Umfeld so nicht umsetzen. Gründe hierfür sind bestimmte Probleme im D&D zwischen Fenstern von OCM und ContentCreator, die mit dem CORS-Policies moderner Browser zusammenhängen. Eine alternative Idee wäre über eine OCM Funktion der Snap API (fs-tpp-api/snap 1.2.20 | Documentation​) ein drop down mit einer Liste der als Favoriten markierten Absätze anzubieten, die für den Contentbereich anwendbar sind. Leider benötigt man hierfür einen Zugriffspunkt zu den Bookmars. Intern gibt es einen Agent dafür (de.espirit.firstspirit.client.bookmark.BookmarkAgent), leider hat der es nie in die API geschafft.

0 Kudos