META-INF.frontend.uibuilder-rich-text-editor.src.uibuilder-rich-text-editor.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of uibuilder-rich-text-editor Show documentation
Show all versions of uibuilder-rich-text-editor Show documentation
A rich text component for the UIBuilder Framework
The newest version!
/*
*
* Copyright © 2018 Webvalto Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { html, PolymerElement } from '@polymer/polymer/polymer-element.js';
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
import Quill from 'quill';
export class UibuilderRichTextEditor extends ElementMixin(ThemableMixin(PolymerElement)) {
static get template() {
return html`
[[errorMessage]]
`;
}
static get is() {
return "uibuilder-rich-text-editor"
}
static get properties() {
return {
value: {
type: String,
value: "",
notify: true,
observer: "_onValueChange"
},
readonly: {
type: Boolean,
value: false,
notify: true,
observer: "_onReadonlyChange"
},
label: {
type: String,
value: null,
notify: true
},
invalid: {
type: Boolean,
value: false,
notify: true
},
errorMessage: {
type: String,
value: null,
notify: true
},
formatter: {
type: String,
value: "HTML",
notify: true
},
/**
* possible html render modes: "backend", "frontend"
*/
htmlRenderMode: {
type: String,
value: "frontend",
notify: true
},
/**
* possible value modes: "html", "plain", "delta", "formatted"
*/
valueMode: {
type: String,
value: "html",
notify: true
}
};
}
constructor() {
super();
this.editorContainer = document.createElement('div');
}
connectedCallback() {
super.connectedCallback();
this.prepend(this.editorContainer);
this.initEditor(this.editorContainer);
}
initEditor(element) {
const configNodes = this._collectConfigurationNodes();
let quillConfig = {}
configNodes.forEach(configNode => configNode.preConfig(quillConfig));
if (!quillConfig.theme) {
Object.assign(quillConfig, {
theme: "snow"
});
}
this.quillEditor = new Quill(element, quillConfig);
configNodes.forEach(configNode => configNode.postConfig(this.quillEditor));
this.quillEditor.on("text-change", (change, oldDelta, source) => {
if (source === "user") {
this._onQuillChange(change);
}
});
this._onReadonlyChange();
}
_collectConfigurationNodes() {
let configNodes = [];
this.shadowRoot.querySelectorAll("slot")
.forEach(slotNode => {
slotNode.assignedNodes()
.filter(node => node instanceof UibuilderRichTextEditorConfig)
.forEach(configNode => {
configNodes.push(configNode);
});
});
return configNodes;
}
_onReadonlyChange() {
if (this.quillEditor) {
this.quillEditor.readonly = this.readonly;
}
}
_isValueChangeBackendDriven() {
if (this.hasAttribute("item-bind")) {
const itemBind = this.getAttribute("item-bind");
return itemBind.startsWith("selected:") || itemBind.startsWith("backend:");
}
return false;
}
_onQuillChange(delta) {
const html = this.htmlRenderMode === 'frontend' ? this.quillEditor.root.innerHTML : null;
const reset = this.valueReset ? this.valueReset : false;
this.valueReset = false;
this._apiValueChange(() => {
if (this._isValueChangeBackendDriven()) {
this.dispatchEvent(new CustomEvent("changed"));
} else {
if (this.valueMode === 'plain') {
this.value = this.quillEditor.getText();
} else if (this.valueMode === 'html') {
this.value = this.quillEditor.root.innerHTML;
} else if (this.valueMode === 'delta') {
this.value = JSON.stringify(this.quillEditor.getContents().ops);
}
}
});
this.dispatchEvent(new CustomEvent("delta", {
detail: {
ops: delta,
html: html,
reset: reset
}
}));
}
_apiValueChange(skipValueChange) {
this._apiValueChangeActive = true;
skipValueChange();
this._apiValueChangeActive = false;
}
_onValueChange(value, oldValue) {
if (!this._apiValueChangeActive && this.quillEditor) {
if (this.valueMode === 'plain') {
this.setValueAsPlainText(this.value);
} else if (this.valueMode === 'html') {
this.setValueAsHtmlText(this.value);
} else if (this.valueMode === 'delta') {
this.setValueAsOps(JSON.parse(this.value));
}
}
}
_silentClear() {
this.valueReset = true;
this.quillEditor.setText("", "silent");
}
setValueAsHtmlText(htmlText) {
this._silentClear();
this.quillEditor.root.innerHTML = htmlText;
}
setValueAsPlainText(plainText) {
this._silentClear();
this.quillEditor.setText(plainText, "user");
}
setValueAsOps(ops) {
this._silentClear();
this.quillEditor.setContents(ops, "user");
}
}
export class UibuilderRichTextEditorConfig extends ElementMixin(PolymerElement) {
preConfig(config) {
}
postConfig(quill) {
}
}
customElements.define(UibuilderRichTextEditor.is, UibuilderRichTextEditor);