Merge lp:~therp-nl/web-addons/web-ckeditor4 into lp:~webaddons-core-editors/web-addons/6.1
- web-ckeditor4
- Merge into 6.1
Status: | Merged |
---|---|
Merged at revision: | 12 |
Proposed branch: | lp:~therp-nl/web-addons/web-ckeditor4 |
Merge into: | lp:~webaddons-core-editors/web-addons/6.1 |
Prerequisite: | lp:~therp-nl/web-addons/web-ckeditor4_no_clutter |
Diff against target: |
403 lines (+376/-0) 5 files modified
web_ckeditor4/__init__.py (+22/-0) web_ckeditor4/__openerp__.py (+114/-0) web_ckeditor4/static/src/css/web_ckeditor4.css (+6/-0) web_ckeditor4/static/src/js/ckeditor_basepath.js (+1/-0) web_ckeditor4/static/src/js/web_ckeditor4.js (+233/-0) |
To merge this branch: | bzr merge lp:~therp-nl/web-addons/web-ckeditor4 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stefan Rijnhart (Opener) | Approve | ||
Guewen Baconnier @ Camptocamp | no test | Approve | |
Review via email: mp+158683@code.launchpad.net |
Commit message
[ADD] web_ckeditor
Description of the change
I've been unhappy with the few existing HTML editing widgets for 6.1, so here an approach to improve on that.
Concerning the name: As ckeditor is not API compatible across major versions and OpenERP has no concept of versioned dependencies, I think we have to encode the version in the module's name. For addons that just need something to display/edit html without messing with the editor we could add a module web_ckeditor that depends on the current version.
I'm still pondering if the base version of this module should do any HTML filtering at all. I see this as a serverside task, because sometimes you actually want to do stuff with possibly malicious HTML, say from a function field where the HTML is generated by your own code. Let's discuss that in the MP.
Then even after a lot of tinkering, it doesn't go perfectly well with jQuery dialogs, so you'll have error popups after editing an HTML field in a popup (x2m dialogs). But it's only a nuisance, the content is properly saved. Any pointers on that issue are more than welcome.
For convenience in review, this branch sits on top of another one that adds stock ckeditor. To review that, have a look at the prerequsite branch.
- 14. By Holger Brunn (Therp)
-
[IMP] adjust css
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Holger Brunn (Therp) (hbrunn) wrote : | # |
something like
if context.
{
return value;
}
else
{
return filter(value);
}
?
Seems to be a very good point, thanks!
- 15. By Holger Brunn (Therp)
-
[FIX] introduce widget text_ckeditor4_raw to display unfiltered html
[IMP] filter html in text_ckeditor4
[FIX] only detach textarea on stop to circumvent issues with jquery
dialog
Holger Brunn (Therp) (hbrunn) wrote : | # |
now I added another widget type to request unfiltered html. That seems to be the most convenient option for users of this addon
- 16. By Holger Brunn (Therp)
-
[ADD] uploader that injects a data uri into the html code
- 17. By Holger Brunn (Therp)
-
[FIX] allow all styles and classes in default filter
Holger Brunn (Therp) (hbrunn) wrote : | # |
Now with the uploader and proper filtering of the HTML-code I'm pretty contend with this addon. What do the reviewers think?
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
It looks good but I need a chance to try it out and see about the x2m popup error.
- 18. By Holger Brunn (Therp)
-
[FIX] really fix errors in popup dialogs
[IMP] also mark the form as dirty the second time we adit an object - 19. By Holger Brunn (Therp)
-
[ADD] make source debugging ckeditor painless
- 20. By Holger Brunn (Therp)
-
[FIX] finally fix problems with popups in chrome
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Seems fine!
Thanks
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Very nicely done! One thing: I understand that the module is versioned according to the ckeditor, but maybe the widget title should not carry this versioning. If you change the widget name to 'text_ckeditor' then the addons that apply the widget need not bother which version is installed. What do you think?
Also, it would be helpful just to state the obvious and mention that you can use the module by setting the widget on selected text fields to 'web_ckeditor' in the module description.
Holger Brunn (Therp) (hbrunn) wrote : | # |
Thanks, I updated the description.
This also explains my thinking about the widget names: I would rather keep them versioned too, as you will very likely have to adapt things when stepping to web_ckeditor5 if you found it necessary to use the versioned widget name in the first place.
- 21. By Holger Brunn (Therp)
-
[IMP] mention which widget names when to use
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Makes me curious to know, as a user of the widget what kind of adaptions to expect when I upgrade the version of the widget? I'd think that the changes would be in the integration module that provides the widget.
Holger Brunn (Therp) (hbrunn) wrote : | # |
Imagine you write a module that is supposed to generate HTML for an email. Then you have to dig deep into the internals of the editor to make it generate code that most mail clients display. So, your mail body field will be widget="ckeditor4".
Your next module needs some old HTML, but also needs to change some toolbars due to customer demand, so you fiddle around with ckeditor's options which are not stable across versions, ergo widget="ckeditor4".
The last one just wants to display and edit some HTML, doesn't really matter what the specifics are: widget="text_html". (And that's the use case I'd mostly expect)
Stefan Rijnhart (Opener) (stefan-opener) wrote : | # |
Then I should have read the module description that you just added because that answers my question as good as your last reply. Thanks!
Preview Diff
1 | === added file 'web_ckeditor4/__init__.py' |
2 | --- web_ckeditor4/__init__.py 1970-01-01 00:00:00 +0000 |
3 | +++ web_ckeditor4/__init__.py 2013-05-29 19:33:26 +0000 |
4 | @@ -0,0 +1,22 @@ |
5 | +# -*- encoding: utf-8 -*- |
6 | +############################################################################## |
7 | +# |
8 | +# OpenERP, Open Source Management Solution |
9 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
10 | +# All Rights Reserved |
11 | +# |
12 | +# This program is free software: you can redistribute it and/or modify |
13 | +# it under the terms of the GNU Affero General Public License as |
14 | +# published by the Free Software Foundation, either version 3 of the |
15 | +# License, or (at your option) any later version. |
16 | +# |
17 | +# This program is distributed in the hope that it will be useful, |
18 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | +# GNU Affero General Public License for more details. |
21 | +# |
22 | +# You should have received a copy of the GNU Affero General Public License |
23 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | +# |
25 | +############################################################################## |
26 | + |
27 | |
28 | === added file 'web_ckeditor4/__openerp__.py' |
29 | --- web_ckeditor4/__openerp__.py 1970-01-01 00:00:00 +0000 |
30 | +++ web_ckeditor4/__openerp__.py 2013-05-29 19:33:26 +0000 |
31 | @@ -0,0 +1,114 @@ |
32 | +# -*- encoding: utf-8 -*- |
33 | +############################################################################## |
34 | +# |
35 | +# OpenERP, Open Source Management Solution |
36 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
37 | +# All Rights Reserved |
38 | +# |
39 | +# This program is free software: you can redistribute it and/or modify |
40 | +# it under the terms of the GNU Affero General Public License as |
41 | +# published by the Free Software Foundation, either version 3 of the |
42 | +# License, or (at your option) any later version. |
43 | +# |
44 | +# This program is distributed in the hope that it will be useful, |
45 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
46 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
47 | +# GNU Affero General Public License for more details. |
48 | +# |
49 | +# You should have received a copy of the GNU Affero General Public License |
50 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
51 | +# |
52 | +############################################################################## |
53 | + |
54 | +{ |
55 | + 'name': 'CKEditor 4.x widget', |
56 | + 'version': '1.0', |
57 | + 'description': """ |
58 | + This addon provides a widget for editing html fields via CKEditor 4.x |
59 | + |
60 | + Use widget="text_html" if you need just html display. In the unlikely case |
61 | + you need specific features of ckeditor, use widget="text_ckeditor4". |
62 | + """, |
63 | + 'author': 'Therp BV', |
64 | + 'website': 'http://www.therp.nl', |
65 | + "category": "Tools", |
66 | + "depends": [ |
67 | + 'web', |
68 | + ], |
69 | + 'css': [ |
70 | + 'static/src/css/web_ckeditor4.css', |
71 | + ], |
72 | + 'data': [ |
73 | + ], |
74 | + 'js': [ |
75 | + 'static/src/js/ckeditor_basepath.js', |
76 | + 'static/lib/ckeditor/ckeditor.js', |
77 | + 'static/lib/ckeditor/config.js', |
78 | + #to debug ckeditor, comment the lines above, |
79 | + #do a |
80 | + #cd static/lib |
81 | + #git clone https://github.com/ckeditor/ckeditor-dev.git trunk |
82 | + #cd trunk |
83 | + #git checkout remotes/origin/release/4.1.x |
84 | + #and uncomment the lines below |
85 | +# 'static/lib/trunk/ckeditor.js', |
86 | +# 'static/lib/trunk/core/event.js', |
87 | +# 'static/lib/trunk/core/editor_basic.js', |
88 | +# 'static/lib/trunk/core/env.js', |
89 | +# 'static/lib/trunk/core/ckeditor_basic.js', |
90 | +# 'static/lib/trunk/core/dom.js', |
91 | +# 'static/lib/trunk/core/tools.js', |
92 | +# 'static/lib/trunk/core/dtd.js', |
93 | +# 'static/lib/trunk/core/dom/event.js', |
94 | +# 'static/lib/trunk/core/dom/domobject.js', |
95 | +# 'static/lib/trunk/core/dom/node.js', |
96 | +# 'static/lib/trunk/core/dom/window.js', |
97 | +# 'static/lib/trunk/core/dom/document.js', |
98 | +# 'static/lib/trunk/core/dom/nodelist.js', |
99 | +# 'static/lib/trunk/core/dom/element.js', |
100 | +# 'static/lib/trunk/core/dom/documentfragment.js', |
101 | +# 'static/lib/trunk/core/dom/walker.js', |
102 | +# 'static/lib/trunk/core/dom/range.js', |
103 | +# 'static/lib/trunk/core/dom/iterator.js', |
104 | +# 'static/lib/trunk/core/command.js', |
105 | +# 'static/lib/trunk/core/ckeditor_base.js', |
106 | +# 'static/lib/trunk/core/config.js', |
107 | +# 'static/lib/trunk/core/filter.js', |
108 | +# 'static/lib/trunk/core/focusmanager.js', |
109 | +# 'static/lib/trunk/core/keystrokehandler.js', |
110 | +# 'static/lib/trunk/core/lang.js', |
111 | +# 'static/lib/trunk/core/scriptloader.js', |
112 | +# 'static/lib/trunk/core/resourcemanager.js', |
113 | +# 'static/lib/trunk/core/plugins.js', |
114 | +# 'static/lib/trunk/core/ui.js', |
115 | +# 'static/lib/trunk/core/editor.js', |
116 | +# 'static/lib/trunk/core/htmlparser.js', |
117 | +# 'static/lib/trunk/core/htmlparser/basicwriter.js', |
118 | +# 'static/lib/trunk/core/htmlparser/node.js', |
119 | +# 'static/lib/trunk/core/htmlparser/comment.js', |
120 | +# 'static/lib/trunk/core/htmlparser/text.js', |
121 | +# 'static/lib/trunk/core/htmlparser/cdata.js', |
122 | +# 'static/lib/trunk/core/htmlparser/fragment.js', |
123 | +# 'static/lib/trunk/core/htmlparser/filter.js', |
124 | +# 'static/lib/trunk/core/htmldataprocessor.js', |
125 | +# 'static/lib/trunk/core/htmlparser/element.js', |
126 | +# 'static/lib/trunk/core/template.js', |
127 | +# 'static/lib/trunk/core/ckeditor.js', |
128 | +# 'static/lib/trunk/core/creators/inline.js', |
129 | +# 'static/lib/trunk/core/creators/themedui.js', |
130 | +# 'static/lib/trunk/core/editable.js', |
131 | +# 'static/lib/trunk/core/selection.js', |
132 | +# 'static/lib/trunk/core/style.js', |
133 | +# 'static/lib/trunk/core/dom/comment.js', |
134 | +# 'static/lib/trunk/core/dom/elementpath.js', |
135 | +# 'static/lib/trunk/core/dom/text.js', |
136 | +# 'static/lib/trunk/core/dom/rangelist.js', |
137 | +# 'static/lib/trunk/core/skin.js', |
138 | +# 'static/lib/trunk/core/_bootstrap.js', |
139 | + #end of ckeditor debug |
140 | + 'static/src/js/web_ckeditor4.js', |
141 | + ], |
142 | + 'installable': True, |
143 | + 'active': False, |
144 | + 'certificate': '', |
145 | +} |
146 | |
147 | === added directory 'web_ckeditor4/static/src' |
148 | === added directory 'web_ckeditor4/static/src/css' |
149 | === added file 'web_ckeditor4/static/src/css/web_ckeditor4.css' |
150 | --- web_ckeditor4/static/src/css/web_ckeditor4.css 1970-01-01 00:00:00 +0000 |
151 | +++ web_ckeditor4/static/src/css/web_ckeditor4.css 2013-05-29 19:33:26 +0000 |
152 | @@ -0,0 +1,6 @@ |
153 | +.openerp .oe_form_field_text_ckeditor4.disabled, .openerp td.oe_form_field_text_ckeditor4, .openerp .oe_form_field_text_ckeditor4_raw.disabled.openerp, .openerp td.oe_form_field_text_ckeditor4_raw { |
154 | + /* here we need to reset openerp's styles to |
155 | + * have the HTML display as (probably) intended |
156 | + */ |
157 | + white-space: normal; |
158 | +} |
159 | |
160 | === added directory 'web_ckeditor4/static/src/js' |
161 | === added file 'web_ckeditor4/static/src/js/ckeditor_basepath.js' |
162 | --- web_ckeditor4/static/src/js/ckeditor_basepath.js 1970-01-01 00:00:00 +0000 |
163 | +++ web_ckeditor4/static/src/js/ckeditor_basepath.js 2013-05-29 19:33:26 +0000 |
164 | @@ -0,0 +1,1 @@ |
165 | +CKEDITOR_BASEPATH='/web_ckeditor4/static/lib/ckeditor/' |
166 | |
167 | === added file 'web_ckeditor4/static/src/js/web_ckeditor4.js' |
168 | --- web_ckeditor4/static/src/js/web_ckeditor4.js 1970-01-01 00:00:00 +0000 |
169 | +++ web_ckeditor4/static/src/js/web_ckeditor4.js 2013-05-29 19:33:26 +0000 |
170 | @@ -0,0 +1,233 @@ |
171 | +/* -*- encoding: utf-8 -*- |
172 | +############################################################################## |
173 | +# |
174 | +# OpenERP, Open Source Management Solution |
175 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
176 | +# All Rights Reserved |
177 | +# |
178 | +# This program is free software: you can redistribute it and/or modify |
179 | +# it under the terms of the GNU Affero General Public License as |
180 | +# published by the Free Software Foundation, either version 3 of the |
181 | +# License, or (at your option) any later version. |
182 | +# |
183 | +# This program is distributed in the hope that it will be useful, |
184 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
185 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
186 | +# GNU Affero General Public License for more details. |
187 | +# |
188 | +# You should have received a copy of the GNU Affero General Public License |
189 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
190 | +# |
191 | +############################################################################*/ |
192 | + |
193 | +openerp.web_ckeditor4 = function(openerp) |
194 | +{ |
195 | + var ckeditor_addFunction_org = CKEDITOR.tools.addFunction; |
196 | + //this is a quite complicated way to kind of monkey patch the private |
197 | + //method onDomReady of ckeditor's plugin wysiwigarea, which causes problems |
198 | + //when the editor is about to be destroyed but because of OpenERP's |
199 | + //architecture updated one last time with its current value |
200 | + CKEDITOR.tools.addFunction = function(fn, scope) |
201 | + { |
202 | + if(scope && scope._ && scope._.attrChanges && scope._.detach) |
203 | + { |
204 | + var scope_reference = scope; |
205 | + return ckeditor_addFunction_org(function() |
206 | + { |
207 | + var self = this, |
208 | + self_arguments=arguments; |
209 | + setTimeout(function() |
210 | + { |
211 | + if(CKEDITOR.instances[self.editor.name]) |
212 | + { |
213 | + fn.apply(self, self_arguments); |
214 | + } |
215 | + }, 0); |
216 | + }, scope); |
217 | + } |
218 | + return ckeditor_addFunction_org(fn, scope); |
219 | + }; |
220 | + |
221 | + CKEDITOR.lang.load(openerp.connection.user_context.lang.split('_')[0], 'en', function() {}); |
222 | + |
223 | + CKEDITOR.on('dialogDefinition', function(e) |
224 | + { |
225 | + _.each(e.data.definition.contents, function(element) |
226 | + { |
227 | + if(element.filebrowser!='uploadButton') |
228 | + { |
229 | + return |
230 | + } |
231 | + _.each(element.elements, function(element) |
232 | + { |
233 | + if(!element.onClick || element.type!='fileButton') |
234 | + { |
235 | + return |
236 | + } |
237 | + var onClick_org = element.onClick; |
238 | + element.onClick = function(e1) |
239 | + { |
240 | + onClick_org.apply(this, arguments); |
241 | + _.each(jQuery('#'+this.domId).closest('table') |
242 | + .find('iframe').contents().find(':file') |
243 | + .get(0).files, |
244 | + function(file) |
245 | + { |
246 | + var reader = new FileReader(); |
247 | + reader.onload = function(load_event) |
248 | + { |
249 | + CKEDITOR.tools.callFunction( |
250 | + e.editor._.filebrowserFn, |
251 | + load_event.target.result, |
252 | + ''); |
253 | + } |
254 | + reader.readAsDataURL(file); |
255 | + }); |
256 | + return false; |
257 | + } |
258 | + }); |
259 | + }); |
260 | + }); |
261 | + |
262 | + openerp.web.form.widgets.add('text_ckeditor4', |
263 | + 'openerp.web_ckeditor4.FieldCKEditor4'); |
264 | + openerp.web.page.readonly.add('text_ckeditor4', |
265 | + 'openerp.web_ckeditor4.FieldCKEditor4Readonly'); |
266 | + openerp.web.form.widgets.add('text_ckeditor4_raw', |
267 | + 'openerp.web_ckeditor4.FieldCKEditor4Raw'); |
268 | + openerp.web.page.readonly.add('text_ckeditor4_raw', |
269 | + 'openerp.web_ckeditor4.FieldCKEditor4ReadonlyRaw'); |
270 | + openerp.web.form.widgets.add('text_html', |
271 | + 'openerp.web_ckeditor4.FieldCKEditor4'); |
272 | + openerp.web.page.readonly.add('text_html', |
273 | + 'openerp.web_ckeditor4.FieldCKEditor4Readonly'); |
274 | + |
275 | + function filter_html(value, ckeditor_filter, ckeditor_writer) |
276 | + { |
277 | + var fragment = CKEDITOR.htmlParser.fragment.fromHtml(value); |
278 | + ckeditor_filter.applyTo(fragment); |
279 | + ckeditor_writer.reset(); |
280 | + fragment.writeHtml(ckeditor_writer); |
281 | + return ckeditor_writer.getHtml(); |
282 | + }; |
283 | + |
284 | + default_ckeditor_filter = new CKEDITOR.filter( |
285 | + { |
286 | + '*': |
287 | + { |
288 | + attributes: 'href,src,style,alt,width,height', |
289 | + styles: '*', |
290 | + classes: '*', |
291 | + }, |
292 | + 'html head title meta style body p div span a h1 h2 h3 h4 h5 img br hr table tr th td ul ol li dd dt': true, |
293 | + }); |
294 | + default_ckeditor_writer = new CKEDITOR.htmlParser.basicWriter(); |
295 | + |
296 | + openerp.web_ckeditor4.FieldCKEditor4 = openerp.web.form.FieldText.extend({ |
297 | + ckeditor_config: { |
298 | + removePlugins: 'iframe,flash,forms,smiley,pagebreak,stylescombo', |
299 | + filebrowserImageUploadUrl: 'dummy', |
300 | + extraPlugins: 'filebrowser', |
301 | + }, |
302 | + ckeditor_filter: default_ckeditor_filter, |
303 | + ckeditor_writer: default_ckeditor_writer, |
304 | + start: function() |
305 | + { |
306 | + var self = this; |
307 | + this._super.apply(this, arguments); |
308 | + |
309 | + if(this.modifiers.readonly) |
310 | + { |
311 | + return; |
312 | + } |
313 | + |
314 | + self.editor = CKEDITOR.replace(this.$element.find('textarea').get(0), |
315 | + _.extend( |
316 | + { |
317 | + language: openerp.connection.user_context.lang.split('_')[0], |
318 | + on: |
319 | + { |
320 | + 'beforeUndoImage': function() |
321 | + { |
322 | + self.on_ui_change(); |
323 | + }, |
324 | + }, |
325 | + }, |
326 | + this.ckeditor_config)); |
327 | + }, |
328 | + get_value: function() |
329 | + { |
330 | + return this.editor ? openerp.web.parse_value(this.editor.getData(), this) : this.value; |
331 | + }, |
332 | + filter_html: function(value) |
333 | + { |
334 | + return filter_html(value, this.ckeditor_filter, this.ckeditor_writer); |
335 | + }, |
336 | + set_value: function(value) |
337 | + { |
338 | + if(this.modifiers.readonly) |
339 | + { |
340 | + this._super.apply(this, [value]); |
341 | + |
342 | + this.$element.html(this.filter_html(value)); |
343 | + return value; |
344 | + } |
345 | + else |
346 | + { |
347 | + if(this.editor) |
348 | + { |
349 | + var self = this; |
350 | + if(this.editor.status != 'ready') |
351 | + { |
352 | + this.editor.on('instanceReady', |
353 | + function() |
354 | + { |
355 | + self.editor.setData(value || ''); |
356 | + }); |
357 | + } |
358 | + else |
359 | + { |
360 | + self.editor.setData(value || ''); |
361 | + } |
362 | + } |
363 | + this._super.apply(this, arguments); |
364 | + } |
365 | + }, |
366 | + |
367 | + stop: function() |
368 | + { |
369 | + if(this.editor) |
370 | + { |
371 | + CKEDITOR.remove(this.editor); |
372 | + } |
373 | + return this._super.apply(this, arguments); |
374 | + } |
375 | + }); |
376 | + openerp.web_ckeditor4.FieldCKEditor4Raw = openerp.web_ckeditor4.FieldCKEditor4.extend({ |
377 | + filter_html: function(value) |
378 | + { |
379 | + return value; |
380 | + } |
381 | + }); |
382 | + |
383 | + |
384 | + openerp.web_ckeditor4.FieldCKEditor4ReadonlyRaw = openerp.web.page.FieldCharReadonly.extend({ |
385 | + set_value: function (value) |
386 | + { |
387 | + this._super.apply(this, arguments); |
388 | + this.$element.find('div').html(value); |
389 | + return value; |
390 | + } |
391 | + }); |
392 | + openerp.web_ckeditor4.FieldCKEditor4Readonly = openerp.web.page.FieldCharReadonly.extend({ |
393 | + ckeditor_filter: default_ckeditor_filter, |
394 | + ckeditor_writer: default_ckeditor_writer, |
395 | + set_value: function (value) |
396 | + { |
397 | + this._super.apply(this, arguments); |
398 | + this.$element.find('div').html(filter_html(value, this.ckeditor_filter, this.ckeditor_writer)); |
399 | + return value; |
400 | + } |
401 | + }); |
402 | +} |
403 | + |
Shouldn't client side filtering be the default if it is easy to do, with the option to disable it with something like a context value?