Merge lp:~therp-nl/web-addons/web-ckeditor4 into lp:~webaddons-core-editors/web-addons/6.1

Proposed by Holger Brunn (Therp)
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
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.

To post a comment you must log in.
14. By Holger Brunn (Therp)

[IMP] adjust css

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

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?

Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

something like
if context.get('use_raw_html_yes_i_know_what_im_doing')
{
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

Revision history for this message
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

Revision history for this message
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?

Revision history for this message
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

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Seems fine!

Thanks

review: Approve (no test)
Revision history for this message
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.

review: Needs Information (testing, functional)
Revision history for this message
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

Revision history for this message
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.

review: Needs Information
Revision history for this message
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)

Revision history for this message
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!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+

Subscribers

People subscribed via source and target branches