diff options
| author | Fabien Pinckaers <fp@tinyerp.com> | 2012-08-09 16:29:23 +0200 |
|---|---|---|
| committer | Fabien Pinckaers <fp@tinyerp.com> | 2012-08-09 16:29:23 +0200 |
| commit | 93f47bb8368066a26211ae106975cadd3c52a9f8 (patch) | |
| tree | 6bc15c2c8eca3d2b746aeb0cbac0a408c10de363 /addons/web/static/src | |
| parent | 2043809be494efb256a6a8d0147a49a614b099c8 (diff) | |
| parent | e46fb9fda8ba93d3eb8ac2907a75012f7a4d920e (diff) | |
[merge] trunk
bzr revid: fp@tinyerp.com-20120809142923-qgk5ckssel2k36mk
Diffstat (limited to 'addons/web/static/src')
| -rw-r--r-- | addons/web/static/src/css/base.css | 291 | ||||
| -rw-r--r-- | addons/web/static/src/css/base.sass | 268 | ||||
| -rw-r--r-- | addons/web/static/src/img/graph_background.png | bin | 0 -> 3920 bytes | |||
| -rw-r--r-- | addons/web/static/src/img/view_empty_arrow.png | bin | 2308 -> 4157 bytes | |||
| -rw-r--r-- | addons/web/static/src/js/boot.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/chrome.js | 229 | ||||
| -rw-r--r-- | addons/web/static/src/js/corelib.js | 7 | ||||
| -rw-r--r-- | addons/web/static/src/js/coresetup.js | 48 | ||||
| -rw-r--r-- | addons/web/static/src/js/data.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/data_import.js | 2 | ||||
| -rw-r--r-- | addons/web/static/src/js/formats.js | 78 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_editor.js | 1212 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_form.js | 214 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list.js | 346 | ||||
| -rw-r--r-- | addons/web/static/src/js/view_list_editable.js | 32 | ||||
| -rw-r--r-- | addons/web/static/src/js/views.js | 153 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 174 |
17 files changed, 1186 insertions, 1876 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index 1519478ee89..eab9c61acd2 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -78,7 +78,15 @@ background: white; /* http://www.quirksmode.org/dom/inputfile.html * http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image - */ + */ */ +} +.openerp :-moz-placeholder { + color: #afafb6 !important; + font-style: italic !important; +} +.openerp ::-webkit-input-placeholder { + color: #afafb6 !important; + font-style: italic !important; } .openerp a { text-decoration: none; @@ -504,6 +512,14 @@ .openerp .oe_avatar + div { margin-left: 5px; } +.openerp .oe_image_small > img { + max-width: 50px; + max-height: 50px; +} +.openerp .oe_image_medium > img { + max-width: 180px; + max-height: 180px; +} .openerp .oe_button.oe_link { border: none; padding: 0; @@ -549,10 +565,6 @@ .openerp .oe_webclient .oe_star_on { color: gold; } -.openerp .oe_bounce { - -moz-animation: bounce 0.4s linear; - -webkit-animation: bounce 0.4s linear; -} .openerp .oe_tag { border: 1px solid #afafb6; font-size: 11px; @@ -599,6 +611,19 @@ .openerp.oe_tooltip .oe_tooltip_technical_title { font-weight: bold; } +.openerp.oe_tooltip .oe_tooltip_close { + margin: -5px 0 0 2px; + cursor: default; + float: right; + color: white; +} +.openerp.oe_tooltip .oe_tooltip_close:hover { + color: #999999; + cursor: pointer; +} +.openerp.oe_tooltip .oe_tooltip_message { + max-width: 310px; +} .openerp .oe_notebook { margin: 8px 0; padding: 0 16px; @@ -1810,15 +1835,29 @@ margin: 0 0 0 4px; padding: 0; } -.openerp .oe_view_nocontent > img { - float: left; - margin: 1.5em; -} -.openerp .oe_view_nocontent > div { - overflow: hidden; - padding: 35px 0px 0px 0px; - max-width: 700px; +.openerp .oe_view_nocontent { + padding: 15px; + margin-top: 0; + color: #777777; font-size: 125%; + max-width: 700px; +} +.openerp .oe_view_nocontent .oe_view_nocontent_create { + background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 7px 0; + margin-top: 0; + padding-top: 35px; + min-height: 28px; + color: #4c4c4c; +} +.openerp .oe_view_nocontent > p { + padding-left: 95px; +} +.openerp .oe_view_nocontent .oe_empty_custom_dashboard { + background: transparent url(/web/static/src/img/graph_background.png) no-repeat 0 0; + margin-top: -15px; + padding: 100px 0 0 137px; + min-height: 327px; + margin-left: -15px; } .openerp .oe_formview { background: white; @@ -1910,6 +1949,16 @@ max-width: 860px; margin: 0 auto; } +.openerp .oe_form div.oe_form_configuration div.oe_horizontal_separator { + margin: 25px 0 10px 0; +} +.openerp .oe_form div.oe_form_configuration p { + color: #aaaaaa; + max-width: 650px; +} +.openerp .oe_form div.oe_form_configuration label { + min-width: 150px; +} .openerp ul.oe_form_steps { height: 30px; padding: 0; @@ -1947,6 +1996,105 @@ font-weight: bold; color: #b33630; } +.openerp ul.oe_form_steps_clickable { + height: 30px; + margin: 0; + padding: 0; + text-shadow: 0 1px 1px #cacaca; + box-shadow: 0 0 1px rgba(0, 0, 0, 0.5); + overflow: hidden; +} +.openerp ul.oe_form_steps_clickable li { + border-right: none; + padding: 0 0 0 12px; + position: relative; + float: left; + vertical-align: top; + height: 30px; + color: white; +} +.openerp ul.oe_form_steps_clickable li:after { + content: " "; + width: 0; + height: 0; + border-top: 21px solid transparent; + border-bottom: 21px solid transparent; + border-left: 5px solid #807fb4; + position: absolute; + top: 50%; + margin-top: -21px; + left: 100%; + z-index: 2; +} +.openerp ul.oe_form_steps_clickable li:hover:after { + border-left: 5px solid #807fb4; +} +.openerp ul.oe_form_steps_clickable li:before { + content: " "; + width: 0; + height: 0; + border-top: 21px solid transparent; + border-bottom: 21px solid transparent; + border-left: 5px solid white; + position: absolute; + top: 50%; + margin-top: -21px; + margin-left: 2px; + left: 100%; + z-index: 2; +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_active { + font-weight: bold; + text-shadow: 0 1px 1px #999999; + box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.25), inset 0 1px 1px rgba(255, 255, 255, 0.25); + background-color: #dc5f59; + background: -webkit-linear-gradient(top, #dc5f59, #b33630); + color: white; +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_inactive { + cursor: pointer; + box-shadow: inset 0 -1px 1px rgba(0, 0, 0, 0.25), inset 0 1px 1px rgba(255, 255, 255, 0.25); + background-color: #adadcf; + background: -webkit-linear-gradient(top, #adadcf, #7c7ba7); +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_inactive div { + padding: 0 30px 0 0; +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_inactive:hover { + background: -webkit-linear-gradient(top, #7c7ba7, #adadcf); +} +.openerp ul.oe_form_steps_clickable li div { + padding: 0 30px 0 0; +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_active:after { + content: " "; + display: block; + width: 0; + height: 0; + border-top: 21px solid transparent; + border-bottom: 21px solid transparent; + border-left: 5px solid #b33630; + position: absolute; + top: 50%; + margin-top: -21px; + left: 100%; + z-index: 2; +} +.openerp ul.oe_form_steps_clickable li.oe_form_steps_active:before { + content: " "; + display: block; + width: 0; + height: 0; + border-top: 21px solid transparent; + border-bottom: 21px solid transparent; + border-left: 5px solid white; + position: absolute; + top: 50%; + margin-top: -21px; + margin-left: 2px; + left: 100%; + z-index: 2; +} .openerp .oe_form .oe_subtotal_footer { width: 1% !important; } @@ -2003,7 +2151,7 @@ } .openerp .oe_form td.oe_form_group_cell_label { border-right: 1px solid #dddddd; - padding: 2px 0px 2px 0px; + padding: 4px 0px 4px 0px; } .openerp .oe_form td.oe_form_group_cell_label label { line-height: 18px; @@ -2015,7 +2163,7 @@ } .openerp .oe_form .oe_form_group { width: 100%; - margin: 6px 0 6px 0; + margin: 9px 0 9px 0; } .openerp .oe_form .oe_form_group .oe_form_group_cell.oe_group_right { padding-left: 20px; @@ -2040,7 +2188,7 @@ font-weight: bold; font-size: 20px; margin: 8px 0px 8px 0px; - color: #aaaabb; + color: #53637e; } .openerp .oe_horizontal_separator:empty { height: 5px; @@ -2099,7 +2247,7 @@ width: 100%; display: inline-block; padding: 2px 2px 2px 0px; - line-height: 18px; + line-height: 1em; } .openerp .oe_form .oe_form_field input { margin: 0px; @@ -2188,10 +2336,10 @@ overflow: hidden; } .openerp .oe_form_editable .oe_form .oe_form_field_integer { - width: 7em !important; + width: 6em !important; } .openerp .oe_form_editable .oe_form .oe_form_field_float { - width: 8em !important; + width: 7em !important; } .openerp .oe_form_editable .oe_form .oe_form_field_date { width: 7.5em !important; @@ -2250,10 +2398,18 @@ } .openerp .oe_form_field_many2one .oe_m2o_cm_button { line-height: 14px; + float: right; + padding-left: 2px; } .openerp .oe_form .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page { display: none; } +.openerp .oe_form_field_one2many > .oe_view_manager .oe_list_pager_single_page, .openerp .oe_form_field_many2many > .oe_view_manager .oe_list_pager_single_page { + display: none !important; +} +.openerp .oe_form_field_one2many .oe_form_field_one2many_list_row_add, .openerp .oe_form_field_many2many .oe_form_field_one2many_list_row_add { + font-weight: bold; +} .openerp .oe_form_field_one2many .oe_list_content > thead, .openerp .oe_form_field_many2many .oe_list_content > thead { border-bottom: 1px; } @@ -2287,6 +2443,49 @@ .openerp .oe_form_field_one2many .oe_list_buttons.oe_editing .oe_list_save, .openerp .oe_form_field_many2many .oe_list_buttons.oe_editing .oe_list_save { visibility: hidden; } +.openerp .oe_form_editable .oe_list_editable .oe_list_content td.oe_required { + background-color: #d2d2ff; +} +.openerp .oe_form_editable .oe_list_editable .oe_list_content td.oe_readonly { + background-color: #eeeeee; +} +.openerp .oe_list_editable .oe_list_content td.oe_list_field_cell { + padding: 4px 6px 3px 6px; +} +.openerp .oe_list.oe_list_editable td.oe_list_record_delete { + position: absolute; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_m2o_drop_down_button { + top: 5px; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_m2o_cm_button { + display: none; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input { + height: 27px; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea { + border: 1px solid #aaaaff; + border-radius: 0px; + margin: 0px; + -webkit-border-radius: 0px; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field textarea { + height: 60px; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_float input, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_view_integer input { + text-align: right; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime > span, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date > span { + width: 100%; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime input.oe_datepicker_master, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date input.oe_datepicker_master { + width: 100% !important; +} +.openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_field_float, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field .oe_form_view_integer, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_datetime, .openerp .oe_list.oe_list_editable.oe_editing .oe_form_field.oe_form_field_date { + min-width: 0 !important; + max-width: none !important; +} .openerp .oe_form .oe_form_field_many2many > .oe_list .oe_list_pager_single_page { display: none; } @@ -2305,6 +2504,11 @@ .openerp .oe_list { position: relative; } +.openerp .oe_list .oe_form .oe_form_nosheet { + margin: 0; + padding: 0; + border: none; +} .openerp .oe_list .oe_form .oe_form_field { width: auto; position: absolute; @@ -2400,15 +2604,6 @@ background: #eeeeee; font-weight: bold; } -.openerp .oe_list_content > tbody tr:hover td, .openerp .oe_list_content tbody tr:hover th { - background-color: #eeeeee; - background-image: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#dedede)); - background-image: -webkit-linear-gradient(top, #eeeeee, #dedede); - background-image: -moz-linear-gradient(top, #eeeeee, #dedede); - background-image: -ms-linear-gradient(top, #eeeeee, #dedede); - background-image: -o-linear-gradient(top, #eeeeee, #dedede); - background-image: linear-gradient(to bottom, #eeeeee, #dedede); -} .openerp .oe_list_content .numeric { text-align: right; width: 82px; @@ -2416,6 +2611,25 @@ .openerp .oe_list_content .numeric input { text-align: right; } +.openerp .oe_list_content th.oe_list_header_handle { + font-size: 1px; + overflow: hidden; + text-indent: -9001px; +} +.openerp .oe_list_content td.oe_list_field_handle { + width: 1em; + cursor: ns-resize; +} +.openerp .oe_list_content td.oe_list_field_handle .oe_list_handle { + font-size: 1px; + letter-spacing: -1px; + color: transparent; +} +.openerp .oe_list_content td.oe_list_field_handle .oe_list_handle:before { + font: 21px "mnmliconsRegular"; + content: "ö"; + color: #404040; +} .openerp .tree_header { background-color: #f0f0f0; border-bottom: 1px solid #cacaca; @@ -2471,27 +2685,6 @@ .openerp .oe_trad_field.touched { border: 1px solid green !important; } -.openerp .oe_view_editor { - width: 100%; - border-collapse: collapse; - margin-left: -12px; - width: 100%; - background-color: white; - border-spacing: 0; -} -.openerp .oe_view_editor td { - text-align: center; - white-space: nowrap; - border: 1px solid #d8d8d8; - cursor: pointer; - font-size: 90%; -} -.openerp .oe_view_editor_field td { - border: 0px !important; -} -.openerp .oe_view_editor tr:hover { - background-color: #ecebf2; -} .openerp .oe_layout_debugging .oe_form_group { outline: 2px dashed green; } diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index ddee25c3105..e0e8a3534dc 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -142,6 +142,14 @@ $sheet-max-width: 860px font-size: 13px background: white // }}} + //Placeholder style{{{ + \:-moz-placeholder + color: $facets-border !important + font-style: italic !important + \::-webkit-input-placeholder + color: $facets-border !important + font-style: italic !important + //}}} // Tag reset {{{ a text-decoration: none @@ -152,7 +160,7 @@ $sheet-max-width: 860px font-weight: bold background-color: #f0f0f0 th - border-right: 1px dotted #afafb6 + border-right: 1px dotted $facets-border &:last-child border-right: none th, td @@ -407,6 +415,12 @@ $sheet-max-width: 860px border: none .oe_avatar + div margin-left: 5px + .oe_image_small > img + max-width: 50px + max-height: 50px + .oe_image_medium > img + max-width: 180px + max-height: 180px .oe_button.oe_link @include reset() img @@ -428,9 +442,6 @@ $sheet-max-width: 860px text-decoration: none .oe_star_on color: gold - .oe_bounce - -moz-animation: bounce .40s linear - -webkit-animation: bounce .40s linear // }}} // Tags (for many2many tags, among others) {{{ .oe_tag @@ -470,6 +481,16 @@ $sheet-max-width: 860px list-style: circle .oe_tooltip_technical_title font-weight: bold + .oe_tooltip_close + margin: -5px 0 0 2px + cursor: default + float: right + color: white + &:hover + color: #999 + cursor: pointer + .oe_tooltip_message + max-width: 310px // }}} // Notebook {{{ .oe_notebook @@ -533,7 +554,7 @@ $sheet-max-width: 860px top: 26px left: 0 z-index: 1 - border: 1px solid #afafb6 + border: 1px solid $facets-border background: white padding: 4px 0 min-width: 140px @@ -813,7 +834,7 @@ $sheet-max-width: 860px display: none width: 220px background: #f0eeee - border-right: 1px solid #afafb6 + border-right: 1px solid $facets-border text-shadow: 0 1px 1px white padding-bottom: 16px a.oe_logo @@ -1254,7 +1275,7 @@ $sheet-max-width: 860px background-color: white min-width: 100% display: none - border: 1px solid #afafb6 + border: 1px solid $facets-border text-align: left @include radius(4px) @include box-shadow(0 1px 4px rgba(0,0,0,0.3)) @@ -1409,15 +1430,26 @@ $sheet-max-width: 860px // }}} // Views Common {{{ .oe_view_nocontent - > img - float: left - margin: 1.5em - > div - // don't encroach on my arrow - overflow: hidden - padding: 35px 0px 0px 0px - max-width: 700px - font-size: 125% + padding: 15px + margin-top: 0 + color: #777777 + font-size: 125% + max-width: 700px + .oe_view_nocontent_create + background: transparent url(/web/static/src/img/view_empty_arrow.png) no-repeat 7px 0 + margin-top: 0 + padding-top: 35px + min-height: 28px + color: #4c4c4c + > p + padding-left: 95px + .oe_empty_custom_dashboard + background: transparent url(/web/static/src/img/graph_background.png) no-repeat 0 0 + margin-top: -15px + padding: 100px 0 0 137px + min-height: 327px + margin-left: -15px + // }}} // FormView.base and dynamic tags {{{ .oe_formview @@ -1471,6 +1503,14 @@ $sheet-max-width: 860px min-width: 650px max-width: $sheet-max-width margin: 0 auto + div.oe_form_configuration + div.oe_horizontal_separator + margin: 25px 0 10px 0 + p + color: #aaa + max-width: 650px + label + min-width: 150px ul.oe_form_steps height: 30px padding: 0 @@ -1500,6 +1540,93 @@ $sheet-max-width: 860px .oe_form_steps_active font-weight: bold color: #b33630 + ul.oe_form_steps_clickable + height: 30px + margin: 0 + padding: 0 + text-shadow: 0 1px 1px #cacaca + box-shadow: 0 0 1px rgba(0,0,0,0.5) + overflow: hidden + li + border-right: none + padding: 0 0 0 12px + position: relative + float: left + vertical-align: top + height: 30px + color: white + &:after + content: " " + width: 0 + height: 0 + border-top: 21px solid transparent + border-bottom: 21px solid transparent + border-left: 5px solid #807fb4 + position: absolute + top: 50% + margin-top: -21px + left: 100% + z-index: 2 + &:hover:after + border-left: 5px solid #807fb4 + &:before + content: " " + width: 0 + height: 0 + border-top: 21px solid transparent + border-bottom: 21px solid transparent + border-left: 5px solid white + position: absolute + top: 50% + margin-top: -21px + margin-left: 2px + left: 100% + z-index: 2 + &.oe_form_steps_active + font-weight: bold + text-shadow: 0 1px 1px #999999 + box-shadow: inset 0 -1px 1px rgba(0,0,0,0.25), inset 0 1px 1px rgba(255,255,255,0.25) + background-color: #dc5f59 + background: -webkit-linear-gradient(top, #dc5f59, #b33630) + color: white + &.oe_form_steps_inactive + cursor: pointer + box-shadow: inset 0 -1px 1px rgba(0,0,0,0.25), inset 0 1px 1px rgba(255,255,255,0.25) + background-color: #adadcf + background: -webkit-linear-gradient(top, #adadcf, #7c7ba7) + div + padding: 0 30px 0 0 + &.oe_form_steps_inactive:hover + background: -webkit-linear-gradient(top, #7c7ba7, #adadcf) + div + padding: 0 30px 0 0 + &.oe_form_steps_active:after + content: " " + display: block + width: 0 + height: 0 + border-top: 21px solid transparent + border-bottom: 21px solid transparent + border-left: 5px solid #b33630 + position: absolute + top: 50% + margin-top: -21px + left: 100% + z-index: 2 + &.oe_form_steps_active:before + content: " " + display: block + width: 0 + height: 0 + border-top: 21px solid transparent + border-bottom: 21px solid transparent + border-left: 5px solid white + position: absolute + top: 50% + margin-top: -21px + margin-left: 2px + left: 100% + z-index: 2 .oe_form .oe_subtotal_footer width: 1% !important td.oe_form_group_cell @@ -1533,7 +1660,7 @@ $sheet-max-width: 860px background: white min-height: 330px padding: 16px - border: 1px solid #afafb6 + border: 1px solid $facets-border @include box-shadow(0 0 10px rgba(0,0,0,0.3)) .ui-tabs margin: 0 -16px @@ -1546,7 +1673,7 @@ $sheet-max-width: 860px margin: 2px td.oe_form_group_cell_label border-right: 1px solid #ddd - padding: 2px 0px 2px 0px + padding: 4px 0px 4px 0px label line-height: 18px display: block @@ -1555,7 +1682,7 @@ $sheet-max-width: 860px padding-left: 6px .oe_form_group width: 100% - margin: 6px 0 6px 0 + margin: 9px 0 9px 0 .oe_form_group_cell.oe_group_right padding-left: 20px // }}} @@ -1580,7 +1707,7 @@ $sheet-max-width: 860px font-weight: bold font-size: 20px margin: 8px 0px 8px 0px - color: #aab + color: #53637e .oe_horizontal_separator:empty height: 5px .oe_vertical_separator @@ -1627,7 +1754,7 @@ $sheet-max-width: 860px width: 100% display: inline-block padding: 2px 2px 2px 0px - line-height: 18px + line-height: 1em input margin: 0px input[type="text"], input[type="password"], input[type="file"], select @@ -1694,9 +1821,9 @@ $sheet-max-width: 860px .oe_form_editable .oe_form .oe_form_field_integer - width: 7em !important + width: 6em !important .oe_form_field_float - width: 8em !important + width: 7em !important .oe_form_field_date width: 7.5em !important .oe_form_field_datetime @@ -1751,6 +1878,8 @@ $sheet-max-width: 860px right: 0px .oe_m2o_cm_button line-height: 14px + float: right + padding-left: 2px // }}} // FormView.one2many {{{ .oe_form .oe_form_field_one2many > .oe_view_manager @@ -1758,6 +1887,11 @@ $sheet-max-width: 860px display: none .oe_form_field_one2many,.oe_form_field_many2many // TODO: oe_form_field_one2many_list? + > .oe_view_manager + .oe_list_pager_single_page + display: none !important + .oe_form_field_one2many_list_row_add + font-weight: bold .oe_list_content > thead border-bottom: 1px @@ -1787,6 +1921,46 @@ $sheet-max-width: 860px .oe_list_buttons.oe_editing .oe_list_save // keep "save row" button hidden in o2m visibility: hidden + .oe_form_editable + .oe_list_editable + .oe_list_content + td.oe_required + background-color: #d2d2ff + td.oe_readonly + background-color: #eee + .oe_list_editable + .oe_list_content + td.oe_list_field_cell + padding: 4px 6px 3px 6px + .oe_list.oe_list_editable + td.oe_list_record_delete + position: absolute + .oe_list.oe_list_editable.oe_editing + .oe_m2o_drop_down_button + top: 5px + .oe_m2o_cm_button + display: none + .oe_form_field + input + height: 27px + input, textarea + border: 1px solid #aaf + border-radius: 0px + margin: 0px + -webkit-border-radius: 0px + textarea + height: 60px + &.oe_form_field_float,&.oe_form_view_integer + input + text-align: right + &.oe_form_field_datetime,&.oe_form_field_date + > span + width: 100% + input.oe_datepicker_master + width: 100% !important + .oe_form_field_float,.oe_form_view_integer,&.oe_form_field_datetime,&.oe_form_field_date + min-width: 0 !important + max-width: none !important // }}} // FormView.many2many {{{ .oe_form .oe_form_field_many2many > .oe_list @@ -1807,11 +1981,16 @@ $sheet-max-width: 860px .oe_list position: relative - .oe_form .oe_form_field - width: auto - position: absolute - margin: 0 !important // dammit - padding: 0 + .oe_form + .oe_form_nosheet + margin: 0 // FIXME: either class or border should not be by default + padding: 0 + border: none + .oe_form_field + width: auto + position: absolute + margin: 0 !important // dammit + padding: 0 .oe_list_content width: 100% @@ -1876,14 +2055,22 @@ $sheet-max-width: 860px background: #eee font-weight: bold - > tbody tr:hover td, tbody tr:hover th - @include vertical-gradient(#eee, #dedede) .numeric text-align: right width: 82px input text-align: right + th.oe_list_header_handle + font-size: 1px + overflow: hidden + text-indent: -9001px + td.oe_list_field_handle + width: 1em + cursor: ns-resize + .oe_list_handle + @include text-to-icon("ö") + // }}} // Tree view {{{ .tree_header @@ -1908,7 +2095,7 @@ $sheet-max-width: 860px border-bottom: 2px solid #cacaca .treeview-tr, .treeview-td cursor: pointer - border-right: 1px dotted #afafb6 + border-right: 1px dotted $facets-border vertical-align: top text-align: left border-bottom: 1px solid #cfcccc @@ -1932,25 +2119,6 @@ $sheet-max-width: 860px .oe_trad_field.touched border: 1px solid green !important // }}} - // View Editor {{{ - .oe_view_editor - width: 100% - border-collapse: collapse - margin-left: -12px - width: 100% - background-color: white - border-spacing: 0 - td - text-align: center - white-space: nowrap - border: 1px solid #D8D8D8 - cursor: pointer - font-size: 90% - .oe_view_editor_field td - border: 0px !important - .oe_view_editor tr:hover - background-color: #ecebf2 - // }}} // Debugging stuff {{{ .oe_layout_debugging .oe_form_group diff --git a/addons/web/static/src/img/graph_background.png b/addons/web/static/src/img/graph_background.png Binary files differnew file mode 100644 index 00000000000..530312b20bb --- /dev/null +++ b/addons/web/static/src/img/graph_background.png diff --git a/addons/web/static/src/img/view_empty_arrow.png b/addons/web/static/src/img/view_empty_arrow.png Binary files differindex b0b1372adfd..ef8f3c820d7 100644 --- a/addons/web/static/src/img/view_empty_arrow.png +++ b/addons/web/static/src/img/view_empty_arrow.png diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js index c1b1b984abe..844dd88a0ac 100644 --- a/addons/web/static/src/js/boot.js +++ b/addons/web/static/src/js/boot.js @@ -48,7 +48,7 @@ * OpenERP Web web module split *---------------------------------------------------------*/ openerp.web = function(session) { - var files = ["corelib","coresetup","dates","formats","chrome","data","views","search","list","form","list_editable","web_mobile","view_tree","data_export","data_import","view_editor"]; + var files = ["corelib","coresetup","dates","formats","chrome","data","views","search","list","form","list_editable","web_mobile","view_tree","data_export","data_import"]; for(var i=0; i<files.length; i++) { if(openerp.web[files[i]]) { openerp.web[files[i]](session); diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 4f6e3c047f8..05f9fb5b1b6 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -57,7 +57,7 @@ instance.web.Dialog = instance.web.Widget.extend({ init: function (parent, options, content) { var self = this; this._super(parent); - this.setElement(content || this.make(this.tagName)); + this.content_to_set = content; this.dialog_options = { modal: true, destroy_on_close: true, @@ -81,11 +81,6 @@ instance.web.Dialog = instance.web.Widget.extend({ if (options) { _.extend(this.dialog_options, options); } - if (this.dialog_options.autoOpen) { - this.open(); - } else { - instance.web.dialog(this.$element, this.get_options()); - } }, get_options: function(options) { var self = this, @@ -114,31 +109,44 @@ instance.web.Dialog = instance.web.Widget.extend({ } else if (val.slice(-1) == "%") { return Math.round(available_size / 100 * parseInt(val.slice(0, -1), 10)); } else { - return parseInt(val, 10); + return parseInt(val, 10); } }, - open: function(options) { - // TODO fme: bind window on resize - if (this.template) { - this.$element.html(this.renderElement()); + renderElement: function() { + if (this.content_to_set) { + this.setElement(this.content_to_set); + } else if (this.template) { + this._super(); } + }, + open: function(options) { + if (! this.dialog_inited) + this.init_dialog(); var o = this.get_options(options); - instance.web.dialog(this.$element, o).dialog('open'); + instance.web.dialog(this.$element, o).dialog('open'); if (o.height === 'auto' && o.max_height) { this.$element.css({ 'max-height': o.max_height, 'overflow-y': 'auto' }); } return this; }, + init_dialog: function(options) { + this.renderElement(); + var o = this.get_options(options); + instance.web.dialog(this.$element, o); + var res = this.start(); + this.dialog_inited = true; + return res; + }, close: function() { this.$element.dialog('close'); }, on_close: function() { - if (this.__tmp_dialog_destroying) - return; + if (this.__tmp_dialog_destroying) + return; if (this.dialog_options.destroy_on_close) { - this.__tmp_dialog_closing = true; + this.__tmp_dialog_closing = true; this.destroy(); - this.__tmp_dialog_closing = undefined; + this.__tmp_dialog_closing = undefined; } }, on_resized: function() { @@ -148,10 +156,10 @@ instance.web.Dialog = instance.web.Widget.extend({ el.destroy(); }); if (! this.__tmp_dialog_closing) { - this.__tmp_dialog_destroying = true; - this.close(); - this.__tmp_dialog_destroying = undefined; - } + this.__tmp_dialog_destroying = true; + this.close(); + this.__tmp_dialog_destroying = undefined; + } if (! this.isDestroyed()) { this.$element.dialog('destroy'); } @@ -261,11 +269,11 @@ instance.web.Loading = instance.web.Widget.extend({ this.count += increment; if (this.count > 0) { - if (instance.connection.debug) { - this.$element.text(_.str.sprintf( _t("Loading (%d)"), this.count)); - } else { - this.$element.text(_t("Loading")); - } + if (instance.connection.debug) { + this.$element.text(_.str.sprintf( _t("Loading (%d)"), this.count)); + } else { + this.$element.text(_t("Loading")); + } this.$element.show(); this.getParent().$element.addClass('oe_wait'); } else { @@ -392,6 +400,9 @@ instance.web.DatabaseManager = instance.web.Widget.extend({ 'db': form_obj['db_name'], 'login': 'admin', 'password': form_obj['create_admin_pwd'], + 'login_successful': function() { + instance.webclient.show_application(); + }, }, }; self.do_action(client_action); @@ -494,7 +505,11 @@ instance.web.Login = instance.web.Widget.extend({ this.has_local_storage = typeof(localStorage) != 'undefined'; this.selected_db = null; this.selected_login = null; - this.params = params; + this.params = params || {}; + + if (this.params.login_successful) { + this.on('login_successful', this, this.params.login_successful); + } if (this.has_local_storage && this.remember_credentials) { this.selected_db = localStorage.getItem('last_db_login_success'); @@ -511,7 +526,7 @@ instance.web.Login = instance.web.Widget.extend({ self.do_action("database_manager"); }); return self.load_db_list().then(self.on_db_list_loaded).then(function() { - if(self.params) { + if (self.params.db) { self.do_login(self.params.db, self.params.login, self.params.password); } }); @@ -597,6 +612,86 @@ instance.web.Login = instance.web.Widget.extend({ }); instance.web.client_actions.add("login", "instance.web.Login"); +/** + * Client action to reload the whole interface. + * If params has an entry 'menu_id', it opens the given menu entry. + */ +instance.web.Reload = instance.web.Widget.extend({ + init: function(parent, params) { + this._super(parent); + this.menu_id = (params && params.menu_id) || false; + }, + start: function() { + var l = window.location; + var timestamp = new Date().getTime(); + var search = "?ts=" + timestamp; + if (l.search) { + search = l.search + "&ts=" + timestamp; + } + var hash = l.hash; + if (this.menu_id) { + hash = "#menu_id=" + this.menu_id; + } + var url = l.protocol + "//" + l.host + l.pathname + search + hash; + window.location = url; + } +}); +instance.web.client_actions.add("reload", "instance.web.Reload"); + +/** + * Client action to go back in breadcrumb history. + * If can't go back in history stack, will go back to home. + */ +instance.web.HistoryBack = instance.web.Widget.extend({ + init: function(parent, params) { + if (!parent.history_back()) { + window.location = '/' + (window.location.search || ''); + } + } +}); +instance.web.client_actions.add("history_back", "instance.web.HistoryBack"); + +/** + * Client action to go back home. + */ +instance.web.Home = instance.web.Widget.extend({ + init: function(parent, params) { + window.location = '/' + (window.location.search || ''); + } +}); +instance.web.client_actions.add("home", "instance.web.Home"); + +instance.web.ChangePassword = instance.web.Widget.extend({ + template: "ChangePassword", + start: function() { + var self = this; + self.$element.find("form[name=change_password_form]").validate({ + submitHandler: function (form) { + self.rpc("/web/session/change_password",{ + 'fields': $(form).serializeArray() + }, function(result) { + if (result.error) { + self.display_error(result); + return; + } else { + instance.webclient.on_logout(); + } + }); + } + }); + }, + display_error: function (error) { + return instance.web.dialog($('<div>'), { + modal: true, + title: error.title, + buttons: [ + {text: _("Ok"), click: function() { $(this).dialog("close"); }} + ] + }).html(error.error); + }, +}) +instance.web.client_actions.add("change_password", "instance.web.ChangePassword"); + instance.web.Menu = instance.web.Widget.extend({ template: 'Menu', init: function() { @@ -764,37 +859,6 @@ instance.web.UserMenu = instance.web.Widget.extend({ } }); }, - change_password :function() { - var self = this; - this.dialog = new instance.web.Dialog(this, { - title: _t("Change Password"), - width : 'auto' - }).open(); - this.dialog.$element.html(QWeb.render("UserMenu.password", self)); - this.dialog.$element.find("form[name=change_password_form]").validate({ - submitHandler: function (form) { - self.rpc("/web/session/change_password",{ - 'fields': $(form).serializeArray() - }, function(result) { - if (result.error) { - self.display_error(result); - return; - } else { - instance.webclient.on_logout(); - } - }); - } - }); - }, - display_error: function (error) { - return instance.web.dialog($('<div>'), { - modal: true, - title: error.title, - buttons: [ - {text: _("Ok"), click: function() { $(this).dialog("close"); }} - ] - }).html(error.error); - }, do_update: function () { var self = this; var fct = function() { @@ -810,7 +874,7 @@ instance.web.UserMenu = instance.web.Widget.extend({ if(res.company_id[0] > 1) topbar_name = _.str.sprintf("%s (%s)", topbar_name, res.company_id[1]); self.$element.find('.oe_topbar_name').text(topbar_name); - var avatar_src = _.str.sprintf('%s/web/binary/image?session_id=%s&model=res.users&field=avatar&id=%s', self.session.prefix, self.session.session_id, self.session.uid); + var avatar_src = _.str.sprintf('%s/web/binary/image?session_id=%s&model=res.users&field=image_small&id=%s', self.session.prefix, self.session.session_id, self.session.uid); $avatar.attr('src', avatar_src); }); }; @@ -822,44 +886,10 @@ instance.web.UserMenu = instance.web.Widget.extend({ }, on_menu_settings: function() { var self = this; - var action_manager = new instance.web.ActionManager(this); - var dataset = new instance.web.DataSet (this,'res.users',this.context); - dataset.call ('action_get','',function (result){ - self.rpc('/web/action/load', {action_id:result}, function(result){ - action_manager.do_action(_.extend(result['result'], { - target: 'inline', - res_id: self.session.uid, - res_model: 'res.users', - flags: { - action_buttons: false, - search_view: false, - sidebar: false, - views_switcher: false, - pager: false - } - })); - }); + self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }, function(result) { + result.result.res_id = instance.connection.uid; + self.getParent().action_manager.do_action(result.result); }); - this.dialog = new instance.web.Dialog(this,{ - title: _t("Preferences"), - width: '700px', - buttons: [ - {text: _t("Change password"), click: function(){ self.change_password(); }}, - {text: _t("Cancel"), click: function(){ $(this).dialog('destroy'); }}, - {text: _t("Save"), click: function(){ - 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 - window.location.reload(); - }); - } - } - ] - }).open(); - action_manager.appendTo(this.dialog.$element); - action_manager.renderElement(this.dialog); }, on_menu_about: function() { var self = this; @@ -918,6 +948,7 @@ instance.web.Client = instance.web.Widget.extend({ }, 0); }); instance.web.bus.on('click', this, function(ev) { + $.fn.tipsy.clear(); if (!$(ev.target).is('input[type=file]')) { self.$element.find('.oe_dropdown_menu.oe_opened').removeClass('oe_opened'); } @@ -1033,15 +1064,15 @@ instance.web.WebClient = instance.web.Client.extend({ $(window).bind('hashchange', this.on_hashchange); var state = $.bbq.getState(true); - if (! _.isEmpty(state)) { - $(window).trigger('hashchange'); - } else { + if (_.isEmpty(state) || state.action == "login") { self.menu.has_been_loaded.then(function() { var first_menu_id = self.menu.$element.find("a:first").data("menu"); if(first_menu_id) { self.menu.menu_click(first_menu_id); } }); + } else { + $(window).trigger('hashchange'); } }, on_hashchange: function(event) { diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js index 846ae3e4758..a46d6314ebe 100644 --- a/addons/web/static/src/js/corelib.js +++ b/addons/web/static/src/js/corelib.js @@ -1135,7 +1135,8 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ uid: new py.float(this.uid), datetime: datetime, time: time, - relativedelta: relativedelta + relativedelta: relativedelta, + current_date: date.today.__call__().strftime(['%Y-%m-%d']) }; }, /** @@ -1376,7 +1377,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ processData: false }, url); if (this.synch) - ajax.async = false; + ajax.async = false; return $.ajax(ajax); }, rpc_jsonp: function(url, payload) { @@ -1395,7 +1396,7 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({ data: data }, url); if (this.synch) - ajax.async = false; + ajax.async = false; var payload_str = JSON.stringify(payload); var payload_url = $.param({r:payload_str}); if(payload_url.length < 2000) { diff --git a/addons/web/static/src/js/coresetup.js b/addons/web/static/src/js/coresetup.js index 0011b7c2450..6ba62162e93 100644 --- a/addons/web/static/src/js/coresetup.js +++ b/addons/web/static/src/js/coresetup.js @@ -393,13 +393,13 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess timer = setTimeout(waitLoop, CHECK_INTERVAL); }, synchronized_mode: function(to_execute) { - var synch = this.synch; - this.synch = true; - try { - return to_execute(); - } finally { - this.synch = synch; - } + var synch = this.synch; + this.synch = true; + try { + return to_execute(); + } finally { + this.synch = synch; + } } }); @@ -540,10 +540,10 @@ $.async_when = function() { // special tweak for the web client var old_async_when = $.async_when; $.async_when = function() { - if (instance.connection.synch) - return $.when.apply(this, arguments); - else - return old_async_when.apply(this, arguments); + if (instance.connection.synch) + return $.when.apply(this, arguments); + else + return old_async_when.apply(this, arguments); }; /** Setup blockui */ @@ -672,32 +672,6 @@ instance.connection.on('module_loaded', this, function () { */ instance.web.client_actions = new instance.web.Registry(); -/** - * Client action to reload the whole interface. - * If params has an entry 'menu_id', it opens the given menu entry. - */ -instance.web.Reload = instance.web.Widget.extend({ - init: function(parent, params) { - this._super(parent); - this.menu_id = (params && params.menu_id) || false; - }, - start: function() { - var l = window.location; - var timestamp = new Date().getTime(); - var search = "?ts=" + timestamp; - if (l.search) { - search = l.search + "&ts=" + timestamp; - } - var hash = l.hash; - if (this.menu_id) { - hash = "#menu_id=" + this.menu_id; - } - var url = l.protocol + "//" + l.host + l.pathname + search + hash; - window.location = url; - } -}); -instance.web.client_actions.add("reload", "instance.web.Reload"); - }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js index fdb15d598af..2589afe5503 100644 --- a/addons/web/static/src/js/data.js +++ b/addons/web/static/src/js/data.js @@ -803,7 +803,7 @@ instance.web.DataSet = instance.web.OldWidget.extend( /** @lends openerp.web.Da return this.ids.length; }, alter_ids: function(n_ids) { - this.ids = n_ids; + this.ids = n_ids; }, }); instance.web.DataSetStatic = instance.web.DataSet.extend({ @@ -1042,7 +1042,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ self.cache.push({id: id, values: record}); } else { // I assume cache value is prioritary - cached.values = _.defaults(_.clone(cached.values), record); + cached.values = _.defaults(_.clone(cached.values), record); } }); return_records(); @@ -1067,7 +1067,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({ return this._super(method, args, callback, error_callback); }, alter_ids: function(n_ids) { - this._super(n_ids); + this._super(n_ids); this.on_change(); }, }); diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js index 6059f292df9..620878569ce 100644 --- a/addons/web/static/src/js/data_import.js +++ b/addons/web/static/src/js/data_import.js @@ -156,7 +156,7 @@ instance.web.DataImport = instance.web.Dialog.extend({ }); }, toggle_import_button: function (newstate) { - instance.web.dialog(this.$element, 'widget') + instance.web.dialog(this.$element, 'widget') .find('.oe_import_dialog_button') .button('option', 'disabled', !newstate); }, diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js index 6ceb7090e44..797e1a2cbdf 100644 --- a/addons/web/static/src/js/formats.js +++ b/addons/web/static/src/js/formats.js @@ -271,82 +271,4 @@ instance.web.auto_date_to_str = function(value, type) { } }; -/** - * Formats a provided cell based on its field type. Most of the field types - * return a correctly formatted value, but some tags and fields are - * special-cased in their handling: - * - * * buttons will return an actual ``<button>`` tag with a bunch of error handling - * - * * boolean fields will return a checkbox input, potentially disabled - * - * * binary fields will return a link to download the binary data as a file - * - * @param {Object} row_data record whose values should be displayed in the cell - * @param {Object} column column descriptor - * @param {"button"|"field"} column.tag base control type - * @param {String} column.type widget type for a field control - * @param {String} [column.string] button label - * @param {String} [column.icon] button icon - * @param {Object} [options] - * @param {String} [options.value_if_empty=''] what to display if the field's value is ``false`` - * @param {Boolean} [options.process_modifiers=true] should the modifiers be computed ? - * @param {String} [options.model] current record's model - * @param {Number} [options.id] current record's id - * - */ -instance.web.format_cell = function (row_data, column, options) { - options = options || {}; - var attrs = {}; - if (options.process_modifiers !== false) { - attrs = column.modifiers_for(row_data); - } - if (attrs.invisible) { return ''; } - - if (column.tag === 'button') { - return _.template('<button type="button" title="<%-title%>" <%=additional_attributes%> >' + - '<img src="<%-prefix%>/web/static/src/img/icons/<%-icon%>.png" alt="<%-alt%>"/>' + - '</button>', { - title: column.string || '', - additional_attributes: isNaN(row_data["id"].value) && instance.web.BufferedDataSet.virtual_id_regex.test(row_data["id"].value) ? - 'disabled="disabled" class="oe_list_button_disabled"' : '', - prefix: instance.connection.prefix, - icon: column.icon, - alt: column.string || '' - }); - } - if (!row_data[column.id]) { - return options.value_if_empty === undefined ? '' : options.value_if_empty; - } - - switch (column.widget || column.type) { - case "boolean": - return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>', - row_data[column.id].value ? 'checked="checked"' : ''); - case "binary": - var text = _t("Download"), - download_url = _.str.sprintf('/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', instance.connection.session_id, options.model, column.id, options.id); - if (column.filename) { - download_url += '&filename_field=' + column.filename; - if (row_data[column.filename]) { - text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value( - row_data[column.filename].value, {type: 'char'})); - } - } - return _.template('<a href="<%-href%>"><%-text%></a> (%<-size%>)', { - text: text, - href: download_url, - size: row_data[column.id].value - }); - case 'progressbar': - return _.template( - '<progress value="<%-value%>" max="100"><%-value%>%</progress>', { - value: _.str.sprintf("%.0f", row_data[column.id].value || 0) - }); - } - - return _.escape(instance.web.format_value( - row_data[column.id].value, column, options.value_if_empty)); -} - }; diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js deleted file mode 100644 index 6df78679ecb..00000000000 --- a/addons/web/static/src/js/view_editor.js +++ /dev/null @@ -1,1212 +0,0 @@ -openerp.web.view_editor = function(instance) { -var _t = instance.web._t; -var QWeb = instance.web.qweb; -instance.web.ViewEditor = instance.web.OldWidget.extend({ - init: function(parent, element_id, dataset, view, options) { - this._super(parent); - this.element_id = element_id; - this.parent = parent; - this.dataset = new instance.web.DataSetSearch(this, 'ir.ui.view', null, null), - this.model = dataset.model; - this.xml_element_id = 0; - this.property = instance.web.ViewEditor.property_widget; - this.one_object = false; - }, - start: function() { - this.init_view_editor(); - }, - init_view_editor: function() { - var self = this, - action_title = _.str.sprintf(_t("Manage Views (%s)"), this.model); - var action = { - name: action_title, - context: this.session.user_context, - domain: [["model", "=", this.model]], - res_model: 'ir.ui.view', - views: [[false, 'list']], - type: 'ir.actions.act_window', - target: "current", - limit: this.dataset.limit || 80, - auto_search : true, - flags: { - sidebar: false, - deletable: false, - views_switcher: false, - action_buttons: false, - search_view: false, - pager: false, - radio: true, - select_view_id: self.parent.fields_view.view_id - } - }; - this.view_edit_dialog = new instance.web.Dialog(this, { - title: action_title, - width: 850, - buttons: [ - {text: _t("Create"), click: function() { self.on_create_view(); }}, - {text: _t("Edit"), click: function() { self.xml_element_id = 0; self.get_arch(); }}, - {text: _t("Remove"), click: function() { self.do_delete_view(); }}, - {text: _t("Close"), click: function() { self.view_edit_dialog.close(); window.location.reload(); }} - ] - }).open(); - this.view_edit_dialog.on_close.add_last(function(){window.location.reload();}); - 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_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); - controller.on_loaded.add_last(function(){ - $(controller.groups).bind({ - 'selected': function(e, ids, records) { - self.main_view_id = ids[0]; - } - }) - }); - }); - }, - on_create_view: function() { - var self = this; - this.create_view_dialog = new instance.web.Dialog(this, { - title: _.str.sprintf(_t("Create a view (%s)"), self.model), - buttons: [ - {text: _t("Save"), click: function () { - var view_values = {}; - var warn = false; - _.each(self.create_view_widget, function(widget) { - if (widget.is_invalid) { - warn = true; - return false; - } - if (widget.dirty && !widget.is_invalid) { - view_values[widget.name] = widget.get_value(); - } - }); - if (warn) { - self.on_valid_create_view(self.create_view_widget); - } else { - $.when(self.do_save_view(view_values)).then(function() { - self.create_view_dialog.close(); - var controller = self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller; - controller.reload_content(); - }); - } - }}, - {text: _t("Cancel"), click: function () { self.create_view_dialog.close(); }} - ] - }).open(); - var view_widget = [{'name': 'view_name', 'string':'View Name', 'type': 'char', 'required': true, 'value' : this.model + '.custom_' + Math.round(Math.random() * 1000)}, - {'name': 'view_type', 'string': 'View Type', 'type': 'selection', 'required': true, 'value': 'Form', 'selection': [['',''],['tree', 'Tree'],['form', 'Form'],['graph', 'Graph'],['calendar', 'Calender']]}, - {'name': 'proirity', 'string': 'Priority', 'type': 'float', 'required': true, 'value':'16'}]; - this.create_view_dialog.$element.append('<table id="create_view" style="width:400px" class="oe_form"></table>'); - this.create_view_widget = []; - _.each(view_widget, function(widget) { - var type_widget = new (self.property.get_any([widget.type])) (self.create_view_dialog, widget); - self.create_view_dialog.$element.find('table[id=create_view]').append('<tr><td width="100px" align="right">' + widget.string + ':</td>' + type_widget.render()+'</tr>'); - var value = null; - if (widget.value) { - value = widget.value; - type_widget.dirty = true; - } - type_widget.start(); - type_widget.set_value(value); - self.create_view_widget.push(type_widget); - }); - }, - do_save_view: function(values) { - def = $.Deferred(); - var field_dataset = new instance.web.DataSetSearch(this, this.model, null, null); - var model_dataset = new instance.web.DataSetSearch(this, 'ir.model', null, null); - var view_string = "", field_name = false, self = this; - field_dataset.call( 'fields_get', [], function(fields) { - _.each(['name', 'x_name'], function(value) { - if (_.include(_.keys(fields), value)) { - field_name = value; - return false; - } - }); - if (field_name) { - model_dataset.read_slice(['name','field_id'], {"domain": [['model','=',self.model]]}).then(function(records) { - if (records) {view_string = records[0].name;} - var arch = _.str.sprintf("<?xml version='1.0'?>\n<%s string='%s'>\n\t<field name='%s'/>\n</%s>", values.view_type, view_string, field_name, values.view_type); - var vals = {'model': self.model, 'name': values.view_name, 'priority': values.priority, 'type': values.view_type, 'arch': arch}; - self.dataset.create(vals, function(suc) { - def.resolve(); - }); - }); - } - }); - return def.promise(); - }, - on_valid_create_view: function(widgets) { - var msg = "<ul>"; - _.each(widgets, function(widget) { - if (widget.is_invalid) { - msg += "<li>" + widget.name + "</li>"; - } - }); - msg += "</ul>"; - this.do_warn("The following fields are invalid :", msg); - }, - add_node_name : function(node) { - if(node.tagName.toLowerCase() == "button" || node.tagName.toLowerCase() == "field"){ - return (node.getAttribute('name'))? - _.str.sprintf( "<%s name='%s'>",node.tagName.toLowerCase(), node.getAttribute('name')): - _.str.sprintf( "<%s>",node.tagName.toLowerCase()); - }else if(node.tagName.toLowerCase() == "group"){ - return (node.getAttribute('string'))? - _.str.sprintf( "<%s>",node.getAttribute('string')): - _.str.sprintf( "<%s>",node.tagName.toLowerCase()); - }else{ - return (node.getAttribute('string'))? - _.str.sprintf( "<%s string='%s'>",node.tagName.toLowerCase(), node.getAttribute('string')): - _.str.sprintf( "<%s>",node.tagName.toLowerCase()); - } - }, - do_delete_view: function() { - var self = this; - if (confirm(_t("Do you really want to remove this view?"))) { - 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; - }); - } - }, - create_View_Node: function(node){ - ViewNode = { - 'level': ($(node).parents()).length + 1, - 'id': this.xml_element_id += 1, - 'att_list': [], - 'name': this.add_node_name(node), - 'child_id': [] - }; - ViewNode.att_list.push(node.tagName.toLowerCase()); - _.each(node.attributes, function(att) { - ViewNode.att_list.push([att.nodeName, att.nodeValue]); - }); - return ViewNode; - }, - append_child_object: function(main_object, parent_id, child_obj_list) { - var self = this; - if (main_object.id == parent_id) { - main_object.child_id = child_obj_list; - return main_object; - } else { - _.each(main_object.child_id, function(child_object) { - self.append_child_object(child_object, parent_id, child_obj_list); - }); - } - }, - convert_arch_to_obj: function(xml_Node, main_object, parent_id) { - var self = this; - var child_obj_list = []; - _.each(xml_Node, function(element) { - child_obj_list.push(self.create_View_Node(element)); - }); - this.append_child_object(main_object, parent_id, child_obj_list); - var obj_xml_list = _.zip(xml_Node, child_obj_list); - _.each(obj_xml_list, function(node) { - var children = _.filter(node[0].childNodes, function(child) { - return child.nodeType == 1; - }); - if (children) { - self.convert_arch_to_obj(children, main_object, node[1].id); - } - }); - return main_object; - }, - parse_xml: function(arch, view_id) { - main_object = { - 'level': 0, - 'id': this.xml_element_id +=1, - 'att_list': [], - 'name': _.str.sprintf("<view view_id = %s>", view_id), - 'child_id': [] - }; - var xml_arch = QWeb.load_xml(arch); - return [this.convert_arch_to_obj(xml_arch.childNodes, main_object, this.xml_element_id)]; - }, - get_arch: function() { - var self = this; - var view_arch_list = []; - this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type','priority']).then(function(arch) { - if (arch.length) { - var arch_object = self.parse_xml(arch[0].arch, self.main_view_id); - self.main_view_type = arch[0].type == 'tree'? 'list': arch[0].type; - view_arch_list.push({"view_id": self.main_view_id, "arch": arch[0].arch,"priority":arch[0].priority}); - self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}).then(function(result) { - _.each(result, function(res) { - view_arch_list.push({"view_id": res.id, "arch": res.arch,"priority":res.priority}); - self.inherit_view(arch_object, res); - }); - return self.edit_view({"main_object": arch_object, - "parent_child_id": self.parent_child_list(arch_object, []), - "arch": view_arch_list}); - }); - } else { - self.do_warn("Please select view in list :"); - } - }); - }, - parent_child_list : function(one_object, parent_list) { - var self = this; - _.each(one_object , function(element) { - if (element.child_id.length != 0) { - parent_list.push({"key": element.id, "value": _.pluck(element.child_id, 'id')}); - self.parent_child_list(element.child_id, parent_list); - } - }); - return parent_list; - }, - inherit_view : function(arch_object, result) { - var self = this, xml_list = [], xml_arch = QWeb.load_xml(result.arch); - if (xml_arch.childNodes[0].tagName == "data") { - xml_list = _.filter(xml_arch.childNodes[0].childNodes, function(child) { - return child.nodeType == 1; - }); - } else { - xml_list.push( xml_arch.childNodes[0]); - } - _.each(xml_list, function(xml) { - var expr_to_list = [], xpath_arch_object = self.parse_xml(QWeb.tools.xml_node_to_string(xml), result.id); - if (xml.tagName == "xpath") { - var part_expr = _.without(xml.getAttribute('expr').split("/"), ""); - _.each(part_expr, function(part) { - expr_to_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"), "")); - }); - } else { - var temp = _.reject(xpath_arch_object[0].child_id[0].att_list, function(list) { - return list instanceof Array? _.include(list, "position"): false; - }); - expr_to_list = [_.flatten(temp)]; - } - self.inherit_apply(expr_to_list, arch_object ,xpath_arch_object); - }); - }, - inherit_apply: function(expr_list ,arch_object ,xpath_arch_object) { - var self = this; - if (xpath_arch_object.length) { - var check = expr_list[0], obj = false; - switch (check.length) { - case 2: - if (parseInt(check[1])) { - //for field[3] - var temp_list = _.select(arch_object, function(element) { - return _.include(_.flatten(element.att_list), check[0]); - }); - obj = arch_object[_.indexOf(arch_object, temp_list[parseInt(check[1]) - 1])]; - } else { - //for notebook[last()] - obj = _.detect(arch_object, function(element) { - return _.include(_.flatten(element.att_list), check[0]); - }); - } - break; - case 3: - //for field[@name='type'] - obj = _.detect(arch_object, function(element){ - if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == _.uniq(check).length) { - return element; - } - }); - break; - case 1: - //for /form/notebook - var temp_list = _.select(arch_object, function(element) { - return _.include(_.flatten(element.att_list), check[0]); - }); - if (temp_list.length != 0) { - expr_list.length == 1 ? obj = temp_list[0] : expr_list.shift(); - } - break; - } - if (obj) { - expr_list.shift(); - if (expr_list.length) { - self.inherit_apply(expr_list, obj.child_id, xpath_arch_object); - } else { - self.increase_level(xpath_arch_object[0], obj.level + 1); - obj.child_id.push(xpath_arch_object[0]); - xpath_arch_object.pop(); - } - } else { - _.each(arch_object, function(element) { - self.inherit_apply(expr_list, element.child_id, xpath_arch_object); - }); - } - } - }, - increase_level: function(val, level) { - var self = this; - val.level = level; - _.each(val.child_id, function(val, key) { - self.increase_level(val, level + 1); - }); - }, - do_select_row: function(row_id) { - this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").removeClass('ui-selected'); - this.edit_xml_dialog.$element.find("tr[id=viewedit-" + row_id + "]").addClass('ui-selected'); - }, - do_parent_img_hide_show: function(img) { - if ($(img).attr('src') == '/web/static/src/img/collapse.gif') { - $(img).attr('src', '/web/static/src/img/expand.gif'); - this.on_expand(img); - } else { - $(img).attr('src', '/web/static/src/img/collapse.gif'); - this.on_collapse(img); - } - }, - edit_view: function(one_object) { - var self = this; - this.one_object = one_object; - this.edit_xml_dialog = new instance.web.Dialog(this, { - title: _.str.sprintf(_t("View Editor %d - %s"), self.main_view_id, self.model), - height: '90%', - buttons: [ - {text: _t("Inherited View"), click: function(){ - var selected_row = self.edit_xml_dialog.$element.find('.ui-selected'); - if (selected_row.length) { - if(selected_row.find('a').text().search("field") != -1){ - if (confirm(_t("Do you really wants to create an inherited view here?"))) { - self.inherited_view(selected_row); - } - }else{ - alert("Can't Update View"); - } - }else{ - alert("Select an element"); - } - }}, - {text: _t("Preview"), click: function() { - var action = { - context: self.session.user_context, - res_model: self.model, - views: [[self.main_view_id, self.main_view_type]], - type: 'ir.actions.act_window', - target: "new", - auto_search: true, - flags: { - sidebar: false, - views_switcher: false, - action_buttons: false - } - }; - var action_manager = new instance.web.ActionManager(self); - action_manager.do_action(action); - }}, - {text: _t("Close"), click: function(){ - self.action_manager.inner_widget.views[self.action_manager.inner_widget.active_view].controller.reload_content(); - self.edit_xml_dialog.close(); - }} - ] - }).open(); - var no_property_att = []; - _.each(_PROPERTIES, function(val, key) { - if (! val.length) no_property_att.push(key); - }); - this.edit_xml_dialog.$element.html(QWeb.render('view_editor', {'data': one_object['main_object'], 'no_properties': no_property_att})); - this.edit_xml_dialog.$element.find("tr[id^='viewedit-']").click(function() { - self.do_select_row(this.id.split('-')[1]); - }); - this.edit_xml_dialog.$element.find("img[id^='parentimg-']").click(function() { - self.do_parent_img_hide_show(this); - }); - this.edit_xml_dialog.$element.find("img[id^='side-']").click(function() { - self.on_select_img(this); - }); - }, - inherited_view: function(selected_row){ - var self = this; - var row_id = parseInt((selected_row.attr('id')).split('-')[1]); - var obj = self.get_object_by_id(row_id,self.one_object['main_object'], [])[0]; - var view_name = this.model + '.inherit_' + Math.round(Math.random() * 1000); - var view_find = selected_row; - var view_id; - var min_level = parseInt(selected_row.attr('level')); - while (1) { - view_find = view_find.prev(); - if (view_find.length == 0 || - self.edit_xml_dialog.$element.find(view_find).find('a').text().search("view_id") != -1 && - parseInt(view_find.attr('level')) < min_level ) { - view_id = parseInt($(view_find).find('a').text().replace(/[^0-9]+/g, '')); - break; - } - if (view_find.attr('level') < min_level) { - min_level = parseInt(view_find.attr('level')); - } - } - var val = _.detect(obj.att_list, function(val) {return val[0] == "name";}); - var priority = _.detect(self.one_object['arch'], function(val) {return val.view_id == view_id;}); - var arch = _.str.sprintf("<?xml version='1.0'?>\n\t <field name='%s' position='after'> </field>", val[1]); - var vals = {'model': self.model, 'name': view_name, 'priority': priority.priority + 1, 'type': "form", 'arch': arch,'inherit_id':self.main_view_id}; - this.dataset.create(vals, function(suc) { - var arch_to_obj = self.parse_xml(arch,suc.result); - obj.child_id.push(arch_to_obj[0]); - self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]); - self.one_object['arch'].push({'view_id':suc.result,"arch":arch,'priority': priority.priority + 1}); - self.increase_level(arch_to_obj[0],obj.level+1); - self.render_inherited_view(selected_row,arch_to_obj[0]); - }); - }, - render_inherited_view: function(selected_row,obj){ - var self = this,row_id = parseInt((selected_row.attr('id')).split('-')[1]); - var clone = this.create_clone(selected_row.clone(),obj); - if (selected_row.find("img[id^='parentimg-']").length == 0) { - ($(selected_row.find('a').parent()).siblings('td')) - .append($('<img width="16" height="16"></img>').attr('src', '/web/static/src/img/collapse.gif'). - attr('id','parentimg-'+ row_id).click(function(){ - self.do_parent_img_hide_show(this); - })); - } - self.edit_xml_dialog.$element. - find("tr[id='viewedit-"+row_id+"']").after(clone.removeClass('ui-selected')); - _.each(obj.child_id,function(obj){self.render_inherited_view(clone,obj);}); - }, - on_select_img: function(element_img) { - var self = this; - var side = $(element_img).closest("tr[id^='viewedit-']"); - this.one_object.clicked_tr_id = parseInt((side.attr('id')).split('-')[1]); - this.one_object.clicked_tr_level = parseInt(side.attr('level')); - var img = side.find("img[id='parentimg-" + this.one_object.clicked_tr_id + "']").attr('src'); - var view_id = 0, view_xml_id = 0, view_find = side; - //for view id finding - var min_level = this.one_object.clicked_tr_id; - if (($(side).find('a').text()).search("view_id") != -1) { - view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, '')); - view_xml_id = (view_find.attr('id')).split('-')[1]; - this.one_object.clicked_tr_id += 1; - this.one_object.clicked_tr_level += 1; - }else{ - while (1) { - view_find = view_find.prev(); - if (view_find.length == 0 || - (self.edit_xml_dialog.$element.find(view_find).find('a').text()).search("view_id") != -1 - && parseInt(view_find.attr('level')) < min_level ) { - view_id = parseInt(($(view_find).find('a').text()).replace(/[^0-9]+/g, '')); - view_xml_id = parseInt((view_find.attr('id')).split('-')[1]); - break; - } - if (view_find.attr('level') < min_level) { - min_level = parseInt(view_find.attr('level')); - } - } - } - this.one_object.clicked_tr_view = [view_id, view_xml_id]; - switch (element_img.id) { - case "side-add": - self.do_node_add(side); - break; - case "side-remove": - if (confirm(_t("Do you really want to remove this node?"))) { - self.do_save_update_arch("remove_node"); - } - break; - case "side-edit": - self.do_node_edit(side); - break; - case "side-up": - self.do_node_up(side, img); - break; - case "side-down": - self.do_node_down(side, img); - break; - } - }, - do_node_add: function(side){ - var self = this,property_to_check = []; - var tr = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], [])[0].att_list[0]; - var parent_tr = ($(side).prevAll("tr[level=" + String(this.one_object.clicked_tr_level - 1) + "]"))[0]; - var field_dataset = new instance.web.DataSetSearch(this, this.model, null, null); - parent_tr = self.get_object_by_id(parseInt($(parent_tr).attr('id').replace(/[^0-9]+/g, '')), this.one_object['main_object'], [])[0].att_list[0]; - _.each([tr, parent_tr],function(element) { - var value = _.has(_CHILDREN, element) ? element : _.str.include(html_tag, element)?"html_tag":false; - property_to_check.push(value); - }); - field_dataset.call( 'fields_get', [], function(result) { - var fields = _.keys(result); - fields.push(" "),fields.sort(); - self.on_add_node(property_to_check, fields); - }); - }, - do_node_edit: function(side) { - var self = this; - var result = self.get_object_by_id(this.one_object.clicked_tr_id, this.one_object['main_object'], []); - if (result.length && result[0] && result[0].att_list) { - var properties = _PROPERTIES[result[0].att_list[0]]; - self.on_edit_node(properties); - } - }, - do_node_down: function(cur_tr, img) { - var self = this, next_tr, last_tr, tr_to_move = []; - tr_to_move.push(cur_tr); - if (img) { - while (1) { - next_tr = cur_tr.next(); - if ( parseInt(next_tr.attr('level')) <= this.one_object.clicked_tr_level || next_tr.length == 0) { - last_tr = next_tr; - break; - } else { - tr_to_move.push(next_tr); - cur_tr = next_tr; - } - } - } else { - last_tr = cur_tr.next(); - } - if ((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1) { - return false; - } - if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == this.one_object.clicked_tr_level) { - var last_tr_id = (last_tr.attr('id')).split('-')[1]; - img = last_tr.find("img[id='parentimg-" + last_tr_id + "']").attr('src'); - if (img) { - self.edit_xml_dialog.$element.find("img[id='parentimg-" + last_tr_id + "']"). - attr('src', '/web/static/src/img/expand.gif'); - while (1) { - var next_tr = last_tr.next(); - if (next_tr.attr('level') <= this.one_object.clicked_tr_level || next_tr.length == 0) break; - next_tr.hide(); - last_tr = next_tr; - } - } - tr_to_move.reverse(); - _.each(tr_to_move, function(rec) { - $(last_tr).after(rec); - }); - self.do_save_update_arch("down"); - } - }, - do_node_up: function(cur_tr, img) { - var self = this, side = cur_tr, tr_to_move = []; - tr_to_move.push(side); - while (1) { - var prev_tr = cur_tr.prev(); - if (this.one_object.clicked_tr_level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) { - last_tr = prev_tr; - break; - } - cur_tr = prev_tr; - } - if (img) { - self.edit_xml_dialog.$element.find("img[id='parentimg-" + this.one_object.clicked_tr_id + "']"). - attr('src', '/web/static/src/img/expand.gif'); - while (1) { - next_tr = side.next(); - if (parseInt(next_tr.attr('level')) <= this.one_object.clicked_tr_level || next_tr.length == 0) { - break; - } else { - next_tr.hide(); - tr_to_move.push(next_tr); - side = next_tr; - } - } - } - if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == this.one_object.clicked_tr_level && - (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) { - _.each(tr_to_move, function(rec) { - $(last_tr).before(rec); - }); - self.do_save_update_arch("up"); - } - }, - do_save_update_arch: function(move_direct, update_values) { - var self = this; - var arch = _.detect(self.one_object['arch'], function(element) - {return element.view_id == self.one_object.clicked_tr_view[0]}); - var obj = self.get_object_by_id(this.one_object.clicked_tr_view[1],this.one_object['main_object'], []); - //for finding xpath tag from inherit view - var xml_arch = QWeb.load_xml(arch.arch); - if (xml_arch.childNodes[0].tagName == "data") { - var check_list = _.flatten(obj[0].child_id[0].att_list); - var children = _.filter(xml_arch.childNodes[0].childNodes, function (child) { - return child.nodeType == 1; - }); - arch.arch = _.detect(children, function(xml_child) { - var temp_obj = self.create_View_Node(xml_child), - insert = _.intersection(_.flatten(temp_obj.att_list),_.uniq(check_list)); - if (insert.length == _.uniq(check_list).length ) {return xml_child;} - }); - xml_arch = QWeb.load_xml(arch.arch); - } - return self.do_save_xml(xml_arch.documentElement, obj[0].child_id[0],obj[0].child_id, move_direct, update_values,arch); - }, - get_object_by_id: function(id, one_object, result) { - var self = this; - if (result.length == 0 ) { - var check = _.detect(one_object , function(obj) { - return id == obj.id; - }); - if (check) {result.push(check);} - _.each(one_object, function(obj) { - self.get_object_by_id(id,obj.child_id, result); - }); - } - return result; - }, - create_clone: function(clone, new_node_obj){ - var self = this; - clone.find('a').text(new_node_obj.name); - ($(clone.find('a').parent()).siblings('td')).css( "padding-left", 20 * new_node_obj.level); - clone.attr("id", "viewedit-" + new_node_obj.id); - clone.attr("level", new_node_obj.level); - clone.find("img[id^='parentimg-']").remove(); - clone.bind("click",function(){ - self.do_select_row(this.id.split('-')[1]); - }); - clone.find("img[id^='side-']").click(function() { - self.on_select_img(this); - }); - return clone; - }, - do_save_xml: function(arch1, obj, child_list, move_direct, update_values, arch){ - var self = this, children_list = $(arch1).children(),list_obj_xml; - try{list_obj_xml = _.zip(children_list, obj.child_id);}catch(err){return;} - if (this.one_object.clicked_tr_id) { - if (obj.id == this.one_object.clicked_tr_id) { - var parent = false, index = _.indexOf(child_list, obj); - if (move_direct == "down") { - var next = $(arch1).next(); - $(next).after(arch1); - var re_insert_obj = child_list.splice(index, 1); - child_list.splice(index+1, 0, re_insert_obj[0]); - parent = $(arch1).parents(); - } else if (move_direct == "up") { - var prev = $(arch1).prev(); - $(prev).before(arch1); - var re_insert_obj = child_list.splice(index, 1); - child_list.splice(index-1, 0, re_insert_obj[0]); - parent = $(arch1).parents(); - } else if (move_direct == "update_node") { - _.each(update_values, function(val){ - if (val[1]) $(arch1)[0].setAttribute(val[0], val[1]); - else $(arch1)[0].removeAttribute(val[0]); - }); - var new_obj = self.create_View_Node(arch1); - new_obj.id = obj.id,new_obj.child_id = obj.child_id; - self.edit_xml_dialog.$element. - find("tr[id='viewedit-"+this.one_object.clicked_tr_id+"']"). - find('a').text(new_obj.name); - child_list.splice(index, 1, new_obj); - parent = $(arch1).parents(); - } else if(move_direct == "add_node") { - var tr_click = self.edit_xml_dialog.$element.find("tr[id='viewedit-"+self.one_object.clicked_tr_id+"']"), - temp_xml = QWeb.load_xml(update_values[0]), - object_xml = self.create_View_Node(temp_xml.childNodes[0]); - (update_values[1] == "Inside")? object_xml.level = obj.level + 1:object_xml.level = obj.level; - var clone = self.create_clone(tr_click.clone(),object_xml), - after_append = _.detect(self.one_object['parent_child_id'],function(ele){ - return self.one_object.clicked_tr_id == ele.key; - }); - after_append = (after_append)?_.last(after_append.value):self.one_object.clicked_tr_id; - switch (update_values[1]) { - case "After": - self.edit_xml_dialog.$element. - find("tr[id='viewedit-"+after_append+"']").after(clone); - $(arch1).after($(update_values[0])); - child_list.splice(index + 1, 0, object_xml); - break; - case "Before": - tr_click.before(clone); - $(arch1).before($(update_values[0])); - child_list.splice(index - 1, 0, object_xml); - break; - case "Inside": - if (tr_click.find("img[id^='parentimg-']").length == 0) { - ($(tr_click.find('a').parent()).siblings('td')) - .append($('<img width="16" height="16"></img>').attr('src', '/web/static/src/img/collapse.gif'). - attr('id','parentimg-'+ self.one_object.clicked_tr_id).click(function(){ - self.do_parent_img_hide_show(this); - })); - } - $(arch1).append($(update_values[0])); - self.edit_xml_dialog.$element. - find("tr[id='viewedit-"+after_append+"']").after(clone); - obj.child_id.push(object_xml); - break; - } - self.edit_xml_dialog.$element. - find("tr[id='viewedit-" + object_xml.id + "']").removeClass('ui-selected'); - parent = $(arch1).parents(); - } else if (move_direct == "remove_node") { - parent = $(arch1).parents(); - if (parent.length == 0 || (parent[0].tagName.toLowerCase() == "data")) { - self.one_object.clicked_tr_id = self.one_object.clicked_tr_id -1; - self.one_object.clicked_tr_level = self.one_object.clicked_tr_level - 1; - (parent.length == 0)?parent.push("remove_view"):false; - } - $(arch1).remove(); - child_list.splice(index,1); - var cur_tr = self.edit_xml_dialog.$element. - find("tr[id='viewedit-" + self.one_object.clicked_tr_id + "']"); - _.each(self.get_list_tr(cur_tr,self.one_object.clicked_tr_level), function(tr_element){ - tr_element.remove(); - }); - cur_tr.remove(); - var parent_img = _.detect(self.one_object['parent_child_id'],function(element){ - return _.include(element.value, self.one_object.clicked_tr_id); - }); - if(parent_img.value.length == 1){ - self.edit_xml_dialog.$element. - find("tr[id='viewedit-"+parent_img.key+"']"). - find("img[id^='parentimg-']").remove(); - } - self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]); - } - var convert_to_utf = (parent.length != 0)? parent[parent.length-1]: arch1; - if (convert_to_utf != "remove_view") { - convert_to_utf = QWeb.tools.xml_node_to_string(convert_to_utf); - convert_to_utf = convert_to_utf.replace('xmlns="http://www.w3.org/1999/xhtml"', ""); - convert_to_utf = '<?xml version="1.0"?>' + convert_to_utf; - arch.arch = convert_to_utf; - this.dataset.write(this.one_object.clicked_tr_view[0] ,{"arch":convert_to_utf}, function(r) {}); - } else { - this.dataset.unlink([this.one_object.clicked_tr_view[0]],function(res) {}); - } - if(move_direct == "add_node"){ - self.add_node_dialog.close(); - self.on_select_img(clone.find("img[id='side-edit']")[0]); - self.one_object['parent_child_id'] = self.parent_child_list(self.one_object['main_object'],[]); - } - } - if (obj.level <= this.one_object.clicked_tr_level) { - _.each(list_obj_xml, function(child_node) { - self.do_save_xml(child_node[0], child_node[1], obj.child_id, move_direct, update_values, arch); - }); - } - } - }, - on_expand: function(expand_img){ - var level = parseInt($(expand_img).closest("tr[id^='viewedit-']").attr('level')); - var cur_tr = $(expand_img).closest("tr[id^='viewedit-']"); - _.each(this.get_list_tr(cur_tr,level), function(tr_element){ - tr_element.hide(); - }); - }, - get_list_tr: function(cur_tr,level){ - tr_list = []; - while (1) { - var nxt_tr = cur_tr.next(); - if (parseInt(nxt_tr.attr('level')) > level) { - cur_tr = nxt_tr; - tr_list.push(nxt_tr); - } else return tr_list; - } - }, - on_collapse: function(collapse_img) { - var self = this, id = collapse_img.id.split('-')[1]; - var datas = _.detect(self.one_object['parent_child_id'] , function(res) { - return res.key == id; - }); - _.each(datas.value, function (rec) { - var tr = self.edit_xml_dialog.$element.find("tr[id='viewedit-" + rec + "']"); - tr.find("img[id='parentimg-" + rec + "']").attr('src', '/web/static/src/img/expand.gif'); - tr.show(); - }); - }, - on_edit_node: function(properties){ - var self = this; - this.edit_node_dialog = new instance.web.Dialog(this,{ - title: _t("Properties"), - width: 450, - buttons: [ - {text: _t("Update"), click: function () { - var warn = false, update_values = []; - _.each(self.edit_widget, function(widget) { - if (widget.is_invalid) { - warn = true; - return false; - } - if (widget.dirty && !widget.is_invalid) { - update_values.push([widget.name, widget.get_value()]); - } - }); - if (warn) { - self.on_valid_create_view(self.edit_widget); - } else { - self.do_save_update_arch("update_node", update_values); - self.edit_node_dialog.close(); - } - }}, - {text: _t("Cancel"), click: function () { self.edit_node_dialog.close(); }} - ] - }).open(); - var _PROPERTIES_ATTRIBUTES = { - 'name' : {'name':'name', 'string': 'Name', 'type': 'char'}, - 'string' : {'name':'string', 'string': 'String', 'type': 'char'}, - 'required' : {'name':'required', 'string': 'Required', 'type': 'boolean'}, - 'readonly' : {'name':'readonly', 'string': 'Readonly', 'type': 'boolean'}, - 'invisible' : {'name':'invisible', 'string': 'Invisible', 'type': 'boolean'}, - 'domain' : {'name':'domain', 'string': 'Domain', 'type': 'char'}, - 'context' : {'name':'context', 'string': 'Context', 'type': 'char'}, - 'limit' : {'name':'limit', 'string': 'Limit', 'type': 'float'}, - 'min_rows' : {'name':'min_rows', 'string': 'Minimum rows', 'type': 'float'}, - 'date_start' : {'name':'date_start', 'string': 'Start date', 'type': 'char'}, - 'date_delay' : {'name':'date_delay', 'string': 'Delay date', 'type': 'char'}, - 'day_length' : {'name':'day_length', 'string': 'Day length', 'type': 'char'}, - 'mode' : {'name':'mode', 'string': 'Mode', 'type': 'char'}, - 'align' : {'name':'align', 'string': 'Alignment ', 'type': 'selection', 'selection': [['', ''], ['0.0', 'Left'], ['0.5', 'Center'], ['1.0', 'Right']]}, - 'icon' : {'name':'icon', 'string': 'Icon', 'type': 'selection', 'selection': _ICONS}, - 'type' : {'name':'type', 'string': 'Type', 'type': 'selection', 'selection': [['', ''], ['action', 'Action'], ['object', 'Object'], ['workflow', 'Workflow'], ['server_action', 'Server Action']]}, - 'special' : {'name':'special', 'string': 'Special', 'type': 'selection', 'selection': [['',''],['save', 'Save Button'], ['cancel', 'Cancel Button'], ['open', 'Open Button']]}, - 'target' : {'name':'target', 'string': 'Target', 'type': 'selection', 'selection': [['', ''], ['new', 'New Window']]}, - 'confirm' : {'name':'confirm', 'string': 'Confirm', 'type': 'char'}, - 'style' : {'name':'style', 'string': 'Style', 'type': 'selection', 'selection':[["",""],["1", "1"],["1-1", "1-1"],["1-2", "1-2"],["2-1", "2-1"],["1-1-1", "1-1-1"]]}, - 'filename' : {'name':'filename', 'string': 'File Name', 'type': 'char'}, - 'width' : {'name':'width', 'string': 'Width', 'type': 'float'}, - 'height' : {'name':'height', 'string': 'Height', 'type': 'float'}, - 'attrs' : {'name':'attrs', 'string': 'Attrs', 'type': 'char'}, - 'col' : {'name':'col', 'string': 'col', 'type': 'float'}, - 'link' : {'name':'link', 'string': 'Link', 'type': 'char'}, - 'position' : {'name':'position', 'string': 'Position', 'type': 'selection', 'selection': [['',''],['after', 'After'],['before', 'Before'],['inside', 'Inside'],['replace', 'Replace']]}, - 'states' : {'name':'states', 'string': 'states', 'type': 'char'}, - 'eval' : {'name':'eval', 'string': 'Eval', 'type': 'char'}, - 'ref' : {'name':'ref', 'string': 'Ref', 'type': 'char'}, - 'on_change' : {'name':'on_change', 'string': 'On change', 'type': 'char'}, - 'nolabel' : {'name':'nolabel', 'string': 'No label', 'type': 'boolean'}, - 'completion' : {'name':'completion', 'string': 'Completion', 'type': 'boolean'}, - 'colspan' : {'name':'colspan', 'string': 'Colspan', 'type': 'float'}, - 'widget' : {'name':'widget', 'string': 'widget', 'type': 'selection'}, - 'colors' : {'name':'colors', 'string': 'Colors', 'type': 'char'}, - 'editable' : {'name':'editable', 'string': 'Editable', 'type': 'selection', 'selection': [["",""],["top","Top"],["bottom", "Bottom"]]}, - 'groups' : {'name':'groups', 'string': 'Groups', 'type': 'selection_multi'}, - 'fonts' : {'name':'fonts', 'string': 'fonts', 'type': 'char'}, - }; - var arch_val = self.get_object_by_id(this.one_object.clicked_tr_id,this.one_object['main_object'], []); - this.edit_node_dialog.$element.append('<table id="rec_table" style="width:400px" class="oe_form"></table>'); - this.edit_widget = []; - self.ready = $.when(self.on_groups(properties)).then(function () { - _PROPERTIES_ATTRIBUTES['groups']['selection'] = self.groups; - var values = _.keys( instance.web.form.widgets.map); - values.push(''); - values.sort(); - _PROPERTIES_ATTRIBUTES['widget']['selection'] = values; - var widgets = _.filter(_PROPERTIES_ATTRIBUTES, function (property) { return _.include(properties, property.name)}); - _.each(widgets, function(widget) { - var type_widget = new (self.property.get_any([widget.type])) (self.edit_node_dialog, widget); - var value = _.detect(arch_val[0]['att_list'],function(res) { - return res instanceof Array? _.include(res, widget.name): false; - }); - - value = value instanceof Array ? value[1] : value; - self.edit_node_dialog.$element.find('table[id=rec_table]').append('<tr><td align="right">' + widget.string + ':</td>' + type_widget.render() + '</tr>'); - type_widget.start(); - type_widget.set_value(value); - self.edit_widget.push(type_widget); - }); - }); - }, - //for getting groups - on_groups: function(properties){ - var self = this, - def = $.Deferred(); - if (!_.include(properties, 'groups')) { - self.groups = false; - def.resolve(); - } - var group_ids = [], group_names = {}, groups = []; - var res_groups = new instance.web.DataSetSearch(this,'res.groups', null, null), - model_data = new instance.web.DataSetSearch(self,'ir.model.data', null, null); - res_groups.read_slice([], {}).done(function (res_grp) { - _.each(res_grp, function (res) { - var key = res.id; - group_names[key]=res.full_name; - group_ids.push(res.id); - }); - model_data.read_slice([], {domain: [ - ['res_id', 'in', group_ids], - ['model', '=', 'res.groups'] - ]}).done(function (model_grp) { - _.each(model_grp, function (res_group) { - groups.push([res_group.module + "." + res_group.name, group_names[res_group.res_id]]); - }); - self.groups = groups; - def.resolve(); - }); - }); - return def.promise(); - }, - on_add_node: function(properties, fields){ - var self = this; - var render_list = [{'name': 'node_type','selection': _.keys(_CHILDREN).sort(), 'value': 'field', 'string': 'Node Type','type': 'selection'}, - {'name': 'field_value','selection': fields, 'value': false, 'string': '','type': 'selection'}, - {'name': 'position','selection': ['After','Before','Inside'], 'value': false, 'string': 'Position','type': 'selection'}]; - this.add_widget = []; - this.add_node_dialog = new instance.web.Dialog(this,{ - title: _t("Properties"), - width: 450, - buttons: [ - {text: _t("Update"), click: function() { - var check_add_node = true, values = {}; - _.each(self.add_widget, function(widget) { - values[widget.name] = widget.get_value() || false; - }); - (values.position == "Inside")? - check_add_node =(_.include(_CHILDREN[properties[0]],values.node_type))?true:false: - check_add_node =(_.include(_CHILDREN[properties[1]],values.node_type))?true:false; - if(values.node_type == "field" && check_add_node ) - {check_add_node = (values.field_value != " ")?true:false; - } - if(check_add_node){ - var tag = (values.node_type == "field")? - _.str.sprintf("<%s name='%s'> </%s>",values.node_type,values.field_value,values.node_type): - _.str.sprintf("<%s> </%s>",values.node_type,values.node_type); - self.do_save_update_arch("add_node", [tag, values.position]); - } else { - alert("Can't Update View"); - } - }}, - {text: _t("Cancel"), click: function() { self.add_node_dialog.close(); }} - ] - }).open(); - this.add_node_dialog.$element.append('<table id="rec_table" style="width:420px" class="oe_form"><tbody><tr></tbody></table>'); - var table_selector = self.add_node_dialog.$element.find('table[id=rec_table] tbody'); - _.each(render_list, function(node) { - type_widget = new (self.property.get_any([node.type])) (self.add_node_dialog, node); - if (node.name == "position") { - table_selector.append('</tr><tr><td align="right" width="100px">' + node.string + '</td>' + type_widget.render() + '</tr>'); - } else { - table_selector.append('<td align="right">' + node.string + '</td>' + type_widget.render() ); - if (node.name == "field_value") { - table_selector.append('<td id="new_field" align="right" width="100px"> <button>New Field</button></td>'); - } - } - type_widget.start(); - type_widget.set_value(node.value); - self.add_widget.push(type_widget); - }); - table_selector.find("td[id^=]").attr("width","100px"); - self.add_node_dialog.$element.find('#new_field').click(function() { - model_data = new instance.web.DataSetSearch(self,'ir.model', null, null); - model_data.read_slice([], {domain: [['model','=', self.model]]}).then(function(result) { - self.render_new_field(result[0]); - }); - }); - }, - render_new_field :function( result ) { - var self = this; - var action = { - context: {'default_model_id': result.id, 'manual': true, 'module' : result.model}, - res_model: "ir.model.fields", - views: [[false, 'form']], - type: 'ir.actions.act_window', - target: "new", - flags: { - action_buttons: true - } - }; - var action_manager = new instance.web.ActionManager(self); - $.when(action_manager.do_action(action)).then(function() { - var controller = action_manager.dialog_widget.views['form'].controller; - controller.on_button_cancel.add_last(function(){ - action_manager.destroy() - }); - controller.do_save.add_last(function(){ - action_manager.destroy(); - var value =controller.fields.name.get('value'); - self.add_node_dialog.$element.find('select[id=field_value]').append($("<option selected></option>").attr("value",value).text(value)); - _.detect(self.add_widget,function(widget){ - widget.name == "field_value"? widget.selection.push(value): false; - }); - }); - }); - } -}); -instance.web.ViewEditor.Field = instance.web.Class.extend({ - init: function(view, widget) { - this.$element = view.$element; - this.dirty = false; - this.name = widget.name; - this.selection = widget.selection || []; - this.required = widget.required || false; - this.string = widget.string || ""; - this.type = widget.type; - this.is_invalid = false; - }, - start: function () { - this.update_dom(); - }, - update_dom: function() { - this.$element.find("td[id=" + this.name + "]").toggleClass('invalid', this.is_invalid); - this.$element.find("td[id=" + this.name + "]").toggleClass('required', this.required); - }, - on_ui_change: function() { - this.validate(); - this.dirty = true; - this.update_dom(); - }, - validate: function() { - this.is_invalid = false; - try { - var value = instance.web.parse_value(this.get_value(), this, ''); - this.is_invalid = this.required && value === ''; - } catch(e) { - this.is_invalid = true; - } - }, - render: function() { - return _.str.sprintf("<td id = %s>%s</td>", this.name, QWeb.render(this.template, {widget: this})) - } -}); -instance.web.ViewEditor.FieldBoolean = instance.web.ViewEditor.Field.extend({ - template : "vieweditor_boolean", - start: function() { - var self = this; - this._super(); - this.$element.find("input[id="+ self.name+"]").change(function() { - self.on_ui_change(); - }); - }, - set_value: function(value) { - if (value) { - this.$element.find("input[id=" + this.name+ "]").attr('checked', true); - } - }, - get_value: function() { - return this.$element.find("input[id=" + this.name + "]").is(':checked')? "1" : null; - } -}); -instance.web.ViewEditor.FieldChar = instance.web.ViewEditor.Field.extend({ - template : "vieweditor_char", - start: function () { - var self = this; - this._super(); - this.$element.find("input[id="+ this.name+"]").css('width','100%').change(function() { - self.on_ui_change(); - }); - }, - set_value: function(value) { - this.$element.find("input[id=" + this.name + "]").val(value); - }, - get_value: function() { - return this.$element.find("input[id=" + this.name + "]").val(); - } -}); -instance.web.ViewEditor.FieldSelect = instance.web.ViewEditor.Field.extend({ - template : "vieweditor_selection", - start: function () { - var self = this; - this._super(); - this.$element.find("select[id=" + this.name + "]").css('width', '100%').change(function() { - self.on_ui_change(); - if (self.name == "node_type") { - if (self.get_value() == "field") { - self.$element.find('#new_field').show(); - self.$element.find("select[id=field_value]").show(); - } else { - self.$element.find('#new_field').hide(); - self.$element.find("select[id=field_value]").hide(); - } - } - }); - }, - set_value: function(value) { - var index = 0; - value = value === null? false: value; - for (var i = 0, ii = this.selection.length; i < ii; i++) { - if ((this.selection[i] instanceof Array && this.selection[i][0] === value) || this.selection[i] === value) index = i; - } - this.$element.find("select[id=" + this.name + "]")[0].selectedIndex = index; - }, - get_value: function() { - return this.$element.find("select[id=" + this.name + "]").val(); - } -}); -instance.web.ViewEditor.FieldSelectMulti = instance.web.ViewEditor.FieldSelect.extend({ - start: function () { - this._super(); - this.$element.find("select[id=" + this.name + "]").css('height', '100px').attr("multiple", true); - }, - set_value: function(value) { - var self = this; - self.$element.find("#groups option").attr("selected",false); - if (!value) return false; - _.each(this.selection, function(item) { - if (_.include(value.split(','), item[0])) { - self.$element.find("select[id="+self.name+"] option[value='" + item[0] +"']").attr("selected",1) - } - }); - } -}); -instance.web.ViewEditor.FieldFloat = instance.web.ViewEditor.FieldChar.extend({ -}); - -var _PROPERTIES = { - 'field' : ['name', 'string', 'required', 'readonly','invisible', 'domain', 'context', 'nolabel', 'completion', - 'colspan', 'widget', 'eval', 'ref', 'on_change', 'attrs', 'groups'], - 'form' : ['string', 'col', 'link'], - 'notebook' : ['colspan', 'position', 'groups'], - 'page' : ['string', 'states', 'attrs', 'groups'], - 'group' : ['string', 'col', 'colspan','invisible', 'states', 'attrs', 'groups'], - 'image' : ['filename', 'width', 'height', 'groups'], - 'separator' : ['string', 'colspan', 'groups'], - 'label': ['string', 'align', 'colspan', 'groups'], - 'button': ['name', 'string', 'icon', 'type', 'states', 'readonly', 'special', 'target', 'confirm', 'context', 'attrs', 'colspan', 'groups'], - 'newline' : [], - 'board': ['style'], - 'column' : [], - 'action' : ['name', 'string', 'colspan', 'groups'], - 'tree' : ['string', 'colors', 'editable', 'link', 'limit', 'min_rows', 'fonts'], - 'graph' : ['string', 'type'], - 'calendar' : ['string', 'date_start', 'date_stop', 'date_delay', 'day_length', 'color', 'mode'] -}; -var _CHILDREN = { - 'form': ['notebook', 'group', 'field', 'label', 'button','board', 'newline', 'separator'], - 'tree': ['field'], - 'graph': ['field'], - 'calendar': ['field'], - 'notebook': ['page'], - 'page': ['notebook', 'group', 'field', 'label', 'button', 'newline', 'separator'], - 'group': ['field', 'label', 'button', 'separator', 'newline','group'], - 'board': ['column'], - 'action': [], - 'field': ['form', 'tree', 'graph','field'], - 'label': [], - 'button' : [], - 'newline': [], - 'separator': [], - 'sheet' :['group','field','notebook','label','separator','div','page'], - 'kanban' : ['field'], - 'html_tag':['notebook', 'group', 'field', 'label', 'button','board', 'newline', 'separator'] -//e.g.:xyz 'td' : ['field'] -}; -// Generic html_tag list and can be added html tag in future. It's support above _CHILDREN dict's *html_tag* by default. -// For specific child node one has to define tag above and specify children tag in list. Like above xyz example. -var html_tag = ['div','h1','h2','h3','h4','h5','h6','td','tr']; - -var _ICONS = ['','STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD', - 'STOCK_CANCEL', 'STOCK_CDROM', 'STOCK_CLEAR', 'STOCK_CLOSE', 'STOCK_COLOR_PICKER', - 'STOCK_CONNECT', 'STOCK_CONVERT', 'STOCK_COPY', 'STOCK_CUT', 'STOCK_DELETE', - 'STOCK_DIALOG_AUTHENTICATION', 'STOCK_DIALOG_ERROR', 'STOCK_DIALOG_INFO', - 'STOCK_DIALOG_QUESTION', 'STOCK_DIALOG_WARNING', 'STOCK_DIRECTORY', 'STOCK_DISCONNECT', - 'STOCK_DND', 'STOCK_DND_MULTIPLE', 'STOCK_EDIT', 'STOCK_EXECUTE', 'STOCK_FILE', - 'STOCK_FIND', 'STOCK_FIND_AND_REPLACE', 'STOCK_FLOPPY', 'STOCK_GOTO_BOTTOM', - 'STOCK_GOTO_FIRST', 'STOCK_GOTO_LAST', 'STOCK_GOTO_TOP', 'STOCK_GO_BACK', - 'STOCK_GO_DOWN', 'STOCK_GO_FORWARD', 'STOCK_GO_UP', 'STOCK_HARDDISK', - 'STOCK_HELP', 'STOCK_HOME', 'STOCK_INDENT', 'STOCK_INDEX', 'STOCK_ITALIC', - 'STOCK_JUMP_TO', 'STOCK_JUSTIFY_CENTER', 'STOCK_JUSTIFY_FILL', - 'STOCK_JUSTIFY_LEFT', 'STOCK_JUSTIFY_RIGHT', 'STOCK_MEDIA_FORWARD', - 'STOCK_MEDIA_NEXT', 'STOCK_MEDIA_PAUSE', 'STOCK_MEDIA_PLAY', - 'STOCK_MEDIA_PREVIOUS', 'STOCK_MEDIA_RECORD', 'STOCK_MEDIA_REWIND', - 'STOCK_MEDIA_STOP', 'STOCK_MISSING_IMAGE', 'STOCK_NETWORK', 'STOCK_NEW', - 'STOCK_NO', 'STOCK_OK', 'STOCK_OPEN', 'STOCK_PASTE', 'STOCK_PREFERENCES', - 'STOCK_PRINT', 'STOCK_PRINT_PREVIEW', 'STOCK_PROPERTIES', 'STOCK_QUIT', - 'STOCK_REDO', 'STOCK_REFRESH', 'STOCK_REMOVE', 'STOCK_REVERT_TO_SAVED', - 'STOCK_SAVE', 'STOCK_SAVE_AS', 'STOCK_SELECT_COLOR', 'STOCK_SELECT_FONT', - 'STOCK_SORT_ASCENDING', 'STOCK_SORT_DESCENDING', 'STOCK_SPELL_CHECK', - 'STOCK_STOP', 'STOCK_STRIKETHROUGH', 'STOCK_UNDELETE', 'STOCK_UNDERLINE', - 'STOCK_UNDO', 'STOCK_UNINDENT', 'STOCK_YES', 'STOCK_ZOOM_100', - 'STOCK_ZOOM_FIT', 'STOCK_ZOOM_IN', 'STOCK_ZOOM_OUT', - 'terp-account', 'terp-crm', 'terp-mrp', 'terp-product', 'terp-purchase', - 'terp-sale', 'terp-tools', 'terp-administration', 'terp-hr', 'terp-partner', - 'terp-project', 'terp-report', 'terp-stock', 'terp-calendar', 'terp-graph' -]; -instance.web.ViewEditor.property_widget = new instance.web.Registry({ - 'boolean' : 'instance.web.ViewEditor.FieldBoolean', - 'selection_multi' : 'instance.web.ViewEditor.FieldSelectMulti', - 'selection' : 'instance.web.ViewEditor.FieldSelect', - 'char' : 'instance.web.ViewEditor.FieldChar', - 'float' : 'instance.web.ViewEditor.FieldFloat' -}); -}; diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 99df34d6c6c..b8acdfea4cd 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -79,6 +79,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM _.defaults(this.options, { "not_interactible_on_create": false, "initial_mode": "view", + "disable_autofocus": false, }); this.is_initialized = $.Deferred(); this.mutating_mutex = new $.Mutex(); @@ -150,19 +151,20 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM this.sidebar.add_items('other', [ { label: _t('Delete'), callback: self.on_button_delete }, { label: _t('Duplicate'), callback: self.on_button_duplicate }, - { label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } }, + { label: _t('Set Default'), callback: function (item) { self.open_defaults_dialog(); } } ]); } + this.has_been_loaded.resolve(); + // Add bounce effect on button 'Edit' when click on readonly page view. - this.$element.find(".oe_form_field, .oe_form_group_cell").on('click', function (e) { + this.$element.find(".oe_form_field,label").on('click', function (e) { if(self.get("actual_mode") == "view") { var $button = self.options.$buttons.find(".oe_form_button_edit"); - $button.wrap('<div>').css('margin-right','4px').addClass('oe_left oe_bounce'); + $button.effect('bounce', {distance: 18, times: 5}, 150) } }); - this.has_been_loaded.resolve(); return $.when(); }, extract_qweb_template: function(fvg) { @@ -269,9 +271,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (this.$pager) { this.$pager.show(); } + this.$element.show().css({ + opacity: '0', + filter: 'alpha(opacity = 0)' + }); this.$element.add(this.$buttons).removeClass('oe_form_dirty'); - this.$element.css('visibility', 'visible'); - this._super(); var shown = this.has_been_loaded; if (options.reload !== false) { @@ -291,6 +295,10 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM if (options.editable) { self.to_edit_mode(); } + self.$element.css({ + opacity: '1', + filter: 'alpha(opacity = 100)' + }); }); }, do_hide: function () { @@ -348,8 +356,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM } if (record.id) { self.do_push_state({id:record.id}); + } else { + self.do_push_state({}); } self.$element.add(self.$buttons).removeClass('oe_form_dirty'); + self.autofocus(); }); }, /** @@ -627,8 +638,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM */ _actualize_mode: function(switch_to) { var mode = switch_to || this.get("actual_mode"); - if (! this.datarecord.id) + if (! this.datarecord.id) { mode = "create"; + } this.set({actual_mode: mode}); }, check_actual_mode: function(source, options) { @@ -649,29 +661,39 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM _.each(this.fields,function(field){ field.set({"force_readonly": false}); }); - var fields_order = self.fields_order.slice(0); - if (self.default_focus_field) { - fields_order.unshift(self.default_focus_field.name); + this.autofocus(); + } + }, + autofocus: function() { + if (this.get("actual_mode") !== "view" && !this.options.disable_autofocus) { + var fields_order = this.fields_order.slice(0); + if (this.default_focus_field) { + fields_order.unshift(this.default_focus_field.name); } for (var i = 0; i < fields_order.length; i += 1) { - var field = self.fields[fields_order[i]]; + var field = this.fields[fields_order[i]]; if (!field.get('effective_invisible') && !field.get('effective_readonly')) { - field.focus(); - break; + if (field.focus() !== false) { + break; + } } } } }, on_button_save: function() { var self = this; - return this.do_save().then(function(result) { + return this.do_save().then(function(result) { self.to_view_mode(); }); }, on_button_cancel: function(event) { if (this.can_be_discarded()) { - this.to_view_mode(); - this.on_record_loaded(this.datarecord); + if (this.get('actual_mode') === 'create') { + this.trigger('history_back'); + } else { + this.to_view_mode(); + this.on_record_loaded(this.datarecord); + } } return false; }, @@ -768,16 +790,16 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM self.set({'display_invalid_fields': false}); var save_deferral; if (!self.datarecord.id) { - //console.log("FormView(", self, ") : About to create", values); + // console.log("FormView(", self, ") : About to create", values); save_deferral = self.dataset.create(values).pipe(function(r) { return self.on_created(r, undefined, prepend_on_create); }, null); } else if (_.isEmpty(values) && ! self.force_dirty) { - //console.log("FormView(", self, ") : Nothing to save"); + // console.log("FormView(", self, ") : Nothing to save"); save_deferral = $.Deferred().resolve({}).promise(); } else { self.force_dirty = false; - //console.log("FormView(", self, ") : About to save", values); + // console.log("FormView(", self, ") : About to save", values); save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) { return self.on_saved(r); }, null); @@ -1962,14 +1984,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w } }, focus: function() { - }, - /** - * Utility method to focus an element, but only after a small amount of time. - */ - delay_focus: function($elem) { - setTimeout(function() { - $elem[0].focus(); - }, 50); + return false; }, /** * Utility method to get the widget options defined in the field xml description. @@ -2068,7 +2083,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we return this.get('value') === '' || this._super(); }, focus: function() { - this.$element.find('input:first')[0].focus(); + this.$('input:first').focus(); } }); @@ -2152,6 +2167,9 @@ instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({ value_ = 0; } this._super.apply(this, [value_]); + }, + focus: function () { + this.$('input:first').select(); } }); @@ -2288,8 +2306,9 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc return this.get('value') === '' || this._super(); }, focus: function() { - if (this.datewidget && this.datewidget.$input) - this.delay_focus(this.datewidget.$input); + if (this.datewidget && this.datewidget.$input) { + this.datewidget.$input.focus(); + } } }); @@ -2344,7 +2363,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we return this.get('value') === '' || this._super(); }, focus: function($element) { - this.delay_focus(this.$textarea); + this.$textarea.focus(); }, do_resize: function(max_height) { max_height = parseInt(max_height, 10); @@ -2437,7 +2456,7 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({ this.$checkbox[0].checked = value_; }, focus: function() { - this.delay_focus(this.$checkbox); + this.$checkbox.focus(); } }); @@ -2461,9 +2480,6 @@ instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({ } }); -instance.web.form.FieldTextXml = instance.web.form.AbstractField.extend({ -// to replace view editor -}); instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, { template: 'FieldSelection', @@ -2532,7 +2548,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan return !! value_; }, focus: function() { - this.delay_focus(this.$element.find('select:first')); + this.$element.find('select:first').focus(); } }); @@ -2702,10 +2718,20 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc self.$input.tipsy({ title: function() { - return "No element was selected, you should create or select one from the dropdown list."; + return QWeb.render('Tipsy.alert', { + message: "No element was selected, you should create or select one from the dropdown list." + }); }, trigger:'manual', fade: true, + gravity: 's', + html: true, + opacity: 1, + offset: 4, + }); + + self.$input.on('focus', function() { + self.$input.tipsy("hide"); }); this.$drop_down = this.$element.find(".oe_m2o_drop_down_button"); @@ -2733,7 +2759,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc }); // some behavior for input - this.$input.keydown(function() { + var input_changed = function() { if (self.current_display !== self.$input.val()) { self.current_display = self.$input.val(); if (self.$input.val() === "") { @@ -2743,7 +2769,9 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc self.floating = true; } } - }); + }; + this.$input.keydown(input_changed); + this.$input.change(input_changed); this.$drop_down.click(function() { if (self.$input.autocomplete("widget").is(":visible")) { self.$input.autocomplete("close"); @@ -2759,7 +2787,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc var tip_def = $.Deferred(); var untip_def = $.Deferred(); var tip_delay = 200; - var tip_duration = 3000; + var tip_duration = 15000; var anyoneLoosesFocus = function() { var used = false; if (self.floating) { @@ -2819,6 +2847,8 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc } else if (item.action) { self.floating = true; item.action(); + // Cancel widget blurring, to avoid form blur event + self.trigger('focused'); return false; } }, @@ -2842,7 +2872,6 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc }); this.setupFocus(this.$input.add(this.$follow_button)); }, - render_value: function(no_recurse) { var self = this; if (! this.get("value")) { @@ -2867,6 +2896,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc if (!this.get("effective_readonly")) { this.$input.val(str.split("\n")[0]); this.current_display = this.$input.val(); + this.$('.oe_m2o_cm_button').css({'visibility': this.is_false() ? 'hidden' : 'visible'}); } else { var lines = _.escape(str).split("\n"); var link = ""; @@ -2922,7 +2952,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc return ! this.get("value"); }, focus: function () { - this.delay_focus(this.$input); + this.$input.focus(); } }); @@ -2985,7 +3015,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({ }, start: function() { this._super.apply(this, arguments); - this.$element.addClass('oe_form_field_one2many'); + this.$element.addClass('oe_form_field oe_form_field_one2many'); var self = this; @@ -3327,6 +3357,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ ListType: instance.web.form.One2ManyList })); this.on('edit:before', this, this.proxy('_before_edit')); + this.on('edit:after', this, this.proxy('_after_edit')); this.on('save:before cancel:before', this, this.proxy('_before_unedit')); this.records @@ -3437,6 +3468,12 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ this.__ignore_blur = false; this.editor.form.on('blurred', this, this._on_form_blur); }, + _after_edit: function () { + // The form's blur thing may be jiggered during the edition setup, + // potentially leading to the o2m instasaving the row. Cancel any + // blurring triggered the edition startup here + this.editor.form.widgetFocused(); + }, _before_unedit: function () { this.editor.form.off('blurred', this, this._on_form_blur); }, @@ -3470,6 +3507,28 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({ // the current row *anyway*, then create a new one/edit the next one) this.__ignore_blur = true; this._super.apply(this, arguments); + }, + do_delete: function (ids) { + var self = this; + var next = $.when(); + var _super = this._super; + // handle deletion of an item which does not exist + // TODO: better handle that in the editable list? + var false_id_index = _(ids).indexOf(false); + if (false_id_index !== -1) { + ids.splice(false_id_index, 1); + next = this.cancel_edition(true); + } + return next.pipe(function () { + // wheeee + var confirm = window.confirm; + window.confirm = function () { return true; }; + try { + return _super.call(self, ids); + } finally { + window.confirm = confirm; + } + }); } }); instance.web.form.One2ManyList = instance.web.ListView.List.extend({ @@ -3490,14 +3549,34 @@ instance.web.form.One2ManyList = instance.web.ListView.List.extend({ var $cell = $('<td>', { colspan: columns, 'class': 'oe_form_field_one2many_list_row_add' - }).text(_t("Add a row")) - .click(function (e) { - e.preventDefault(); - e.stopPropagation(); - self.view.do_add_record(); - }); - this.$current.append( - $('<tr>').append($cell)) + }).append( + $('<a>', {href: '#'}).text(_t("Add a row")) + .mousedown(function () { + // FIXME: needs to be an official API somehow + if (self.view.editor.is_editing()) { + self.view.__ignore_blur = true; + } + }) + .click(function (e) { + e.preventDefault(); + e.stopPropagation(); + // FIXME: there should also be an API for that one + if (self.view.editor.form.__blur_timeout) { + clearTimeout(self.view.editor.form.__blur_timeout); + self.view.editor.form.__blur_timeout = false; + } + self.view.ensure_saved().then(function () { + self.view.do_add_record(); + }); + })); + + var $padding = this.$current.find('tr:not([data-id]):first'); + var $newrow = $('<tr>').append($cell); + if ($padding.length) { + $padding.before($newrow); + } else { + this.$current.append($newrow) + } } }); @@ -3605,7 +3684,7 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in $("textarea", this.$element).focusout(function() { self.$text.trigger("setInputData", ""); }).keydown(function(e) { - if (event.keyCode === 9 && self._drop_shown) { + if (e.which === $.ui.keyCode.TAB && self._drop_shown) { self.$text.textext()[0].autocomplete().selectFromDropdown(); } }); @@ -4534,7 +4613,7 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ }, render_value: function() { var url; - if (this.get('value') && this.get('value').substr(0, 10).indexOf(' ') == -1) { + if (this.get('value') && ! /^\d+(\.\d*)? \w+$/.test(this.get('value'))) { url = 'data:image/png;base64,' + this.get('value'); } else if (this.get('value')) { url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' + @@ -4563,9 +4642,11 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ template: "FieldStatus", + clickable: false, start: function() { this._super(); this.selected_value = null; + this.clickable = !!this.node.attrs.clickable; if (this.$element.parent().is('header')) { this.$element.after('<div class="oe_clear"/>'); } @@ -4670,19 +4751,34 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({ * state (given by the key of (key, label)). */ render_elements: function () { + var self = this; var content = instance.web.qweb.render("FieldStatus.content", {widget: this, _:_}); this.$element.html(content); - + if (this.clickable) { + this.$element.addClass("oe_form_steps_clickable"); + $('.oe_form_steps_arrow').remove(); + var elemts = this.$element.find('.oe_form_steps_button'); + _.each(elemts, function(element){ + $item = $(element); + if ($item.attr("data-id") != self.selected_value) { + $item.click(function(event){ + var data_id = parseInt($(this).attr("data-id")) + self.view.dataset.call('stage_set', [[self.view.datarecord.id],data_id]).then(function() { + return self.view.reload(); + }); + }); + } + }); + } else { + this.$element.addClass("oe_form_steps"); + } var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}"); var color = colors[this.selected_value]; - if (color) { + if (color) { var elem = this.$element.find("li.oe_form_steps_active span"); - elem.css("color", color); + elem.css("color", color); } }, - focus: function() { - return false; - }, }); /** diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index 9c7bf88db1a..986b0e49faf 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -354,7 +354,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi this.sidebar.add_items('other', [ { label: _t("Import"), callback: this.on_sidebar_import }, { label: _t("Export"), callback: this.on_sidebar_export }, - { label: _t('Delete'), callback: this.do_delete_selected }, + { label: _t('Delete'), callback: this.do_delete_selected } ]); this.sidebar.add_toolbar(this.fields_view.toolbar); this.sidebar.$element.hide(); @@ -399,77 +399,23 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi * @param {Boolean} [grouped] Should the grouping columns (group and count) be displayed */ setup_columns: function (fields, grouped) { - var domain_computer = instance.web.form.compute_domain; - - var noop = function () { return {}; }; - var field_to_column = function (field) { - var name = field.attrs.name; - var column = _.extend({id: name, tag: field.tag}, - fields[name], field.attrs); - // modifiers computer - if (column.modifiers) { - var modifiers = JSON.parse(column.modifiers); - column.modifiers_for = function (fields) { - var out = {}; - - for (var attr in modifiers) { - if (!modifiers.hasOwnProperty(attr)) { continue; } - var modifier = modifiers[attr]; - out[attr] = _.isBoolean(modifier) - ? modifier - : domain_computer(modifier, fields); - } - - return out; - }; - if (modifiers['tree_invisible']) { - column.invisible = '1'; - } else { - delete column.invisible; - } - column.modifiers = modifiers; - } else { - column.modifiers_for = noop; - column.modifiers = {}; - } - return column; - }; - + var registry = instance.web.list.columns; this.columns.splice(0, this.columns.length); - this.columns.push.apply( - this.columns, - _(this.fields_view.arch.children).map(field_to_column)); + this.columns.push.apply(this.columns, + _(this.fields_view.arch.children).map(function (field) { + var id = field.attrs.name; + return registry.for_(id, fields[id], field); + })); if (grouped) { - this.columns.unshift({ - id: '_group', tag: '', string: _t("Group"), meta: true, - modifiers_for: function () { return {}; }, - modifiers: {} - }, { - id: '_count', tag: '', string: '#', meta: true, - modifiers_for: function () { return {}; }, - modifiers: {} - }); + this.columns.unshift( + new instance.web.list.MetaColumn('_group', _t("Group"))); } this.visible_columns = _.filter(this.columns, function (column) { return column.invisible !== '1'; }); - this.aggregate_columns = _(this.visible_columns) - .map(function (column) { - if (column.type !== 'integer' && column.type !== 'float') { - return {}; - } - var aggregation_func = column['group_operator'] || 'sum'; - if (!(aggregation_func in column)) { - return {}; - } - - return _.extend({}, column, { - 'function': aggregation_func, - label: column[aggregation_func] - }); - }); + this.aggregate_columns = _(this.visible_columns).invoke('to_aggregate'); }, /** * Used to handle a click on a table row, if no other handler caught the @@ -678,6 +624,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi * Base handling of buttons, can be called when overriding do_button_action * in order to bypass parent overrides. * + * The callback will be provided with the ``id`` as its parameter, in case + * handle_button's caller had to alter the ``id`` (or even create one) + * while not being ``callback``'s creator. + * * This method should not be overridden. * * @param {String} name action name @@ -703,7 +653,8 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi c.add(action.context); } action.context = c; - this.do_execute_action(action, this.dataset, id, callback); + this.do_execute_action( + action, this.dataset, id, _.bind(callback, null, id)); }, /** * Handles the activation of a record (clicking on it) @@ -819,9 +770,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi } $footer_cells.filter(_.str.sprintf('[data-field=%s]', column.id)) - .html(instance.web.format_cell(aggregation, column, { - process_modifiers: false - })); + .html(column.format(aggregation, { process_modifiers: false })); }); }, get_selected_ids: function() { @@ -880,9 +829,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi } this.$element.find('table:first').hide(); this.$element.prepend( - $('<div class="oe_view_nocontent">') - .append($('<img>', { src: '/web/static/src/img/view_empty_arrow.png' })) - .append($('<div>').html(this.options.action.help)) + $('<div class="oe_view_nocontent">').html(this.options.action.help) ); } }); @@ -997,8 +944,8 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. // of digits, nice when storing actual numbers, not nice when // storing strings composed only of digits. Force the action // name to be a string - $(self).trigger('action', [field.toString(), record_id, function () { - return self.reload_record(self.records.get(record_id)); + $(self).trigger('action', [field.toString(), record_id, function (id) { + return self.reload_record(self.records.get(id)); }]); }) .delegate('a', 'click', function (e) { @@ -1059,7 +1006,7 @@ instance.web.ListView.List = instance.web.Class.extend( /** @lends instance.web. }); } } - return instance.web.format_cell(record.toForm().data, column, { + return column.format(record.toForm().data, { model: this.dataset.model, id: record.get('id') }); @@ -1344,15 +1291,18 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we _t("Grouping on field '%s' is not possible because that field does not appear in the list view."), group.grouped_on)); } + var group_label; try { - $group_column.html(instance.web.format_cell( - row_data, group_column, { - value_if_empty: _t("Undefined"), - process_modifiers: false - })); + group_label = group_column.format(row_data, { + value_if_empty: _t("Undefined"), + process_modifiers: false + }); } catch (e) { - $group_column.html(row_data[group_column.id].value); + group_label = row_data[group_column.id].value; } + $group_column.text(_.str.sprintf("%s (%d)", + group_label, group.length)); + if (group.length && group.openable) { // Make openable if not terminal group & group_by_no_leaf $group_column.prepend('<span class="ui-icon ui-icon-triangle-1-e" style="float: left;">'); @@ -1364,14 +1314,12 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we } } self.indent($group_column, group.level); - // count column - $('<td>').text(group.length).appendTo($row); if (self.options.selectable) { $row.append('<td>'); } _(self.columns).chain() - .filter(function (column) {return !column.invisible;}) + .filter(function (column) { return column.invisible !== '1'; }) .each(function (column) { if (column.meta) { // do not do anything @@ -1379,8 +1327,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we var r = {}; r[column.id] = {value: group.aggregates[column.id]}; $('<td class="oe_number">') - .html(instance.web.format_cell( - r, column, {process_modifiers: false})) + .html(column.format(r, {process_modifiers: false})) .appendTo($row); } else { $row.append('<td>'); @@ -1467,18 +1414,31 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we }, setup_resequence_rows: function (list, dataset) { // drag and drop enabled if list is not sorted and there is a - // "sequence" column in the view. + // visible column with @widget=handle or "sequence" column in the view. if ((dataset.sort && dataset.sort()) || !_(this.columns).any(function (column) { - return column.name === 'sequence'; })) { + return column.widget === 'handle' + || column.name === 'sequence'; })) { return; } + var sequence_field = _(this.columns).find(function (c) { + return c.widget === 'handle'; + }); + var seqname = sequence_field ? sequence_field.name : 'sequence'; + // ondrop, move relevant record & fix sequences list.$current.sortable({ axis: 'y', items: '> tr[data-id]', - containment: 'parent', - helper: 'clone', + helper: 'clone' + }); + if (sequence_field) { + list.$current.sortable('option', 'handle', '.oe_list_field_handle'); + } + list.$current.sortable('option', { + start: function (e, ui) { + ui.placeholder.height(ui.item.height()); + }, stop: function (event, ui) { var to_move = list.records.get(ui.item.data('id')), target_id = ui.item.prev().data('id'), @@ -1496,7 +1456,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we var record, index = to, // if drag to 1st row (to = 0), start sequencing from 0 // (exclusive lower bound) - seq = to ? list.records.at(to - 1).get('sequence') : 0; + seq = to ? list.records.at(to - 1).get(seqname) : 0; while (++seq, record = list.records.at(index++)) { // write are independent from one another, so we can just // launch them all at the same time and we don't really @@ -1506,10 +1466,12 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we // when synchronous (without setTimeout) (function (dataset, id, seq) { $.async_when().then(function () { - dataset.write(id, {sequence: seq}); + var attrs = {}; + attrs[seqname] = seq; + dataset.write(id, attrs); }); }(dataset, record.get('id'), seq)); - record.set('sequence', seq); + record.set(seqname, seq); } } }); @@ -1963,6 +1925,204 @@ instance.web.list = { Events: Events, Record: Record, Collection: Collection -} +}; +/** + * Registry for column objects used to format table cells (and some other tasks + * e.g. aggregation computations). + * + * Maps a field or button to a Column type via its ``$tag.$widget``, + * ``$tag.$type`` or its ``$tag`` (alone). + * + * This specific registry has a dedicated utility method ``for_`` taking a + * field (from fields_get/fields_view_get.field) and a node (from a view) and + * returning the right object *already instantiated from the data provided*. + * + * @type {instance.web.Registry} + */ +instance.web.list.columns = new instance.web.Registry({ + 'field': 'instance.web.list.Column', + 'field.boolean': 'instance.web.list.Boolean', + 'field.binary': 'instance.web.list.Binary', + 'field.progressbar': 'instance.web.list.ProgressBar', + 'field.handle': 'instance.web.list.Handle', + 'button': 'instance.web.list.Button', +}); +instance.web.list.columns.for_ = function (id, field, node) { + var description = _.extend({tag: node.tag}, field, node.attrs); + var tag = description.tag; + var Type = this.get_any([ + tag + '.' + description.widget, + tag + '.'+ description.type, + tag + ]); + return new Type(id, node.tag, description) +}; + +instance.web.list.Column = instance.web.Class.extend({ + init: function (id, tag, attrs) { + _.extend(attrs, { + id: id, + tag: tag + }); + + this.modifiers = attrs.modifiers ? JSON.parse(attrs.modifiers) : {}; + delete attrs.modifiers; + _.extend(this, attrs); + + if (this.modifiers['tree_invisible']) { + this.invisible = '1'; + } else { delete this.invisible; } + }, + modifiers_for: function (fields) { + var out = {}; + var domain_computer = instance.web.form.compute_domain; + + for (var attr in this.modifiers) { + if (!this.modifiers.hasOwnProperty(attr)) { continue; } + var modifier = this.modifiers[attr]; + out[attr] = _.isBoolean(modifier) + ? modifier + : domain_computer(modifier, fields); + } + + return out; + }, + to_aggregate: function () { + if (this.type !== 'integer' && this.type !== 'float') { + return {}; + } + var aggregation_func = this['group_operator'] || 'sum'; + if (!(aggregation_func in this)) { + return {}; + } + var C = function (label, fn) { + this['function'] = fn; + this.label = label; + }; + C.prototype = this; + return new C(aggregation_func, this[aggregation_func]); + }, + /** + * + * @param row_data record whose values should be displayed in the cell + * @param {Object} [options] + * @param {String} [options.value_if_empty=''] what to display if the field's value is ``false`` + * @param {Boolean} [options.process_modifiers=true] should the modifiers be computed ? + * @param {String} [options.model] current record's model + * @param {Number} [options.id] current record's id + * @return {String} + */ + format: function (row_data, options) { + options = options || {}; + var attrs = {}; + if (options.process_modifiers !== false) { + attrs = this.modifiers_for(row_data); + } + if (attrs.invisible) { return ''; } + + if (!row_data[this.id]) { + return options.value_if_empty === undefined + ? '' + : options.value_if_empty; + } + return this._format(row_data, options); + }, + /** + * Method to override in order to provide alternative HTML content for the + * cell. Column._format will simply call ``instance.web.format_value`` and + * escape the output. + * + * The output of ``_format`` will *not* be escaped by ``format``, any + * escaping *must be done* by ``format``. + * + * @private + */ + _format: function (row_data, options) { + return _.escape(instance.web.format_value( + row_data[this.id].value, this, options.value_if_empty)); + } +}); +instance.web.list.MetaColumn = instance.web.list.Column.extend({ + meta: true, + init: function (id, string) { + this._super(id, '', {string: string}); + } +}); +instance.web.list.Button = instance.web.list.Column.extend({ + /** + * Return an actual ``<button>`` tag + */ + format: function (row_data, options) { + return _.template('<button type="button" title="<%-title%>" <%=additional_attributes%> >' + + '<img src="<%-prefix%>/web/static/src/img/icons/<%-icon%>.png" alt="<%-alt%>"/>' + + '</button>', { + title: this.string || '', + additional_attributes: isNaN(row_data["id"].value) && instance.web.BufferedDataSet.virtual_id_regex.test(row_data["id"].value) ? + 'disabled="disabled" class="oe_list_button_disabled"' : '', + prefix: instance.connection.prefix, + icon: this.icon, + alt: this.string || '' + }); + } +}); +instance.web.list.Boolean = instance.web.list.Column.extend({ + /** + * Return a potentially disabled checkbox input + * + * @private + */ + _format: function (row_data, options) { + return _.str.sprintf('<input type="checkbox" %s disabled="disabled"/>', + row_data[this.id].value ? 'checked="checked"' : ''); + } +}); +instance.web.list.Binary = instance.web.list.Column.extend({ + /** + * Return a link to the binary data as a file + * + * @private + */ + _format: function (row_data, options) { + var text = _t("Download"); + var download_url = _.str.sprintf( + '/web/binary/saveas?session_id=%s&model=%s&field=%s&id=%d', + instance.connection.session_id, options.model, this.id, options.id); + if (this.filename) { + download_url += '&filename_field=' + this.filename; + if (row_data[this.filename]) { + text = _.str.sprintf(_t("Download \"%s\""), instance.web.format_value( + row_data[this.filename].value, {type: 'char'})); + } + } + return _.template('<a href="<%-href%>"><%-text%></a> (%<-size%>)', { + text: text, + href: download_url, + size: row_data[this.id].value + }); + } +}); +instance.web.list.ProgressBar = instance.web.list.Column.extend({ + /** + * Return a formatted progress bar display + * + * @private + */ + _format: function (row_data, options) { + return _.template( + '<progress value="<%-value%>" max="100"><%-value%>%</progress>', { + value: _.str.sprintf("%.0f", row_data[this.id].value || 0) + }); + } +}); +instance.web.list.Handle = instance.web.list.Column.extend({ + /** + * Return styling hooks for a drag handle + * + * @private + */ + _format: function (row_data, options) { + return '<div class="oe_list_handle">'; + } +}); }; // vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax: diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js index 6c38495d0dc..9a101a5ac1a 100644 --- a/addons/web/static/src/js/view_list_editable.js +++ b/addons/web/static/src/js/view_list_editable.js @@ -99,6 +99,7 @@ openerp.web.list_editable = function (instance) { // tree/@editable takes priority on everything else if present. var result = this._super(data, grouped); if (this.editable()) { + this.$element.addClass('oe_list_editable'); // FIXME: any hook available to ensure this is only done once? this.$buttons .off('click', '.oe_list_save') @@ -123,6 +124,8 @@ openerp.web.list_editable = function (instance) { .then(this.proxy('setup_events')); return $.when(result, editor_ready); + } else { + this.$element.removeClass('oe_list_editable'); } return result; @@ -135,10 +138,13 @@ openerp.web.list_editable = function (instance) { make_editor: function () { return new instance.web.list.Editor(this); }, - do_button_action: function () { + do_button_action: function (name, id, callback) { var self = this, args = arguments; - this.ensure_saved().then(function () { - self.handle_button.apply(self, args); + this.ensure_saved().then(function (done) { + if (!id && done.created) { + id = done.record.get('id'); + } + self.handle_button.call(self, name, id, callback); }); }, /** @@ -242,10 +248,11 @@ openerp.web.list_editable = function (instance) { var $cell = $(cell); var position = $cell.position(); + // jquery does not understand !important + field.$element.attr('style', 'width: '+$cell.outerWidth()+'px !important') field.$element.css({ top: position.top, left: position.left, - width: $cell.outerWidth(), minHeight: $cell.outerHeight() }); }, @@ -281,16 +288,17 @@ openerp.web.list_editable = function (instance) { }); }, /** + * @param {Boolean} [force=false] discards the data even if the form has been edited * @return {jQuery.Deferred} */ - cancel_edition: function () { + cancel_edition: function (force) { var self = this; return this.with_event('cancel', { editor: this.editor, form: this.editor.form, cancel: false }, function () { - return this.editor.cancel().pipe(function (attrs) { + return this.editor.cancel(force).pipe(function (attrs) { if (attrs.id) { var record = self.records.get(attrs.id); if (!record) { @@ -602,6 +610,7 @@ openerp.web.list_editable = function (instance) { this.form = new (this.options.formView)( this, this.delegate.dataset, false, { initial_mode: 'edit', + disable_autofocus: true, $buttons: $(), $pager: $() }); @@ -681,9 +690,8 @@ openerp.web.list_editable = function (instance) { if (!field.$element.is(':visible')) { return false; } - field.focus(); // Stop as soon as a field got focused - return true; + return field.focus() !== false; }); }, edit: function (record, configureField, options) { @@ -717,13 +725,13 @@ openerp.web.list_editable = function (instance) { return self.cancel(); }); }, - cancel: function () { - var record = this.record; - this.record = null; - if (!this.form.can_be_discarded()) { + cancel: function (force) { + if (!(force || this.form.can_be_discarded())) { return $.Deferred().reject({ message: "The form's data can not be discarded"}).promise(); } + var record = this.record; + this.record = null; this.form.do_hide(); return $.when(record); } diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index 2b79701ba4d..2845d9afb73 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -14,6 +14,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog = null; this.dialog_widget = null; this.breadcrumbs = []; + this.on('history_back', this, function() { + return this.history_back(); + }); }, start: function() { this._super.apply(this, arguments); @@ -65,21 +68,46 @@ instance.web.ActionManager = instance.web.Widget.extend({ item.id = _.uniqueId('breadcrumb_'); this.breadcrumbs.push(item); }, + history_back: function() { + var last = this.breadcrumbs.slice(-1)[0]; + if (!last) { + return false; + } + var title = last.get_title(); + if (_.isArray(title) && title.length > 1) { + return this.select_breadcrumb(this.breadcrumbs.length - 1, title.length - 2); + } else if (this.breadcrumbs.length === 1) { + // Only one single titled item in breadcrumb, most of the time you want to trigger back to home + return false; + } else { + var prev = this.breadcrumbs[this.breadcrumbs.length - 2]; + title = prev.get_title(); + return this.select_breadcrumb(this.breadcrumbs.length - 2, _.isArray(title) ? title.length - 1 : undefined); + } + }, on_breadcrumb_clicked: function(ev) { var $e = $(ev.target); var id = $e.data('id'); - var item; + var index; for (var i = this.breadcrumbs.length - 1; i >= 0; i--) { - var it = this.breadcrumbs[i]; - if (it.id == id) { - item = it; + if (this.breadcrumbs[i].id == id) { + index = i; break; } - this.remove_breadcrumb(i); } - var index = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); - item.show(index, $e); + var subindex = $e.parent().find('.oe_breadcrumb_item[data-id=' + $e.data('id') + ']').index($e); + this.select_breadcrumb(index, subindex); + }, + select_breadcrumb: function(index, subindex) { + for (var i = this.breadcrumbs.length - 1; i >= 0; i--) { + if (i > index) { + this.remove_breadcrumb(i); + } + } + var item = this.breadcrumbs[index]; + item.show(subindex); this.inner_widget = item.widget; + return true; }, clear_breadcrumbs: function() { while (this.breadcrumbs.length) { @@ -117,6 +145,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ return titles.join(' <span class="oe_fade">/</span> '); }, do_push_state: function(state) { + state = state || {}; if (this.getParent() && this.getParent().do_push_state) { if (this.inner_action) { state['title'] = this.inner_action.name; @@ -124,7 +153,10 @@ instance.web.ActionManager = instance.web.Widget.extend({ state['model'] = this.inner_action.res_model; } if (this.inner_action.id) { - state['action_id'] = this.inner_action.id; + state['action'] = this.inner_action.id; + } else if (this.inner_action.type == 'ir.actions.client') { + state['action'] = this.inner_action.tag; + //state = _.extend(this.inner_action.params || {}, state); } } this.getParent().do_push_state(state); @@ -133,14 +165,20 @@ instance.web.ActionManager = instance.web.Widget.extend({ do_load_state: function(state, warm) { var self = this, action_loaded; - if (state.action_id) { - var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action_id; - if (run_action) { + if (state.action) { + if (_.isString(state.action) && instance.web.client_actions.contains(state.action)) { + var action_client = {type: "ir.actions.client", tag: state.action, params: state}; this.null_action(); - action_loaded = this.do_action(state.action_id); - instance.webclient.menu.has_been_loaded.then(function() { - instance.webclient.menu.open_action(state.action_id); - }); + action_loaded = this.do_action(action_client); + } else { + var run_action = (!this.inner_widget || !this.inner_widget.action) || this.inner_widget.action.id !== state.action; + if (run_action) { + this.null_action(); + action_loaded = this.do_action(state.action); + instance.webclient.menu.has_been_loaded.then(function() { + instance.webclient.menu.open_action(state.action); + }); + } } } else if (state.model && state.id) { // TODO handle context & domain ? @@ -154,23 +192,12 @@ instance.web.ActionManager = instance.web.Widget.extend({ action_loaded = this.do_action(action); } else if (state.sa) { // load session action - var self = this; this.null_action(); action_loaded = this.rpc('/web/session/get_session_action', {key: state.sa}).pipe(function(action) { if (action) { return self.do_action(action); } }); - } else if (state.client_action) { - this.null_action(); - var action = state.client_action; - if(_.isString(action)) { - action = { - tag: action, - params: state, - }; - } - this.ir_actions_client(action); } $.when(action_loaded || null).then(function() { @@ -191,7 +218,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ } if (!action.type) { console.error("No type for action", action); - return; + return null; } var type = action.type.replace(/\./g,'_'); var popup = action.target === 'new'; @@ -206,7 +233,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ }, action.flags || {}); if (!(type in this)) { console.error("Action manager can't handle action of type " + action.type, action); - return; + return null; } return this[type](action, on_close); }, @@ -216,21 +243,24 @@ instance.web.ActionManager = instance.web.Widget.extend({ }, do_ir_actions_common: function(action, on_close) { - var self = this, klass, widget, add_breadcrumb; + var self = this, klass, widget, post_process; if (action.type === 'ir.actions.client') { var ClientWidget = instance.web.client_actions.get_object(action.tag); widget = new ClientWidget(this, action.params); klass = 'oe_act_client'; - add_breadcrumb = function() { + post_process = function() { self.push_breadcrumb({ widget: widget, title: action.name }); - } + if (action.tag !== 'reload') { + self.do_push_state({}); + } + }; } else { widget = new instance.web.ViewManagerAction(this, action); klass = 'oe_act_window'; - add_breadcrumb = widget.proxy('add_breadcrumb'); + post_process = widget.proxy('add_breadcrumb'); } if (action.target === 'new') { if (this.dialog === null) { @@ -250,14 +280,9 @@ instance.web.ActionManager = instance.web.Widget.extend({ this.dialog.open(); } else { this.dialog_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_widget = widget; - add_breadcrumb(); + post_process(); this.inner_widget.appendTo(this.$element); } }, @@ -435,7 +460,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ container.hide(); controller.do_hide(); } - // put the <footer> in the dialog's buttonpane + // 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( @@ -462,6 +487,13 @@ instance.web.ViewManager = instance.web.Widget.extend({ } var controller = new controllerclass(this, this.dataset, view.view_id, options); + controller.on('history_back', this, function() { + var am = self.getParent(); + if (am && am.trigger) { + return am.trigger('history_back'); + } + }); + controller.on("change:title", this, function() { if (self.active_view === view_type) { self.set_title(controller.get('title')); @@ -505,7 +537,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ this.getParent().push_breadcrumb({ widget: this, action: this.action, - show: function(index, $e) { + show: function(index) { var view_to_select = views[index]; self.$element.show(); if (self.active_view !== view_to_select) { @@ -528,7 +560,7 @@ instance.web.ViewManager = instance.web.Widget.extend({ } return controller.get('title'); }); - if (next && next.action.res_id && self.active_view === 'form' && self.model === next.action.res_model && id === next.action.res_id) { + if (next && next.action && next.action.res_id && self.active_view === 'form' && self.model === next.action.res_model && id === next.action.res_id) { // If the current active view is a formview and the next item in the breadcrumbs // is an action on same object (model / res_id), then we omit the current formview's title titles.pop(); @@ -755,15 +787,6 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({ width: '95%'}, $root).open(); }); break; - case 'manage_views': - if (current_view.fields_view && current_view.fields_view.arch) { - var view_editor = new instance.web.ViewEditor(current_view, current_view.$element, this.dataset, current_view.fields_view.arch); - view_editor.start(); - } else { - this.do_warn(_t("Manage Views"), - _t("Could not find current view declaration")); - } - break; case 'edit_workflow': return this.do_action({ res_model : 'workflow', @@ -1052,14 +1075,15 @@ instance.web.TranslateDialog = instance.web.Dialog.extend({ this['on_button_' + _t("Close")] = this.on_btn_close; this._super(view, { width: '80%', - height: '80%' + height: '80%', + destroy_on_close: false, }); this.view = view; this.view_type = view.fields_view.type || ''; this.$fields_form = null; this.$view_form = null; this.$sidebar_form = null; - this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name }); + this.translatable_fields_keys = _.map(this.view.translatable_fields || [], function(i) { return i.name; }); this.languages = null; this.languages_loaded = $.Deferred(); (new instance.web.DataSetSearch(this, 'res.lang', this.view.dataset.get_context(), @@ -1090,7 +1114,8 @@ instance.web.TranslateDialog = instance.web.Dialog.extend({ deffered.push(deff); var callback = function(values) { _.each(self.translatable_fields_keys, function(f) { - self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '').attr('data-value', values[0][f] || ''); + var value = values[0][f] || ''; + self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(value).attr('data-value', value); }); deff.resolve(); }; @@ -1101,31 +1126,24 @@ instance.web.TranslateDialog = instance.web.Dialog.extend({ }); callback([values]); } else { - self.rpc('/web/dataset/get', { - model: self.view.dataset.model, - ids: [self.view.datarecord.id], - fields: self.translatable_fields_keys, - context: self.view.dataset.get_context({ - 'lang': lg.code - })}, callback); + self.view.dataset.read_ids([self.view.datarecord.id], self.translatable_fields_keys, { + context: { 'lang': lg.code } + }).then(callback); } }); $.when.apply(null, deffered).then(callback); }, open: function(field) { - var self = this, - sup = this._super; + var self = this; + this._super(); $.when(this.languages_loaded).then(function() { if (self.view.translatable_fields && self.view.translatable_fields.length) { self.do_load_fields_values(function() { - sup.call(self); - // desactivated because it created an exception, plus it does not seem very useful - /* if (field) { var $field_input = self.$element.find('tr[data-field="' + field.name + '"] td:nth-child(2) *:first-child'); self.$element.scrollTo($field_input); $field_input.focus(); - }*/ + } }); } else { sup.call(self); @@ -1214,7 +1232,7 @@ instance.web.View = instance.web.Widget.extend({ }, open_translate_dialog: function(field) { if (!this.translate_dialog) { - this.translate_dialog = new instance.web.TranslateDialog(this).start(); + this.translate_dialog = new instance.web.TranslateDialog(this); } this.translate_dialog.open(field); }, @@ -1384,7 +1402,6 @@ instance.web.xml_to_json = function(node) { } instance.web.json_node_to_xml = function(node, human_readable, indent) { // For debugging purpose, this function will convert a json node back to xml - // Maybe useful for xml view editor indent = indent || 0; var sindent = (human_readable ? (new Array(indent + 1).join('\t')) : ''), r = sindent + '<' + node.tag, diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 37da66eb082..b96f284c966 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -25,6 +25,13 @@ </div> </div> </t> +<t t-name="Tipsy.alert"> + <a class="oe_tooltip_close oe_e">[</a> + <span style="float:left; margin:2px 5px 0 0;" class="ui-icon ui-icon-alert ui-state-error"></span> + <div class="oe_tooltip_message"> + <t t-esc="message"/> + </div> +</t> <t t-name="CrashManager.warning"> <table cellspacing="0" cellpadding="0" border="0" class="oe_dialog_warning"> @@ -264,6 +271,31 @@ </div> </t> +<t t-name="ChangePassword"> + <form name="change_password_form" method="POST"> + <table align="center"> + <tr> + <td><label for="old_pwd">Old Password:</label></td> + <td><input type="password" name="old_pwd" + minlength="1" autofocus="autofocus"/></td> + </tr> + <tr> + <td><label for="new_password">New Password:</label></td> + <td><input type="password" name="new_password" + minlength="1" autofocus="autofocus"/></td> + </tr> + <tr> + <td><label for="confirm_pwd">Confirm Password:</label></td> + <td><input type="password" name="confirm_pwd" + minlength="1"/></td> + </tr> + <tr> + <td colspan="2" align="right"><button class="oe_button">Change Password</button></td> + </tr> + </table> + </form> +</t> + <t t-name="Menu"> <ul class="oe_menu" t-if="widget.data"> <li t-foreach="widget.data.data.children" t-as="menu"> @@ -303,7 +335,7 @@ </ul> </t> <t t-name="Menu.secondary.link"> - <a t-attf-href="#menu_id=#{menu.id}&action_id=#{menu.action ? menu.action.split(',')[1] : ''}" + <a t-attf-href="#menu_id=#{menu.id}&action=#{menu.action ? menu.action.split(',')[1] : ''}" t-att-class="menu.children.length ? 'oe_menu_toggler' : 'oe_menu_leaf'" t-att-data-menu="menu.id" t-att-data-action-model="menu.action ? menu.action.split(',')[0] : ''" @@ -331,7 +363,7 @@ <t t-name="UserMenu.about"> <div class="oe_about"> - <a class="oe_activate_debug_mode oe_right" href="?debug">Activate the developer mode</a> + <a class="oe_activate_debug_mode oe_right" href="?debug" style="background-color: white; padding:2px 6px; border-radius: 10px;">Activate the developer mode</a> <img class="oe_logo" src="/web/static/src/img/logo2.png"/> <h3>Version <t t-esc="version_info.version"/></h3> @@ -344,30 +376,6 @@ </div> </t> -<t t-name="UserMenu.password"> - <form name="change_password_form" method="POST"> - <table align="center"> - <tr> - <td><label for="old_pwd">Old Password:</label></td> - <td><input type="password" name="old_pwd" - minlength="1" autofocus="autofocus"/></td> - </tr> - <tr> - <td><label for="new_password">New Password:</label></td> - <td><input type="password" name="new_password" - minlength="1" autofocus="autofocus"/></td> - </tr> - <tr> - <td><label for="confirm_pwd">Confirm Password:</label></td> - <td><input type="password" name="confirm_pwd" - minlength="1"/></td> - </tr> - <tr> - <td colspan="2" align="right"><button class="oe_button">Change Password</button></td> - </tr> - </table> - </form> -</t> <t t-name="WebClient"> <div class="openerp openerp_webclient_container"> @@ -406,10 +414,10 @@ <t t-name="ViewManager"> <div class="oe_view_manager"> <table class="oe_view_manager_header"> - <col width="20%"/> - <col width="25%"/> - <col width="20%"/> - <col width="35%"/> + <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"> @@ -607,11 +615,11 @@ </th> <t t-foreach="columns" t-as="column"> <th t-if="!column.meta and column.invisible !== '1'" t-att-data-id="column.id" - t-att-class="((options.sortable and column.tag !== 'button') ? 'oe_sortable' : null)"> + t-attf-class="oe_list_header_#{column.widget or column.type} #{((options.sortable and column.tag !== 'button') ? 'oe_sortable' : null)}"> <t t-if="column.tag !== 'button'"><t t-esc="column.string"/></t> </th> </t> - <th t-if="options.deletable" width="1"/> + <th t-if="options.deletable" width="13px"/> </tr> </thead> <tfoot> @@ -663,11 +671,11 @@ <t t-set="number" t-value="column.type === 'integer' or column.type == 'float'"/> <t t-set="modifiers" t-value="column.modifiers_for(asData)"/> <td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help" - t-attf-class="oe_list_field_cell oe_list_field_#{column.widget or column.type} #{number ? 'oe_number' : ''} #{column.tag === 'button' ? 'oe-button' : ''} #{modifiers.readonly ? 'oe_readonly' : ''}" + t-attf-class="oe_list_field_cell oe_list_field_#{column.widget or column.type} #{number ? 'oe_number' : ''} #{column.tag === 'button' ? 'oe-button' : ''} #{modifiers.readonly ? 'oe_readonly' : ''} #{modifiers.required ? 'oe_required' : ''}" t-att-data-field="column.id" ><t t-raw="render_cell(record, column)"/></td> </t> - <td t-if="options.deletable" class='oe_list_record_delete' width="1"> + <td t-if="options.deletable" class='oe_list_record_delete' width="13px"> <button type="button" name="delete" class="oe_i">d</button> </td> </tr> @@ -701,7 +709,9 @@ <div t-name="FormView.buttons" class="oe_form_buttons"> <t t-if="widget.options.action_buttons !== false"> <span class="oe_form_buttons_view"> - <button type="button" class="oe_button oe_form_button_edit">Edit</button> + <div style="display: inline-block;"> <!-- required for the bounce effect on button --> + <button type="button" class="oe_button oe_form_button_edit">Edit</button> + </div> <button type="button" class="oe_button oe_form_button_create">Create</button> </span> <span class="oe_form_buttons_edit"> @@ -921,9 +931,10 @@ t-att-tabindex="widget.node.attrs.tabindex" t-att-autofocus="widget.node.attrs.autofocus" t-att-placeholder="! widget.get('effective_readonly') ? widget.node.attrs.placeholder : ''" - ></textarea> - <img class="oe_field_translate oe_input_icon" t-if="widget.field.translate" - t-att-src='_s + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/> + ></textarea><img class="oe_field_translate oe_input_icon" + t-if="widget.field.translate and !widget.get('effective_readonly')" + t-att-src='_s + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0" + /> </div> </t> <t t-name="web.datepicker"> @@ -966,7 +977,7 @@ </t> <t t-if="!widget.get('effective_readonly')"> <a t-if="! widget.get_definition_options().no_open" href="#" tabindex="-1" - class="oe_m2o_cm_button oe_e oe_right">/</a> + class="oe_m2o_cm_button oe_e">/</a> <div> <input type="text" t-att-id="widget.id_for_label" @@ -1026,14 +1037,19 @@ </span> </t> <t t-name="FieldStatus"> - <ul class="oe_form_steps" t-att-style="widget.node.attrs.style"/> + <ul class="" t-att-style="widget.node.attrs.style"/> </t> <t t-name="FieldStatus.content"> <t t-set="size" t-value="widget.to_show.length"/> <t t-foreach="_.range(size)" t-as="i"> - <li t-att-class="widget.to_show[i][0] === widget.selected_value ? 'oe_form_steps_active' : ''"> - <span><t t-esc="widget.to_show[i][1]"/></span> - <img t-att-src='_s + "/web/static/src/img/form_steps.png"' class="oe_form_steps_arrow" t-if="i < size - 1"/> + <li t-att-class="widget.to_show[i][0] === widget.selected_value ? 'oe_form_steps_active' : 'oe_form_steps_inactive'"> + <div class="oe_form_steps_button" t-att-data-id="widget.to_show[i][0]"> + <t t-esc="widget.to_show[i][1]"/> + <span class="oe_form_steps_arrow"> + <span></span> + </span> + <img t-att-src='_s + "/web/static/src/img/form_steps.png"' class="oe_form_steps_arrow" t-if="i < size - 1"/> + </div> </li> </t> </t> @@ -1179,11 +1195,11 @@ </tr> <tr t-foreach="widget.view.translatable_fields" t-as="field" t-att-data-field="field.name"> <td class="oe_form_group_cell" width="1%" nowrap="nowrap"> - <label class="oe_label"><t t-esc="field.node.attrs.string"/>:</label> + <label class="oe_label"><t t-esc="field.string"/>:</label> </td> <td t-foreach="widget.languages" t-as="lg" class="oe_form_group_cell"> - <input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" data-value="" class="oe_trad_field" style="width: 100%"/> - <textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" data-value="" class="oe_trad_field" style="width: 100%"></textarea> + <input t-if="field.field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" data-value="" class="oe_trad_field" style="width: 100%"/> + <textarea t-if="field.field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" data-value="" class="oe_trad_field" style="width: 100%"></textarea> </td> </tr> </table> @@ -1439,7 +1455,7 @@ </div> </div> <div t-name="SearchView.addtoreporting" class="oe_searchview_dashboard"> - <h4>Add to Reporting</h4> + <h4>Add to Dashboard</h4> <form> <p><input placeholder="Title of new dashboard item"/></p> <button class="oe_apply" type="submit">Add</button> @@ -1497,70 +1513,6 @@ </select> </t> -<t t-name="view_editor"> - <table class="oe_view_editor"> - <t t-call="view_editor.row"/> - </table> -</t> -<t t-name="view_editor.row"> - <tr t-att-id="'viewedit-' + rec.id" t-att-level="rec.level" t-foreach="data" t-as="rec"> - <td width="90%"> - <table class="oe_view_editor_field"> - <tr> - <td width="16px" t-att-style="'background-position: ' + 20*rec.level + 'px; padding-left: ' + 20*rec.level + 'px'"> - <img t-if="rec.child_id.length" t-att-id="'parentimg-' + rec.id" - t-att-src='_s + "/web/static/src/img/collapse.gif"' width="16" height="16" border="0"/> - </td> - <td style="cursor: pointer;"> - <a style="text-decoration:none" href="javascript:void(0);"> - <t t-esc="rec.name"/> - </a> - </td> - </tr> - </table> - </td> - <td width="2%"> - <img t-if="rec.att_list.length" - id="side-add" t-att-src='_s + "/web/static/src/img/icons/gtk-add.png"' style="cursor: pointer;"/> - </td> - <td width="2%"> - <img id="side-remove" t-att-src='_s + "/web/static/src/img/icons/gtk-remove.png"' style="cursor: pointer;"/> - </td> - <td width="2%"> - <img t-if="rec.att_list.length and !_.include(no_properties, rec.att_list[0])" - id="side-edit" t-att-src='_s + "/web/static/src/img/icons/gtk-edit.png"' style="cursor: pointer;"/> - </td> - <td width="2%"> - <img t-if="rec.att_list.length" - id="side-up" t-att-src='_s + "/web/static/src/img/icons/gtk-go-up.png"' style="cursor: pointer;"/> - </td> - <td width="2%"> - <img t-if="rec.att_list.length" - id="side-down" t-att-src='_s + "/web/static/src/img/icons/gtk-go-down.png"' style="cursor: pointer;"/> - </td> - <t t-if="rec.child_id.length"> - <t t-set="data" t-value="rec.child_id"/> - <t t-call="view_editor.row"/> - </t> - </tr> -</t> -<t t-name="vieweditor_char"> - <input type="text" t-att-id="widget.name" class="field_char" size="50"/> -</t> -<t t-name="vieweditor_selection"> - <select t-att-id="widget.name" > - <t t-if="widget.selection" t-foreach="widget.selection" t-as="option"> - <option - t-att-value="typeof option === 'object' ? option[0] : option"> - <t t-esc="typeof option === 'object' ? option[1] : option"/> - </option> - </t> - </select> -</t> -<t t-name="vieweditor_boolean"> - <input type="checkbox" t-att-id="widget.name"/> -</t> - <t t-name="ExportView"> <a id="exportview" href="javascript: void(0)" style="text-decoration: none;color: #3D3D3D;">Export</a> </t> |
