Instead of doing a name_get on the edited value and trying to find out an m2o to assign back (which there's pretty much no chance of given there's no autocompletion or anything), alter the m2o record in-place by setting the provided edited value to its _rec_name. Ideally, both features could be supported via more advanced m2o edition widgets which would allow selecting an existing m2o, creating a new m2o record from scratch or (maybe) editing the existing m2o's display_name if possible, somewhat similar to what the form view provides. Without these though, the only action which makes any sense is to edit the user-visible "value" where it is found, as with more normal fields. bzr revid: xmo@openerp.com-20131218140917-4eo2o55yfcumzhov
138 lines
5.4 KiB
Python
138 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
import copy
|
|
from urlparse import urlparse
|
|
|
|
from lxml import etree, html
|
|
|
|
from openerp.osv import osv, fields
|
|
from openerp.addons.base import ir
|
|
|
|
class view(osv.osv):
|
|
_inherit = "ir.ui.view"
|
|
_columns = {
|
|
'inherit_option_id': fields.many2one('ir.ui.view','Optional Inheritancy'),
|
|
'inherited_option_ids': fields.one2many('ir.ui.view','inherit_option_id','Optional Inheritancies'),
|
|
'page': fields.boolean("Whether this view is a web page template (complete)"),
|
|
'website_meta_title': fields.char("Website meta title", size=70, translate=True),
|
|
'website_meta_description': fields.text("Website meta description", size=160, translate=True),
|
|
'website_meta_keywords': fields.char("Website meta keywords", translate=True),
|
|
}
|
|
_defaults = {
|
|
'page': False,
|
|
}
|
|
|
|
# Returns all views (called and inherited) related to a view
|
|
# Used by translation mechanism, SEO and optional templates
|
|
def _views_get(self, cr, uid, view, options=True, context=None, root=True, stack_result=None):
|
|
if not context:
|
|
context = {}
|
|
if not stack_result:
|
|
stack_result = []
|
|
|
|
def view_obj(view):
|
|
if type(view) in (str, unicode):
|
|
mod_obj = self.pool.get("ir.model.data")
|
|
m, n = view.split('.')
|
|
_, view = mod_obj.get_object_reference(cr, uid, m, n)
|
|
if type(view) == int:
|
|
view_obj = self.pool.get("ir.ui.view")
|
|
view = view_obj.browse(cr, uid, view, context=context)
|
|
return view
|
|
view = view_obj(view)
|
|
|
|
while root and view.inherit_id:
|
|
view = view.inherit_id
|
|
|
|
result = [view]
|
|
todo = view.inherit_children_ids
|
|
if options:
|
|
todo += filter(lambda x: not x.inherit_id, view.inherited_option_ids)
|
|
for child_view in todo:
|
|
for r in self._views_get(cr, uid, child_view, options=options, context=context, root=False, stack_result=result):
|
|
if r not in result:
|
|
result.append(r)
|
|
node = etree.fromstring(view.arch)
|
|
for child in node.xpath("//t[@t-call]"):
|
|
call_view = view_obj(child.get('t-call'))
|
|
if call_view not in result:
|
|
result += self._views_get(cr, uid, call_view, options=options, context=context, stack_result=result)
|
|
return result
|
|
|
|
def extract_embedded_fields(self, cr, uid, arch, context=None):
|
|
return arch.xpath('//*[@data-oe-model != "ir.ui.view"]')
|
|
|
|
def save_embedded_field(self, cr, uid, el, context=None):
|
|
Model = self.pool[el.get('data-oe-model')]
|
|
field = el.get('data-oe-field')
|
|
|
|
column = Model._all_columns[field].column
|
|
converter = self.pool['website.qweb'].get_converter_for(
|
|
el.get('data-oe-type'))
|
|
value = converter.from_html(cr, uid, Model, column, el)
|
|
|
|
if value is not None:
|
|
# TODO: batch writes?
|
|
Model.write(cr, uid, [int(el.get('data-oe-id'))], {
|
|
field: value
|
|
}, context=context)
|
|
|
|
def to_field_ref(self, cr, uid, el, context=None):
|
|
# filter out meta-information inserted in the document
|
|
attributes = dict((k, v) for k, v in el.items()
|
|
if not k.startswith('data-oe-'))
|
|
attributes['t-field'] = el.get('data-oe-expression')
|
|
|
|
out = html.html_parser.makeelement(el.tag, attrib=attributes)
|
|
out.tail = el.tail
|
|
return out
|
|
|
|
def replace_arch_section(self, cr, uid, view_id, section_xpath, replacement, context=None):
|
|
# the root of the arch section shouldn't actually be replaced as it's
|
|
# not really editable itself, only the content truly is editable.
|
|
|
|
[view] = self.browse(cr, uid, [view_id], context=context)
|
|
arch = etree.fromstring(view.arch.encode('utf-8'))
|
|
# => get the replacement root
|
|
if not section_xpath:
|
|
root = arch
|
|
else:
|
|
# ensure there's only one match
|
|
[root] = arch.xpath(section_xpath)
|
|
|
|
root.text = replacement.text
|
|
root.tail = replacement.tail
|
|
# replace all children
|
|
del root[:]
|
|
for child in replacement:
|
|
root.append(copy.deepcopy(child))
|
|
|
|
return arch
|
|
|
|
def save(self, cr, uid, res_id, value, xpath=None, context=None):
|
|
""" Update a view section. The view section may embed fields to write
|
|
|
|
:param str model:
|
|
:param int res_id:
|
|
:param str xpath: valid xpath to the tag to replace
|
|
"""
|
|
res_id = int(res_id)
|
|
|
|
arch_section = html.fromstring(
|
|
value, parser=html.HTMLParser(encoding='utf-8'))
|
|
|
|
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)
|
|
|
|
# transform embedded field back to t-field
|
|
el.getparent().replace(el, self.to_field_ref(cr, uid, el, context=context))
|
|
|
|
arch = self.replace_arch_section(cr, uid, res_id, xpath, arch_section, context=context)
|
|
self.write(cr, uid, res_id, {
|
|
'arch': etree.tostring(arch, encoding='utf-8').decode('utf-8')
|
|
}, context=context)
|