[MGNLUI-4419] Allow RichTextFieldFactory to link to any workspace Created: 17/Apr/18 Updated: 08/Mar/21 |
|
| Status: | Open |
| Project: | Magnolia UI |
| Component/s: | forms |
| Affects Version/s: | 5.6.4, 6.2 |
| Fix Version/s: | None |
| Type: | Improvement | Priority: | Neutral |
| Reporter: | Adrien Manzoni | Assignee: | Unassigned |
| Resolution: | Unresolved | Votes: | 2 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||
| Template: |
|
||||
| Acceptance criteria: |
Empty
|
||||
| Task DoD: |
[ ]*
Doc/release notes changes? Comment present?
[ ]*
Downstream builds green?
[ ]*
Solution information and context easily available?
[ ]*
Tests
[ ]*
FixVersion filled and not yet released
[ ] 
Architecture Decision Record (ADR)
|
||||
| Date of First Response: | |||||
| Description |
|
In a RichTextField, the users have the possibility to add links to a website node or to a DAM node. If we want to create links to another workspaces, we need to create a custom field type and duplicate half of the methods. It would be great to have the mapping workspace -> app name available in the definition of the form field, so we can configure it in yaml. |
| Comments |
| Comment by Chris Jennings [ 07/Oct/19 ] |
|
Another client has raised this and has suggested this replacement method with an accompanying addAcceptedWorkspaceToApp method.
private String mapWorkSpaceToApp(String workspace) { for (final var workspaceToAppMapping : workspaceToAppMappings) { if (workspace.equalsIgnoreCase(workspaceToAppMapping.workspace)) { return workspaceToAppMapping.app; } } throw new IllegalArgumentException(workspace + " is not a supported workspace by rich text field"); }
|
| Comment by Michael Fosgerau [ 07/Oct/19 ] |
|
Here's a workaround implementation until this gets into the official magnolia code: public class SgRichTextFieldFactory extends RichTextFieldFactory { private static final Logger log = LoggerFactory.getLogger(SgRichTextFieldFactory.class); private final SimpleTranslator i18n; private final ChooserController chooserController; private final AppDescriptorRegistry appDescriptorRegistry; private MagnoliaCKEditorTextField richTextEditor; private List<WorkspaceToAppMapping> workspaceToAppMappings; public SgRichTextFieldFactory(RichTextFieldDefinition definition, ComponentProvider componentProvider, SimpleTranslator i18n, ChooserController chooserController, AppDescriptorRegistry appDescriptorRegistry) { super(definition, componentProvider, i18n, chooserController, appDescriptorRegistry); this.i18n = i18n; this.chooserController = chooserController; this.appDescriptorRegistry = appDescriptorRegistry; workspaceToAppMappings = new ArrayList<>(); addAcceptedWorkspaceToApp(RepositoryConstants.WEBSITE,"pages"); addAcceptedWorkspaceToApp("dam","assets"); } @Override protected Component createFieldComponent() { MagnoliaCKEditorConfig config = initializeCKEditorConfig(); richTextEditor = new MagnoliaCKEditorTextField(config); if (getDefinition().getHeight() > 0) { richTextEditor.setHeight(getDefinition().getHeight(), Sizeable.Unit.PIXELS); } richTextEditor.addListener((eventName, value) -> { if (eventName.equals(EVENT_GET_MAGNOLIA_LINK)) { try { Gson gson = new Gson(); RichTextFieldFactory.PluginData pluginData = gson.fromJson(value, RichTextFieldFactory.PluginData.class); openLinkDialog(pluginData.path, pluginData.workspace); } catch (Exception e) { log.error("openLinkDialog failed", e); richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, i18n.translate("ui-framework.richtexteditorexception.opentargetappfailure")); } } }); return richTextEditor; } protected MagnoliaCKEditorConfig initializeCKEditorConfig() { MagnoliaCKEditorConfig config = new MagnoliaCKEditorConfig(); String path = VaadinService.getCurrentRequest().getContextPath(); // MAGNOLIA LINK PLUGIN — may be used with/without customConfig config.addExternalPlugin(PLUGIN_NAME_MAGNOLIALINK, path + PLUGIN_PATH_MAGNOLIALINK); config.addListenedEvent(EVENT_GET_MAGNOLIA_LINK); // CUSTOM CONFIG.JS — bypass further config because it can't be overridden otherwise if (StringUtils.isNotBlank(getDefinition().getConfigJsFile())) { config.addExtraConfig("customConfig", "'" + path + getDefinition().getConfigJsFile() + "'"); return config; } // DEFINITION if (!getDefinition().isAlignment()) { config.addToRemovePlugins("justify"); } if (!getDefinition().isImages()) { config.addToRemovePlugins("image"); } if (!getDefinition().isLists()) { // In CKEditor 4.1.1 enterkey depends on indent which itself depends on list config.addToRemovePlugins("enterkey"); config.addToRemovePlugins("indent"); config.addToRemovePlugins("list"); } if (!getDefinition().isSource()) { config.addToRemovePlugins("sourcearea"); } if (!getDefinition().isTables()) { config.addToRemovePlugins("table"); config.addToRemovePlugins("tabletools"); config.addToRemovePlugins("tableselection"); } if (getDefinition().getColors() != null) { config.addExtraConfig("colorButton_colors", "'" + getDefinition().getColors() + "'"); config.addExtraConfig("colorButton_enableMore", "false"); config.addToRemovePlugins("colordialog"); } else { config.addToRemovePlugins("colorbutton"); config.addToRemovePlugins("colordialog"); } if (getDefinition().getFonts() != null) { config.addExtraConfig("font_names", "'" + getDefinition().getFonts() + "'"); } else { config.addExtraConfig("removeButtons", "'Font'"); } if (getDefinition().getFontSizes() != null) { config.addExtraConfig("fontSize_sizes", "'" + getDefinition().getFontSizes() + "'"); } else { config.addExtraConfig("removeButtons", "'FontSize'"); } if (getDefinition().getFonts() == null && getDefinition().getFontSizes() == null) { config.addToRemovePlugins("font"); config.addToRemovePlugins("fontSize"); } // MAGNOLIA EXTRA CONFIG List<MagnoliaCKEditorConfig.ToolbarGroup> toolbars = initializeToolbarConfig(); config.addToolbarLine(toolbars); config.addToExtraPlugins(PLUGIN_NAME_MAGNOLIALINK); config.addToRemovePlugins("elementspath"); config.setBaseFloatZIndex(10000); config.setResizeEnabled(false); return config; } protected List<MagnoliaCKEditorConfig.ToolbarGroup> initializeToolbarConfig() { return defaultToolbar(); } public void addAcceptedWorkspaceToApp(final String workspace, final String app) { try { sgMapWorkspaceToApp(workspace); log.debug("Mapping was already added from {} to {}", workspace, app); } catch (final IllegalArgumentException ex) { final var mapping = new WorkspaceToAppMapping(); mapping.setWorkspace(workspace); mapping.setApp(app); workspaceToAppMappings.add(mapping); } } private String mapWorkSpaceToApp(final String workspace) { for (final var workspaceToAppMapping : workspaceToAppMappings) { if (workspace.equalsIgnoreCase(workspaceToAppMapping.workspace)) { return workspaceToAppMapping.app; } } throw new IllegalArgumentException(workspace + " is not a supported workspace by rich text field"); } private void openLinkDialog(String path, String workspace) { chooserController.openChooser(createChooserDefinition(workspace), SessionUtil.getNode(path, workspace)) .whenComplete((ChooserController.ChooseResult<Node> result, Throwable e) -> { if (!result.isChosen()) { richTextEditor.firePluginEvent(EVENT_CANCEL_LINK); return; } if (e != null) { String error = i18n.translate("ui-framework.richtexteditorexception.cannotaccessselecteditem"); log.error(error, e); richTextEditor.firePluginEvent(EVENT_CANCEL_LINK, error); } result.getChoice().ifPresent(node -> { Gson gson = new Gson(); RichTextFieldFactory.MagnoliaLink mlink = createMagnoliaLink(node); richTextEditor.firePluginEvent(EVENT_SEND_MAGNOLIA_LINK, gson.toJson(mlink)); }); }); } private RichTextFieldFactory.MagnoliaLink createMagnoliaLink(Node node) { RichTextFieldFactory.MagnoliaLink mlink = new RichTextFieldFactory.MagnoliaLink(); try { mlink.identifier = node.getIdentifier(); mlink.repository = node.getSession().getWorkspace().getName(); mlink.path = node.getPath(); mlink.caption = PropertyUtil.getString(node, "title", node.getName()); } catch (final RepositoryException ex) { log.error("Failed to get linked node {}", node, ex); } return mlink; } private ChooserDefinition<Node, SingleItemWorkbenchChooser<Node>> createChooserDefinition(String workspace) { SingleItemWorkbenchChooserDefinition<Node> definition = new SingleItemWorkbenchChooserDefinition<>(); AppAwareWorkbenchChooserDefinition<Node> workbenchChooserDefinition = new AppAwareWorkbenchChooserDefinition<>(appDescriptorRegistry); workbenchChooserDefinition.setAppName(mapWorkSpaceToApp(workspace)); definition.setWorkbenchChooser(workbenchChooserDefinition); return definition; } /** * Link info wrapper. */ public static class MagnoliaLink { public String identifier; public String repository; public String path; public String caption; } /** * Plugin data wrapper. */ public static class PluginData { public String workspace; public String path; } /** * Mapping class between a workspace and an app. */ public static class WorkspaceToAppMapping { public String workspace; public String app; } } |
| Comment by Samuli Saarinen [ 05/Feb/21 ] |
|
This is still an issue with Magnolia 6.2.5+ RichTextFieldFactory. Even making RichTextFieldFactory#mapWorkspaceToChooserDialog from private -> protected would allow easier extensibility. |