diff --git a/addons/base/controllers/main.py b/addons/base/controllers/main.py index a610fbe177e..3f519f30962 100644 --- a/addons/base/controllers/main.py +++ b/addons/base/controllers/main.py @@ -98,7 +98,12 @@ class Session(openerpweb.Controller): "session_id": req.session_id, "uid": req.session._uid, } - + + @openerpweb.jsonrequest + def sc_list(self, req): + return req.session.model('ir.ui.view_sc').get_sc(req.session._uid, "ir.ui.menu", + req.session.eval_context(req.context)) + @openerpweb.jsonrequest def get_databases_list(self, req): proxy = req.session.proxy("db") @@ -166,9 +171,9 @@ class Session(openerpweb.Controller): a list of fields to group by, potentially empty (in which case no group by should be performed) """ - context = req.session.eval_contexts(contexts) - domain = req.session.eval_domains(domains, context) - + context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(*contexts)) + domain = req.session.eval_domain(openerpweb.nonliterals.CompoundDomain(*(domains or [])), context) + group_by_sequence = [] for candidate in (group_by_seq or []): ctx = req.session.eval_context(candidate, context) @@ -179,7 +184,7 @@ class Session(openerpweb.Controller): group_by_sequence.append(group_by) else: group_by_sequence.extend(group_by) - + return { 'context': context, 'domain': domain, @@ -226,8 +231,14 @@ class Session(openerpweb.Controller): return None return saved_actions["actions"].get(key) +def eval_context_and_domain(session, context, domain=None): + e_context = session.eval_context(context) + e_domain = session.eval_domain(domain or [], e_context) + + return (e_context, e_domain) def load_actions_from_ir_values(req, key, key2, models, meta, context): + context['bin_size'] = False # Possible upstream bug. Antony says not to loose time on this. Values = req.session.model('ir.values') actions = Values.get(key, key2, models, meta, context) @@ -301,8 +312,9 @@ class Menu(openerpweb.Controller): Menus = req.session.model('ir.ui.menu') # menus are loaded fully unlike a regular tree view, cause there are # less than 512 items - menu_ids = Menus.search([]) - menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id']) + context = req.session.eval_context(req.context) + menu_ids = Menus.search([], 0, False, False, context) + menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context) menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, '']} menu_items.append(menu_root) @@ -327,8 +339,8 @@ class Menu(openerpweb.Controller): @openerpweb.jsonrequest def action(self, req, menu_id): actions = load_actions_from_ir_values(req,'action', 'tree_but_open', - [('ir.ui.menu', menu_id)], False, {}) - + [('ir.ui.menu', menu_id)], False, + req.session.eval_context(req.context)) return {"action": actions} class DataSet(openerpweb.Controller): @@ -336,7 +348,8 @@ class DataSet(openerpweb.Controller): @openerpweb.jsonrequest def fields(self, req, model): - return {'fields': req.session.model(model).fields_get()} + return {'fields': req.session.model(model).fields_get(False, + req.session.eval_context(req.context))} @openerpweb.jsonrequest def search_read(self, request, model, fields=False, offset=0, limit=False, domain=None, context=None, sort=None): @@ -358,21 +371,23 @@ class DataSet(openerpweb.Controller): :rtype: list """ Model = request.session.model(model) - - ids = Model.search(domain or [], offset or 0, limit or False, - sort or False, request.context) + context, domain = eval_context_and_domain(request.session, request.context, domain) + + ids = Model.search(domain, offset or 0, limit or False, + sort or False, context) if fields and fields == ['id']: # shortcut read if we only want the ids return map(lambda id: {'id': id}, ids) - reads = Model.read(ids, fields or False, request.context) + reads = Model.read(ids, fields or False, context) reads.sort(key=lambda obj: ids.index(obj['id'])) return reads @openerpweb.jsonrequest def read(self, request, model, ids, fields=False): - return self.do_search_read(request, model, ids, fields) + return self.do_search_read(request, model, ids, fields, + request.session.eval_context(request.context)) @openerpweb.jsonrequest def get(self, request, model, ids, fields=False): @@ -397,40 +412,48 @@ class DataSet(openerpweb.Controller): :rtype: list """ Model = request.session.model(model) - records = Model.read(ids, fields, request.context) + records = Model.read(ids, fields, request.session.eval_context(request.context)) record_map = dict((record['id'], record) for record in records) return [record_map[id] for id in ids if record_map.get(id)] + @openerpweb.jsonrequest - def load(self, req, model, id, fields): m = req.session.model(model) value = {} - r = m.read([id]) + r = m.read([id], False, req.session.eval_context(req.context)) if r: value = r[0] return {'value': value} @openerpweb.jsonrequest - def create(self, req, model, data, context={}): + def create(self, req, model, data): m = req.session.model(model) - r = m.create(data, context) + r = m.create(data, req.session.eval_context(req.context)) return {'result': r} @openerpweb.jsonrequest - def save(self, req, model, id, data, context={}): + def save(self, req, model, id, data): m = req.session.model(model) - r = m.write([id], data, context) + r = m.write([id], data, req.session.eval_context(req.context)) return {'result': r} @openerpweb.jsonrequest def unlink(self, request, model, ids=[]): Model = request.session.model(model) - return Model.unlink(ids) + return Model.unlink(ids, request.session.eval_context(request.context)) @openerpweb.jsonrequest - def call(self, req, model, method, args): + def call(self, req, model, method, args, domain_id=None, context_id=None): + domain = args[domain_id] if domain_id and len(args) - 1 >= domain_id else [] + context = args[context_id] if context_id and len(args) - 1 >= context_id else {} + c, d = eval_context_and_domain(req.session, context, domain); + if(domain_id and len(args) - 1 >= domain_id): + args[domain_id] = d + if(context_id and len(args) - 1 >= context_id): + args[context_id] = c + m = req.session.model(model) r = getattr(m, method)(*args) return {'result': r} @@ -441,15 +464,9 @@ class DataSet(openerpweb.Controller): return {'result': r} @openerpweb.jsonrequest - def default_get(self, req, model, fields, context={}): + def default_get(self, req, model, fields): m = req.session.model(model) - r = m.default_get(fields, context) - return {'result': r} - - @openerpweb.jsonrequest - def name_search(self, req, model, search_str, domain=[], context={}, limit=False): - m = req.session.model(model) - r = m.name_search(search_str, domain, 'ilike', context, limit) + r = m.default_get(fields, req.session.eval_context(req.context)) return {'result': r} class DataGroup(openerpweb.Controller): @@ -457,10 +474,11 @@ class DataGroup(openerpweb.Controller): @openerpweb.jsonrequest def read(self, request, model, group_by_fields, domain=None): Model = request.session.model(model) + context, domain = eval_context_and_domain(request.session, request.context, domain) return Model.read_group( domain or [], False, group_by_fields, 0, False, - dict(request.context, group_by=group_by_fields)) + dict(context, group_by=group_by_fields)) class View(openerpweb.Controller): _cp_path = "/base/view" @@ -468,9 +486,10 @@ class View(openerpweb.Controller): def fields_view_get(self, request, model, view_id, view_type, transform=True, toolbar=False, submenu=False): Model = request.session.model(model) - fvg = Model.fields_view_get(view_id, view_type, request.context, - toolbar, submenu) - self.process_view(request.session, fvg, request.context, transform) + context = request.session.eval_context(request.context) + fvg = Model.fields_view_get(view_id, view_type, context, toolbar, submenu) + # todo fme?: check that we should pass the evaluated context here + self.process_view(request.session, fvg, context, transform) return fvg def process_view(self, session, fvg, context, transform): @@ -492,18 +511,20 @@ class View(openerpweb.Controller): 'user_id': request.session._uid, 'ref_id': view_id, 'arch': arch - }) + }, request.session.eval_context(request.context)) return {'result': True} @openerpweb.jsonrequest def undo_custom(self, request, view_id, reset=False): CustomView = request.session.model('ir.ui.view.custom') - vcustom = CustomView.search([('user_id', '=', request.session._uid), ('ref_id' ,'=', view_id)]) + context = request.session.eval_context(request.context) + vcustom = CustomView.search([('user_id', '=', request.session._uid), ('ref_id' ,'=', view_id)], + 0, False, False, context) if vcustom: if reset: - CustomView.unlink(vcustom) + CustomView.unlink(vcustom, context) else: - CustomView.unlink([vcustom[0]]) + CustomView.unlink([vcustom[0]], context) return {'result': True} return {'result': False} @@ -640,7 +661,7 @@ class SearchView(View): @openerpweb.jsonrequest def fields_get(self, req, model): Model = req.session.model(model) - fields = Model.fields_get() + fields = Model.fields_get(False, req.session.eval_context(req.context)) return {'fields': fields} class Binary(openerpweb.Controller): @@ -650,11 +671,12 @@ class Binary(openerpweb.Controller): def image(self, request, session_id, model, id, field, **kw): cherrypy.response.headers['Content-Type'] = 'image/png' Model = request.session.model(model) + context = request.session.eval_context(request.context) try: if not id: - res = Model.default_get([field], request.context).get(field, '') + res = Model.default_get([field], context).get(field, '') else: - res = Model.read([int(id)], [field], request.context)[0].get(field, '') + res = Model.read([int(id)], [field], context)[0].get(field, '') return base64.decodestring(res) except: # TODO: what's the exception here? return self.placeholder() @@ -664,7 +686,8 @@ class Binary(openerpweb.Controller): @openerpweb.httprequest def saveas(self, request, session_id, model, id, field, fieldname, **kw): Model = request.session.model(model) - res = Model.read([int(id)], [field, fieldname])[0] + context = request.session.eval_context(request.context) + res = Model.read([int(id)], [field, fieldname], context)[0] filecontent = res.get(field, '') if not filecontent: raise cherrypy.NotFound @@ -706,6 +729,7 @@ class Binary(openerpweb.Controller): @openerpweb.httprequest def upload_attachment(self, request, session_id, callback, model, id, ufile=None): cherrypy.response.timeout = 500 + context = request.session.eval_context(request.context) Model = request.session.model('ir.attachment') try: out = """' ); + + iframe_doc.close(); + + // Update the Iframe's hash, for great justice. + iframe.location.hash = hash; + } + }; + + })(); + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^ + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + return self; + })(); + +})(jQuery,this); +/* +* jQuery Mobile Framework : "page" plugin +* Copyright (c) jQuery Project +* Dual licensed under the MIT or GPL Version 2 licenses. +* http://jquery.org/license +*/ +(function($, undefined ) { + +$.widget( "mobile.page", $.mobile.widget, { + options: { + backBtnText: "Back", + addBackBtn: true, + backBtnTheme: null, + degradeInputs: { + color: false, + date: false, + datetime: false, + "datetime-local": false, + email: false, + month: false, + number: false, + range: "number", + search: true, + tel: false, + time: false, + url: false, + week: false + }, + keepNative: null + }, + + _create: function() { + var $elem = this.element, + o = this.options; + + this.keepNative = ":jqmData(role='none'), :jqmData(role='nojs')" + (o.keepNative ? ", " + o.keepNative : ""); + + if ( this._trigger( "beforeCreate" ) === false ) { + return; + } + + //some of the form elements currently rely on the presence of ui-page and ui-content + // classes so we'll handle page and content roles outside of the main role processing + // loop below. + $elem.find( ":jqmData(role='page'), :jqmData(role='content')" ).andSelf().each(function() { + $(this).addClass( "ui-" + $(this).jqmData( "role" ) ); + }); + + $elem.find( ":jqmData(role='nojs')" ).addClass( "ui-nojs" ); + + // pre-find data els + var $dataEls = $elem.find( ":jqmData(role)" ).andSelf().each(function() { + var $this = $( this ), + role = $this.jqmData( "role" ), + theme = $this.jqmData( "theme" ); + + //apply theming and markup modifications to page,header,content,footer + if ( role === "header" || role === "footer" ) { + $this.addClass( "ui-bar-" + (theme || $this.parent( ":jqmData(role='page')" ).jqmData( "theme" ) || "a") ); + + // add ARIA role + $this.attr( "role", role === "header" ? "banner" : "contentinfo" ); + + //right,left buttons + var $headeranchors = $this.children( "a" ), + leftbtn = $headeranchors.hasClass( "ui-btn-left" ), + rightbtn = $headeranchors.hasClass( "ui-btn-right" ); + + if ( !leftbtn ) { + leftbtn = $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length; + } + + if ( !rightbtn ) { + rightbtn = $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length; + } + + // auto-add back btn on pages beyond first view + if ( o.addBackBtn && role === "header" && + $( ".ui-page" ).length > 1 && + $elem.jqmData( "url" ) !== $.mobile.path.stripHash( location.hash ) && + !leftbtn && $this.jqmData( "backbtn" ) !== false ) { + + var backBtn = $( ""+ o.backBtnText +"" ).prependTo( $this ); + + //if theme is provided, override default inheritance + if( o.backBtnTheme ){ + backBtn.attr( "data-"+ $.mobile.ns +"theme", o.backBtnTheme ); + } + } + + //page title + $this.children( "h1, h2, h3, h4, h5, h6" ) + .addClass( "ui-title" ) + //regardless of h element number in src, it becomes h1 for the enhanced page + .attr({ "tabindex": "0", "role": "heading", "aria-level": "1" }); + + } else if ( role === "content" ) { + if ( theme ) { + $this.addClass( "ui-body-" + theme ); + } + + // add ARIA role + $this.attr( "role", "main" ); + + } else if ( role === "page" ) { + $this.addClass( "ui-body-" + (theme || "c") ); + } + + switch(role) { + case "header": + case "footer": + case "page": + case "content": + $this.addClass( "ui-" + role ); + break; + case "collapsible": + case "fieldcontain": + case "navbar": + case "listview": + case "dialog": + $this[ role ](); + break; + } + }); + + //enhance form controls + this._enhanceControls(); + + //links in bars, or those with data-role become buttons + $elem.find( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a" ) + .not( ".ui-btn" ) + .not(this.keepNative) + .buttonMarkup(); + + $elem + .find(":jqmData(role='controlgroup')") + .controlgroup(); + + //links within content areas + $elem.find( "a:not(.ui-btn):not(.ui-link-inherit)" ) + .not(this.keepNative) + .addClass( "ui-link" ); + + //fix toolbars + $elem.fixHeaderFooter(); + }, + + _typeAttributeRegex: /\s+type=["']?\w+['"]?/, + + _enhanceControls: function() { + var o = this.options, self = this; + + // degrade inputs to avoid poorly implemented native functionality + this.element.find( "input" ).not(this.keepNative).each(function() { + var type = this.getAttribute( "type" ), + optType = o.degradeInputs[ type ] || "text"; + + if ( o.degradeInputs[ type ] ) { + $( this ).replaceWith( + $( "