Skip to content

Commit

Permalink
apps/documents: adjust to new ckeditor5
Browse files Browse the repository at this point in the history
  • Loading branch information
goapunk committed Mar 25, 2024
1 parent 2c0c8f7 commit 04b6b61
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 150 deletions.
6 changes: 6 additions & 0 deletions adhocracy-plus/assets/scss/_form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ label {
border-radius: 0;
}


textarea,
select,
input {
Expand Down Expand Up @@ -86,6 +87,11 @@ div.cke_focus {
// adhocracy4 core).
margin-bottom: 0;
}

// hide ckeditor input field
.django-ckeditor-widget textarea {
display: none;
}
}

.form-fieldset {
Expand Down
33 changes: 19 additions & 14 deletions apps/documents/assets/ChapterForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,25 @@ const ChapterForm = (props) => {
props.chapter.paragraphs.map(function (paragraph, index, arr) {
const key = paragraph.id || paragraph.key
return (
<ParagraphForm
id={key}
key={key}
index={index}
paragraph={paragraph}
config={props.config}
onDelete={() => { props.onParagraphDelete(index) }}
onMoveUp={index !== 0 ? () => { props.onParagraphMoveUp(index) } : null}
onMoveDown={index < arr.length - 1 ? () => { props.onParagraphMoveDown(index) } : null}
onParagraphAddBefore={() => { props.onParagraphAddBefore(index) }}
onNameChange={(name) => { props.onParagraphNameChange(index, name) }}
onTextChange={(text) => { props.onParagraphTextChange(index, text) }}
errors={props.errors && props.errors.paragraphs ? props.errors.paragraphs[index] : {}}
/>
<div key={key}>
<ParagraphForm
id={key}
key={key}
index={index}
paragraph={paragraph}
csrfCookieName={props.csrfCookieName}
uploadUrl={props.uploadUrl}
uploadFileTypes={props.uploadFileTypes}
config={props.config}
onDelete={() => { props.onParagraphDelete(index) }}
onMoveUp={index !== 0 ? () => { props.onParagraphMoveUp(index) } : null}
onMoveDown={index < arr.length - 1 ? () => { props.onParagraphMoveDown(index) } : null}
onParagraphAddBefore={() => { props.onParagraphAddBefore(index) }}
onNameChange={(name) => { props.onParagraphNameChange(index, name) }}
onTextChange={(text) => { props.onParagraphTextChange(index, text) }}
errors={props.errors && props.errors.paragraphs ? props.errors.paragraphs[index] : {}}
/>
</div>
)
})
}
Expand Down
3 changes: 3 additions & 0 deletions apps/documents/assets/DocumentManagement.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ class DocumentManagement extends React.Component {
onParagraphMoveUp={(paragraphIndex) => { this.handleParagraphMoveUp(chapterIndex, paragraphIndex) }}
onParagraphMoveDown={(paragraphIndex) => { this.handleParagraphMoveDown(chapterIndex, paragraphIndex) }}
onParagraphDelete={(paragraphIndex) => { this.handleParagraphDelete(chapterIndex, paragraphIndex) }}
csrfCookieName={this.props.csrfCookieName}
uploadUrl={this.props.uploadUrl}
uploadFileTypes={this.props.uploadFileTypes}
config={this.props.config}
chapter={chapter}
errors={chapterErrors}
Expand Down
168 changes: 87 additions & 81 deletions apps/documents/assets/ParagraphForm.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
const React = require('react')
const django = require('django')
const FormFieldError = require('adhocracy4/adhocracy4/static/FormFieldError')

const ckGet = function (id) {
return window.CKEDITOR.instances[id]
}

const ckReplace = function (id, config) {
return window.CKEDITOR.replace(id, config)
}
import React, { useRef, useEffect } from 'react'
import django from 'django'
import FormFieldError from 'adhocracy4/adhocracy4/static/FormFieldError'

// translations
const translations = {
Expand All @@ -25,75 +17,90 @@ const translations = {
)
}

class ParagraphForm extends React.Component {
handleNameChange (e) {
const name = e.target.value
this.props.onNameChange(name)
}
const ParagraphForm = (props) => {
const editor = useRef(null)
const index = useRef(props.index)
const id = 'id_paragraphs-' + props.id + '-text'

ckId () {
return 'id_paragraphs-' + this.props.id + '-text'
}

ckEditorDestroy () {
const editor = ckGet(this.ckId())
if (editor) {
editor.destroy()
useEffect(() => {
// destroy if component renders multiple times to prevent
// multiple CKEditors
let destroy = false
const createEditor = async () => {
const config = window.ckeditorPrepareConfig(
JSON.stringify(props.config),
props.csrfCookieName,
props.uploadUrl,
props.uploadFileTypes
)
const ckeditor = await window.ClassicEditor.create(
document.querySelector('#' + id),
config
)
if (destroy) {
ckeditor.destroy()
} else {
editor.current = ckeditor
editor.current.model.document.on('change:data', (e) => {
const text = editor.current.getData()
props.onTextChange(text)
})
editor.current.setData(props.paragraph.text)
}
}
}

ckEditorCreate () {
if (!ckGet(this.ckId())) {
const editor = ckReplace(this.ckId(), this.props.config)
editor.on('change', function (e) {
const text = e.editor.getData()
this.props.onTextChange(text)
}.bind(this))
editor.setData(this.props.paragraph.text)
if (editor.current) {
if (index.current !== props.index) {
// recreate if index changed
destroyEditor()
}
}
}

UNSAFE_componentWillUpdate (nextProps) {
if (nextProps.index > this.props.index) {
this.ckEditorDestroy()
index.current = props.index
if (!editor.current) {
createEditor()
return () => {
// destroy if still in process of creating
destroy = true
// destroy if already created
destroyEditor()
}
}
}
}, [props.index])

componentDidUpdate (prevProps) {
if (this.props.index > prevProps.index) {
this.ckEditorCreate()
const destroyEditor = () => {
if (editor.current) {
editor.current.destroy()
editor.current = null
}
}

componentDidMount () {
this.ckEditorCreate()
}

componentWillUnmount () {
this.ckEditorDestroy()
const handleNameChange = (e) => {
const name = e.target.value
props.onNameChange(name)
}

render () {
const ckEditorToolbarsHeight = 60 // measured on example editor
return (
<section className="commenting">
<div className="commenting__content">
return (
<section>
<div className="row">
<div className="col-lg-9">
<div className="commenting__content--border">
<div className="form-group">
<label
htmlFor={'id_paragraphs-' + this.props.id + '-name'}
>
<label htmlFor={'id_paragraphs-' + props.id + '-name'}>
{translations.headline}
<input
className="form-control"
id={'id_paragraphs-' + this.props.id + '-name'}
name={'paragraphs-' + this.props.id + '-name'}
id={'id_paragraphs-' + props.id + '-name'}
name={'paragraphs-' + props.id + '-name'}
type="text"
value={this.props.paragraph.name}
onChange={this.handleNameChange.bind(this)}
value={props.paragraph.name}
onChange={handleNameChange}
aria-invalid={props.errors ? 'true' : 'false'}
aria-describedby={props.errors && 'id_error-' + props.id}
/>
<FormFieldError
id={'id_error-' + props.id}
error={props.errors}
field="name"
/>
</label>
<FormFieldError id={'id_error-' + this.props.id} error={this.props.errors} field="name" />
</div>

<div className="form-group">
Expand All @@ -107,7 +114,7 @@ class ParagraphForm extends React.Component {
</div>
<div
className="django-ckeditor-widget"
data-field-id={'id_paragraphs-' + this.props.id + '-text'}
data-field-id={'id_paragraphs-' + props.id + '-text'}
style={{ display: 'inline-block' }}
>
<textarea
Expand All @@ -119,28 +126,30 @@ class ParagraphForm extends React.Component {
}
/>
</div>
<FormFieldError
id={'id_error-' + props.id}
error={props.errors}
field="text"
/>
</label>
<FormFieldError id={'id_error-' + this.props.id} error={this.props.errors} field="text" />
</div>
</div>
</div>

<div className="commenting__actions btn-group" role="group">
<button
className="btn btn--light btn--small"
onClick={this.props.onMoveUp}
disabled={!this.props.onMoveUp}
onClick={props.onMoveUp}
disabled={!props.onMoveUp}
title={translations.moveUp}
type="button"
>
<i
className="fa fa-chevron-up"
aria-label={translations.moveUp}
/>
<i className="fa fa-chevron-up" aria-label={translations.moveUp} />
</button>
<button
className="btn btn--light btn--small"
onClick={this.props.onMoveDown}
disabled={!this.props.onMoveDown}
onClick={props.onMoveDown}
disabled={!props.onMoveDown}
title={translations.moveDown}
type="button"
>
Expand All @@ -151,19 +160,16 @@ class ParagraphForm extends React.Component {
</button>
<button
className="btn btn--light btn--small"
onClick={this.props.onDelete}
onClick={props.onDelete}
title={translations.delete}
type="button"
>
<i
className="far fa-trash-alt"
aria-label={translations.delete}
/>
<i className="fas fa-trash-alt" aria-label={translations.delete} />
</button>
</div>
</section>
)
}
</div>
</section>
)
}

module.exports = ParagraphForm
35 changes: 11 additions & 24 deletions apps/documents/assets/react_documents_init.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import DocumentManagement from './DocumentManagement'
import { widget as ReactWidget } from 'adhocracy4'

function init () {
ReactWidget.initialise('mb', 'document-management',
function (el) {
const chapters = JSON.parse(el.dataset.chapters)
const module = el.dataset.module
const config = JSON.parse(el.dataset.config)

// used getAttribute as returns string that can be parsed as json
const reloadOnSuccess = JSON.parse(el.getAttribute('data-reloadOnSuccess'))
import DocumentManagement from './DocumentManagement'

const root = createRoot(el)
root.render(
<React.StrictMode>
<DocumentManagement
key={module}
module={module}
chapters={chapters}
config={config}
reloadOnSuccess={reloadOnSuccess}
/>
</React.StrictMode>
)
}
)
function init () {
ReactWidget.initialise('mb', 'document-management', (el) => {
const props = JSON.parse(el.dataset.attributes)
const root = createRoot(el)
root.render(
<React.StrictMode>
<DocumentManagement {...props} />
</React.StrictMode>
)
})
}

document.addEventListener('DOMContentLoaded', init, false)
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ <h2 class="chapter-title">{{ object.name }}</h2>
{% for paragraph in object.paragraphs.all %}

<section class="paragraph" id="paragraph-{{ object.pk }}-{{ paragraph.pk }}">
<div class="paragraph__content ck-content">
<div class="paragraph__content">
<h3 class="paragraph__title">
{{ paragraph.name }}
</h3>
<div class="ck-content">
<div class="ck-content">
{{ paragraph.text|richtext }}
</div>
</div>
</div>
<div class="paragraph__actions">
<a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ <h1 class="mt-0">{% translate 'Edit document' %}</h1>

{% endblock %}


{% block extra_css %}
{{ block.super }}
{# include ckeditor css from widget, comes as link tag #}
{{ ckeditor_media.css }}
{% endblock %}
{% block extra_js %}
{{ block.super }}
{{ block.super }}
{# include ckeditor js from widget, comes as script tag #}
{{ ckeditor_media.js }}
<script type="text/javascript" src="{% static 'documents.js' %}"></script>
{% endblock %}
13 changes: 0 additions & 13 deletions apps/documents/templates/a4_candy_documents/react_documents.html

This file was deleted.

Loading

0 comments on commit 04b6b61

Please sign in to comment.