summaryrefslogtreecommitdiff
path: root/addons/pad/static/src
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/pad/static/src
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/pad/static/src')
-rw-r--r--addons/pad/static/src/css/etherpad.css129
-rw-r--r--addons/pad/static/src/img/pad_link_companies.jpegbin0 -> 70544 bytes
-rw-r--r--addons/pad/static/src/js/pad.js193
-rw-r--r--addons/pad/static/src/xml/pad.xml21
4 files changed, 343 insertions, 0 deletions
diff --git a/addons/pad/static/src/css/etherpad.css b/addons/pad/static/src/css/etherpad.css
new file mode 100644
index 00000000..a0157bb3
--- /dev/null
+++ b/addons/pad/static/src/css/etherpad.css
@@ -0,0 +1,129 @@
+
+.oe_pad_switch_positioner {
+ position: relative;
+}
+
+.oe_pad_switch {
+ position: absolute;
+ top: 5px;
+ left: 383px;
+ width: 28px;
+ height: 28px;
+ background-image: -webkit-linear-gradient(top, white, #f0f0f0);
+ border: solid 1px #ccc;
+ border-radius:3px;
+ text-align: center;
+ line-height: 28px;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ color: #666666;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+@media (max-width: 767px) {
+ .oe_pad_switch {
+ left: auto;
+ right: 5px;
+ }
+ html .o_scroll_hidden {
+ overflow: hidden;
+ }
+}
+
+.oe_pad_switch:hover{
+ background-image: -webkit-linear-gradient(top, #f4f4f4, #e4e4e4);
+}
+
+.oe_pad_fullscreen .oe_pad_switch {
+ top:4px;
+}
+
+.oe_pad_fullscreen {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ right: 0px;
+ bottom: 0px;
+ background-color: white;
+ margin:0;
+ padding:0;
+ border:none;
+ z-index: 1001;
+}
+
+.oe_pad .oe_pad_content.oe_editing{
+ border: solid 1px #c4c4c4;
+ height:500px;
+ -webkit-box-shadow: 0 5px 10px rgba(0,0,0,0.1);
+ -moz-box-shadow: 0 5px 10px rgba(0,0,0,0.1);
+ -ms-box-shadow: 0 5px 10px rgba(0,0,0,0.1);
+ -o-box-shadow: 0 5px 10px rgba(0,0,0,0.1);
+ box-shadow: 0 5px 10px rgba(0,0,0,0.1);
+}
+
+.oe_pad.oe_pad_fullscreen .oe_pad_content {
+ height: 100%;
+ border: none;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ -ms-box-shadow: none;
+ -o-box-shadow: none;
+ box-shadow: none;
+}
+
+.oe_pad .oe_unconfigured {
+ text-align: center;
+ opacity: 0.75;
+}
+
+.oe_pad_loading{
+ text-align: center;
+ opacity: 0.75;
+ font-style: italic;
+}
+
+.etherpad_readonly ul, .etherpad_readonly ol {
+ margin: 0;
+ margin-left: 1.5em;
+ padding: 0;
+}
+.etherpad_readonly ul li{
+ list-style-type: disc;
+}
+.etherpad_readonly ol li{
+ list-style-type: decimal;
+}
+.etherpad_readonly .indent li{
+ list-style-type: none !important;
+}
+
+.etherpad_readonly{
+ font-family: arial, sans-serif;
+ font-size: 15px;
+ line-height: 19px;
+ word-wrap: break-word;
+}
+
+.openerp .oe_form_nomargin .etherpad_readonly{
+ padding: 10px;
+}
+
+.etherpad_readonly ul.indent { list-style-type: none !important; }
+.etherpad_readonly ol li{ list-style-type: decimal !important; }
+.etherpad_readonly ol ol li{ list-style-type: lower-latin !important; }
+.etherpad_readonly ol ol ol li{ list-style-type: lower-roman !important; }
+.etherpad_readonly ol ol ol ol li{ list-style-type: decimal !important; }
+.etherpad_readonly ol ol ol ol ol li{ list-style-type: lower-latin !important; }
+.etherpad_readonly ol ol ol ol ol ol li{ list-style-type: lower-roman !important; }
+.etherpad_readonly ol ol ol ol ol ol ol li{ list-style-type: decimal !important; }
+.etherpad_readonly ol ol ol ol ol ol ol ol li{ list-style-type: lower-latin !important; }
+.etherpad_readonly ul li { list-style-type: disc !important; }
+.etherpad_readonly ul ul li { list-style-type: circle !important; }
+.etherpad_readonly ul ul ul li { list-style-type: square !important; }
+.etherpad_readonly ul ul ul ul li { list-style-type: disc !important; }
+.etherpad_readonly ul ul ul ul ul li { list-style-type: circle !important; }
+.etherpad_readonly ul ul ul ul ul ul li { list-style-type: square !important; }
+.etherpad_readonly ul ul ul ul ul ul ul li { list-style-type: disc !important; }
+.etherpad_readonly ul ul ul ul ul ul ul ul li { list-style-type: circle !important; }
+.etherpad_readonly ul ul ul ul ul ul ul ul ul li { list-style-type: square !important; }
diff --git a/addons/pad/static/src/img/pad_link_companies.jpeg b/addons/pad/static/src/img/pad_link_companies.jpeg
new file mode 100644
index 00000000..1bce3a56
--- /dev/null
+++ b/addons/pad/static/src/img/pad_link_companies.jpeg
Binary files differ
diff --git a/addons/pad/static/src/js/pad.js b/addons/pad/static/src/js/pad.js
new file mode 100644
index 00000000..7107c2d6
--- /dev/null
+++ b/addons/pad/static/src/js/pad.js
@@ -0,0 +1,193 @@
+odoo.define('pad.pad', function (require) {
+"use strict";
+
+var AbstractField = require('web.AbstractField');
+var core = require('web.core');
+var fieldRegistry = require('web.field_registry');
+
+var _t = core._t;
+
+var FieldPad = AbstractField.extend({
+ template: 'FieldPad',
+ content: "",
+ events: {
+ 'click .oe_pad_switch': '_onToggleFullScreen',
+ },
+
+ /**
+ * @override
+ */
+ willStart: function () {
+ if (this.isPadConfigured === undefined) {
+ return this._rpc({
+ method: 'pad_is_configured',
+ model: this.model,
+ }).then(function (result) {
+ // we write on the prototype to share the information between
+ // all pad widgets instances, across all actions
+ FieldPad.prototype.isPadConfigured = result;
+ });
+ }
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ if (!this.isPadConfigured) {
+ this.$(".oe_unconfigured").removeClass('d-none');
+ this.$(".oe_configured").addClass('d-none');
+ return Promise.resolve();
+ }
+ if (this.mode === 'edit' && typeof(this.value) === 'object') {
+ this.value = this.value.toJSON();
+ }
+ if (this.mode === 'edit' && _.str.startsWith(this.value, 'http')) {
+ this.url = this.value;
+ // please close your eyes and look elsewhere...
+ // Since the pad value (the url) will not change during the edition
+ // process, we have a problem: the description field will not be
+ // properly updated. We need to explicitely write the value each
+ // time someone edit the record in order to force the server to read
+ // the updated value of the pad and put it in the description field.
+ //
+ // However, the basic model optimizes away the changes if they are
+ // not really different from the current value. So, we need to
+ // either add special configuration options to the basic model, or
+ // to trick him into accepting the same value as being different...
+ // Guess what we decided...
+ var url = {};
+ url.toJSON = _.constant(this.url);
+ this._setValue(url, {doNotSetDirty: true});
+ }
+
+ return this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * If we had to generate an url, we wait for the generation to be completed,
+ * so the current record will be associated with the correct pad url.
+ *
+ * @override
+ */
+ commitChanges: function () {
+ return this.urlDef;
+ },
+ /**
+ * @override
+ */
+ isSet: function () {
+ return true;
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Note that this method has some serious side effects: performing rpcs and
+ * setting the value of this field. This is not conventional and should not
+ * be copied in other code, unless really necessary.
+ *
+ * @override
+ * @private
+ */
+ _renderEdit: function () {
+ if (this.url) {
+ // here, we have a valid url, so we can simply display an iframe
+ // with the correct src attribute
+ var userName = encodeURIComponent(this.getSession().name);
+ var url = this.url + '?showChat=false&userName=' + userName;
+ var content = '<iframe width="100%" height="100%" frameborder="0" src="' + url + '"></iframe>';
+ this.$('.oe_pad_content').html(content);
+ } else if (this.value) {
+ // it looks like the field does not contain a valid url, so we just
+ // display it (it cannot be edited in that case)
+ this.$('.oe_pad_content').text(this.value);
+ } else {
+ // It is totally discouraged to have a render method that does
+ // non-rendering work, especially since the work in question
+ // involves doing RPCs and changing the value of the field.
+ // However, this is kind of necessary in this case, because the
+ // value of the field is actually only the url of the pad. The
+ // actual content will be loaded in an iframe. We could do this
+ // work in the basic model, but the basic model does not know that
+ // this widget is in edit or readonly, and we really do not want to
+ // create a pad url everytime a task without a pad is viewed.
+ var self = this;
+ this.urlDef = this._rpc({
+ method: 'pad_generate_url',
+ model: this.model,
+ context: {
+ model: this.model,
+ field_name: this.name,
+ object_id: this.res_id,
+ record: this.recordData,
+ },
+ }, {
+ shadow: true
+ }).then(function (result) {
+ // We need to write the url of the pad to trigger
+ // the write function which updates the actual value
+ // of the field to the value of the pad content
+ self.url = result.url;
+ self._setValue(result.url, {doNotSetDirty: true});
+ });
+ }
+ },
+ /**
+ * @override
+ * @private
+ */
+ _renderReadonly: function () {
+ if (_.str.startsWith(this.value, 'http')) {
+ var self = this;
+ this.$('.oe_pad_content')
+ .addClass('oe_pad_loading')
+ .text(_t("Loading"));
+ this._rpc({
+ method: 'pad_get_content',
+ model: this.model,
+ args: [this.value]
+ }, {
+ shadow: true
+ }).then(function (data) {
+ self.$('.oe_pad_content')
+ .removeClass('oe_pad_loading')
+ .html('<div class="oe_pad_readonly"><div>');
+ self.$('.oe_pad_readonly').html(data);
+ }).guardedCatch(function () {
+ self.$('.oe_pad_content').text(_t('Unable to load pad'));
+ });
+ } else {
+ this.$('.oe_pad_content')
+ .addClass('oe_pad_loading')
+ .show()
+ .text(_t("This pad will be initialized on first edit"));
+ }
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ * @private
+ */
+ _onToggleFullScreen: function () {
+ this.$el.toggleClass('oe_pad_fullscreen mb0');
+ this.$('.oe_pad_switch').toggleClass('fa-expand fa-compress');
+ this.$el.parents('.o_touch_device').toggleClass('o_scroll_hidden');
+ },
+});
+
+fieldRegistry.add('pad', FieldPad);
+
+return FieldPad;
+
+});
diff --git a/addons/pad/static/src/xml/pad.xml b/addons/pad/static/src/xml/pad.xml
new file mode 100644
index 00000000..44eb11c8
--- /dev/null
+++ b/addons/pad/static/src/xml/pad.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<templates id="template" xml:space="preserve">
+
+ <t t-name="FieldPad">
+ <div class="oe_form_field_text oe_pad">
+ <p class="oe_unconfigured d-none">
+ Please, enter your Etherpad credentials through the Settings.
+ </p>
+ <t t-if="widget.mode === 'readonly'">
+ <div class="oe_pad_content etherpad_readonly oe_configured" />
+ </t>
+ <t t-if="widget.mode === 'edit'">
+ <div class="oe_pad_switch_positioner oe_configured">
+ <span class="fa fa-expand oe_pad_switch" role="img" aria-label="Switch pad" title="Switch pad"/>
+ </div>
+ <div class="oe_pad_content oe_editing oe_configured" />
+ </t>
+ </div>
+ </t>
+
+</templates>