[IMP] single whole-page editor, reinstate ability to save only an embedded field (not part of a view)
bzr revid: xmo@openerp.com-20130917085753-aa32xxezhtrfaffj
This commit is contained in:
parent
f3eec24a6f
commit
757a2dbc4e
|
@ -242,14 +242,7 @@
|
|||
this.$('#website-top-edit').show();
|
||||
$('.css_non_editable_mode_hidden').removeClass("css_non_editable_mode_hidden");
|
||||
|
||||
var $editables = $('[data-oe-model][data-oe-xpath]')
|
||||
// FIXME: propagation should make "meta" blocks non-editable in the first place...
|
||||
.not('link, script')
|
||||
.not('[data-oe-type]')
|
||||
.not('.oe_snippet_editor')
|
||||
.prop('contentEditable', true)
|
||||
.addClass('oe_editable');
|
||||
this.rte.start_edition($editables);
|
||||
this.rte.start_edition();
|
||||
},
|
||||
rte_changed: function () {
|
||||
this.$buttons.save.prop('disabled', false);
|
||||
|
@ -258,20 +251,26 @@
|
|||
var self = this;
|
||||
|
||||
observer.disconnect();
|
||||
var defs = _(CKEDITOR.instances).chain()
|
||||
.filter(function (editor) { return editor.element.hasClass('oe_dirty'); })
|
||||
.map(function (editor) {
|
||||
var $el = $(editor.element.$);
|
||||
var editor = this.rte.editor;
|
||||
var root = editor.element.$;
|
||||
editor.destroy();
|
||||
// FIXME: select editables then filter by dirty?
|
||||
var defs = this.rte.fetch_editables(root)
|
||||
.removeClass('oe_editable cke_focus')
|
||||
.removeAttr('contentEditable')
|
||||
.filter('.oe_dirty')
|
||||
.map(function () {
|
||||
var $el = $(this);
|
||||
// TODO: Add a queue with concurrency limit in webclient
|
||||
// https://github.com/medikoo/deferred/blob/master/lib/ext/function/gate.js
|
||||
return self.saving_mutex.exec(function () {
|
||||
return self.saveEditor(editor)
|
||||
return self.saveElement($el)
|
||||
.fail(function () {
|
||||
var data = $el.data();
|
||||
console.error(_.str.sprintf('Could not save %s(%d).%s', data.oeModel, data.oeId, data.oeField));
|
||||
});
|
||||
});
|
||||
}).value();
|
||||
}).get();
|
||||
return $.when.apply(null, defs).then(function () {
|
||||
window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
|
||||
});
|
||||
|
@ -279,18 +278,15 @@
|
|||
/**
|
||||
* Saves an RTE content, which always corresponds to a view section (?).
|
||||
*/
|
||||
saveEditor: function (editor) {
|
||||
var element = editor.element;
|
||||
editor.destroy();
|
||||
element.removeClass('cke_focus')
|
||||
.removeClass('oe_dirty')
|
||||
.removeClass('oe_editable')
|
||||
.removeAttribute('contentEditable');
|
||||
var data = element.getOuterHtml();
|
||||
saveElement: function ($el) {
|
||||
$el.removeClass('oe_dirty');
|
||||
var markup = $el.prop('outerHTML');
|
||||
return openerp.jsonRpc('/web/dataset/call', 'call', {
|
||||
model: 'ir.ui.view',
|
||||
method: 'save',
|
||||
args: [element.data('oe-id'), data, element.data('oe-xpath'), website.get_context()],
|
||||
args: [$el.data('oe-id'), markup,
|
||||
$el.data('oe-xpath') || null,
|
||||
website.get_context()],
|
||||
});
|
||||
},
|
||||
cancel: function () {
|
||||
|
@ -313,22 +309,57 @@
|
|||
|
||||
start_edition: function ($elements) {
|
||||
var self = this;
|
||||
$elements
|
||||
// create a single editor for the whole page
|
||||
// FIXME: is not the whole page, ckeditor can't handle body
|
||||
var root = document.getElementById('wrap');
|
||||
root.setAttribute('data-cke-editable', 'true');
|
||||
this.editor = CKEDITOR.inline(root, self._config());
|
||||
this.editor.on('instanceReady', function () {
|
||||
// ckeditor set root to editable, disable it (only inner
|
||||
// sections are editable)
|
||||
// FIXME: are there cases where the whole editor is editable?
|
||||
root.contentEditable = false;
|
||||
|
||||
self.setup_editables(root);
|
||||
});
|
||||
},
|
||||
|
||||
setup_editables: function (root) {
|
||||
// selection of editable sub-items was previously in
|
||||
// EditorBar#edit, but for some unknown reason the elements were
|
||||
// apparently removed and recreated (?) at editor initalization,
|
||||
// and observer setup was lost.
|
||||
var self = this;
|
||||
// setup dirty-marking for each editable element
|
||||
this.fetch_editables(root)
|
||||
.prop('contentEditable', true)
|
||||
.addClass('oe_editable')
|
||||
.each(function () {
|
||||
var node = this;
|
||||
observer.observe(node, OBSERVER_CONFIG);
|
||||
var $node = $(node);
|
||||
var editor = CKEDITOR.inline(this, self._config());
|
||||
editor.on('instanceReady', function () {
|
||||
self.trigger('instanceReady');
|
||||
observer.observe(node, OBSERVER_CONFIG);
|
||||
});
|
||||
$node.one('content_changed', function () {
|
||||
console.log("!", $node)
|
||||
$node.addClass('oe_dirty');
|
||||
self.trigger('change');
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
fetch_editables: function (root) {
|
||||
return $(root).find('[data-oe-model]')
|
||||
// FIXME: propagation should make "meta" blocks non-editable in the first place...
|
||||
.not('link, script')
|
||||
.not('.oe_snippet_editor')
|
||||
.filter(function () {
|
||||
var $this = $(this);
|
||||
// keep view sections and fields which are *not* in
|
||||
// view sections for toplevel editables
|
||||
return $this.data('oe-model') === 'ir.ui.view'
|
||||
|| !$this.closest('[data-oe-model = "ir.ui.view"]').length;
|
||||
});
|
||||
},
|
||||
|
||||
_current_editor: function () {
|
||||
return CKEDITOR.currentInstance;
|
||||
},
|
||||
|
|
|
@ -154,6 +154,21 @@ class TestViewSaving(common.TransactionCase):
|
|||
)
|
||||
)
|
||||
|
||||
def test_save_only_embedded(self):
|
||||
Company = self.registry('res.company')
|
||||
company_id = 1
|
||||
Company.write(self.cr, self.uid, company_id, {'name': "Foo Corporation"})
|
||||
|
||||
node = html.tostring(h.SPAN(
|
||||
"Acme Corporation",
|
||||
attrs(model='res.company', id=company_id, field="name", expression='bob')))
|
||||
|
||||
self.registry('ir.ui.view').save(self.cr, self.uid, res_id=company_id,value=node)
|
||||
|
||||
company = Company.browse(self.cr, self.uid, company_id)
|
||||
self.assertEqual(company.name, "Acme Corporation")
|
||||
|
||||
|
||||
def test_field_tail(self):
|
||||
View = self.registry('ir.ui.view')
|
||||
replacement = ET.tostring(
|
||||
|
|
|
@ -91,6 +91,11 @@ class view(osv.osv):
|
|||
|
||||
arch_section = html.fromstring(value)
|
||||
|
||||
if xpath is None:
|
||||
# value is an embedded field on its own, not a view section
|
||||
self.save_embedded_field(cr, uid, arch_section, context=context)
|
||||
return
|
||||
|
||||
for el in self.extract_embedded_fields(cr, uid, arch_section, context=context):
|
||||
self.save_embedded_field(cr, uid, el, context=context)
|
||||
|
||||
|
|
Loading…
Reference in New Issue