diff options
| author | Xavier Morel <xmo@odoo.com> | 2018-10-26 14:32:46 +0000 |
|---|---|---|
| committer | Xavier Morel <xmo@odoo.com> | 2019-01-29 10:22:18 +0000 |
| commit | 58e0c88eced65fe8cc8929d5ea7350f817a5a90e (patch) | |
| tree | f1256f81ad9108239426d1f9aa4f4f5f0042fdc3 /addons/web/static/src/js/views/qweb | |
| parent | 1d1d5ed7adfdf8352ddb960293c6c07cd51af51d (diff) | |
[ADD] web: server-side-rendered qweb templates as views
Diffstat (limited to 'addons/web/static/src/js/views/qweb')
| -rw-r--r-- | addons/web/static/src/js/views/qweb/qweb_view.js | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/addons/web/static/src/js/views/qweb/qweb_view.js b/addons/web/static/src/js/views/qweb/qweb_view.js new file mode 100644 index 00000000000..9e79ecf19d2 --- /dev/null +++ b/addons/web/static/src/js/views/qweb/qweb_view.js @@ -0,0 +1,202 @@ +/** + * Client-side implementation of a qweb view. + */ +odoo.define('web.qweb', function (require) { +"use strict"; + +var core = require('web.core'); +var AbstractView = require('web.AbstractView'); +var AbstractModel = require('web.AbstractModel'); +var AbstractRenderer = require('web.AbstractRenderer'); +var AbstractController = require('web.AbstractController'); +var registry = require('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) { + // FIXME: update this._state or something? + 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', + }), + + init: function () { + this._super.apply(this, arguments); + this._$buttons = $('<nav>').on('click', '[type="action"]', this.proxy('_onActionClicked')); + }, + + renderButtons: function ($node) { + this._super($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: { + 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); +return { + View: QWebView, + Controller: Controller, + Renderer: Renderer, + Model: Model +}; +}); |
