[IMP] web: add mode qweb in ace

Add a new parser in the ace for the qweb highlight. This makes it possible
to visualize the qweb tags and the part of code.
Used in the website and in xml fields.

closes odoo/odoo#69609

Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
Gorash
2021-04-21 12:15:01 +00:00
parent 7519a500cf
commit aa47eda087
7 changed files with 169 additions and 4 deletions
+1
View File
@@ -95,6 +95,7 @@ This module provides the core of the Odoo Web Client.
'web/static/src/scss/tooltip.scss',
'web/static/src/scss/switch_company_menu.scss',
'web/static/src/scss/debug_manager.scss',
'web/static/src/scss/ace.scss',
'web/static/src/scss/control_panel.scss',
'web/static/src/scss/fields.scss',
'web/static/src/scss/file_upload.scss',
+143
View File
@@ -0,0 +1,143 @@
define("ace/mode/qweb_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/xml_highlight_rules"], function (require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var XmlHighlightRules = require("./xml_highlight_rules").XmlHighlightRules;
var QWebHighlightRules = function () {
XmlHighlightRules.call(this);
const xmlRules = this.$rules;
const tagRegex = xmlRules.attributes[0].regex;
this.$rules = Object.assign({},
xmlRules,
{
attributes: [{
include: "attributes_odoo",
}, {
include: "attributes_qweb",
}, {
include: "attributes_groups",
}, {
include: "attributes_sample",
}],
attributes_odoo: [{
token: ["entity.other.attribute-name.xml.odoo", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml.code", "string.attribute-value.xml.end"],
regex: '(domain|attrs|options)(=)(\\s*)(")([^"]*)(")',
}, {
token: ["entity.other.attribute-name.xml.odoo", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml.code", "string.attribute-value.xml.end"],
regex: "(domain|attrs|options)(=)(\\s*)(')([^']*)(')",
}],
attributes_qweb: [{
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: '(t-name|t-call-assets|t-js|t-css)(=)(\\s*)(")([^"]*)(")',
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: "(t-name|t-call-assets|t-js|t-css)(=)(\\s*)(')([^']*)(')",
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml", "string.attribute-value.xml.code", "string.attribute-value.xml", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: '(t-call|t-attf-(?:' + tagRegex + '))(=)(\\s*)(")([^"#{]*)(?:([#{]\\{)([^"}]+)(\\}[}]?))?([^"]*)(")',
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml", "string.attribute-value.xml.code", "string.attribute-value.xml", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: "(t-call|t-attf-(?:" + tagRegex + "))(=)(\\s*)(')([^'#{]*)(?:([#{]\\{)([^'}]+)(\\}[}]?))?([^']*)(')",
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml.code", "string.attribute-value.xml.end"],
regex: '(t-(?:' + tagRegex + '))(=)(\\s*)(")([^"]*)(")',
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml.code", "string.attribute-value.xml.end"],
regex: "(t-(?:" + tagRegex + "))(=)(\\s*)(')([^']*)(')",
}],
attributes_groups: [{
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: '(groups)(=)(\\s*)(")([\\s\\na-zA-Z0-9,_-]*)(")',
}, {
token: ["entity.other.attribute-name.xml.qweb", "keyword.operator.attribute-equals.xml", "text", "string.attribute-value.xml.start", "string.attribute-value.xml", "string.attribute-value.xml.end"],
regex: "(groups)(=)(\\s*)(')((?:[\\s\\na-zA-Z0-9,_-]*)*)(')",
}],
attributes_sample: [{
token: "entity.other.attribute-name.xml",
regex: tagRegex,
}, {
token: "keyword.operator.attribute-equals.xml",
regex: "=",
}, {
include: "tag_whitespace",
}, {
include: "attribute_value",
}],
tag: [{
token: ["meta.tag.punctuation.tag-open.xml", "meta.tag.punctuation.end-tag-open.xml", "meta.tag.tag-name.xml"],
regex: "(?:(<)|(</))((?:" + tagRegex + ":)?" + tagRegex + ")",
next: [{
include: "attributes",
}, {
token: ["meta.tag.punctuation.end-tag-close.xml", "meta.tag.punctuation.tag-close.xml"],
regex: "(/>)|(>)",
next: "start",
},
],
}],
},
);
if (this.constructor === QWebHighlightRules) {
this.normalizeRules();
}
};
oop.inherits(QWebHighlightRules, XmlHighlightRules);
exports.QWebHighlightRules = QWebHighlightRules;
});
define("ace/mode/qweb",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text","ace/mode/qweb_highlight_rules","ace/mode/behaviour/xml","ace/mode/folding/xml","ace/worker/worker_client"], function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var lang = require("../lib/lang");
var TextMode = require("./text").Mode;
var QWebHighlightRules = require("./qweb_highlight_rules").QWebHighlightRules;
var XmlBehaviour = require("./behaviour/xml").XmlBehaviour;
var XmlFoldMode = require("./folding/xml").FoldMode;
var WorkerClient = require("../worker/worker_client").WorkerClient;
var Mode = function() {
this.HighlightRules = QWebHighlightRules;
this.$behaviour = new XmlBehaviour();
this.foldingRules = new XmlFoldMode();
};
oop.inherits(Mode, TextMode);
(function() {
this.voidElements = lang.arrayToMap([]);
this.blockComment = {start: "<!--", end: "-->"};
this.createWorker = function(session) {
var worker = new WorkerClient(["ace"], "ace/mode/xml_worker", "Worker");
worker.attachToDocument(session.getDocument());
worker.on("error", function(e) {
session.setAnnotations(e.data);
});
worker.on("terminate", function() {
session.clearAnnotations();
});
return worker;
};
this.$id = "ace/mode/xml";
}).call(Mode.prototype);
exports.Mode = Mode;
});
@@ -3520,7 +3520,8 @@ var AceEditor = DebouncedField.extend({
'/web/static/lib/ace/ace.js',
[
'/web/static/lib/ace/mode-python.js',
'/web/static/lib/ace/mode-xml.js'
'/web/static/lib/ace/mode-xml.js',
'/web/static/lib/ace/mode-qweb.js'
]
],
events: {}, // events are triggered manually for this debounced widget
@@ -3613,9 +3614,10 @@ var AceEditor = DebouncedField.extend({
}
this.aceEditor.$blockScrolling = true;
this.aceSession = this.aceEditor.getSession();
const mode = this.nodeOptions.mode || 'qweb';
this.aceSession.setOptions({
useWorker: false,
mode: "ace/mode/" + (this.nodeOptions.mode || 'xml'),
mode: "ace/mode/" + (mode === 'xml' ? 'qweb' : mode),
tabSize: 2,
useSoftTabs: true,
});
+15
View File
@@ -0,0 +1,15 @@
.ace_editor > .ace_gutter {
display: block !important; // display even with aria-hidden
}
.ace_editor .ace_qweb {
color: orange !important;
}
.ace_editor .ace_code {
color: fuchsia !important;
}
.ace_editor.ace-monokai .ace_qweb {
color: lightblue !important;
}
.ace_editor.ace-monokai .ace_code {
color: #c94bc9 !important;
}
@@ -122,6 +122,7 @@ var ViewEditor = Widget.extend({
[
'/web/static/lib/ace/javascript_highlight_rules.js',
'/web/static/lib/ace/mode-xml.js',
'/web/static/lib/ace/mode-qweb.js',
'/web/static/lib/ace/mode-scss.js',
'/web/static/lib/ace/mode-js.js',
'/web/static/lib/ace/theme-monokai.js'
@@ -349,7 +350,8 @@ var ViewEditor = Widget.extend({
type = type || this.currentType;
var editingSession = new window.ace.EditSession(this.resources[type][resID].arch);
editingSession.setUseWorker(false);
editingSession.setMode('ace/mode/' + (type || this.currentType));
let mode = (type || this.currentType);
editingSession.setMode('ace/mode/' + (mode === 'xml' ? 'qweb' : mode));
editingSession.setUndoManager(new window.ace.UndoManager());
editingSession.on('change', function () {
_.defer(function () {
+1
View File
@@ -183,6 +183,7 @@
'website.assets_editor': [
('include', 'web._assets_helpers'),
'web/static/lib/bootstrap/scss/_variables.scss',
'web/static/src/scss/ace.scss',
'website/static/src/scss/website.editor.ui.scss',
'website/static/src/scss/website.theme_install.scss',
'website/static/src/js/menu/content.js',
@@ -965,6 +965,7 @@ options.registry.OptionsTab = options.Class.extend({
jsLibs: [
'/web/static/lib/ace/ace.js',
'/web/static/lib/ace/mode-xml.js',
'/web/static/lib/ace/mode-qweb.js',
],
});
@@ -1163,7 +1164,7 @@ options.registry.OptionsTab = options.Class.extend({
const aceSession = aceEditor.getSession();
aceSession.setOptions({
mode: "ace/mode/xml",
mode: "ace/mode/qweb",
useWorker: false,
});
return aceEditor;