[ADD] basic loading of default values in faceted search view
bzr revid: xmo@openerp.com-20120320102846-g2ymabvt4qc4bwzg
This commit is contained in:
parent
16fddf9207
commit
b39712cf3d
34
.bzrignore
34
.bzrignore
|
@ -1,23 +1,13 @@
|
|||
*.pyc
|
||||
.*.swp
|
||||
.bzrignore
|
||||
openerp/addons/*
|
||||
openerp/filestore*
|
||||
.Python
|
||||
include
|
||||
lib
|
||||
bin/activate
|
||||
bin/activate_this.py
|
||||
bin/easy_install
|
||||
bin/easy_install-2.6
|
||||
bin/pip
|
||||
bin/python
|
||||
bin/python2.6
|
||||
*.pyc
|
||||
*.pyo
|
||||
.*
|
||||
*.egg-info
|
||||
*.orig
|
||||
build/
|
||||
bin/yolk
|
||||
bin/pil*.py
|
||||
.project
|
||||
.pydevproject
|
||||
.settings
|
||||
RE:^bin/
|
||||
RE:^dist/
|
||||
RE:^include/
|
||||
|
||||
RE:^share/
|
||||
RE:^man/
|
||||
RE:^lib/
|
||||
|
||||
RE:^doc/_build/
|
||||
|
|
|
@ -314,6 +314,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
|
|||
}
|
||||
},
|
||||
on_loaded: function(data) {
|
||||
var self = this;
|
||||
this.fields_view = data.fields_view;
|
||||
if (data.fields_view.type !== 'search' ||
|
||||
data.fields_view.arch.tag !== 'search') {
|
||||
|
@ -322,12 +323,16 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
|
|||
data.fields_view.type, data.fields_view.arch.tag));
|
||||
}
|
||||
|
||||
var self = this,
|
||||
lines = this.make_widgets(
|
||||
this.make_widgets(
|
||||
data.fields_view['arch'].children,
|
||||
data.fields_view.fields);
|
||||
|
||||
return this.ready.resolve().promise();
|
||||
// load defaults
|
||||
return $.when.apply(null, _(this.inputs).invoke('facet_for_defaults', this.defaults))
|
||||
.then(function () {
|
||||
self.vs.searchQuery.reset(_(arguments).compact());
|
||||
self.ready.resolve();
|
||||
});
|
||||
|
||||
// for extended search view
|
||||
var ext = new openerp.web.search.ExtendedSearch(this, this.model);
|
||||
|
@ -730,10 +735,6 @@ openerp.web.search.Widget = openerp.web.OldWidget.extend( /** @lends openerp.web
|
|||
destroy: function () {
|
||||
delete this.view;
|
||||
this._super();
|
||||
},
|
||||
render: function (defaults) {
|
||||
// FIXME
|
||||
return this._super(_.extend(this, {defaults: defaults}));
|
||||
}
|
||||
});
|
||||
openerp.web.search.add_expand_listener = function($root) {
|
||||
|
@ -781,11 +782,29 @@ openerp.web.search.Input = openerp.web.search.Widget.extend( /** @lends openerp.
|
|||
* label, value prefixed with an object with keys type=section and label
|
||||
*
|
||||
* @param {String} value value to complete
|
||||
* @returns {jQuery.Deferred<null|Object>}
|
||||
* @returns {jQuery.Deferred<null|Array>}
|
||||
*/
|
||||
complete: function (value) {
|
||||
return $.when(null)
|
||||
},
|
||||
/**
|
||||
* Returns a VS.model.SearchFacet instance for the provided defaults if
|
||||
* they apply to this widget, or null if they don't.
|
||||
*
|
||||
* This default implementation will try calling
|
||||
* :js:func:`openerp.web.search.Input#facet_for` if the widget's name
|
||||
* matches the input key
|
||||
*
|
||||
* @param {Object} defaults
|
||||
* @returns {jQuery.Deferred<null|Object>}
|
||||
*/
|
||||
facet_for_defaults: function (defaults) {
|
||||
if (!this.attrs ||
|
||||
!(this.attrs.name in defaults && defaults[this.attrs.name])) {
|
||||
return $.when(null);
|
||||
}
|
||||
return this.facet_for(defaults[this.attrs.name]);
|
||||
},
|
||||
get_context: function () {
|
||||
throw new Error(
|
||||
"get_context not implemented for widget " + this.attrs.type);
|
||||
|
@ -879,26 +898,18 @@ openerp.web.search.Filter = openerp.web.search.Input.extend(/** @lends openerp.w
|
|||
self.view.do_toggle_filter(self);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Returns whether the filter is currently enabled (in use) or not.
|
||||
*
|
||||
* @returns a boolean
|
||||
*/
|
||||
is_enabled:function () {
|
||||
return this.$element.hasClass('enabled');
|
||||
},
|
||||
/**
|
||||
* If the filter is present in the defaults (and has a truthy value),
|
||||
* enable the filter.
|
||||
*
|
||||
* @param {Object} defaults the search view's default values
|
||||
*/
|
||||
render: function (defaults) {
|
||||
if (this.attrs.name && defaults[this.attrs.name]) {
|
||||
this.classes.push('enabled');
|
||||
this.view.do_toggle_filter(this, true);
|
||||
}
|
||||
return this._super(defaults);
|
||||
facet_for: function (value) {
|
||||
return $.when(new VS.model.SearchFacet({
|
||||
category: this.attrs.string || this.attrs.name,
|
||||
value: 'true',
|
||||
app: this.view.vs
|
||||
}));
|
||||
},
|
||||
get_context: function () {
|
||||
if (!this.is_enabled()) {
|
||||
|
@ -939,6 +950,13 @@ openerp.web.search.Field = openerp.web.search.Input.extend( /** @lends openerp.w
|
|||
})), view);
|
||||
this.make_id('input', field.type, this.attrs.name);
|
||||
},
|
||||
facet_for: function (value) {
|
||||
return $.when(new VS.model.SearchFacet({
|
||||
category: this.attrs.name,
|
||||
value: String(value),
|
||||
app: this.view.vs
|
||||
}));
|
||||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
this.filters.start();
|
||||
|
@ -1096,6 +1114,17 @@ openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends o
|
|||
return $.when.apply(null,
|
||||
[{type: 'section', label: this.attrs.string}].concat(results));
|
||||
},
|
||||
facet_for: function (value) {
|
||||
var match = _(this.attrs.selection).detect(function (sel) {
|
||||
return sel[0] === value;
|
||||
});
|
||||
if (!match) { return $.when(null); }
|
||||
return $.when(new VS.model.SearchFacet({
|
||||
category: this.attrs.name,
|
||||
value: match[1],
|
||||
app: this.view.vs
|
||||
}));
|
||||
},
|
||||
get_value: function () {
|
||||
var index = parseInt(this.$element.val(), 10);
|
||||
if (isNaN(index)) { return null; }
|
||||
|
@ -1103,20 +1132,6 @@ openerp.web.search.SelectionField = openerp.web.search.Field.extend(/** @lends o
|
|||
if (value === false) { return null; }
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* The selection field needs a default ``false`` value in case none is
|
||||
* provided, so that selector options with a ``false`` value (convention
|
||||
* for explicitly empty options) get selected by default rather than the
|
||||
* first (value-holding) option in the selection.
|
||||
*
|
||||
* @param {Object} defaults search default values
|
||||
*/
|
||||
render: function (defaults) {
|
||||
if (!defaults[this.attrs.name]) {
|
||||
defaults[this.attrs.name] = false;
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
clear: function () {
|
||||
var self = this, d = $.Deferred(), selection = this.attrs.selection;
|
||||
for(var index=0; index<selection.length; ++index) {
|
||||
|
@ -1146,23 +1161,6 @@ openerp.web.search.BooleanField = openerp.web.search.SelectionField.extend(/** @
|
|||
['false', _t("No")]
|
||||
];
|
||||
},
|
||||
/**
|
||||
* Search defaults likely to be boolean values (for a boolean field).
|
||||
*
|
||||
* In the HTML, we only want/get strings, and our strings here are ``true``
|
||||
* and ``false``, so ensure we use precisely those by truth-testing the
|
||||
* default value (iif there is one in the view's defaults).
|
||||
*
|
||||
* @param {Object} defaults default values for this search view
|
||||
* @returns {String} rendered boolean field
|
||||
*/
|
||||
render: function (defaults) {
|
||||
var name = this.attrs.name;
|
||||
if (name in defaults) {
|
||||
defaults[name] = defaults[name] ? "true" : "false";
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
get_value: function () {
|
||||
switch (this.$element.val()) {
|
||||
case 'false': return false;
|
||||
|
@ -1242,6 +1240,24 @@ openerp.web.search.ManyToOneField = openerp.web.search.CharField.extend({
|
|||
}));
|
||||
});
|
||||
},
|
||||
facet_for: function (value) {
|
||||
var self = this;
|
||||
if (value instanceof Array) {
|
||||
return $.when(new VS.model.SearchFacet({
|
||||
category: this.attrs.string,
|
||||
value: value[1],
|
||||
app: this.view.vs
|
||||
}));
|
||||
}
|
||||
return new openerp.web.Model(this.attrs.relation)
|
||||
.call('name_get', [value], {}).pipe(function (names) {
|
||||
return new VS.model.SearchFacet({
|
||||
category: self.attrs.string,
|
||||
value: names[0][1],
|
||||
app: self.view.vs
|
||||
});
|
||||
})
|
||||
},
|
||||
start: function () {
|
||||
this._super();
|
||||
this.setup_autocomplete();
|
||||
|
@ -1250,51 +1266,6 @@ openerp.web.search.ManyToOneField = openerp.web.search.CharField.extend({
|
|||
function () { started.resolve(); });
|
||||
return started.promise();
|
||||
},
|
||||
setup_autocomplete: function () {
|
||||
var self = this;
|
||||
this.$element.autocomplete({
|
||||
source: function (req, resp) {
|
||||
if (self.abort_last) {
|
||||
self.abort_last();
|
||||
delete self.abort_last;
|
||||
}
|
||||
self.dataset.name_search(
|
||||
req.term, self.attrs.domain, 'ilike', 8, function (data) {
|
||||
resp(_.map(data, function (result) {
|
||||
return {id: result[0], label: result[1]}
|
||||
}));
|
||||
});
|
||||
self.abort_last = self.dataset.abort_last;
|
||||
},
|
||||
select: function (event, ui) {
|
||||
self.id = ui.item.id;
|
||||
self.name = ui.item.label;
|
||||
},
|
||||
delay: 0
|
||||
})
|
||||
},
|
||||
on_name_get: function (name_get) {
|
||||
if (!name_get.length) {
|
||||
delete this.id;
|
||||
this.got_name.reject();
|
||||
return;
|
||||
}
|
||||
this.name = name_get[0][1];
|
||||
this.got_name.resolve();
|
||||
},
|
||||
render: function (defaults) {
|
||||
if (defaults[this.attrs.name]) {
|
||||
this.id = defaults[this.attrs.name];
|
||||
if (this.id instanceof Array)
|
||||
this.id = this.id[0];
|
||||
// TODO: maybe this should not be completely removed
|
||||
delete defaults[this.attrs.name];
|
||||
this.dataset.name_get([this.id], $.proxy(this, 'on_name_get'));
|
||||
} else {
|
||||
this.got_name.reject();
|
||||
}
|
||||
return this._super(defaults);
|
||||
},
|
||||
make_domain: function (name, operator, value) {
|
||||
if (this.id && this.name) {
|
||||
if (value === this.name) {
|
||||
|
|
|
@ -11,6 +11,8 @@ Contents:
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
search-view
|
||||
|
||||
getting-started
|
||||
production
|
||||
widgets
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
Search View
|
||||
===========
|
||||
|
||||
Loading Defaults
|
||||
----------------
|
||||
|
||||
After loading the view data, the SearchView will call
|
||||
:js:func:`openerp.web.search.Input.facet_for_defaults` with the ``defaults``
|
||||
mapping of key:values (where each key corresponds to an input).
|
||||
|
||||
The default implementation is to check if there is a default value for the
|
||||
current input's name (via :js:attr:`openerp.web.search.Input.attrs.name`) and
|
||||
if there is to convert this value to a :js:class:`VS.models.SearchFacet` by
|
||||
calling :js:func:`openerp.web.search.Input.facet_for`.
|
||||
|
||||
Both methods should return a ``jQuery.Deferred<Null|VS.model.SearchFacet>``.
|
||||
|
||||
There is no built-in (default) implementation of
|
||||
:js:func:`openerp.web.search.Input.facet_for`.
|
||||
|
||||
Providing auto-completion
|
||||
-------------------------
|
||||
|
||||
An important component of the unified search view is the faceted autocompletion
|
||||
pane. In order to provide good user and developer experiences, this pane is
|
||||
pluggable (value-wise): each and every control of the search view can check for
|
||||
(and provide) categorized auto-completions for a given value being typed by
|
||||
the user.
|
||||
|
||||
This is done by implementing :js:func:`openerp.web.search.Input.complete`: the
|
||||
method is provided with a value to complete, and the input must either return
|
||||
a ``jQuery.Deferred<Null>`` or fetch (by returning a ``jQuery.Deferred``) an
|
||||
array of completion values.
|
||||
|
||||
.. todo:: describe the shape of "completion values"?
|
||||
|
||||
Converting to and from facet objects
|
||||
------------------------------------
|
||||
|
||||
Changes
|
||||
-------
|
||||
|
||||
.. todo:: merge in changelog instead
|
||||
|
||||
The displaying of the search view was significantly altered from OpenERP Web
|
||||
6.1 to OpenERP Web 6.2: it went form a form-like appearance (inherited from
|
||||
previous web client versions and ultimately from the GTK client) to a
|
||||
"universal" search input with facets.
|
||||
|
||||
As a result, while the external API used to interact with the search view does
|
||||
not change the internal details — including the interaction between the search
|
||||
view and its widgets — is significantly altered:
|
||||
|
||||
Widgets API
|
||||
+++++++++++
|
||||
|
||||
* :js:func:`openerp.web.search.Widget.render` has been removed
|
||||
* Search field objects are not openerp widgets anymore, their ``start`` is
|
||||
not generally called
|
||||
|
||||
Filters
|
||||
+++++++
|
||||
|
||||
* :js:func:`openerp.web.search.Filter.is_enabled` has been removed
|
||||
|
||||
Many To One
|
||||
+++++++++++
|
||||
|
||||
* Because the autocompletion service is now provided by the search view
|
||||
itself, :js:func:`openerp.web.search.ManyToOneField.setup_autocomplete` has
|
||||
been removed.
|
Loading…
Reference in New Issue