128 lines
3.7 KiB
JavaScript
128 lines
3.7 KiB
JavaScript
import {
|
|
Plugin,
|
|
Widget,
|
|
toWidget,
|
|
viewToModelPositionOutsideModelElement,
|
|
} from "ckeditor5";
|
|
import FieldCommand from "./fieldcommand";
|
|
|
|
// Helper functions to avoid extending String prototype
|
|
const rtrim = (str, s) => {
|
|
if (s === undefined) s = "\\s";
|
|
return str.replace(new RegExp("[" + s + "]*$"), "");
|
|
};
|
|
const ltrim = (str, s) => {
|
|
if (s === undefined) s = "\\s";
|
|
return str.replace(new RegExp("^[" + s + "]*"), "");
|
|
};
|
|
|
|
export class FieldConfig {
|
|
fields = [];
|
|
}
|
|
|
|
export default class FieldEditing extends Plugin {
|
|
static get requires() {
|
|
return [Widget];
|
|
}
|
|
|
|
init() {
|
|
this._defineSchema();
|
|
this._defineConverters();
|
|
|
|
this.editor.commands.add("field", new FieldCommand(this.editor));
|
|
|
|
this.editor.editing.mapper.on(
|
|
"viewToModelPosition",
|
|
viewToModelPositionOutsideModelElement(this.editor.model, (viewElement) =>
|
|
viewElement.hasClass("field"),
|
|
),
|
|
);
|
|
this.editor.config.define("fieldConfig", FieldConfig);
|
|
}
|
|
|
|
_defineSchema() {
|
|
const schema = this.editor.model.schema;
|
|
|
|
schema.register("field", {
|
|
// Behaves like a self-contained inline object (e.g. an inline image)
|
|
// allowed in places where $text is allowed (e.g. in paragraphs).
|
|
// The inline widget can have the same attributes as text (for example linkHref, bold).
|
|
inheritAllFrom: "$inlineObject",
|
|
|
|
// The field can have many types, like date, name, surname, etc:
|
|
allowAttributes: ["field"],
|
|
});
|
|
}
|
|
|
|
_defineConverters() {
|
|
const conversion = this.editor.conversion;
|
|
|
|
conversion.for("upcast").elementToElement({
|
|
view: {
|
|
name: "span",
|
|
classes: ["field"],
|
|
},
|
|
model: (viewElement, conversionApi) => {
|
|
// Extract the "name" from "{name}".
|
|
if (viewElement === undefined) {
|
|
return null;
|
|
}
|
|
|
|
const { writer } = conversionApi;
|
|
|
|
const name = viewElement.getChild(0)?._textData;
|
|
|
|
const fieldtype = viewElement.getAttribute("fieldtype");
|
|
const guid = viewElement.getAttribute("guid");
|
|
const fieldid = viewElement.getAttribute("fieldid");
|
|
|
|
const field = {
|
|
name,
|
|
type: fieldtype,
|
|
guid,
|
|
fieldid,
|
|
};
|
|
|
|
return writer.createElement("field", { field });
|
|
},
|
|
});
|
|
|
|
conversion.for("editingDowncast").elementToElement({
|
|
model: "field",
|
|
view: (modelItem, { writer: viewWriter }) => {
|
|
const widgetElement = createfieldView(modelItem, viewWriter);
|
|
|
|
// Enable widget handling on a field element inside the editing view.
|
|
return toWidget(widgetElement, viewWriter);
|
|
},
|
|
});
|
|
|
|
conversion.for("dataDowncast").elementToElement({
|
|
model: "field",
|
|
view: (modelItem, { writer: viewWriter }) =>
|
|
createfieldView(modelItem, viewWriter),
|
|
});
|
|
|
|
// Helper method for both downcast converters.
|
|
// function createfieldView( modelItem : Element, viewWriter : DowncastWriter ) {
|
|
function createfieldView(modelItem, viewWriter) {
|
|
const field = modelItem.getAttribute("field"); //todo any is a cop out.
|
|
|
|
const fieldView = viewWriter.createContainerElement("span", {
|
|
class: "field",
|
|
fieldType: field.type,
|
|
guid: field.guid,
|
|
fieldid: field.guid !== undefined ? null : field.id,
|
|
});
|
|
|
|
// Insert the field name (as a text).
|
|
const innerText = viewWriter.createText(
|
|
"{" + rtrim(ltrim(field.name, "{"), "}") + "}",
|
|
);
|
|
viewWriter.insert(viewWriter.createPositionAt(fieldView, 0), innerText);
|
|
|
|
return fieldView;
|
|
}
|
|
}
|
|
}
|