diff --git a/.gitignore b/.gitignore index 818770fb1bdc..26c6ce0f7fa9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,6 @@ build/ develop-eggs/ dist/ eggs/ -lib/ lib64/ parts/ sdist/ @@ -72,4 +71,3 @@ docs/_build/ *.swp # OCA rules -!static/lib/ diff --git a/web_widget_html_markdown/README.rst b/web_widget_html_markdown/README.rst new file mode 100644 index 000000000000..c4bf2a0ac585 --- /dev/null +++ b/web_widget_html_markdown/README.rst @@ -0,0 +1,118 @@ +======================== +Web Widget Html Markdown +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github + :target: https://github.com/OCA/web/tree/14.0/web_widget_html_markdown + :alt: OCA/web +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/web-14-0/web-14-0-web_widget_html_markdown + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/162/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Behaviour of the module and best practices +========================================== + +- In readonly mode, the widget renders as Html +- In editable mode, there is a switcher to choose if the source should be HTML or Markdown. If HTML, it shows the HTML edit widget. If Markdown, it shows a markdown widget. When done editing, it will save in the field as Html, no matter which widget is chosen. +- In markdown mode, the markdown is saved embedded within the HTML so that it can be shown again on subsequent edits of the field and there is no loss from backconversion of Html to Markdown. +- When switching the widget from Markdown to HTML, the Markdown source is lost. +- When switching the widget from HTML back to Markdown, the Showdown.JS backconversion is used to generate a reasonable representation of the HTML in markdown. This is where some information loss can occur, so the user should not needlessly switch from HTML to Markdown and back - in general, choose one way to edit your field content, and stick to it. +- In edit mode, the widget provides some feedback about potential loss of information when switching from HTML to markdown or when editing in HTML text that was edited in markdown. + + +Utility of this module vs web_widget_text_markdown +================================================== + +Why this module when web_widget_text_markdown already exists? Mainly because it is designed to work on Text fields, and most fields within Odoo are HTML fields for example: mail content, project.task description etc. Although you could develop a custom module that overrides these fields to be Text fields and render them on-screen as HTML, this rendering would not be done when the field is for example used in sending out a mail or fetching the field content through Odoo API. In these cases this widget comes in handy because it is plug-and-play: the field type and content remains as HTML, but you can choose to edit it with a markdown widget. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Your XML form view definition should contain: + + ... + + ... + + +This will replace the default Html widget by the new Markdown/HTML widget and +allow the field to be edited as Markdown or HTML, depending on the user's choice. + + +Known issues / Roadmap +====================== + +* Images Will be lost when passing from Html to markdown +* Other information may be lost when switching from Html to markdown + + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Giovanni Francesco Capalbo +* Therp B.V.Komit +* Sudokeys +* Sunflower IT + +Contributors +~~~~~~~~~~~~ + +* Tom Blauwendraat +* Kevin Kamau +* Giovanni Francesco Capalbo + +Other credits +~~~~~~~~~~~~~ + +* Therp B.V. https://therp.nl + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/web `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/web_widget_html_markdown/__init__.py b/web_widget_html_markdown/__init__.py new file mode 100644 index 000000000000..ef5ae3587f59 --- /dev/null +++ b/web_widget_html_markdown/__init__.py @@ -0,0 +1 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). diff --git a/web_widget_html_markdown/__manifest__.py b/web_widget_html_markdown/__manifest__.py new file mode 100644 index 000000000000..a77a066406a4 --- /dev/null +++ b/web_widget_html_markdown/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright (C) 2014 Sudokeys () +# Copyright (C) 2017 Komit () +# +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Web Widget Html Markdown", + "version": "14.0.1.0.0", + "author": "Giovanni Francesco Capalbo, Therp B.V." + "Komit, " + "Sudokeys, " + "Sunflower IT, " + "Odoo Community Association (OCA)", + "category": "Web", + "license": "AGPL-3", + "website": "https://github.com/OCA/web", + "summary": "Widget for Html fields that adds markdown Html bidirectional editor", + "depends": [ + "web", "web_editor", + ], + "demo": ["demo/bootstrap_markdown.xml"], + "data": ["views/assets.xml"], + "qweb": ["static/src/xml/bootstrap_markdown.xml"], + "installable": True, + "auto_install": False, + "application": False, +} diff --git a/web_widget_html_markdown/demo/bootstrap_markdown.xml b/web_widget_html_markdown/demo/bootstrap_markdown.xml new file mode 100644 index 000000000000..277a0c429cbc --- /dev/null +++ b/web_widget_html_markdown/demo/bootstrap_markdown.xml @@ -0,0 +1,12 @@ + + + + res.groups + + + + html_markdown + + + + diff --git a/web_widget_html_markdown/readme/CONTRIBUTORS.rst b/web_widget_html_markdown/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..e74d0af8ea9a --- /dev/null +++ b/web_widget_html_markdown/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Tom Blauwendraat +* Kevin Kamau +* Giovanni Francesco Capalbo diff --git a/web_widget_html_markdown/readme/CREDITS.rst b/web_widget_html_markdown/readme/CREDITS.rst new file mode 100644 index 000000000000..9772a1ca1637 --- /dev/null +++ b/web_widget_html_markdown/readme/CREDITS.rst @@ -0,0 +1 @@ +* Therp B.V. https://therp.nl diff --git a/web_widget_html_markdown/readme/DESCRIPTION.rst b/web_widget_html_markdown/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..645f5ae366ef --- /dev/null +++ b/web_widget_html_markdown/readme/DESCRIPTION.rst @@ -0,0 +1,15 @@ +Behaviour of the module and best practices +========================================== + +- In readonly mode, the widget renders as Html +- In editable mode, there is a switcher to choose if the source should be HTML or Markdown. If HTML, it shows the HTML edit widget. If Markdown, it shows a markdown widget. When done editing, it will save in the field as Html, no matter which widget is chosen. +- In markdown mode, the markdown is saved embedded within the HTML so that it can be shown again on subsequent edits of the field and there is no loss from backconversion of Html to Markdown. +- When switching the widget from Markdown to HTML, the Markdown source is lost. +- When switching the widget from HTML back to Markdown, the Showdown.JS backconversion is used to generate a reasonable representation of the HTML in markdown. This is where some information loss can occur, so the user should not needlessly switch from HTML to Markdown and back - in general, choose one way to edit your field content, and stick to it. +- In edit mode, the widget provides some feedback about potential loss of information when switching from HTML to markdown or when editing in HTML text that was edited in markdown. + + +Utility of this module vs web_widget_text_markdown +================================================== + +Why this module when web_widget_text_markdown already exists? Mainly because it is designed to work on Text fields, and most fields within Odoo are HTML fields for example: mail content, project.task description etc. Although you could develop a custom module that overrides these fields to be Text fields and render them on-screen as HTML, this rendering would not be done when the field is for example used in sending out a mail or fetching the field content through Odoo API. In these cases this widget comes in handy because it is plug-and-play: the field type and content remains as HTML, but you can choose to edit it with a markdown widget. diff --git a/web_widget_html_markdown/readme/ROADMAP.rst b/web_widget_html_markdown/readme/ROADMAP.rst new file mode 100644 index 000000000000..ddf8f749ed30 --- /dev/null +++ b/web_widget_html_markdown/readme/ROADMAP.rst @@ -0,0 +1,3 @@ +* Images Will be lost when passing from Html to markdown +* Other information may be lost when switching from Html to markdown + diff --git a/web_widget_html_markdown/readme/USAGE.rst b/web_widget_html_markdown/readme/USAGE.rst new file mode 100644 index 000000000000..84027d32d2ab --- /dev/null +++ b/web_widget_html_markdown/readme/USAGE.rst @@ -0,0 +1,10 @@ +Your XML form view definition should contain: + + ... + + ... + + +This will replace the default Html widget by the new Markdown/HTML widget and +allow the field to be edited as Markdown or HTML, depending on the user's choice. + diff --git a/web_widget_html_markdown/static/description/icon.png b/web_widget_html_markdown/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/web_widget_html_markdown/static/description/icon.png differ diff --git a/web_widget_html_markdown/static/description/index.html b/web_widget_html_markdown/static/description/index.html new file mode 100644 index 000000000000..97f25027ee10 --- /dev/null +++ b/web_widget_html_markdown/static/description/index.html @@ -0,0 +1,450 @@ + + + + + + +Web Widget Html Markdown + + + +
+

Web Widget Html Markdown

+ + +

Beta License: AGPL-3 OCA/web Translate me on Weblate Try me on Runbot

+
+

Behaviour of the module and best practices

+
    +
  • In readonly mode, the widget renders as Html
  • +
  • In editable mode, there is a switcher to choose if the source should be HTML or Markdown. If HTML, it shows the HTML edit widget. If Markdown, it shows a markdown widget. When done editing, it will save in the field as Html, no matter which widget is chosen.
  • +
  • In markdown mode, the markdown is saved embedded within the HTML so that it can be shown again on subsequent edits of the field and there is no loss from backconversion of Html to Markdown.
  • +
  • When switching the widget from Markdown to HTML, the Markdown source is lost.
  • +
  • When switching the widget from HTML back to Markdown, the Showdown.JS backconversion is used to generate a reasonable representation of the HTML in markdown. This is where some information loss can occur, so the user should not needlessly switch from HTML to Markdown and back - in general, choose one way to edit your field content, and stick to it.
  • +
  • In edit mode, the widget provides some feedback about potential loss of information when switching from HTML to markdown or when editing in HTML text that was edited in markdown.
  • +
+
+
+

Utility of this module vs web_widget_text_markdown

+

Why this module when web_widget_text_markdown already exists? Mainly because it is designed to work on Text fields, and most fields within Odoo are HTML fields for example: mail content, project.task description etc. Although you could develop a custom module that overrides these fields to be Text fields and render them on-screen as HTML, this rendering would not be done when the field is for example used in sending out a mail or fetching the field content through Odoo API. In these cases this widget comes in handy because it is plug-and-play: the field type and content remains as HTML, but you can choose to edit it with a markdown widget.

+

Table of contents

+
+
+

Usage

+

Your XML form view definition should contain:

+
+… +<field name=”field_name” widget=”html_markdown”/> +…
+

This will replace the default Html widget by the new Markdown/HTML widget and +allow the field to be edited as Markdown or HTML, depending on the user’s choice.

+
+
+

Known issues / Roadmap

+
    +
  • Images Will be lost when passing from Html to markdown
  • +
  • Other information may be lost when switching from Html to markdown
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Giovanni Francesco Capalbo
  • +
  • Therp B.V.Komit
  • +
  • Sudokeys
  • +
  • Sunflower IT
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/web project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/web_widget_html_markdown/static/src/css/web_widget_html_markdown.css b/web_widget_html_markdown/static/src/css/web_widget_html_markdown.css new file mode 100644 index 000000000000..de6bf2f71ed3 --- /dev/null +++ b/web_widget_html_markdown/static/src/css/web_widget_html_markdown.css @@ -0,0 +1,9 @@ +.md_preserved { + background-color: #90EE90; + color: Black; +} +.md_not_preserved { + background-color: #FFB6C1; + color: Black; +} + diff --git a/web_widget_html_markdown/static/src/js/web_widget_html_markdown.js b/web_widget_html_markdown/static/src/js/web_widget_html_markdown.js new file mode 100644 index 000000000000..d920e9618a53 --- /dev/null +++ b/web_widget_html_markdown/static/src/js/web_widget_html_markdown.js @@ -0,0 +1,861 @@ +/* global showdown */ +/* Copyright 2021 Therp B.V. - + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ +odoo.define("web_widget_html_markdown.FieldHtmlMarkDown", function(require) { + "use strict"; + + var ajax = require('web.ajax'); + var basic_fields = require('web.basic_fields'); + var config = require('web.config'); + var core = require('web.core'); + var Wysiwyg = require('web_editor.wysiwyg.root'); + var field_registry = require('web.field_registry'); + require('web._field_registry'); + var Dialog = require('web.Dialog'); + var QWeb = core.qweb; + var assetsLoaded; + + var jinjaRegex = /(^|\n)\s*%\s(end|set\s)/; + + var _t = core._t; + var _lt = core._lt; + var TranslatableFieldMixin = basic_fields.TranslatableFieldMixin; + var LIBS_PATH = "/web_widget_html_markdown/static/src/lib/"; + + /* + Events : _.extend({}, DebouncedField.prototype.events, { + 'change .mk_html_switch' : '_switch_markdown_html', + }), + */ + var FieldHtmlMarkDown = basic_fields.DebouncedField.extend(TranslatableFieldMixin, { + description: _lt("HtmlMarkdown"), + classname: 'oe_form_field oe_form_field_html_markdown', + supportedFieldTypes: ['html'], + + custom_events: { + wysiwyg_focus: '_onWysiwygFocus', + wysiwyg_blur: '_onWysiwygBlur', + wysiwyg_change: '_onChange', + wysiwyg_attachment: '_onAttachmentChange', + }, + + /** + * @override + */ + willStart: function () { + var self = this; + this.isSwitch = false; + this.isRendered = false; + this._onUpdateIframeId = 'onLoad_' + _.uniqueId('FieldHtmlMarkdown'); + var defAsset; + if (this.nodeOptions.cssReadonly) { + defAsset = ajax.loadAsset(this.nodeOptions.cssReadonly); + } + + if (!assetsLoaded) { // Avoid flickering when begin to edit + assetsLoaded = new Promise(function (resolve) { + var wysiwyg = new Wysiwyg(self, {}); + wysiwyg.attachTo($('" + $(this.$el[0]).append(markdownEditor); + this.markdownEditor = $(this.$el[0]).find('#comment-md'); + var $md = this.markdownEditor.markdown( + this._getMarkdownOptions() + ); + + }, + /** + * Get wysiwyg options to create wysiwyg instance. + * + * @private + * @returns {Object} + */ + _getWysiwygOptions: function () { + var self = this; + return Object.assign({}, this.nodeOptions, { + recordInfo: { + context: this.record.getContext(this.recordParams), + res_model: this.model, + res_id: this.res_id, + }, + noAttachment: this.nodeOptions['no-attachment'], + inIframe: Boolean(this.nodeOptions.cssEdit), + iframeCssAssets: this.nodeOptions.cssEdit, + snippets: this.nodeOptions.snippets, + + tabsize: 0, + height: 180, + generateOptions: function (options) { + var toolbar = options.toolbar || options.airPopover || {}; + var para = _.find(toolbar, function (item) { + return item[0] === 'para'; + }); + if (para && para[1] && para[1].indexOf('checklist') === -1) { + para[1].splice(2, 0, 'checklist'); + } + if (config.isDebug()) { + options.codeview = true; + var view = _.find(toolbar, function (item) { + return item[0] === 'view'; + }); + if (view) { + if (!view[1].includes('codeview')) { + view[1].splice(-1, 0, 'codeview'); + } + } else { + toolbar.splice(-1, 0, ['view', ['codeview']]); + } + } + if (self.model === "mail.compose.message" || self.model === "mailing.mailing") { + options.noVideos = true; + } + options.prettifyHtml = false; + return options; + }, + }); + }, + /** + * Trigger_up 'field_changed' add record into the "ir.attachment" field found in the view. + * This method is called when an image is uploaded via the media dialog. + * + * For e.g. when sending email, this allows people to add attachments with the content + * editor interface and that they appear in the attachment list. + * The new documents being attached to the email, they will not be erased by the CRON + * when closing the wizard. + * + * @private + * @param {Object} attachments + */ + _onAttachmentChange: function (attachments) { + if (!this.fieldNameAttachment) { + return; + } + this.trigger_up('field_changed', { + dataPointID: this.dataPointID, + changes: _.object([this.fieldNameAttachment], [{ + operation: 'ADD_M2M', + ids: attachments.data, + }]) + }); + }, + /** + * @override + */ + _renderEdit: function () { + var value = this._textToHtml(this.value); + if (this.nodeOptions.wrapper) { + value = this._wrap(value); + } + this.$target = $('