[REM] web: qweb views
QWeb views allowed to render QWeb templates rendered by the server in a view. Today, QWeb views are only used in website to see the hierarchy of their views. The use case of website has now more sense in a client action rather than an extension of a QWeb view. This commit removes this view because it is not used anymore and will probably not find any useful use case in the future. closes odoo/odoo#103477 Related: odoo/upgrade#4016 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -33,14 +33,6 @@ DISPLAY_DATE_FORMATS = {
|
||||
}
|
||||
|
||||
|
||||
class IrActionsActWindowView(models.Model):
|
||||
_inherit = 'ir.actions.act_window.view'
|
||||
|
||||
view_mode = fields.Selection(selection_add=[
|
||||
('qweb', 'QWeb')
|
||||
], ondelete={'qweb': 'cascade'})
|
||||
|
||||
|
||||
class Base(models.AbstractModel):
|
||||
_inherit = 'base'
|
||||
|
||||
@@ -221,32 +213,6 @@ class Base(models.AbstractModel):
|
||||
|
||||
return records_values
|
||||
|
||||
##### qweb view hooks #####
|
||||
@api.model
|
||||
def qweb_render_view(self, view_id, domain):
|
||||
assert view_id
|
||||
return self.env['ir.qweb']._render(
|
||||
view_id,
|
||||
{
|
||||
'model': self,
|
||||
'domain': domain,
|
||||
# not necessarily necessary as env is already part of the
|
||||
# non-minimal qcontext
|
||||
'context': self.env.context,
|
||||
'records': lazy(self.search, domain),
|
||||
})
|
||||
|
||||
@api.model
|
||||
def _get_view(self, view_id=None, view_type='form', **options):
|
||||
arch, view = super()._get_view(view_id, view_type, **options)
|
||||
# avoid leaking the raw (un-rendered) template, also avoids bloating
|
||||
# the response payload for no reason. Only send the root node,
|
||||
# to send attributes such as `js_class`.
|
||||
if view_type == 'qweb':
|
||||
root = arch
|
||||
arch = etree.Element('qweb', root.attrib)
|
||||
return arch, view
|
||||
|
||||
@api.model
|
||||
def _search_panel_field_image(self, field_name, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/** @odoo-module alias=web.qweb **/
|
||||
|
||||
/**
|
||||
* Client-side implementation of a qweb view.
|
||||
*/
|
||||
|
||||
import core from 'web.core';
|
||||
import AbstractView from '../abstract_view';
|
||||
import AbstractModel from '../abstract_model';
|
||||
import AbstractRenderer from '../abstract_renderer';
|
||||
import AbstractController from '../abstract_controller';
|
||||
import registry from 'web.view_registry';
|
||||
|
||||
var _lt = core._lt;
|
||||
|
||||
/**
|
||||
* model
|
||||
*/
|
||||
var Model = AbstractModel.extend({
|
||||
/**
|
||||
* init
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this._state = {
|
||||
viewId: false,
|
||||
modelName: false,
|
||||
body: '',
|
||||
context: {},
|
||||
domain: [],
|
||||
};
|
||||
},
|
||||
/**
|
||||
* fetches the rendered qweb view
|
||||
*/
|
||||
_fetch: function () {
|
||||
var state = this._state;
|
||||
return this._rpc({
|
||||
model: state.modelName,
|
||||
method: 'qweb_render_view',
|
||||
kwargs: {
|
||||
view_id: state.viewId,
|
||||
domain: state.domain,
|
||||
context: state.context
|
||||
}
|
||||
}).then(function (r) {
|
||||
state.body = r;
|
||||
return state.viewId;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* get
|
||||
*/
|
||||
__get: function () {
|
||||
return this._state;
|
||||
},
|
||||
/**
|
||||
* load
|
||||
*/
|
||||
__load: function (params) {
|
||||
_.extend(this._state, _.pick(params, ['viewId', 'modelName', 'domain', 'context']));
|
||||
|
||||
return this._fetch();
|
||||
},
|
||||
/**
|
||||
* reload
|
||||
*/
|
||||
__reload: function (_id, params) {
|
||||
_.extend(this._state, _.pick(params, ['domain', 'context']));
|
||||
|
||||
return this._fetch();
|
||||
}
|
||||
});
|
||||
/**
|
||||
* renderer
|
||||
*/
|
||||
var Renderer = AbstractRenderer.extend({
|
||||
/**
|
||||
* render
|
||||
*/
|
||||
_render: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
self.$el.html(self.state.body);
|
||||
});
|
||||
}
|
||||
});
|
||||
/**
|
||||
* controller
|
||||
*/
|
||||
var Controller = AbstractController.extend({
|
||||
events: _.extend({}, AbstractController.prototype.events, {
|
||||
'click [type="toggle"]': '_onLazyToggle',
|
||||
'click [type="action"]' : '_onActionClicked',
|
||||
}),
|
||||
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
renderButtons: function ($node) {
|
||||
this.$buttons = $('<nav/>');
|
||||
if ($node) {
|
||||
$node.append(this.$buttons);
|
||||
}
|
||||
},
|
||||
_update: function () {
|
||||
var self = this;
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
// move control panel buttons from the view to the control panel
|
||||
// area
|
||||
var $cp_buttons = self.renderer.$('nav.o_qweb_cp_buttons');
|
||||
$cp_buttons.children().appendTo(self.$buttons.empty());
|
||||
$cp_buttons.remove();
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Lazy toggle. Content is not remembered between unfolds.
|
||||
*/
|
||||
_onLazyToggle: function (e) {
|
||||
// TODO: add support for view (possibly action as well?)
|
||||
var $target = $(e.target);
|
||||
var $t = $target.closest('[data-model]');
|
||||
if (!($target.hasClass('fa-caret-down') || $target.hasClass('fa-caret-right'))) {
|
||||
$target = $t.find('.fa-caret-down, .fa-caret-right');
|
||||
}
|
||||
|
||||
var data = $t.data();
|
||||
if (this._fold($t)) {
|
||||
$target.removeClass('fa-caret-down').addClass('fa-caret-right');
|
||||
return;
|
||||
}
|
||||
|
||||
// NB: $.data() automatically parses json attributes, but does not
|
||||
// automatically parse lone float literals in data-*, so a
|
||||
// data-args (as a json object) is very convenient
|
||||
var args = data.args || _.omit(data, 'model', 'method', 'id');
|
||||
|
||||
return this._rpc({
|
||||
model: data.model,
|
||||
method: data.method,
|
||||
args: data.id ? [data.id] : undefined,
|
||||
kwargs: args // FIXME: context?
|
||||
}).then(function (s) {
|
||||
return $(s);
|
||||
}).then(function ($newcontent) {
|
||||
$t.data('children', $newcontent).after($newcontent);
|
||||
$target.removeClass('fa-caret-right').addClass('fa-caret-down');
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Attempts to fold the parameter, returns whether that happened.
|
||||
*/
|
||||
_fold: function ($el) {
|
||||
var $children = $el.data('children');
|
||||
if (!$children) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
$children.each(function (_i, e) {
|
||||
self._fold($(e));
|
||||
}).remove();
|
||||
$el.removeData('children');
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* view
|
||||
*/
|
||||
var QWebView = AbstractView.extend({
|
||||
display_name: _lt('Freedom View'),
|
||||
icon: 'fa-file-picture-o',
|
||||
viewType: 'qweb',
|
||||
// groupable?
|
||||
enableTimeRangeMenu: true,
|
||||
config: _.extend({}, AbstractView.prototype.config, {
|
||||
Model: Model,
|
||||
Renderer: Renderer,
|
||||
Controller: Controller,
|
||||
}),
|
||||
|
||||
/**
|
||||
* init method
|
||||
*/
|
||||
init: function (viewInfo, params) {
|
||||
this._super.apply(this, arguments);
|
||||
this.loadParams.viewId = viewInfo.view_id;
|
||||
}
|
||||
});
|
||||
|
||||
registry.add('qweb', QWebView);
|
||||
export default {
|
||||
View: QWebView,
|
||||
Controller: Controller,
|
||||
Renderer: Renderer,
|
||||
Model: Model
|
||||
};
|
||||
@@ -1,75 +0,0 @@
|
||||
odoo.define('web.qweb_view_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const utils = require('web.test_utils');
|
||||
const { createWebClient, doAction } = require('@web/../tests/webclient/helpers');
|
||||
const { getFixture } = require("@web/../tests/helpers/utils");
|
||||
|
||||
QUnit.module("Views", {
|
||||
|
||||
}, function () {
|
||||
QUnit.module("QWeb");
|
||||
QUnit.test("basic", async function (assert) {
|
||||
assert.expect(14);
|
||||
|
||||
const serverData = {
|
||||
models: {
|
||||
test: {
|
||||
fields: {},
|
||||
records: [],
|
||||
}
|
||||
},
|
||||
views: {
|
||||
'test,5,qweb': '<div id="xxx"><t t-esc="ok"/></div>',
|
||||
'test,false,search': '<search/>'
|
||||
},
|
||||
};
|
||||
|
||||
const mockRPC = (route, args) => {
|
||||
if (/^\/web\/dataset\/call_kw/.test(route)) {
|
||||
switch (_.str.sprintf('%(model)s.%(method)s', args)) {
|
||||
case 'test.qweb_render_view':
|
||||
assert.step('fetch');
|
||||
assert.equal(args.kwargs.view_id, 5);
|
||||
return Promise.resolve(
|
||||
'<div>foo' +
|
||||
'<div data-model="test" data-method="wheee" data-id="42" data-other="5">' +
|
||||
'<a type="toggle" class="fa fa-caret-right">Unfold</a>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
case 'test.wheee':
|
||||
assert.step('unfold');
|
||||
assert.deepEqual(args.args, [42]);
|
||||
assert.deepEqual(args.kwargs, { other: 5, context: {} });
|
||||
return Promise.resolve('<div id="sub">ok</div>');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const target = getFixture();
|
||||
const webClient = await createWebClient({ serverData, mockRPC});
|
||||
|
||||
let resolved = false;
|
||||
const doActionProm = doAction(webClient, {
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'qweb']],
|
||||
res_model: 'test',
|
||||
}).then(function () { resolved = true; });
|
||||
assert.ok(!resolved, "Action cannot be resolved synchronously");
|
||||
|
||||
await doActionProm;
|
||||
assert.ok(resolved, "Action is resolved asynchronously");
|
||||
|
||||
const content = target.querySelector('.o_content');
|
||||
assert.ok(/^\s*foo/.test(content.textContent));
|
||||
await utils.dom.click(content.querySelector('[type=toggle]'));
|
||||
assert.equal(content.querySelector('div#sub').textContent, 'ok', 'should have unfolded the sub-item');
|
||||
await utils.dom.click(content.querySelector('[type=toggle]'));
|
||||
assert.containsNone(content, "div#sub");
|
||||
await utils.dom.click(content.querySelector('[type=toggle]'));
|
||||
|
||||
assert.verifySteps(['fetch', 'unfold', 'unfold']);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user