summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
authorged-odoo <ged@odoo.com>2014-06-12 16:27:11 +0200
committerged-odoo <ged@odoo.com>2014-06-12 16:27:11 +0200
commit74168c4e9d1527cfdd62aae5e37ca3bfd4f584c3 (patch)
tree6f11de511ecebc37aa539be6eb99ee8e7085e7ab /addons/web/static
parent64b78b34d6427a4756dd652b21ab24c291a0110e (diff)
parentc73736694e7f99cbd5052de278c88c9efd160add (diff)
Merge pull request #272 from odoo-dev/master-inline-searchview-ged
[MERGP] Inline Searchview This task split the searchview in two parts: SearchView and SearchViewDrawer. The drawer is displayed inside the main view and the searchview stays in place. It also changes the scrolling behavior of the web client: the main view area can scroll without affecting the UI (so the various menus stays in place) Because of this, other large changes have been made: the drawer has been redesigned, the Custom Filter widget has been split in two (Custom Report and SaveCurrentFilter), the main view is now scrollable, so the UI stays in place and only the view can change The text 'Group By...' has been changed into 'Group By' (most addons had to be modified) bootstrap classes are used when it makes sense (for example, badge) the left menu is also scrollable (separately from the main view) It is likely that some stupid bugs have been introduced. Please don't hurt me.
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/css/base.css257
-rw-r--r--addons/web/static/src/css/base.sass441
-rw-r--r--addons/web/static/src/js/search.js434
-rw-r--r--addons/web/static/src/js/view_form.js6
-rw-r--r--addons/web/static/src/js/views.js10
-rw-r--r--addons/web/static/src/xml/base.xml80
-rw-r--r--addons/web/static/test/search.js51
7 files changed, 720 insertions, 559 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index f664baf5319..b234e2738df 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -1,4 +1,4 @@
-@charset "utf-8";
+@charset "UTF-8";
@font-face {
font-family: "mnmliconsRegular";
src: url("/web/static/src/font/mnmliconsv21-webfont.eot") format("eot");
@@ -994,19 +994,22 @@
background: #f0eeee;
border-right: 1px solid #afafb6;
text-shadow: none;
- padding-bottom: 16px;
}
-.openerp a.oe_logo {
- position: relative;
+.openerp .oe_leftbar > div {
+ height: 100%;
+ display: table;
width: 220px;
- display: block;
+ position: relative;
+}
+.openerp .oe_leftbar > div a.oe_logo {
+ display: table-row;
text-align: center;
}
-.openerp a.oe_logo img {
+.openerp .oe_leftbar > div a.oe_logo img {
margin: 14px 0;
border: 0;
}
-.openerp a.oe_logo .oe_logo_edit {
+.openerp .oe_leftbar > div a.oe_logo .oe_logo_edit {
margin: 14px 0;
position: absolute;
top: 1px;
@@ -1021,22 +1024,36 @@
-ms-box-sizing: border-box;
box-sizing: border-box;
}
-.openerp a.oe_logo:hover .oe_logo_edit_admin {
+.openerp .oe_leftbar > div a.oe_logo:hover .oe_logo_edit_admin {
display: block;
}
-.openerp .oe_footer {
- position: fixed;
+.openerp .oe_leftbar > div > div {
+ display: table-row;
+ height: 100%;
+}
+.openerp .oe_leftbar > div > div > div {
+ position: relative;
+ height: 100%;
+}
+.openerp .oe_leftbar > div > div > div > div.oe_secondary_menus_container {
+ position: absolute;
+ position: static\9;
+ top: 0;
bottom: 0;
- padding: 4px 0;
+ left: 0;
+ right: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.openerp .oe_leftbar > div .oe_footer {
background: #f0eeee;
- width: 220px;
text-align: center;
}
-.openerp .oe_footer a {
+.openerp .oe_leftbar > div .oe_footer a {
font-weight: bold;
color: black;
}
-.openerp .oe_footer a span {
+.openerp .oe_leftbar > div .oe_footer a span {
color: #a24689;
}
.openerp .oe_secondary_menu_section {
@@ -1140,8 +1157,26 @@
color: #7c7bad;
}
.openerp .oe_application > div {
+ position: relative;
height: 100%;
}
+.openerp .oe_application > div > .oe_view_manager > .oe_view_manager_wrapper {
+ display: table-row;
+ height: 100%;
+}
+.openerp .oe_application > div > .oe_view_manager > .oe_view_manager_wrapper > div {
+ position: relative;
+ height: 100%;
+}
+.openerp .oe_application > div > .oe_view_manager > .oe_view_manager_wrapper > div > .oe_view_manager_body {
+ position: absolute;
+ position: static\9;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow: auto;
+}
.openerp .oe_application .oe_breadcrumb_item:not(:last-child) {
max-width: 7em;
white-space: nowrap;
@@ -1157,11 +1192,8 @@
height: inherit;
width: 100%;
}
-.openerp .oe_view_manager .oe_view_manager_body {
- height: inherit;
-}
.openerp .oe_view_manager .oe_view_manager_view_kanban:not(:empty) {
- height: inherit;
+ height: 100%;
}
.openerp .oe_view_manager[data-view-type=kanban] .oe_view_manager_body {
display: table-row;
@@ -1381,7 +1413,7 @@
float: right;
padding: 1px 0;
line-height: 18px;
- width: 400px;
+ min-width: 400px;
border: 1px solid #ababab;
background: white;
-moz-border-radius: 13px;
@@ -1556,59 +1588,64 @@
-webkit-border-radius: 2px;
border-radius: 2px;
}
-.openerp .oe_searchview.oe_searchview_open_drawer .oe_searchview_drawer {
- display: block;
+.openerp .oe_searchview_drawer_container {
+ overflow: auto;
}
-.openerp .oe_searchview .oe_searchview_drawer {
+.openerp .oe_searchview_drawer {
+ display: none;
+ width: 100%;
cursor: default;
- position: absolute;
- z-index: 2;
- margin-top: 4px;
- top: 100%;
- right: -1px;
- background-color: white;
- min-width: 100%;
display: none;
- border: 1px solid #afafb6;
+ overflow: hidden;
+ border-bottom: 1px solid #afafb6;
text-align: left;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- border-radius: 4px;
- -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
- -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
+ padding: 8px 0;
}
-.openerp .oe_searchview .oe_searchview_drawer > div {
- border-top: 1px solid #cccccc;
- margin: 0;
- padding: 8px;
+.openerp .oe_searchview_drawer .badge {
+ font-size: 12px;
+ line-height: 12px;
}
-.openerp .oe_searchview .oe_searchview_drawer > div:first-child {
- border-top: none;
- margin: 0;
+.openerp .oe_searchview_drawer > div:first-child {
+ border: none;
+ padding-left: 0;
+}
+.openerp .oe_searchview_drawer > div:first-child li:hover:not(.badge) {
+ background-color: #f0f0fa;
+}
+.openerp .oe_searchview_drawer .col-md-5 {
+ padding-left: 0;
}
-.openerp .oe_searchview .oe_searchview_drawer h3 {
- margin: 8px 4px 4px 0px;
+.openerp .oe_searchview_drawer dl {
+ margin-bottom: 0;
+}
+.openerp .oe_searchview_drawer dt {
color: #7c7bad;
font-size: 13px;
+ line-height: 24px;
}
-.openerp .oe_searchview .oe_searchview_drawer h4, .openerp .oe_searchview .oe_searchview_drawer h4 * {
+.openerp .oe_searchview_drawer dd {
+ line-height: 24px;
+ font-size: 13px;
+ padding-top: 3px;
+}
+.openerp .oe_searchview_drawer h4, .openerp .oe_searchview_drawer h4 * {
margin: 0 0 0 2px;
+ padding-left: 20px;
cursor: pointer;
font-weight: normal;
display: inline-block;
}
-.openerp .oe_searchview .oe_searchview_drawer h4:hover, .openerp .oe_searchview .oe_searchview_drawer h4 *:hover {
+.openerp .oe_searchview_drawer h4:hover, .openerp .oe_searchview_drawer h4 *:hover {
background-color: #f0f0fa;
}
-.openerp .oe_searchview .oe_searchview_drawer h4:before {
+.openerp .oe_searchview_drawer h4:before {
content: "▸ ";
color: #a3a3a3;
}
-.openerp .oe_searchview .oe_searchview_drawer button {
+.openerp .oe_searchview_drawer button {
margin: 4px 0;
}
-.openerp .oe_searchview .oe_searchview_drawer .button {
+.openerp .oe_searchview_drawer .button {
border: none;
background: transparent;
padding: 0 2px;
@@ -1619,126 +1656,112 @@
-webkit-border-radius: 0;
border-radius: 0;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section {
- display: table;
- width: 100%;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section > div {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- display: table-cell;
- width: 50%;
- padding-left: 2px;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section ul {
- margin: 0 8px 8px;
+.openerp .oe_searchview_drawer .oe_searchview_section ul {
+ margin: 0 8px;
padding: 0;
list-style: none;
+ display: inline;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section li {
- list-style: none;
- padding: 2px 4px 2px 20px;
- line-height: 14px;
- color: inherit;
+.openerp .oe_searchview_drawer .oe_searchview_section li {
+ display: inline-block;
cursor: pointer;
position: relative;
+ margin-right: 8px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section li.oe_selected:before {
- content: "W";
- font-family: "entypoRegular" !important;
- font-size: 24px;
- font-weight: 300 !important;
- color: #a3a3a3;
- position: absolute;
- left: 4px;
- top: -2px;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_section li:hover {
- background-color: #f0f0fa;
+.openerp .oe_searchview_drawer .oe_searchview_section li > span {
+ display: inline-block;
+ max-width: 250px;
+ text-overflow: ellipsis;
+ vertical-align: bottom;
+ overflow: hidden;
}
-.openerp .oe_searchview .oe_searchview_drawer form {
+.openerp .oe_searchview_drawer form {
margin-left: 12px;
}
-.openerp .oe_searchview .oe_searchview_drawer form p {
+.openerp .oe_searchview_drawer form p {
margin: 4px 0;
line-height: 18px;
}
-.openerp .oe_searchview .oe_searchview_drawer form button {
+.openerp .oe_searchview_drawer form button {
margin: 0 0 8px -3px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom {
- padding: 0 8px 8px 8px;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom div {
- padding: 0;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom div h4 {
- margin: 0;
+.openerp .oe_searchview_drawer .oe_searchview_savefilter form {
+ display: none;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom form {
+.openerp .oe_searchview_drawer .oe_searchview_custom {
display: none;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li {
+.openerp .oe_searchview_drawer .oe_searchview_custom li {
cursor: pointer;
position: relative;
line-height: 14px;
- padding: 2px 4px 2px 20px;
+ margin-right: 0;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li:hover {
- background-color: #f0f0fa;
-}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom li button {
+.openerp .oe_searchview_drawer .oe_searchview_custom li button {
position: absolute;
top: 0;
right: 5px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom label {
+.openerp .oe_searchview_drawer .oe_searchview_custom li a {
+ margin-left: 10px;
+ position: inherit;
+ visibility: hidden;
+ display: inline-block;
+}
+.openerp .oe_searchview_drawer .oe_searchview_custom li span:hover:not(.badge) {
+ background-color: #f0f0fa;
+}
+.openerp .oe_searchview_drawer .oe_searchview_custom li:hover a {
+ visibility: visible;
+}
+.openerp .oe_searchview_drawer .oe_searchview_custom label {
font-weight: normal;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_dashboard form {
+.openerp .oe_searchview_drawer .oe_searchview_dashboard form {
display: none;
margin-top: 2px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced form {
+.openerp .oe_searchview_drawer .oe_searchview_advanced {
+ overflow: auto;
+}
+.openerp .oe_searchview_drawer .oe_searchview_advanced form {
display: none;
margin-top: 8px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced button.oe_add_condition:before {
+.openerp .oe_searchview_drawer .oe_searchview_advanced button.oe_add_condition:before {
content: "Z";
font-family: "entypoRegular" !important;
font-size: 24px;
font-weight: 300 !important;
margin-right: 4px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced ul {
+.openerp .oe_searchview_drawer .oe_searchview_advanced ul {
list-style: none;
padding: 0;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li {
+.openerp .oe_searchview_drawer .oe_searchview_advanced li {
position: relative;
list-style: none;
margin: 0;
white-space: nowrap;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced li:first-child .searchview_extended_prop_or {
+.openerp .oe_searchview_drawer .oe_searchview_advanced li:first-child .searchview_extended_prop_or {
visibility: hidden;
margin-left: -14px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_advanced .searchview_extended_prop_or {
+.openerp .oe_searchview_drawer .oe_searchview_advanced .searchview_extended_prop_or {
opacity: 0.5;
margin-left: -14px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_opened h4:before {
+.openerp .oe_searchview_drawer .oe_opened h4:before {
content: "▾ ";
position: relative;
top: -1px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_opened form {
+.openerp .oe_searchview_drawer .oe_opened form {
display: block;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_delete, .openerp .oe_searchview .oe_searchview_drawer .searchview_extended_delete_prop {
+.openerp .oe_searchview_drawer .oe_searchview_custom_delete, .openerp .oe_searchview_drawer .searchview_extended_delete_prop {
display: inline-block;
width: 12px;
height: 12px;
@@ -1750,7 +1773,7 @@
font-weight: bold;
text-shadow: 0 1px 1px white;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_delete:hover, .openerp .oe_searchview .oe_searchview_drawer .searchview_extended_delete_prop:hover {
+.openerp .oe_searchview_drawer .oe_searchview_custom_delete:hover, .openerp .oe_searchview_drawer .searchview_extended_delete_prop:hover {
text-decoration: none;
color: white;
background: #8786b7;
@@ -1759,16 +1782,16 @@
-webkit-border-radius: 2px;
border-radius: 2px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_delete {
+.openerp .oe_searchview_drawer .oe_searchview_custom_delete {
display: none;
position: absolute;
bottom: 1px;
right: 4px;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_private:hover .oe_searchview_custom_delete, .openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_public:hover .oe_searchview_custom_delete {
+.openerp .oe_searchview_drawer .oe_searchview_custom_private:hover .oe_searchview_custom_delete, .openerp .oe_searchview_drawer .oe_searchview_custom_public:hover .oe_searchview_custom_delete {
display: inline-block;
}
-.openerp .oe_searchview .oe_searchview_drawer .oe_searchview_custom_public:after {
+.openerp .oe_searchview_drawer .oe_searchview_custom_public:after {
content: ",";
font-family: "entypoRegular" !important;
font-size: 22px;
@@ -3423,3 +3446,7 @@ input[type="radio"], input[type="checkbox"] {
background-color: black;
opacity: 0.6;
}
+
+body {
+ overflow: auto;
+}
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 4d952cc47bb..093ebf6cb0b 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -844,40 +844,53 @@ $sheet-padding: 16px
background: #f0eeee
border-right: 1px solid $tag-border
text-shadow: none
- padding-bottom: 16px
- a.oe_logo
- position: relative
- width: 220px
- display: block
- text-align: center
- img
- margin: 14px 0
- border: 0
- .oe_logo_edit
- margin: 14px 0
- position: absolute
- top: 1px
- padding: 4px
- width: 100%
- display: none
- text-align: center
- color: #eee
- background: rgba(37,37,37,0.9)
- @include box-sizing(border)
- &:hover .oe_logo_edit_admin
- display: block
- .oe_footer
- position: fixed
- bottom: 0
- padding: 4px 0
- background: #f0eeee
- width: 220px
- text-align: center
- a
- font-weight: bold
- color: black
- span
- color: #a24689
+ > div
+ height: 100%
+ display: table
+ width: 220px
+ position: relative
+ a.oe_logo
+ display: table-row
+ text-align: center
+ img
+ margin: 14px 0
+ border: 0
+ .oe_logo_edit
+ margin: 14px 0
+ position: absolute
+ top: 1px
+ padding: 4px
+ width: 100%
+ display: none
+ text-align: center
+ color: #eee
+ background: rgba(37,37,37,0.9)
+ @include box-sizing(border)
+ &:hover .oe_logo_edit_admin
+ display: block
+ > div
+ display: table-row
+ height: 100%
+ > div
+ position: relative
+ height: 100%
+ > div.oe_secondary_menus_container
+ position: absolute
+ position: static\9
+ top: 0
+ bottom: 0
+ left: 0
+ right: 0
+ overflow-x: hidden
+ overflow-y: auto
+ .oe_footer
+ background: #f0eeee
+ text-align: center
+ a
+ font-weight: bold
+ color: black
+ span
+ color: #a24689
// }}}
// Webclient.leftbar items {{{
@@ -955,7 +968,25 @@ $sheet-padding: 16px
a
color: $link-color
> div
+ position: relative
height: 100%
+ > .oe_view_manager
+ > .oe_view_manager_wrapper
+ display: table-row
+ height: 100%
+ > div
+ position: relative
+ height: 100%
+ > .oe_view_manager_body
+ position: absolute
+ position: static\9
+ top: 0
+ bottom: 0
+ left: 0
+ right: 0
+ overflow: auto
+
+
.oe_breadcrumb_item:not(:last-child)
max-width: 7em
white-space: nowrap
@@ -970,10 +1001,8 @@ $sheet-padding: 16px
display: table
height: inherit
width: 100%
- .oe_view_manager_body
- height: inherit
.oe_view_manager_view_kanban:not(:empty)
- height: inherit
+ height: 100%
&[data-view-type=kanban]
.oe_view_manager_body
display: table-row
@@ -1150,7 +1179,7 @@ $sheet-padding: 16px
float: right
padding: 1px 0
line-height: 18px
- width: 400px
+ min-width: 400px
border: 1px solid #ababab
background: white
@include radius(13px)
@@ -1277,188 +1306,180 @@ $sheet-padding: 16px
background: #8786b7
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
@include radius(2px)
- &.oe_searchview_open_drawer
- .oe_searchview_drawer
- display: block
- .oe_searchview_drawer
- cursor: default
- position: absolute
- z-index: 2
- // detach drawer from field slightly
- margin-top: 4px
- top: 100%
- right: -1px
- background-color: white
- min-width: 100%
- display: none
- border: 1px solid $tag-border
- text-align: left
- @include radius(4px)
- @include box-shadow(0 1px 4px rgba(0,0,0,0.3))
- > div
- border-top: 1px solid #ccc
- margin: 0
- padding: 8px
- > div:first-child
- border-top: none
- margin: 0
- h3
- margin: 8px 4px 4px 0px
- color: $section-title-color
- font-size: 13px
- h4, h4 *
- margin: 0 0 0 2px
- cursor: pointer
- font-weight: normal
+ .oe_searchview_drawer_container
+ overflow: auto
+ .oe_searchview_drawer
+ display: none
+ width: 100%
+ cursor: default
+ display: none
+ overflow: hidden
+ border-bottom: 1px solid $tag-border
+ text-align: left
+ padding: 8px 0
+ .badge
+ font-size: 12px
+ line-height: 12px
+ > div:first-child
+ border: none
+ padding-left: 0
+ li:hover:not(.badge)
+ background-color: $hover-background
+ .col-md-5
+ padding-left: 0
+ dl
+ margin-bottom: 0
+ dt
+ color: $section-title-color
+ font-size: 13px
+ line-height: 24px
+ dd
+ line-height: 24px
+ font-size: 13px
+ padding-top: 3px
+ h4, h4 *
+ margin: 0 0 0 2px
+ padding-left: 20px
+ cursor: pointer
+ font-weight: normal
+ display: inline-block
+ &:hover
+ background-color: $hover-background
+ h4:before
+ content: "▸ "
+ color: #a3a3a3
+ button
+ margin: 4px 0
+ .button
+ border: none
+ background: transparent
+ padding: 0 2px
+ @include box-shadow(none)
+ @include radius(0)
+ .oe_searchview_section
+ ul
+ margin: 0 8px
+ padding: 0
+ list-style: none
+ display: inline
+ li
display: inline-block
- &:hover
- background-color: $hover-background
- h4:before
- content: "▸ "
- color: #a3a3a3
- button
+ cursor: pointer
+ position: relative
+ margin-right: 8px
+ > span
+ display: inline-block
+ max-width: 250px
+ text-overflow: ellipsis
+ vertical-align: bottom
+ overflow: hidden
+ form
+ margin-left: 12px
+ p
margin: 4px 0
- .button
- border: none
- background: transparent
- padding: 0 2px
- @include box-shadow(none)
- @include radius(0)
- .oe_searchview_section
- display: table
- width: 100%
- > div
- @include box-sizing(border)
- display: table-cell
- width: 50%
- padding-left: 2px // Managed padding-left according bootstrap3
- ul
- margin: 0 8px 8px
- padding: 0
- list-style: none
- li
- list-style: none
- padding: 2px 4px 2px 20px
- line-height: 14px
- color: inherit
- cursor: pointer
- position: relative
- &.oe_selected:before
- content: "W"
- font-family: "entypoRegular" !important
- font-size: 24px
- font-weight: 300 !important
- color: #a3a3a3
- position: absolute
- left: 4px
- top: -2px
- // after oe_selected so background color is not overridden
- &:hover
- background-color: $hover-background
+ line-height: 18px
+ button
+ margin: 0 0 8px -3px // Managed margin-left according bootstrap3
+ .oe_searchview_savefilter
form
- margin-left: 12px
- p
- margin: 4px 0
- line-height: 18px
+ display: none
+ .oe_searchview_custom
+ display: none
+ li
+ cursor: pointer
+ position: relative
+ line-height: 14px
+ margin-right: 0
button
- margin: 0 0 8px -3px // Managed margin-left according bootstrap3
- .oe_searchview_custom
- padding: 0 8px 8px 8px
- div
- padding: 0
- h4
- margin: 0
- form
- display: none
- li
- cursor: pointer
- position: relative
- line-height: 14px
- padding: 2px 4px 2px 20px
- &:hover
- background-color: $hover-background
- button
- position: absolute
- top: 0
- right: 5px
- //Customize for searchview label
- label
- font-weight: normal
- //End of Customize
- .oe_searchview_dashboard
- form
- display: none
- margin-top: 2px
-
- .oe_searchview_advanced
- form
- display: none
- margin-top: 8px
- button.oe_add_condition:before
- content: "Z"
- font-family: "entypoRegular" !important
- font-size: 24px
- font-weight: 300 !important
- margin-right: 4px
- ul
- list-style: none
- padding: 0
- li
- position: relative
- list-style: none
- margin: 0
- white-space: nowrap
- &:first-child .searchview_extended_prop_or
- visibility: hidden
- margin-left: -14px
- .searchview_extended_prop_or
- opacity: 0.5
- margin-left: -14px //Customize 'or' in searchview
- .oe_opened
- h4:before
- content: "▾ "
- position: relative
- top: -1px
- form
- display: block
+ position: absolute
+ top: 0
+ right: 5px
+ a
+ margin-left: 10px
+ position: inherit
+ visibility: hidden
+ display: inline-block
+ span:hover:not(.badge)
+ background-color: $hover-background
+ li:hover a
+ visibility: visible
+ //Customize for searchview label
+ label
+ font-weight: normal
+ //End of Customize
+ .oe_searchview_dashboard
+ form
+ display: none
+ margin-top: 2px
- // delete buttons
- .oe_searchview_custom_delete, .searchview_extended_delete_prop
- display: inline-block
- width: 12px
- height: 12px
- line-height: 12px
- padding: 1px
- color: #8786b7
- line-height: 8px
- text-align: center
- font-weight: bold
- text-shadow: 0 1px 1px white
- &:hover
- text-decoration: none
- color: white
- background: #8786b7
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
- @include radius(2px)
- .oe_searchview_custom_delete
+ .oe_searchview_advanced
+ overflow: auto
+ form
display: none
- position: absolute
- bottom: 1px
- right: 4px
- .oe_searchview_custom_private, .oe_searchview_custom_public
- &:hover
- .oe_searchview_custom_delete
- display: inline-block
- .oe_searchview_custom_public:after
- content: ","
+ margin-top: 8px
+ button.oe_add_condition:before
+ content: "Z"
font-family: "entypoRegular" !important
- font-size: 22px
+ font-size: 24px
font-weight: 300 !important
- margin: 0 0 0 4px
+ margin-right: 4px
+ ul
+ list-style: none
padding: 0
+ li
+ position: relative
+ list-style: none
+ margin: 0
+ white-space: nowrap
+ &:first-child .searchview_extended_prop_or
+ visibility: hidden
+ margin-left: -14px
+ .searchview_extended_prop_or
+ opacity: 0.5
+ margin-left: -14px //Customize 'or' in searchview
+ .oe_opened
+ h4:before
+ content: "▾ "
+ position: relative
+ top: -1px
+ form
+ display: block
-
+ // delete buttons
+ .oe_searchview_custom_delete, .searchview_extended_delete_prop
+ display: inline-block
+ width: 12px
+ height: 12px
+ line-height: 12px
+ padding: 1px
+ color: #8786b7
+ line-height: 8px
+ text-align: center
+ font-weight: bold
+ text-shadow: 0 1px 1px white
+ &:hover
+ text-decoration: none
+ color: white
+ background: #8786b7
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.4)
+ @include radius(2px)
+ .oe_searchview_custom_delete
+ display: none
+ position: absolute
+ bottom: 1px
+ right: 4px
+ .oe_searchview_custom_private, .oe_searchview_custom_public
+ &:hover
+ .oe_searchview_custom_delete
+ display: inline-block
+ .oe_searchview_custom_public:after
+ content: ","
+ font-family: "entypoRegular" !important
+ font-size: 22px
+ font-weight: 300 !important
+ margin: 0 0 0 4px
+ padding: 0
// }}}
// Views Common {{{
.oe_view_nocontent
@@ -2779,5 +2800,7 @@ input[type="radio"], input[type="checkbox"]
opacity: 0.6000000238418579
+body
+ overflow: auto
// au BufWritePost,FileWritePost *.sass :!sass --style expanded --line-numbers <afile> > "%:p:r.css"
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index 832faa4ca62..5653447566b 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -340,7 +340,8 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
},
'click .oe_searchview_unfold_drawer': function (e) {
e.stopImmediatePropagation();
- this.$el.toggleClass('oe_searchview_open_drawer');
+ if (this.drawer)
+ this.drawer.toggle();
},
'keydown .oe_searchview_input, .oe_searchview_facet': function (e) {
switch(e.which) {
@@ -383,19 +384,24 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
this.defaults = defaults || {};
this.has_defaults = !_.isEmpty(this.defaults);
- this.inputs = [];
- this.controls = [];
-
this.headless = this.options.hidden && !this.has_defaults;
this.input_subviews = [];
+ this.view_manager = null;
+ this.$view_manager_header = null;
this.ready = $.Deferred();
+ this.drawer_ready = $.Deferred();
+ this.fields_view_get = $.Deferred();
+ this.drawer = new instance.web.SearchViewDrawer(parent, this);
+
},
start: function() {
var self = this;
var p = this._super();
+ this.$view_manager_header = this.$el.parents(".oe_view_manager_header").first();
+
this.setup_global_completion();
this.query = new my.SearchQuery()
.on('add change reset remove', this.proxy('do_search'))
@@ -416,20 +422,32 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
});
this.alive($.when(load_view)).then(function (r) {
+ self.fields_view_get.resolve(r);
return self.search_view_loaded(r);
}).fail(function () {
self.ready.reject.apply(null, arguments);
});
}
- instance.web.bus.on('click', this, function(ev) {
- if ($(ev.target).parents('.oe_searchview').length === 0) {
- self.$el.removeClass('oe_searchview_open_drawer');
- }
- });
+ var view_manager = this.getParent();
+ while (!(view_manager instanceof instance.web.ViewManager) &&
+ view_manager && view_manager.getParent) {
+ view_manager = view_manager.getParent();
+ }
+ if (view_manager) {
+ this.view_manager = view_manager;
+ view_manager.on('switch_mode', this, function (e) {
+ self.drawer.toggle(e === 'graph');
+ });
+ }
return $.when(p, this.ready);
},
+
+ set_drawer: function (drawer) {
+ this.drawer = drawer;
+ },
+
show: function () {
this.$el.show();
},
@@ -463,14 +481,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
},
/**
- * Sets up thingie where all the mess is put?
- */
- select_for_drawer: function () {
- return _(this.inputs).filter(function (input) {
- return input.in_drawer();
- });
- },
- /**
* Sets up search view's view-wide auto-completion widget
*/
setup_global_completion: function () {
@@ -530,7 +540,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
* @param {Function} resp response callback
*/
complete_global_search: function (req, resp) {
- $.when.apply(null, _(this.inputs).chain()
+ $.when.apply(null, _(this.drawer.inputs).chain()
.filter(function (input) { return input.visible(); })
.invoke('complete', req.term)
.value()).then(function () {
@@ -630,87 +640,6 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
});
},
- /**
- * Builds a list of widget rows (each row is an array of widgets)
- *
- * @param {Array} items a list of nodes to convert to widgets
- * @param {Object} fields a mapping of field names to (ORM) field attributes
- * @param {Object} [group] group to put the new controls in
- */
- make_widgets: function (items, fields, group) {
- if (!group) {
- group = new instance.web.search.Group(
- this, 'q', {attrs: {string: _t("Filters")}});
- }
- var self = this;
- var filters = [];
- _.each(items, function (item) {
- if (filters.length && item.tag !== 'filter') {
- group.push(new instance.web.search.FilterGroup(filters, group));
- filters = [];
- }
-
- switch (item.tag) {
- case 'separator': case 'newline':
- break;
- case 'filter':
- filters.push(new instance.web.search.Filter(item, group));
- break;
- case 'group':
- self.make_widgets(item.children, fields,
- new instance.web.search.Group(group, 'w', item));
- break;
- case 'field':
- var field = this.make_field(
- item, fields[item['attrs'].name], group);
- group.push(field);
- // filters
- self.make_widgets(item.children, fields, group);
- break;
- }
- }, this);
-
- if (filters.length) {
- group.push(new instance.web.search.FilterGroup(filters, this));
- }
- },
- /**
- * Creates a field for the provided field descriptor item (which comes
- * from fields_view_get)
- *
- * @param {Object} item fields_view_get node for the field
- * @param {Object} field fields_get result for the field
- * @param {Object} [parent]
- * @returns instance.web.search.Field
- */
- make_field: function (item, field, parent) {
- // M2O combined with selection widget is pointless and broken in search views,
- // but has been used in the past for unsupported hacks -> ignore it
- if (field.type === "many2one" && item.attrs.widget === "selection"){
- item.attrs.widget = undefined;
- }
- var obj = instance.web.search.fields.get_any( [item.attrs.widget, field.type]);
- if(obj) {
- return new (obj) (item, field, parent || this);
- } else {
- console.group('Unknown field type ' + field.type);
- console.error('View node', item);
- console.info('View field', field);
- console.info('In view', this);
- console.groupEnd();
- return null;
- }
- },
-
- add_common_inputs: function() {
- // add Filters to this.inputs, need view.controls filled
- (new instance.web.search.Filters(this));
- // add custom filters to this.inputs
- this.custom_filters = new instance.web.search.CustomFilters(this);
- // add Advanced to this.inputs
- (new instance.web.search.Advanced(this));
- },
-
search_view_loaded: function(data) {
var self = this;
this.fields_view = data;
@@ -720,24 +649,9 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
"Got non-search view after asking for a search view: type %s, arch root %s",
data.type, data.arch.tag));
}
- this.make_widgets(
- data['arch'].children,
- data.fields);
-
- this.add_common_inputs();
- // build drawer
- var drawer_started = $.when.apply(
- null, _(this.select_for_drawer()).invoke(
- 'appendTo', this.$('.oe_searchview_drawer')));
-
-
- // load defaults
- var defaults_fetched = $.when.apply(null, _(this.inputs).invoke(
- 'facet_for_defaults', this.defaults))
- .then(this.proxy('setup_default_query'));
-
- return $.when(drawer_started, defaults_fetched)
+ return this.drawer_ready
+ .then(this.proxy('setup_default_query'))
.then(function () {
self.trigger("search_view_loaded", data);
self.ready.resolve();
@@ -747,14 +661,14 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
// Hacky implementation of CustomFilters#facet_for_defaults ensure
// CustomFilters will be ready (and CustomFilters#filters will be
// correctly filled) by the time this method executes.
- var custom_filters = this.custom_filters.filters;
+ var custom_filters = this.drawer.custom_filters.filters;
if (!this.options.disable_custom_filters && !_(custom_filters).isEmpty()) {
// Check for any is_default custom filter
var personal_filter = _(custom_filters).find(function (filter) {
return filter.user_id && filter.is_default;
});
if (personal_filter) {
- this.custom_filters.toggle_filter(personal_filter, true);
+ this.drawer.custom_filters.toggle_filter(personal_filter, true);
return;
}
@@ -762,7 +676,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
return !filter.user_id && filter.is_default;
});
if (global_filter) {
- this.custom_filters.toggle_filter(global_filter, true);
+ this.drawer.custom_filters.toggle_filter(global_filter, true);
return;
}
}
@@ -872,9 +786,167 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea
on_invalid: function (errors) {
this.do_notify(_t("Invalid Search"), _t("triggered from search view"));
this.trigger('invalid_search', errors);
+ },
+
+ // The method appendTo is overwrited to be able to insert the drawer anywhere
+ appendTo: function ($searchview_parent, $searchview_drawer_node) {
+ var $searchview_drawer_node = $searchview_drawer_node || $searchview_parent;
+
+ return $.when(
+ this._super($searchview_parent),
+ this.drawer.appendTo($searchview_drawer_node)
+ );
+ },
+
+ destroy: function () {
+ this.drawer.destroy();
+ this.getParent().destroy.call(this);
}
});
+instance.web.SearchViewDrawer = instance.web.Widget.extend({
+ template: "SearchViewDrawer",
+
+ init: function(parent, searchview) {
+ this._super(parent);
+ this.searchview = searchview;
+ this.searchview.set_drawer(this);
+ this.ready = searchview.drawer_ready;
+ this.controls = [];
+ this.inputs = [];
+ },
+
+ toggle: function (visibility) {
+ this.$el.toggle(visibility);
+ var $view_manager_body = this.$el.closest('.oe_view_manager_body');
+ if ($view_manager_body.length) {
+ $view_manager_body.scrollTop(0);
+ }
+ },
+
+ start: function() {
+ var self = this;
+ var filters_ready = this.searchview.fields_view_get
+ .then(this.proxy('prepare_filters'));
+ return $.when(this._super(), filters_ready).then(function () {
+ var defaults = arguments[1][0];
+ self.ready.resolve.apply(null, defaults);
+ });
+ },
+ prepare_filters: function (data) {
+ this.make_widgets(
+ data['arch'].children,
+ data.fields);
+
+ this.add_common_inputs();
+
+ // build drawer
+ var in_drawer = this.select_for_drawer();
+
+ var $first_col = this.$(".col-md-7"),
+ $snd_col = this.$(".col-md-5");
+
+ var add_custom_reports = in_drawer[0].appendTo($first_col),
+ add_filters = in_drawer[1].appendTo($first_col),
+ add_rest = $.when.apply(null, _(in_drawer.slice(2)).invoke('appendTo', $snd_col)),
+ defaults_fetched = $.when.apply(null, _(this.inputs).invoke(
+ 'facet_for_defaults', this.searchview.defaults));
+
+ return $.when(defaults_fetched, add_custom_reports, add_filters, add_rest);
+ },
+ /**
+ * Sets up thingie where all the mess is put?
+ */
+ select_for_drawer: function () {
+ return _(this.inputs).filter(function (input) {
+ return input.in_drawer();
+ });
+ },
+
+ /**
+ * Builds a list of widget rows (each row is an array of widgets)
+ *
+ * @param {Array} items a list of nodes to convert to widgets
+ * @param {Object} fields a mapping of field names to (ORM) field attributes
+ * @param {Object} [group] group to put the new controls in
+ */
+ make_widgets: function (items, fields, group) {
+ if (!group) {
+ group = new instance.web.search.Group(
+ this, 'q', {attrs: {string: _t("Filters")}});
+ }
+ var self = this;
+ var filters = [];
+ _.each(items, function (item) {
+ if (filters.length && item.tag !== 'filter') {
+ group.push(new instance.web.search.FilterGroup(filters, group));
+ filters = [];
+ }
+
+ switch (item.tag) {
+ case 'separator': case 'newline':
+ break;
+ case 'filter':
+ filters.push(new instance.web.search.Filter(item, group));
+ break;
+ case 'group':
+ self.make_widgets(item.children, fields,
+ new instance.web.search.Group(group, 'w', item));
+ break;
+ case 'field':
+ var field = this.make_field(
+ item, fields[item['attrs'].name], group);
+ group.push(field);
+ // filters
+ self.make_widgets(item.children, fields, group);
+ break;
+ }
+ }, this);
+
+ if (filters.length) {
+ group.push(new instance.web.search.FilterGroup(filters, this));
+ }
+ },
+ /**
+ * Creates a field for the provided field descriptor item (which comes
+ * from fields_view_get)
+ *
+ * @param {Object} item fields_view_get node for the field
+ * @param {Object} field fields_get result for the field
+ * @param {Object} [parent]
+ * @returns instance.web.search.Field
+ */
+ make_field: function (item, field, parent) {
+ // M2O combined with selection widget is pointless and broken in search views,
+ // but has been used in the past for unsupported hacks -> ignore it
+ if (field.type === "many2one" && item.attrs.widget === "selection"){
+ item.attrs.widget = undefined;
+ }
+ var obj = instance.web.search.fields.get_any( [item.attrs.widget, field.type]);
+ if(obj) {
+ return new (obj) (item, field, parent || this);
+ } else {
+ console.group('Unknown field type ' + field.type);
+ console.error('View node', item);
+ console.info('View field', field);
+ console.info('In view', this);
+ console.groupEnd();
+ return null;
+ }
+ },
+
+ add_common_inputs: function() {
+ // add custom filters to this.inputs
+ this.custom_filters = new instance.web.search.CustomReports(this);
+ // add Filters to this.inputs, need view.controls filled
+ (new instance.web.search.Filters(this));
+ (new instance.web.search.SaveFilter(this, this.custom_filters));
+ // add Advanced to this.inputs
+ (new instance.web.search.Advanced(this));
+ },
+
+});
+
/**
* Registry of search fields, called by :js:class:`instance.web.SearchView` to
* find and instantiate its field widgets.
@@ -932,9 +1004,10 @@ instance.web.search.Widget = instance.web.Widget.extend( /** @lends instance.web
this._super(parent);
var ancestor = parent;
do {
- this.view = ancestor;
- } while (!(ancestor instanceof instance.web.SearchView)
+ this.drawer = ancestor;
+ } while (!(ancestor instanceof instance.web.SearchViewDrawer)
&& (ancestor = (ancestor.getParent && ancestor.getParent())));
+ this.view = this.drawer.searchview || this.drawer;
}
});
@@ -956,7 +1029,7 @@ instance.web.search.Group = instance.web.search.Widget.extend({
this.name = attrs.string;
this.children = [];
- this.view.controls.push(this);
+ this.drawer.controls.push(this);
},
push: function (input) {
this.children.push(input);
@@ -977,7 +1050,7 @@ instance.web.search.Input = instance.web.search.Widget.extend( /** @lends instan
init: function (parent) {
this._super(parent);
this.load_attrs({});
- this.view.inputs.push(this);
+ this.drawer.inputs.push(this);
},
/**
* Fetch auto-completion values for the widget.
@@ -1088,7 +1161,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
*/
search_change: function () {
var self = this;
- var $filters = this.$('> li').removeClass('oe_selected');
+ var $filters = this.$('> li').removeClass('badge');
var facet = this.view.query.find(_.bind(this.match_facet, this));
if (!facet) { return; }
facet.values.each(function (v) {
@@ -1096,7 +1169,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in
if (i === -1) { return; }
$filters.filter(function () {
return Number($(this).data('index')) === i;
- }).addClass('oe_selected');
+ }).addClass('badge');
});
},
/**
@@ -1628,12 +1701,12 @@ instance.web.search.ManyToOneField = instance.web.search.CharField.extend({
}
});
-instance.web.search.CustomFilters = instance.web.search.Input.extend({
- template: 'SearchView.CustomFilters',
+instance.web.search.CustomReports = instance.web.search.Input.extend({
+ template: 'SearchView.CustomReports',
_in_drawer: true,
init: function () {
this.is_ready = $.Deferred();
- this._super.apply(this, arguments);
+ this._super.apply(this,arguments);
},
start: function () {
var self = this;
@@ -1648,13 +1721,6 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
self.clear_selection();
})
.on('reset', this.proxy('clear_selection'));
- this.$el.on('submit', 'form', this.proxy('save_current'));
- this.$el.on('click', 'input[type=checkbox]', function() {
- $(this).siblings('input[type=checkbox]').prop('checked', false);
- });
- this.$el.on('click', 'h4', function () {
- self.$el.toggleClass('oe_opened');
- });
return this.model.call('get_filters', [this.view.model])
.then(this.proxy('set_filters'))
.done(function () { self.is_ready.resolve(); })
@@ -1708,7 +1774,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
};
},
clear_selection: function () {
- this.$('li.oe_selected').removeClass('oe_selected');
+ this.$('span.badge').removeClass('badge');
},
append_filter: function (filter) {
var self = this;
@@ -1721,12 +1787,13 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
} else {
var id = filter.id;
this.filters[key] = filter;
- $filter = this.$filters[key] = $('<li></li>')
+ $filter = $('<li></li>')
.appendTo(this.$('.oe_searchview_custom_list'))
- .addClass(filter.user_id ? 'oe_searchview_custom_private'
- : 'oe_searchview_custom_public')
.toggleClass('oe_searchview_custom_default', filter.is_default)
- .text(filter.name);
+ .append(this.$filters[key] = $('<span>').text(filter.name));
+
+ this.$filters[key].addClass(filter.user_id ? 'oe_searchview_custom_private'
+ : 'oe_searchview_custom_public')
$('<a class="oe_searchview_custom_delete">x</a>')
.click(function (e) {
@@ -1738,14 +1805,18 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
$filter.remove();
delete self.$filters[key];
delete self.filters[key];
+ if (_.isEmpty(self.filters)) {
+ self.hide();
+ }
});
})
.appendTo($filter);
}
- $filter.unbind('click').click(function () {
+ this.$filters[key].unbind('click').click(function () {
self.toggle_filter(filter);
});
+ this.show();
},
toggle_filter: function (filter, preventSearch) {
var current = this.view.query.find(function (facet) {
@@ -1753,15 +1824,44 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
});
if (current) {
this.view.query.remove(current);
- this.$filters[this.key_for(filter)].removeClass('oe_selected');
+ this.$filters[this.key_for(filter)].removeClass('badge');
return;
}
this.view.query.reset([this.facet_for(filter)], {
preventSearch: preventSearch || false});
- this.$filters[this.key_for(filter)].addClass('oe_selected');
+ this.$filters[this.key_for(filter)].addClass('badge');
},
set_filters: function (filters) {
_(filters).map(_.bind(this.append_filter, this));
+ if (!filters.length) {
+ this.hide();
+ }
+ },
+ hide: function () {
+ this.$el.hide();
+ },
+ show: function () {
+ this.$el.show();
+ },
+});
+
+instance.web.search.SaveFilter = instance.web.search.Input.extend({
+ template: 'SearchView.SaveFilter',
+ _in_drawer: true,
+ init: function (parent, custom_reports) {
+ this._super(parent);
+ this.custom_reports = custom_reports;
+ },
+ start: function () {
+ var self = this;
+ this.model = new instance.web.Model('ir.filters');
+ this.$el.on('submit', 'form', this.proxy('save_current'));
+ this.$el.on('click', 'input[type=checkbox]', function() {
+ $(this).siblings('input[type=checkbox]').prop('checked', false);
+ });
+ this.$el.on('click', 'h4', function () {
+ self.$el.toggleClass('oe_opened');
+ });
},
save_current: function () {
var self = this;
@@ -1799,14 +1899,16 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({
// FIXME: current context?
return self.model.call('create_or_replace', [filter]).done(function (id) {
filter.id = id;
- self.append_filter(filter);
+ if (self.custom_reports) {
+ self.custom_reports.append_filter(filter);
+ }
self.$el
.removeClass('oe_opened')
.find('form')[0].reset();
});
});
return false;
- }
+ },
});
instance.web.search.Filters = instance.web.search.Input.extend({
@@ -1814,22 +1916,13 @@ instance.web.search.Filters = instance.web.search.Input.extend({
_in_drawer: true,
start: function () {
var self = this;
- var running_count = 0;
- // get total filters count
var is_group = function (i) { return i instanceof instance.web.search.FilterGroup; };
- var visible_filters = _(this.view.controls).chain().reject(function (group) {
+ var visible_filters = _(this.drawer.controls).chain().reject(function (group) {
return _(_(group.children).filter(is_group)).isEmpty()
|| group.modifiers.invisible;
});
- var filters_count = visible_filters
- .pluck('children')
- .flatten()
- .filter(is_group)
- .map(function (i) { return i.filters.length; })
- .sum()
- .value();
- var col1 = [], col2 = visible_filters.map(function (group) {
+ var groups = visible_filters.map(function (group) {
var filters = _(group.children).filter(is_group);
return {
name: _.str.sprintf("<span class='oe_i'>%s</span> %s",
@@ -1840,27 +1933,16 @@ instance.web.search.Filters = instance.web.search.Input.extend({
};
}).value();
- while (col2.length) {
- // col1 + group should be smaller than col2 + group
- if ((running_count + col2[0].length) <= (filters_count - running_count)) {
- running_count += col2[0].length;
- col1.push(col2.shift());
- } else {
- break;
- }
- }
+ var $dl = $('<dl class="dl-horizontal">').appendTo(this.$el);
- return $.when(
- this.render_column(col1, $('<div>').appendTo(this.$el)),
- this.render_column(col2, $('<div>').appendTo(this.$el)));
- },
- render_column: function (column, $el) {
- return $.when.apply(null, _(column).map(function (group) {
- $('<h3>').html(group.name).appendTo($el);
- return $.when.apply(null,
- _(group.filters).invoke('appendTo', $el));
- }));
- }
+ var rendered_lines = _.map(groups, function (group) {
+ $('<dt>').html(group.name).appendTo($dl);
+ var $dd = $('<dd>').appendTo($dl);
+ return $.when.apply(null, _(group.filters).invoke('appendTo', $dd));
+ });
+
+ return $.when.apply(this, rendered_lines);
+ },
});
instance.web.search.Advanced = instance.web.search.Input.extend({
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index b03820eecaa..e276a5e3995 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -5306,8 +5306,12 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
if (this.searchview) {
this.searchview.destroy();
}
+ if (this.searchview_drawer) {
+ this.searchview_drawer.destroy();
+ }
this.searchview = new instance.web.SearchView(this,
this.dataset, false, search_defaults);
+ this.searchview_drawer = new instance.web.SearchViewDrawer(this, this.searchview);
this.searchview.on('search_data', self, function(domains, contexts, groupbys) {
if (self.initial_ids) {
self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]),
@@ -5353,7 +5357,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
});
});
});
- this.searchview.appendTo($(".oe_popup_search", self.$el));
+ this.searchview.appendTo(this.$(".oe_popup_search"));
},
do_search: function(domains, contexts, groupbys) {
var self = this;
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index ec233159d63..19597add308 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -607,7 +607,6 @@ instance.web.ViewManager = instance.web.Widget.extend({
// If no default view defined, switch to the first one in sequence
var default_view = this.flags.default_view || this.views_src[0].view_type;
-
return this.switch_mode(default_view, null, this.flags[default_view] && this.flags[default_view].options);
@@ -647,7 +646,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
_.each(_.keys(self.views), function(view_name) {
var controller = self.views[view_name].controller;
if (controller) {
- var container = self.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_name);
+ var container = self.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_name);
if (view_name === view_type) {
container.show();
controller.do_show(view_options || {});
@@ -690,7 +689,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
controller.on('switch_mode', self, this.switch_mode);
controller.on('previous_view', self, this.prev_view);
- var container = this.$el.find("> .oe_view_manager_body > .oe_view_manager_view_" + view_type);
+ var container = this.$el.find("> div > div > .oe_view_manager_body > .oe_view_manager_view_" + view_type);
var view_promise = controller.appendTo(container);
this.views[view_type].controller = controller;
this.views[view_type].deferred.resolve(view_type);
@@ -705,6 +704,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
self.trigger("controller_inited",view_type,controller);
});
},
+
/**
* @returns {Number|Boolean} the view id of the given type, false if not found
*/
@@ -800,6 +800,7 @@ instance.web.ViewManager = instance.web.Widget.extend({
if (this.searchview) {
this.searchview.destroy();
}
+
var options = {
hidden: this.flags.search_view === false,
disable_custom_filters: this.flags.search_disable_custom_filters,
@@ -807,7 +808,8 @@ instance.web.ViewManager = instance.web.Widget.extend({
this.searchview = new instance.web.SearchView(this, this.dataset, view_id, search_defaults, options);
this.searchview.on('search_data', self, this.do_searchview_search);
- return this.searchview.appendTo(this.$el.find(".oe_view_manager_view_search"));
+ return this.searchview.appendTo(this.$(".oe_view_manager_view_search"),
+ this.$(".oe_searchview_drawer_container"));
},
do_searchview_search: function(domains, contexts, groupbys) {
var self = this,
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index de544c7dff8..913783a2396 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -440,14 +440,20 @@
</tr>
<tr>
<td class="oe_leftbar" valign="top">
- <t t-set="debug" t-value="__debug__ ? '&amp;debug' : ''"/>
- <a class="oe_logo" t-attf-href="/web?#{debug}">
- <span class="oe_logo_edit">Edit Company data</span>
- <img t-att-src='widget.session.url("/web/binary/company_logo")'/>
- </a>
- <div class="oe_secondary_menus_container"/>
- <div class="oe_footer">
- Powered by <a href="https://www.odoo.com" target="_blank"><span>Odoo</span></a>
+ <div>
+ <t t-set="debug" t-value="__debug__ ? '&amp;debug' : ''"/>
+ <a class="oe_logo" t-attf-href="/web?#{debug}">
+ <span class="oe_logo_edit">Edit Company data</span>
+ <img t-att-src='widget.session.url("/web/binary/company_logo")'/>
+ </a>
+ <div>
+ <div>
+ <div class="oe_secondary_menus_container"/>
+ </div>
+ </div>
+ <div class="oe_footer">
+ Powered by <a href="http://www.odoo.com" target="_blank"><span>Odoo</span></a>
+ </div>
</div>
</td>
<td class="oe_application">
@@ -520,10 +526,15 @@
</tr>
</table>
- <div class="oe_view_manager_body">
- <t t-foreach="widget.views_src" t-as="view">
- <div t-attf-class="oe_view_manager_view_#{view.view_type}"/>
- </t>
+ <div class="oe_view_manager_wrapper">
+ <div>
+ <div class="oe_view_manager_body">
+ <div class="oe_searchview_drawer_container"/>
+ <t t-foreach="widget.views_src" t-as="view">
+ <div t-attf-class="oe_view_manager_view_#{view.view_type}"/>
+ </t>
+ </div>
+ </div>
</div>
</div>
</t>
@@ -1556,11 +1567,15 @@
<div class="oe_searchview_facets"/>
<div class="oe_searchview_clear"/>
<div class="oe_searchview_unfold_drawer" title="Advanced Search..."/>
- <div class="oe_searchview_drawer"/>
<button type="button" class="oe_searchview_search"
title="Search Again">Search</button>
</div>
+<div t-name="SearchViewDrawer" class="oe_searchview_drawer" style="display:none;">
+ <div class="col-md-7"></div>
+ <div class="col-md-5"></div>
+</div>
+
<div t-name="SearchView.InputView"
class="oe_searchview_input"
contenteditable="true"
@@ -1717,24 +1732,27 @@
<div t-name="SearchView.Filters" class="oe_searchview_filters oe_searchview_section">
</div>
-<div t-name="SearchView.CustomFilters" class="oe_searchview_custom oe_searchview_section">
- <div>
- <h3><span class="oe_i">M</span> Custom Filters</h3>
- <ul class="oe_searchview_custom_list"/>
- <div class="oe_searchview_custom">
- <h4>Save current filter</h4>
- <form class="oe_form">
- <p class="oe_form_required"><input id="oe_searchview_custom_input" placeholder="Filter name"/></p>
- <p>
- <input id="oe_searchview_custom_public" type="checkbox"/>
- <label for="oe_searchview_custom_public">Share with all users</label>
- <input id="oe_searchview_custom_default" type="checkbox"/>
- <label for="oe_searchview_custom_default">Use by default</label>
- </p>
- <button>Save</button>
- </form>
- </div>
- </div>
+
+
+<div t-name="SearchView.CustomReports" class="oe_searchview_custom oe_searchview_section">
+ <dl class="dl-horizontal">
+ <dt><span class="oe_i">M</span> Custom Reports</dt>
+ <dd><ul class="oe_searchview_custom_list"/></dd>
+ </dl>
+</div>
+
+ <div t-name="SearchView.SaveFilter" class="oe_searchview_savefilter">
+ <h4>Save current filter</h4>
+ <form class="oe_form">
+ <p class="oe_form_required"><input id="oe_searchview_custom_input" placeholder="Filter name"/></p>
+ <p>
+ <input id="oe_searchview_custom_public" type="checkbox"/>
+ <label for="oe_searchview_custom_public">Share with all users</label>
+ <input id="oe_searchview_custom_default" type="checkbox"/>
+ <label for="oe_searchview_custom_default">Use by default</label>
+ </p>
+ <button>Save</button>
+ </form>
</div>
<div t-name="SearchView.advanced" class="oe_searchview_advanced">
diff --git a/addons/web/static/test/search.js b/addons/web/static/test/search.js
index 96bbb660103..4724ca0792d 100644
--- a/addons/web/static/test/search.js
+++ b/addons/web/static/test/search.js
@@ -173,7 +173,9 @@ var makeSearchView = function (instance, dummy_widget_attributes, defaults) {
};
var dataset = new instance.web.DataSet(null, 'dummy.model');
- var view = new instance.web.SearchView(null, dataset, false, defaults);
+ var mock_parent = {getParent: function () {return null;}};
+
+ var view = new instance.web.SearchView(mock_parent, dataset, false, defaults);
var self = this;
view.on('invalid_search', self, function () {
ok(false, JSON.stringify([].slice(arguments)));
@@ -1071,10 +1073,10 @@ openerp.testing.section('search.filters', {
return view.appendTo($fix)
.done(function () {
var $fs = $fix.find('.oe_searchview_filters ul');
- // 3 filters, 1 filtergroup, 1 custom filters widget,
- // 1 advanced and 1 Filters widget
- equal(view.inputs.length, 7,
- 'view should have 7 inputs total');
+ // 3 filters, 1 filtergroup, 1 custom report widget,
+ // 1 Filters, 1 SaveFilter widget, and 1 advanced
+ equal(view.drawer.inputs.length, 8,
+ 'view should have 8 inputs total');
equal($fs.children().length, 3,
"drawer should have a filter group with 3 filters");
equal(_.str.strip($fs.children().eq(0).text()), "Foo1",
@@ -1159,14 +1161,15 @@ openerp.testing.section('search.groupby', {
return view.appendTo($fix)
.done(function () {
// 3 filters, 1 filtergroup group, 1 custom filter, 1 advanced, 1 Filters
- equal(view.inputs.length, 7,
- 'should have 7 inputs total');
- var group = _.find(view.inputs, function (f) {
+ // and 1 SaveFilter widget
+ equal(view.drawer.inputs.length, 8,
+ 'should have 8 inputs total');
+ var group = _.find(view.drawer.inputs, function (f) {
return f instanceof instance.web.search.GroupbyGroup;
});
ok(group, "should have a GroupbyGroup input");
- ok(group.getParent() === view,
- "group's parent should be view");
+ ok(group.getParent() === view.drawer,
+ "group's parent should be the drawer");
group.toggle(group.filters[0]);
group.toggle(group.filters[2]);
@@ -1208,9 +1211,10 @@ openerp.testing.section('search.groupby', {
return view.appendTo($fix)
.done(function () {
// 3 filters, 3 filtergroups, 1 custom filter, 1 advanced, 1 Filters
- equal(view.inputs.length, 9, "should have 9 inputs total");
+ // and 1 SaveFilter widget
+ equal(view.drawer.inputs.length, 10, "should have 10 inputs total");
- var groups = _.filter(view.inputs, function (f) {
+ var groups = _.filter(view.drawer.inputs, function (f) {
return f instanceof instance.web.search.GroupbyGroup;
});
equal(groups.length, 3, "should have 3 GroupbyGroups");
@@ -1242,10 +1246,10 @@ openerp.testing.section('search.filters.saved', {
return view.appendTo($fix)
.done(function () {
- var $row = $fix.find('.oe_searchview_custom li:first').click();
+ var $span = $fix.find('.oe_searchview_custom_list span:first').click();
- ok($row.hasClass('oe_selected'), "should check/select the filter's row");
- ok($row.hasClass("oe_searchview_custom_private"),
+ ok($span.hasClass('badge'), "should check/select the filter's row");
+ ok($span.hasClass("oe_searchview_custom_private"),
"should have private filter note/class");
equal(view.query.length, 1, "should have only one facet");
var values = view.query.at(0).values;
@@ -1268,7 +1272,7 @@ openerp.testing.section('search.filters.saved', {
var $row = $fix.find('.oe_searchview_custom li:first').click();
view.query.remove(view.query.at(0));
- ok(!$row.hasClass('oe_selected'),
+ ok(!$row.hasClass('badge'),
"should not be checked anymore");
});
});
@@ -1280,7 +1284,7 @@ openerp.testing.section('search.filters.saved', {
return view.appendTo($fix)
.done(function () {
- var $row = $fix.find('.oe_searchview_custom li:first').click();
+ var $row = $fix.find('.oe_searchview_custom_list span:first').click();
equal(view.query.length, 1, "should have one facet");
$row.click();
equal(view.query.length, 0, "should have removed facet");
@@ -1296,13 +1300,13 @@ openerp.testing.section('search.filters.saved', {
});
return view.appendTo($fix)
.done(function () {
- $fix.find('.oe_searchview_custom li:eq(0)').click();
+ $fix.find('.oe_searchview_custom_list span:eq(0)').click();
equal(view.query.length, 1, "should have one facet");
deepEqual(
view.query.at(0).get('field').get_context(),
{'private': 1},
"should have selected first filter");
- $fix.find('.oe_searchview_custom li:eq(1)').click();
+ $fix.find('.oe_searchview_custom_list span:eq(1)').click();
equal(view.query.length, 1, "should have one facet");
deepEqual(
view.query.at(0).get('field').get_context(),
@@ -1325,10 +1329,10 @@ openerp.testing.section('search.filters.saved', {
});
return view.appendTo($fix)
.then(function () {
- $fix.find('.oe_searchview_custom input#oe_searchview_custom_input')
+ $fix.find('.oe_searchview_savefilter input#oe_searchview_custom_input')
.val("filter name")
.end()
- .find('.oe_searchview_custom button').click();
+ .find('.oe_searchview_savefilter button').click();
return done.promise();
});
});
@@ -1529,10 +1533,10 @@ openerp.testing.section('search.invisible', {
].join(''));
return view.appendTo($fix)
.then(function () {
- strictEqual($fix.find('.oe_searchview_filters h3').length,
+ strictEqual($fix.find('.oe_searchview_filters dt').length,
1,
"should only display one group");
- strictEqual($fix.find('.oe_searchview_filters h3').text(),
+ strictEqual($fix.find('.oe_searchview_filters dt').text(),
'w Visibles',
"should only display the Visibles group (and its icon char)");
@@ -1588,3 +1592,4 @@ openerp.testing.section('search.invisible', {
});
});
});
+