diff options
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/css/base.css | 236 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 183 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 69 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_editor.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 64 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_tree.js | 103 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 287 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 45 |
10 files changed, 638 insertions, 367 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 3e260601581..e69d3696655 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -34,7 +34,7 @@ background: white; /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ */ + */ } .openerp a { text-decoration: none; @@ -188,13 +188,7 @@ } .openerp.ui-dialog { display: none; - position: fixed; padding: 6px; - top: 50%; - left: 50%; - z-index: 1050; - width: 560px; - margin: -150px 0 0 -280px; background-color: rgba(60, 60, 60, 0.7); border: 1px solid; border-color: #888888 #555555 #444444; @@ -208,6 +202,9 @@ -moz-background-clip: padding-box; background-clip: padding-box; } +.openerp.ui-dialog .ui-dialog-content { + padding: 0px; +} .openerp.ui-dialog .ui-dialog-titlebar, .openerp.ui-dialog .ui-dialog-content, .openerp.ui-dialog .ui-dialog-buttonpane { padding: 16px; } @@ -246,6 +243,9 @@ .openerp.ui-dialog .ui-dialog-buttonpane button { margin-left: 8px; } +.openerp.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: left; +} .openerp.ui-dialog .ui-dialog-titlebar-close { padding: 0; } @@ -268,6 +268,9 @@ color: black; text-decoration: none; } +.openerp.ui-dialog.oe_act_window .ui-dialog-content { + padding: 0px; +} .openerp .modal-backdrop { position: fixed; top: 0; @@ -395,7 +398,7 @@ .openerp .oe_avatar { margin: 0 16px 0 0; } -.openerp .oe_avatar img { +.openerp .oe_avatar > img { height: 50px; -moz-border-radius: 3px; -webkit-border-radius: 3px; @@ -450,6 +453,29 @@ .openerp .oe_webclient .oe_star_on { color: gold; } +.openerp .oe_tag { + border-radius: 2px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #9daccc; + background: #e2e6f0; + color: black !important; + padding: 0px 3px 0px 3px; + margin: 0 2px 2px 0; + height: 16px; +} +.openerp .oe_tags .text-wrap { + width: 100% !important; +} +.openerp .oe_tags .text-wrap textarea { + width: 100% !important; +} +.openerp .oe_tags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em { + font-style: italic; + text-decoration: none; +} .openerp.oe_tooltip { font-size: 12px; } @@ -1136,63 +1162,63 @@ .openerp .oe_view_manager .oe_view_manager_view_kanban { height: inherit; } -.openerp .oe_view_manager .oe_view_manager_header { +.openerp .oe_view_manager table.oe_view_manager_header { width: 100%; + table-layout: fixed; } -.openerp .oe_view_manager .oe_view_manager_header .oe_header_row { +.openerp .oe_view_manager table.oe_view_manager_header .oe_header_row { clear: both; text-shadow: 0 1px 1px white; } -.openerp .oe_view_manager .oe_view_manager_header .oe_header_row:last-child td { +.openerp .oe_view_manager table.oe_view_manager_header .oe_header_row:last-child td { padding-top: 0; } -.openerp .oe_view_manager .oe_view_manager_header .oe_view_manager_sidebar { +.openerp .oe_view_manager table.oe_view_manager_header .oe_view_manager_sidebar { margin: 0px auto; - width: 400px; text-align: center; } -.openerp .oe_view_manager .oe_view_manager_header td { +.openerp .oe_view_manager table.oe_view_manager_header td { line-height: 26px; } -.openerp .oe_view_manager .oe_view_manager_header h2 { +.openerp .oe_view_manager table.oe_view_manager_header h2 { font-size: 18px; margin: 0; float: left; } -.openerp .oe_view_manager .oe_view_manager_header h2 a { +.openerp .oe_view_manager table.oe_view_manager_header h2 a { color: #8a89ba; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group { display: inline-block; border: 1px solid #ababab; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group li { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group li { float: left; border-right: 1px solid #ababab; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group li:last-child { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group li:last-child { border: none; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group a { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group a { color: #4c4c4c; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group a:hover { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group a:hover { text-decoration: none; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group .active { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group .active { background: #999999; -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3) inset; } -.openerp .oe_view_manager .oe_view_manager_header .oe_button_group .active a { +.openerp .oe_view_manager table.oe_view_manager_header .oe_button_group .active a { color: white; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); } -.openerp .oe_view_manager .oe_view_manager_header .oe_view_manager_buttons { +.openerp .oe_view_manager table.oe_view_manager_header .oe_view_manager_buttons { white-space: nowrap; } .openerp .oe_view_manager .oe_view_manager_pager { @@ -1319,7 +1345,7 @@ float: right; padding: 1px 0; line-height: 18px; - width: 480px; + width: 400px; border: 1px solid #ababab; background: white; -moz-border-radius: 13px; @@ -1741,12 +1767,12 @@ width: auto; } .openerp .oe_form_nosheet { - margin-left: 10px; - margin-right: 10px; + margin: 20px; } .openerp .oe_form_nosheet > header { - margin-left: -10px; - margin-right: -10px; + margin-top: -20px; + margin-left: -20px; + margin-right: -20px; } .openerp .oe_form header { position: relative; @@ -1765,7 +1791,7 @@ display: inline-block; float: right; } -.openerp .oe_form footer { +.openerp .oe_form div.oe_chatter { min-width: 650px; max-width: 860px; margin: 0 auto; @@ -1817,18 +1843,19 @@ .openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell_label { border-right: none; } -.openerp .oe_form .oe_subtotal_footer .oe_form_field { - width: auto !important; -} .openerp .oe_form .oe_subtotal_footer .oe_subtotal_footer_separator { + width: 108px; border-top: 1px solid #cacaca; - font-sie: 120%; font-weight: bold; + font-size: 18px; } .openerp .oe_form .oe_subtotal_footer label.oe_subtotal_footer_separator { font-weight: bold !important; padding: 2px 8px 2px 0px !important; } +.openerp .oe_form .oe_subtotal_footer label.oe_form_label_help { + font-weight: normal; +} .openerp .oe_application .oe_form_sheetbg { background: url(/web/static/src/img/form_sheetbg.png); padding: 8px 0; @@ -1870,8 +1897,8 @@ width: 100%; margin: 4px 0 4px 0; } -.openerp .oe_form .oe_form_group .oe_group_right > tbody > tr > td:first-child { - padding-left: 18px; +.openerp .oe_form .oe_form_group .oe_group_right { + margin-left: 18px; } .openerp .oe_form .oe_form_label_help[for], .openerp .oe_form .oe_form_label[for] { font-weight: bold; @@ -1941,15 +1968,6 @@ .openerp .oe_form .oe_form_field_text.oe_inline, .openerp .oe_form .oe_form_field_text.oe_inline > textarea { width: 500px; } -.openerp .oe_form .oe_form_field_float input { - width: 100px; -} -.openerp .oe_form h1 .oe_form_field_float input { - width: 140px; -} -.openerp .oe_form h2 .oe_form_field_float input { - width: 120px; -} .openerp .oe_form h1, .openerp .oe_form h2, .openerp .oe_form h3, .openerp .oe_form h4, .openerp .oe_form h5, .openerp .oe_form h6 { margin: 0 0 4px 0; } @@ -1966,18 +1984,6 @@ .openerp .oe_form .oe_form_field input { margin: 0px; } -.openerp .oe_form .oe_form_field_integer { - width: 180px; -} -.openerp .oe_form .oe_form_field_float { - width: 180px; -} -.openerp .oe_form .oe_form_field_date { - width: 7.5em; -} -.openerp .oe_form .oe_form_field_datetime { - width: 11em; -} .openerp .oe_form input[type="text"], .openerp .oe_form input[type="password"], .openerp .oe_form input[type="file"], .openerp .oe_form select { height: 22px; padding-top: 2px; @@ -2017,32 +2023,6 @@ padding-top: 4px; width: auto; } -.openerp .oe_form .oe_form_field_many2manytags .text-wrap { - width: 100% !important; -} -.openerp .oe_form .oe_form_field_many2manytags .text-wrap textarea { - width: 100% !important; -} -.openerp .oe_form .oe_form_field_many2manytags .oe_form_field_many2manytags_box { - border-radius: 2px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - box-sizing: border-box; - position: relative; - float: left; - border: 1px solid #9daccc; - background: #e2e6f0; - color: black; - padding: 0px 3px 0px 3px; - margin: 0 2px 2px 0; - height: 16px; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; -} -.openerp .oe_form .oe_form_field_many2manytags .text-core .text-wrap .text-dropdown .text-list .text-suggestion em { - font-style: italic; - text-decoration: none; -} .openerp .oe_form .oe_datepicker_container { display: none; } @@ -2096,6 +2076,18 @@ position: relative; overflow: hidden; } +.openerp .oe_form_editable .oe_form .oe_form_field_integer { + width: 7em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_float { + width: 8em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_date { + width: 7.5em !important; +} +.openerp .oe_form_editable .oe_form .oe_form_field_datetime { + width: 11.5em !important; +} .openerp .oe_hidden_input_file { overflow: hidden; position: relative; @@ -2125,6 +2117,7 @@ } .openerp .oe_form .oe_form_field_image .oe_form_field_image_controls { position: absolute; + white-space: nowrap; top: 1px; padding: 3px 0 0 0; margin: 0 1px; @@ -2152,27 +2145,33 @@ .openerp .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page { display: none; } -.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save { +.openerp .oe_form_field_one2many .oe_list_content > thead, .openerp .oe_form_field_many2many .oe_list_content > thead { + border-bottom: 1px; +} +.openerp .oe_form_field_one2many .oe_list_content > tbody tr:nth-child(odd), .openerp .oe_form_field_many2many .oe_list_content > tbody tr:nth-child(odd) { + background: transparent; +} +.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save, .openerp .oe_form_field_many2many .oe_list .oe_list_edit_row_save { background: url(/web/static/src/img/iconset-b-remove.png) 50% 50% no-repeat; } -.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save:before { +.openerp .oe_form_field_one2many .oe_list .oe_list_edit_row_save:before, .openerp .oe_form_field_many2many .oe_list .oe_list_edit_row_save:before { visibility: hidden; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_header_row_top { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_header_row_top, .openerp .oe_form_field_many2many > .oe_view_manager .oe_header_row_top { display: none; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td { padding: 0px 8px; line-height: 16px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_i { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_i, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_i { font-size: 13px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group { height: auto; line-height: 16px; } -.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li { +.openerp .oe_form_field_one2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li, .openerp .oe_form_field_many2many > .oe_view_manager .oe_view_manager_header2 td .oe_pager_group li { height: auto; line-height: 16px; } @@ -2233,6 +2232,9 @@ .openerp .oe_list_content > tbody > tr > td.oe_list_field_cell { padding: 3px 6px; } +.openerp .oe_list_content > tbody > tr > td.oe_list_field_cell progress { + width: 100%; +} .openerp .oe_list_content > tbody > tr > td, .openerp .oe_list_content > tbody > tr > th { line-height: 18px; } @@ -2252,6 +2254,7 @@ } .openerp .oe_list_content > tbody > tr > td.oe_number { text-align: right !important; + max-width: 100px; } .openerp .oe_list_content > tbody > tr:nth-child(odd) { background-color: #f0f0fa; @@ -2353,6 +2356,59 @@ color: #333333; } +.openerp .tree_header { + background-color: #f0f0f0; + border-bottom: 1px solid #cacaca; + color: #4c4c4c; + padding: 5px; + height: 25px; +} +.openerp .tree_header button { + float: right; + height: 27px; + margin-right: 5px; +} +.openerp .oe-treeview-table { + width: 100%; + background-color: white; + border-spacing: 0; +} +.openerp .oe-treeview-table th { + padding: 10px; + color: #4c4c4c; + font-weight: bold; + background-color: #f0f0f0; + border-bottom: 2px solid #cacaca; +} +.openerp .oe-treeview-table .treeview-tr, .openerp .oe-treeview-table .treeview-td { + cursor: pointer; + border-right: 1px dotted #afafb6; + vertical-align: top; + text-align: left; + border-bottom: 1px solid #cfcccc; +} +.openerp .oe-treeview-table tr:hover { + background-color: #e0e0f8; +} +.openerp .oe-treeview-table .oe-number { + text-align: right !important; +} +.openerp .oe-treeview-table span { + font-size: 90%; + font-weight: normal; + white-space: nowrap; + display: block; +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first { + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat; +} +.openerp .oe-treeview-table .oe_open .treeview-tr.oe-treeview-first { + background-image: url(/web/static/src/img/collapse.gif); +} +.openerp .oe-treeview-table .treeview-tr.oe-treeview-first span, .openerp .oe-treeview-table .treeview-td.oe-treeview-first span { + margin-left: 16px; +} + .kitten-mode-activated { background-image: url(http://placekitten.com/g/1365/769); background-size: cover; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 1410a1ce872..9bfe5fe32da 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -205,13 +205,7 @@ $sheet-max-width: 860px // Modal box &.ui-dialog display: none - position: fixed padding: 6px - top: 50% - left: 50% - z-index: 1050 - width: 560px - margin: -150px 0 0 -280px //overflow: hidden background-color: rgba(60,60,60,0.7) border: 1px solid @@ -220,6 +214,8 @@ $sheet-max-width: 860px @include radius(8px) @include box-shadow(0 1px 12px rgba(0, 0, 0, 0.6)) @include background-clip() + .ui-dialog-content + padding: 0px .ui-dialog-titlebar, .ui-dialog-content, .ui-dialog-buttonpane padding: 16px .ui-dialog-titlebar @@ -241,6 +237,8 @@ $sheet-max-width: 860px @include radius(0 0 2px 2px) button margin-left: 8px + .ui-dialog-buttonset + float: left .ui-dialog-titlebar-close padding: 0 .ui-icon-closethick @@ -260,6 +258,10 @@ $sheet-max-width: 860px color: black text-decoration: none + &.ui-dialog.oe_act_window + .ui-dialog-content + padding: 0px + .modal-backdrop position: fixed top: 0 @@ -336,7 +338,7 @@ $sheet-max-width: 860px margin: 4px .oe_avatar margin: 0 16px 0 0 - img + > img height: 50px @include radius(3px) @include box-shadow(0 1px 3px rgba(0, 0, 0, 0.3)) @@ -362,8 +364,26 @@ $sheet-max-width: 860px text-decoration: none .oe_star_on color: gold - - //.oe_edit_only + // }}} + // Tags (for many2many tags, among others) {{{ + .oe_tag + border-radius: 2px + @include box-sizing(border) + border: 1px solid #9DACCC + background: #E2E6F0 + color: black !important + padding: 0px 3px 0px 3px + margin: 0 2px 2px 0 + height: 16px + // font: 11px "lucida grande", tahoma, verdana, arial, sans-serif + .oe_tags + .text-wrap + width: 100% !important + textarea + width: 100% !important + .text-core .text-wrap .text-dropdown .text-list .text-suggestion em + font-style: italic + text-decoration: none // }}} // Tooltips {{{ &.oe_tooltip @@ -823,7 +843,7 @@ $sheet-max-width: 860px text-shadow: 0 1px 1px rgba(0,0,0,0.2) @include radius(4px) @include box-shadow(inset 0 1px 1px rgba(0, 0, 0, 0.2)) - .oe_menu_counter + .oe_menu_counter float: right background: #8a89ba color: #eee @@ -846,7 +866,7 @@ $sheet-max-width: 860px color: $colour4 text-shadow: 0 1px 1px white @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.2)) - .oe_menu_counter + .oe_menu_counter background: #eee color: #8a89ba .oe_menu_toggler:before @@ -888,8 +908,9 @@ $sheet-max-width: 860px .oe_view_manager_view_kanban height: inherit - .oe_view_manager_header + table.oe_view_manager_header width: 100% + table-layout: fixed .oe_header_row //min-height: 26px //line-height: 26px @@ -900,7 +921,6 @@ $sheet-max-width: 860px padding-top: 0 .oe_view_manager_sidebar margin: 0px auto - width: 400px text-align: center td line-height: 26px @@ -1033,7 +1053,7 @@ $sheet-max-width: 860px float: right padding: 1px 0 line-height: 18px - width: 480px + width: 400px border: 1px solid #ababab background: white @include radius(13px) @@ -1312,7 +1332,7 @@ $sheet-max-width: 860px margin: 0 0 0 4px padding: 0 - + // }}} // Views Common {{{ .oe_view_nocontent @@ -1356,25 +1376,25 @@ $sheet-max-width: 860px display: none !important .oe_form .oe_form_field_date width: auto - .oe_form_nosheet - margin-left: 10px - margin-right: 10px + .oe_form_nosheet + margin: 20px .oe_form_nosheet > header - margin-left: -10px - margin-right: -10px + margin-top: -20px + margin-left: -20px + margin-right: -20px // }}} // FormView.custom tags and classes {{{ - .oe_form + .oe_form header position: relative border-bottom: 1px solid #cacaca @include vertical-gradient(#fcfcfc, #dedede) padding: 0 8px - line-height: 30px + line-height: 30px ul display: inline-block float: right - footer + div.oe_chatter min-width: 650px max-width: $sheet-max-width margin: 0 auto @@ -1387,12 +1407,12 @@ $sheet-max-width: 860px vertical-align: top margin-left: 8px li - border-right: none + border-right: none padding: 0 margin: 0 - float: left + float: left vertical-align: top - height: 30px + height: 30px padding: 0 0 0 12px &:first-child border-left: 1px solid #cacaca @@ -1414,21 +1434,22 @@ $sheet-max-width: 860px padding: 0 !important td.oe_form_group_cell_label border-right: none - .oe_form_field - width: auto !important .oe_subtotal_footer_separator + width: 108px border-top: 1px solid #cacaca - font-sie: 120% font-weight: bold + font-size: 18px label.oe_subtotal_footer_separator font-weight: bold !important padding: 2px 8px 2px 0px !important + label.oe_form_label_help + font-weight: normal // no sheet in popups .oe_application .oe_form_sheetbg background: url(/web/static/src/img/form_sheetbg.png) padding: 8px 0 - border-bottom: 1px solid #ddd + border-bottom: 1px solid #ddd .oe_form_sheet_width min-width: 650px max-width: $sheet-max-width @@ -1459,8 +1480,7 @@ $sheet-max-width: 860px width: 100% margin: 4px 0 4px 0 .oe_group_right - > tbody > tr > td:first-child - padding-left: 18px + margin-left: 18px // }}} // FormView.label {{{ .oe_form @@ -1521,12 +1541,6 @@ $sheet-max-width: 860px width: 100% .oe_form_field_text.oe_inline, .oe_form_field_text.oe_inline > textarea width: 500px - .oe_form_field_float input - width: 100px - h1 .oe_form_field_float input - width: 140px - h2 .oe_form_field_float input - width: 120px h1, h2, h3, h4, h5, h6 margin: 0 0 4px 0 input @@ -1539,14 +1553,6 @@ $sheet-max-width: 860px line-height: 18px input margin: 0px - .oe_form_field_integer - width: 180px - .oe_form_field_float - width: 180px - .oe_form_field_date - width: 7.5em - .oe_form_field_datetime - width: 11em input[type="text"], input[type="password"], input[type="file"], select height: 22px padding-top: 2px @@ -1572,26 +1578,6 @@ $sheet-max-width: 860px .oe_form_field_boolean padding-top: 4px width: auto - .oe_form_field_many2manytags - .text-wrap - width: 100% !important - textarea - width: 100% !important - .oe_form_field_many2manytags_box - border-radius: 2px - @include box-sizing(border) - position: relative - float: left - border: 1px solid #9DACCC - background: #E2E6F0 - color: black - padding: 0px 3px 0px 3px - margin: 0 2px 2px 0 - height: 16px - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif - .text-core .text-wrap .text-dropdown .text-list .text-suggestion em - font-style: italic - text-decoration: none .oe_datepicker_container display: none .oe_datepicker_root @@ -1636,6 +1622,16 @@ $sheet-max-width: 860px > div position: relative overflow: hidden + .oe_form_editable + .oe_form + .oe_form_field_integer + width: 7em !important + .oe_form_field_float + width: 8em !important + .oe_form_field_date + width: 7.5em !important + .oe_form_field_datetime + width: 11.5em !important // }}} // FormView.fields_binary {{{ /* http://www.quirksmode.org/dom/inputfile.html @@ -1669,6 +1665,7 @@ $sheet-max-width: 860px vertical-align: top .oe_form_field_image_controls position: absolute + white-space: nowrap top: 1px padding: 3px 0 0 0 margin: 0 1px @@ -1694,8 +1691,14 @@ $sheet-max-width: 860px .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page display: none - .oe_form_field_one2many + .oe_form_field_one2many,.oe_form_field_many2many // TODO: oe_form_field_one2many_list? + .oe_list_content + > thead + border-bottom: 1px + > tbody + tr:nth-child(odd) + background: transparent .oe_list .oe_list_edit_row_save background: url(/web/static/src/img/iconset-b-remove.png) 50% 50% no-repeat &:before @@ -1763,6 +1766,8 @@ $sheet-max-width: 860px border-top: 1px solid #ddd > td.oe_list_field_cell padding: 3px 6px + progress + width: 100% > td, > th line-height: 18px > button @@ -1776,6 +1781,7 @@ $sheet-max-width: 860px border-width: 0 > td.oe_number text-align: right !important + max-width: 100px > tr:nth-child(odd) background-color: #f0f0fa @include vertical-gradient(#f0f0fa, #eeeef6) @@ -1853,6 +1859,49 @@ $sheet-max-width: 860px float: right color: #333 // }}} +//Tree view +.openerp + .tree_header + background-color: #f0f0f0 + border-bottom: 1px solid #cacaca + color: #4c4c4c + padding: 5px + height: 25px + button + float: right + height: 27px + margin-right: 5px + .oe-treeview-table + width: 100% + background-color: white + border-spacing: 0 + th + padding: 10px + color: #4c4c4c + font-weight: bold + background-color: #f0f0f0 + border-bottom: 2px solid #cacaca + .treeview-tr, .treeview-td + cursor: pointer + border-right: 1px dotted #afafb6 + vertical-align: top + text-align: left + border-bottom: 1px solid #cfcccc + tr:hover + background-color: #e0e0f8 + .oe-number + text-align: right !important + span + font-size: 90% + font-weight: normal + white-space: nowrap + display: block + .treeview-tr.oe-treeview-first + background: transparent url(/web/static/src/img/expand.gif) 0 50% no-repeat + .oe_open .treeview-tr.oe-treeview-first + background-image: url(/web/static/src/img/collapse.gif) + .treeview-tr.oe-treeview-first span, .treeview-td.oe-treeview-first span + margin-left: 16px // Kitten Mode {{{ .kitten-mode-activated background-image: url(http://placekitten.com/g/1365/769) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index b87ebe56856..094e2f184e6 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -63,7 +63,7 @@ instance.web.Dialog = instance.web.Widget.extend({ this.dialog_options = { modal: true, destroy_on_close: true, - width: $(window).width() * (($(window).width() > 1024) ? 0.5 : 0.75), + width: 900, min_width: 0, max_width: '95%', height: 'auto', @@ -145,9 +145,9 @@ instance.web.Dialog = instance.web.Widget.extend({ _.each(this.getChildren(), function(el) { el.destroy(); }); - if (! this.isDestroyed()) { - this.$element.dialog('destroy'); - } + if (! this.isDestroyed()) { + this.$element.dialog('destroy'); + } this._super(); } }); @@ -212,11 +212,11 @@ instance.web.CrashManager = instance.web.CallbackEnabled.extend({ dialog.$element.html(QWeb.render('CrashManager.error', {session: instance.connection, error: error})); }, on_javascript_exception: function(exception) { - this.on_traceback({ - type: _t("Client Error"), - message: exception, - data: {debug: ""} - }); + this.on_traceback({ + type: _t("Client Error"), + message: exception, + data: {debug: ""} + }); }, }); @@ -482,24 +482,26 @@ instance.web.Login = instance.web.Widget.extend({ } } }, + open_db_manager: function(){ + var self = this; + self.$element.find('.oe_login_bottom').hide(); + self.$element.find('.oe_login_pane').hide(); + self.databasemanager = new instance.web.DatabaseManager(self); + self.databasemanager.appendTo(self.$element); + self.databasemanager.do_exit.add_last(function() { + self.databasemanager.destroy(); + self.$element.find('.oe_login_bottom').show(); + self.$element.find('.oe_login_pane').show(); + self.load_db_list(true).then(self.on_db_list_loaded); + }); + }, start: function() { var self = this; - self.$element.find("form").submit(self.on_submit); - self.$element.find('.oe_login_manage_db').click(function() { - self.$element.find('.oe_login_bottom').hide(); - self.$element.find('.oe_login_pane').hide(); - self.databasemanager = new instance.web.DatabaseManager(self); - self.databasemanager.appendTo(self.$element); - self.databasemanager.do_exit.add_last(function() { - self.databasemanager.destroy(); - self.$element.find('.oe_login_bottom').show(); - self.$element.find('.oe_login_pane').show(); - self.load_db_list(true).then(self.proxy('_db_list_loaded')); - }); + self.open_db_manager(); }); - return self.load_db_list().then(self.proxy('_db_list_loaded')); + return self.load_db_list().then(self.on_db_list_loaded); }, load_db_list: function (force) { var d = $.when(), self = this; @@ -514,11 +516,14 @@ instance.web.Login = instance.web.Widget.extend({ } return d; }, - _db_list_loaded: function () { - var list = this._db_list, - dbdiv = this.$element.find('div.oe_login_dbpane'); + on_db_list_loaded: function () { + var self = this; + var list = this._db_list; + var dbdiv = this.$element.find('div.oe_login_dbpane'); this.$element.find("[name=db]").replaceWith(instance.web.qweb.render('Login.dblist', { db_list: list, selected_db: this.selected_db})); - if(list && list.length === 1) { + if(list.length === 0) { + self.open_db_manager(); + } else if(list && list.length === 1) { dbdiv.hide(); } else { dbdiv.show(); @@ -667,7 +672,7 @@ instance.web.Menu = instance.web.Widget.extend({ * @param {Number} id the action_id to match */ open_action: function (id) { - var $menu = this.$element.add(this.$secondary_menus).find('a[data-action-id=' + id + ']'); + var $menu = this.$element.add(this.$secondary_menus).find('a[data-action-id="' + id + '"]'); var menu_id = $menu.data('menu'); if (menu_id) { this.open_menu(menu_id); @@ -822,8 +827,8 @@ instance.web.UserMenu = instance.web.Widget.extend({ {text: _t("Change password"), click: function(){ self.change_password(); }}, {text: _t("Cancel"), click: function(){ $(this).dialog('destroy'); }}, {text: _t("Save"), click: function(){ - var inner_viewmanager = action_manager.inner_viewmanager; - inner_viewmanager.views[inner_viewmanager.active_view].controller.do_save() + var inner_widget = action_manager.inner_widget; + inner_widget.views[inner_widget.active_view].controller.do_save() .then(function() { self.dialog.destroy(); // needs to refresh interface in case language changed @@ -894,11 +899,12 @@ instance.web.WebClient = instance.web.Widget.extend({ }); this.$element.on('click', '.oe_dropdown_toggle', function(ev) { ev.preventDefault(); - var $menu = $(this).find('.oe_dropdown_menu'); + var $toggle = $(this); + var $menu = $toggle.find('.oe_dropdown_menu'); var state = $menu.is('.oe_opened'); setTimeout(function() { // Do not alter propagation - $menu.toggleClass('oe_opened', !state); + $toggle.add($menu).toggleClass('oe_opened', !state); if (!state) { // Move $menu if outside window's edge var doc_width = $(document).width(); @@ -1036,6 +1042,7 @@ instance.web.WebClient = instance.web.Widget.extend({ if (options.needaction) { action.context.search_default_needaction_pending = true; } + self.action_manager.clear_breadcrumbs(); self.action_manager.do_action(action); }); }, diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index a00ca4002e5..a5a62b9bcc1 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -404,10 +404,11 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess } }); + /** * Event Bus used to bind events scoped in the current instance */ -instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMixin, { +instance.web.Bus = instance.web.Class.extend(instance.web.EventDispatcherMixin, { init: function() { instance.web.EventDispatcherMixin.init.call(this, parent); var self = this; @@ -425,7 +426,8 @@ instance.web.bus = new (instance.web.Class.extend(instance.web.EventDispatcherMi }); }); } -}))(); +}) +instance.web.bus = new instance.web.Bus(); /** OpenERP Translations */ instance.web.TranslationDataBase = instance.web.Class.extend(/** @lends instance.web.TranslationDataBase# */{ diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js index 8733a191b21..6df78679ecb 100644 --- a/addons/web/static/src/js/view_editor.js +++ b/addons/web/static/src/js/view_editor.js @@ -53,7 +53,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ this.main_view_id = this.parent.fields_view.view_id; this.action_manager = new instance.web.ActionManager(this); $.when(this.action_manager.do_action(action)).then(function() { - var viewmanager = self.action_manager.inner_viewmanager, + var viewmanager = self.action_manager.inner_widget, controller = viewmanager.views[viewmanager.active_view].controller; self.action_manager.appendTo(self.view_edit_dialog.$element); self.action_manager.renderElement(self.view_edit_dialog); @@ -88,7 +88,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ } else { $.when(self.do_save_view(view_values)).then(function() { self.create_view_dialog.close(); - var controller = self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller; + var controller = self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller; controller.reload_content(); }); } @@ -167,7 +167,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ do_delete_view: function() { var self = this; if (confirm(_t("Do you really want to remove this view?"))) { - var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller; + var controller = this.action_manager.inner_widget.views[this.action_manager.inner_widget.active_view].controller; this.dataset.unlink([this.main_view_id]).then(function() { controller.reload_content(); self.main_view_id = self.parent.fields_view.view_id; @@ -397,7 +397,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ action_manager.do_action(action); }}, {text: _t("Close"), click: function(){ - self.action_manager.inner_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller.reload_content(); + self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller.reload_content(); self.edit_xml_dialog.close(); }} ] @@ -998,7 +998,7 @@ instance.web.ViewEditor = instance.web.OldWidget.extend({ }; var action_manager = new instance.web.ActionManager(self); $.when(action_manager.do_action(action)).then(function() { - var controller = action_manager.dialog_viewmanager.views['form'].controller; + var controller = action_manager.dialog_widget.views['form'].controller; controller.on_button_cancel.add_last(function(){ action_manager.destroy() }); diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index f9eaaba4b91..2f832d2728a 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -9,7 +9,7 @@ instance.web.form = {}; /** * Interface implemented by the form view or any other object * able to provide the features necessary for the fields to work. - * + * * Properties: * - display_invalid_fields : if true, all fields where is_valid() return true should * be displayed as invalid. @@ -287,10 +287,12 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM on_record_loaded: function(record) { var self = this, set_values = []; if (!record) { + this.set({ 'title' : undefined }); this.do_warn("Form", "The record could not be found in the database.", true); return $.Deferred().reject(); } this.datarecord = record; + this.set({ 'title' : record.id ? record.name : "New record" }); if (this.qweb) { this.kill_current_form(); @@ -524,7 +526,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.on_form_changed(); } if (!_.isEmpty(result.warning)) { - instance.web.dialog($(QWeb.render("CrashManager.warning", result.warning)), { + instance.web.dialog($(QWeb.render("CrashManager.warning", result.warning)), { title:result.warning.title, modal: true, buttons: [ @@ -961,7 +963,7 @@ instance.web.form.FormRenderingEngineInterface = instance.web.Class.extend({ /** * Default rendering engine for the form view. - * + * * It is necessary to set the view using set_view() before usage. */ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInterface.extend({ @@ -1284,7 +1286,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt page_attrs.__page = $new_page; page_attrs.__ic = ic; pages.push(page_attrs); - + $new_page.children().each(function() { self.process($(this)); }); @@ -1310,7 +1312,7 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt } }); }); - + this.handle_common_properties($new_notebook, $notebook); return $new_notebook; }, @@ -1611,7 +1613,7 @@ instance.web.form.FormWidget = instance.web.Widget.extend(instance.web.form.Invi if (! v_context) { v_context = (this.field || {}).context || {}; } - + if (v_context.__ref || true) { //TODO: remove true var fields_values = this._build_eval_context(blacklist); v_context = new instance.web.CompoundContext(v_context).set_eval_context(fields_values); @@ -1719,14 +1721,14 @@ instance.web.form.WidgetButton = instance.web.form.FormWidget.extend({ /** * Interface to be implemented by fields. - * + * * Properties: * - readonly: boolean. If set to true the field should appear in readonly mode. * - force_readonly: boolean, When it is true, the field should always appear * in read only mode, no matter what the value of the "readonly" property can be. * Events: * - changed_value: triggered to inform the view to check on_changes - * + * */ instance.web.form.FieldInterface = { /** @@ -1737,14 +1739,14 @@ instance.web.form.FieldInterface = { init: function(field_manager, node) {}, /** * Called by the form view to indicate the value of the field. - * + * * set_value() may return an object that can be passed to $.when() that represents the moment when * the field has finished all operations necessary before the user can effectively use the widget. - * + * * Multiple calls to set_value() can occur at any time and must be handled correctly by the implementation, * regardless of any asynchronous operation currently running and the status of any promise that a * previous call to set_value() could have returned. - * + * * set_value() must be able, at any moment, to handle the syntax returned by the "read" method of the * osv class in the OpenERP server as well as the syntax used by the set_value() (see below). It must * also be able to handle any other format commonly used in the _defaults key on the models in the addons @@ -1754,16 +1756,16 @@ instance.web.form.FieldInterface = { set_value: function(value_) {}, /** * Get the current value of the widget. - * + * * Must always return a syntaxically correct value to be passed to the "write" method of the osv class in * the OpenERP server, although it is not assumed to respect the constraints applied to the field. * For example if the field is marqued as "required", a call to get_value() can return false. - * + * * get_value() can also be called *before* a call to set_value() and, in that case, is supposed to * return a defaut value according to the type of field. - * + * * This method is always assumed to perform synchronously, it can not return a promise. - * + * * If there was no user interaction to modify the value of the field, it is always assumed that * get_value() return the same semantic value than the one passed in the last call to set_value(), * altough the syntax can be different. This can be the case for type of fields that have a different @@ -1793,14 +1795,14 @@ instance.web.form.FieldInterface = { /** * Abstract class for classes implementing FieldInterface. - * + * * Properties: * - effective_readonly: when it is true, the widget is displayed as readonly. Vary depending * the values of the "readonly" property and the "force_readonly" property on the field manager. * - value: useful property to hold the value of the field. By default, set_value() and get_value() * set and retrieve the value property. Changing the value property also triggers automatically * a 'changed_value' event that inform the view to trigger on_changes. - * + * */ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.web.form.FieldInterface, { /** @@ -1819,7 +1821,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.string = this.node.attrs.string || this.field.string || this.name; this.set({'value': false}); this.set({required: this.modifiers['required'] === true}); - + // some events to make the property "effective_readonly" sync automatically with "readonly" and // "force_readonly" this.set({"readonly": this.modifiers['readonly'] === true}); @@ -1829,7 +1831,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w this.on("change:readonly", this, test_effective_readonly); this.on("change:force_readonly", this, test_effective_readonly); _.bind(test_effective_readonly, this)(); - + this.on("change:value", this, function() { if (! this._inhibit_on_change) this.trigger('changed_value'); @@ -2011,7 +2013,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we }); instance.web.form.FieldID = instance.web.form.FieldChar.extend({ - + }); instance.web.form.FieldEmail = instance.web.form.FieldChar.extend({ @@ -2404,7 +2406,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan } else { var self = this; var option = _(this.values) - .detect(function (record) { return record[0] === self.get('value'); }); + .detect(function (record) { return record[0] === self.get('value'); }); this.$element.text(option ? option[1] : this.values[0][1]); } }, @@ -2583,7 +2585,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc render_editable: function() { var self = this; this.$input = this.$element.find("input"); - + self.$input.tipsy({ title: function() { return "No element was selected, you should create or select one from the dropdown list."; @@ -2591,10 +2593,10 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc trigger:'manual', fade: true, }); - + this.$drop_down = this.$element.find(".oe_m2o_drop_down_button"); this.$follow_button = $(".oe_m2o_cm_button", this.$element); - + this.$follow_button.click(function() { if (!self.get('value')) { self.focus(); @@ -2888,7 +2890,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }, load_views: function() { var self = this; - + var modes = this.node.attrs.mode; modes = !!modes ? modes.split(",") : ["tree"]; var views = []; @@ -3470,7 +3472,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in $("textarea", self.$element).css("padding-left", "3px"); self.tags.addTags(_.map(data, function(el) {return {name: el[1], id:el[0]};})); } else { - self.$element.html(QWeb.render("FieldMany2ManyTags.box", {elements: data})); + self.$element.html(QWeb.render("FieldMany2ManyTag", {elements: data})); } }; if (! self.get('values') || self.get('values').length > 0) { @@ -3642,7 +3644,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend( this.dataset.on_unlink.add_last(function(ids) { self.dataset_changed(); }); - + this.is_setted.then(function() { self.load_view(); }); @@ -3758,7 +3760,7 @@ instance.web.form.Many2ManyKanbanView = instance.web_kanban.KanbanView.extend({ }); instance.web.form.Many2ManyQuickCreate = instance.web.Widget.extend({ template: 'Many2ManyKanban.quick_create', - + /** * close_btn: If true, the widget will display a "Close" button able to trigger * a "close" event. @@ -3874,8 +3876,8 @@ instance.web.form.AbstractFormPopup = instance.web.OldWidget.extend({ var self = this; this.renderElement(); new instance.web.Dialog(this, { - width: '90%', min_width: '800px', + dialogClass: 'oe_act_window', close: function() { self.check_exit(true); }, @@ -4451,7 +4453,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ this.selection = []; // get fold information from widget var fold = ((this.node.attrs || {}).statusbar_fold || true); - // build final domain: if fold option required, add the + // build final domain: if fold option required, add the if (fold == true) { var domain = new instance.web.CompoundDomain(['|'], ['&'], self.build_domain(), [['fold', '=', false]], [['id', '=', self.selected_value]]); } else { @@ -4483,7 +4485,7 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ var shown = _.map(((this.node.attrs || {}).statusbar_visible || "").split(","), function(x) { return _.str.trim(x); }); shown = _.select(shown, function(x) { return x.length > 0; }); - + if (shown.length == 0) { this.to_show = this.selection; } else { diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index a79e25a1474..7ac501e6e72 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1052,7 +1052,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. render_cell: function () { return self.render_cell.apply(self, arguments); } }, this))); - this.pad_table_to(5); + this.pad_table_to(4); }, pad_table_to: function (count) { if (this.records.length >= count || diff --git a/addons/web/static/src/js/view_tree.js b/addons/web/static/src/js/view_tree.js index e8bd7351f1f..2181b2aa157 100644 --- a/addons/web/static/src/js/view_tree.js +++ b/addons/web/static/src/js/view_tree.js @@ -63,6 +63,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie } return fields; }, + store_record:function(records){ + var self = this; + _(records).each(function (record) { + self.records[record.id] = record; + }); + }, on_loaded: function (fields_view) { var self = this; var has_toolbar = !!fields_view.arch.attrs.toolbar; @@ -87,17 +93,19 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie this.$element.addClass(this.fields_view.arch.attrs['class']); this.dataset.read_slice(this.fields_list()).then(function(records) { + self.store_record(records); if (!has_toolbar) { // WARNING: will do a second read on the same ids, but only on // first load so not very important - self.getdata(null, _(records).pluck('id')); + self.render_data({'null':records}) + self.getdata(_.pluck(records,"id")); return; } var $select = self.$element.find('select') .change(function () { var $option = $(this).find(':selected'); - self.getdata($option.val(), $option.data('children')); + self.getdata($option.val()); }); _(records).each(function (record) { self.records[record.id] = record; @@ -112,7 +120,12 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie $select.change(); } }); - + this.$element.find("#tree_view_expand").click(function(){ + self.expand_all(); + }); + this.$element.find("#tree_view_collapse").click(function(){ + self.collpase_all(); + }); // TODO store open nodes in url ?... this.do_push_state({}); @@ -128,6 +141,22 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie return [color, py.parse(py.tokenize(expr)), expr]; }).value(); }, + expand_all: function(){ + var self = this; + var tr = this.$element.find(".oe-treeview-table tbody tr[id^='treerow_']"); + _.each(tr,function(rec){ + self.showcontent($(rec).attr('data-id'),true); + }); + }, + collpase_all: function(){ + var self = this; + var root_tr = this.$element.find(".oe-treeview-table tbody tr[data-level='"+1+"']"); + _.each(root_tr,function(rec){ + if($(rec).hasClass('oe_open')){ + self.showcontent($(rec).attr('data-id'),false); + } + }); + }, /** * Returns the color for the provided record in the current view (from the * ``@colors`` attribute) @@ -164,50 +193,44 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie }); this.$element.delegate('.treeview-tr', 'click', function () { - var is_loaded = 0, - $this = $(this), + var $this = $(this), record_id = $this.data('id'), - record = self.records[record_id], - children_ids = record[self.children_field]; - - _(children_ids).each(function(childid) { - if (self.$element.find('#treerow_' + childid).length) { - if (self.$element.find('#treerow_' + childid).is(':hidden')) { - is_loaded = -1; - } else { - is_loaded++; - } - } - }); - if (is_loaded === 0) { - if (!$this.parent().hasClass('oe_open')) { - self.getdata(record_id, children_ids); - } - } else { - self.showcontent(record_id, is_loaded < 0); - } + bool = $this.parent().hasClass('oe_open'); + self.showcontent(record_id, !bool); }); }, // get child data of selected value - getdata: function (id, children_ids) { + getdata: function (id) { var self = this; - - self.dataset.read_ids(children_ids, this.fields_list()).then(function(records) { - _(records).each(function (record) { - self.records[record.id] = record; - }); - - var $curr_node = self.$element.find('#treerow_' + id); + var parent_child ={}; + id = _.isArray(id)?id:parseInt(id); + var ir_model_data = new instance.web.Model(this.model,self.dataset.get_context() || {},[['id','child_of',id]]).query(); + ir_model_data._execute().then(function(records){ + self.store_record(records); + _.each(records,function(rec){ + if(rec[self.children_field].length === 0)return; + parent_child[rec.id] = []; + _.each(rec[self.children_field],function(key){ + parent_child[rec.id].push(self.records[key]); + }); + }) + self.render_data(parent_child); + }); + }, + render_data: function(groupby){ + var self = this; + _.each(_.keys(groupby),function(key){ + var $curr_node = self.$element.find('#treerow_' + key); + var record = groupby[key]; var children_rows = QWeb.render('TreeView.rows', { - 'records': records, + 'records': record, 'children_field': self.children_field, 'fields_view': self.fields_view.arch.children, 'fields': self.fields, - 'level': $curr_node.data('level') || 0, + 'level': ($curr_node.data('level') || 0) + 1, 'render': instance.web.format_value, 'color_for': self.color_for }); - if ($curr_node.length) { $curr_node.addClass('oe_open'); $curr_node.after(children_rows); @@ -215,8 +238,10 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie self.$element.find('tbody').html(children_rows); } }); + self.collpase_all(); }, + // Get details in listview activate: function(id) { var self = this; @@ -259,13 +284,5 @@ instance.web.TreeView = instance.web.View.extend(/** @lends instance.web.TreeVie }, this); }, - do_show: function () { - this.$element.show(); - }, - - do_hide: function () { - this.$element.hide(); - this.hidden = true; - } }); }; diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 6586807264d..e11adb9d595 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -10,29 +10,112 @@ instance.web.ActionManager = instance.web.Widget.extend({ init: function(parent) { this._super(parent); this.inner_action = null; - this.inner_viewmanager = null; + this.inner_widget = null; this.dialog = null; - this.dialog_viewmanager = null; - this.client_widget = null; + this.dialog_widget = null; + this.breadcrumbs = []; + }, + start: function() { + this._super.apply(this, arguments); + this.$element.on('click', '.oe_breadcrumb_item', this.on_breadcrumb_clicked); }, dialog_stop: function () { if (this.dialog) { - this.dialog_viewmanager.destroy(); - this.dialog_viewmanager = null; + this.dialog_widget.destroy(); + this.dialog_widget = null; this.dialog.destroy(); this.dialog = null; } }, - content_stop: function () { - if (this.inner_viewmanager) { - this.inner_viewmanager.destroy(); - this.inner_viewmanager = null; + /** + * Add a new item to the breadcrumb + * + * If the title of an item is an array, the multiple title mode is in use. + * (eg: a widget with multiple views might need to display a title for each view) + * In multiple title mode, the show() callback can check the index it receives + * in order to detect which of its titles has been clicked on by the user. + * + * @param {Object} item breadcrumb item + * @param {Object} item.widget widget containing the view(s) to be added to the breadcrumb added + * @param {Function} [item.show] triggered whenever the widget should be shown back + * @param {Function} [item.hide] triggered whenever the widget should be shown hidden + * @param {Function} [item.destroy] triggered whenever the widget should be destroyed + * @param {String|Array} [item.title] title(s) of the view(s) to be displayed in the breadcrumb + * @param {Function} [item.get_title] should return the title(s) of the view(s) to be displayed in the breadcrumb + */ + push_breadcrumb: function(item) { + var last = this.breadcrumbs.slice(-1)[0]; + if (last) { + last.hide(); + } + var item = _.extend({ + show: function(index) { + this.widget.$element.show(); + }, + hide: function() { + this.widget.$element.hide(); + }, + destroy: function() { + this.widget.destroy(); + }, + get_title: function() { + return this.title || this.widget.get('title'); + } + }, item); + item.id = _.uniqueId('breadcrumb_'); + this.breadcrumbs.push(item); + }, + on_breadcrumb_clicked: function(ev) { + var $e = $(ev.target); + var id = $e.data('id'); + var item; + for (var i = this.breadcrumbs.length - 1; i >= 0; i--) { + var it = this.breadcrumbs[i]; + if (it.id == id) { + item = it; + break; + } + this.remove_breadcrumb(i); + } + var index = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); + item.show(index, $e); + this.inner_widget = item.widget; + }, + clear_breadcrumbs: function() { + while (this.breadcrumbs.length) { + this.remove_breadcrumb(0); } - if (this.client_widget) { - this.client_widget.destroy(); - this.client_widget = null; + }, + remove_breadcrumb: function(index) { + var item = this.breadcrumbs.splice(index, 1)[0]; + if (item) { + var dups = _.filter(this.breadcrumbs, function(it) { + return item.widget === it.widget; + }); + if (!dups.length) { + item.destroy(); + } } }, + get_title: function() { + var titles = []; + for (var i = 0; i < this.breadcrumbs.length; i += 1) { + var item = this.breadcrumbs[i]; + var tit = item.get_title(); + if (!_.isArray(tit)) { + tit = [tit]; + } + for (var j = 0; j < tit.length; j += 1) { + var label = _.escape(tit[j]); + if (i === this.breadcrumbs.length - 1 && j === tit.length - 1) { + titles.push(label); + } else { + titles.push(_.str.sprintf('<a href="#" class="oe_breadcrumb_item" data-id="%s">%s</a>', item.id, label)); + } + } + } + return titles.join(' / '); + }, do_push_state: function(state) { if (this.getParent() && this.getParent().do_push_state) { if (this.inner_action) { @@ -49,7 +132,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ var self = this, action_loaded; if (state.action_id) { - var run_action = (!this.inner_viewmanager) || this.inner_viewmanager.action.id !== state.action_id; + var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action_id; if (run_action) { this.null_action(); action_loaded = this.do_action(state.action_id); @@ -89,13 +172,13 @@ instance.web.ActionManager = instance.web.Widget.extend({ } $.when(action_loaded || null).then(function() { - if (self.inner_viewmanager) { - self.inner_viewmanager.do_load_state(state, warm); + if (self.inner_widget && self.inner_widget.do_load_state) { + self.inner_widget.do_load_state(state, warm); } }); }, do_action: function(action, on_close) { - if (_.isNumber(action)) { + if (_.isNumber(action) || _.isString(action)) { var self = this; return self.rpc("/web/action/load", { action_id: action }, function(result) { self.do_action(result.result, on_close); @@ -124,7 +207,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ }, null_action: function() { this.dialog_stop(); - this.content_stop(); + this.clear_breadcrumbs(); }, ir_actions_act_window: function (action, on_close) { var self = this; @@ -137,29 +220,31 @@ instance.web.ActionManager = instance.web.Widget.extend({ } if (action.target === 'new') { if (this.dialog === null) { - this.dialog = new instance.web.Dialog(this, { width: '80%' }); + // These buttons will be overwrited by <footer> if any + this.dialog = new instance.web.Dialog(this, { + buttons: { "Close": function() { $(this).dialog("close"); }}, + dialogClass: 'oe_act_window' + }); if(on_close) this.dialog.on_close.add(on_close); } else { - this.dialog_viewmanager.destroy(); + this.dialog_widget.destroy(); } this.dialog.dialog_title = action.name; - this.dialog_viewmanager = new instance.web.ViewManagerAction(this.dialog, action); - this.dialog_viewmanager.appendTo(this.dialog.$element); - this.dialog_viewmanager.$element.addClass("oe_view_manager_" + (action.target || 'current')); + this.dialog_widget = new instance.web.ViewManagerAction(this, action); + this.dialog_widget.appendTo(this.dialog.$element); this.dialog.open(); } else { this.dialog_stop(); - this.content_stop(); if(action.menu_id) { return this.getParent().do_action(action, function () { instance.webclient.menu.open_menu(action.menu_id); }); } this.inner_action = action; - this.inner_viewmanager = new instance.web.ViewManagerAction(this, action); - this.inner_viewmanager.appendTo(this.$element); - this.inner_viewmanager.$element.addClass("oe_view_manager_" + (action.target || 'current')); + var inner_widget = this.inner_widget = new instance.web.ViewManagerAction(this, action); + inner_widget.add_breadcrumb(); + this.inner_widget.appendTo(this.$element); } }, ir_actions_act_window_close: function (action, on_closed) { @@ -178,10 +263,14 @@ instance.web.ActionManager = instance.web.Widget.extend({ }); }, ir_actions_client: function (action) { - this.content_stop(); this.dialog_stop(); var ClientWidget = instance.web.client_actions.get_object(action.tag); - (this.client_widget = new ClientWidget(this, action.params)).appendTo(this.$element); + this.inner_widget = new ClientWidget(this, action.params); + this.push_breadcrumb({ + widget: this.inner_widget, + title: action.name + }); + this.inner_widget.appendTo(this.$element); }, ir_actions_report_xml: function(action, on_closed) { var self = this; @@ -290,35 +379,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ this.active_view = view_type; if (!view.controller) { - // Lazy loading of views - var controllerclass = this.registry.get_object(view_type); - var options = _.clone(view.options); - if (view_type === "form" && this.action) { - switch (this.action.target) { - case 'new': - case 'inline': - options.initial_mode = 'edit'; - break; - } - } - var controller = new controllerclass(this, this.dataset, view.view_id, options); - if (view.embedded_view) { - controller.set_embedded_view(view.embedded_view); - } - controller.do_switch_view.add_last(_.bind(this.switch_view, this)); - controller.do_prev_view.add_last(this.on_prev_view); - var container = this.$element.find(".oe_view_manager_view_" + view_type); - view_promise = controller.appendTo(container); - this.views[view_type].controller = controller; - this.views[view_type].deferred.resolve(view_type); - $.when(view_promise).then(function() { - self.on_controller_inited(view_type, controller); - if (self.searchview - && self.flags.auto_search - && view.controller.searchable !== false) { - self.searchview.ready.then(self.searchview.do_search); - } - }); + view_promise = this.do_create_view(view_type); } else if (this.searchview && self.flags.auto_search && view.controller.searchable !== false) { @@ -347,14 +408,90 @@ instance.web.ViewManager = instance.web.Widget.extend({ container.hide(); controller.do_hide(); } + // put the <footer> in the dialog's buttonpane + if (self.$element.parent('.ui-dialog-content') && self.$element.find('footer')) { + self.$element.parent('.ui-dialog-content').parent().find('div.ui-dialog-buttonset').hide() + self.$element.find('footer').appendTo( + self.$element.parent('.ui-dialog-content').parent().find('div.ui-dialog-buttonpane') + ); + } } }); - - self.$element.find('.oe_view_title_text:first').text( - self.display_title()); }); return view_promise; }, + do_create_view: function(view_type) { + // Lazy loading of views + var self = this; + var view = this.views[view_type]; + var controllerclass = this.registry.get_object(view_type); + var options = _.clone(view.options); + if (view_type === "form" && this.action) { + switch (this.action.target) { + case 'new': + case 'inline': + options.initial_mode = 'edit'; + break; + } + } + var controller = new controllerclass(this, this.dataset, view.view_id, options); + + controller.on("change:title", this, function() { + if (self.active_view === view_type) { + self.set_title(controller.get('title')); + } + }); + + if (view.embedded_view) { + controller.set_embedded_view(view.embedded_view); + } + controller.do_switch_view.add_last(_.bind(this.switch_view, this)); + + controller.do_prev_view.add_last(this.on_prev_view); + var container = this.$element.find(".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); + return $.when(view_promise).then(function() { + self.on_controller_inited(view_type, controller); + if (self.searchview + && self.flags.auto_search + && view.controller.searchable !== false) { + self.searchview.ready.then(self.searchview.do_search); + } + }); + }, + set_title: function(title) { + this.$element.find('.oe_view_title_text:first').text(title); + }, + add_breadcrumb: function() { + var self = this; + var views = [this.active_view || this.views_src[0].view_type]; + this.on_mode_switch.add(function(mode) { + var last = views.slice(-1)[0]; + if (mode !== last) { + if (mode !== 'form') { + views.length = 0; + } + views.push(mode); + } + }); + this.getParent().push_breadcrumb({ + widget: this, + show: function(index, $e) { + var view_to_select = views[index]; + self.$element.show(); + if (self.active_view !== view_to_select) { + self.on_mode_switch(view_to_select); + } + }, + get_title: function() { + return _.map(views, function(v) { + return self.views[v].controller.get('title'); + }); + } + }); + }, /** * Method used internally when a view asks to switch view. This method is meant * to be extended by child classes to change the default behavior, which simply @@ -447,14 +584,6 @@ instance.web.ViewManager = instance.web.Widget.extend({ */ on_action_executed: function () { }, - display_title: function () { - var view = this.views[this.active_view]; - if (view) { - // ick - return view.controller.fields_view.arch.attrs.string; - } - return ''; - } }); instance.web.ViewManagerAction = instance.web.ViewManager.extend({ @@ -499,7 +628,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ if (this.session.hidden_menutips) { return; } - this.session.hidden_menutips = {} + this.session.hidden_menutips = {}; }, /** * Initializes the ViewManagerAction: sets up the searchview (if the @@ -527,6 +656,7 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ var manager_ready = $.when(searchview_loaded, main_view_loaded); this.$element.find('.oe_debug_view').change(this.on_debug_changed); + this.$element.addClass("oe_view_manager_" + (this.action.target || 'current')); if (this.action.help && !this.flags.low_profile) { var Users = new instance.web.DataSet(self, 'res.users'), @@ -675,12 +805,18 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ view: controller, view_manager: self })); - if (!self.action.name && fvg) { - self.$element.find('.oe_view_title_text').text(fvg.arch.attrs.string || fvg.name); - } - + self.set_title(); }); }, + do_create_view: function(view_type) { + var r = this._super.apply(this, arguments); + var view = this.views[view_type].controller; + view.set({ 'title': this.action.name }); + return r; + }, + set_title: function(title) { + this.$element.find('.oe_breadcrumb_title:first').html(this.getParent().get_title()); + }, do_push_state: function(state) { if (this.getParent() && this.getParent().do_push_state) { state["view_type"] = this.active_view; @@ -702,9 +838,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ self.views[self.active_view].controller.do_load_state(state, warm); }); }, - display_title: function () { - return this.action.name; - } }); instance.web.Sidebar = instance.web.Widget.extend({ @@ -1130,7 +1263,7 @@ instance.web.View = instance.web.Widget.extend({ args.push(context); return dataset.call_button(action_data.name, args, handler); } else if (action_data.type=="action") { - return this.rpc('/web/action/load', { action_id: parseInt(action_data.name, 10), context: context, do_not_eval: true}, handler); + return this.rpc('/web/action/load', { action_id: action_data.name, context: context, do_not_eval: true}, handler); } else { return dataset.exec_workflow(record_id, action_data.name, handler); } diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index a8d7a061a81..3f1478d3b1b 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -399,16 +399,17 @@ <t t-name="ViewManager"> <div class="oe_view_manager"> <table class="oe_view_manager_header"> - <col width="33%"/> - <col width="33%"/> - <col width="34%"/> + <col width="20%"/> + <col width="25%"/> + <col width="20%"/> + <col width="35%"/> <tr class="oe_header_row oe_header_row_top"> <td colspan="2"> <h2 class="oe_view_title" t-if="widget.flags.display_title !== false"> - <span class="oe_view_title_text"><t t-esc="widget.display_title()"/></span> + <span class="oe_view_title_text oe_breadcrumb_title"/> </h2> </td> - <td> + <td colspan="2"> <div class="oe_view_manager_view_search" t-opentag="true"/> </td> </tr> @@ -416,7 +417,7 @@ <td> <div class="oe_view_manager_buttons"/> </td> - <td> + <td colspan="2"> <div class="oe_view_manager_sidebar"/> </td> <td> @@ -535,14 +536,16 @@ </t> <t t-name="TreeView"> - <select t-if="toolbar" style="width: 30%"> - </select> - <table class="oe_tree_table"> + <div class = "tree_header"> + <select t-if="toolbar" ></select> + <button id = "tree_view_collapse">Collapse All</button> + <button id = "tree_view_expand">Expand All</button> + </div> + <table class="oe-treeview-table"> <thead> <tr> <th t-foreach="fields_view" t-as="field" - t-if="!field.attrs.modifiers.tree_invisible" - class="treeview-header"> + t-if="!field.attrs.modifiers.tree_invisible"> <t t-esc="fields[field.attrs.name].string" /> </th> </tr> @@ -554,11 +557,11 @@ <tr t-name="TreeView.rows" t-foreach="records" t-as="record" t-att-id="'treerow_' + record.id" - t-att-data-id="record.id" t-att-data-level="level + 1"> + t-att-data-id="record.id" t-att-data-level="level"> <t t-set="children" t-value="record[children_field]"/> <t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/> - <t t-set="rank" t-value="'oe_tree_first'"/> - <t t-set="style" t-value="'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;'"/> + <t t-set="rank" t-value="'oe-treeview-first'"/> + <t t-set="style" t-value="'background-position: ' + 19*(level-1) + 'px; padding-left: ' + 19*(level-1) + 'px;'"/> <td t-foreach="fields_view" t-as="field" t-if="!field.attrs.modifiers.tree_invisible" @@ -959,18 +962,20 @@ </t> </span> </t> +<!-- Collection of m2m tags --> <t t-name="FieldMany2ManyTags"> - <div class="oe_form_field oe_form_field_many2manytags" t-att-style="widget.node.attrs.style"> + <div class="oe_form_field oe_tags" t-att-style="widget.node.attrs.style"> <t t-if="! widget.get('effective_readonly')"> <textarea rows="1" style="width: 100%" t-att-placeholder="widget.node.attrs.placeholder"></textarea> </t> </div> </t> -<t t-name="FieldMany2ManyTags.box"> +<!-- Individual m2m tag element --> +<t t-name="FieldMany2ManyTag"> <t t-set="i" t-value="0"/> <t t-foreach="elements" t-as="el"> - <span class="oe_form_field_many2manytags_box" t-att-data-index="i"> + <span class="oe_tag" t-att-data-index="i"> <t t-esc="el[1]"/> </span> <t t-set="i" t-value="i + 1"/> @@ -1467,11 +1472,11 @@ </t> <t t-name="AbstractFormPopup.buttons"> <t t-if="! multi_select"> - <button type="button" class="oe_button oe_abstractformpopup-form-save">Save</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save</button> </t> <t t-if="multi_select"> - <button type="button" class="oe_button oe_abstractformpopup-form-save-new">Save & New</button> - <button type="button" class="oe_button oe_abstractformpopup-form-save">Save & Close</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save-new oe_highlight">Save & New</button> + <button type="button" class="oe_button oe_abstractformpopup-form-save oe_highlight">Save & Close</button> </t> <button type="button" class="oe_button oe_abstractformpopup-form-close">Cancel</button> </t> |
