From 8c559044a5e1be111dcb577ad7e5ab462c1002a0 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 7 Jul 2015 16:02:53 +0200 Subject: [PATCH] [IMP] web_editor: split website into web_editor (to use editor in backend for html field) and website --- addons/web/static/src/css/base.css | 2 +- addons/web/static/src/js/framework/ajax.js | 34 + addons/web/static/src/js/tour.js | 24 +- addons/web/static/src/js/views/form_common.js | 6 + addons/web/static/src/js/views/form_view.js | 130 +- addons/web/views/webclient_templates.xml | 22 +- addons/web_editor/__init__.py | 4 + addons/web_editor/__openerp__.py | 21 + addons/web_editor/controllers/__init__.py | 1 + addons/web_editor/controllers/main.py | 276 ++ addons/web_editor/models/__init__.py | 7 + addons/web_editor/models/ir_attachment.py | 149 + addons/web_editor/models/ir_http.py | 16 + addons/web_editor/models/ir_qweb.py | 566 ++++ addons/web_editor/models/ir_ui_view.py | 123 + .../models/test_models.py | 7 +- .../web_editor/security/ir.model.access.csv | 3 + addons/web_editor/static/src/css/backend.css | 73 + addons/web_editor/static/src/css/common.sass | 4 + addons/web_editor/static/src/css/inline.css | 64 + addons/web_editor/static/src/css/snippets.css | 490 ++++ .../web_editor/static/src/css/snippets.sass | 376 +++ .../web_editor/static/src/css/web_editor.css | 266 ++ .../web_editor/static/src/css/web_editor.sass | 195 ++ .../static/src/img/drag_here.png | Bin .../static/src/img/edit_here.png | Bin addons/web_editor/static/src/js/backend.js | 322 +++ addons/web_editor/static/src/js/base.js | 85 + addons/web_editor/static/src/js/editor.js | 164 ++ addons/web_editor/static/src/js/iframe.js | 78 + addons/web_editor/static/src/js/inline.js | 77 + addons/web_editor/static/src/js/rte.js | 597 ++++ .../static/src/js/rte.summernote.js | 781 ++++++ .../static/src/js/snippets.animation.js | 82 + .../static/src/js/snippets.editor.js | 1137 ++++++++ .../static/src/js/snippets.options.js | 534 ++++ .../static/src/js/summernote.js | 112 +- .../static/src/js/tour.rte.js} | 222 +- addons/web_editor/static/src/js/transcoder.js | 172 ++ addons/web_editor/static/src/js/translator.js | 214 ++ addons/web_editor/static/src/js/widgets.js | 1069 +++++++ addons/web_editor/static/src/xml/backend.xml | 59 + addons/web_editor/static/src/xml/editor.xml | 372 +++ .../static/src/xml/snippets.xml} | 12 +- .../web_editor/static/src/xml/translator.xml | 14 + addons/web_editor/tests/__init__.py | 3 + addons/web_editor/tests/test_converter.py | 243 ++ addons/web_editor/tests/test_ui.py | 9 + addons/web_editor/views/editor.xml | 153 + addons/web_editor/views/iframe.xml | 62 + addons/web_editor/views/snippets.xml | 56 + addons/web_tests/static/src/js/web.tour.js | 6 +- addons/website/__openerp__.py | 2 +- addons/website/controllers/main.py | 194 +- addons/website/models/__init__.py | 2 - addons/website/models/ir_http.py | 3 +- addons/website/models/ir_qweb.py | 558 +--- addons/website/models/ir_ui_view.py | 148 +- addons/website/models/website.py | 186 +- addons/website/security/ir.model.access.csv | 2 - .../static/lib/summernote/src/js/Renderer.js | 2 +- addons/website/static/src/css/snippets.css | 722 ----- addons/website/static/src/css/snippets.sass | 579 ---- .../static/src/css/website.backend.css | 31 - addons/website/static/src/css/website.css | 249 +- .../website/static/src/css/website.editor.css | 263 ++ .../static/src/css/website.editor.sass | 234 ++ addons/website/static/src/css/website.sass | 181 +- .../website/static/src/js/openerp.define.js | 107 - .../static/src/js/website.backend.iframe.js | 75 - .../website/static/src/js/website.backend.js | 153 - .../website/static/src/js/website.editor.js | 2463 +---------------- addons/website/static/src/js/website.js | 268 +- .../src/js/website.snippets.animation.js | 72 - .../static/src/js/website.snippets.editor.js | 1667 +---------- addons/website/static/src/js/website.theme.js | 2 +- .../static/src/js/website.translator.js | 258 +- .../static/src/xml/website.backend.xml | 6 - .../static/src/xml/website.contentMenu.xml | 6 +- .../website/static/src/xml/website.editor.xml | 609 +--- .../static/src/xml/website.gallery.xml | 2 +- .../static/src/xml/website.translator.xml | 8 +- addons/website/tests/test_converter.py | 240 +- addons/website/tests/test_ui.py | 9 +- addons/website/views/snippets.xml | 17 +- addons/website/views/website.backend.xml | 65 - .../website/views/website_backend_navbar.xml | 6 +- addons/website/views/website_templates.xml | 131 +- .../static/src/xml/website.gengo.xml | 4 +- addons/website_version/models/ir_ui_view.py | 2 +- openerp/addons/base/ir/ir_qweb.py | 5 +- openerp/addons/base/ir/ir_ui_view.py | 2 +- .../addons/base/tests/test_mail_examples.py | 2 +- openerp/tools/translate.py | 2 +- 94 files changed, 10096 insertions(+), 8935 deletions(-) create mode 100644 addons/web_editor/__init__.py create mode 100644 addons/web_editor/__openerp__.py create mode 100644 addons/web_editor/controllers/__init__.py create mode 100644 addons/web_editor/controllers/main.py create mode 100644 addons/web_editor/models/__init__.py create mode 100644 addons/web_editor/models/ir_attachment.py create mode 100644 addons/web_editor/models/ir_http.py create mode 100644 addons/web_editor/models/ir_qweb.py create mode 100644 addons/web_editor/models/ir_ui_view.py rename addons/{website => web_editor}/models/test_models.py (88%) create mode 100644 addons/web_editor/security/ir.model.access.csv create mode 100644 addons/web_editor/static/src/css/backend.css create mode 100644 addons/web_editor/static/src/css/common.sass create mode 100644 addons/web_editor/static/src/css/inline.css create mode 100644 addons/web_editor/static/src/css/snippets.css create mode 100644 addons/web_editor/static/src/css/snippets.sass create mode 100644 addons/web_editor/static/src/css/web_editor.css create mode 100644 addons/web_editor/static/src/css/web_editor.sass rename addons/{website => web_editor}/static/src/img/drag_here.png (100%) rename addons/{website => web_editor}/static/src/img/edit_here.png (100%) create mode 100644 addons/web_editor/static/src/js/backend.js create mode 100644 addons/web_editor/static/src/js/base.js create mode 100644 addons/web_editor/static/src/js/editor.js create mode 100644 addons/web_editor/static/src/js/iframe.js create mode 100644 addons/web_editor/static/src/js/inline.js create mode 100644 addons/web_editor/static/src/js/rte.js create mode 100644 addons/web_editor/static/src/js/rte.summernote.js create mode 100644 addons/web_editor/static/src/js/snippets.animation.js create mode 100644 addons/web_editor/static/src/js/snippets.editor.js create mode 100644 addons/web_editor/static/src/js/snippets.options.js rename addons/{website => web_editor}/static/src/js/summernote.js (95%) rename addons/{website/static/src/js/website.tour.rte.js => web_editor/static/src/js/tour.rte.js} (56%) create mode 100644 addons/web_editor/static/src/js/transcoder.js create mode 100644 addons/web_editor/static/src/js/translator.js create mode 100644 addons/web_editor/static/src/js/widgets.js create mode 100644 addons/web_editor/static/src/xml/backend.xml create mode 100644 addons/web_editor/static/src/xml/editor.xml rename addons/{website/static/src/xml/website.snippets.xml => web_editor/static/src/xml/snippets.xml} (92%) create mode 100644 addons/web_editor/static/src/xml/translator.xml create mode 100644 addons/web_editor/tests/__init__.py create mode 100644 addons/web_editor/tests/test_converter.py create mode 100644 addons/web_editor/tests/test_ui.py create mode 100644 addons/web_editor/views/editor.xml create mode 100644 addons/web_editor/views/iframe.xml create mode 100644 addons/web_editor/views/snippets.xml create mode 100644 addons/website/static/src/css/website.editor.css create mode 100644 addons/website/static/src/css/website.editor.sass delete mode 100644 addons/website/static/src/js/openerp.define.js delete mode 100644 addons/website/static/src/js/website.backend.iframe.js diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 2fce98dd145..37e68889f01 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -1,4 +1,4 @@ -@charset "UTF-8"; +@charset "utf-8"; @font-face { font-family: "mnmliconsRegular"; src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot"); diff --git a/addons/web/static/src/js/framework/ajax.js b/addons/web/static/src/js/framework/ajax.js index dd1eee906c1..ce61f225524 100644 --- a/addons/web/static/src/js/framework/ajax.js +++ b/addons/web/static/src/js/framework/ajax.js @@ -275,11 +275,45 @@ function get_file(options) { }; +var loadXML = (function () { + var loading = false; + var urls = []; + var qwebs = []; + var templates_def = $.Deferred(); + + var load = function loadXML(url, qweb) { + if (url) { + urls.push(url); + qwebs.push(qweb); + } + + if (!loading && urls.length) { + if (templates_def.state() === "resolved") { + templates_def = $.Deferred(); + } + + loading = true; + qwebs.shift().add_template(urls.shift(), function () { + loading = false; + if (!urls.length) { + templates_def.resolve(); + } + load(null); + }); + } + + return templates_def; + }; + + return load; +})(); + return { jsonRpc: jsonRpc, jsonpRpc: jsonpRpc, loadCSS: loadCSS, loadJS: loadJS, + loadXML: loadXML, get_file: get_file, }; diff --git a/addons/web/static/src/js/tour.js b/addons/web/static/src/js/tour.js index 234b681f7d2..585626ab4a2 100644 --- a/addons/web/static/src/js/tour.js +++ b/addons/web/static/src/js/tour.js @@ -6,25 +6,6 @@ var core = require('web.core'); var _t = core._t; var qweb = core.qweb; -// make this work -// raise an error in test mode if openerp don't exist -// if (typeof openerp === "undefined") { -// var error = "openerp is undefined" -// + "\nhref: " + window.location.href -// + "\nreferrer: " + document.referrer -// + "\nlocalStorage: " + window.localStorage.getItem("tour"); -// if (typeof $ !== "undefined") { -// error += '\n\n' + $("body").html(); -// } -// throw new Error(error); -// } - - -// // don't rewrite T in test mode -// if (typeof openerp.Tour !== "undefined") { -// return; -// } - ///////////////////////////////////////////////// @@ -78,7 +59,7 @@ var Tour = { defaultDelay: 50, autoRunning: true, retryRunningDelay: 1000, - errorDelay: 5000, + errorDelay: 10000, state: null, $element: null, timer: null, @@ -700,7 +681,7 @@ var Tour = { }, scrollIntoView: function ($element){ // if element is not on window (screen) then it scroll down to get popup visible - if (!$element.is('body')){ + if (!$element.is('body') && !$element.parents().filter(function () { return $(this).css("position") === "fixed";}).length){ var element_top = $element.offset().top; var visible = ((element_top > $(window).scrollTop()) && (element_top < ($(window).scrollTop() + $(window).height()))); if (!visible) { @@ -709,7 +690,6 @@ var Tour = { } } }; -// openerp.Tour = Tour; ///////////////////////////////////////////////// diff --git a/addons/web/static/src/js/views/form_common.js b/addons/web/static/src/js/views/form_common.js index 19737746b4a..4d8a302882d 100644 --- a/addons/web/static/src/js/views/form_common.js +++ b/addons/web/static/src/js/views/form_common.js @@ -630,6 +630,12 @@ var FieldInterface = { the field to save its value before reading it using get_value(). Must return a promise. */ commit_value: function() {}, + /* + The form view call before_save before save data and if before_save return a deferred, + the form view wait that all deferred are resolve or fail. + If the deferred is rejected, the field is invalidate + */ + before_save: function() {}, }; /** diff --git a/addons/web/static/src/js/views/form_view.js b/addons/web/static/src/js/views/form_view.js index fd024ae0f75..3286f34eff4 100644 --- a/addons/web/static/src/js/views/form_view.js +++ b/addons/web/static/src/js/views/form_view.js @@ -837,68 +837,92 @@ var FormView = View.extend(common.FieldManagerMixin, { _process_save: function(save_obj) { var self = this; var prepend_on_create = save_obj.prepend_on_create; + var def_process_save = $.Deferred(); try { var form_invalid = false, values = {}, first_invalid_field = null, - readonly_values = {}; - for (var f in self.fields) { - if (!self.fields.hasOwnProperty(f)) { continue; } - f = self.fields[f]; - if (!f.is_valid()) { - form_invalid = true; - if (!first_invalid_field) { - first_invalid_field = f; - } - } else if (f.name !== 'id' && (!self.datarecord.id || f._dirty_flag)) { - // Special case 'id' field, do not save this field - // on 'create' : save all non readonly fields - // on 'edit' : save non readonly modified fields - if (!f.get("readonly")) { - values[f.name] = f.get_value(true); - } else { - readonly_values[f.name] = f.get_value(true); - } + readonly_values = {}, + deferred = []; + + _.each(self.fields, function (f) { + var res = f.before_save(); + if (res) { + deferred.push(res); + res.fail(function () { + form_invalid = true; + if (!first_invalid_field) { + first_invalid_field = f; + } + }); } - } - // Heuristic to assign a proper sequence number for new records that - // are added in a dataset containing other lines with existing sequence numbers - if (!self.datarecord.id && self.fields.sequence && - !_.has(values, 'sequence') && !_.isEmpty(self.dataset.cache)) { - // Find current max or min sequence (editable top/bottom) - var current = _[prepend_on_create ? "min" : "max"]( - _.map(self.dataset.cache, function(o){return o.values.sequence}) - ); - values['sequence'] = prepend_on_create ? current - 1 : current + 1; - } - if (form_invalid) { - self.set({'display_invalid_fields': true}); - first_invalid_field.focus(); - self.on_invalid(); - return $.Deferred().reject(); - } else { - self.set({'display_invalid_fields': false}); - var save_deferral; - if (!self.datarecord.id) { - // Creation save - save_deferral = self.dataset.create(values, {readonly_fields: readonly_values}).then(function(r) { - return self.record_created(r, prepend_on_create); - }, null); - } else if (_.isEmpty(values)) { - // Not dirty, noop save - save_deferral = $.Deferred().resolve({}).promise(); + }); + + $.when.apply($, deferred).always(function () { + + _.each(self.fields, function (f) { + if (!f.is_valid()) { + form_invalid = true; + if (!first_invalid_field) { + first_invalid_field = f; + } + } else if (f.name !== 'id' && (!self.datarecord.id || f._dirty_flag)) { + // Special case 'id' field, do not save this field + // on 'create' : save all non readonly fields + // on 'edit' : save non readonly modified fields + if (!f.get("readonly")) { + values[f.name] = f.get_value(true); + } else { + readonly_values[f.name] = f.get_value(true); + } + } + + }); + + // Heuristic to assign a proper sequence number for new records that + // are added in a dataset containing other lines with existing sequence numbers + if (!self.datarecord.id && self.fields.sequence && + !_.has(values, 'sequence') && !_.isEmpty(self.dataset.cache)) { + // Find current max or min sequence (editable top/bottom) + var current = _[prepend_on_create ? "min" : "max"]( + _.map(self.dataset.cache, function(o){return o.values.sequence}) + ); + values['sequence'] = prepend_on_create ? current - 1 : current + 1; + } + if (form_invalid) { + self.set({'display_invalid_fields': true}); + first_invalid_field.focus(); + self.on_invalid(); + def_process_save.reject(); } else { - // Write save - save_deferral = self.dataset.write(self.datarecord.id, values, {readonly_fields: readonly_values}).then(function(r) { - return self.record_saved(r); - }, null); + self.set({'display_invalid_fields': false}); + var save_deferral; + if (!self.datarecord.id) { + // Creation save + save_deferral = self.dataset.create(values, {readonly_fields: readonly_values}).then(function(r) { + return self.record_created(r, prepend_on_create); + }, null); + } else if (_.isEmpty(values)) { + // Not dirty, noop save + save_deferral = $.Deferred().resolve({}).promise(); + } else { + // Write save + save_deferral = self.dataset.write(self.datarecord.id, values, {readonly_fields: readonly_values}).then(function(r) { + return self.record_saved(r); + }, null); + } + save_deferral.then(function(result) { + def_process_save.resolve(result); + }).fail(function() { + def_process_save.reject(); + }); } - return save_deferral; - } + }); } catch (e) { console.error(e); - return $.Deferred().reject(); + return def_process_save.reject(); } + return def_process_save; }, on_invalid: function() { var warnings = _(this.fields).chain() @@ -1266,7 +1290,7 @@ var FormRenderingEngine = FormRenderingEngineInterface.extend({ } var obj = self.fields_registry.get_any([$elem.attr('widget'), self.fvg.fields[name].type]); if (!obj) { - throw new Error(_.str.sprintf(_t("Widget type '%s' is not implemented"), $elem.attr('widget'))); + throw new Error(_.str.sprintf(_t("Widget type '%s' is not implemented"), $elem.attr('widget') || self.fvg.fields[name].type )); } var w = new (obj)(self.view, utils.xml_to_json($elem[0])); var $label = self.labels[$elem.attr("name")]; diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 6082bca1363..94553687043 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -10,6 +10,8 @@ + + @@ -64,19 +66,6 @@ - -