[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:
fdardenne
2022-11-15 18:25:12 +01:00
parent 439db9eaeb
commit 4edbe54456
3 changed files with 0 additions and 316 deletions
-34
View File
@@ -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']);
});
});
});