diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js index 0d868ce1f9..fa5f99edf9 100644 --- a/src/bundle/Resources/encore/ibexa.js.config.js +++ b/src/bundle/Resources/encore/ibexa.js.config.js @@ -55,6 +55,7 @@ const layout = [ path.resolve(__dirname, '../public/js/scripts/admin.form.autosubmit.js'), path.resolve(__dirname, '../public/js/scripts/admin.anchor.navigation'), path.resolve(__dirname, '../public/js/scripts/admin.context.menu'), + path.resolve(__dirname, '../public/js/scripts/admin.focus.mode.js'), path.resolve(__dirname, '../public/js/scripts/sidebar/main.menu.js'), path.resolve(__dirname, '../public/js/scripts/admin.input.text.js'), path.resolve(__dirname, '../public/js/scripts/admin.table.js'), diff --git a/src/bundle/Resources/public/img/ibexa-icons.svg b/src/bundle/Resources/public/img/ibexa-icons.svg index 745c5c2723..71da466a78 100644 --- a/src/bundle/Resources/public/img/ibexa-icons.svg +++ b/src/bundle/Resources/public/img/ibexa-icons.svg @@ -772,6 +772,12 @@ + + + + + + diff --git a/src/bundle/Resources/public/img/icons/un-focus.svg b/src/bundle/Resources/public/img/icons/un-focus.svg new file mode 100644 index 0000000000..dc81cef08c --- /dev/null +++ b/src/bundle/Resources/public/img/icons/un-focus.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/bundle/Resources/public/js/scripts/admin.focus.mode.js b/src/bundle/Resources/public/js/scripts/admin.focus.mode.js new file mode 100644 index 0000000000..b532d3a2b7 --- /dev/null +++ b/src/bundle/Resources/public/js/scripts/admin.focus.mode.js @@ -0,0 +1,65 @@ +(function (global, doc) { + let activeFieldEdit = null; + const FOCUS_MODE_ENABLE_EVENT_NAME = 'ibexa-focus-mode:enable'; + const FOCUS_MODE_DISABLE_EVENT_NAME = 'ibexa-focus-mode:disable'; + const focusModeEnableBtns = doc.querySelectorAll('.ibexa-field-edit__focus-mode-control-btn--enable'); + const focusModeDisbaleBtns = doc.querySelectorAll('.ibexa-field-edit__focus-mode-control-btn--disable'); + const changeFocusModeState = (active) => { + if (!activeFieldEdit) { + return; + } + + const dispatchEventName = active ? FOCUS_MODE_ENABLE_EVENT_NAME : FOCUS_MODE_DISABLE_EVENT_NAME; + const editorSourceElement = activeFieldEdit.querySelector('.ibexa-data-source__richtext'); + const editorInstance = editorSourceElement.ckeditorInstance; + + activeFieldEdit.classList.toggle('ibexa-field-edit--focus-mode-active', active); + editorInstance.set('focusModeActive', active); + + doc.body.dispatchEvent( + new CustomEvent(dispatchEventName, { + detail: { + activeFieldEdit, + }, + }), + ); + + if (!active) { + activeFieldEdit = null; + } + }; + const handleKeyPress = (event) => { + if (event.key === 'Escape') { + changeFocusModeState(false); + } + }; + + focusModeEnableBtns.forEach((btn) => { + btn.addEventListener( + 'click', + ({ currentTarget }) => { + activeFieldEdit = currentTarget.closest('.ibexa-field-edit'); + changeFocusModeState(true); + }, + false, + ); + }); + focusModeDisbaleBtns.forEach((btn) => { + btn.addEventListener('click', () => changeFocusModeState(false), false); + }); + + doc.body.addEventListener( + FOCUS_MODE_ENABLE_EVENT_NAME, + () => { + doc.body.addEventListener('keydown', handleKeyPress, false); + }, + false, + ); + doc.body.addEventListener( + FOCUS_MODE_DISABLE_EVENT_NAME, + () => { + doc.body.removeEventListener('keydown', handleKeyPress, false); + }, + false, + ); +})(window, window.document); diff --git a/src/bundle/Resources/public/scss/_alerts.scss b/src/bundle/Resources/public/scss/_alerts.scss index 404ae487fc..f85114c592 100644 --- a/src/bundle/Resources/public/scss/_alerts.scss +++ b/src/bundle/Resources/public/scss/_alerts.scss @@ -199,4 +199,14 @@ } } } + + &--complementary { + color: $ibexa-color-complementary-700; + background-color: $ibexa-color-complementary-100; + border-color: $ibexa-color-complementary; + + .ibexa-icon { + fill: $ibexa-color-complementary-700; + } + } } diff --git a/src/bundle/Resources/public/scss/fieldType/edit/_base-field.scss b/src/bundle/Resources/public/scss/fieldType/edit/_base-field.scss index 7ee540cd04..9dc2b8b217 100644 --- a/src/bundle/Resources/public/scss/fieldType/edit/_base-field.scss +++ b/src/bundle/Resources/public/scss/fieldType/edit/_base-field.scss @@ -15,6 +15,35 @@ color: $ibexa-color-danger; } + &__focus-mode { + display: flex; + flex-direction: column; + height: auto; + background: $ibexa-color-white; + border-radius: $ibexa-border-radius $ibexa-border-radius 0 0; + } + + &__focus-mode-notice-container { + display: none; + } + + &__focus-mode-control-container { + display: flex; + align-self: flex-end; + } + + &__focus-mode-control-btn { + align-self: flex-end; + + &--enable { + display: inline-flex; + } + + &--disable { + display: none; + } + } + .ibexa-input-text-wrapper { width: auto; } @@ -59,6 +88,108 @@ } } } + + &--has-focus-mode { + display: flex; + flex-wrap: wrap; + + .ibexa-field-edit { + &__focus-mode { + margin: auto 0 0; + align-self: baseline; + } + + &__label-wrapper { + width: 80%; + } + + &__focus-mode { + width: 20%; + } + + &__data { + width: 100%; + } + } + } + + &--focus-mode-active { + position: fixed; + top: 0; + left: 0; + z-index: 1080; + flex-direction: column; + width: 100vw; + height: 100vh; + padding: calculateRem(16px); + background: $ibexa-color-black; + + .ibexa-field-edit { + &__label-wrapper { + display: none; + } + + &__focus-mode { + width: 100%; + height: fit-content; + padding: calculateRem(32px) calculateRem(32px) 0 calculateRem(32px); + } + + &__focus-mode-notice-container { + display: block; + width: 100%; + } + + &__focus-mode-control-container { + height: calculateRem(40px); + } + + &__focus-mode-control-btn { + margin: 0; + + &--enable { + display: none; + } + + &--disable { + display: inline-flex; + } + } + + &__data { + width: 100%; + overflow-y: auto; + align-self: stretch; + flex-grow: 1; + padding: calculateRem(8px) calculateRem(32px) calculateRem(32px); + background: $ibexa-color-white; + border-radius: 0 0 $ibexa-border-radius $ibexa-border-radius; + + .ibexa-data-source { + height: 100%; + } + } + } + + .ibexa-alert { + margin-bottom: calculateRem(4px); + } + } + + &--focus-mode-active.is-invalid { + .ibexa-field-edit { + &__data { + border-radius: 0; + padding-bottom: 0; + } + } + + .ibexa-form-error { + padding: calculateRem(16px) calculateRem(32px); + background: $ibexa-color-white; + border-radius: 0 0 $ibexa-border-radius $ibexa-border-radius; + } + } } .ibexa-content-edit { diff --git a/src/bundle/Resources/translations/messages.en.xliff b/src/bundle/Resources/translations/messages.en.xliff index 57d5e3c56b..f6516781c9 100644 --- a/src/bundle/Resources/translations/messages.en.xliff +++ b/src/bundle/Resources/translations/messages.en.xliff @@ -433,6 +433,31 @@ Show key: fieldview.toggler.show + + Default mode + Default mode + key: focus_mode.disable.label + + + Exit focus mode. + Exit focus mode. + key: focus_mode.disable.tooltip + + + To exit focus mode, click the %icon% or press Esc. + To exit focus mode, click the %icon% or press Esc. + key: focus_mode.disable_hint + + + Focus mode + Focus mode + key: focus_mode.enable.label + + + Enter focus mode. It shows only rich text editor toolbar and focuses your attention on editing text. + Enter focus mode. It shows only rich text editor toolbar and focuses your attention on editing text. + key: focus_mode.enable.tooltip + diff --git a/src/bundle/Resources/views/themes/admin/content/form_fields.html.twig b/src/bundle/Resources/views/themes/admin/content/form_fields.html.twig index 44d7dfdb3f..c8209085e5 100644 --- a/src/bundle/Resources/views/themes/admin/content/form_fields.html.twig +++ b/src/bundle/Resources/views/themes/admin/content/form_fields.html.twig @@ -80,9 +80,10 @@ {% set fieldtype_identifier = fieldtype.vars.value.fieldDefinition.fieldTypeIdentifier %} {% set translation_mode = fieldtype.vars.mainLanguageCode != fieldtype.vars.languageCode %} {% set fieldtype_is_not_translatable = translation_mode and not fieldtype.vars.value.fieldDefinition.isTranslatable %} + {% set has_focus_mode = fieldtype_identifier == 'ezrichtext' %} {% set widget_wrapper_attr = widget_wrapper_attr|default({})|merge({'class': (widget_wrapper_attr.class|default('') ~ ' ibexa-field-edit__data ibexa-field-edit__data')|trim}) %} - {% set wrapper_class = 'ibexa-field-edit ibexa-field-edit--' ~ fieldtype_identifier ~ ' ibexa-field-edit ibexa-field-edit--' ~ fieldtype_identifier %} + {% set wrapper_class = 'ibexa-field-edit ibexa-field-edit--' ~ fieldtype_identifier ~ ' ibexa-field-edit ibexa-field-edit--' ~ fieldtype_identifier ~ (has_focus_mode ? ' ibexa-field-edit--has-focus-mode') %} {% if fieldtype.vars.disabled %} {% set wrapper_class = wrapper_class ~ ' ibexa-field-edit--disabled ibexa-field-edit--disabled' %} @@ -114,9 +115,13 @@
- {% with { 'compound': false } %}{{- block('form_label') }}{% endwith %} + {% with { 'compound': false } %}{{ block('form_label') }}{% endwith %}
+ {% if has_focus_mode %} + {{- block('focus_mode') }} + {% endif %} + {% if widget_container_block is defined %} {{ widget_container_block|raw }} {% else %} diff --git a/src/bundle/Resources/views/themes/admin/ui/form_fields.html.twig b/src/bundle/Resources/views/themes/admin/ui/form_fields.html.twig index 19fe07aae0..1492d16fe1 100644 --- a/src/bundle/Resources/views/themes/admin/ui/form_fields.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/form_fields.html.twig @@ -503,3 +503,49 @@ {{- form_errors(form) -}} {%- endblock %} + +{%- block focus_mode -%} + {%- set title_icon -%} + + + + {%- endset -%} + {%- set title -%} + {{ 'focus_mode.disable_hint'|trans({ '%icon%': title_icon|raw })|desc('To exit focus mode, click the %icon% or press Esc.')|raw }} + {%- endset -%} + +
+
+ {% include '@ibexadesign/ui/component/alert/alert.html.twig' with { + type: 'complementary', + title, + icon_path: ibexa_icon_path('system-information'), + show_close_btn: true + } only %} +
+
+ + +
+
+{%- endblock -%} diff --git a/src/lib/Behat/Component/Fields/RichText.php b/src/lib/Behat/Component/Fields/RichText.php index 1fe5e34120..15fda86f61 100644 --- a/src/lib/Behat/Component/Fields/RichText.php +++ b/src/lib/Behat/Component/Fields/RichText.php @@ -57,13 +57,6 @@ public function getValue(): array return [$this->getFieldInput()->getText()]; } - public function openElementsToolbar(): void - { - $this->focusFieldInput(); - $script = "document.querySelector('.ck-toolbar__grouped-dropdown > .ck-dropdown__button').click()"; - $this->getSession()->executeScript($script); - } - public function changeStyle(string $style): void { $this->focusFieldInput(); @@ -130,13 +123,11 @@ public function addUnorderedList(array $listElements): void public function clickEmbedInlineButton(): void { - $this->openElementsToolbar(); $this->clickElementsToolbarButton('Embed inline'); } public function clickEmbedButton(): void { - $this->openElementsToolbar(); $this->clickElementsToolbarButton('Embed'); } @@ -184,8 +175,7 @@ private function executeCommand(string $commandName): void private function clickElementsToolbarButton(string $buttonText): void { $script = sprintf( - "Array.from(document.querySelectorAll('%s %s')).filter(e => e.textContent =='%s')[0].click()", - $this->getLocator('additionalToolbar')->getSelector(), + "Array.from(document.querySelectorAll('%s')).filter(e => e.textContent =='%s')[0].click()", $this->getLocator('toolbarElement')->getSelector(), $buttonText );