diff options
| author | Géry Debongnie <ged@odoo.com> | 2018-05-18 10:02:04 +0200 |
|---|---|---|
| committer | Géry Debongnie <ged@odoo.com> | 2018-05-23 10:48:36 +0200 |
| commit | d01787c19d4631a1de56f9873586e44ae06318f1 (patch) | |
| tree | d212f930156e4aa076308e3c33aaef4e9c968666 /addons/web/static/src | |
| parent | 4232eb7bcd4dd895b86db728a2b689ae9568f951 (diff) | |
[IMP] web,mail: improve search view for mobile devices
With this commit, we introduce a better screen to manipulate the search
view in a mobile device.
Note: most of this work was initially done by suh-odoo, then was adapted
and moved to community by myself.
task 31464
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/js/chrome/search_menus.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/search_view.js | 34 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome/search_view_mobile.js | 96 | ||||
| -rw-r--r-- | addons/web/static/src/scss/control_panel.scss | 2 | ||||
| -rw-r--r-- | addons/web/static/src/scss/search_view.scss | 128 | ||||
| -rw-r--r-- | addons/web/static/src/scss/search_view_mobile.scss | 88 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 27 |
7 files changed, 307 insertions, 74 deletions
diff --git a/addons/web/static/src/js/chrome/search_menus.js b/addons/web/static/src/js/chrome/search_menus.js index d33cdce6500..a6548b051f4 100644 --- a/addons/web/static/src/js/chrome/search_menus.js +++ b/addons/web/static/src/js/chrome/search_menus.js @@ -1,6 +1,7 @@ odoo.define('web.FavoriteMenu', function (require) { "use strict"; +var config = require('web.config'); var core = require('web.core'); var data_manager = require('web.data_manager'); var pyeval = require('web.pyeval'); @@ -38,6 +39,7 @@ return Widget.extend({ this.action = action; this.action_id = action.id; this.filters = {}; + this.isMobile = config.device.isMobile; _.each(filters, this.add_filter.bind(this)); }, start: function () { @@ -305,6 +307,7 @@ return Widget.extend({ odoo.define('web.FilterMenu', function (require) { "use strict"; +var config = require('web.config'); var search_filters = require('web.search_filters'); var search_inputs = require('web.search_inputs'); var Widget = require('web.Widget'); @@ -333,6 +336,7 @@ return Widget.extend({ }, init: function (parent, filters, fields) { this._super(parent); + this.isMobile = config.device.isMobile; this.filters = filters || []; this.searchview = parent; this.propositions = []; @@ -409,6 +413,7 @@ return Widget.extend({ odoo.define('web.GroupByMenu', function (require) { "use strict"; +var config = require('web.config'); var core = require('web.core'); var search_inputs = require('web.search_inputs'); var Widget = require('web.Widget'); @@ -433,6 +438,7 @@ return Widget.extend({ var self = this; this._super(parent); this.searchview = parent; + this.isMobile = config.device.isMobile; this.groups = groups || []; this.groupableFields = []; var groupable_types = ['many2one', 'char', 'boolean', 'selection', 'date', 'datetime']; diff --git a/addons/web/static/src/js/chrome/search_view.js b/addons/web/static/src/js/chrome/search_view.js index 94087c999b6..8fc3cd73a2b 100644 --- a/addons/web/static/src/js/chrome/search_view.js +++ b/addons/web/static/src/js/chrome/search_view.js @@ -326,18 +326,19 @@ var SearchView = Widget.extend({ .toggleClass('fa-search-plus', !this.visible_filters); var menu_defs = []; this.prepare_search_inputs(); - if (this.$buttons) { + var $buttons = this._getButtonsElement(); + if ($buttons) { if (!this.options.disable_filters) { this.filter_menu = new FilterMenu(this, this.filters, this.fields); - menu_defs.push(this.filter_menu.appendTo(this.$buttons)); + menu_defs.push(this.filter_menu.appendTo($buttons)); } if (!this.options.disable_groupby) { this.groupby_menu = new GroupByMenu(this, this.groupbys, this.fields); - menu_defs.push(this.groupby_menu.appendTo(this.$buttons)); + menu_defs.push(this.groupby_menu.appendTo($buttons)); } if (!this.options.disable_favorites) { this.favorite_menu = new FavoriteMenu(this, this.query, this.dataset.model, this.action, this.favorite_filters); - menu_defs.push(this.favorite_menu.appendTo(this.$buttons)); + menu_defs.push(this.favorite_menu.appendTo($buttons)); } } return $.when.apply($, menu_defs).then(this.set_default_filters.bind(this)); @@ -454,7 +455,7 @@ var SearchView = Widget.extend({ return self.$('.o_searchview_input').val().trim(); }, }); - this.autocomplete.appendTo(this.$el); + this.autocomplete.appendTo(this.$('.o_searchview_input_container')); }, /** * Provide auto-completion result for req.term (an array to `resp`) @@ -528,11 +529,11 @@ var SearchView = Widget.extend({ this.query.each(function (facet) { var f = new FacetView(this, facet); - started.push(f.appendTo(self.$el)); + started.push(f.appendTo(self.$('.o_searchview_input_container'))); self.input_subviews.push(f); }, this); var i = new InputView(this); - started.push(i.appendTo(self.$el)); + started.push(i.appendTo(self.$('.o_searchview_input_container'))); self.input_subviews.push(i); _.each(this.input_subviews, function (childView) { childView.on('focused', self, self.proxy('childFocused')); @@ -540,7 +541,12 @@ var SearchView = Widget.extend({ }); $.when.apply(null, started).then(function () { - _.last(self.input_subviews).$el.focus(); + if (!config.device.isMobile) { + // in mobile mode, we would rathor not focusing manually the + // input, because it opens up the integrated keyboard, which is + // not what you expect when you just selected a filter. + _.last(self.input_subviews).$el.focus(); + } }); }, childFocused: function () { @@ -666,6 +672,18 @@ var SearchView = Widget.extend({ // Private //-------------------------------------------------------------------------- + + /** + * Will return $element where Filters, Group By and Favorite buttons are + * going to be pushed. This method is overriden by the mobile search view + * to add these buttons somewhere else in the dom. + * + * @private + * @returns {jQueryElement} + */ + _getButtonsElement: function () { + return this.$buttons; + }, /** * Processes a fieldsView in place. In particular, parses its arch. * diff --git a/addons/web/static/src/js/chrome/search_view_mobile.js b/addons/web/static/src/js/chrome/search_view_mobile.js new file mode 100644 index 00000000000..852a65c0a37 --- /dev/null +++ b/addons/web/static/src/js/chrome/search_view_mobile.js @@ -0,0 +1,96 @@ + odoo.define('web.SearchViewMobile', function (require) { +"use strict"; + +var config = require('web.config'); +var SearchView = require('web.SearchView'); + +if (!config.device.isMobile) { + return; +} + +SearchView.include({ + template:'SearchViewMobile', + events:_.extend({}, SearchView.prototype.events, { + 'click .o_mobile_search_close, .o_mobile_search_show_result, .o_enable_searchview': '_toggleMobileSearchView', + 'click': '_onOpenMobileSearchView', + 'click .o_mobile_search_clear_facets': '_onEmptyAll', + 'show.bs.dropdown .o_mobile_search_filter .o_dropdown': '_onDropdownToggle', + 'hide.bs.dropdown .o_mobile_search_filter .o_dropdown': '_onDropdownToggle', + }), + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @override + */ + renderFacets: function () { + this._super.apply(this, arguments); + this.$('.o_mobile_search_clear_facets') + .toggleClass('o_hidden', !this.query.length); + }, + /** + * @override + */ + toggle_visibility: function (is_visible) { + // Do not do anything, toggling visibility of searchview is handled + // explicitly for mobile + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _getButtonsElement: function () { + return this.$('.o_mobile_search_filter'); + }, + /** + * Toggle mobile search view screen + * + * @private + */ + _toggleMobileSearchView: function () { + this.$('.o_enable_searchview').toggleClass('btn-default', !!this.query.length); + this.$('.o_mobile_search').toggleClass('o_hidden'); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * Toggle the little arrow in main buttons + * + * @private + * @param {BootstrapEvent} ev + */ + _onDropdownToggle: function (ev) { + $(ev.currentTarget).find('.fa-chevron-right').toggleClass('fa-chevron-down'); + }, + /** + * Clears all filters from the search view + * + * @private + * @param {MouseEvent} event + */ + _onEmptyAll: function () { + this.query.reset(); + }, + /** + * Open the mobile search view screen + * + * @private + * @param {MouseEvent} ev + */ + _onOpenMobileSearchView: function (ev) { + if (ev.target === this.el) { + this._toggleMobileSearchView(); + } + }, +}); + +});
\ No newline at end of file diff --git a/addons/web/static/src/scss/control_panel.scss b/addons/web/static/src/scss/control_panel.scss index f883631c713..ef94b4c0f17 100644 --- a/addons/web/static/src/scss/control_panel.scss +++ b/addons/web/static/src/scss/control_panel.scss @@ -30,9 +30,9 @@ } .btn.o_enable_searchview { - width: 10%; margin-left: 2%; padding: 0px; + background: white; } > .o_cp_left { diff --git a/addons/web/static/src/scss/search_view.scss b/addons/web/static/src/scss/search_view.scss index f2b0f7fd14f..be6cb0b3f5b 100644 --- a/addons/web/static/src/scss/search_view.scss +++ b/addons/web/static/src/scss/search_view.scss @@ -5,84 +5,90 @@ } .o_searchview { - @include o-flex-display; - @include o-flex-flow(row, wrap); @include o-align-items(flex-end); position: relative; padding: 0 20px 1px 0; - .o_searchview_facet { - $o-searchview-facet-remove-width: 18px; + .o_searchview_more { + font-size: 16px; + cursor: pointer; + } - @include o-flex(0, 0, auto); - max-width: 100%; + .o_searchview_input_container { @include o-flex-display; - position: relative; - margin: 1px 3px 0 0; + @include o-flex-flow(row, wrap); - .o_searchview_facet_label { + .o_searchview_facet { + $o-searchview-facet-remove-width: 18px; @include o-flex(0, 0, auto); - @include o-text-overflow; - padding: 0 3px; - color: white; - + max-width: 100%; @include o-flex-display; - @include o-align-items(center); - } + position: relative; + margin: 1px 3px 0 0; - .o_facet_values { - padding: 0 $o-searchview-facet-remove-width 0 5px; - .o_facet_values_sep { - font-style: italic; + .o_searchview_facet_label { + @include o-flex(0, 0, auto); + @include o-text-overflow; + padding: 0 3px; + color: white; + + @include o-flex-display; + @include o-align-items(center); + } + + .o_facet_values { + padding: 0 $o-searchview-facet-remove-width 0 5px; + .o_facet_values_sep { + font-style: italic; + } + } + .o_facet_remove { + @include o-flex(0, 0, auto); + @include o-flex-display; + @include o-justify-content(center); + @include o-align-items(center); + @include o-position-absolute(0, 0, 0); + width: $o-searchview-facet-remove-width; + cursor: pointer; } } - .o_facet_remove { - @include o-flex(0, 0, auto); - @include o-flex-display; - @include o-justify-content(center); - @include o-align-items(center); - @include o-position-absolute(0, 0, 0); - width: $o-searchview-facet-remove-width; - cursor: pointer; + .o_searchview_input { + width: 100px; + @include o-flex(1, 0, auto); } - } - - .o_searchview_input { - width: 100px; - @include o-flex(1, 0, auto); - } - .o_searchview_more { - font-size: 16px; - cursor: pointer; - } + .o_searchview_more { + font-size: 16px; + cursor: pointer; + } - .o_searchview_autocomplete { - @include o-position-absolute(100%, $left: auto); - width: 100%; + .o_searchview_autocomplete { + @include o-position-absolute(100%, $left: auto); + width: 100%; - li { - padding-left: 25px; - position: relative; - &.o-indent { - padding-left: 50px; - } - a { - display: inline-block; - padding-left: 0px; - padding-right: 0px; - &:hover { - background-color: inherit; - } - &.o-expand, &.o-expanded { // caret - @include o-position-absolute($left: 6px); - padding: 3px; - } - &.o-expand:before { - @include o-caret-right; + li { + padding-left: 25px; + position: relative; + &.o-indent { + padding-left: 50px; } - &.o-expanded:before { - @include o-caret-down; + a { + display: inline-block; + padding-left: 0px; + padding-right: 0px; + &:hover { + background-color: inherit; + } + &.o-expand, &.o-expanded { // caret + @include o-position-absolute($left: 6px); + padding: 3px; + } + &.o-expand:before { + @include o-caret-right; + } + &.o-expanded:before { + @include o-caret-down; + } } } } diff --git a/addons/web/static/src/scss/search_view_mobile.scss b/addons/web/static/src/scss/search_view_mobile.scss new file mode 100644 index 00000000000..2f0a3c3fc90 --- /dev/null +++ b/addons/web/static/src/scss/search_view_mobile.scss @@ -0,0 +1,88 @@ +.o_web_client.o_touch_device { + .o_mobile_search { + position: fixed; + top: 0; + left: 0; + bottom: 0; + padding: 0; + width: 100%; + background-color: white; + z-index: 1000; + overflow: auto; + .o_mobile_search_header { + height: 46px; + margin-bottom: 10px; + width: 100%; + background-color: $o-brand-primary; + color: white; + span:active { + background-color: darken($o-brand-primary, 10%); + } + } + .o_searchview_input_container { + display: flex; + padding: 15px 20px 0 20px; + position: relative; + .o_searchview_input { + width: 100%; + margin-bottom: 15px; + border-bottom: 1px solid $o-brand-secondary; + } + .o_searchview_facet { + border-radius: 10px; + display: inline-flex; + order:1; + .o_searchview_facet_label { + border-radius: 2em 0em 0em 2em; + } + } + .o_searchview_autocomplete { + top:100%; + > li { + margin: 5px 0px; + } + } + } + .o_mobile_search_filter { + padding-bottom: 15%; + .o_dropdown { + width: 100%; + margin: 15px 5px 0px 5px; + border: solid 1px darken($gray-lighter, 20%); + + } + .o_dropdown_toggler_btn { + width: 100%; + text-align: left; + } + + // We disable the backdrop in this case because it prevents any + // interaction outside of a dropdown while it is open. + .dropdown-backdrop { + z-index: -1; + } + ul { + position: relative; + width: 100%; + box-shadow: none; + border: none; + color: $gray-light; + .divider { + margin: 0px; + } + > li > a { + padding: 10px 26px; + } + } + } + .o_mobile_search_show_result { + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 15px; + font-size: 17px; + z-index: 1000; + } + } +}
\ No newline at end of file diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 20fee925a0f..0debc65dc54 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -1013,7 +1013,26 @@ </div> <div t-name="SearchView" class="o_searchview"> <span class="o_searchview_more fa" title="Advanced Search..."/> + <div class="o_searchview_input_container"/> </div> +<t t-name="SearchViewMobile"> + <div class="o_searchview"> + <button class="o_enable_searchview btn btn-sm fa fa-search"/> + <div class="o_mobile_search o_hidden"> + <div class="o_mobile_search_header"> + <span class="o_mobile_search_close pull-left mt16 mb16 mr8 ml16"> + <i class="fa fa-arrow-left"/> + <strong class="pull-right ml8">FILTER</strong> + </span> + <span class="pull-right o_mobile_search_clear_facets mt16 mr16">CLEAR</span> + </div> + <div class="o_searchview_input_container"/> + <div class="o_mobile_search_filter o_search_options mb8 mt8 ml16 mr16"/> + <div class="btn btn-primary o_mobile_search_show_result">SEE RESULT</div> + </div> + </div> +</t> + <input t-name="SearchView.InputView" type="text" class="o_searchview_input" accesskey="Q" placeholder="Search..."/> <div t-name="SearchView.FacetView" tabindex="0" class="o_searchview_facet"> <span t-if="widget.model.has('icon')" t-att-class="'fa ' + widget.model.get('icon') + ' o_searchview_facet_label'"/> @@ -1031,7 +1050,7 @@ </t> <div t-name="SearchView.FilterMenu" class="btn-group o_dropdown"> <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> - <span class="fa fa-filter"/> Filters <span class="caret"/> + <span class="fa fa-filter"/> Filters <span t-attf-class="#{widget.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret'}"/> </button> <ul class="dropdown-menu o_filters_menu" role="menu"> <li class="o_add_filter o_closed_menu"> @@ -1141,9 +1160,9 @@ </option> </select> </t> -<div t-name="SearchView.GroupByMenu" class="btn-group hidden-xs o_dropdown"> +<div t-name="SearchView.GroupByMenu" class="btn-group o_dropdown"> <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> - <span class="fa fa-bars"/> Group By <span class="caret"/> + <span class="fa fa-bars"/> Group By <span t-attf-class="#{widget.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret'}"/> </button> <ul class="dropdown-menu o_group_by_menu" role="menu"> <li class="divider"/> @@ -1164,7 +1183,7 @@ </t> <div t-name="SearchView.FavoriteMenu" class="btn-group o_dropdown"> <button class="o_dropdown_toggler_btn btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" tabindex="-1"> - <span class="fa fa-star"/> Favorites <span class="caret"/> + <span class="fa fa-star"/> Favorites <span t-attf-class="#{widget.isMobile ? 'fa fa-chevron-right pull-right mt4' : 'caret'}"/> </button> <ul class="dropdown-menu o_favorites_menu" role="menu"> <li class="divider user_filter"/> |
