From 870a9a59efefb7ce6ff2f9dc2b952416247a9953 Mon Sep 17 00:00:00 2001
From: Rafi Zadanly
Date: Wed, 8 Mar 2023 11:04:08 +0700
Subject: add widget ckeditor
---
.../static/src/js/field_ckeditor.js | 330 +++++++++++++++++++++
.../static/src/js/field_html_override.js | 15 +
.../static/src/scss/web_widget_ckeditor.scss | 23 ++
3 files changed, 368 insertions(+)
create mode 100644 web_widget_ckeditor/static/src/js/field_ckeditor.js
create mode 100644 web_widget_ckeditor/static/src/js/field_html_override.js
create mode 100644 web_widget_ckeditor/static/src/scss/web_widget_ckeditor.scss
(limited to 'web_widget_ckeditor/static/src')
diff --git a/web_widget_ckeditor/static/src/js/field_ckeditor.js b/web_widget_ckeditor/static/src/js/field_ckeditor.js
new file mode 100644
index 00000000..0f212abe
--- /dev/null
+++ b/web_widget_ckeditor/static/src/js/field_ckeditor.js
@@ -0,0 +1,330 @@
+/*
+ Copyright 2021 Camptocamp SA (https://www.camptocamp.com).
+ @author Iván Todorovich
+ License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+*/
+odoo.define("web_widget_ckeditor.field_ckeditor", function (require) {
+ "use strict";
+
+ const core = require("web.core");
+ const session = require("web.session");
+ const config = require("web.config");
+ const ajax = require("web.ajax");
+ const rpc = require("web.rpc");
+ const basic_fields = require("web.basic_fields");
+ const field_registry = require("web.field_registry");
+ const _lt = core._lt;
+ const TranslatableFieldMixin = basic_fields.TranslatableFieldMixin;
+
+ // Load configuration for the editor
+ const getCKEditorConfigPromise = rpc.query({
+ model: "ir.config_parameter",
+ method: "get_web_widget_ckeditor_config",
+ });
+
+ // Load CKEditor localization files
+ async function loadCKEditorLanguageSource(languageCode) {
+ if (languageCode === "en") {
+ return;
+ }
+ const languageURL = `/web_widget_ckeditor/static/lib/ckeditor/build/translations/${languageCode}.js`;
+ try {
+ ajax.loadJS(languageURL);
+ } catch (error) {
+ console.warn("Unable to load CKEditor language: ", languageCode);
+ }
+ }
+ const CKEditorLanguageCode = session.user_context.lang.split("_")[0];
+ const loadCKEditorLanguagePromise = loadCKEditorLanguageSource(
+ CKEditorLanguageCode
+ );
+
+ const FieldHtmlCKEditor = basic_fields.DebouncedField.extend(
+ TranslatableFieldMixin,
+ {
+ description: _lt("Html (CKEditor)"),
+ className: "oe_form_field oe_form_field_html oe_form_field_html_ckeditor",
+ supportedFieldTypes: ["html"],
+
+ /**
+ * @override
+ */
+ willStart: function () {
+ return Promise.all([
+ this._super.apply(this, arguments),
+ loadCKEditorLanguagePromise,
+ ]);
+ },
+
+ /**
+ * @override
+ */
+ destroy: function () {
+ if (this.ckeditor) {
+ this.ckeditor.destroy();
+ this.ckeditor = undefined;
+ }
+ return this._super();
+ },
+
+ // --------------------------------------------------------------------------
+ // Public
+ // --------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ activate: function () {
+ if (this.ckeditor) {
+ this.ckeditor.focus();
+ return true;
+ }
+ },
+ /**
+ * This function is similar to the one found in core's web_editor.FieldHtml.
+ *
+ * @override
+ */
+ isSet: function () {
+ // Removing spaces & html spaces
+ const value =
+ this.value &&
+ this.value.split(" ").join("").replace(/\s/g, "");
+ return (
+ value &&
+ value !== "" &&
+ value !== "
" &&
+ value.match(/\S/)
+ );
+ },
+ /**
+ * This function is similar to the one found in core's web_editor.FieldHtml.
+ *
+ * @override
+ */
+ getFocusableElement: function () {
+ return this.$target || $();
+ },
+ /**
+ * Do not re-render this field if it was the origin of the onchange call.
+ * This function is similar to the one found in core's web_editor.FieldHtml.
+ *
+ * @override
+ */
+ reset: function (record, event) {
+ this._reset(record, event);
+ const value = this._textToHtml(this.value);
+ if (!event || event.target !== this) {
+ if (this.mode === "edit") {
+ this.ckeditor.setData(value);
+ } else {
+ this.$content.html(value);
+ }
+ }
+ return Promise.resolve();
+ },
+
+ // --------------------------------------------------------------------------
+ // Private
+ // --------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _getValue: function () {
+ if (this.mode === "edit" && this.ckeditor) {
+ return this.ckeditor.getData();
+ }
+ return this.$target.val();
+ },
+ /**
+ * Gets the CKEditor toolbar items configuration.
+ * If not found, returns the default configuration.
+ */
+ _getCKEditorToolbarItems: async function () {
+ try {
+ const ckconfig = await getCKEditorConfigPromise;
+ if (ckconfig.toolbar) {
+ return ckconfig.toolbar.split(/[\s,]+/).filter((item) => item);
+ }
+ } catch (error) {
+ console.warn(
+ "Unable to use CKEditor toolbar configuration: ",
+ error
+ );
+ console.warn(
+ "Please check the value for ir.config_parameter 'web_widget_ckeditor.toolbar' is correct"
+ );
+ console.warn("Using default toolbar configuration");
+ }
+ return [
+ "heading",
+ "|",
+ "bold",
+ "italic",
+ "underline",
+ "removeFormat",
+ "|",
+ "fontSize",
+ "fontColor",
+ "fontBackgroundColor",
+ "|",
+ "bulletedList",
+ "numberedList",
+ "alignment",
+ "|",
+ "outdent",
+ "indent",
+ "pagebreak",
+ "|",
+ "link",
+ "imageUpload",
+ "blockQuote",
+ "insertTable",
+ "|",
+ "undo",
+ "redo",
+ ];
+ },
+ /**
+ * Gets the CKEditor configuration.
+ * See for details:
+ * https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html
+ *
+ * @returns EditorConfig
+ */
+ _getCKEditorConfig: async function () {
+ const res = {
+ toolbar: {
+ items: await this._getCKEditorToolbarItems(),
+ shouldNotGroupWhenFull: true,
+ },
+ language: CKEditorLanguageCode,
+ image: {
+ toolbar: [
+ "imageTextAlternative",
+ "imageStyle:inline",
+ "imageStyle:block",
+ "imageStyle:side",
+ "linkImage",
+ ],
+ },
+ table: {
+ contentToolbar: [
+ "tableColumn",
+ "tableRow",
+ "mergeTableCells",
+ "tableCellProperties",
+ "tableProperties",
+ ],
+ },
+ };
+ if (config.isDebug()) {
+ res.toolbar.items.push("sourceEditing");
+ }
+ return res;
+ },
+ /**
+ * Create the CKEditor instance with the target (this.$target)
+ * then add the editable content (this.$content).
+ *
+ * @private
+ * @returns {$.Promise}
+ */
+ _createCKEditorIntance: async function () {
+ const editorConfig = await this._getCKEditorConfig();
+ this.ckeditor = await window.ClassicEditor.create(
+ this.$target.get(0),
+ editorConfig
+ );
+ // Register event hooks
+ this.ckeditor.on("change", () => this._onChange());
+ this.ckeditor.ui.focusTracker.on(
+ "change:isFocused",
+ (ev, name, isFocused) => (isFocused ? null : this._onChange())
+ );
+ this._onLoadCKEditor();
+ },
+ /**
+ * @override
+ */
+ _renderEdit: function () {
+ const value = this._textToHtml(this.value);
+ this.$target = $("
");
+ }
+ }
+ return value;
+ },
+
+ // --------------------------------------------------------------------------
+ // Handler
+ // --------------------------------------------------------------------------
+
+ /**
+ * Method called when the CKEditor instance is loaded.
+ *
+ * @private
+ */
+ _onLoadCKEditor: function () {
+ const $button = this._renderTranslateButton();
+ $button.css({
+ "font-size": "15px",
+ position: "absolute",
+ right: "+5px",
+ top: "+5px",
+ });
+ this.$el.append($button);
+ },
+ /**
+ * Method called when ckeditor triggers a change.
+ *
+ * @private
+ * @param {OdooEvent} ev
+ */
+ _onChange: function () {
+ this._doDebouncedAction.apply(this, arguments);
+ },
+ }
+ );
+
+ field_registry.add("ckeditor", FieldHtmlCKEditor);
+
+ return FieldHtmlCKEditor;
+});
diff --git a/web_widget_ckeditor/static/src/js/field_html_override.js b/web_widget_ckeditor/static/src/js/field_html_override.js
new file mode 100644
index 00000000..aa9d42bc
--- /dev/null
+++ b/web_widget_ckeditor/static/src/js/field_html_override.js
@@ -0,0 +1,15 @@
+/*
+ Copyright 2021 Camptocamp SA (https://www.camptocamp.com).
+ @author Iván Todorovich
+ License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+*/
+odoo.define("web_widget_ckeditor.field_html_override", function (require) {
+ "use strict";
+
+ const FieldHtml = require("web_editor.field.html");
+ const FieldHtmlCKEditor = require("web_widget_ckeditor.field_ckeditor");
+ const field_registry = require("web.field_registry");
+
+ field_registry.add("html_odoo", FieldHtml);
+ field_registry.add("html", FieldHtmlCKEditor);
+});
diff --git a/web_widget_ckeditor/static/src/scss/web_widget_ckeditor.scss b/web_widget_ckeditor/static/src/scss/web_widget_ckeditor.scss
new file mode 100644
index 00000000..6e2c13f1
--- /dev/null
+++ b/web_widget_ckeditor/static/src/scss/web_widget_ckeditor.scss
@@ -0,0 +1,23 @@
+/*
+ Copyright 2021 Camptocamp SA (https://www.camptocamp.com).
+ @author Iván Todorovich
+ License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+*/
+
+.o_field_widget {
+ &.oe_form_field_html_ckeditor {
+ .ck-editor__editable {
+ min-height: 330px;
+ }
+
+ .ck-toolbar {
+ .ck-button {
+ font-size: 0.9rem;
+
+ .ck-icon {
+ will-change: auto;
+ }
+ }
+ }
+ }
+}
--
cgit v1.2.3