[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
This commit is contained in:
Christophe Matthieu
2016-08-25 09:51:07 +02:00
18 changed files with 14664 additions and 69 deletions
File diff suppressed because one or more lines are too long
+185
View File
@@ -0,0 +1,185 @@
define("ace/mode/python_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
"use strict";
var r = e("../lib/oop"),
i = e("./text_highlight_rules").TextHighlightRules,
s = function() {
var e = "and|as|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|with|yield",
t = "True|False|None|NotImplemented|Ellipsis|__debug__",
n = "abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|binfile|iter|property|tuple|bool|filter|len|range|type|bytearray|float|list|raw_input|unichr|callable|format|locals|reduce|unicode|chr|frozenset|long|reload|vars|classmethod|getattr|map|repr|xrange|cmp|globals|max|reversed|zip|compile|hasattr|memoryview|round|__import__|complex|hash|min|set|apply|delattr|help|next|setattr|buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern",
r = this.createKeywordMapper({
"invalid.deprecated": "debugger",
"support.function": n,
"constant.language": t,
keyword: e
}, "identifier"),
i = "(?:r|u|ur|R|U|UR|Ur|uR)?",
s = "(?:(?:[1-9]\\d*)|(?:0))",
o = "(?:0[oO]?[0-7]+)",
u = "(?:0[xX][\\dA-Fa-f]+)",
a = "(?:0[bB][01]+)",
f = "(?:" + s + "|" + o + "|" + u + "|" + a + ")",
l = "(?:[eE][+-]?\\d+)",
c = "(?:\\.\\d+)",
h = "(?:\\d+)",
p = "(?:(?:" + h + "?" + c + ")|(?:" + h + "\\.))",
d = "(?:(?:" + p + "|" + h + ")" + l + ")",
v = "(?:" + d + "|" + p + ")",
m = "\\\\(x[0-9A-Fa-f]{2}|[0-7]{3}|[\\\\abfnrtv'\"]|U[0-9A-Fa-f]{8}|u[0-9A-Fa-f]{4})";
this.$rules = {
start: [{
token: "comment",
regex: "#.*$"
}, {
token: "string",
regex: i + '"{3}',
next: "qqstring3"
}, {
token: "string",
regex: i + '"(?=.)',
next: "qqstring"
}, {
token: "string",
regex: i + "'{3}",
next: "qstring3"
}, {
token: "string",
regex: i + "'(?=.)",
next: "qstring"
}, {
token: "constant.numeric",
regex: "(?:" + v + "|\\d+)[jJ]\\b"
}, {
token: "constant.numeric",
regex: v
}, {
token: "constant.numeric",
regex: f + "[lL]\\b"
}, {
token: "constant.numeric",
regex: f + "\\b"
}, {
token: r,
regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
}, {
token: "keyword.operator",
regex: "\\+|\\-|\\*|\\*\\*|\\/|\\/\\/|%|<<|>>|&|\\||\\^|~|<|>|<=|=>|==|!=|<>|="
}, {
token: "paren.lparen",
regex: "[\\[\\(\\{]"
}, {
token: "paren.rparen",
regex: "[\\]\\)\\}]"
}, {
token: "text",
regex: "\\s+"
}],
qqstring3: [{
token: "constant.language.escape",
regex: m
}, {
token: "string",
regex: '"{3}',
next: "start"
}, {
defaultToken: "string"
}],
qstring3: [{
token: "constant.language.escape",
regex: m
}, {
token: "string",
regex: "'{3}",
next: "start"
}, {
defaultToken: "string"
}],
qqstring: [{
token: "constant.language.escape",
regex: m
}, {
token: "string",
regex: "\\\\$",
next: "qqstring"
}, {
token: "string",
regex: '"|$',
next: "start"
}, {
defaultToken: "string"
}],
qstring: [{
token: "constant.language.escape",
regex: m
}, {
token: "string",
regex: "\\\\$",
next: "qstring"
}, {
token: "string",
regex: "'|$",
next: "start"
}, {
defaultToken: "string"
}]
}
};
r.inherits(s, i), t.PythonHighlightRules = s
}), define("ace/mode/folding/pythonic", ["require", "exports", "module", "ace/lib/oop", "ace/mode/folding/fold_mode"], function(e, t, n) {
"use strict";
var r = e("../../lib/oop"),
i = e("./fold_mode").FoldMode,
s = t.FoldMode = function(e) {
this.foldingStartMarker = new RegExp("([\\[{])(?:\\s*)$|(" + e + ")(?:\\s*)(?:#.*)?$")
};
r.inherits(s, i),
function() {
this.getFoldWidgetRange = function(e, t, n) {
var r = e.getLine(n),
i = r.match(this.foldingStartMarker);
if (i) return i[1] ? this.openingBracketBlock(e, i[1], n, i.index) : i[2] ? this.indentationBlock(e, n, i.index + i[2].length) : this.indentationBlock(e, n)
}
}.call(s.prototype)
}), define("ace/mode/python", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text", "ace/mode/python_highlight_rules", "ace/mode/folding/pythonic", "ace/range"], function(e, t, n) {
"use strict";
var r = e("../lib/oop"),
i = e("./text").Mode,
s = e("./python_highlight_rules").PythonHighlightRules,
o = e("./folding/pythonic").FoldMode,
u = e("../range").Range,
a = function() {
this.HighlightRules = s, this.foldingRules = new o("\\:")
};
r.inherits(a, i),
function() {
this.lineCommentStart = "#", this.getNextLineIndent = function(e, t, n) {
var r = this.$getIndent(t),
i = this.getTokenizer().getLineTokens(t, e),
s = i.tokens;
if (s.length && s[s.length - 1].type == "comment") return r;
if (e == "start") {
var o = t.match(/^.*[\{\(\[\:]\s*$/);
o && (r += n)
}
return r
};
var e = {
pass: 1,
"return": 1,
raise: 1,
"break": 1,
"continue": 1
};
this.checkOutdent = function(t, n, r) {
if (r !== "\r\n" && r !== "\r" && r !== "\n") return !1;
var i = this.getTokenizer().getLineTokens(n.trim(), t).tokens;
if (!i) return !1;
do var s = i.pop(); while (s && (s.type == "comment" || s.type == "text" && s.value.match(/^\s+$/)));
return s ? s.type == "keyword" && e[s.value] : !1
}, this.autoOutdent = function(e, t, n) {
n += 1;
var r = this.$getIndent(t.getLine(n)),
i = t.getTabString();
r.slice(-i.length) == i && t.remove(new u(n, r.length - i.length, n, r.length))
}, this.$id = "ace/mode/python"
}.call(a.prototype), t.Mode = a
});
+502
View File
@@ -0,0 +1,502 @@
define("ace/mode/xml_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function(e, t, n) {
"use strict";
var r = e("../lib/oop"),
i = e("./text_highlight_rules").TextHighlightRules,
s = function(e) {
var t = "[_:a-zA-Z\u00c0-\uffff][-_:.a-zA-Z0-9\u00c0-\uffff]*";
this.$rules = {
start: [{
token: "string.cdata.xml",
regex: "<\\!\\[CDATA\\[",
next: "cdata"
}, {
token: ["punctuation.xml-decl.xml", "keyword.xml-decl.xml"],
regex: "(<\\?)(xml)(?=[\\s])",
next: "xml_decl",
caseInsensitive: !0
}, {
token: ["punctuation.instruction.xml", "keyword.instruction.xml"],
regex: "(<\\?)(" + t + ")",
next: "processing_instruction"
}, {
token: "comment.xml",
regex: "<\\!--",
next: "comment"
}, {
token: ["xml-pe.doctype.xml", "xml-pe.doctype.xml"],
regex: "(<\\!)(DOCTYPE)(?=[\\s])",
next: "doctype",
caseInsensitive: !0
}, {
include: "tag"
}, {
token: "text.end-tag-open.xml",
regex: "</"
}, {
token: "text.tag-open.xml",
regex: "<"
}, {
include: "reference"
}, {
defaultToken: "text.xml"
}],
xml_decl: [{
token: "entity.other.attribute-name.decl-attribute-name.xml",
regex: "(?:" + t + ":)?" + t + ""
}, {
token: "keyword.operator.decl-attribute-equals.xml",
regex: "="
}, {
include: "whitespace"
}, {
include: "string"
}, {
token: "punctuation.xml-decl.xml",
regex: "\\?>",
next: "start"
}],
processing_instruction: [{
token: "punctuation.instruction.xml",
regex: "\\?>",
next: "start"
}, {
defaultToken: "instruction.xml"
}],
doctype: [{
include: "whitespace"
}, {
include: "string"
}, {
token: "xml-pe.doctype.xml",
regex: ">",
next: "start"
}, {
token: "xml-pe.xml",
regex: "[-_a-zA-Z0-9:]+"
}, {
token: "punctuation.int-subset",
regex: "\\[",
push: "int_subset"
}],
int_subset: [{
token: "text.xml",
regex: "\\s+"
}, {
token: "punctuation.int-subset.xml",
regex: "]",
next: "pop"
}, {
token: ["punctuation.markup-decl.xml", "keyword.markup-decl.xml"],
regex: "(<\\!)(" + t + ")",
push: [{
token: "text",
regex: "\\s+"
}, {
token: "punctuation.markup-decl.xml",
regex: ">",
next: "pop"
}, {
include: "string"
}]
}],
cdata: [{
token: "string.cdata.xml",
regex: "\\]\\]>",
next: "start"
}, {
token: "text.xml",
regex: "\\s+"
}, {
token: "text.xml",
regex: "(?:[^\\]]|\\](?!\\]>))+"
}],
comment: [{
token: "comment.xml",
regex: "-->",
next: "start"
}, {
defaultToken: "comment.xml"
}],
reference: [{
token: "constant.language.escape.reference.xml",
regex: "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
}],
attr_reference: [{
token: "constant.language.escape.reference.attribute-value.xml",
regex: "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
}],
tag: [{
token: ["meta.tag.punctuation.tag-open.xml", "meta.tag.punctuation.end-tag-open.xml", "meta.tag.tag-name.xml"],
regex: "(?:(<)|(</))((?:" + t + ":)?" + t + ")",
next: [{
include: "attributes"
}, {
token: "meta.tag.punctuation.tag-close.xml",
regex: "/?>",
next: "start"
}]
}],
tag_whitespace: [{
token: "text.tag-whitespace.xml",
regex: "\\s+"
}],
whitespace: [{
token: "text.whitespace.xml",
regex: "\\s+"
}],
string: [{
token: "string.xml",
regex: "'",
push: [{
token: "string.xml",
regex: "'",
next: "pop"
}, {
defaultToken: "string.xml"
}]
}, {
token: "string.xml",
regex: '"',
push: [{
token: "string.xml",
regex: '"',
next: "pop"
}, {
defaultToken: "string.xml"
}]
}],
attributes: [{
token: "entity.other.attribute-name.xml",
regex: "(?:" + t + ":)?" + t + ""
}, {
token: "keyword.operator.attribute-equals.xml",
regex: "="
}, {
include: "tag_whitespace"
}, {
include: "attribute_value"
}],
attribute_value: [{
token: "string.attribute-value.xml",
regex: "'",
push: [{
token: "string.attribute-value.xml",
regex: "'",
next: "pop"
}, {
include: "attr_reference"
}, {
defaultToken: "string.attribute-value.xml"
}]
}, {
token: "string.attribute-value.xml",
regex: '"',
push: [{
token: "string.attribute-value.xml",
regex: '"',
next: "pop"
}, {
include: "attr_reference"
}, {
defaultToken: "string.attribute-value.xml"
}]
}]
}, this.constructor === s && this.normalizeRules()
};
(function() {
this.embedTagRules = function(e, t, n) {
this.$rules.tag.unshift({
token: ["meta.tag.punctuation.tag-open.xml", "meta.tag." + n + ".tag-name.xml"],
regex: "(<)(" + n + "(?=\\s|>|$))",
next: [{
include: "attributes"
}, {
token: "meta.tag.punctuation.tag-close.xml",
regex: "/?>",
next: t + "start"
}]
}), this.$rules[n + "-end"] = [{
include: "attributes"
}, {
token: "meta.tag.punctuation.tag-close.xml",
regex: "/?>",
next: "start",
onMatch: function(e, t, n) {
return n.splice(0), this.token
}
}], this.embedRules(e, t, [{
token: ["meta.tag.punctuation.end-tag-open.xml", "meta.tag." + n + ".tag-name.xml"],
regex: "(</)(" + n + "(?=\\s|>|$))",
next: n + "-end"
}, {
token: "string.cdata.xml",
regex: "<\\!\\[CDATA\\["
}, {
token: "string.cdata.xml",
regex: "\\]\\]>"
}])
}
}).call(i.prototype), r.inherits(s, i), t.XmlHighlightRules = s
}), define("ace/mode/behaviour/xml", ["require", "exports", "module", "ace/lib/oop", "ace/mode/behaviour", "ace/token_iterator", "ace/lib/lang"], function(e, t, n) {
"use strict";
function u(e, t) {
return e.type.lastIndexOf(t + ".xml") > -1
}
var r = e("../../lib/oop"),
i = e("../behaviour").Behaviour,
s = e("../../token_iterator").TokenIterator,
o = e("../../lib/lang"),
a = function() {
this.add("string_dquotes", "insertion", function(e, t, n, r, i) {
if (i == '"' || i == "'") {
var o = i,
a = r.doc.getTextRange(n.getSelectionRange());
if (a !== "" && a !== "'" && a != '"' && n.getWrapBehavioursEnabled()) return {
text: o + a + o,
selection: !1
};
var f = n.getCursorPosition(),
l = r.doc.getLine(f.row),
c = l.substring(f.column, f.column + 1),
h = new s(r, f.row, f.column),
p = h.getCurrentToken();
if (c == o && (u(p, "attribute-value") || u(p, "string"))) return {
text: "",
selection: [1, 1]
};
p || (p = h.stepBackward());
if (!p) return;
while (u(p, "tag-whitespace") || u(p, "whitespace")) p = h.stepBackward();
var d = !c || c.match(/\s/);
if (u(p, "attribute-equals") && (d || c == ">") || u(p, "decl-attribute-equals") && (d || c == "?")) return {
text: o + o,
selection: [1, 1]
}
}
}), this.add("string_dquotes", "deletion", function(e, t, n, r, i) {
var s = r.doc.getTextRange(i);
if (!i.isMultiLine() && (s == '"' || s == "'")) {
var o = r.doc.getLine(i.start.row),
u = o.substring(i.start.column + 1, i.start.column + 2);
if (u == s) return i.end.column++, i
}
}), this.add("autoclosing", "insertion", function(e, t, n, r, i) {
if (i == ">") {
var o = n.getCursorPosition(),
a = new s(r, o.row, o.column),
f = a.getCurrentToken() || a.stepBackward();
if (!f || !(u(f, "tag-name") || u(f, "tag-whitespace") || u(f, "attribute-name") || u(f, "attribute-equals") || u(f, "attribute-value"))) return;
if (u(f, "reference.attribute-value")) return;
if (u(f, "attribute-value")) {
var l = f.value.charAt(0);
if (l == '"' || l == "'") {
var c = f.value.charAt(f.value.length - 1),
h = a.getCurrentTokenColumn() + f.value.length;
if (h > o.column || h == o.column && l != c) return
}
}
while (!u(f, "tag-name")) f = a.stepBackward();
var p = a.getCurrentTokenRow(),
d = a.getCurrentTokenColumn();
if (u(a.stepBackward(), "end-tag-open")) return;
var v = f.value;
p == o.row && (v = v.substring(0, o.column - d));
if (this.voidElements.hasOwnProperty(v.toLowerCase())) return;
return {
text: "></" + v + ">",
selection: [1, 1]
}
}
}), this.add("autoindent", "insertion", function(e, t, n, r, i) {
if (i == "\n") {
var o = n.getCursorPosition(),
u = r.getLine(o.row),
a = new s(r, o.row, o.column),
f = a.getCurrentToken();
if (f && f.type.indexOf("tag-close") !== -1) {
if (f.value == "/>") return;
while (f && f.type.indexOf("tag-name") === -1) f = a.stepBackward();
if (!f) return;
var l = f.value,
c = a.getCurrentTokenRow();
f = a.stepBackward();
if (!f || f.type.indexOf("end-tag") !== -1) return;
if (this.voidElements && !this.voidElements[l]) {
var h = r.getTokenAt(o.row, o.column + 1),
u = r.getLine(c),
p = this.$getIndent(u),
d = p + r.getTabString();
return h && h.value === "</" ? {
text: "\n" + d + "\n" + p,
selection: [1, d.length, 1, d.length]
} : {
text: "\n" + d
}
}
}
}
})
};
r.inherits(a, i), t.XmlBehaviour = a
}), define("ace/mode/folding/xml", ["require", "exports", "module", "ace/lib/oop", "ace/lib/lang", "ace/range", "ace/mode/folding/fold_mode", "ace/token_iterator"], function(e, t, n) {
"use strict";
function l(e, t) {
return e.type.lastIndexOf(t + ".xml") > -1
}
var r = e("../../lib/oop"),
i = e("../../lib/lang"),
s = e("../../range").Range,
o = e("./fold_mode").FoldMode,
u = e("../../token_iterator").TokenIterator,
a = t.FoldMode = function(e, t) {
o.call(this), this.voidElements = e || {}, this.optionalEndTags = r.mixin({}, this.voidElements), t && r.mixin(this.optionalEndTags, t)
};
r.inherits(a, o);
var f = function() {
this.tagName = "", this.closing = !1, this.selfClosing = !1, this.start = {
row: 0,
column: 0
}, this.end = {
row: 0,
column: 0
}
};
(function() {
this.getFoldWidget = function(e, t, n) {
var r = this._getFirstTagInLine(e, n);
return r ? r.closing || !r.tagName && r.selfClosing ? t == "markbeginend" ? "end" : "" : !r.tagName || r.selfClosing || this.voidElements.hasOwnProperty(r.tagName.toLowerCase()) ? "" : this._findEndTagInLine(e, n, r.tagName, r.end.column) ? "" : "start" : ""
}, this._getFirstTagInLine = function(e, t) {
var n = e.getTokens(t),
r = new f;
for (var i = 0; i < n.length; i++) {
var s = n[i];
if (l(s, "tag-open")) {
r.end.column = r.start.column + s.value.length, r.closing = l(s, "end-tag-open"), s = n[++i];
if (!s) return null;
r.tagName = s.value, r.end.column += s.value.length;
for (i++; i < n.length; i++) {
s = n[i], r.end.column += s.value.length;
if (l(s, "tag-close")) {
r.selfClosing = s.value == "/>";
break
}
}
return r
}
if (l(s, "tag-close")) return r.selfClosing = s.value == "/>", r;
r.start.column += s.value.length
}
return null
}, this._findEndTagInLine = function(e, t, n, r) {
var i = e.getTokens(t),
s = 0;
for (var o = 0; o < i.length; o++) {
var u = i[o];
s += u.value.length;
if (s < r) continue;
if (l(u, "end-tag-open")) {
u = i[o + 1];
if (u && u.value == n) return !0
}
}
return !1
}, this._readTagForward = function(e) {
var t = e.getCurrentToken();
if (!t) return null;
var n = new f;
do
if (l(t, "tag-open")) n.closing = l(t, "end-tag-open"), n.start.row = e.getCurrentTokenRow(), n.start.column = e.getCurrentTokenColumn();
else if (l(t, "tag-name")) n.tagName = t.value;
else if (l(t, "tag-close")) return n.selfClosing = t.value == "/>", n.end.row = e.getCurrentTokenRow(), n.end.column = e.getCurrentTokenColumn() + t.value.length, e.stepForward(), n;
while (t = e.stepForward());
return null
}, this._readTagBackward = function(e) {
var t = e.getCurrentToken();
if (!t) return null;
var n = new f;
do {
if (l(t, "tag-open")) return n.closing = l(t, "end-tag-open"), n.start.row = e.getCurrentTokenRow(), n.start.column = e.getCurrentTokenColumn(), e.stepBackward(), n;
l(t, "tag-name") ? n.tagName = t.value : l(t, "tag-close") && (n.selfClosing = t.value == "/>", n.end.row = e.getCurrentTokenRow(), n.end.column = e.getCurrentTokenColumn() + t.value.length)
} while (t = e.stepBackward());
return null
}, this._pop = function(e, t) {
while (e.length) {
var n = e[e.length - 1];
if (!t || n.tagName == t.tagName) return e.pop();
if (this.optionalEndTags.hasOwnProperty(n.tagName)) {
e.pop();
continue
}
return null
}
}, this.getFoldWidgetRange = function(e, t, n) {
var r = this._getFirstTagInLine(e, n);
if (!r) return null;
var i = r.closing || r.selfClosing,
o = [],
a;
if (!i) {
var f = new u(e, n, r.start.column),
l = {
row: n,
column: r.start.column + r.tagName.length + 2
};
r.start.row == r.end.row && (l.column = r.end.column);
while (a = this._readTagForward(f)) {
if (a.selfClosing) {
if (!o.length) return a.start.column += a.tagName.length + 2, a.end.column -= 2, s.fromPoints(a.start, a.end);
continue
}
if (a.closing) {
this._pop(o, a);
if (o.length == 0) return s.fromPoints(l, a.start)
} else o.push(a)
}
} else {
var f = new u(e, n, r.end.column),
c = {
row: n,
column: r.start.column
};
while (a = this._readTagBackward(f)) {
if (a.selfClosing) {
if (!o.length) return a.start.column += a.tagName.length + 2, a.end.column -= 2, s.fromPoints(a.start, a.end);
continue
}
if (!a.closing) {
this._pop(o, a);
if (o.length == 0) return a.start.column += a.tagName.length + 2, a.start.row == a.end.row && a.start.column < a.end.column && (a.start.column = a.end.column), s.fromPoints(a.start, c)
} else o.push(a)
}
}
}
}).call(a.prototype)
}), define("ace/mode/xml", ["require", "exports", "module", "ace/lib/oop", "ace/lib/lang", "ace/mode/text", "ace/mode/xml_highlight_rules", "ace/mode/behaviour/xml", "ace/mode/folding/xml", "ace/worker/worker_client"], function(e, t, n) {
"use strict";
var r = e("../lib/oop"),
i = e("../lib/lang"),
s = e("./text").Mode,
o = e("./xml_highlight_rules").XmlHighlightRules,
u = e("./behaviour/xml").XmlBehaviour,
a = e("./folding/xml").FoldMode,
f = e("../worker/worker_client").WorkerClient,
l = function() {
this.HighlightRules = o, this.$behaviour = new u, this.foldingRules = new a
};
r.inherits(l, s),
function() {
this.voidElements = i.arrayToMap([]), this.blockComment = {
start: "<!--",
end: "-->"
}, this.createWorker = function(e) {
var t = new f(["ace"], "ace/mode/xml_worker", "Worker");
return t.attachToDocument(e.getDocument()), t.on("error", function(t) {
e.setAnnotations(t.data)
}), t.on("terminate", function() {
e.clearAnnotations()
}), t
}, this.$id = "ace/mode/xml"
}.call(l.prototype), t.Mode = l
});
+105
View File
@@ -0,0 +1,105 @@
define("ace/theme/monokai",["require","exports","module","ace/lib/dom"], function(require, exports, module) {
exports.isDark = true;
exports.cssClass = "ace-monokai";
exports.cssText = ".ace-monokai .ace_gutter {\
background: #2F3129;\
color: #8F908A\
}\
.ace-monokai .ace_print-margin {\
width: 1px;\
background: #555651\
}\
.ace-monokai {\
background-color: #272822;\
color: #F8F8F2\
}\
.ace-monokai .ace_cursor {\
color: #F8F8F0\
}\
.ace-monokai .ace_marker-layer .ace_selection {\
background: #49483E\
}\
.ace-monokai.ace_multiselect .ace_selection.ace_start {\
box-shadow: 0 0 3px 0px #272822;\
}\
.ace-monokai .ace_marker-layer .ace_step {\
background: rgb(102, 82, 0)\
}\
.ace-monokai .ace_marker-layer .ace_bracket {\
margin: -1px 0 0 -1px;\
border: 1px solid #49483E\
}\
.ace-monokai .ace_marker-layer .ace_active-line {\
background: #202020\
}\
.ace-monokai .ace_gutter-active-line {\
background-color: #272727\
}\
.ace-monokai .ace_marker-layer .ace_selected-word {\
border: 1px solid #49483E\
}\
.ace-monokai .ace_invisible {\
color: #52524d\
}\
.ace-monokai .ace_entity.ace_name.ace_tag,\
.ace-monokai .ace_keyword,\
.ace-monokai .ace_meta.ace_tag,\
.ace-monokai .ace_storage {\
color: #F92672\
}\
.ace-monokai .ace_punctuation,\
.ace-monokai .ace_punctuation.ace_tag {\
color: #fff\
}\
.ace-monokai .ace_constant.ace_character,\
.ace-monokai .ace_constant.ace_language,\
.ace-monokai .ace_constant.ace_numeric,\
.ace-monokai .ace_constant.ace_other {\
color: #AE81FF\
}\
.ace-monokai .ace_invalid {\
color: #F8F8F0;\
background-color: #F92672\
}\
.ace-monokai .ace_invalid.ace_deprecated {\
color: #F8F8F0;\
background-color: #AE81FF\
}\
.ace-monokai .ace_support.ace_constant,\
.ace-monokai .ace_support.ace_function {\
color: #66D9EF\
}\
.ace-monokai .ace_fold {\
background-color: #A6E22E;\
border-color: #F8F8F2\
}\
.ace-monokai .ace_storage.ace_type,\
.ace-monokai .ace_support.ace_class,\
.ace-monokai .ace_support.ace_type {\
font-style: italic;\
color: #66D9EF\
}\
.ace-monokai .ace_entity.ace_name.ace_function,\
.ace-monokai .ace_entity.ace_other,\
.ace-monokai .ace_entity.ace_other.ace_attribute-name,\
.ace-monokai .ace_variable {\
color: #A6E22E\
}\
.ace-monokai .ace_variable.ace_parameter {\
font-style: italic;\
color: #FD971F\
}\
.ace-monokai .ace_string {\
color: #E6DB74\
}\
.ace-monokai .ace_comment {\
color: #75715E\
}\
.ace-monokai .ace_indent-guide {\
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y\
}";
var dom = require("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);
});
File diff suppressed because it is too large Load Diff
+99 -2
View File
@@ -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.odoo-custom.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
@@ -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
+13
View File
@@ -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">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,11 +0,0 @@
odoo.define('website.ace_theme_monokai', function () {
function load () {
ace.define("ace/theme/monokai",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!0,t.cssClass="ace-monokai",t.cssText=".ace-monokai .ace_gutter {background: #2F3129;color: #8F908A}.ace-monokai .ace_print-margin {width: 1px;background: #555651}.ace-monokai {background-color: #272822;color: #F8F8F2}.ace-monokai .ace_cursor {border-left: 2px solid #F8F8F0}.ace-monokai .ace_overwrite-cursors .ace_cursor {border-left: 0px;border-bottom: 1px solid #F8F8F0}.ace-monokai .ace_marker-layer .ace_selection {background: #49483E}.ace-monokai.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px #272822;border-radius: 2px}.ace-monokai .ace_marker-layer .ace_step {background: rgb(102, 82, 0)}.ace-monokai .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid #49483E}.ace-monokai .ace_marker-layer .ace_active-line {background: #202020}.ace-monokai .ace_gutter-active-line {background-color: #272727}.ace-monokai .ace_marker-layer .ace_selected-word {border: 1px solid #49483E}.ace-monokai .ace_invisible {color: #52524d}.ace-monokai .ace_entity.ace_name.ace_tag,.ace-monokai .ace_keyword,.ace-monokai .ace_meta.ace_tag,.ace-monokai .ace_storage {color: #F92672}.ace-monokai .ace_constant.ace_character,.ace-monokai .ace_constant.ace_language,.ace-monokai .ace_constant.ace_numeric,.ace-monokai .ace_constant.ace_other {color: #AE81FF}.ace-monokai .ace_invalid {color: #F8F8F0;background-color: #F92672}.ace-monokai .ace_invalid.ace_deprecated {color: #F8F8F0;background-color: #AE81FF}.ace-monokai .ace_support.ace_constant,.ace-monokai .ace_support.ace_function {color: #66D9EF}.ace-monokai .ace_fold {background-color: #A6E22E;border-color: #F8F8F2}.ace-monokai .ace_storage.ace_type,.ace-monokai .ace_support.ace_class,.ace-monokai .ace_support.ace_type {font-style: italic;color: #66D9EF}.ace-monokai .ace_entity.ace_name.ace_function,.ace-monokai .ace_entity.ace_other,.ace-monokai .ace_entity.ace_other.ace_attribute-name,.ace-monokai .ace_variable {color: #A6E22E}.ace-monokai .ace_variable.ace_parameter {font-style: italic;color: #FD971F}.ace-monokai .ace_string {color: #E6DB74}.ace-monokai .ace_comment {color: #75715E}.ace-monokai .ace_markup.ace_underline {text-decoration: underline}.ace-monokai .ace_indent-guide {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAEklEQVQImWPQ0FD0ZXBzd/wPAAjVAoxeSgNeAAAAAElFTkSuQmCC) right repeat-y;}";var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
}
return {
load: load,
};
});
+17 -8
View File
@@ -6,7 +6,6 @@ var Class = require('web.Class');
var core = require('web.core');
var Widget = require('web.Widget');
var base = require('web_editor.base');
var ace_call = require('website.ace_call');
var website = require('website.website');
var local_storage = require('web.local_storage');
@@ -22,17 +21,26 @@ var Ace = Widget.extend({
'click a[data-action=ace]': 'launchAce',
},
launchAce: function (e) {
ace_call.load();
var self = this;
if (!window.ace && !this.loadJS_def) {
this.loadJS_def = ajax.loadJS('/web/static/lib/ace/ace.odoo-custom.js').then(function () {
return $.when(ajax.loadJS('/web/static/lib/ace/mode-xml.js'),
ajax.loadJS('/web/static/lib/ace/theme-monokai.js'));
});
}
if (e) {
e.preventDefault();
}
if (this.globalEditor) {
this.globalEditor.open();
} else {
this.globalEditor = new ViewEditor(this);
this.globalEditor.appendTo($(document.body));
}
return $.when(this.loadJS_def).then(function () {
if (self.globalEditor) {
self.globalEditor.open();
} else {
self.globalEditor = new ViewEditor(self);
self.globalEditor.appendTo($(document.body));
}
});
},
});
@@ -217,6 +225,7 @@ var ViewEditor = Widget.extend({
var editingSession = self.buffers[viewId] = new ace.EditSession(result[0].arch);
editingSession.setMode("ace/mode/xml");
editingSession.setUndoManager(new ace.UndoManager());
editingSession.setUseWorker(false);
editingSession.on("change", function () {
setTimeout(function () {
var $option = self.$('#ace-view-list').find('[value='+viewId+']');
@@ -306,13 +306,13 @@ body .modal {
}
// ACE EDITOR
.oe_ace_view_editor {
.o_ace_view_editor {
.o-position-absolute(@odoo-navbar-height, 0, 0);
position: fixed;
z-index: 1001;
background: #2F3129;
color: white;
.oe_ace_view_editor_title {
.o_ace_view_editor_title {
width: 100%;
height: 30px;
padding-top: 0;
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website.ace_view_editor">
<div class="oe_ace_view_editor oe_ace_closed">
<div class="form-inline oe_ace_view_editor_title">
<div class="o_ace_view_editor oe_ace_closed">
<div class="form-inline o_ace_view_editor_title">
<select id="ace-view-list" class="form-control oe_view_list">
<!-- filled in JS -->
</select>
@@ -33,9 +33,6 @@
<script type="text/javascript" src="/website/static/src/js/website.editor.js"></script>
<script type="text/javascript" src="/website/static/lib/jQuery.transfo.js"></script>
<script type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
<script type="text/javascript" src="/website/static/lib/ace/theme-monokai.js"></script>
<script type="text/javascript" src="/website/static/lib/ace/mode-xml.js"></script>
<script type="text/javascript" src="/website/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
<script type="text/javascript" src="/website/static/lib/jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.mobile.js"></script>
+1 -1
View File
@@ -292,7 +292,7 @@
<notebook colspan="4">
<page string="Python Code" name='code' autofocus="autofocus"
attrs="{'invisible': [('state', '!=', 'code')]}">
<field name="code" placeholder="Enter Python code here. Help about Python expression is available in the help tab of this document."/>
<field name="code" widget="ace" options="{'mode': 'python'}" placeholder="Enter Python code here. Help about Python expression is available in the help tab of this document."/>
</page>
<page string="Worflow Signal" autofocus="autofocus"
+2 -2
View File
@@ -109,7 +109,7 @@
attrs="{'readonly': [('state','=','base')]}"/>
<field name="related"/>
<field name="depends"/>
<field name="compute"/>
<field name="compute" widget="ace" options="{'mode': 'python'}"/>
</group>
<h3>How to define a computed field</h3>
<p>Computed fields are defined with the fields
@@ -276,7 +276,7 @@
attrs="{'readonly': [('state','=','base')]}"/>
<field name="related"/>
<field name="depends" attrs="{'required': [('compute', '!=', False)] }"/>
<field name="compute"/>
<field name="compute" widget="ace" options="{'mode': 'python'}"/>
</group>
<h3>How to define a computed field</h3>
<p>Computed fields are defined with the fields
+1 -1
View File
@@ -26,7 +26,7 @@
<page string="Architecture">
<button type="object" name="open_translations"
string="Edit Translations" class="oe_link oe_right"/>
<field name="arch_base"/>
<field name="arch_base" widget="ace" options="{'mode': 'xml'}"/>
</page>
<page string="Groups">
<field name="groups_id"/>