Is there a way to create a custom plugin for CK Editor to support inline SVGs? - ckeditor

I want to create a plugin that lets users insert a widget with a SVG icon and some text. I created the widget that allows the user to add text but when I try to add an SVG it striped all of my attributes out. Is there a way to allow inline SVGs inside of the editor. I can not find any documentation on SVG support.
schema.register('actionIcon', {
allowWhere: '$text',
isInline: true
allowAttributes: ['name', 'class']
})
schema.register('actionCircle', {
allowWhere: '$text',
isInline: true,
allowAttributes: ['name', 'class', 'cx', 'cy', 'r', 'stroke', 'fill']
})
// ...
conversion.elementToElement({
model: 'actionIcon',
view: {
name: 'svg',
classes: 'action-icon'
}
})
conversion.elementToElement({
model: 'actionCircle',
view: {
name: 'circle',
classes: 'action-circle',
['cx']: '50',
['cy']: '50',
['r']: '40',
['stroke']: 'green',
['fill']: 'yellow'
}
})
Result:
<p>
<svg class="action-icon">
<circle class="action-circle"> </circle>
</svg>
<span class="placeholder ck-widget" contenteditable="false">
Item
</span>
</p>
I expected to create a scheme and converter for an svg and insert that into the widget but ck editor strips away all the attributes I verbosely defined.

Related

How to style a data table td in Vuetify?

Good Afternoon.
I'm trying to build a stylized table with "v-data-table", without being used to it. Mainly put style into second or third cell (table, tr, td). I don't find the solution for my problem. Help me, please.
thanks.
You can use the item-class attributes to style every row
Property on supplied items that contains item’s row class or function that takes an item as an argument and returns the class of corresponding row
It works as the following :
It takes a function as argument that return a class depending on the row.
If you want to return a specific class depending on the item use it like this :
<template>
<v-datad-table :item="items" :item-class="getMyClass"></v-data-table>
</template>
<script>
methods: {
getMyClass(item){
// here define your logic
if (item.value === 1) return "myFirstClass"
else return "mySecondClass"
}
}
</script>
If you want to always give the same class you can just return the class you want to give (note that this is the same as stylized the td of the table using css)
<template>
<v-data-table :items="items" :item-class="() => 'myClass'"></v-data-table>
</template>
In your case, you can add an index to your data using a computed property and added a class based on the index
computed: {
myItemsWithIndex(){
retunr this.items.map((x, index) => {...x, index: index})
}
}
methods: {
getMyClass(item){
if(item.index === 2 || item.index === 3) return "myClass"
}
}
Working example
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => {
return {
items: [
{name: "foo"},
{name: "bar"},
{name: "baz"},
{name: "qux"},
{name: "quux"},
{name: "corge"},
{name: "grault"},
],
headers: [{ text: 'Name', value: 'name'}],
}
},
computed: {
itemsWithIndex(){
return this.items.map((item, index) => ({ ...item, index:index }))
}
},
methods: {
getMyClass(item){
if(item.index === 2 || item.index === 3){
return "myClass"
} else return
}
}
})
.myClass {
background: red
}
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.css" />
<div id="app" data-app>
<v-data-table :items="itemsWithIndex" :headers="headers" :item-class="getMyClass"></v-data-table>
</div>
I'd bet that what you're trying to achieve can be done using named slots
See this example from the docs. Basically, the template tag you see in the example will become whatever node is 'above it' (which it really isn't because it takes its place, but you get the point). For instance, in the case of data-tables, <template #item="{ item }">... represents every <td> of your table. Then you can use the destructured item and apply some logic to it to still of modify you table as you will.
Don't forget to upvote/validate the answer if it helped your to solve your issue, comment if you need more details and welcome to Stack!
There are also the possibility to use cellClass, which is part of the headers.
The image is from https://vuetifyjs.com/en/api/v-data-table/#props
As computed property i have:
headers() {
return [
{ text: this.$t('Name'), align: 'left', sortable: true, value: 'name', cellClass:'select' },
{ text: 'CVR', sortable: false, value: 'cvrno' },
{ text: this.$t('Updated At'), sortable: false, value: 'updatedAt' }
]
},
and by v-data-table tag looks like:
<v-data-table
v-model="selected"
:headers="headers"
:items="customerFiltered"
:loading="loadingCustomers"
:items-per-page="-1"
selected-key="id"
show-select
hide-default-footer
fixed-header
>

Vuetify breadcrumbs text color

I'm trying to have different text colors for my breadcrumbs based on a property but I can't figure out how to apply those colors anywhere. Can't add a color or class in the items either.
breadcrumbItems() {
return [
{
text: this.$t("receiving.breadcrumbs.step1"),
disabled: this.item.Status !== "STEP1"
},
{
text: this.$t("receiving.breadcrumbs.step2"),
disabled: this.item.Status !== "STEP2"
},
{
text: this.$t("receiving.breadcrumbs.step3"),
disabled: this.item.Status !== "STEP3"
}
];
}
<v-breadcrumbs :items="breadcrumbItems" class="breadStyle">
<template v-slot:divider>
<v-icon size="25">mdi-forward</v-icon>
</template>
</v-breadcrumbs>
Looking at the API for v-breadcrumbs: https://vuetifyjs.com/en/api/v-breadcrumbs-item/ it doesn't provide a property "color" or something similar, but there is a slot, so you can pass any kind of components in it.
You can create a <span> and customize its color and its style depending on the items:
<template>
<v-breadcrumbs :items="items">
<template v-slot:divider>
<v-icon size="25">mdi-forward</v-icon>
</template>
<template v-slot:item="{ item }">
<v-breadcrumbs-item :disabled="item.disabled">
<span :style="`color: ${item.color}`">
{{ item.text.toUpperCase() }}
</span>
</v-breadcrumbs-item>
</template>
</v-breadcrumbs>
</template>
<script>
export default {
data: () => ({
items: [
{
text: "Dashboard",
disabled: false,
color: "green",
},
{
text: "Link 1",
disabled: false,
color: "blue",
},
{
text: "Link 2",
disabled: true,
color: "red",
},
],
}),
};
</script>
I've found that the deep selector (https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors) often helps with styling Vuetify components. I added this to my components scoped CSS and the colours work just fine for links:
.v-breadcrumbs >>> a {
color: purple;
}
I found the relevant tag by looking through the Elements-tab under Inspect (in Chrome).
I don't know if this is the best solution for your specific situation, but figured I'd add this for anyone with a simpler use case.

Setting width of Image in CKEditor 5

I have a page where I use CKEditor 5 with CKFinder 3.
By default, the images that are included in the textarea are responsive and can only be aligned as full or right.
The concerning page has photos of contacts on it and they shouldn't be that big.
How can I configure the width of an image that is inserted through the button of the toolbar?
ClassicEditor
.create( document.querySelector( '#pageTextArea' ), {
image: {
styles: [ { name: 'contact', icon: 'right', title: 'My contact style', className: 'my-contact-side-image' } ]
}
ckfinder: {
uploadUrl: 'example.com/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json'
}
})
.catch( error => {
console.error( error );
process.exit(1);
});
To provide some custom image styling you need to:
First, configure the image.styles option.
ClassicEditor.create( element, {
// ...
image: {
// ...
styles: [
// Pottentially some other style can go here. E.g. the `full` or `side`.
{ name: 'contact', icon: 'right', title: 'My contact style', className: 'my-contact-side-image' }
]
}
}
And secondly, make the image 100px wide via CSS:
.ck-content figure.image.my-contact-side-image {
float: right;
width: 100px;
}
Note that you need to handle styles of the created content outside of the editor as well.

How to set the height of CKEditor 5 (Classic Editor)

In CKEditor 4 to change the editor height there was a configuration option: config.height.
How do I change the height of CKEditor 5? (the Classic Editor)
Answering my own question as it might help others.
CKEditor 5 no longer comes with a configuration setting to change its height.
The height can be easily controlled with CSS.
There is one tricky thing though, if you use the Classic Editor:
<div id="editor1"></div>
ClassicEditor
.create( document.querySelector( '#editor1' ) )
.then( editor => {
// console.log( editor );
} )
.catch( error => {
console.error( error );
} );
Then the Classic Editor will hide the original element (with id editor1) and render next to it. That's why changing height of #editor1 via CSS will not work.
The simplified HTML structure, after CKEditor 5 (the Classic Editor) renders, looks as follows:
<!-- This one gets hidden -->
<div id="editor1" style="display:none"></div>
<div class="ck-reset ck-editor..." ...>
<div ...>
<!-- This is the editable element -->
<div class="ck-blurred ck-editor__editable ck-rounded-corners ck-editor__editable_inline" role="textbox" aria-label="Rich Text Editor, main" contenteditable="true">
...
</div>
</div>
</div>
In reality the HTML is much more complex, because the whole CKEditor UI is rendered. However the most important element is the "editing area" (or "editing box") marked with a ck-editor__editable_inline class:
<div class="... ck-editor__editable ck-editor__editable_inline ..."> ... </div>
The "editing area" is the white rectangle where one can enter the text. So to style / change the height of the editing area, it is enough to target the editable element with CSS:
<style>
.ck-editor__editable_inline {
min-height: 400px;
}
</style>
Setting the height via a global stylesheet.
Just add to your common .css file (like style.css):
.ck-editor__editable {
min-height: 500px;
}
In the case of ReactJS.
<CKEditor
editor={ClassicEditor}
data="<p>Hello from CKEditor 5!</p>"
onInit={(editor) => {
// You can store the "editor" and use when it is needed.
// console.log("Editor is ready to use!", editor);
editor.editing.view.change((writer) => {
writer.setStyle(
"height",
"200px",
editor.editing.view.document.getRoot()
);
});
}}
/>
editor.ui.view.editable.editableElement.style.height = '300px';
From CKEditor 5 version 22 the proposed programmatic solutions are not working. Here it is how I get the work done:
ClassicEditor.create( document.querySelector( '#editor' ) )
.then( editor => {
editor.ui.view.editable.element.style.height = '500px';
} )
.catch( error => {
console.error( error );
} );
.ck-editor__editable {min-height: 500px;}
<div>
<textarea id="editor">Hi world!</textarea>
</div>
<script src="https://cdn.ckeditor.com/ckeditor5/22.0.0/classic/ckeditor.js"></script>
Add this to your stylesheet:
.ck-editor__editable {
min-height: 200px !important;
}
If you wish to do this programatically, the best way to do it is to use a Plugin. You can easily do it as follows. The following works with CKEditor 5 version 12.x
function MinHeightPlugin(editor) {
this.editor = editor;
}
MinHeightPlugin.prototype.init = function() {
this.editor.ui.view.editable.extendTemplate({
attributes: {
style: {
minHeight: '300px'
}
}
});
};
ClassicEditor.builtinPlugins.push(MinHeightPlugin);
ClassicEditor
.create( document.querySelector( '#editor1' ) )
.then( editor => {
// console.log( editor );
})
.catch( error => {
console.error( error );
});
Or if you wish to add this to a custom build, you can use the following plugin.
class MinHeightPlugin extends Plugin {
init() {
const minHeight = this.editor.config.get('minHeight');
if (minHeight) {
this.editor.ui.view.editable.extendTemplate({
attributes: {
style: {
minHeight: minHeight
}
}
});
}
}
}
This adds a new configuration to the CKEditor called "minHeight" that will set the editor minimum height which can be used like this.
ClassicEditor
.create(document.querySelector( '#editor1' ), {
minHeight: '300px'
})
.then( editor => {
// console.log( editor );
} )
.catch( error => {
console.error( error );
} );
I tried to set the height and width on the config but it just didn't work on the classic Editor.
I was able to change the height of the editor programmatically on Vue by doing this.
mounted() {
const root = document.querySelector('#customer_notes');
ClassicEditor.create(root, config).then(editor=>{
// After mounting the application change the height
editor.editing.view.change(writer=>{
writer.setStyle('height', '400px', editor.editing.view.document.getRoot());
});
});
}
Use css:
.ck.ck-editor__main .ck-content {
height: 239px;
}
Add this to your global stylesheet, this will increase the size of the CKEditor :)
.ck-editor__editable_inline {
min-height: 500px;
}
Just add it to the style tag.
<style>
.ck-editor__editable
{
min-height: 150px !important;
max-height: 400px !important;
}
</style>
As for configuring the width of the CKEditor 5:
CKEditor 5 no longer comes with a configuration setting to change its width but its width can be easily controlled with CSS.
To set width of the editor (including toolbar and editing area) it is enough to set width of the main container of the editor (with .ck-editor class):
<style>
.ck.ck-editor {
max-width: 500px;
}
</style>
Simply you can add this to your CSS file
.ck-editor__editable {min-height: 150px;}
Put this CSS in your global CSS file and the magic will happen. CkEditor is full of unsolved mysteries.
.ck-editor__editable_inline {
min-height: 400px;
}
Use max-height and min-height both. Beacuse max-height give scroll bar option after reached maximum mention height. Where min-height give static height to <textarea>.
.ck-editor__editable {
max-height: 400px; min-height:400px;}
If its in latest version of Angular say 12 or 12+. We can add below style to your components style file.
:host ::ng-deep .ck-editor__editable_inline { min-height: 300px; }
If you use jQuery and the CKEditor 5 has to be applied to a textarea, there is a "quick and dirty" solution.
The condition:
<textarea name='my-area' id='my_textarea_id'>
If you use jQuery the Editor call could be:
var $ref=$('#my_textarea_id');
ClassicEditor
.create( $ref[0] ,{
// your options
} )
.then( editor => {
// Set custom height via jQuery by appending a scoped style
$('<style type="text/css" scoped>.ck-editor .ck-editor__editable_inline {min-height: 200px !important;}</style>').insertAfter($ref);
} )
.catch( error => {
console.error( error );
} );
In other words, after rendering, you can address the same element used to build the editor and append after a scoped style tag with containing the custom height.
$('<style type="text/css" scoped>.ck-editor .ck-editor__editable_inline {min-height: 200px !important;}</style>').insertAfter($ref);
If you like to use a function (or some class method) to do this, you need something like this:
var editorBuildTo = function(id,options){
var options=options || {};
//Height represents the full widget height including toolbar
var h = options.height || 250; //Default height if not set
var $ref = $('#'+id);
h=(h>40?h-40:h);//Fix the editor height if the toolbar is simple
ClassicEditor
.create( $ref[0] ,{
// your options
} )
.then( editor => {
// Set custom height via jQuery
$('<style type="text/css" scoped>.ck-editor .ck-editor__editable_inline {min-height: '+h+'px !important;}</style>').insertAfter($ref);
} )
.catch( error => {
console.error( error );
} );
}
editorBuildTo('my_textarea_id',{
height:175,
// other options as you need
});
This works well for me
1.resource/assets/js/app.js
=================================
2.paste this code
=================================
require('./bootstrap');
//integrate
window.ClassicEditor = require('#ckeditor/ckeditor5-build-classic');
============================================
3.write on terminal
============================================
npm install --save #ckeditor/ckeditor5-build-classic
npm run watch
=======================================
4.in blade file
=======================================
<!DOCTYPE html>
<html lang="en">
<title></title>
<body>
<form action="{{route('admin.category.store')}}" method="post" accept-charset="utf-8">
#csrf
<div class="form-group row">
<div class="col-sm-12">
<label class="form-control-label">Description:</label>
<textarea name="description" id="editor" class="form-control" row="10" cols="80"></textarea>
</div>
</div>
</form>
<script>
$(function () {
ClassicEditor
.create( document.querySelector( '#editor' ), {
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote' ],
heading: {
options: [
{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },
{ model: 'heading1', view: 'h1', title: 'Heading 1', class: 'ck-heading_heading1' },
{ model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' }
]
}
} )
.catch( error => {
console.log( error );
} );
})
</script>
</body>
</html>
click to show image here
Building on #Jaskaran Singh React solution. I also needed to ensure it was 100% height to it's parent. I achieved this by assigning a ref called "modalComponent" and further adding this code:
editor.editing.view.change(writer => {
let reactRefComponentHeight = this.modalComponent.current.offsetHeight
let editorToolbarHeight = editor.ui.view.toolbar.element.offsetHeight
let gapForgiveness = 5
let maximizingHeight = reactRefComponentHeight - editorToolbarHeight - gapForgiveness
writer.setStyle(
'height',
`${maximizingHeight}px`,
editor.editing.view.document.getRoot()
)
})
This CSS Method works for me:
.ck-editor__editable {
min-height: 400px;
}
I resolve this just adding in my layout page
<style>
.ck-content{
height: 250px;
}
</style>
Hope i help someone :D
For this particular version https://cdn.ckeditor.com/4.16.0/standard/ckeditor.js,
the below code block worked for me.
.cke_contents { height: 500px !important; }
I guess the difference is just the fact that is it in plural.
In my case it worked for me
Add a ck class and write style like below:
<style>
.ck {
height: 200px;
}
</style>
Using plugin here I came up with this
let rows: number;
export class MinHeightPlugin {
constructor(public editor) {
}
init = function () {
this.editor.ui.view.editable.extendTemplate({
attributes: {
style: {
minHeight: (rows * 40) + 'px',
}
}
});
};
}
export const MinHeightPluginFactory = (rowss: number): typeof MinHeightPlugin => {
rows = rowss;
return MinHeightPlugin;
};
and the usage(4 rows each rows is considered 40px height):
this.editor.builtinPlugins.push(MinHeightPluginFactory(4));
I couldn't manage to make rows variable local to MinHeightPlugin, does anyone know how to do it?
.ck-editor__editable_inline {
min-height: 400px;
}
This makes height change for every editor used across all components. So it doesn't work in my case.
In Case of react js
<CKEditor
toolbar = {
[
'heading',
'bold',
'Image'
]
}
editor={ClassicEditor}
data={this.state.description}//your state where you save data
config={{ placeholder: "Enter description.." }}
onChange={(event, editor) => {
const data = editor.getData();
this.setState({
description : data
})
}}
onReady={(editor)=>{
editor.editing.view.change((writer) => {
writer.setStyle(
//use max-height(for scroll) or min-height(static)
"min-height",
"180px",
editor.editing.view.document.getRoot()
);
});
}}
/>
In order to enable both rich text editor and source mode to have the same height, use the following CSS:
.ck-source-editing-area,
.ck-editor__editable {
min-height: 500px;
}
.ck-editor__main {
height: 500px;
min-height: 500px;
max-height: 500px;
overflow-y: scroll;
border: 1px solid #bbbbbb;
}
Just test it's work. Hoping help you
var editor_ = CKEDITOR.replace('content', {height: 250});

Custom legend labels in my rechart chart

I have a pretty straight forward data array for my recharts component :
{name: '12.1.2011', series1: 4000, series2: 2400, series3: 2400},
{name: '12.2.2011', series1: 3000, series2: 1398, series3: 2210},
{name: '12.3.2011', series1: 2000, series2: 9800, series3: 2290}
I would like to have labels for the series values in my Legend. Instead of the chart showing me the different colors for "series1", "series2", and "series3".
Of course I could set the actual values I want to use for my legend in the JSON already but this just doesn't look right. Eg :
{name: '12.1.2011', 'My nice long descriptive text': 4000, 'Some other text': 2400, 'Some other descriptive text': 2400},
{name: '12.2.2011', 'My nice long descriptive text': 3000, 'Some other text': 1398, 'Some other descriptive text: 2210},
{name: '12.3.2011', 'My nice long descriptive text': 2000, 'Some other text': 9800, 'Some other descriptive text: 2290}
I need to map my series level to a descriptive label.
I have looked at content in Legend : http://recharts.org/#/en-US/api/Legend, but that seems more concerned with completely rewriting the Legend Component.
In your Line, Bar and Area add a name attribute.
Example:
<Line name="# Apples" type="monotone" dataKey="series1" stroke="#FF0000" />
<Line name="# Bananas" type="monotone" dataKey="series2" stroke="#FFFF00" />
<Line name="# Grapes" type="monotone" dataKey="series3" stroke="#FF00FF" />
The legend will pick this up automatically:
http://recharts.org/en-US/api/Legend
By default, the content of legend is generated by the name of Line,
Bar, Area, etc. When no name has been setted, dataKey will be used to
generate legend content alternatively.
If you're looking to get this working on a <Pie /> you can override the <Legend /> payload. Please see the following example;
<Legend
payload={
data.map(
(item, index) => ({
id: item.name,
type: "square",
value: `${item.name} (${item.value}%)`,
color: colors[index % colors.length]
})
)
}
/>
http://recharts.org/en-US/api/Legend#payload
For custom legend, use content props, Ref: https://recharts.org/en-US/api/Legend#content
const renderLegend = (props) => {
const { payload } = props;
return (
<ul>
{
payload.map((entry, index) => (
<li key={`item-${index}`}>{entry.value}</li>
))
}
</ul>
);
}
<Legend content={renderLegend} />

Resources