diff options
| author | Christophe Matthieu <chm@odoo.com> | 2016-03-23 16:37:56 +0100 |
|---|---|---|
| committer | Christophe Matthieu <chm@odoo.com> | 2016-08-23 17:03:56 +0200 |
| commit | 6d04c70abea6bbbe198c474a00b8a9c91a8ab69a (patch) | |
| tree | 797cb5f7142cba36d09f817c1e6ee770c7c3e96a /addons/web/static/src | |
| parent | a765b3e643f4ad98f319b983dda313e0ebdf931f (diff) | |
[IMP] web: add ace editor for xml and python edition
* display all lines and don't display the scroll bar into ace editor
* lazy read ace lib and add missing lib file
* use not minified version of ace lib
* Move ace lib from website to web
* Added ace widget for webclient
* XML mode for view text box
* Python mode for server action text box
* Removed web_ace_editor.xml, instead added template in base.xml itself
* Added widget=ace_editor in compute field of ir.model.fields
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/js/views/form_widgets.js | 101 | ||||
| -rw-r--r-- | addons/web/static/src/less/form_view_layout.less | 9 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 13 |
3 files changed, 121 insertions, 2 deletions
diff --git a/addons/web/static/src/js/views/form_widgets.js b/addons/web/static/src/js/views/form_widgets.js index a72702a2d08..334f0db758c 100644 --- a/addons/web/static/src/js/views/form_widgets.js +++ b/addons/web/static/src/js/views/form_widgets.js @@ -1,6 +1,7 @@ odoo.define('web.form_widgets', function (require) { "use strict"; +var ajax = require('web.ajax'); var core = require('web.core'); var crash_manager = require('web.crash_manager'); var data = require('web.data'); @@ -1579,6 +1580,102 @@ var FieldToggleBoolean = common.AbstractField.extend({ }, }); +/** + This widget is intended to be used on Text fields. It will provide Ace Editor for editing XML and Python. +*/ + +var AceEditor = common.AbstractField.extend(common.ReinitializeFieldMixin, { + template: "AceEditor", + willStart: function() { + if (!window.ace && !this.loadJS_def) { + this.loadJS_def = ajax.loadJS('/web/static/lib/ace/ace.js').then(function () { + return $.when(ajax.loadJS('/web/static/lib/ace/mode-python.js'), + ajax.loadJS('/web/static/lib/ace/mode-xml.js'), + ajax.loadJS('/web/static/lib/ace/theme-monokai.js')); + }); + } + return $.when(this._super(), this.loadJS_def); + }, + initialize_content: function () { + if (! this.get("effective_readonly")) { + var self = this; + + this.aceEditor = ace.edit(this.$('.ace-view-editor')[0]); + this.aceEditor.setOptions({"maxLines": Infinity}); + this.aceEditor.setTheme("ace/theme/monokai"); + this.aceEditor.$blockScrolling = true; + + var scrollIntoViewIfNeeded = _.throttle(function () { + var node = self.aceEditor.renderer.textarea; + if (node.scrollIntoViewIfNeeded) { + node.scrollIntoViewIfNeeded(false); + } else { + var offsetParent = node.offsetParent; + while (offsetParent) { + var elY = 0; + var elH = node.offsetHeight+20; + var parent = node; + while (offsetParent && parent) { + elY += node.offsetTop; + // get if a parent have a scrollbar + parent = node.parentNode; + while (parent != offsetParent && + (parent.tagName === "BODY" || ["auto", "scroll"].indexOf(window.getComputedStyle(parent).overflowY) === -1)) { + parent = parent.parentNode; + } + node = parent; + if (parent !== offsetParent) { + elY -= parent.offsetTop; + parent = null; + } + offsetParent = node.offsetParent; + } + + if ((node.tagName === "BODY" || ["auto", "scroll"].indexOf(window.getComputedStyle(node).overflowY) !== -1) && + (node.scrollTop + node.clientHeight) < (elY + elH)) { + node.scrollTop = (elY + elH) - node.clientHeight; + } + } + } + }); + var $moveTextAreaToCursor = this.aceEditor.renderer.$moveTextAreaToCursor; + self.aceEditor.renderer.$moveTextAreaToCursor = function() { + $moveTextAreaToCursor.call(this); + if (parseInt($(self.aceEditor.renderer.textarea).css('top'), 10) >= 0) { + scrollIntoViewIfNeeded(); + } + }; + + this.aceSession = this.aceEditor.getSession(); + this.aceSession.setUseWorker(false); + this.aceSession.setMode("ace/mode/"+(this.options.mode || 'xml')); + + this.aceEditor.on("blur", function() { + if (self.aceSession.getUndoManager().hasUndo()) { + self.set_value(self.aceSession.getValue()); + } + }); + } + }, + destroy_content: function() { + if (this.aceEditor) { + this.aceEditor.destroy(); + } + }, + render_value: function() { + if (! this.get("effective_readonly")) { + var value = formats.format_value(this.get('value'), this); + this.aceSession.setValue(value); + + } else { + var txt = this.get("value") || ''; + this.$(".oe_form_text_content").text(txt); + } + }, + focus: function() { + return this.aceEditor.focus(); + }, +}); /** * Registry of form fields, called by :js:`instance.web.FormView`. @@ -1614,8 +1711,8 @@ core.form_widget_registry .add('kanban_state_selection', KanbanSelection) .add('statinfo', StatInfo) .add('timezone_mismatch', TimezoneMismatch) - .add('label_selection', LabelSelection); - + .add('label_selection', LabelSelection) + .add('ace', AceEditor); /** * Registry of widgets usable in the form view that can substitute to any possible diff --git a/addons/web/static/src/less/form_view_layout.less b/addons/web/static/src/less/form_view_layout.less index d94c3c3129d..281cf0d217e 100644 --- a/addons/web/static/src/less/form_view_layout.less +++ b/addons/web/static/src/less/form_view_layout.less @@ -267,6 +267,15 @@ .o_group.o_inner_group.oe_subtotal_footer { .oe_right; } + + //ace + .o_ace_view_editor { + width: 100%; + .ace-view-editor { + height: 300px; + padding: 0 1em; + } + } } // Overriden style when form view in modal diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index a9f51b12c48..56b69d91225 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1250,6 +1250,19 @@ </div> </t> +<t t-name="AceEditor"> + <t t-if="!widget.get('effective_readonly')"> + <div class="oe_form_field o_ace_view_editor oe_ace_open"> + <div class="ace-view-editor"/> + </div> + </t> + <t t-if="widget.get('effective_readonly')"> + <div class="oe_form_field oe_form_field_text" t-att-style="widget.node.attrs.style"> + <span class="oe_form_text_content"></span> + </div> + </t> +</t> + <t t-name="notification-box"> <div t-att-class="'alert alert-dismissible alert-' + type" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
