Skip to content

Instantly share code, notes, and snippets.

@nikitalarionov
Last active June 27, 2019 16:08
Show Gist options
  • Save nikitalarionov/e0dbbb580d181e6363b19b49ac1d46d4 to your computer and use it in GitHub Desktop.
Save nikitalarionov/e0dbbb580d181e6363b19b49ac1d46d4 to your computer and use it in GitHub Desktop.
Latest ckEditor DailyNotePlugin
import Command from '@ckeditor/ckeditor5-core/src/command';
export default class EditDailyNoteCommand extends Command {
execute() {
const editor = this.editor;
const model = editor.model;
const doc = model.document;
const selection = doc.selection;
const selectedElement = selection.getSelectedElement();
if (selectedElement.name === 'dailyNote') {
model.enqueueChange(writer => {
const text = selectedElement.getAttribute('text');
const src = selectedElement.getAttribute('src');
writer.setAttribute('text', 'new text', selectedElement);
console.log(editor.getData());
});
}
}
}
/** some text text text and: ....<span class="article-note js-tooltip"><span class="article-note__tooltip"><span class="article-body js-tooltip-body"><img src="https://img03.rl0.ru/afisha/290x-/daily.afisha.ru/uploads/images/9/b5/9b50660636a19bb09f4314aa920cda1d.jpg" classes="article-note__img js-article-note-img"></span></span>new text</span> **/
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import CKEditorInspector from '@ckeditor/ckeditor5-inspector';
import { toWidget, viewToModelPositionOutsideModelElement } from "@ckeditor/ckeditor5-widget/src/utils";
import EditDailyNoteCommand from "./edit_command";
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');
// Register edit command
this.editor.commands.add('editDailyNote', new EditDailyNoteCommand(this.editor));
if (name) {
setTimeout(() => {
// Attach inspector to editor
CKEditorInspector.attach(name, this.editor);
}, 2000);
}
this.editor.editing.mapper.on(
'viewToModelPosition',
viewToModelPositionOutsideModelElement(
this.editor.model,
viewElement => viewElement.hasClass('dailynote')
)
);
this.listenTo( this.editor.editing.view.document, 'click', ( evt, data ) => {
const { domTarget } = data;
if (domTarget.classList.contains('dailynote__icon')) {
this.editor.execute('editDailyNote', {foo: 'bar'});
}
});
}
_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' ]
});
}
_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'),
};
return modelWriter.createElement('dailyNote', context);
}
});
conversion.for('editingDowncast').elementToElement({
model: 'dailyNote',
view: (modelItem, viewWriter) => {
const widgetElement = createDailyNoteView(modelItem, viewWriter);
// Enable widget handling on a daily note element inside the editing view.
return toWidget(widgetElement, viewWriter);
}
});
// Конвектируем dailyNote в выходной формат для фронта дейли
conversion.for('dataDowncast').elementToElement({
model: 'dailyNote',
view: (modelItem, viewWriter) => {
return createDailyNoteOutputView(modelItem, viewWriter, entryType);
}
});
}
}
/**
* Возвращает View для редактирования внутри CkEditor
* @param modelItem
* @param viewWriter
* @return {*}
*/
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);
viewWriter.insert(viewWriter.createPositionAt(dailyNoteView, 0), viewWriter.createText(text));
return dailyNoteView;
};
/**
* Возвращает View для фронта дейли
* @param modelItem
* @param viewWriter
* @param entryType {String} - article, news, etc
*/
const createDailyNoteOutputView = (modelItem, viewWriter, entryType = 'article') => {
const text = modelItem.getAttribute('text');
const src = modelItem.getAttribute('image');
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`
].join(' ')
});
viewWriter.insert(viewWriter.createPositionAt(noteBody, 0), emptyImgElement);
viewWriter.insert(viewWriter.createPositionAt(containerTooltip, 0), noteBody);
viewWriter.insert(viewWriter.createPositionAt(dailyNoteOutputView, 0), containerTooltip);
viewWriter.insert(viewWriter.createPositionAt(dailyNoteOutputView, 0), viewWriter.createText(text));
return dailyNoteOutputView;
};
const getNoteContainerElement = (viewWriter, classes, div = false) => {
return viewWriter.createContainerElement(
div ? 'div' : 'span',
{
class: classes
}
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment