Skip to content

Instantly share code, notes, and snippets.

@nikitalarionov
Last active June 26, 2019 15:05
Show Gist options
  • Save nikitalarionov/61d56a0dacf8d63d8474854938b94643 to your computer and use it in GitHub Desktop.
Save nikitalarionov/61d56a0dacf8d63d8474854938b94643 to your computer and use it in GitHub Desktop.
Note plugin example
// Example of data provided in ckEditor
// DATA = '`some text text text and: .... <div class="article-note js-tooltip">листовки<span class="article-note__tooltip"><span class="article-note__body js-tooltip-body" data-referal=""><img src="https://img03.rl0.ru/afisha/290x-/daily.afisha.ru/uploads/images/9/b5/9b50660636a19bb09f4314aa920cda1d.jpg" class="article-note__img js-article-note-img"></span></span></div>`;'
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import CKEditorInspector from '@ckeditor/ckeditor5-inspector';
import {toWidget, toWidgetEditable, viewToModelPositionOutsideModelElement} from "@ckeditor/ckeditor5-widget/src/utils";
const baseEditingCls = 'dailynote';
export default class DailyNote extends Plugin {
static get requires() {
return [ Widget ];
}
init() {
this._defineSchema();
this._defineConverters();
const name = this.editor.config.get('instanceName');
if (name) {
setTimeout(() => {
// Attach inspector to editor
CKEditorInspector.attach(name, this.editor);
}, 2000);
}
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( 'dailyNote', {
// Allow wherever text is allowed:
allowWhere: '$text',
// The daily note will act as an inline node:
isInline: true,
// The inline widget is self-contained
// It cannot be split by the caret and can be selected
isObject: true,
allowAttributes: [ 'text' , 'src' ]
});
schema.register('dailyNoteText', {
allowWhere: 'dailyNote',
isInline: true,
allowAttributes: [ 'text' ]
});
}
_defineConverters() {
const conversion = this.editor.conversion;
const entryType = this.editor.config.get('entryType');
conversion.for( 'upcast' ).elementToElement({
view: {
name: 'div',
classes: [ 'js-tooltip' ]
},
model: (viewElement, modelWriter) => {
const text = viewElement.getChild(0).data;
const img = viewElement.getChild(1).getChild(0).getChild(0);
const context = {
text,
image: img.getAttribute('src'),
};
const dailyNote = modelWriter.createElement('dailyNote', context);
modelWriter.appendElement('dailyNoteText', { text }, dailyNote);
return dailyNote;
}
});
conversion.for('editingDowncast').elementToElement({
model: 'dailyNote',
view: (modelItem, viewWriter) => {
const widgetElement = createDailyNoteView(modelItem, viewWriter);
return toWidget(widgetElement, viewWriter);
}
});
conversion.for( 'editingDowncast' ).elementToElement( {
model: 'dailyNoteText',
view: ( modelElement, viewWriter ) => {
const text = modelElement.getAttribute('text');
// Note: You use a more specialized createEditableElement() method here.
const spanEl = viewWriter.createEditableElement( 'span', {
class: `${baseEditingCls}__text`
});
viewWriter.insert(viewWriter.createPositionAt(spanEl, 0), viewWriter.createText(text));
return toWidgetEditable( spanEl, viewWriter );
}
});
conversion.for('dataDowncast').elementToElement({
model: 'dailyNote',
view: (modelItem, viewWriter) => {
return createDailyNoteOutputView(modelItem, viewWriter, entryType);
}
});
}
}
const createDailyNoteView = (modelItem, viewWriter) => {
const noteIconSrc = '/assets/icons/note-icon.svg';
const text = modelItem.getAttribute('text');
const dailyNoteView = getNoteContainerElement(viewWriter, baseEditingCls);
const imgIconEmptyElement = viewWriter.createEmptyElement( 'img' , {
'src': noteIconSrc,
'class': `${baseEditingCls}__icon`
});
viewWriter.insert(viewWriter.createPositionAt(dailyNoteView, 0), imgIconEmptyElement);
return dailyNoteView;
};
const createDailyNoteOutputView = (modelItem, viewWriter, entryType = 'article') => {
const text = modelItem.getAttribute('text');
const src = modelItem.getAttribute('src');
const className = `${entryType}-note js-tooltip`;
const tooltipClassName = `${entryType}-note__tooltip`;
const bodyClassName = `${entryType}-body js-tooltip-body`;
const dailyNoteOutputView = getNoteContainerElement(viewWriter, [className]);
const containerTooltip = getNoteContainerElement(viewWriter, [tooltipClassName]);
const noteBody = getNoteContainerElement(viewWriter, [bodyClassName]);
const emptyImgElement = viewWriter.createEmptyElement('img', {
src,
classes: [
`${entryType}-note__img`,
`js-${entryType}-note-img`
]
});
viewWriter.insert(viewWriter.createPositionAt(dailyNoteOutputView, 0), viewWriter.createText(text));
viewWriter.insert(viewWriter.createPositionAt(noteBody, 0), emptyImgElement);
viewWriter.insert(viewWriter.createPositionAt(containerTooltip, 0), noteBody);
viewWriter.insert(viewWriter.createPositionAt(dailyNoteOutputView, 0), containerTooltip);
return dailyNoteOutputView;
};
const getNoteContainerElement = (viewWriter, classes) => {
return viewWriter.createContainerElement(
'span',
{
class: classes
}
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment