ckeditor / ckeditor5

Powerful rich text editor framework with a modular architecture, modern integrations, and features like collaborative editing.
https://ckeditor.com/ckeditor-5
Other
9.54k stars 3.7k forks source link

Possible to make editor.getData() returns content with inline styles? #1627

Open nakupanda opened 5 years ago

nakupanda commented 5 years ago

Hi,

Thanks for the new CKEditor (to me it's new).

Here is my question:

When inserting tables, we get content by editor.getData() like:

<figure class="table"><table><tbody><tr><td>....... <table></figure>

In my case, what I actually want is:

<table style="border: 1px solid #ccc...">....</table>

The reason is that the content will be used again in another WYSIWYG editor and finally sent as email and we expect who received the email would see a decently styled email.

Any help would be appreciated.


If you'd like to see this feature implemented, add 👍 to this post.

Mgsy commented 5 years ago

Hello, @nakupanda! Basically, it's possible to achieve the result you mentioned, but it requires changing all downcast converters.

I'll confirm your issue as a feature request. We might create API for this purpose and the feature could be called "inlining styles". Anyway, we can't declare any ETA for this one right now.

nakupanda commented 5 years ago

@Mgsy Great! Thank you for looking at this.

For now I'm switching back to CKEditor 4 for my purpose.

ghost commented 5 years ago

Hi @Mgsy ,I think this feautre is very important.May I know when this feature will be supported? Thanks.

Mgsy commented 4 years ago

Hi @Mgsy ,I think this feautre is very important.May I know when this feature will be supported? Thanks.

Hi @mengjoel, we understand that this feature might be important for you. However, unfortunately, due to other priorities, we don't have ETA for it.

Feel free to add 👍 to the first post, it will allow us to track a popularity of this request.

jswiderski commented 4 years ago

The same goes for images. This is especially important if they are to be used in email templates.

0uergujiaming commented 4 years ago

May I know when this feature will be supported? Thanks.

Reinmar commented 4 years ago

I like the case mentioned in #8004 by @justlester:

Hi! I am using the CKEditor 5 for creating email content.
When I get output data from the editor, the image output in HTML have class styles of "image-style-right":

<figure class="image image_resized image-style-align-right" style="width:484px;">
<img src="https://c.cksource.com/a/1/img/docs/sample-image-bilingual-personality-disorder.jpg">
<figcaption>One language, one person.</figcaption>
</figure>

What I need is:

<figure style="width:484px; float:right;margin: 16px 0 16px 24px;">
<img style="width:100%" src="https://c.cksource.com/a/1/img/docs/sample-image-bilingual-personality-disorder.jpg">
<figcaption style="text-align:center; padding: .6em;font-size: .75em;">One language, one person.</figcaption>
</figure>

Without the styles, I can't display the image properly. I read the documentation but I'm not sure what APIs I will be using.

What it shows is that it's not only about the <figure> itself but also about all the elements inside that might've been styled by a selector consisting of figure.image.

IMO, the same applies to all styles that might've been applied to the content. That includes styles for p, h1, blockquote, etc. The editor does not come with styles for these elements, but the page on which it is integrated usually does. And when trying to reflect the same styles in an email or a different medium (we had the same problem with export to PDF), it's best if these styles are inlined.

Therefore, I think we should consider a mechanism capable of inlining an entire set of styles. It'd be best if it simply combined output HTML + stylesheets.

djkarlos commented 4 years ago

I too use the ckeditor5 to generate HTML for sending as email content. Without the styling inline the recipient doesn't get what we see on screen.

ogabrielsantos commented 4 years ago

I temporarily got around this issue with juice:

const styles = `<styles>
:root {
    --ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
    --ck-color-mention-text: hsl(341, 100%, 30%);
    --ck-highlight-marker-blue: hsl(201, 97%, 72%);
    --ck-highlight-marker-green: hsl(120, 93%, 68%);
    --ck-highlight-marker-pink: hsl(345, 96%, 73%);
    --ck-highlight-marker-yellow: hsl(60, 97%, 73%);
    --ck-highlight-pen-green: hsl(112, 100%, 27%);
    --ck-highlight-pen-red: hsl(0, 85%, 49%);
    --ck-image-style-spacing: 1.5em;
    --ck-todo-list-checkmark-size: 16px;
}

/* ckeditor5-highlight/theme/highlight.css */
.marker-yellow {
    background-color: var(--ck-highlight-marker-yellow);
}

/* and so on.. */
</styles>`;
import InlineEditor from '@ckeditor/ckeditor5-editor-inline/src/inlineeditor';
import CKEditor from '@ckeditor/ckeditor5-react';
import juice from 'juice';

<CKEditor
  editor={InlineEditor}
  data=""
  onChange={(event, editor) => {
    const data = editor.getData();

    console.log(juice.inlineContent(data, styles));
  }}
/>

Worked weel when using CKEDITOR plugins and sending inlined datas as email body.

ps: base64 images doesn't works with major email clients, so I've disabled inline images as this are not one of my requirements ps2: I will be glad to see an official solution

xiongsongsong commented 3 years ago

en.. and i very hope support this feature.

dmboucher commented 3 years ago

We have a need to use the contents of the editor as the body of emails. Most Email clients ignore any non-in-line CSS so we are very interested in an option to output all in-line styles. Thank you!

jerickcm commented 3 years ago

I was panicking that juice was not working in my nuxt project, the installation failed, but when i reinstall the node_modules i was able to install juice.js 7.00 version currently

justlester commented 3 years ago

I was able to create a temporary solution with Vue2 based from @ogabrielsantos's answer. I created a custom component with the following plugins:

  1. @ckeditor/ckeditor5-vue2
  2. juice (needed to convert styles to inline styles)
  3. postcss-css-variables (needed to convert css variables to static values)
Vue.component('ckeditor5-textarea',{
    template: /*html*/`
        <ckeditor :editor="editorBuild" :config="config" v-model="innerEditorValue" @ready="onEditorReady" @input="onEditorChange"></ckeditor>
    `,
    components: {
        ckeditor: CKEditorSource.Vue2CKEditor.component
    },
    props: {
        value: {
            type: String,
            default: ''
        },
        config: {
            type: Object,
            default: ()=>({
                toolbar: {
                    items: [
                        'undo',
                        'redo',
                        '|',
                        'removeFormat',
                        'bold',
                        'italic',
                        'underline',
                        'link',
                        'numberedList',
                        'bulletedList',
                    ],
                },
            })
        }
    },
    data(){
        return {
            editorBuild: CKEditorSource.Editor,
            lastValue: '',
            innerEditorValue: '', 
            editorStyles: '',      
        }
    },  
    mounted() {
         //get ckeditor styles, convert css variables to static using postcss-css-variables
        //and save to editorStyles for later use
        var stylesObj = Array.from(document.getElementsByTagName('style')).find(x=>x.hasAttribute("data-cke"));
        this.editorStyles = CKEditorSource.EditorUtils.postcss([CKEditorSource.EditorUtils.cssvariables()]).process((stylesObj ? stylesObj.innerHTML : '')).css;
    },
    watch: {
        value(newVal,oldVal){
              //prevents undo stack from clearing unless new value is being passed to v-model
            if(newVal !== oldVal && newVal !== this.lastValue){
                this.innerEditorValue = (newVal || '');
            }
        }
    },
    methods: {
        onEditorReady(editor){
            //set editor value after created
            this.innerEditorValue = this.value || '';
            this.$emit('ready',editor);
        },
        onEditorChange(value){
            //with the editorStyles, convert using juice
           //and emit back the value with the inline style
            var htmlWithInlineStyles = CKEditorSource.EditorUtils.juice.inlineContent(`<div class="ck-content">${value}</div>`,this.editorStyles);
            var div = document.createElement('div'); 
            div.innerHTML = htmlWithInlineStyles;
            var currentData = div.firstChild ? div.firstChild.innerHTML : '';
            //set the lastValue 
            var d = this.lastValue = currentData;
            this.$emit('input',d);
        },
    },
});
zomby22 commented 3 years ago

for me installing Juice with ckeditor 5 version 28.0.0 cause the ckeditor to not display on the page after building the js file. why couldnt it be built simplier, like emailStyleFormat: true or false (if false use the bootstrap classes, else used the styling for Outlook). All I want is to see the colors (font colors, background colors, table borders and highlight colors) to be supported with Outlook emails.

what's the easiest method (how to downcast in using legacy styling instead)

jesstrable commented 3 years ago

Any status update on this request? Seems like a potential blocker to using CKEditor5 if the purpose is to create emails. Has any work arounds been established to support this email build use case in 5?

kuku711 commented 2 years ago

This feature is very important! Please help us get this thing faster, breaking changes between ck4 and ck5 should be prioritize...

** After further checking it seems most classes are required with .ck.ck-content and when showing them on other screens/emails style must be added... This is a problem to solve as soon as possible...

rasimatics commented 2 years ago

I think this feature is very important. At least for web we can solve this issue with adding full css to our document. What about mobile application? Because rich text content can be rendered also for mobile devices.

ortonomy commented 2 years ago

Hi, it's 2022 and this is still a feature that is not in the editor? I'm frankly astonished that this is not included as default prop to react component / setting in the CKEditor. You even advertise the editor as being suitable for email content.

What's going on? 3 years later?

sluc23 commented 2 years ago

This is blocking issue for us to start using CKEditor5 to compose email templates. I don't see the point of composing html with css classes that are only defined in the scope of CKEditor5, and are not included in the final html result.

Or you include the css classes definitions as part of the html result inside <style> or you include all of those as inline styles as <table style="..."> If not the html composed it's only properly visible inside the CKEditor5 box, but not outside of it..

rferons commented 1 year ago

I want to add my comment that this is a really important feature. I just finished implementing email templates using ckeditor5 before realizing that styles don't translate over into email clients. Inlining the styles is extremely important for content portability beyond just the email use case. Hopefully we will hear an update on this request soon...

ekoooo commented 1 year ago

hi, this is my temporary solution 😁

  1. get content styles.
  2. get editor content value.
  3. use juice convert styles to inline styles.
import juice from 'juice';

const CkeditorUtil = {
  getEditorStyles() {
    const cssTexts = [], rootCssTexts = [];

    for (const styleSheets of document.styleSheets) {
      if (styleSheets.ownerNode.hasAttribute('data-cke')) {
        for (const cssRule of styleSheets['cssRules']) {
          if (cssRule.cssText.indexOf('.ck-content') !== -1) {
            cssTexts.push(cssRule.cssText);
          } else if (cssRule.cssText.indexOf(':root') !== -1) {
            rootCssTexts.push(cssRule.cssText);
          }
        }
      }
    }

    return cssTexts.length ? [...rootCssTexts, ...cssTexts].join(' ').trim() : '';
  },
  getContentWithLineStyles(editorContent) {
    return juice.inlineContent(`<div class="ck-content">${editorContent}<div>`, CkeditorUtil.getEditorStyles());
  }
};

export default CkeditorUtil;
// convert
CkeditorUtil.getContentWithLineStyles(editorContent);

if you needed to convert css variables to static values, You can refer to this code.

OzgurAkinci commented 1 year ago

This feature is really important. I don't understand how it got such a negative response. Also, this problem has been going on for a long time. Up to 3 years long.

ashishforgrz commented 1 year ago

Is there any update for this feature??

AliaksandrBortnik commented 1 year ago

As for the temp fix using juice to dynamically inject inline styles suggested by @ogabrielsantos, I see there might be an issue regarding the format of injected inline styles.

  1. CKE5 internally shrinks inline styles and outputs them compressed: styles="font-weight:10px;color:black".
  2. Unlike juice that injects in a standard CSS way with white-spaces between CSS properties: styles="font-weight: 10px; color: black".

Is there someone who synchronized inline handling between CKE5 and juice approaches, or any reliable way to achieve it without RegExp? Otherwise, it would trigger redundant value update (CKE5 content data). Especially if React or similar has been used, onChange would change the output value each time with juice, then CKE5 compresses the injected styles back.

ferreira-tb commented 1 year ago

This feature would really be great. Looking forward to it being implemented.

o-yanchenko commented 11 months ago

Bump! We've been waiting for this feature for ages. The CKEditor community really needs this!

NvanWeeghel commented 8 months ago

+1

edwardbryant commented 8 months ago

Been waiting so long for this, please make this happen soon.

Alejjito commented 7 months ago

Estuve revisando y aun no esta esa funcion, realmente es importante, consideo que lo hacen para que se pague la licencia premium para exportar en pdf y en word :(

ilapavuluri commented 6 months ago

Looking forward to it being implemented.

mohdabidansari commented 5 months ago

Any update? Wanted this feature

mvprabhu-ma commented 4 months ago

I recently encountered similar issue. To address this, I developed a custom plugin that overrides the 'insertTable' command's default behavior. Upon executing the 'insertTable' command, my plugin not only inserts the table but also applies predefined styles directly to the table and its cells. The Approach: My solution involves setting an observer on the 'insertTable' command. When a table is inserted, the plugin programmatically invokes style commands, such as TableBorderStyleCommand and TableCellBorderStyleCommand, ensuring the styles are applied inline. I'm sharing the core part of my custom plugin below, hoping it might help others facing similar challenges:


setObserver(): void {
    const editor = this.editor;
    const insertTableCommand = editor.commands.get('insertTable');

    // Store the original execute method
    const originalExecute = insertTableCommand.execute.bind(insertTableCommand);

    // Override the execute method
    insertTableCommand.execute = (options?) => {
      // Call the original execute method to actually insert the table
      originalExecute(options);

      // Apply styles to the newly inserted table
      this.applyStylesToTable(editor);

      // Apply styles to all the cells in the newly inserted table
      this.applyStylesToTableCells(editor);
    };
}

applyStylesToTable(editor: Editor): void {
    const commands = editor.commands;
    // Apply the border styles
    commands.get('tableBorderStyle')?.execute({ value: 'solid' });
}

applyStylesToTableCells(editor: Editor): void {
    const commands: CommandCollection = editor.commands;

    // Get the newly created table element in the document.
    const table = this.getCreatedTable(editor);

    if (table) {
        // Select all table cells
        this.selectAllCells(editor, table);

        // Apply the border styles
        (commands.get('tableCellBorderStyle') as TableCellBorderStyleCommand)?.execute({ value: 'solid' });

        // Select first cell of the table (so as to maintain the previous behavior of having first cell as selected after inserting a table)
        this.selectFirstCell(editor, table);
    }
}

This custom plugin effectively solves the issue by ensuring that every table inserted through the editor comes with the desired inline styles, fulfilling the requirements for direct HTML styling. I hope this solution proves useful to others in the community. Feedback or suggestions for improvement are welcome!

Best regards, Venkatesh

bosemian commented 2 months ago

Is there any update. ? Anybody have the idea for save output and render it on pdf with content style ?

aoleksyshyn-spscommerce commented 2 months ago

5 years later... CKEditor team still has other higher priorities.

Witoso commented 2 months ago

Hey, we appreciate all the pings, we have plans to jump to this topic this year, so stay tuned.

corneliu-gavrilovici commented 1 month ago

+1

trieu-hphuc96 commented 1 month ago

+1

IKK-LTU commented 1 month ago

🆙

hisham-othman commented 1 month ago

+1

Kolizzz commented 1 month ago

+5

OWS-thinhpv commented 2 weeks ago

+99999999999999999

tienanh2907 commented 2 weeks ago

let's do it, please

ngphuc2808 commented 2 weeks ago
amanmishra1321 commented 1 week ago

+2

iea79 commented 3 days ago

You can get HTML like this: editor.sourceElement.innerHTML