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

Outline RFC 46: Single paragraph rich text fields/blocks #46

Merged
merged 1 commit into from
Apr 21, 2022

Conversation

kaedroho
Copy link
Contributor

@kaedroho kaedroho commented Nov 18, 2019

Rendered

This is an outline proposal for a new field and block type which would behave like a RichTextField/RichTextBlock but only allows a single segment of text.

Inline elements such as formatting and hyperlinks may be allowed. But block elements like paragraphs, images and bullet points will not. The HTML segment in the database will not be enclosed in a <p> tag giving developers more flexibility in where it can be used.

I think this will be very useful for:

  • Introductions/summaries which can usually only be one paragraph but use rich text fields as they may need inline formatting. For example, the sentence above "Tom Dyson" in https://wagtail.io/blog/wagtail-2-7/.
  • Image captions
  • Inline styling in titles. For example https://torchbox.com/digital-products/
  • Make editors use a separate block for each paragraph in StreamFields

We should create a separate type to represent the values of these fields. Having a separate type rather than reusing RichText would be useful because logic, like diffing and translating, would work very differently when working with individual segments.

@kaedroho kaedroho changed the title Outline RFC for single-block rich text fields Outline RFC 46: Single-block rich text fields Nov 18, 2019
@kaedroho kaedroho changed the title Outline RFC 46: Single-block rich text fields Outline RFC 46: Single block rich text fields Nov 18, 2019
@kaedroho kaedroho added the 1:New label Nov 18, 2019
@benjaoming
Copy link

@kaedroho could this be solved with a keyword parameter max_paragraphs for RichTextField?

@kaedroho
Copy link
Contributor Author

kaedroho commented Nov 18, 2019

@kaedroho could this be solved with a keyword parameter max_paragraphs for RichTextField?

This field would have a different internal representation and also be rendered differently on the frontend, so I think it would be best for it to be a different field type. Also, having a separate type would allow us to add APIs that are useful for segments alone, such as converting them to plain text or diffing them. There would also be no need to manually configure rich text features to limit them to inline elements only (I've noticed developers use TextField to work around having to do this).

@kaedroho kaedroho changed the title Outline RFC 46: Single block rich text fields Outline RFC 46: Single paragraph rich text fields Nov 18, 2019
@kaedroho kaedroho changed the title Outline RFC 46: Single paragraph rich text fields Outline RFC 46: Single paragraph rich text fields/blocks Nov 18, 2019
@kaedroho kaedroho added 2:Accepted and removed 1:New labels Nov 20, 2019
Copy link
Member

@thibaudcolas thibaudcolas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 nice, simple RFC. I think this would be very valuable, and as you say should be straightforward to implement.

I’ve made a prototype for this with Draftail a few months ago, https://demo.draftail.org/storybook/?path=/story/plugins--single-line. It:

  • Disables block formatting and block-level entities (images, embeds)
  • Disables pressing "Enter" to create a new block
  • Has a check to automatically concatenate the content to a single line if the user finds a way to enter multiline content (e.g. copy-pasting rich text)

text/046-simple-rich-text.md Show resolved Hide resolved
text/046-simple-rich-text.md Show resolved Hide resolved
text/046-simple-rich-text.md Show resolved Hide resolved
@thibaudcolas
Copy link
Member

thibaudcolas commented May 27, 2021

Does anyone know what the status of this RFC is? I’m interested in implementing this for a client who needs italics in headings, but it looks like it might be possible for me to implement it straight in Wagtail core.

@thibaudcolas
Copy link
Member

Here is my work-in-progress implementation if anyone wants to take a look: wagtail/wagtail#7249.

@kaedroho
Copy link
Contributor Author

kaedroho commented Oct 20, 2021

New idea I've been thinking about that we could do in addition to this

A subclass of StreamBlock that has rich text features built in. You would still sub-class this like you do with StreamBlock but developers wouldn't add paragraph/heading blocks as this would be supplied by the new block type.

For example:

from wagtail.blocks import StoryBlock

class MyStoryBlock(StoryBlock):
    # heading/paragraph block types are inherited
    image = ImageBlock()

The advantage of doing it this way is we can customise the display and behaviour of paragraphs/headings in the editor at the stream level rather than the individual blocks. This would allow us to display consecutive paragraph blocks one single rich text field, but save them as separate blocks.

Advantages of this include:

  • One standard representation of a paragraph and headings inside stream fields. This would make it much easier for us to develop standard import packages (wagtail-content-import, wagtail-wordpress-import). It would also make the API representation of these types consistent making it possible for us to create a standard library for rendering rich text in headless frontends
  • It should make it easier to implement inserting block types between paragraphs in the editor
  • Every paragraph is a separate block, which should make comments and diffing more accurate and also make autosave work better when we implement that
  • The rich text toolbar could be displayed once for the whole streamfield

The definition of this new block type inside Wagtail could be like so:

class HeadingBlock(StructBlock):
    text = ParagraphBlock()
    level = NumberBlock()
    id = CharBlock(required=False)


class ListItemBlock(StructBlock):
    content = ParagraphBlock()
    indent_level = NumberBlock()


class StoryBlock(StreamBlock):
    heading = HeadingBlock()
    paragraph = ParagraphBlock()
    ordered_list_item = ListItemBlock()
    unordered_list_item = ListItemBlock()

   js_component = 'StoryBlock'   # It would have it's own JS component

What do you think?

@thibaudcolas
Copy link
Member

thibaudcolas commented Feb 1, 2022

I’ve advanced this RFC one step in its lifecycle now that we’re making plans to implement this as part of the page editor 2022 project.

I don’t feel competent to provide feedback on Karl’s comment above so would appreciate others stepping in.

For my WIP implementation at wagtail/wagtail#7249 – I still think it’s relevant, although we’re going to be making changes to Draftail directly, as part of which I’d be keen for single-line editing to become a built-in feature of the editor.

@lb-
Copy link
Member

lb- commented Feb 6, 2022

My general thoughts

  • This is a great idea, I think that it has a good use case as described in the RFC.
    1. I think this should be opt in only, it is kind of implied by the RFC but maybe could be clearer that this is another field type that is separate from a standard TextField or CharField and completely opt in based on the use case.
    1. I think this field should be separate from the StoryBlock proposal above, maybe StoryBlock or something similar can exist as a Block wrapper around this new field. In the same way we have a field and block that wraps the field usually, this new field type should follow that convention as not everyone needs to or wants to use StreamFields for their implementation.
    1. Naming - rather than 'segment' or 'story' maybe we could call this something like RichFragmentField (although the term fragment is a bit overloaded from the React space) OR RichInlineTextField to imply that this is best used to contain a single outer inline element.
    1. The concept of HTML inline elements as the baseline for available usage inside this field type could help guide the way this is built also. Link to all inline tags - https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements#list_of_inline_elements (this is mentioned in the RFC already).
    1. Have we thought about this from a translations perspective? I assume this will work just like the RichTextField from that perspective but just ensuring we have not missed anything.

@thibaudcolas thibaudcolas self-assigned this Feb 10, 2022
@thibaudcolas
Copy link
Member

Thank you for the feedback @lb-! To reply to your points:

  • Yes this would be opt-in only
  • I think Karl’s StoryBlock would be an extension of this outside of what the RFC currently covers. Some of the advantages listed by Karl will no longer stand based on what we’re doing over in page editor 2022.
  • For naming, yes, I think it’ll be inline or fragment. The "block" will either render wrapped in a <span> if this is necessary due to how our rich text processing works, or with no wrapper at all so it’s as flexible as possible.
  • For translations, diffing, search – Yes, I think the intention is this works the same as a multiline RichTextField.

@thibaudcolas
Copy link
Member

I have now moved this RFC to 4: Final Comment Period, and will merge it as-is by the end of this week unless there is new feedback on the contents.

@thibaudcolas
Copy link
Member

@kaedroho @jacobtoppm just want to check if you intend to review this further / comment or if you think this is good to go as-is?

Copy link
Member

@emilytoppm emilytoppm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! I think I'm happy with what's been proposed so far. Just a note that for implementation, we'll need to make sure (if we're not persisting the Draftail block ids, as currently inline comment positions store the block id and the offsets) the comment positions are stored and retrieved relative to the start of the field instead if this option is turned on in CommentableEditor. Not a big deal, just thought I'd mention it!

@thibaudcolas
Copy link
Member

👍 thank you! Right now my implementation tasks are here: wagtail/wagtail#8249. The assumption is that draftail would get built-in support for the UI side of this via wagtail/wagtail#8248.

Both of those are quite high-level plans, feel free to add :)

@lb-
Copy link
Member

lb- commented Apr 13, 2022

Draft.js has confirmed that it is no longer maintained. The project will no longer receive updates and the GitHub repo will be archived in October of this year (October 2022).

I think we need to consider this if we are to adopt our wrapper around Draft.js in even more places in Wagtail.

Personally I don't think it's a blocker for this specific RFC but it needs to be a consideration in our long term planning and in how we try to allocate efforts.

For example, should we start the journey of changing the underlying library of Draftail instead of focusing on making Draftail have different features.

Sorry to be a pain with pointing these things out, it's just that a rich text field is far from simple and we want to try to build on something solid (well... As solid as we can get in the npm ecosystem).

facebookarchive/draft-js#3091 (comment)
facebookarchive/draft-js#3136

@thibaudcolas
Copy link
Member

@lb- this is definitely worth being aware of but I don’t think it affects this specific RFC. The RFC itself should be relevant regardless of whichever editor widget ends up supporting it, and the majority of the work needed will be for Wagtail to have this as a new field type.

If we look at the implementation plan (wagtail/wagtail#8248, wagtail/wagtail#8249), about 1/3 of the work is specific to Draftail (and that’s the things I’ve already done as a POC so just need more testing / a better implementation). The remaining 2/3 are about the new field type.

There’s been plenty of validation of this RFC to date so I’ll now merge this and we can proceed with the implementation.

@thibaudcolas thibaudcolas merged commit a83cc37 into main Apr 21, 2022
@thibaudcolas thibaudcolas deleted the simple-rich-text branch April 21, 2022 23:31
@lb-
Copy link
Member

lb- commented Apr 22, 2022

100% agree Thibaud. Thanks for replying, thanks for the amazing work along the way (and yet to do) on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
No open projects
Status: Done
Development

Successfully merging this pull request may close these issues.

9 participants