1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
odoo.define('web_editor.base', function (require) {
'use strict';
// TODO this should be re-removed as soon as possible.
var ajax = require('web.ajax');
var session = require('web.session');
var domReady = new Promise(function(resolve) {
$(resolve);
});
return {
/**
* Retrieves all the CSS rules which match the given parser (Regex).
*
* @param {Regex} filter
* @returns {Object[]} Array of CSS rules descriptions (objects). A rule is
* defined by 3 values: 'selector', 'css' and 'names'. 'selector'
* is a string which contains the whole selector, 'css' is a string
* which contains the css properties and 'names' is an array of the
* first captured groups for each selector part. E.g.: if the
* filter is set to match .fa-* rules and capture the icon names,
* the rule:
* '.fa-alias1::before, .fa-alias2::before { hello: world; }'
* will be retrieved as
* {
* selector: '.fa-alias1::before, .fa-alias2::before',
* css: 'hello: world;',
* names: ['.fa-alias1', '.fa-alias2'],
* }
*/
cacheCssSelectors: {},
getCssSelectors: function (filter) {
if (this.cacheCssSelectors[filter]) {
return this.cacheCssSelectors[filter];
}
this.cacheCssSelectors[filter] = [];
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
var rules;
try {
// try...catch because Firefox not able to enumerate
// document.styleSheets[].cssRules[] for cross-domain
// stylesheets.
rules = sheets[i].rules || sheets[i].cssRules;
} catch (e) {
console.warn("Can't read the css rules of: " + sheets[i].href, e);
continue;
}
if (!rules) {
continue;
}
for (var r = 0 ; r < rules.length ; r++) {
var selectorText = rules[r].selectorText;
if (!selectorText) {
continue;
}
var selectors = selectorText.split(/\s*,\s*/);
var data = null;
for (var s = 0; s < selectors.length; s++) {
var match = selectors[s].trim().match(filter);
if (!match) {
continue;
}
if (!data) {
data = {
selector: match[0],
css: rules[r].cssText.replace(/(^.*\{\s*)|(\s*\}\s*$)/g, ''),
names: [match[1]]
};
} else {
data.selector += (', ' + match[0]);
data.names.push(match[1]);
}
}
if (data) {
this.cacheCssSelectors[filter].push(data);
}
}
}
return this.cacheCssSelectors[filter];
},
/**
* List of font icons to load by editor. The icons are displayed in the media
* editor and identified like font and image (can be colored, spinned, resized
* with fa classes).
* To add font, push a new object {base, parser}
*
* - base: class who appear on all fonts
* - parser: regular expression used to select all font in css stylesheets
*
* @type Array
*/
fontIcons: [{base: 'fa', parser: /\.(fa-(?:\w|-)+)::?before/i}],
/**
* Searches the fonts described by the @see fontIcons variable.
*/
computeFonts: _.once(function () {
var self = this;
_.each(this.fontIcons, function (data) {
data.cssData = self.getCssSelectors(data.parser);
data.alias = _.flatten(_.map(data.cssData, _.property('names')));
});
}),
/**
* If a widget needs to be instantiated on page loading, it needs to wait
* for appropriate resources to be loaded. This function returns a Promise
* which is resolved when the dom is ready, the session is bound
* (translations loaded) and the XML is loaded. This should however not be
* necessary anymore as widgets should not be parentless and should then be
* instantiated (directly or not) by the page main component (webclient,
* website root, editor bar, ...). The DOM will be ready then, the main
* component is in charge of waiting for the session and the XML can be
* lazy loaded thanks to the @see Widget.xmlDependencies key.
*
* @returns {Promise}
*/
ready: function () {
return Promise.all([domReady, session.is_bound, ajax.loadXML()]);
},
};
});
//==============================================================================
odoo.define('web_editor.context', function (require) {
'use strict';
// TODO this should be re-removed as soon as possible.
function getContext(context) {
var html = document.documentElement;
return _.extend({
lang: (html.getAttribute('lang') || 'en_US').replace('-', '_'),
// Unfortunately this is a mention of 'website' in 'web_editor' as there
// was no other way to do it as this was restored in a stable version.
// Indeed, the editor is currently using this context at the root of JS
// module, so there is no way for website to hook itself before
// web_editor uses it (without a risky refactoring of web_editor in
// stable). As mentioned above, the editor should not use this context
// anymore anyway (this was restored by the saas-12.2 editor revert).
'website_id': html.getAttribute('data-website-id') | 0,
}, context || {});
}
function getExtraContext(context) {
var html = document.documentElement;
return _.extend(getContext(), {
editable: !!(html.dataset.editable || $('[data-oe-model]').length), // temporary hack, this should be done in python
translatable: !!html.dataset.translatable,
edit_translations: !!html.dataset.edit_translations,
}, context || {});
}
return {
get: getContext,
getExtra: getExtraContext,
};
});
//==============================================================================
odoo.define('web_editor.ready', function (require) {
'use strict';
// TODO this should be re-removed as soon as possible.
var base = require('web_editor.base');
return base.ready();
});
|