Work on the text editor.

pull/10/head
Jens Pelzetter 2021-08-23 21:29:26 +02:00
parent 55fd96523d
commit df4cab4b5c
7 changed files with 1528 additions and 1214 deletions

View File

@ -129,7 +129,7 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep {
} }
if (itemPermissionChecker.canEditItem(getArticle())) { if (itemPermissionChecker.canEditItem(getArticle())) {
return "org/librecms/ui/contenttypes/article/article-text.xhtml"; return "org/librecms/ui/contenttypes/article/article-text/available-languages.xhtml";
// return "org/librecms/ui/contenttypes/article/article-text/available-languages.xhtml"; // return "org/librecms/ui/contenttypes/article/article-text/available-languages.xhtml";
} else { } else {
return documentUi.showAccessDenied( return documentUi.showAccessDenied(
@ -165,7 +165,6 @@ public class MvcArticleTextBodyStep extends AbstractMvcAuthoringStep {
// public String getSelectedLocale() { // public String getSelectedLocale() {
// return selectedLocale; // return selectedLocale;
// } // }
/** /**
* Adds a localized main text. * Adds a localized main text.
* *

View File

@ -9,7 +9,7 @@
<cc:interface <cc:interface
shortDescription="A editor component for HTML texts using the TipTap editor. To use this component you have also to include the cms-editor.js file into the page." shortDescription="A editor component for HTML texts using the TipTap editor. To use this component you have also to include the cms-editor.js file into the page."
> >
<cc:attribute <!-- <cc:attribute
name="addMethod" name="addMethod"
required="true" required="true"
shortDescription="URL of teh endpoint for adding localized values." shortDescription="URL of teh endpoint for adding localized values."
@ -56,6 +56,12 @@
required="false" required="false"
shortDescription="Title for the dialog." shortDescription="Title for the dialog."
type="String" type="String"
/>-->
<cc:attribute
name="backUrl"
required="true"
shortDescription="The back URL."
type="String"
/> />
<cc:attribute <cc:attribute
name="canEdit" name="canEdit"
@ -64,13 +70,13 @@
shortDescription="Can the current user edit the text?" shortDescription="Can the current user edit the text?"
type="boolean" type="boolean"
/> />
<cc:attribute <!-- <cc:attribute
name="editButtonLabel" name="editButtonLabel"
default="#{CmsAdminMessages['edit_button.label']}" default="#{CmsAdminMessages['edit_button.label']}"
required="false" required="false"
shortDescription="Label for the edit button" shortDescription="Label for the edit button"
type="String" type="String"
/> />-->
<cc:attribute <cc:attribute
name="editDialogCancelLabel" name="editDialogCancelLabel"
default="#{CmsAdminMessages['cancel_button.label']}" default="#{CmsAdminMessages['cancel_button.label']}"
@ -112,12 +118,12 @@
shortDescription="URL of the endpoint for editing/updating a value. The value of the locale to update is added after the provided URL, eg. /de for updating the german value." shortDescription="URL of the endpoint for editing/updating a value. The value of the locale to update is added after the provided URL, eg. /de for updating the german value."
type="String" type="String"
/> />
<cc:attribute <!-- <cc:attribute
name="hasUnusedLocales" name="hasUnusedLocales"
required="true" required="true"
shortDescription="Are there unused locales? This will usually be an expression pointing to some method. The result must resolve to boolean." shortDescription="Are there unused locales? This will usually be an expression pointing to some method. The result must resolve to boolean."
type="boolean" type="boolean"
/> />-->
<cc:attribute <cc:attribute
name="headingLevel" name="headingLevel"
default="2" default="2"
@ -131,13 +137,13 @@
shortDescription="ID for the editor. Also used as prefix to generate IDs for some subcomponents" shortDescription="ID for the editor. Also used as prefix to generate IDs for some subcomponents"
type="String" type="String"
/> />
<cc:attribute <!-- <cc:attribute
name="emptyText" name="emptyText"
default="#{text.editor.no_localized_values}" default="#{text.editor.no_localized_values}"
required="false" required="false"
shortDescription="Text shown if the localized has no values yet." shortDescription="Text shown if the localized has no values yet."
type="String" type="String"
/> />-->
<cc:attribute <cc:attribute
name="messageSaveFailed" name="messageSaveFailed"
default="Failed to save." default="Failed to save."
@ -170,6 +176,12 @@
type="String" type="String"
/> />
<cc:attribute <cc:attribute
name="selectedLocale"
required="true"
shortDescription="The selected locale."
type="String"
/>
<!-- <cc:attribute
name="removeButtonLabel" name="removeButtonLabel"
default="Remove" default="Remove"
required="false" required="false"
@ -230,14 +242,14 @@
required="false" required="false"
shortDescription="Heading for the word count column" shortDescription="Heading for the word count column"
type="String" type="String"
/> />-->
<cc:attribute <cc:attribute
name="title" name="title"
required="true" required="true"
shortDescription="Title/Heading of the editor widget" shortDescription="Title/Heading of the editor widget"
type="String" type="String"
/> />
<cc:attribute <!-- <cc:attribute
name="unusedLocales" name="unusedLocales"
required="true" required="true"
shortDescription="A collection of the unused locales of the edited localized string" shortDescription="A collection of the unused locales of the edited localized string"
@ -248,14 +260,14 @@
required="true" required="true"
shortDescription="Info about the available variants. Must be a List of CmsEditorLocaleVariantRow objects." shortDescription="Info about the available variants. Must be a List of CmsEditorLocaleVariantRow objects."
type="java.util.List" type="java.util.List"
/> />-->
<cc:attribute <cc:attribute
name="variantUrl" name="variantUrl"
required="true" required="true"
shortDescription="URL of the endpoint for retrieving a variant. The locale of the variant to retrieve is appended as last token." shortDescription="URL of the endpoint for retrieving a variant. The locale of the variant to retrieve is appended as last token."
type="String" type="String"
/> />
<cc:attribute name="viewButtonLabel" default="View" type="String" /> <!-- <cc:attribute name="viewButtonLabel" default="View" type="String" />
<cc:attribute name="viewDialogTitle" default="View" type="String" /> <cc:attribute name="viewDialogTitle" default="View" type="String" />
<cc:attribute <cc:attribute
name="viewDialogEditButtonLabel" name="viewDialogEditButtonLabel"
@ -272,7 +284,7 @@
required="true" required="true"
shortDescription="URL of the endpoint for retrieving the wordcount of a variant. The locale of the variant to retrieve is appended as last token." shortDescription="URL of the endpoint for retrieving the wordcount of a variant. The locale of the variant to retrieve is appended as last token."
type="String" type="String"
/> />-->
</cc:interface> </cc:interface>
<cc:implementation> <cc:implementation>
<div class="cms-editor" id="#{cc.attrs.editorId}"> <div class="cms-editor" id="#{cc.attrs.editorId}">
@ -316,7 +328,7 @@
</div> </div>
</template> </template>
</div> </div>
<c:if test="#{cc.attrs.hasUnusedLocales}"> <!-- <c:if test="#{cc.attrs.hasUnusedLocales}">
<div class="mb-2"> <div class="mb-2">
<div class="text-right"> <div class="text-right">
<button <button
@ -735,50 +747,50 @@
> >
<div class="modal-dialog modal-xl modal-dialog-scrollable"> <div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">-->
<c:choose> <c:choose>
<c:when test="#{cc.attrs.headingLevel == 1}"> <c:when test="#{cc.attrs.headingLevel == 1}">
<h2 id="#{cc.attrs.editorId}-edit-dialog-title"> <h2 id="#{cc.attrs.editorId}-edit-dialog-title">
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</h2> </h2>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 2}"> <c:when test="#{cc.attrs.headingLevel == 2}">
<h3 id="#{cc.attrs.editorId}-edit-dialog-title"> <h3 id="#{cc.attrs.editorId}-edit-dialog-title">
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</h3> </h3>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 3}"> <c:when test="#{cc.attrs.headingLevel == 3}">
<h4 id="#{cc.attrs.editorId}-edit-dialog-title"> <h4 id="#{cc.attrs.editorId}-edit-dialog-title">
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</h4> </h4>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 4}"> <c:when test="#{cc.attrs.headingLevel == 4}">
<h5 id="#{cc.attrs.editorId}-edit-dialog-title"> <h5 id="#{cc.attrs.editorId}-edit-dialog-title">
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</h5> </h5>
</c:when> </c:when>
<c:when test="#{cc.attrs.headingLevel == 5}"> <c:when test="#{cc.attrs.headingLevel == 5}">
<h6 id="#{cc.attrs.editorId}-edit-dialog-title"> <h6 id="#{cc.attrs.editorId}-edit-dialog-title">
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</h6> </h6>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<div <div
id="#{cc.attrs.editorId}-edit-dialog-title" id="#{cc.attrs.editorId}-edit-dialog-title"
> >
#{cc.attrs.editDialogTitle} #{cc.attrs.editDialogTitle} #{cc.attrs.selectedLocale}
</div> </div>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
<button <!-- <button
aria-label="#{cc.attrs.editDialogCancelLabel}" aria-label="#{cc.attrs.editDialogCancelLabel}"
class="close" class="close"
type="button" type="button"
> >
<bootstrap:svgIcon icon="x" /> <bootstrap:svgIcon icon="x" />
</button> </button>-->
</div> </div>
<div class="modal-body"> <!--<div class="modal-body">-->
<div class="cms-tiptap-editor-buttons d-flex mb-1"> <div class="cms-tiptap-editor-buttons d-flex mb-1">
<div class="px-2 cms-tiptap-editor-textformatting"> <div class="px-2 cms-tiptap-editor-textformatting">
<button <button
@ -1005,24 +1017,26 @@
</div> </div>
</div> </div>
</div> </div>
<div class="cms-tiptap-editor border"></div> <div class="cms-tiptap-editor border"
</div> data-locale="#{cc.attrs.selectedLocale}"
<div class="modal-footer"> data-variant-url="#{cc.attrs.variantUrl}"></div>
<button <!--</div>-->
class="btn btn-warning cms-editor-cancel-button" <!--<div class="modal-footer">-->
type="button" <div class="mt-3">
> <a class="btn btn-warning cms-editor-cancel-button"
href="#{backUrl}">
#{cc.attrs.editDialogCancelLabel} #{cc.attrs.editDialogCancelLabel}
</button> </a>
<button <button
class="btn btn-success cms-editor-save-button" class="btn btn-success cms-editor-save-button"
disabled="#{cc.attrs.canEdit ? '' : 'disabled'}"
type="button" type="button"
> >
#{cc.attrs.editDialogSubmitLabel} #{cc.attrs.editDialogSubmitLabel}
</button> </button>
</div> </div>
<!--</div>
</div> </div>
</div> </div>-->
</div>
</cc:implementation> </cc:implementation>
</html> </html>

View File

@ -0,0 +1,558 @@
<!DOCTYPE html [<!ENTITY times '&#215;'>]>
<html
xmlns="http://www.w3.org/1999/xhtml"
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
>
<cc:interface shortDescription="The variants list for the rich text editor">
<cc:attribute
name="addMethod"
required="true"
shortDescription="URL of the endpoint for adding localized values."
type="String"
/>
<cc:attribute
name="addButtonLabel"
default="Add"
required="false"
shortDescription="Label for the add button"
type="String"
/>
<cc:attribute
name="addDialogCancelLabel"
default="#{CmsAdminMessages['cancel_button.label']}"
required="false"
shortDescription="Label for the cancel and close buttons."
type="String"
/>
<cc:attribute
name="addDialogLocaleSelectHelp"
default="The locale of the value of add"
required="false"
shortDescription="Help text for the locale select field"
type="String"
/>
<cc:attribute
name="addDialogLocaleSelectLabel"
default="#{CmsAdminMessages['locale_select.label']}"
required="false"
shortDescription="Label for the locale select field"
type="String"
/>
<cc:attribute
name="addDialogSubmitLabel"
default="#{CmsAdminMessages['locale_add.label']}"
required="false"
shortDescription="Label for the submit button"
type="String"
/>
<cc:attribute
name="addDialogTitle"
default="#{CmsAdminMessages['locale_add.dialog.title']}"
required="false"
shortDescription="Title for the dialog."
type="String"
/>
<cc:attribute
name="canEdit"
default="true"
required="false"
shortDescription="Can the current user edit the text?"
type="boolean"
/>
<cc:attribute
name="editButtonLabel"
default="#{CmsAdminMessages['edit_button.label']}"
required="false"
shortDescription="Label for the edit button."
type="String"
/>
<cc:attribute
name="editSourceCodeButtonLabel"
default="#{CmsAdminMessages['edit_source_code_button.label']}"
required="false"
shortDescription="Label for the edit source code button."
type="String"
/>
<cc:attribute
name="editorPageUrl"
required="true"
shortDescription="The URL of the page that contains the editor component. The URL of the page must accept the locale of the variant to edit as last path element."
type="String"
/>
<cc:attribute
name="hasUnusedLocales"
required="true"
shortDescription="Are there unused locales? This will usually be an expression pointing to some method. The result must resolve to boolean."
type="boolean"
/>
<cc:attribute
name="headingLevel"
default="2"
required="false"
shortDescription="Level of the heading used for the component. Also determines the heading levels used for other parts of the component."
type="int"
/>
<cc:attribute
name="emptyText"
default="#{text.editor.no_localized_values}"
required="false"
shortDescription="Text shown if the localized has no values yet."
type="String"
/>
<cc:attribute
name="sourceEditorPageUrl"
required="true"
shortDescription="The URL of the page that contains the source editor component. The URL of the page must accept the locale of the variant to edit as last path element."
type="String"
/>
<cc:attribute
name="removeButtonLabel"
default="Remove"
required="false"
shortDescription="Label for the remove button"
type="String"
/>
<cc:attribute
name="removeDialogCancelLabel"
default="Cancel"
required="false"
shortDescription="Label for the cancel and close buttons of the remove dialog"
type="String"
/>
<cc:attribute
name="removeDialogSubmitLabel"
default="Remove localized value"
required="false"
shortDescription="Label for the submit button of the remove dialog (removes the localized value)"
type="String"
/>
<cc:attribute
name="removeDialogText"
default="Are you sure to remove the following localized value?"
required="false"
shortDescription="Text for the remove dialog"
type="String"
/>
<cc:attribute
name="removeDialogTitle"
default="Remove localized value"
required="false"
shortDescription="The title of the remove dialog"
type="String"
/>
<cc:attribute
name="removeMethod"
required="true"
shortDescription="URL of the endpoint for remvoving a value. The locale of the value to remove is added to the end of the URL. Eg. /de for removing the value for the locale de."
type="String"
/>
<cc:attribute
name="tableActionsHeading"
default="Actions"
required="false"
shortDescription="Heading for the action columns"
type="String"
/>
<cc:attribute
name="tableLocaleHeading"
default="Locale"
required="false"
shortDescription="Heading for the locale column"
type="String"
/>
<cc:attribute
name="tableWordCountHeading"
default="Words"
required="false"
shortDescription="Heading for the word count column"
type="String"
/>
<cc:attribute
name="title"
required="true"
shortDescription="Title/Heading of the editor widget"
type="String"
/>
<cc:attribute
name="unusedLocales"
required="true"
shortDescription="A collection of the unused locales of the edited localized string"
type="java.util.Collection"
/>
<cc:attribute
name="variants"
required="true"
shortDescription="Info about the available variants. Must be a List of CmsEditorLocaleVariantRow objects."
type="java.util.List"
/>
<cc:attribute
name="viewPageUrl"
required="true"
shortDescription="The URL of the page that contains the preview component. The URL of the page must accept the locale of the variant to edit as last path element."
type="String"
/>
<cc:attribute name="viewButtonLabel" default="View" type="String" />
<cc:implementation>
<div class="cms-editor">
<c:choose>
<c:when test="#{cc.attrs.headingLevel == 1}">
<h1>#{cc.attrs.title}</h1>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 2}">
<h2>#{cc.attrs.title}</h2>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 3}">
<h3>#{cc.attrs.title}</h3>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 4}">
<h4>#{cc.attrs.title}</h4>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 5}">
<h5>#{cc.attrs.title}</h5>
</c:when>
<c:when test="#{cc.attrs.headingLevel == 6}">
<h6>#{cc.attrs.title}</h6>
</c:when>
<c:otherwise>
<div>#{cc.attrs.title}</div>
</c:otherwise>
</c:choose>
<div class="cms-editor-messages"></div>
<c:if test="#{cc.attrs.hasUnusedLocales}">
<div class="mb-2">
<div class="text-right">
<button
class="btn btn-secondary"
data-target="##{cc.attrs.editorId}-dialog"
data-toggle="modal"
type="button"
>
<bootstrap:svgIcon icon="plus-circle" />
<span> #{cc.attrs.addButtonLabel} </span>
</button>
</div>
<div
aria-labelledby="#{cc.attrs.editorId}-dialog-title"
aria-hidden="true"
class="modal fade"
id="#{cc.attrs.editorId}-dialog"
tabindex="-1"
>
<div class="modal-dialog">
<form
action="#{cc.attrs.addMethod}"
class="modal-content"
method="post"
>
<div class="modal-header">
<c:choose>
<c:when
test="#{cc.attrs.headingLevel == 1}"
>
<h2
class="modal-title"
id="#{cc.attrs.editorId}-dialog-title"
>
#{cc.attrs.addDialogTitle}
</h2>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 2}"
>
<h3
class="modal-title"
id="#{cc.attrs.editorId}-dialog-title"
>
#{cc.attrs.addDialogTitle}
</h3>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 3}"
>
<h4
class="modal-title"
id="#{cc.attrs.editorId}-dialog-title"
>
#{cc.attrs.addDialogTitle}
</h4>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 4}"
>
<h5
class="modal-title"
id="#{cc.attrs.editorId}-dialog-title"
>
#{cc.attrs.addDialogTitle}
</h5>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 5}"
>
<h6
class="modal-title"
id="#{cc.attrs.editorId}-dialog-title"
>
#{cc.attrs.addDialogTitle}
</h6>
</c:when>
<c:otherwise>
<div>
#{cc.attrs.addDialogTitle}
</div>
</c:otherwise>
</c:choose>
<button
aria-label="#{cc.attrs.addDialogCancelLabel}"
class="close"
data-dismiss="modal"
type="button"
>
<span aria-hidden="true">
<bootstrap:svgIcon icon="x" />
</span>
</button>
</div>
<div class="modal-body">
<div class="form-group">
<label
for="#{cc.attrs.editorId}-form-locale-select"
>
#{cc.attrs.addDialogLocaleSelectLabel}
</label>
<select
aria-describedby="#{cc.attrs.editorId}-form-locale-select-help"
id="#{cc.attrs.editorId}-form-locale-select"
name="locale"
required="true"
>
<c:forEach
items="#{cc.attrs.unusedLocales}"
var="locale"
>
<option value="#{locale}">
#{locale}
</option>
</c:forEach>
</select>
<small
class="form-text text-muted"
id="#{cc.attrs.editorId}-form-locale-select-help"
>
#{cc.attrs.addDialogLocaleSelectHelp}
</small>
</div>
</div>
<div class="modal-footer">
<button
class="btn btn-secondary"
data-dismiss="modal"
type="button"
>
#{cc.attrs.addDialogCancelLabel}
</button>
<button
type="submit"
class="btn btn-primary"
>
#{cc.attrs.addDialogSubmitLabel}
</button>
</div>
</form>
</div>
</div>
</div>
</c:if>
<c:choose>
<c:when test="#{cc.attrs.values.isEmpty()}">
<p>#{cc.attrs.emptyText}</p>
</c:when>
<c:otherwise>
<table class="cms-editor-variants table table-hover">
<thead class="thead-light">
<tr>
<th scope="col">
#{cc.attrs.tableLocaleHeading}
</th>
<th scope="col">
#{cc.attrs.tableWordCountHeading}
</th>
<th scope="col">
#{cc.attrs.tableActionsHeading}
</th>
</tr>
</thead>
<tbody>
<c:forEach
items="#{cc.attrs.variants}"
var="variant">
<tr id="variant-#{variant.locale}">
<td>#{variant.locale}</td>
<td>
<span class="wordcount"
>#{variant.wordCount}</span
>
#{CmsAdminMessages['cms_editor.variants.wordcount']}
</td>
<td>
<a class="btn btn-primary cms-editor-viewbutton"
href="#{cc.attrs.viewPageUrl}/#{variant.locale}">
<bootstrap:svgIcon icon="eye" />
<span class="sr-only">
#{cc.attrs.viewButtonLabel}
</span>
</a>
<c:if test="#{cc.attrs.canEdit}">
<a class="btn btn-primary"
href="#{cc.attrs.editorPageUrl}/#{variant.locale}">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">
#{cc.attrs.editButtonLabel}
</span>
</a>
<a class="btn btn-secondary"
href="#{cc.attrs.sourceEditorPageUrl}/#{variant.locale}">
<bootstrap:svgIcon icon="code-slash" />
<span class="sr-only">
#{cc.attrs.editSourceCodeButtonLabel}
</span>
</a>
<button
class="btn btn-danger"
data-target="##{cc.attrs.editorId}-#{variant.locale}-remove-dialog"
data-toggle="modal"
type="button"
>
<bootstrap:svgIcon
icon="x-circle"
/>
<span class="sr-only">
#{cc.attrs.removeButtonLabel}
</span>
</button>
<div
aria-describedby="#{cc.attrs.editorId}-#{variant.locale}-remove-dialog-title"
aria-hidden="true"
class="modal fade"
data-backdrop="static"
id="#{cc.attrs.editorId}-#{variant.locale}-remove-dialog"
tabindex="-1"
>
<div class="modal-dialog">
<form
action="#{cc.attrs.removeMethod}/#{variant.locale}"
class="modal-content"
method="post"
>
<div
class="modal-header"
>
<c:choose>
<c:when
test="#{cc.attrs.headingLevel == 1}"
>
<h2>
#{cc.attrs.removeDialogTitle}
</h2>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 2}"
>
<h3>
#{cc.attrs.removeDialogTitle}
</h3>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 3}"
>
<h4>
#{cc.attrs.removeDialogTitle}
</h4>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 4}"
>
<h5>
#{cc.attrs.removeDialogTitle}
</h5>
</c:when>
<c:when
test="#{cc.attrs.headingLevel == 5}"
>
<h6>
#{cc.attrs.removeDialogTitle}
</h6>
</c:when>
<c:otherwise>
<div>
#{cc.attrs.removeDialogTitle}
</div>
</c:otherwise>
</c:choose>
<button
aria-label="#{cc.attrs.removeDialogCancelLabel}"
class="close"
data-dismiss="modal"
type="button"
>
<span
aria-hidden="true"
>&times;</span
>
</button>
</div>
<div class="modal-body">
<p>
#{cc.attrs.removeDialogText}
</p>
<pre>
#{variant.locale}</pre
>
<input
name="confirmed"
type="hidden"
value="true"
/>
</div>
<div
class="modal-footer"
>
<button
class="
btn
btn-secondary
"
data-dismiss="modal"
type="button"
>
#{cc.attrs.removeDialogCancelLabel}
</button>
<button
type="submit"
class="
btn
btn-danger
"
>
#{cc.attrs.removeDialogSubmitLabel}
</button>
</div>
</form>
</div>
</div>
</c:if>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
</div>
</cc:implementation>
</cc:interface>
</html>

View File

@ -3,130 +3,36 @@
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap" xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm" xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:librecms="http://xmlns.jcp.org/jsf/composite/components/librecms"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"> xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml"> <ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
<ui:define name="authoringStep"> <ui:param name="authoringStep"
<h2>#{CmsArticleMessageBundle['textstep.header.languages']}</h2> value="/libreccm/@contentsections/info/documents/test-article/@article-text" />
<ui:define name="authoringStep">
<h2>#{CmsArticleMessageBundle['textstep.header']}</h2>
<librecms:cmsEditorVariants
addButtonLabel="#{CmsArticleMessageBundle['text.editor.add_variant']}"
addDialogLocaleSelectHelp="#{CmsAdminMessages['text.editor.add.locale.help']}"
addMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/add"
editorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/edit"
hasUnusedLocales="#{!CmsArticleTextBodyStep.unusedLocales.isEmpty()}"
removeMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/remove"
sourceEditorPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/edit-source"
title="#{CmsArticleMessageBundle['text.editor.header']}"
unusedLocales="#{CmsArticleTextBodyStep.unusedLocales}"
variants="#{CmsArticleTextBodyStep.variants}"
viewPageUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/view"
/>
<c:if test="#{CmsArticleTextBodyStep.canEdit and !CmsArticleTextBodyStep.unusedLocales.isEmpty()}">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/@add"
method="post">
<div class="d-flex justify-content-start">
<div class="form-group mr-2">
<label for="add-locale">#{CmsArticleMessageBundle['textstep.languages.add_language.label']}</label>
<select aria-describedby="add-locale-help"
name="locale"
size="1">
<c:forEach items="#{CmsArticleTextBodyStep.unusedLocales}"
var="locale">
<option value="#{locale}">#{locale}</option>
</c:forEach>
</select>
<small id="add-locale-help"
class="form-text text-muted">
#{CmsArticleMessageBundle['textstep.languages.add_language.help']}
</small>
</div>
<button class="btn btn-secondary align-self-start"
type="submit">
<bootstrap:svgIcon icon="plus-circle" />
<span>
#{CmsArticleMessageBundle['textstep.languages.add_language.submit']}
</span>
</button>
</div>
</form>
</c:if>
<c:choose>
<c:when test="#{CmsArticleTextBodyStep.textValues.isEmpty()}">
#{CmsArticleMessageBundle['textstep.languages.none']}
</c:when>
<c:otherwise>
<table>
<thead>
<tr>
<th>#{CmsArticleMessageBundle['textstep.languages.th.language']}</th>
<th>#{CmsArticleMessageBundle['textstep.languages.th.actions']}</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{CmsArticleTextBodyStep.textValues}"
var="entry">
<tr>
<td>#{entry.key}</td>
<td>
<a class="btn btn-secondary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/#{entry.key}/@view">
<bootstrap:svgIcon icon="eye" />
<span class="sr-only">#{CmsArticleMessageBundle['textstep.languages.view']}</span>
</a>
<c:if test="#{CmsArticleTextBodyStep.canEdit}">
<a class="btn btn-secondary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/#{entry.key}/@edit">
<bootstrap:svgIcon icon="pen" />
<span class="sr-only">#{CmsArticleMessageBundle['textstep.languages.edit']}</span>
</a>
<button class="btn btn-danger"
data-target="#remove-locale-#{entry.key}-dialog"
data-toggle="modal"
type="button">
<bootstrap:svgIcon icon="x-circle" />
<span class="sr-only">#{CmsArticleMessageBundle['textstep.languages.remove']}</span>
</button>
<div aria-labelledby="remove-locale-#{entry.key}-dialog-title"
aria-hidden="true"
class="modal fade"
data-backdrop="static"
id="remove-locale-#{entry.key}-dialog"
tabindex="-1">
<div class="modal-dialog">
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/#{entry.key}/@remove"
class="modal-content"
method="post">
<div class="modal-header">
<div class="modal-title">
<h3 class="remove-locale-#{entry.key}-dialog-title">#{CmsArticleMessageBundle.getMessage('textstep.languages.remove.title', [entry.key])}</h3>
<button aria-label="#{CmsArticleMessageBundle['textstep.languages.remove.cancel']}"
class="close"
data-dismiss="modal"
type="button">
<bootstrap:svgIcon icon="x" />
</button>
</div>
</div>
<div class="modal-body">
<input name="confirmed" type="hidden" value="true" />
<p>
#{CmsArticleMessageBundle.getMessage('textstep.languages.remove.message', [entry.key])}
</p>
</div>
<div class="modal-footer">
<button class="btn btn-secondary"
data-dismiss="modal"
type="button" >
#{CmsArticleMessageBundle['textstep.languages.remove.cancel']}
</button>
<button type="submit" class="btn btn-danger">
#{CmsArticleMessageBundle['textstep.languages.remove.confirm']}
</button>
</div>
</form>
</div>
</div>
<!-- <button class="btn btn-secondary"
href="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/#{entry.key}/@delete">
<bootstrap:svgIcon icon="eye" />
<span>{CmsArticleMessageBundle['textstep.languages.view']}</span>
</button>-->
</c:if>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</c:otherwise>
</c:choose>
</ui:define> </ui:define>
<ui:define name="scripts">
<script src="#{request.contextPath}/assets/@content-sections/cms-editor.js"></script>
</ui:define>
</ui:composition> </ui:composition>
</html> </html>

View File

@ -3,6 +3,7 @@
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap" xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm" xmlns:libreccm="http://xmlns.jcp.org/jsf/composite/components/libreccm"
xmlns:librecms="http://xmlns.jcp.org/jsf/composite/components/librecms"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"> xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml"> <ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
@ -16,17 +17,24 @@
<h2>#{CmsArticleMessageBundle.getMessage('textstep.header.edit',[CmsArticleTextBodyStep.selectedLocale])}</h2> <h2>#{CmsArticleMessageBundle.getMessage('textstep.header.edit',[CmsArticleTextBodyStep.selectedLocale])}</h2>
</div> </div>
<pre>selected locale: #{CmsArticleTextBodyStep.selectedLocale}</pre>
<c:if test="#{CmsArticleTextBodyStep.canEdit}"> <c:if test="#{CmsArticleTextBodyStep.canEdit}">
<div class="cms-editor"> <librecms:cmsEditor
#{CmsArticleTextBodyStep.textValues.get(CmsArticleTextBodyStep.selectedLocale)} backUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text"
</div> canEdit="#{CmsArticleTextBodyStep.canEdit}"
editMethod="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text/edit"
editorId="article-text-editor"
objectIdentifier="#{CmsSelectedDocumentModel.itemPath}"
selectedLocale="#{CmsArticleTextBodyStep.selectedLocale}"
title="#{CmsArticleMessageBundle['text.editor.header']}"
variantUrl="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-text-resources/variants"
/>
</c:if> </c:if>
</ui:define> </ui:define>
<ui:define name="scripts">
<script src="#{request.contextPath}/assets/@content-sections/cms-editor.js"></script>
</ui:define>
</ui:composition> </ui:composition>
</html> </html>

View File

@ -11,241 +11,43 @@ import TableCell from "@tiptap/extension-table-cell";
import TableHeader from "@tiptap/extension-table-header"; import TableHeader from "@tiptap/extension-table-header";
document.addEventListener("DOMContentLoaded", function (event) { document.addEventListener("DOMContentLoaded", function (event) {
const viewButtons = document.querySelectorAll( // const viewButtons = document.querySelectorAll(
".cms-editor .cms-editor-variants .cms-editor-view-button"
);
for (let i = 0; i < viewButtons.length; i++) {
viewButtons[i].addEventListener("click", event =>
showViewDialog(event)
);
}
const editButtons = document.querySelectorAll(
".cms-editor .cms-editor-variants .cms-editor-edit-button"
);
for (let i = 0; i < editButtons.length; i++) {
editButtons[i].addEventListener("click", event =>
showEditDialog(event)
);
}
// document
// .querySelector(
// ".cms-editor .cms-editor-variants .cms-editor-view-button" // ".cms-editor .cms-editor-variants .cms-editor-view-button"
// )
// .addEventListener("click", function (event) {
// event.preventDefault();
// const target = event.currentTarget as Element;
// const variantUrl = target.getAttribute("data-variant-url");
// const viewDialogId = target.getAttribute("data-view-dialog");
// fetch(variantUrl, {
// method: "GET",
// credentials: "include"
// })
// .then(response => {
// if (response.ok) {
// response
// .text()
// .then(text => {
// const viewDialog = document.querySelector(
// `#${viewDialogId}`
// ); // );
// const viewDialogBody = // for (let i = 0; i < viewButtons.length; i++) {
// viewDialog.querySelector(".modal-body"); // viewButtons[i].addEventListener("click", event =>
// showViewDialog(event)
// viewDialogBody.textContent = text;
// $(`#${viewDialogId}`).modal("toggle");
// })
// .catch(err => {
// showMessage(
// "#cms-editor-msg-variant-load-failed"
// ); // );
// });
// } else {
// showMessage("#cms-editor-msg-variant-load-failed");
// } // }
// })
// .catch(err => {
// showMessage("#cms-editor-msg-variant-load-failed");
// });
// });
// document // const editButtons = document.querySelectorAll(
// .querySelector(
// ".cms-editor .cms-editor-variants .cms-editor-edit-button" // ".cms-editor .cms-editor-variants .cms-editor-edit-button"
// )
// .addEventListener("click", function (event) {
// event.preventDefault();
// const target = event.currentTarget as Element;
// const locale = target.getAttribute("data-locale");
// const variantUrl = target.getAttribute("data-variant-url");
// const editDialogId = target.getAttribute("data-edit-dialog");
// const saveUrl = target.getAttribute("data-save-url");
// fetch(variantUrl, {
// method: "GET",
// credentials: "include"
// })
// .then(response => {
// if (response.ok) {
// response
// .text()
// .then(text => {
// const editDialog = document.querySelector(
// `#${editDialogId}`
// ); // );
// const tiptapDiv = editDialog.querySelector( // for (let i = 0; i < editButtons.length; i++) {
// ".modal-body .cms-tiptap-editor" // editButtons[i].addEventListener("click", event =>
// ); // showEditDialog(event)
// if (!tiptapDiv) {
// console.warn("tiptapDiv is null");
// }
// const editor = new Editor({
// element: tiptapDiv,
// extensions: [StarterKit],
// content: text
// });
// const buttonsDiv = editDialog.querySelector(
// ".cms-tiptap-editor-buttons"
// );
// if (!buttonsDiv) {
// console.warn("buttonsDiv is null.");
// }
// const emphButton =
// buttonsDiv.querySelector(".tiptap-emph");
// if (!emphButton) {
// console.warn("emphButton not found.");
// }
// emphButton.addEventListener("click", event => {
// event.preventDefault();
// editor.chain().focus().toggleItalic().run();
// });
// const strongEmphButton =
// buttonsDiv.querySelector(
// ".tiptap-strong-emph"
// );
// if (!strongEmphButton) {
// console.warn("strongEmphButton not found.");
// }
// strongEmphButton.addEventListener(
// "click",
// event => {
// event.preventDefault();
// editor
// .chain()
// .focus()
// .toggleBold()
// .run();
// }
// );
// const closeButton = editDialog.querySelector(
// ".modal-header .close"
// );
// const cancelButton = editDialog.querySelector(
// ".modal-footer .cms-editor-cancel-button"
// );
// const saveButton = editDialog.querySelector(
// ".modal-footer .cms-editor-save-button"
// );
// closeButton.addEventListener("click", event => {
// editor.chain().clearContent();
// editor.destroy();
// $(`#${editDialogId}`).modal("toggle");
// });
// cancelButton.addEventListener(
// "click",
// event => {
// editor.chain().clearContent();
// editor.destroy();
// $(`#${editDialogId}`).modal("toggle");
// }
// );
// saveButton.addEventListener("click", event => {
// const html = editor.getHTML();
// const params = new URLSearchParams();
// params.append("value", html);
// fetch(saveUrl, {
// method: "POST",
// credentials: "include",
// headers: {
// "Content-Type":
// "application/x-www-form-urlencoded"
// },
// body: params
// })
// .then(saveResponse => {
// if (saveResponse.ok) {
// showMessage(
// "#cms-editor-msg-save-successful"
// );
// window.location.reload();
// } else {
// showMessage(
// "#cms-editor-msg-save-failed"
// ); // );
// } // }
// $(`#${editDialogId}`).modal(
// "toggle"
// );
// })
// .catch(err => {
// showMessage(
// "#cms-editor-msg-save-failed"
// );
// console.error(err);
// $(`#${editDialogId}`).modal(
// "toggle"
// );
// });
// });
// $(`#${editDialogId}`).modal("toggle"); console.log("Trying to init editor...");
// }) const editor = document.querySelector(".cms-tiptap-editor");
// .catch(err => { if (editor) {
// showMessage( initEditor(editor as HTMLElement)
// "#cms-editor-msg-variant-load-failed" .then(() => console.log("editor initalized."))
// ); .catch(error => console.log(`Failed to init editor ${error}`));
// console.error(err); } else {
// }); console.log("No editor found.");
// } else { }
// showMessage("#cms-editor-msg-variant-load-failed");
// }
// })
// .catch(err => {
// showMessage("#cms-editor-msg-variant-load-failed");
// console.error(err);
// });
// });
// console.log("Starting editor");
// new Editor({
// element: document.querySelector('#cms-editor'),
// extensions: [
// StarterKit
// ],
// content: '<h1>Hello World</h1>'
// })
}); });
function closeEditor(event: Event, editor: Editor, editDialogId: string) { // function closeEditor(event: Event, editor: Editor, editDialogId: string) {
event.preventDefault(); // event.preventDefault();
editor.chain().clearContent(); // editor.chain().clearContent();
editor.destroy(); // editor.destroy();
const editDialog = $(`#${editDialogId}`) as any; // const editDialog = $(`#${editDialogId}`) as any;
editDialog.modal("toggle"); // editDialog.modal("toggle");
} // }
async function fetchVariant(fromUrl: string) { async function fetchVariant(fromUrl: string) {
try { try {
@ -281,16 +83,43 @@ async function fetchWordCount(fromUrl: string) {
} }
} }
async function initEditor(editorElem: HTMLElement) {
console.log("init editor");
const variantUrl = editorElem.getAttribute("data-variant-url");
if (variantUrl == null) {
console.error("variantUrl is null");
return;
}
console.log(`variantUrl = ${variantUrl}`);
const variant = await fetchVariant(variantUrl);
console.log("Got variant");
const editor = new Editor({
element: editorElem,
extensions: [
Gapcursor,
StarterKit,
Subscript,
Superscript,
Table.configure({ resizable: true }),
TableRow,
TableHeader,
TableCell
],
content: variant
});
console.log("initializing editor buttons");
const buttonsElem = editorElem.querySelector(".cms-tiptap-editor-buttons");
if (buttonsElem) {
initEditorButtons(editor, buttonsElem);
} else {
console.error("editorButtons are null");
return;
}
}
function initEditorButtons(editor: Editor, buttonsElem: Element) { function initEditorButtons(editor: Editor, buttonsElem: Element) {
// const emphButton: HTMLButtonElement | null = buttonsElem.querySelector(
// ".tiptap-emph"
// );
// if(emphButton) {
// emphButton.addEventListener("click", event => {
// event.preventDefault();
// editor.chain().focus().toggleItalic().run();
// });
// }
buttonsElem buttonsElem
.querySelector(".tiptap-emph") .querySelector(".tiptap-emph")
?.addEventListener("click", event => { ?.addEventListener("click", event => {
@ -485,12 +314,12 @@ async function showEditDialog(event: Event) {
} }
initEditorButtons(editor, editorButtons); initEditorButtons(editor, editorButtons);
const editDialogHeader = editDialog.querySelector(".modal-header .close"); // const editDialogHeader = editDialog.querySelector(".modal-header .close");
if (editDialogHeader) { // if (editDialogHeader) {
editDialogHeader.addEventListener("click", event => // editDialogHeader.addEventListener("click", event =>
closeEditor(event, editor, editDialogId) // closeEditor(event, editor, editDialogId)
); // );
} // }
const cancelButton = editDialog.querySelector( const cancelButton = editDialog.querySelector(
".modal-footer .cms-editor-cancel-button" ".modal-footer .cms-editor-cancel-button"
); );
@ -498,9 +327,9 @@ async function showEditDialog(event: Event) {
console.error("cancelButton is null"); console.error("cancelButton is null");
return; return;
} }
cancelButton.addEventListener("click", event => // cancelButton.addEventListener("click", event =>
closeEditor(event, editor, editDialogId) // closeEditor(event, editor, editDialogId)
); // );
const editButton = editDialog.querySelector( const editButton = editDialog.querySelector(
".modal-footer .cms-editor-save-button" ".modal-footer .cms-editor-save-button"
); );