summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorFabien Pinckaers <fp@tinyerp.com>2012-08-09 16:29:23 +0200
committerFabien Pinckaers <fp@tinyerp.com>2012-08-09 16:29:23 +0200
commit93f47bb8368066a26211ae106975cadd3c52a9f8 (patch)
tree6bc15c2c8eca3d2b746aeb0cbac0a408c10de363 /addons/web/static/src
parent2043809be494efb256a6a8d0147a49a614b099c8 (diff)
parente46fb9fda8ba93d3eb8ac2907a75012f7a4d920e (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.css291
-rw-r--r--addons/web/static/src/css/base.sass268
-rw-r--r--addons/web/static/src/img/graph_background.pngbin0 -> 3920 bytes
-rw-r--r--addons/web/static/src/img/view_empty_arrow.pngbin2308 -> 4157 bytes
-rw-r--r--addons/web/static/src/js/boot.js2
-rw-r--r--addons/web/static/src/js/chrome.js229
-rw-r--r--addons/web/static/src/js/corelib.js7
-rw-r--r--addons/web/static/src/js/coresetup.js48
-rw-r--r--addons/web/static/src/js/data.js6
-rw-r--r--addons/web/static/src/js/data_import.js2
-rw-r--r--addons/web/static/src/js/formats.js78
-rw-r--r--addons/web/static/src/js/view_editor.js1212
-rw-r--r--addons/web/static/src/js/view_form.js214
-rw-r--r--addons/web/static/src/js/view_list.js346
-rw-r--r--addons/web/static/src/js/view_list_editable.js32
-rw-r--r--addons/web/static/src/js/views.js153
-rw-r--r--addons/web/static/src/xml/base.xml174
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
new file mode 100644
index 00000000000..530312b20bb
--- /dev/null
+++ b/addons/web/static/src/img/graph_background.png
Binary files differ
diff --git a/addons/web/static/src/img/view_empty_arrow.png b/addons/web/static/src/img/view_empty_arrow.png
index b0b1372adfd..ef8f3c820d7 100644
--- a/addons/web/static/src/img/view_empty_arrow.png
+++ b/addons/web/static/src/img/view_empty_arrow.png
Binary files differ
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}&amp;action_id=#{menu.action ? menu.action.split(',')[1] : ''}"
+ <a t-attf-href="#menu_id=#{menu.id}&amp;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 &lt; 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 &lt; 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>