Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use text editor for editing question description #2164

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@

use OCA\Forms\Capabilities;
use OCA\Forms\FormsMigrator;
use OCA\Forms\Listener\BeforeTemplateRenderedListener;
use OCA\Forms\Listener\UserDeletedListener;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\User\Events\UserDeletedEvent;

class Application extends App implements IBootstrap {
Expand All @@ -59,6 +61,7 @@
$context->registerCapability(Capabilities::class);
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
$context->registerUserMigrator(FormsMigrator::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);

Check warning on line 64 in lib/AppInfo/Application.php

View check run for this annotation

Codecov / codecov/patch

lib/AppInfo/Application.php#L64

Added line #L64 was not covered by tests
}

/**
Expand Down
26 changes: 26 additions & 0 deletions lib/Listener/BeforeTemplateRenderedListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace OCA\Forms\Listener;

use OCA\Text\Event\LoadEditor;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\EventDispatcher\IEventListener;

/** @template-implements IEventListener<Event|BeforeTemplateRenderedEvent> */
class BeforeTemplateRenderedListener implements IEventListener {
public function __construct(private IEventDispatcher $eventDispatcher) {

Check warning on line 13 in lib/Listener/BeforeTemplateRenderedListener.php

View check run for this annotation

Codecov / codecov/patch

lib/Listener/BeforeTemplateRenderedListener.php#L13

Added line #L13 was not covered by tests
}

public function handle(Event $event): void {
if (!($event instanceof BeforeTemplateRenderedEvent)) {
return;

Check warning on line 18 in lib/Listener/BeforeTemplateRenderedListener.php

View check run for this annotation

Codecov / codecov/patch

lib/Listener/BeforeTemplateRenderedListener.php#L16-L18

Added lines #L16 - L18 were not covered by tests
}

$isFormsResponse = $event->getResponse()->getApp() === \OCA\Forms\AppInfo\Application::APP_ID;
if ($isFormsResponse && class_exists(LoadEditor::class)) {
$this->eventDispatcher->dispatchTyped(new LoadEditor());

Check failure on line 23 in lib/Listener/BeforeTemplateRenderedListener.php

View workflow job for this annotation

GitHub Actions / Static analysis

UndefinedClass

lib/Listener/BeforeTemplateRenderedListener.php:23:46: UndefinedClass: Class, interface or enum named OCA\Text\Event\LoadEditor does not exist (see https://psalm.dev/019)

Check warning on line 23 in lib/Listener/BeforeTemplateRenderedListener.php

View check run for this annotation

Codecov / codecov/patch

lib/Listener/BeforeTemplateRenderedListener.php#L21-L23

Added lines #L21 - L23 were not covered by tests
}
}
}
73 changes: 61 additions & 12 deletions src/components/Questions/Question.vue
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,24 @@
</NcActions>
</div>
<div v-if="hasDescription || !readOnly" class="question__header__description">
<textarea v-if="!readOnly"
ref="description"
dir="auto"
:value="description"
:placeholder="t('forms', 'Description (formatting using Markdown is supported)')"
:maxlength="maxStringLengths.questionDescription"
class="question__header__description__input"
@input="onDescriptionChange" />
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-else class="question__header__description__output" v-html="computedDescription" />
<div v-show="editor">
<label>{{ t('forms', 'Description') }}</label>
<div v-if="!readOnly" ref="editor" />
</div>

<template v-if="!editor">
<textarea v-if="!readOnly"
ref="description"
dir="auto"
:value="description"
:placeholder="t('forms', 'Description (formatting using Markdown is supported)')"
:maxlength="maxStringLengths.questionDescription"
class="question__header__description__input"
@input="onDescriptionChange" />

<!-- eslint-disable-next-line vue/no-v-html -->
<div v-else class="question__header__description__output" v-html="computedDescription" />
</template>
</div>
</div>

Expand All @@ -162,6 +170,7 @@
import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
import IconIdentifier from 'vue-material-design-icons/Identifier.vue'
import IconOverlay from '../Icons/IconOverlay.vue'
import debounce from 'debounce'

export default {
name: 'Question',
Expand Down Expand Up @@ -241,6 +250,12 @@
},
},

data() {
return {
editor: null,
}
},

computed: {
/**
* Extend text with asterisk if question is required
Expand Down Expand Up @@ -279,10 +294,18 @@
return this.description !== ''
},
},

// Ensure description is sized correctly on initial render
mounted() {
async mounted() {
this.$nextTick(() => this.resizeDescription())

await this.setupEditor()
},

beforeDestroy() {
this.editor?.destroy()
},

methods: {
onTitleChange({ target }) {
this.$emit('update:text', target.value)
Expand Down Expand Up @@ -338,6 +361,28 @@
onClone() {
this.$emit('clone')
},

async setupEditor() {
if (!window.OCA.Text || this.readOnly) {
return
}

this.editor = await window.OCA.Text.createEditor({
el: this.$refs.editor,
content: this.description,
readOnly: false,
onUpdate: ({ markdown }) => {
this.updateEditorContent(markdown)
},
onFileInsert() {
console.log(arguments)

Check failure on line 378 in src/components/Questions/Question.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Unexpected console statement
},
})
},

updateEditorContent: debounce(function(markdown) {
this.$emit('update:description', markdown)
}, 200, { immediate: true }),
},
}
</script>
Expand All @@ -358,6 +403,10 @@

&--editable {
padding-inline-start: 56px; // add 12px for the title input box

:deep(.ProseMirror) {
padding-bottom: 10px;
}
}

> * {
Expand Down Expand Up @@ -449,7 +498,7 @@
}

&__description {
display: flex;
//display: flex;

&__input {
margin: 0px;
Expand Down
69 changes: 54 additions & 15 deletions src/views/Create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,27 @@
autofocus
@input="onTitleChange" />
</h2>
<label class="hidden-visually" for="form-desc">
{{ t('forms', 'Description') }}
</label>
<textarea id="form-desc"
ref="description"
class="form-desc"
rows="1"
dir="auto"
:value="form.description"
:placeholder="t('forms', 'Description (formatting using Markdown is supported)')"
:maxlength="maxStringLengths.formDescription"
@input="updateDescription" />

<div v-show="editor">
<label for="form-desc-editor">{{ t('forms', 'Description') }}</label>
<div id="form-desc-editor" ref="editor" />
</div>

<template v-if="!editor">
<label class="hidden-visually" for="form-desc">
{{ t('forms', 'Description') }}
</label>
<textarea id="form-desc"
ref="description"
class="form-desc"
rows="1"
dir="auto"
:value="form.description"
:placeholder="t('forms', 'Description (formatting using Markdown is supported)')"
:maxlength="maxStringLengths.formDescription"
@input="updateDescription" />
</template>

<!-- Show expiration message-->
<p v-if="form.expires && form.showExpiration" class="info-message">
{{ expirationMessage }}
Expand Down Expand Up @@ -177,6 +186,7 @@ window.axios = axios

export default {
name: 'Create',

components: {
Draggable,
IconLock,
Expand All @@ -193,7 +203,9 @@ export default {
TopBar,
},

mixins: [ViewsMixin],
mixins: [
ViewsMixin,
],

data() {
return {
Expand All @@ -205,6 +217,7 @@ export default {

maxStringLengths: loadState('forms', 'maxStringLengths'),
questionMenuOpened: false,
editor: null,
}
},

Expand Down Expand Up @@ -285,9 +298,15 @@ export default {
},
},

mounted() {
this.fetchFullForm(this.form.id)
async mounted() {
await this.fetchFullForm(this.form.id)
SetWindowTitle(this.formTitle)

await this.setupEditor()
},

beforeDestroy() {
this.editor?.destroy()
},

methods: {
Expand Down Expand Up @@ -465,6 +484,22 @@ export default {
this.isLoadingQuestions = false
}
},

async setupEditor() {
if (!window.OCA.Text) {
return
}

this.editor = await window.OCA.Text.createEditor({
el: this.$refs.editor,
content: this.form.description,
readOnly: false,
onUpdate: ({ markdown }) => {
this.form.description = markdown
this.saveDescription()
},
})
},
},
}
</script>
Expand Down Expand Up @@ -524,6 +559,10 @@ export default {
}
}

:deep(.ProseMirror) {
padding-bottom: 10px;
}

.form-desc,
.info-message {
font-size: 100%;
Expand Down
Loading