summaryrefslogtreecommitdiff
path: root/addons/web/static/src
diff options
context:
space:
mode:
authorAntony Lesuisse <al@openerp.com>2011-12-08 14:39:52 +0100
committerAntony Lesuisse <al@openerp.com>2011-12-08 14:39:52 +0100
commit78312ed1dd77aff07951cf5646bb4e38e51becb6 (patch)
tree7c36ad833ac86d01f242995a722e5f609ce35312 /addons/web/static/src
parent3225e9d5c42d7396ba9e3089e46c494bf919e283 (diff)
parent54f3f38957fc36fbb705524b99cc2af0b5aceeca (diff)
[MERGE] trunk
bzr revid: al@openerp.com-20111208133952-183wp4ozrr0gvea8
Diffstat (limited to 'addons/web/static/src')
-rw-r--r--addons/web/static/src/css/base.css293
-rw-r--r--addons/web/static/src/css/data_import.css2
-rw-r--r--addons/web/static/src/img/icons/kanban-apply.png (renamed from addons/web/static/src/img/icons/lead-stage-won.png)bin918 -> 918 bytes
-rw-r--r--addons/web/static/src/img/icons/kanban-pause.png (renamed from addons/web/static/src/img/icons/lead-stage-pending.png)bin882 -> 882 bytes
-rw-r--r--addons/web/static/src/img/icons/kanban-stop.png (renamed from addons/web/static/src/img/icons/lead-stage-lost.png)bin692 -> 692 bytes
-rw-r--r--addons/web/static/src/img/icons/save-document.pngbin0 -> 1189 bytes
-rw-r--r--addons/web/static/src/img/iconset-b-remove.pngbin0 -> 189 bytes
-rw-r--r--addons/web/static/src/js/boot.js2
-rw-r--r--addons/web/static/src/js/chrome.js45
-rw-r--r--addons/web/static/src/js/core.js7
-rw-r--r--addons/web/static/src/js/data.js21
-rw-r--r--addons/web/static/src/js/data_import.js24
-rw-r--r--addons/web/static/src/js/formats.js11
-rw-r--r--addons/web/static/src/js/search.js97
-rw-r--r--addons/web/static/src/js/view_editor.js1318
-rw-r--r--addons/web/static/src/js/view_form.js362
-rw-r--r--addons/web/static/src/js/view_list.js29
-rw-r--r--addons/web/static/src/js/view_list_editable.js145
-rw-r--r--addons/web/static/src/js/view_page.js218
-rw-r--r--addons/web/static/src/js/views.js223
-rw-r--r--addons/web/static/src/xml/base.xml255
21 files changed, 2107 insertions, 945 deletions
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index d8f31af1d35..3a163beb832 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -1,4 +1,3 @@
-/* TODO: separate openerp web client page css from openerp views css */
body.openerp {
padding: 0;
margin: 0;
@@ -6,10 +5,17 @@ body.openerp {
min-width: 1000px;
overflow-y: scroll;
font-size: 80%;
+ font-family: Ubuntu, Helvetica, sans-serif;
}
body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp option, .openerp button, .openerp .ui-widget {
font-family: Ubuntu, Helvetica, sans-serif;
+ font-size:85%;
+}
+
+.openerp .view-manager-main-content {
+ width: 100%;
+ padding: 0 8px 8px 8px;
}
.oe_box {
@@ -29,6 +35,17 @@ body.openerp, .openerp textarea, .openerp input, .openerp select, .openerp optio
.openerp .oe-listview .oe-number {
text-align: right !important;
}
+.oe-listview-header-columns {
+ background: #444; /* Old browsers */
+ background: -moz-linear-gradient(top, #ffffff 0%, #d1d1d1 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(100%,#d1d1d1)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* IE10+ */
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#d1d1d1',GradientType=0 ); /* IE6-9 */
+ background: linear-gradient(top, #ffffff 0%,#d1d1d1 100%); /* W3C */
+}
+
.openerp .oe_hide {
display: none !important;
}
@@ -261,7 +278,7 @@ label.error {
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#BD5E54', endColorstr='#90322A',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #bd5e54 0%,#90322a 60%); /* W3C */
- border: 1px solid #6E2A24;
+ border: 1px solid #5E1A14;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
@@ -272,7 +289,7 @@ label.error {
text-transform: uppercase;
line-height: 20px;
font-weight: bold;
- font-size: 85%;
+ font-size: 75%;
white-space: nowrap;
}
@@ -331,6 +348,7 @@ label.error {
height: 100%;
display: block;
position: relative;
+ font-size:85%;
}
.openerp .secondary_menu.oe_folded {
width: 20px;
@@ -371,6 +389,10 @@ label.error {
white-space: nowrap;
color: white;
text-shadow: 0 1px 0 #333;
+
+}
+.openerp a.oe_secondary_submenu_item {
+ padding: 0 5px 2px 10px;
}
.openerp a.oe_secondary_submenu_item:hover,
.openerp a.oe_secondary_submenu_item.leaf.active {
@@ -383,7 +405,7 @@ label.error {
background: -ms-linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* IE10+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#5A5858',GradientType=0 ); /* IE6-9 */
background: linear-gradient(top, #ffffff 0%,#d8d8d8 11%,#afafaf 86%,#333333 91%,#5a5858 96%); /* W3C */
- padding: 0 5px 2px 5px;
+ padding: 0 5px 2px 10px;
line-height: 20px;
color: #3f3d3d;
text-decoration: none;
@@ -431,6 +453,8 @@ label.error {
margin: 0;
padding: 4px 10px;
text-shadow: 0 1px 0 #111111;
+ font-weight:normal;
+ line-height:14px;
}
.openerp .header_title small {
color: #ccc;
@@ -464,15 +488,11 @@ label.error {
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#929292', endColorstr='#4D4D4D',GradientType=0 );
}
.openerp .header_corner ul.block {
- /*float: left;*/
list-style: none;
height: 34px;
margin: 0;
padding: 0 0 0 2px;
- /*background: url(../images/top-sep-a.png) no-repeat;*/
line-height: 33px;
- /*font-size: 1em;*/
- /*text-transform: uppercase;*/
}
.openerp .header_corner ul.block li {
float: left;
@@ -498,6 +518,10 @@ label.error {
font-weight: bold;
}
+.openerp .logout {
+ font-size:80%;
+}
+
/* Footer */
.openerp div.oe_footer {
background: none repeat scroll 0 0 #CCCCCC;
@@ -530,7 +554,7 @@ label.error {
}
.openerp h2.oe_view_title {
- font-size: 175%;
+ font-size: 110%;
font-weight: normal;
margin: 2px 0;
color: #252424;
@@ -541,12 +565,15 @@ label.error {
.openerp .oe_vm_switch {
float: right;
}
+.openerp .oe-view-manager-header .oe_view_title {
+ font-size:150%;
+}
/* SearchView */
.openerp .filter_label, .openerp .filter_icon {
- border: 1px solid #666;
border-left-width: 0;
background: #F0F0F0;
+ border: 1px solid #999;
background: -moz-linear-gradient(top, #F0F0F0 0%, #C0C0C0 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F0F0F0), color-stop(100%,#C0C0C0));
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#C0C0C0',GradientType=0 );
@@ -558,13 +585,13 @@ label.error {
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F0F0F0', endColorstr='#A1A7CE',GradientType=0 );
}
.openerp .filter_label:active, .openerp .filter_icon:active {
- background: #AAAAAA;
+ background: #aaa;
background: -moz-linear-gradient(top, #999999 0%, #EEEEEE 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#999999), color-stop(100%,#EEEEEE));
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#999999', endColorstr='#EEEEEE',GradientType=0 );
}
.openerp .filter_label.enabled, .openerp .filter_icon.enabled {
- background: #AAAAAA;
+ background: #aaa;
}
.openerp .filter_icon {
height: 22px;
@@ -588,13 +615,16 @@ label.error {
white-space: nowrap;
}
.openerp .filter_label_group button:first-child {
- border-left: 1px solid #666;
-webkit-border-top-left-radius: 7px;
-webkit-border-bottom-left-radius: 7px;
-moz-border-radius-topleft: 7px;
-moz-border-radius-bottomleft: 7px;
border-top-left-radius: 7px;
border-bottom-left-radius: 7px;
+ border-right: none;
+}
+.openerp .filter_label_group button {
+ border-right: none;
}
.openerp .filter_label_group button:last-child {
-webkit-border-top-right-radius: 7px;
@@ -603,6 +633,20 @@ label.error {
-moz-border-radius-bottomright: 7px;
border-top-right-radius: 7px;
border-bottom-right-radius: 7px;
+ border-right: 1px solid #999;
+}
+.openerp .filter_label_group button.filter_icon img {
+ padding: 1px 8px 0 8px;
+}
+.openerp .filter_label_group button.filter_icon:first-child {
+ border-left: solid 1px #999;
+ margin-left: -7px;
+ -webkit-border-top-left-radius: 0px;
+ -webkit-border-bottom-left-radius: 0px;
+ -moz-border-radius-topleft: 0px;
+ -moz-border-radius-bottomleft: 0px;
+ border-top-left-radius: 0px;
+ border-bottom-left-radius: 0px;
}
.openerp .searchview_group_string {
@@ -628,8 +672,16 @@ label.error {
.openerp .searchview_group.expanded .searchview_group_content {
display: block;
}
-.openerp .searchview_group_content {
- padding-left: 10px;
+
+.openerp .searchview_group_content .oe_label, .openerp .searchview_group_content .oe_label_help {
+ font-weight: bold;
+ color: #4c4c4c;
+}
+
+.openerp .oe-searchview-render-line .oe_label, .openerp .oe-searchview-render-line .oe_label_help {
+ font-weight: bold;
+ font-size: 80%;
+ white-space: nowrap;
}
.openerp .searchview_extended_group {
@@ -715,20 +767,27 @@ label.error {
text-align: left;
padding: 1px 2px;
}
-.openerp .oe-listview th.oe-record-selector,
-.openerp .oe-listview td.oe-button,
-.openerp .oe-listview td.oe-record-delete {
- padding: 0 1px;
+
+.openerp .oe-record-delete button,
+.openerp button.oe-edit-row-save {
+ border: none;
+ height: 12px;
+ width: 12px;
+ background: url("/web/static/src/img/iconset-b-remove.png") no-repeat scroll center center transparent;
+ cursor: pointer;
+}
+.openerp button.oe-edit-row-save {
+ background-image: url('/web/static/src/img/icons/save-document.png');
}
/* Could use :not selectors if they were supported by MSIE8... */
.openerp .oe-listview tbody td {
- border-left: 1px solid #dadada;
+ border-left: 1px solid #dadada; /*currently commenting to test with no vertical lines in list view*/
}
.openerp .oe-listview tbody td:first-child,
.openerp .oe-listview tbody td.oe-button,
-.openerp .oe-listview tbody td.oe-button+td,
-.openerp .oe-listview tbody th.oe-record-selector+td,
+.openerp .oe-listview tbody td.oe-button,
+.openerp .oe-listview tbody th.oe-record-selector,
.openerp .oe-listview tbody td.oe-record-delete {
border-left: none;
}
@@ -738,15 +797,36 @@ label.error {
}
.openerp .oe-listview th.oe-sortable {
cursor: pointer;
+ font-size: 75%;
+ text-transform: uppercase;
+ padding: 0;
+ margin: 0;
+ padding-left: 3px;
+ color: #333;
}
.openerp .oe-listview th.oe-sortable .ui-icon {
- height: 1em;
+ height: 60%;
+ margin: -6px 0 0;
display: inline;
display: inline-block;
+ vertical-align: middle;
+}
+
+.openerp .oe-listview table tbody td {
+ border-bottom: 1px solid #E3E3E3;
+}
+
+.openerp .oe-listview .oe-record-selector {
+ border-bottom: 1px solid #E3E3E3;
}
.openerp .oe-listview .oe-field-cell {
cursor: pointer;
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-top: 3px;
+ padding-bottom: 3px;
+ font-size: 80%;
}
.openerp .oe-listview .oe-field-cell progress {
width: 100%;
@@ -778,6 +858,8 @@ label.error {
}
.openerp .oe-list-pager .oe-pager-state {
cursor: pointer;
+ font-size: 90%;
+ color: #555;
}
.openerp .oe-listview .oe-group-name {
@@ -794,6 +876,8 @@ label.error {
.openerp .oe-listview .oe-list-footer {
text-align: center;
white-space: nowrap;
+ color: #444;
+ font-size: 85%;
}
.openerp .oe-listview .oe-list-footer span {
margin: 0 1em;
@@ -846,28 +930,68 @@ label.error {
}
.openerp .oe_form_notebook .ui-tabs-panel {
padding: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
}
.openerp .oe_form_notebook ul.ui-tabs-nav {
padding-left: 0;
background: transparent;
- border-width: 0 0 1px 0;
+ border-width: 0;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
- line-height: 0.5em;
+ line-height: 0.8em;
+ font-size: 95%;
+ color: #555;
}
.openerp .oe_form_notebook ul.ui-tabs-nav li {
font-weight: bold;
}
.openerp .oe_form_notebook .ui-tabs-panel {
background: #f9f9f9;
- border-width: 0 1px 1px 1px;
+ border-width: 1px;
}
.openerp .oe_form_notebook .ui-tabs-selected {
background: #f9f9f9;
}
+/* Unedit Form */
+.openerp .field_char,
+.openerp .field_date,
+.openerp .field_float,
+.openerp .field_selection,
+.openerp .oe_form_field_many2one a,
+.openerp .oe_form_field_reference a{
+ vertical-align: middle;
+ padding-top: 3px;
+ font-size: 90%;
+ color: #222;
+}
+.openerp .oe_form_field_many2one a,
+.openerp .oe_form_field_reference a {
+ color: #9A0404;
+ line-height: 12px;
+}
+
+
/* Form */
+
+.openerp .oe_form_frame_cell input[type="checkbox"] {
+ margin-top: 3px;
+ vertical-align: center;
+}
+.openerp .oe_form_frame_cell .input[type="text"] {
+ padding-bottom: 1px;
+}
+
+.openerp table.oe_frame td {
+ color: #4c4c4c;
+}
+.openerp td.oe_form_frame_cell {
+ padding: 2px;
+ position: relative;
+}
.openerp .oe_frame.oe_forms {
clear: both;
}
@@ -889,6 +1013,9 @@ label.error {
padding: 2px;
position: relative;
}
+.openerp td.oe_form_field_boolean {
+ padding-top: 4px;
+}
.openerp td.oe_form_frame_cell.oe_form_group {
padding: 0;
}
@@ -900,14 +1027,31 @@ label.error {
}
.openerp .oe_form_pager, .openerp .oe_list_pager {
float: right;
+ font-size: 80%;
+ color: gray;
+ font-weight: bold;
+}
+
+.openerp .oe_form_pager {
+ margin-right: 3px;
+}
+
+
+.openerp label.oe_label_help, .openerp label.oe_label, .openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms .oe_button, .openerp .oe_forms textarea {
+ font-size: 85%;
}
.openerp label.oe_label_help, .openerp label.oe_label {
display: block;
+ color: #4c4c4c;
+ font-weight: normal;
}
.openerp label.oe_label_help {
cursor: help;
}
+.openerp .oe_form_frame_cell .oe_label, .openerp .oe_form_frame_cell .oe_label_help {
+ font-weight: normal;
+}
.openerp #tiptip_content {
font-size: 12px;
}
@@ -926,8 +1070,13 @@ label.error {
}
.openerp .oe_forms label.oe_label, .openerp .oe_forms label.oe_label_help {
- margin: 3px 0 0 10px;
+ margin: 4px 0 0 3px;
+ white-space: nowrap;
}
+.openerp .oe_forms .searchview_group_content label.oe_label, .openerp .searchview_group_content .oe_forms label.oe_label_help { /* making a distinction between labels in search view and other labels */
+ margin: 3px 0 0 3px;
+}
+
.openerp label.oe_label_help span {
font-size: 80%;
color: darkgreen;
@@ -949,13 +1098,29 @@ label.error {
margin: 3px 0 0 0;
}
+/* Uneditable Form View */
+.openerp .oe_form_readonly {
+
+}
+.openerp .oe_form_readonly .field_char, .openerp .oe_form_readonly .oe_form_field_email {
+ padding-top: 4px;
+ background-color: white;
+}
+
+.openerp .oe_form_readonly .field_selection {
+ padding-top: 2px;
+ background-color: white;
+}
+
+
/* Inputs */
.openerp .oe_forms input[type="text"], .openerp .oe_forms input[type="password"], .openerp .oe_forms select, .openerp .oe_forms textarea {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
- padding: 0 2px 0 2px;
+ padding: 0 2px;
+ margin: 0 2px;
border: 1px solid #999;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
@@ -964,6 +1129,10 @@ label.error {
min-width: 90px;
color: #1f1f1f;
}
+.openerp .oe_forms select{
+ padding-top: 2px;
+}
+
.openerp .oe_forms textarea {
resize:vertical;
}
@@ -979,6 +1148,9 @@ label.error {
min-width: 100%;
width: 100%;
}
+.openerp .oe_forms .button {
+ height: 22px;
+}
@-moz-document url-prefix() {
/* Strange firefox behaviour on width: 100% + white-space: nowrap */
.openerp .oe_forms .oe_button {
@@ -992,9 +1164,9 @@ label.error {
.openerp .oe_input_icon {
position: absolute;
cursor: pointer;
- right: 5px;
- top: 3px;
- z-index: 2;
+ right: 4px;
+ top: 5px;
+ z-index: 1;
}
.openerp .oe_datepicker_container {
position: absolute;
@@ -1003,7 +1175,6 @@ label.error {
display: none;
}
.openerp .oe_datepicker_root {
- position: relative;
display: inline-block;
}
.openerp .oe_forms.oe_frame .oe_datepicker_root {
@@ -1017,13 +1188,6 @@ label.error {
right: 5px;
top: 3px;
}
-.openerp img.oe_field_translate {
- margin-left: -21px;
- vertical-align: top;
- cursor: pointer;
- position: relative;
- top: 4px;
-}
.openerp .oe_trad_field.touched {
border: 1px solid green !important;
}
@@ -1055,10 +1219,14 @@ label.error {
border: 0 solid #666;
}
.openerp .separator.horizontal {
- font-weight: bold;
+ font-weight: bold;
border-bottom-width: 1px;
margin: 3px 4px 3px 1px;
- height: 15px;
+ height: 17px;
+ font-size: 95%;
+}
+.openerp .separator.horizontal:empty {
+ height: 5px;
}
.openerp .oe_form_frame_cell.oe_form_separator_vertical {
border-left: 1px solid #666;
@@ -1095,6 +1263,14 @@ label.error {
background: white;
min-width: 90px;
}
+.openerp tbody.ui-widget-content {
+ margin-bottom: 10px;
+ border-spacing: 4px;
+}
+.openerp .ui-widget-header {
+ background-image: none;
+ background-color: white;
+}
/* Sidebar */
.openerp .view-manager-main-table {
@@ -1108,16 +1284,13 @@ label.error {
vertical-align: top;
}
-.openerp .view-manager-main-content {
- width: 100%;
-}
.openerp .oe-view-manager-header {
overflow: auto;
}
.openerp .oe-view-manager-header h2 {
float: left;
}
-.openerp .oe-view-manager-header blockquote {
+.openerp .oe_view_manager_menu_tips blockquote {
display: none;
font-size: 85%;
margin: 0;
@@ -1126,14 +1299,14 @@ label.error {
padding: 1px 10px;
color: #4C4C4C;
}
-.openerp .oe-view-manager-header blockquote p {
+.openerp .oe_view_manager_menu_tips blockquote p {
margin: 0;
padding: 6px 1px 4px;
}
-.openerp .oe-view-manager-header blockquote div {
+.openerp .oe_view_manager_menu_tips blockquote div {
text-align: right;
}
-.openerp .oe-view-manager-header blockquote div button {
+.openerp .oe_view_manager_menu_tips blockquote div button {
border: none;
background: none;
padding: 0 4px;
@@ -1365,6 +1538,7 @@ label.error {
}
.openerp .oe_forms .oe-m2o input[type="text"] {
padding-right: 20px;
+ padding-top: 2px;
}
.openerp .oe-m2o-drop-down-button {
margin-left: -23px;
@@ -1374,12 +1548,12 @@ label.error {
margin-bottom: -4px;
cursor: pointer;
}
-.openerp .oe-m2o-cm-button img {
- margin-left: 4px;
-}
.openerp .oe-m2o-disabled-cm {
color: grey;
}
+.openerp ul[role="listbox"] li a {
+ font-size:80%;
+}
.parent_top {
vertical-align: text-top;
}
@@ -1425,20 +1599,19 @@ label.error {
/* Shortcuts*/
.oe-shortcut-toggle {
height: 20px;
+ margin-top: 3px;
padding: 0;
width: 24px;
cursor: pointer;
display: block;
- background: url(/web/static/src/img/add-shortcut.png) no-repeat bottom;
+ background: url(/web/static/src/img/add-shortcut.png) no-repeat center center;
float: left;
}
.oe-shortcut-remove{
- background: url(/web/static/src/img/remove-shortcut.png) no-repeat bottom;
+ background: url(/web/static/src/img/remove-shortcut.png) no-repeat center center;
}
-/* ================ */
.oe-shortcuts {
position: absolute;
-
margin: 0;
padding: 6px 15px;
top: 37px;
@@ -1463,9 +1636,14 @@ label.error {
color: #fff;
text-align: center;
border-left: 1px solid #909090;
- padding: 4px;
- font-size: 90%;
+ padding: 0 4px;
+ font-size: 80%;
font-weight: normal;
+ vertical-align: top;
+}
+
+.oe-shortcuts li:hover {
+ background-color: #666;
}
.oe-shortcuts li:first-child {
border-left: none;
@@ -1535,4 +1713,3 @@ ul.oe-arrow-list li.oe-arrow-list-selected .oe-arrow-list-after {
.openerp .oe_view_editor_tree_grid a {
display: block;
}
-
diff --git a/addons/web/static/src/css/data_import.css b/addons/web/static/src/css/data_import.css
index e5d1c9a910c..a63a52802f0 100644
--- a/addons/web/static/src/css/data_import.css
+++ b/addons/web/static/src/css/data_import.css
@@ -27,7 +27,7 @@
.openerp .oe-import fieldset.oe-closed table {
display: none;
}
-.openerp .separator.horizontal {
+.openerp .oe-import .separator.horizontal {
font-weight: bold;
border-bottom-width: 1px;
margin: 6px 4px 6px 1px;
diff --git a/addons/web/static/src/img/icons/lead-stage-won.png b/addons/web/static/src/img/icons/kanban-apply.png
index 02effd5f14c..02effd5f14c 100644
--- a/addons/web/static/src/img/icons/lead-stage-won.png
+++ b/addons/web/static/src/img/icons/kanban-apply.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/lead-stage-pending.png b/addons/web/static/src/img/icons/kanban-pause.png
index 9e9544ee178..9e9544ee178 100644
--- a/addons/web/static/src/img/icons/lead-stage-pending.png
+++ b/addons/web/static/src/img/icons/kanban-pause.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/lead-stage-lost.png b/addons/web/static/src/img/icons/kanban-stop.png
index e1f98a26b59..e1f98a26b59 100644
--- a/addons/web/static/src/img/icons/lead-stage-lost.png
+++ b/addons/web/static/src/img/icons/kanban-stop.png
Binary files differ
diff --git a/addons/web/static/src/img/icons/save-document.png b/addons/web/static/src/img/icons/save-document.png
new file mode 100644
index 00000000000..8933ca0bed9
--- /dev/null
+++ b/addons/web/static/src/img/icons/save-document.png
Binary files differ
diff --git a/addons/web/static/src/img/iconset-b-remove.png b/addons/web/static/src/img/iconset-b-remove.png
new file mode 100644
index 00000000000..497f03b4ceb
--- /dev/null
+++ b/addons/web/static/src/img/iconset-b-remove.png
Binary files differ
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 7440ae42dbc..14f50adb473 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -59,7 +59,7 @@ openerp.web = function(instance) {
openerp.web.formats(instance);
openerp.web.chrome(instance);
openerp.web.data(instance);
- var files = ["views","search","list","form","list_editable","web_mobile","view_tree","data_export","data_import","view_editor", 'embed'];
+ var files = ["views","search","list","form", "page","list_editable","web_mobile","view_tree","data_export","data_import","view_editor","embed"];
for(var i=0; i<files.length; i++) {
if(openerp.web[files[i]]) {
openerp.web[files[i]](instance);
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index b69b6f40cc4..1eaab8b2dee 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -30,8 +30,6 @@ openerp.web.Notification = openerp.web.Widget.extend(/** @lends openerp.web.Not
this.$element.notify('create', 'oe_notification_alert', {
title: title,
text: text
- }, {
- expires: false
});
}
@@ -242,6 +240,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
init: function(parent, element_id, option_id) {
this._super(parent, element_id);
this.$option_id = $('#' + option_id);
+ this.unblockUIFunction = $.unblockUI;
},
start: function() {
this._super();
@@ -337,11 +336,27 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.widget_parent.do_login(
info.db, admin.login, admin.password);
self.stop();
- $.unblockUI();
+ self.unblockUI();
});
});
},
/**
+ * Blocks UI and replaces $.unblockUI by a noop to prevent third parties
+ * from unblocking the UI
+ */
+ blockUI: function () {
+ $.blockUI();
+ $.unblockUI = function () {};
+ },
+ /**
+ * Reinstates $.unblockUI so third parties can play with blockUI, and
+ * unblocks the UI
+ */
+ unblockUI: function () {
+ $.unblockUI = this.unblockUIFunction;
+ $.unblockUI();
+ },
+ /**
* Displays an error dialog resulting from the various RPC communications
* failing over themselves
*
@@ -366,10 +381,10 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.$option_id.find("form[name=create_db_form]").validate({
submitHandler: function (form) {
var fields = $(form).serializeArray();
- $.blockUI();
+ self.blockUI();
self.rpc("/web/database/create", {'fields': fields}, function(result) {
if (result.error) {
- $.unblockUI();
+ self.unblockUI();
self.display_error(result);
return;
}
@@ -417,7 +432,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
.html(QWeb.render("BackupDB", self))
.find("form[name=backup_db_form]").validate({
submitHandler: function (form) {
- $.blockUI();
+ self.blockUI();
self.session.get_file({
form: form,
error: function (body) {
@@ -427,7 +442,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
error: error[1]
});
},
- complete: $.unblockUI
+ complete: $.proxy(self, 'unblockUI')
});
}
});
@@ -438,7 +453,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
self.$option_id.find("form[name=restore_db_form]").validate({
submitHandler: function (form) {
- $.blockUI();
+ self.blockUI();
$(form).ajaxSubmit({
url: '/web/database/restore',
type: 'POST',
@@ -463,9 +478,7 @@ openerp.web.Database = openerp.web.Widget.extend(/** @lends openerp.web.Database
})
}
},
- complete: function () {
- $.unblockUI();
- }
+ complete: $.proxy(self, 'unblockUI')
});
}
});
@@ -824,7 +837,8 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
init: function(parent, element_id, secondary_menu_id) {
this._super(parent, element_id);
this.secondary_menu_id = secondary_menu_id;
- this.$secondary_menu = $("#" + secondary_menu_id).hide();
+ this.$secondary_menu = $("#" + secondary_menu_id);
+ this.$secondary_menu.hide();
this.menu = false;
this.folded = false;
if (window.localStorage) {
@@ -898,7 +912,10 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
sub_menu_visible = $sub_menu.is(':visible');
this.$secondary_menu.find('.oe_secondary_menu').hide();
- $('.active', this.$element.add(this.$secondary_menu.show())).removeClass('active');
+ if (this.$secondary_menu.hasClass('oe_folded')) {
+ this.$secondary_menu.show();
+ }
+ $('.active', this.$element.add(this.$secondary_menu)).removeClass('active');
$main_menu.add($clicked_menu).add($sub_menu).addClass('active');
if (!(this.folded && manual)) {
@@ -960,6 +977,8 @@ openerp.web.Menu = openerp.web.Widget.extend(/** @lends openerp.web.Menu# */{
if (data.action.length) {
var action = data.action[0][2];
self.on_action(action);
+ } else {
+ self.on_action({type: 'null_action'});
}
},
on_action: function(action) {
diff --git a/addons/web/static/src/js/core.js b/addons/web/static/src/js/core.js
index b67a0c59147..ddfca9d4698 100644
--- a/addons/web/static/src/js/core.js
+++ b/addons/web/static/src/js/core.js
@@ -1109,7 +1109,8 @@ openerp.web.TranslationDataBase = openerp.web.Class.extend(/** @lends openerp.we
set_bundle: function(translation_bundle) {
var self = this;
this.db = {};
- var modules = _.keys(translation_bundle.modules).sort();
+ var modules = _.keys(translation_bundle.modules);
+ modules.sort();
if (_.include(modules, "web")) {
modules = ["web"].concat(_.without(modules, "web"));
}
@@ -1156,7 +1157,8 @@ openerp.web._t = new openerp.web.TranslationDataBase().build_translation_functio
openerp.web.qweb = new QWeb2.Engine();
openerp.web.qweb.debug = (window.location.search.indexOf('?debug') !== -1);
openerp.web.qweb.default_dict = {
- '_' : _
+ '_' : _,
+ '_t' : openerp.web._t
}
openerp.web.qweb.format_text_node = function(s) {
// Note that 'this' is the Qweb Node of the text
@@ -1174,6 +1176,7 @@ openerp.web.qweb.format_text_node = function(s) {
/** Setup default connection */
openerp.connection = new openerp.web.Connection();
+openerp.web.qweb.default_dict['__debug__'] = openerp.connection.debug;
};
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index 1f2520ee774..26147b4d4e0 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -265,14 +265,25 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
return this;
},
select_id: function(id) {
- var idx = _.indexOf(this.ids, id);
- if (idx === -1) {
+ var idx = this.get_id_index(id);
+ if (idx === null) {
return false;
} else {
this.index = idx;
return true;
}
},
+ get_id_index: function(id) {
+ for (var i=0, ii=this.ids.length; i<ii; i++) {
+ // Here we use type coercion because of the mess potentially caused by
+ // OpenERP ids fetched from the DOM as string. (eg: dhtmlxcalendar)
+ // OpenERP ids can be non-numeric too ! (eg: recursive events in calendar)
+ if (id == this.ids[i]) {
+ return i;
+ }
+ }
+ return null;
+ },
/**
* Read records.
*
@@ -414,8 +425,8 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
return this.rpc('/web/dataset/call', {
model: this.model,
method: method,
- domain_id: domain_index || null,
- context_id: context_index || null,
+ domain_id: domain_index == undefined ? null : domain_index,
+ context_id: context_index == undefined ? null : context_index,
args: args || []
}, callback, error_callback);
},
@@ -433,7 +444,7 @@ openerp.web.DataSet = openerp.web.Widget.extend( /** @lends openerp.web.DataSet
model: this.model,
method: method,
domain_id: null,
- context_id: 1,
+ context_id: args.length - 1,
args: args || []
}, callback, error_callback);
},
diff --git a/addons/web/static/src/js/data_import.js b/addons/web/static/src/js/data_import.js
index d5e789ce3e7..cd699c0481d 100644
--- a/addons/web/static/src/js/data_import.js
+++ b/addons/web/static/src/js/data_import.js
@@ -183,6 +183,20 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
this.$element.find('#result').empty();
var headers, result_node = this.$element.find("#result");
+ if (results['error']) {
+ result_node.append(QWeb.render('ImportView.error', {
+ 'error': results['error']}));
+ this.$element.find('fieldset').removeClass('oe-closed');
+ return;
+ }
+ if (results['success']) {
+ if (this.widget_parent.widget_parent.active_view == "list") {
+ this.widget_parent.reload_content();
+ }
+ this.stop();
+ return;
+ }
+
if (results['records']) {
var lines_to_skip = parseInt(this.$element.find('#csv_skip').val(), 10),
with_headers = this.$element.find('#file_has_headers').prop('checked');
@@ -195,16 +209,6 @@ openerp.web.DataImport = openerp.web.Dialog.extend({
: results.records
}));
this.$element.find('fieldset').addClass('oe-closed');
- } else if (results['error']) {
- result_node.append(QWeb.render('ImportView.error', {
- 'error': results['error']}));
- this.$element.find('fieldset').removeClass('oe-closed');
- } else if (results['success']) {
- if (this.widget_parent.widget_parent.active_view == "list") {
- this.widget_parent.reload_content();
- }
- this.stop();
- return;
}
this.$element.find('form').removeClass('oe-import-no-result');
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index 18b679bed3c..13cceaeba8d 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -158,16 +158,17 @@ openerp.web.parse_value = function (value, descriptor, value_if_empty) {
var tmp = Number(value);
if (!isNaN(tmp))
return tmp;
- tmp = value.replace(openerp.web._t.database.parameters.decimal_point, ".");
- var tmp2 = tmp;
+
+ var tmp2 = value;
do {
tmp = tmp2;
tmp2 = tmp.replace(openerp.web._t.database.parameters.thousands_sep, "");
} while(tmp !== tmp2);
- tmp = Number(tmp);
- if (isNaN(tmp))
+ var reformatted_value = tmp.replace(openerp.web._t.database.parameters.decimal_point, ".");
+ var parsed = Number(reformatted_value);
+ if (isNaN(parsed))
throw new Error(value + " is not a correct float");
- return tmp;
+ return parsed;
case 'float_time':
var float_time_pair = value.split(":");
if (float_time_pair.length != 2)
diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js
index f95801975b5..c3e27fc52be 100644
--- a/addons/web/static/src/js/search.js
+++ b/addons/web/static/src/js/search.js
@@ -139,6 +139,7 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
}
},
on_loaded: function(data) {
+ this.fields_view = data.fields_view;
if (data.fields_view.type !== 'search' ||
data.fields_view.arch.tag !== 'search') {
throw new Error(_.str.sprintf(
@@ -197,18 +198,22 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
var self = this;
var select = this.$element.find(".oe_search-view-filters-management");
var val = select.val();
-
- if (val.slice(0,1) == "_") { // useless action
- select.val("_filters");
- return;
- }
- if (val.slice(0, "get:".length) == "get:") {
- val = val.slice("get:".length);
- val = parseInt(val);
- var filter = this.managed_filters[val];
- this.on_search([filter.domain], [filter.context], []);
- } else if (val == "save_filter") {
- select.val("_filters");
+ switch(val) {
+ case 'add_to_dashboard':
+ this.on_add_to_dashboard();
+ break;
+ case 'manage_filters':
+ this.do_action({
+ res_model: 'ir.filters',
+ views: [[false, 'list'], [false, 'form']],
+ type: 'ir.actions.act_window',
+ context: {"search_default_user_id": this.session.uid,
+ "search_default_model_id": this.dataset.model},
+ target: "current",
+ limit : 80
+ });
+ break;
+ case 'save_filter':
var data = this.build_search_data();
var context = new openerp.web.CompoundContext();
_.each(data.contexts, function(x) {
@@ -241,19 +246,63 @@ openerp.web.SearchView = openerp.web.Widget.extend(/** @lends openerp.web.Search
}}
]
});
- } else { // manage_filters
- select.val("_filters");
- this.do_action({
- res_model: 'ir.filters',
- views: [[false, 'list'], [false, 'form']],
- type: 'ir.actions.act_window',
- context: {"search_default_user_id": this.session.uid,
- "search_default_model_id": this.dataset.model},
- target: "current",
- limit : 80,
- auto_search : true
- });
+ break;
}
+ if (val.slice(0, 4) == "get:") {
+ val = val.slice(4);
+ val = parseInt(val, 10);
+ var filter = this.managed_filters[val];
+ this.on_search([filter.domain], [filter.context], []);
+ } else {
+ select.val('');
+ }
+ },
+ on_add_to_dashboard: function() {
+ this.$element.find(".oe_search-view-filters-management")[0].selectedIndex = 0;
+ var self = this,
+ menu = openerp.webclient.menu,
+ $dialog = $(QWeb.render("SearchView.add_to_dashboard", {
+ dashboards : menu.data.data.children,
+ selected_menu_id : menu.$element.find('a.active').data('menu')
+ }));
+ $dialog.find('input').val(this.fields_view.name);
+ $dialog.dialog({
+ modal: true,
+ title: _t("Add to Dashboard"),
+ buttons: [
+ {text: _t("Cancel"), click: function() {
+ $(this).dialog("close");
+ }},
+ {text: _t("OK"), click: function() {
+ $(this).dialog("close");
+ var menu_id = $(this).find("select").val(),
+ title = $(this).find("input").val(),
+ data = self.build_search_data(),
+ context = new openerp.web.CompoundContext(),
+ domain = new openerp.web.CompoundDomain();
+ _.each(data.contexts, function(x) {
+ context.add(x);
+ });
+ _.each(data.domains, function(x) {
+ domain.add(x);
+ });
+ self.rpc('/web/searchview/add_to_dashboard', {
+ menu_id: menu_id,
+ action_id: self.widget_parent.action.id,
+ context_to_save: context,
+ domain: domain,
+ view_mode: self.widget_parent.active_view,
+ name: title
+ }, function(r) {
+ if (r === false) {
+ self.do_warn("Could not add filter to dashboard");
+ } else {
+ self.do_notify("Filter added to dashboard", '');
+ }
+ });
+ }}
+ ]
+ });
},
/**
* Performs the search view collection of widget data.
diff --git a/addons/web/static/src/js/view_editor.js b/addons/web/static/src/js/view_editor.js
index c53a7f8df38..352856c2b6c 100644
--- a/addons/web/static/src/js/view_editor.js
+++ b/addons/web/static/src/js/view_editor.js
@@ -1,13 +1,16 @@
openerp.web.view_editor = function(openerp) {
+var _t = openerp.web._t;
var QWeb = openerp.web.qweb;
openerp.web.ViewEditor = openerp.web.Widget.extend({
init: function(parent, element_id, dataset, view, options) {
this._super(parent);
this.element_id = element_id
this.parent = parent
- this.dataset = dataset;
+ this.dataset = new openerp.web.DataSetSearch(this, 'ir.ui.view', null, null),
this.model = dataset.model;
- this.xml_id = 0;
+ this.xml_element_id = 0;
+ this.property = openerp.web.ViewEditor.property_widget;
+ this.one_object = false;
},
start: function() {
this.init_view_editor();
@@ -15,24 +18,24 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
init_view_editor: function() {
var self = this;
var action = {
- name:'ViewEditor',
- context:this.session.user_context,
- domain: [["model", "=", this.dataset.model]],
- res_model : 'ir.ui.view',
- views : [[false, 'list']],
+ name: _.str.sprintf("Manage Views (%s)", this.model),
+ 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 : 80,
- auto_search : true,
+ limit: this.dataset.limit || 80,
flags: {
sidebar: false,
deletable: false,
views_switcher: false,
- action_buttons:false,
- search_view:false,
- pager:false,
- radio: true
- }
+ action_buttons: false,
+ search_view: false,
+ pager: false,
+ radio: true,
+ select_view_id: self.parent.fields_view.view_id
+ },
};
this.view_edit_dialog = new openerp.web.Dialog(this, {
modal: true,
@@ -41,207 +44,308 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
height: 500,
buttons: {
"Create": function(){
- //to do
+ self.on_create_view();
},
"Edit": function(){
- self.xml_id=0;
- self.get_data();
+ self.xml_element_id = 0;
+ self.get_arch();
+ },
+ "Remove": function(){
+ self.do_delete_view();
},
"Close": function(){
self.view_edit_dialog.close();
}
- }
- });
- this.view_edit_dialog.start().open();
- var action_manager = new openerp.web.ActionManager(this);
- action_manager.appendTo(this.view_edit_dialog);
- action_manager.do_action(action);
- },
- check_attr: function(xml, tag, level) {
- var obj = {'child_id': [], 'id': this.xml_id++, 'level': level+1, 'att_list': [], 'name': ""};
- var render_name = "<" + tag;
- obj.att_list.push(tag);
- $(xml).each(function() {
- _.each(this.attributes, function(attrs){
- if (tag != 'button') {
- if (attrs.nodeName == "string" || attrs.nodeName == "name" || attrs.nodeName == "index") {
- render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"' ;
+ },
+ }).start().open();
+ this.main_view_id = this.parent.fields_view.view_id;
+ this.action_manager = new openerp.web.ActionManager(this);
+ this.action_manager.appendTo(this.view_edit_dialog);
+ $.when(this.action_manager.do_action(action)).then(function() {
+ var viewmanager = self.action_manager.inner_viewmanager,
+ controller = viewmanager.views[viewmanager.active_view].controller;
+ controller.on_loaded.add_last(function(){
+ $(controller.groups).bind({
+ 'selected': function(e, ids, records) {
+ self.main_view_id = ids[0];
}
- } else {
- if (attrs.nodeName == "name") {
- render_name += ' ' + attrs.nodeName + '=' + '"' + attrs.nodeValue + '"';
- }
- }
- obj.att_list.push( [attrs.nodeName,attrs.nodeValue] );
+ })
});
- render_name+= ">";
});
- obj.name = render_name;
- return obj;
},
- save_object: function(val, parent_list, child_obj_list) {
+ on_create_view: function() {
var self = this;
- var check_id = parent_list[0];
- var p_list = parent_list.slice(1);
- if (val.child_id.length != 0) {
- _.each(val.child_id, function(val, key) {
- if (val.id == check_id) {
- if (p_list.length!=0) {
- self.save_object(val, p_list, child_obj_list);
- } else {
- val.child_id = child_obj_list;
- return false;
+ this.create_view_dialog = new openerp.web.Dialog(this, {
+ modal: true,
+ title: _.str.sprintf("Create a view (%s)", self.model),
+ width: 500,
+ height: 400,
+ buttons: {
+ "Save": 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_viewmanager.views[self.action_manager.inner_viewmanager.active_view].controller;
+ controller.reload_content();
+ });
+ }
+ },
+ "Cancel": function(){
+ self.create_view_dialog.close();
}
}
+ });
+ this.create_view_dialog.start().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_forms"></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 openerp.web.DataSetSearch(this, this.model, null, null);
+ var model_dataset = new openerp.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]]}, 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() {
+ if (confirm(_t("Do you really want to remove this view?"))) {
+ var controller = this.action_manager.inner_viewmanager.views[this.action_manager.inner_viewmanager.active_view].controller;
+ this.dataset.unlink([this.main_view_id]).then(function() {
+ controller.reload_content();
+ this.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 {
- val.child_id = child_obj_list;
+ _.each(main_object.child_id, function(child_object) {
+ self.append_child_object(child_object, parent_id, child_obj_list);
+ });
}
},
- xml_node_create: function(xml, root, parent_list, parent_id, main_object){
+ convert_arch_to_obj: function(xml_Node, main_object, parent_id) {
var self = this;
var child_obj_list = [];
- var children_list = $(xml).filter(root).children();
- var parents = $(children_list[0]).parents().get();
- _.each(children_list, function (child_node) {
- child_obj_list.push(self.check_attr(child_node,child_node.tagName.toLowerCase(),parents.length));
+ _.each(xml_Node, function(element) {
+ child_obj_list.push(self.create_View_Node(element));
});
- if (children_list.length != 0) {
- if (parents.length <= parent_list.length) {
- parent_list.splice(parents.length - 1);
+ 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);
}
- parent_list.push(parent_id);
- self.save_object(main_object[0], parent_list.slice(1), child_obj_list);
- }
- for (var i = 0; i < children_list.length; i++) {
- self.xml_node_create
- (children_list[i], children_list[i].tagName.toLowerCase(),
- parent_list, child_obj_list[i].id, main_object);
- }
+ });
return main_object;
},
parse_xml: function(arch, view_id) {
- var root = $(arch).filter(":first")[0];
- var tag = root.tagName.toLowerCase();
- var obj ={'child_id':[],'id':this.xml_id++,'level':0,'att_list':[],'name':"<view view_id='"+view_id+"'>"};
- var root_object = this.check_attr(root,tag,0);
- obj.child_id = this.xml_node_create(arch, tag, [], this.xml_id-1, [root_object], [])
- return [obj];
- },
- get_data: function() {
+ 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 = [];
- self.main_view_id =((this.view_edit_dialog.$element.find("input[name='radiogroup']:checked").parent()).parent()).attr('data-id');
- var ve_dataset = new openerp.web.DataSet(this, 'ir.ui.view');
- ve_dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], function (arch) {
- one_object = self.parse_xml(arch[0].arch,self.main_view_id);
- self.main_view_type = arch[0].type
- view_arch_list.push({"view_id" : self.main_view_id, "arch" : arch[0].arch});
- dataset = new openerp.web.DataSetSearch(self, 'ir.ui.view', null, null);
- dataset.read_slice([], {domain : [['inherit_id','=', parseInt(self.main_view_id)]]}, function (result) {
- _.each(result, function(res) {
- view_arch_list.push({"view_id":res.id,"arch":res.arch});
- self.inherit_view(one_object, res);
+ this.dataset.read_ids([parseInt(self.main_view_id)], ['arch', 'type'], 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});
+ self.dataset.read_slice([], {domain: [['inherit_id','=', parseInt(self.main_view_id)]]}, function(result) {
+ _.each(result, function(res) {
+ view_arch_list.push({"view_id": res.id, "arch": res.arch});
+ 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});
});
- return self.edit_view({"main_object": one_object,
- "parent_child_id": self.parent_child_list(one_object, []),
- "arch": view_arch_list});
- });
+ } else {
+ self.do_warn("Please select view in list :");
+ }
});
},
- parent_child_list : function(one_object, p_list) {
+ parent_child_list : function(one_object, parent_list) {
var self = this;
- _.each(one_object , function(element){
- if(element.child_id.length != 0){
- p_list.push({"key":element.id,"value":_.pluck(element.child_id, 'id')});
- self.parent_child_list(element.child_id, p_list);
+ _.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 p_list;
+ return parent_list;
},
- inherit_view : function(one_object, result) {
- var self = this;
- var root = $(result.arch).filter('*');
- var xml_list = [];
- if (root[0].tagName.toLowerCase() == "data") {
- xml_list = $(root[0]).children();
+ 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(root[0]);
+ xml_list.push( xml_arch.childNodes[0]);
}
- _.each(xml_list , function(xml){
- var parent_id;
- var check_list = [];
- var xpath_object = self.parse_xml(xml,result.id);
- if (xml.tagName.toLowerCase() == "xpath" ) {
- var part_expr = _.without($(xml).attr('expr').split("/"),"");
- _.each(part_expr,function(part){
- check_list.push(_.without($.trim(part.replace(/[^a-zA-Z 0-9 _]+/g,'!')).split("!"),""));
+ _.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 = [];
- _.each(xpath_object[0].child_id[0].att_list, function(list){
- if(!_.include(list, "position")){
- temp.push(list);
- }
+ var temp = _.reject(xpath_arch_object[0].child_id[0].att_list, function(list) {
+ return list instanceof Array? _.include(list, "position"): false;
});
- check_list = [_.flatten(temp)];
+ expr_to_list = [_.flatten(temp)];
}
- self.full_path_search(check_list ,one_object ,xpath_object);
+ self.inherit_apply(expr_to_list, arch_object ,xpath_arch_object);
});
},
- full_path_search: function(check_list ,val ,xpath_object) {
+ inherit_apply: function(expr_list ,arch_object ,xpath_arch_object) {
var self = this;
- if(xpath_object.length!=0){
- var check = check_list[0];
- var obj;
+ if (xpath_arch_object.length) {
+ var check = expr_list[0], obj = false;
switch (check.length) {
case 2:
- if(parseInt(check[1])){
- var list_1 = _.select(val,function(element){
- var main_list = _.flatten(element.att_list);
- return _.include(main_list, check[0]);
+ if (parseInt(check[1])) {
+ //for field[3]
+ var temp_list = _.select(arch_object, function(element) {
+ return _.include(_.flatten(element.att_list), check[0]);
});
- obj = val[_.indexOf(val,list_1[parseInt(check[1])-1])];
+ obj = arch_object[_.indexOf(arch_object, temp_list[parseInt(check[1]) - 1])];
} else {
- obj = _.detect(val, function(element){
- var main_list = _.flatten(element.att_list);
- return _.include(main_list, check[0]);
+ //for notebook[last()]
+ obj = _.detect(arch_object, function(element) {
+ return _.include(_.flatten(element.att_list), check[0]);
});
}
break;
case 3:
- obj = _.detect(val,function(element){
- var main_list = _.flatten(element.att_list);
- check = _.uniq(check);
- var insert = _.intersection(main_list,check);
- if(insert.length == check.length ){return element;}
+ //for field[@name='type']
+ obj = _.detect(arch_object, function(element){
+ if ((_.intersection(_.flatten(element.att_list), _.uniq(check))).length == check.length) {
+ return element;
+ }
});
break;
case 1:
- var list_1 = _.select(val,function(element){
- var main_list = _.flatten(element.att_list);
- return _.include(main_list, check[0]);
+ //for /form/notebook
+ var temp_list = _.select(arch_object, function(element) {
+ return _.include(_.flatten(element.att_list), check[0]);
});
- if(list_1.length != 0){
- (check_list.length == 1)? obj = list_1[0] : check_list.shift();
+ if (temp_list.length != 0) {
+ expr_list.length == 1 ? obj = temp_list[0] : expr_list.shift();
}
break;
}
- if(obj) {
- check_list.shift();
- if (check_list.length !=0){
- self.full_path_search(check_list ,obj.child_id ,xpath_object);
+ if (obj) {
+ expr_list.shift();
+ if (expr_list.length) {
+ self.inherit_apply(expr_list, obj.child_id, xpath_arch_object);
} else {
- var level = obj.level+1;
- self.increase_level(xpath_object[0], level)
- obj.child_id.push(xpath_object[0]);
- xpath_object.pop();
- return;
+ self.increase_level(xpath_arch_object[0], obj.level + 1);
+ obj.child_id.push(xpath_arch_object[0]);
+ xpath_arch_object.pop();
}
- }
- else {
- _.each(val,function(element){
- self.full_path_search(check_list ,element.child_id ,xpath_object);
+ } else {
+ _.each(arch_object, function(element) {
+ self.inherit_apply(expr_list, element.child_id, xpath_arch_object);
});
}
}
@@ -253,31 +357,40 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
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.edit_xml_dialog = new openerp.web.Dialog(this,{
+ this.one_object = one_object;
+ this.edit_xml_dialog = new openerp.web.Dialog(this, {
modal: true,
- title: 'View Editor',
+ title: _.str.sprintf("View Editor %d - %s", self.main_view_id, self.model),
width: 750,
height: 500,
buttons: {
- "Inherited View": function(){
- //todo
- },
- "Preview": function(){
+ "Preview": function() {
var action = {
- context:self.session.user_context,
- res_model : self.model,
- views : [[self.main_view_id, self.main_view_type]],
+ 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",
flags: {
sidebar: false,
views_switcher: false,
- action_buttons:false,
- search_view:false,
- pager:false
- }
+ action_buttons: false,
+ },
};
var action_manager = new openerp.web.ActionManager(self);
action_manager.do_action(action);
@@ -286,231 +399,766 @@ openerp.web.ViewEditor = openerp.web.Widget.extend({
self.edit_xml_dialog.close();
}
}
+ }).start().open();
+ var no_property_att = [];
+ _.each(_PROPERTIES, function(val, key) {
+ if (! val.length) no_property_att.push(key);
});
- this.edit_xml_dialog.start().open();
- this.edit_xml_dialog.$element.html(QWeb.render('view_editor', {
- 'data': one_object['main_object']
- }));
+ 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.edit_xml_dialog.$element.find("tr[id^='viewedit-']").removeClass('ui-selected');
- $(this).addClass('ui-selected');
+ self.do_select_row(this.id.split('-')[1]);
});
this.edit_xml_dialog.$element.find("img[id^='parentimg-']").click(function() {
- if ($(this).attr('src') == '/web/static/src/img/collapse.gif') {
- $(this).attr('src', '/web/static/src/img/expand.gif');
- self.on_expand(this);
- } else {
- $(this).attr('src', '/web/static/src/img/collapse.gif');
- var id = this.id.split('-')[1];
- self.on_collapse(this,one_object['parent_child_id'], one_object['main_object']);
- }
+ self.do_parent_img_hide_show(this);
});
this.edit_xml_dialog.$element.find("img[id^='side-']").click(function() {
- var side = $(this).closest("tr[id^='viewedit-']")
- var id_tr = (side.attr('id')).split('-')[1];
- var img = side.find("img[id='parentimg-"+id_tr+"']").attr('src'); ;
- var level = parseInt(side.attr('level'));
- var list_shift =[];
- var last_tr;
- var cur_tr = side;
- list_shift.push(side);
- var next_tr;
- var ls = side;
- var view_id;
- var view_xml_id;
- while(1){
- ls = ls.prev();
- if((self.edit_xml_dialog.$element.find(ls).find('a').text()).search("view_id") != -1
- && parseInt(ls.attr('level')) < level){
- view_id = parseInt(($(ls).find('a').text()).replace(/[^0-9]+/g,''));
- view_xml_id = (ls.attr('id')).split('-')[1];
+ self.on_select_img(this);
+ });
+ },
+ 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'));
+ }
}
- switch (this.id) {
- case "side-add":
- break;
- case "side-remove":
- break;
- case "side-edit":
- break;
- case "side-up":
- while (1) {
- var prev_tr = cur_tr.prev();
- if(level >= parseInt(prev_tr.attr('level')) || prev_tr.length == 0) {
- last_tr = prev_tr;
- break;
- }
- cur_tr = prev_tr;
- }
- if (img) {
- while (1) {
- next_tr = side.next();
- if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) {
- break;
- } else {
- list_shift.push(next_tr);
- side = next_tr;
- }
- }
- }
- if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == level &&
- (self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") == -1) {
- _.each(list_shift, function(rec) {
- $(last_tr).before(rec);
- });
- self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "up");
- }
+ }
+ 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-down":
- if (img) {
- while (1) {
- next_tr = cur_tr.next();
- if ( parseInt(next_tr.attr('level')) <= level || next_tr.length == 0) {
- last_tr = next_tr;
- break;
- } else {
- list_shift.push(next_tr);
- cur_tr = next_tr;
- }
- }
+ case "side-remove":
+ if (confirm(_t("Do you really want to remove this node?"))) {
+ self.do_save_update_arch("remove_node");
}
- else {
- last_tr = cur_tr.next();
+ 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;
+ var tr = $(side).find('a').text();
+ var parent_tr = ($(side).prevAll("tr[level=" + String(this.one_object.clicked_tr_level - 1) + "]"))[0];
+ var field_dataset = new openerp.web.DataSetSearch(this, this.model, null, null);
+ parent_tr = $(parent_tr).find('a').text();
+ field_dataset.call( 'fields_get', [], function(result) {
+ var fields = _.keys(result);
+ fields.push(" "),fields.sort();
+ var property_to_check = [];
+ _.each([tr, parent_tr],function(element) {
+ property_to_check.push(
+ _.detect(_.keys(_CHILDREN),function(res){
+ return _.str.include(element, res);
+ }));
+ });
+ 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;
}
- if((self.edit_xml_dialog.$element.find(last_tr).find('a').text()).search("view_id") != -1){
- return;
+ }
+ } 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;
}
- if (last_tr.length != 0 && parseInt(last_tr.attr('level')) == 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') <= level || next_tr.length == 0) break;
- next_tr.hide();
- last_tr = next_tr;
- }
- }
- list_shift.reverse();
- _.each(list_shift, function(rec) {
- $(last_tr).after(rec);
- });
- self.save_move_arch(one_object, view_id, view_xml_id, id_tr, level, "down");
+ }
+ 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;
}
- break;
}
- });
+ }
+ 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");
+ }
},
- save_move_arch: function(one_object, view_id, view_xml_id, id_tr, level, move_direct){
+ do_save_update_arch: function(move_direct, update_values) {
var self = this;
- var arch = _.detect(one_object['arch'],function(element){
- return element.view_id == view_id;
- });
- var obj = self.get_view_object(view_xml_id, one_object['main_object'], []);
- if(($(arch.arch).filter("data")).length != 0 && view_xml_id != 0){
+ 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);
- arch.arch = _.detect($(arch.arch).children(), function(xml_child){
- var temp_obj = self.check_attr(xml_child, xml_child.tagName.toLowerCase());
- var main_list = _.flatten(temp_obj.att_list);
- check_list = _.uniq(check_list);
- var insert = _.intersection(main_list,check_list);
- if(insert.length == check_list.length ){return xml_child;}
+ 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 == check_list.length ) {return xml_child;}
});
}
- return self.get_node(arch.arch, obj[0].child_id[0], parseInt(id_tr), [], parseInt(level),
- parseInt(view_id), arch, move_direct);
+ arch_to_pass = _.filter($(arch.arch), function (child) {
+ return child.nodeType == 1;
+ });
+ return self.do_save_xml(arch_to_pass[0], obj[0].child_id[0],[], move_direct, update_values,arch);
},
-
- get_view_object: function(view_xml_id, one_object,result){
+ get_object_by_id: function(id, one_object, result) {
var self = this;
- if(result.length==0){
- var check = _.detect(one_object , function(obj){
- return view_xml_id==obj.id;
+ 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_view_object(view_xml_id, obj.child_id, result);
+ if (check) {result.push(check);};
+ _.each(one_object, function(obj) {
+ self.get_object_by_id(id,obj.child_id, result);
});
}
return result;
},
- get_node: function(arch1, obj, id, child_list, level, view_id, arch, move_direct){
+ create_clone: function(clone, new_node_obj, position){
var self = this;
- var children_list = $(arch1).children();
- var list_obj_xml = _.zip(children_list,obj.child_id);
- if (id) {
- if (obj.id == id) {
- var id;
- var parent = $(arch1).parents();
- var index = _.indexOf(child_list, obj)
- var re_insert_obj = child_list.splice(index, 1);
+ 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 = _.zip(children_list, obj.child_id);
+ 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]);
- } else {
+ 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'],[]);
}
- parent = parent[parent.length-1];
- var convert_to_utf = self.xml2Str(parent);
- if (convert_to_utf) {
+ 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;
- dataset = new openerp.web.DataSet(this, 'ir.ui.view');
- dataset.write(parseInt(view_id),{"arch":convert_to_utf}, function(r) {
- });
+ 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 <= level) {
+ if (obj.level <= this.one_object.clicked_tr_level) {
_.each(list_obj_xml, function(child_node) {
- self.get_node(child_node[0], child_node[1], id, obj.child_id, level, view_id, arch, move_direct);
+ self.do_save_xml(child_node[0], child_node[1], obj.child_id, move_direct, update_values, arch);
});
}
}
},
- xml2Str: function(xmlNode) {
- try {
- return (new XMLSerializer()).serializeToString(xmlNode);
- }
- catch (e) {
- try {
- return xmlNode.xml;
- }
- catch (e) {
- return false;
- }
- }
-
- },
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){
+ if (parseInt(nxt_tr.attr('level')) > level) {
cur_tr = nxt_tr;
- nxt_tr.hide();
- } else return nxt_tr;
+ tr_list.push(nxt_tr);
+ } else return tr_list;
}
},
- on_collapse: function(collapse_img, parent_child_id, id, main_object) {
- var self = this;
- var id = collapse_img.id.split('-')[1];
- var datas = _.detect(parent_child_id,function(res) {
+ 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');
+ _.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 openerp.web.Dialog(this,{
+ modal: true,
+ title: 'Properties',
+ width: 500,
+ height: 400,
+ buttons: {
+ "Update": 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();
+ }
+ },
+ "Cancel": function(){
+ self.edit_node_dialog.close();
+ }
+ }
+ });
+ this.edit_node_dialog.start().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'},
+ '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': 'seleciton_multi'},
+ };
+ 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_forms"></table>');
+ this.edit_widget = [];
+ self.ready = $.when(self.on_groups(properties)).then(function () {
+ _PROPERTIES_ATTRIBUTES['groups']['selection'] = self.groups;
+ var values = _.keys( openerp.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 openerp.web.DataSetSearch(this,'res.groups', null, null),
+ model_data = new openerp.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.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 openerp.web.Dialog(this,{
+ modal: true,
+ title: 'Properties',
+ width: 450,
+ height: 190,
+ buttons: {
+ "Update": 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");}
+ },
+ "Cancel": function(){
+ self.add_node_dialog.close();
+ }
+ }
+ }).start().open();
+ this.add_node_dialog.$element.append('<table id="rec_table" style="width:420px" class="oe_forms"><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 openerp.web.DataSetSearch(self,'ir.model', null, null);
+ model_data.read_slice([], {domain: [['model','=', self.model]]}, function(result) {
+ self.render_new_field(result[0].id);
+ });
+ });
+ },
+ render_new_field :function(id){
+ var self = this;
+ var action = {
+ context: {'default_model_id': id, 'manual':true},
+ res_model: "ir.model.fields",
+ views: [[false, 'form']],
+ type: 'ir.actions.act_window',
+ target: "new",
+ flags: {
+ action_buttons: true,
+ }
+ }
+ var action_manager = new openerp.web.ActionManager(self);
+ $.when(action_manager.do_action(action)).then(function() {
+ var controller = action_manager.dialog_viewmanager.views['form'].controller;
+ // TODO NIV: use page view
+ controller.do_set_readonly.add_last(function(){
+ action_manager.stop();
+ new_fields_name = new openerp.web.DataSetSearch(self,'ir.model.fields', null, null);
+ new_fields_name.read_ids([controller.datarecord.id], ['name'], function(result) {
+ self.add_node_dialog.$element.find('select[id=field_value]').append($("<option selected></option>").attr("value", result[0].name).text(result[0].name));
+ _.detect(self.add_widget,function(widget){
+ widget.name == "field_value"? widget.selection.push(result[0].name): false;
+ });
+ });
+ });
+ });
+ }
+});
+openerp.web.ViewEditor.Field = openerp.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 = openerp.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}))
+ },
+});
+openerp.web.ViewEditor.FieldBoolean = openerp.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;
}
+});
+openerp.web.ViewEditor.FieldChar = openerp.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();
+ }
+});
+openerp.web.ViewEditor.FieldSelect = openerp.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][1] === 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();
+ }
+});
+openerp.web.ViewEditor.FieldSelectMulti = openerp.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)
+ }
+ });
+ }
+});
+openerp.web.ViewEditor.FieldFloat = openerp.web.ViewEditor.FieldChar.extend({
+});
+var _PROPERTIES = {
+ 'field' : ['name', 'string', 'required', 'readonly', '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', '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'],
+ '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'],
+ 'board': ['column'],
+ 'action': [],
+ 'field': ['form', 'tree', 'graph'],
+ 'label': [],
+ 'button' : [],
+ 'newline': [],
+ 'separator': [],
+};
+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'
+];
+openerp.web.ViewEditor.property_widget = new openerp.web.Registry({
+ 'boolean' : 'openerp.web.ViewEditor.FieldBoolean',
+ 'seleciton_multi' : 'openerp.web.ViewEditor.FieldSelectMulti',
+ 'selection' : 'openerp.web.ViewEditor.FieldSelect',
+ 'char' : 'openerp.web.ViewEditor.FieldChar',
+ 'float' : 'openerp.web.ViewEditor.FieldFloat',
});
};
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index c5a2fbb4dc6..15a402efb47 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -33,16 +33,18 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
this.widgets = {};
this.widgets_counter = 0;
this.fields = {};
+ this.fields_order = [];
this.datarecord = {};
this.show_invalid = true;
this.default_focus_field = null;
this.default_focus_button = null;
- this.registry = this.readonly ? openerp.web.form.readonly : openerp.web.form.widgets;
+ this.registry = openerp.web.form.widgets;
this.has_been_loaded = $.Deferred();
this.$form_header = null;
this.translatable_fields = [];
- _.defaults(this.options, {"always_show_new_button": true,
- "not_interactible_on_create": false});
+ _.defaults(this.options, {
+ "not_interactible_on_create": false
+ });
this.mutating_lock = $.Deferred();
this.initial_mutating_lock = this.mutating_lock;
this.on_change_lock = $.Deferred().resolve();
@@ -86,6 +88,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
on_loaded: function(data) {
var self = this;
if (data) {
+ this.fields_order = [];
this.fields_view = data;
var frame = new (this.registry.get_object('frame'))(this, this.fields_view.arch);
@@ -102,10 +105,7 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
});
this.$form_header.find('button.oe_form_button_save').click(this.on_button_save);
- this.$form_header.find('button.oe_form_button_new').click(this.on_button_new);
- this.$form_header.find('button.oe_form_button_duplicate').click(this.on_button_duplicate);
- this.$form_header.find('button.oe_form_button_delete').click(this.on_button_delete);
- this.$form_header.find('button.oe_form_button_toggle').click(this.on_toggle_readonly);
+ this.$form_header.find('button.oe_form_button_cancel').click(this.on_button_cancel);
if (!this.sidebar && this.options.sidebar && this.options.sidebar_id) {
this.sidebar = new openerp.web.Sidebar(this, this.options.sidebar_id);
@@ -117,23 +117,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
this.has_been_loaded.resolve();
},
- on_toggle_readonly: function() {
- var self = this;
- self.translatable_fields = [];
- self.widgets = {};
- self.fields = {};
- self.$form_header.find('button').unbind('click');
- self.readonly = !self.readonly;
- self.registry = self.readonly ? openerp.web.form.readonly : openerp.web.form.widgets;
- self.on_loaded(self.fields_view);
- return self.reload();
- },
- do_set_readonly: function() {
- return this.readonly ? $.Deferred().resolve() : this.on_toggle_readonly();
- },
- do_set_editable: function() {
- return !this.readonly ? $.Deferred().resolve() : this.on_toggle_readonly();
- },
do_show: function () {
var promise;
if (this.dataset.index === null) {
@@ -160,19 +143,6 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (!record) {
throw("Form: No record received");
}
- if (!record.id) {
- this.$form_header.find('.oe_form_on_create').show();
- this.$form_header.find('.oe_form_on_update').hide();
- if (!this.options["always_show_new_button"]) {
- this.$form_header.find('button.oe_form_button_new').hide();
- }
- } else {
- this.$form_header.find('.oe_form_on_create').hide();
- this.$form_header.find('.oe_form_on_update').show();
- this.$form_header.find('button.oe_form_button_new').show();
- }
- this.$form_header.find('.oe_form_on_readonly').toggle(this.readonly);
- this.$form_header.find('.oe_form_on_editable').toggle(!this.readonly);
this.datarecord = record;
_(this.fields).each(function (field, f) {
@@ -188,15 +158,16 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
deferred_stack.push('force resolution if no fields');
return deferred_stack.then(function() {
if (!record.id) {
- // New record: Second pass in order to trigger the onchanges
self.show_invalid = false;
- for (var f in record) {
- var field = self.fields[f];
- if (field) {
+ // New record: Second pass in order to trigger the onchanges
+ // respecting the fields order defined in the view
+ _.each(self.fields_order, function(field_name) {
+ if (record[field_name] !== undefined) {
+ var field = self.fields[field_name];
field.dirty = true;
self.do_onchange(field);
}
- }
+ });
}
self.on_form_changed();
self.initial_mutating_lock.resolve();
@@ -273,6 +244,10 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
if (field in argument_replacement) {
return argument_replacement[field](i);
}
+ // literal number
+ if (/^-?\d+(\.\d+)?$/.test(field)) {
+ return Number(field);
+ }
// form field
if (self.fields[field]) {
var value = self.fields[field].get_on_change_value();
@@ -380,63 +355,35 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
}
},
on_button_save: function() {
- return this.do_save().then(this.do_set_readonly);
- },
- on_button_new: function() {
var self = this;
- var def = $.Deferred();
- $.when(this.has_been_loaded).then(function() {
- if (self.can_be_discarded()) {
- var keys = _.keys(self.fields_view.fields);
- $.when(self.do_set_editable()).then(function() {
- if (keys.length) {
- self.dataset.default_get(keys).pipe(self.on_record_loaded).then(function() {
- def.resolve();
- });
- } else {
- self.on_record_loaded({}).then(function() {
- def.resolve();
- });
- }
- });
- }
+ return this.do_save().then(function(result) {
+ self.do_prev_view(result.created);
});
- return def.promise();
},
- on_button_duplicate: function() {
- var self = this;
- var def = $.Deferred();
- $.when(this.has_been_loaded).then(function() {
- if (self.can_be_discarded()) {
- self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
- return self.on_created({ result : new_id });
- }).then(self.do_set_editable).then(function() {
- def.resolve();
- });
- }
- });
- return def.promise();
+ on_button_cancel: function() {
+ return this.do_prev_view();
},
- on_button_delete: function() {
+ on_button_new: function() {
var self = this;
var def = $.Deferred();
$.when(this.has_been_loaded).then(function() {
- if (self.can_be_discarded() && self.datarecord.id) {
- if (confirm(_t("Do you really want to delete this record?"))) {
- self.dataset.unlink([self.datarecord.id]).then(function() {
- self.on_pager_action('next');
+ if (self.can_be_discarded()) {
+ var keys = _.keys(self.fields_view.fields);
+ if (keys.length) {
+ self.dataset.default_get(keys).pipe(self.on_record_loaded).then(function() {
def.resolve();
});
} else {
- setTimeout(function () {
- def.reject();
- }, 0)
+ self.on_record_loaded({}).then(function() {
+ def.resolve();
+ });
}
}
});
return def.promise();
},
can_be_discarded: function() {
+ return true; // FIXME: Disabled until the page view and button refactoring is done
return !this.is_dirty() || confirm(_t("Warning, the record has been modified, your changes will be discarded."));
},
/**
@@ -476,22 +423,22 @@ openerp.web.FormView = openerp.web.View.extend( /** @lends openerp.web.FormView#
self.on_invalid();
return $.Deferred().reject();
} else {
+ var save_deferral;
if (!self.datarecord.id) {
openerp.log("FormView(", self, ") : About to create", values);
- return self.dataset.create(values).pipe(function(r) {
+ save_deferral = self.dataset.create(values).pipe(function(r) {
return self.on_created(r, undefined, prepend_on_create);
- }).then(success);
+ }, null);
} else if (_.isEmpty(values)) {
openerp.log("FormView(", self, ") : Nothing to save");
- if (success) {
- success();
- }
+ save_deferral = $.Deferred().resolve({}).promise();
} else {
openerp.log("FormView(", self, ") : About to save", values);
- return self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
+ save_deferral = self.dataset.write(self.datarecord.id, values, {}).pipe(function(r) {
return self.on_saved(r);
- }).then(success);
+ }, null);
}
+ return save_deferral.then(success);
}
} catch (e) {
console.error(e);
@@ -951,8 +898,9 @@ openerp.web.form.WidgetFrame = openerp.web.form.Widget.extend({
var type = {};
if (node.tag == 'field') {
type = this.view.fields_view.fields[node.attrs.name] || {};
- if (node.attrs.widget == 'statusbar') {
+ if (node.attrs.widget == 'statusbar' && node.attrs.nolabel !== '1') {
// This way we can retain backward compatibility between addons and old clients
+ node.attrs.colspan = (parseInt(node.attrs.colspan, 10) || 1) + 1;
node.attrs.nolabel = '1';
}
}
@@ -1095,6 +1043,7 @@ openerp.web.form.WidgetButton = openerp.web.form.Widget.extend({
this.execute_action().always(function() {
self.force_disabled = false;
self.check_disable();
+ $.tipTipClear();
});
},
execute_action: function() {
@@ -1169,6 +1118,11 @@ openerp.web.form.WidgetLabel = openerp.web.form.Widget.extend({
if (this.node.tag == 'label' && (this.align === 'left' || this.node.attrs.colspan || (this.string && this.string.length > 32))) {
this.template = "WidgetParagraph";
this.colspan = parseInt(this.node.attrs.colspan || 1, 10);
+ // Widgets default to right-aligned, but paragraph defaults to
+ // left-aligned
+ if (isNaN(parseFloat(this.node.attrs.align))) {
+ this.align = 'left';
+ }
} else {
this.colspan = 1;
this.width = '1%';
@@ -1209,6 +1163,7 @@ openerp.web.form.Field = openerp.web.form.Widget.extend(/** @lends openerp.web.f
this.name = node.attrs.name;
this.value = undefined;
view.fields[this.name] = this;
+ view.fields_order.push(this.name);
this.type = node.attrs.widget || view.fields_view.fields[node.attrs.name].type;
this.element_name = "field_" + this.name + "_" + this.type;
@@ -1600,7 +1555,7 @@ openerp.web.form.FieldSelection = openerp.web.form.Field.extend({
init: function(view, node) {
var self = this;
this._super(view, node);
- this.values = this.field.selection;
+ this.values = _.clone(this.field.selection);
_.each(this.values, function(v, i) {
if (v[0] === false && v[1] === '') {
self.values.splice(i, 1);
@@ -2099,16 +2054,20 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
view.options.deletable = null;
}
} else if (view.view_type === "form") {
+ if (self.is_readonly()) {
+ view.view_type = 'page';
+ }
view.options.not_interactible_on_create = true;
}
views.push(view);
});
this.views = views;
-
+
this.viewmanager = new openerp.web.ViewManager(this, this.dataset, views);
this.viewmanager.registry = openerp.web.views.clone({
list: 'openerp.web.form.One2ManyListView',
- form: 'openerp.web.FormView'
+ form: 'openerp.web.FormView',
+ page: 'openerp.web.PageView'
});
var once = $.Deferred().then(function() {
self.init_form_last_update.resolve();
@@ -2121,10 +2080,9 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
controller.o2m = self;
if (self.is_readonly())
controller.set_editable(false);
- } else if (view_type == "form") {
- if (self.is_readonly()) {
- controller.on_toggle_readonly();
- $(controller.$element.find(".oe_form_buttons")[0]).children().remove();
+ } else if (view_type == "form" || view_type == 'page') {
+ if (view_type == 'page') {
+ controller.$element.find(".oe_form_buttons").hide();
}
controller.on_record_loaded.add_last(function() {
once.resolve();
@@ -2154,22 +2112,23 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
reload_current_view: function() {
var self = this;
return self.is_loaded = self.is_loaded.pipe(function() {
- var view = self.viewmanager.views[self.viewmanager.active_view].controller;
- if(self.viewmanager.active_view === "list") {
+ var active_view = self.viewmanager.active_view;
+ var view = self.viewmanager.views[active_view].controller;
+ if(active_view === "list") {
return view.reload_content();
- } else if (self.viewmanager.active_view === "form") {
+ } else if (active_view === "form" || active_view === 'page') {
if (self.dataset.index === null && self.dataset.ids.length >= 1) {
self.dataset.index = 0;
}
var act = function() {
return view.do_show();
- }
+ };
self.form_last_update = self.form_last_update.pipe(act, act);
return self.form_last_update;
- } else if (self.viewmanager.active_view === "graph") {
+ } else if (active_view === "graph") {
return view.do_search(self.build_domain(), self.dataset.get_context(), []);
}
- });
+ }, undefined);
},
set_value: function(value) {
value = value || [];
@@ -2233,6 +2192,7 @@ openerp.web.form.FieldOne2Many = openerp.web.form.Field.extend({
var self = this;
if (!this.dataset)
return [];
+ this.save_any_view();
var val = this.dataset.delete_all ? [commands.delete_all()] : [];
val = val.concat(_.map(this.dataset.ids, function(id) {
var alter_order = _.detect(self.dataset.to_create, function(x) {return x.id === id;});
@@ -2489,7 +2449,9 @@ openerp.web.form.Many2ManyListView = openerp.web.ListView.extend(/** @lends open
do_activate_record: function(index, id) {
var self = this;
var pop = new openerp.web.form.FormOpenPopup(this);
- pop.show_element(this.dataset.model, id, this.m2m_field.build_context(), {});
+ pop.show_element(this.dataset.model, id, this.m2m_field.build_context(), {
+ readonly: this.widget_parent.is_readonly()
+ });
pop.on_write_completed.add_last(function() {
self.reload_content();
});
@@ -2548,18 +2510,30 @@ openerp.web.form.SelectCreatePopup = openerp.web.OldWidget.extend(/** @lends ope
this.dataset.parent_view = this.options.parent_view;
this.dataset.on_default_get.add(this.on_default_get);
if (this.options.initial_view == "search") {
- this.setup_search_view();
+ self.rpc('/web/session/eval_domain_and_context', {
+ domains: [],
+ contexts: [this.context]
+ }, function (results) {
+ var search_defaults = {};
+ _.each(results.context, function (value, key) {
+ var match = /^search_default_(.*)$/.exec(key);
+ if (match) {
+ search_defaults[match[1]] = value;
+ }
+ });
+ self.setup_search_view(search_defaults);
+ });
} else { // "form"
this.new_object();
}
},
- setup_search_view: function() {
+ setup_search_view: function(search_defaults) {
var self = this;
if (this.searchview) {
this.searchview.stop();
}
this.searchview = new openerp.web.SearchView(this,
- this.dataset, false, {});
+ this.dataset, false, search_defaults);
this.searchview.on_search.add(function(domains, contexts, groupbys) {
if (self.initial_ids) {
self.do_search(domains.concat([[["id", "in", self.initial_ids]], self.domain]),
@@ -2743,18 +2717,15 @@ openerp.web.form.FormOpenPopup = openerp.web.OldWidget.extend(/** @lends openerp
on_write_completed: function() {},
setup_form_view: function() {
var self = this;
- this.view_form = new openerp.web.FormView(this, this.dataset, false, self.options.form_view_options);
+ var FormClass = this.options.readonly
+ ? openerp.web.views.get_object('page')
+ : openerp.web.views.get_object('form');
+ this.view_form = new FormClass(this, this.dataset, false, self.options.form_view_options);
if (this.options.alternative_form_view) {
this.view_form.set_embedded_view(this.options.alternative_form_view);
}
this.view_form.appendTo(this.$element.find("#" + this.element_id + "_view_form"));
- var once = $.Deferred().then(function() {
- if (self.options.readonly) {
- self.view_form.on_toggle_readonly();
- }
- });
this.view_form.on_loaded.add_last(function() {
- once.resolve();
var $buttons = self.view_form.$element.find(".oe_form_buttons");
$buttons.html(QWeb.render("FormOpenPopup.form.buttons"));
var $nbutton = $buttons.find(".oe_formopenpopup-form-save");
@@ -2808,10 +2779,12 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
this.view_id = 'reference_' + _.uniqueId();
this.widgets = {};
this.fields = {};
+ this.fields_order = [];
this.selection = new openerp.web.form.FieldSelection(this, { attrs: {
name: 'selection',
widget: 'selection'
}});
+ this.reference_ready = true;
this.selection.on_value_changed.add_last(this.on_selection_changed);
this.m2o = new openerp.web.form.FieldMany2One(this, { attrs: {
name: 'm2o',
@@ -2821,10 +2794,12 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
on_nop: function() {
},
on_selection_changed: function() {
- var sel = this.selection.get_value();
- this.m2o.field.relation = sel;
- this.m2o.set_value(null);
- this.m2o.$element.toggle(sel !== false);
+ if (this.reference_ready) {
+ var sel = this.selection.get_value();
+ this.m2o.field.relation = sel;
+ this.m2o.set_value(null);
+ this.m2o.$element.toggle(sel !== false);
+ }
},
start: function() {
this._super();
@@ -2839,11 +2814,18 @@ openerp.web.form.FieldReference = openerp.web.form.Field.extend({
},
set_value: function(value) {
this._super(value);
+ this.reference_ready = false;
+ var vals = [], sel_val, m2o_val;
if (typeof(value) === 'string') {
- var vals = value.split(',');
- this.selection.set_value(vals[0]);
- this.m2o.set_value(parseInt(vals[1], 10));
+ vals = value.split(',');
}
+ sel_val = vals[0] || false;
+ m2o_val = vals[1] ? parseInt(vals[1], 10) : false;
+ this.selection.set_value(sel_val);
+ this.m2o.field.relation = sel_val;
+ this.m2o.set_value(m2o_val);
+ this.m2o.$element.toggle(sel_val !== false);
+ this.reference_ready = true;
},
get_value: function() {
var model = this.selection.get_value(),
@@ -3053,119 +3035,7 @@ openerp.web.form.FieldStatus = openerp.web.form.Field.extend({
}
});
-openerp.web.form.FieldReadonly = openerp.web.form.Field.extend({
-});
-openerp.web.form.FieldCharReadonly = openerp.web.form.FieldReadonly.extend({
- template: 'FieldChar.readonly',
- init: function(view, node) {
- this._super(view, node);
- this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1';
- },
- set_value: function (value) {
- this._super.apply(this, arguments);
- var show_value = openerp.web.format_value(value, this, '');
- if (this.password) {
- show_value = new Array(show_value.length + 1).join('*');
- }
- this.$element.find('div').text(show_value);
- return show_value;
- }
-});
-openerp.web.form.FieldURIReadonly = openerp.web.form.FieldCharReadonly.extend({
- template: 'FieldURI.readonly',
- scheme: null,
- set_value: function (value) {
- var displayed = this._super.apply(this, arguments);
- this.$element.find('a')
- .attr('href', this.scheme + ':' + displayed)
- .text(displayed);
- }
-});
-openerp.web.form.FieldEmailReadonly = openerp.web.form.FieldURIReadonly.extend({
- scheme: 'mailto'
-});
-openerp.web.form.FieldUrlReadonly = openerp.web.form.FieldURIReadonly.extend({
- set_value: function (value) {
- var s = /(\w+):(.+)/.exec(value);
- if (!s || !(s[1] === 'http' || s[1] === 'https')) { return; }
- this.scheme = s[1];
- this._super(s[2]);
- }
-});
-openerp.web.form.FieldBooleanReadonly = openerp.web.form.FieldCharReadonly.extend({
- set_value: function (value) {
- this._super(value ? '\u2611' : '\u2610');
- }
-});
-openerp.web.form.FieldSelectionReadonly = openerp.web.form.FieldReadonly.extend({
- template: 'FieldChar.readonly',
- init: function(view, node) {
- // lifted straight from r/w version
- var self = this;
- this._super(view, node);
- this.values = this.field.selection;
- _.each(this.values, function(v, i) {
- if (v[0] === false && v[1] === '') {
- self.values.splice(i, 1);
- }
- });
- this.values.unshift([false, '']);
- },
- set_value: function (value) {
- value = value === null ? false : value;
- value = value instanceof Array ? value[0] : value;
- var option = _(this.values)
- .detect(function (record) { return record[0] === value; });
- this._super(value);
- this.$element.find('div').text(option ? option[1] : this.values[0][1]);
- }
-});
-openerp.web.form.FieldMany2OneReadonly = openerp.web.form.FieldURIReadonly.extend({
- set_value: function (value) {
- value = value || null;
- this.invalid = false;
- var self = this;
- this.value = value;
- self.update_dom();
- self.on_value_changed();
- var real_set_value = function(rval) {
- self.value = rval;
- self.$element.find('a')
- .unbind('click')
- .text(rval ? rval[1] : '')
- .click(function () {
- self.do_action({
- type: 'ir.actions.act_window',
- res_model: self.field.relation,
- res_id: self.value[0],
- context: self.build_context(),
- views: [[false, 'form']],
- target: 'current'
- });
- return false;
- });
- };
- if (value && !(value instanceof Array)) {
- new openerp.web.DataSetStatic(
- this, this.field.relation, self.build_context())
- .name_get([value], function(data) {
- real_set_value(data[0]);
- });
- } else {
- setTimeout(function() {real_set_value(value);}, 0);
- }
- },
- get_value: function() {
- if (!this.value) {
- return false;
- } else if (this.value instanceof Array) {
- return this.value[0];
- } else {
- return this.value;
- }
- }
-});
/**
* Registry of form widgets, called by :js:`openerp.web.FormView`
@@ -3201,30 +3071,6 @@ openerp.web.form.widgets = new openerp.web.Registry({
'statusbar': 'openerp.web.form.FieldStatus'
});
-openerp.web.form.FieldMany2ManyReadonly = openerp.web.form.FieldMany2Many.extend({
- force_readonly: true
-});
-openerp.web.form.FieldOne2ManyReadonly = openerp.web.form.FieldOne2Many.extend({
- force_readonly: true
-});
-openerp.web.form.readonly = openerp.web.form.widgets.clone({
- 'char': 'openerp.web.form.FieldCharReadonly',
- 'email': 'openerp.web.form.FieldEmailReadonly',
- 'url': 'openerp.web.form.FieldUrlReadonly',
- 'text': 'openerp.web.form.FieldCharReadonly',
- 'text_wiki' : 'openerp.web.form.FieldCharReadonly',
- 'date': 'openerp.web.form.FieldCharReadonly',
- 'datetime': 'openerp.web.form.FieldCharReadonly',
- 'selection' : 'openerp.web.form.FieldSelectionReadonly',
- 'many2one': 'openerp.web.form.FieldMany2OneReadonly',
- 'many2many' : 'openerp.web.form.FieldMany2ManyReadonly',
- 'one2many' : 'openerp.web.form.FieldOne2ManyReadonly',
- 'one2many_list' : 'openerp.web.form.FieldOne2ManyReadonly',
- 'boolean': 'openerp.web.form.FieldBooleanReadonly',
- 'float': 'openerp.web.form.FieldCharReadonly',
- 'integer': 'openerp.web.form.FieldCharReadonly',
- 'float_time': 'openerp.web.form.FieldCharReadonly'
-});
};
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 728b090d679..f76eec7d178 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -388,10 +388,10 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
* new record.
*
* @param {Number|void} index the record index (in the current dataset) to switch to
- * @param {String} [view="form"] the view type to switch to
+ * @param {String} [view="page"] the view type to switch to
*/
select_record:function (index, view) {
- view = view || 'form';
+ view = view || index == null ? 'form' : 'page';
this.dataset.index = index;
_.delay(_.bind(function () {
this.do_switch_view(view);
@@ -462,6 +462,7 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
* @param {Object} results results of evaluating domain and process for a search
*/
do_search: function (domain, context, group_by) {
+ this.page = 0;
this.groups.datagroup = new openerp.web.DataGroup(
this, this.model, domain, context, group_by);
this.groups.datagroup.sort = this.dataset._sort;
@@ -661,8 +662,8 @@ openerp.web.ListView = openerp.web.View.extend( /** @lends openerp.web.ListView#
*
* @param {Number} count number of columns to add
* @param {Object} options
- * @param {"before"|"after"} [position="after"] insertion position for the new columns
- * @param {Object} [except] content row to not pad
+ * @param {"before"|"after"} [options.position="after"] insertion position for the new columns
+ * @param {Object} [options.except] content row to not pad
*/
pad_columns: function (count, options) {
options = options || {};
@@ -1191,7 +1192,7 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
} else if (column.type === 'float') {
format = "%.2f";
}
- $('<td>')
+ $('<td class="oe-number">')
.text(_.str.sprintf(format, value))
.appendTo($row);
} else {
@@ -1280,10 +1281,15 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
items: '> tr[data-id]',
stop: function (event, ui) {
var to_move = list.records.get(ui.item.data('id')),
- target_id = ui.item.prev().data('id');
+ target_id = ui.item.prev().data('id'),
+ from_index = list.records.indexOf(to_move),
+ target = list.records.get(target_id);
+ if (list.records.at(from_index - 1) == target) {
+ return;
+ }
list.records.remove(to_move);
- var to = target_id ? list.records.indexOf(list.records.get(target_id)) + 1 : 0;
+ var to = target_id ? list.records.indexOf(target) + 1 : 0;
list.records.add(to_move, { at: to });
// resequencing time!
@@ -1295,7 +1301,14 @@ openerp.web.ListView.Groups = openerp.web.Class.extend( /** @lends openerp.web.L
// write are independent from one another, so we can just
// launch them all at the same time and we don't really
// give a fig about when they're done
- dataset.write(record.get('id'), {sequence: seq});
+ // FIXME: breaks on o2ms (e.g. Accounting > Financial
+ // Accounting > Taxes > Taxes, child tax accounts)
+ // when synchronous (without setTimeout)
+ (function (dataset, id, seq) {
+ setTimeout(function () {
+ dataset.write(id, {sequence: seq});
+ }, 0);
+ }(dataset, record.get('id'), seq));
record.set('sequence', seq);
}
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index dba0a1abba4..b2edf55b314 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -5,6 +5,7 @@
openerp.web.list_editable = function (openerp) {
var KEY_RETURN = 13,
KEY_ESCAPE = 27;
+ var QWeb = openerp.web.qweb;
// editability status of list rows
openerp.web.ListView.prototype.defaults.editable = null;
@@ -165,6 +166,35 @@ openerp.web.list_editable = function (openerp) {
view.arch.attrs.col = 2 * view.arch.children.length;
return view;
},
+ on_row_keyup: function (e) {
+ var self = this;
+ switch (e.which) {
+ case KEY_RETURN:
+ this.save_row().then(function (result) {
+ if (result.created) {
+ self.new_record();
+ return;
+ }
+
+ var next_record_id,
+ next_record = self.records.at(
+ self.records.indexOf(result.edited_record) + 1);
+ if (next_record) {
+ next_record_id = next_record.get('id');
+ self.dataset.index = _(self.dataset.ids)
+ .indexOf(next_record_id);
+ } else {
+ self.dataset.index = 0;
+ next_record_id = self.records.at(0).get('id');
+ }
+ self.edit_record(next_record_id);
+ });
+ break;
+ case KEY_ESCAPE:
+ this.cancel_edition();
+ break;
+ }
+ },
render_row_as_form: function (row) {
var self = this;
this.cancel_pending_edition().then(function () {
@@ -178,24 +208,10 @@ openerp.web.list_editable = function (openerp) {
.delegate('button.oe-edit-row-save', 'click', function () {
self.save_row();
})
- .delegate('button.oe-edit-row-cancel', 'click', function () {
- self.cancel_edition();
- })
.delegate('button', 'keyup', function (e) {
e.stopImmediatePropagation();
})
- .keyup(function (e) {
- switch (e.which) {
- case KEY_RETURN:
- self.save_row(true);
- break;
- case KEY_ESCAPE:
- self.cancel_edition();
- break;
- default:
- return;
- }
- });
+ .keyup($.proxy(self, 'on_row_keyup'));
if (row) {
$new_row.replaceAll(row);
} else if (self.options.editable) {
@@ -230,20 +246,18 @@ openerp.web.list_editable = function (openerp) {
.addClass('oe-field-cell')
.removeAttr('width')
.end()
- .find('td:first').removeClass('oe-field-cell').end()
.find('td:last').removeClass('oe-field-cell').end();
+ if (self.options.selectable) {
+ $new_row.prepend('<td>');
+ }
// pad in case of groupby
_(self.columns).each(function (column) {
if (column.meta) {
$new_row.prepend('<td>');
}
});
- // Add columns for the cancel and save buttons, if
- // there are none in the list
- if (!self.options.selectable) {
- self.view.pad_columns(
- 1, {except: $new_row, position: 'before'});
- }
+ // Add column for the save, if
+ // there is none in the list
if (!self.options.deletable) {
self.view.pad_columns(
1, {except: $new_row});
@@ -273,53 +287,43 @@ openerp.web.list_editable = function (openerp) {
});
},
/**
- * Saves the current row, and triggers the edition of its following
- * sibling if asked.
+ * Saves the current row, and returns a Deferred resolving to an object
+ * with the following properties:
*
- * @param {Boolean} [edit_next=false] should the next row become editable
- * @returns {$.Deferred}
+ * ``created``
+ * Boolean flag indicating whether the record saved was being created
+ * (``true`` or edited (``false``)
+ * ``edited_record``
+ * The result of saving the record (either the newly created record,
+ * or the post-edition record), after insertion in the Collection if
+ * needs be.
+ *
+ * @returns {$.Deferred<{created: Boolean, edited_record: Record}>}
*/
- save_row: function (edit_next) {
+ save_row: function () {
//noinspection JSPotentiallyInvalidConstructorUsage
var self = this, done = $.Deferred();
- this.edition_form.do_save(function (result) {
- if (result.created && !self.edition_id) {
- self.records.add({id: result.result},
- {at: self.options.editable === 'top' ? 0 : null});
- self.edition_id = result.result;
- }
- var edited_record = self.records.get(self.edition_id),
- next_record = self.records.at(
- self.records.indexOf(edited_record) + 1);
+ return this.edition_form
+ .do_save(null, this.options.editable === 'top')
+ .pipe(function (result) {
+ if (result.created && !self.edition_id) {
+ self.records.add({id: result.result},
+ {at: self.options.editable === 'top' ? 0 : null});
+ self.edition_id = result.result;
+ }
+ var edited_record = self.records.get(self.edition_id);
- $.when(
- self.handle_onwrite(self.edition_id),
- self.cancel_pending_edition().then(function () {
- $(self).trigger('saved', [self.dataset]);
- if (!edit_next) {
- return;
- }
- if (result.created) {
- self.new_record();
- return;
- }
- var next_record_id;
- if (next_record) {
- next_record_id = next_record.get('id');
- self.dataset.index = _(self.dataset.ids)
- .indexOf(next_record_id);
- } else {
- self.dataset.index = 0;
- next_record_id = self.records.at(0).get('id');
- }
- self.edit_record(next_record_id);
- })).then(function () {
- done.resolve();
- });
- }, this.options.editable === 'top').fail(function () {
- done.reject();
- });
- return done.promise();
+ return $.when(
+ self.handle_onwrite(self.edition_id),
+ self.cancel_pending_edition().then(function () {
+ $(self).trigger('saved', [self.dataset]);
+ })).pipe(function () {
+ return {
+ created: result.created || false,
+ edited_record: edited_record
+ };
+ }, null);
+ }, null);
},
/**
* If the current list is being edited, ensures it's saved
@@ -350,6 +354,19 @@ openerp.web.list_editable = function (openerp) {
new_record: function () {
this.dataset.index = null;
this.render_row_as_form();
+ },
+ render_record: function (record) {
+ var index = this.records.indexOf(record);
+ // FIXME: context dict should probably be extracted cleanly
+ return QWeb.render('ListView.row', {
+ columns: this.columns,
+ options: this.options,
+ record: record,
+ row_parity: (index % 2 === 0) ? 'even' : 'odd',
+ view: this.view,
+ render_cell: $.proxy(this, 'render_cell'),
+ edited: !!this.edition_form
+ });
}
});
if (!openerp.web.list) {
diff --git a/addons/web/static/src/js/view_page.js b/addons/web/static/src/js/view_page.js
new file mode 100644
index 00000000000..2ca07152a56
--- /dev/null
+++ b/addons/web/static/src/js/view_page.js
@@ -0,0 +1,218 @@
+openerp.web.page = function (openerp) {
+ var _t = openerp.web._t;
+ var QWeb = openerp.web.qweb;
+
+ openerp.web.views.add('page', 'openerp.web.PageView');
+ openerp.web.PageView = openerp.web.FormView.extend({
+ form_template: "PageView",
+ init: function () {
+ this._super.apply(this, arguments);
+ this.registry = openerp.web.page.readonly;
+ },
+ on_loaded: function(data) {
+ this._super(data);
+ this.$form_header.find('button.oe_form_button_edit').click(this.on_button_edit);
+ this.$form_header.find('button.oe_form_button_create').click(this.on_button_create);
+ this.$form_header.find('button.oe_form_button_duplicate').click(this.on_button_duplicate);
+ this.$form_header.find('button.oe_form_button_delete').click(this.on_button_delete);
+ },
+ on_button_edit: function() {
+ return this.do_switch_view('form');
+ },
+ on_button_create: function() {
+ this.dataset.index = null;
+ return this.do_switch_view('form');
+ },
+ on_button_duplicate: function() {
+ var self = this;
+ var def = $.Deferred();
+ $.when(this.has_been_loaded).then(function() {
+ self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
+ return self.on_created({ result : new_id });
+ }).then(function() {
+ return self.do_switch_view('form');
+ }).then(function() {
+ def.resolve();
+ });
+ });
+ return def.promise();
+ },
+ on_button_delete: function() {
+ var self = this;
+ var def = $.Deferred();
+ $.when(this.has_been_loaded).then(function() {
+ if (self.datarecord.id && confirm(_t("Do you really want to delete this record?"))) {
+ self.dataset.unlink([self.datarecord.id]).then(function() {
+ self.on_pager_action('next');
+ def.resolve();
+ });
+ } else {
+ setTimeout(function () {
+ def.reject();
+ }, 0)
+ }
+ });
+ return def.promise();
+ }
+ });
+
+ /** @namespace */
+ openerp.web.page = {};
+
+ openerp.web.page.FieldReadonly = openerp.web.form.Field.extend({
+
+ });
+ openerp.web.page.FieldCharReadonly = openerp.web.page.FieldReadonly.extend({
+ template: 'FieldChar.readonly',
+ init: function(view, node) {
+ this._super(view, node);
+ this.password = this.node.attrs.password === 'True' || this.node.attrs.password === '1';
+ },
+ set_value: function (value) {
+ this._super.apply(this, arguments);
+ var show_value = openerp.web.format_value(value, this, '');
+ if (this.password) {
+ show_value = new Array(show_value.length + 1).join('*');
+ }
+ this.$element.find('div').text(show_value);
+ return show_value;
+ }
+ });
+ openerp.web.page.FieldURIReadonly = openerp.web.page.FieldCharReadonly.extend({
+ template: 'FieldURI.readonly',
+ scheme: null,
+ set_value: function (value) {
+ var displayed = this._super.apply(this, arguments);
+ this.$element.find('a')
+ .attr('href', this.scheme + ':' + displayed)
+ .text(displayed);
+ }
+ });
+ openerp.web.page.FieldEmailReadonly = openerp.web.page.FieldURIReadonly.extend({
+ scheme: 'mailto'
+ });
+ openerp.web.page.FieldUrlReadonly = openerp.web.page.FieldURIReadonly.extend({
+ set_value: function (value) {
+ var s = /(\w+):(.+)/.exec(value);
+ if (!s || !(s[1] === 'http' || s[1] === 'https')) { return; }
+ this.scheme = s[1];
+ this._super(s[2]);
+ }
+ });
+ openerp.web.page.FieldBooleanReadonly = openerp.web.page.FieldCharReadonly.extend({
+ set_value: function (value) {
+ this._super(value ? '\u2611' : '\u2610');
+ }
+ });
+ openerp.web.page.FieldSelectionReadonly = openerp.web.page.FieldReadonly.extend({
+ template: 'FieldChar.readonly',
+ init: function(view, node) {
+ // lifted straight from r/w version
+ var self = this;
+ this._super(view, node);
+ this.values = _.clone(this.field.selection);
+ _.each(this.values, function(v, i) {
+ if (v[0] === false && v[1] === '') {
+ self.values.splice(i, 1);
+ }
+ });
+ this.values.unshift([false, '']);
+ },
+ set_value: function (value) {
+ value = value === null ? false : value;
+ value = value instanceof Array ? value[0] : value;
+ var option = _(this.values)
+ .detect(function (record) { return record[0] === value; });
+ this._super(value);
+ this.$element.find('div').text(option ? option[1] : this.values[0][1]);
+ }
+ });
+ openerp.web.page.FieldMany2OneReadonly = openerp.web.page.FieldURIReadonly.extend({
+ set_value: function (value) {
+ value = value || null;
+ this.invalid = false;
+ var self = this;
+ this.value = value;
+ self.update_dom();
+ self.on_value_changed();
+ var real_set_value = function(rval) {
+ self.value = rval;
+ self.$element.find('a')
+ .unbind('click')
+ .text(rval ? rval[1] : '')
+ .click(function () {
+ self.do_action({
+ type: 'ir.actions.act_window',
+ res_model: self.field.relation,
+ res_id: self.value[0],
+ context: self.build_context(),
+ views: [[false, 'page'], [false, 'form']],
+ target: 'current'
+ });
+ return false;
+ });
+ };
+ if (value && !(value instanceof Array)) {
+ new openerp.web.DataSetStatic(
+ this, this.field.relation, self.build_context())
+ .name_get([value], function(data) {
+ real_set_value(data[0]);
+ });
+ } else {
+ setTimeout(function() {real_set_value(value);}, 0);
+ }
+ },
+ get_value: function() {
+ if (!this.value) {
+ return false;
+ } else if (this.value instanceof Array) {
+ return this.value[0];
+ } else {
+ return this.value;
+ }
+ }
+ });
+ openerp.web.page.FieldReferenceReadonly = openerp.web.page.FieldMany2OneReadonly.extend({
+ set_value: function (value) {
+ if (!value) {
+ return this._super(null);
+ }
+ var reference = value.split(',');
+ this.field.relation = reference[0];
+ var id = parseInt(reference[1], 10);
+ return this._super(id);
+ },
+ get_value: function () {
+ if (!this.value) {
+ return null;
+ }
+ return _.str.sprintf('%s,%d', this.field.relation, this.value[0]);
+ }
+ });
+
+ openerp.web.page.FieldMany2ManyReadonly = openerp.web.form.FieldMany2Many.extend({
+ force_readonly: true
+ });
+ openerp.web.page.FieldOne2ManyReadonly = openerp.web.form.FieldOne2Many.extend({
+ force_readonly: true
+ });
+ openerp.web.page.readonly = openerp.web.form.widgets.clone({
+ 'char': 'openerp.web.page.FieldCharReadonly',
+ 'email': 'openerp.web.page.FieldEmailReadonly',
+ 'url': 'openerp.web.page.FieldUrlReadonly',
+ 'text': 'openerp.web.page.FieldCharReadonly',
+ 'text_wiki' : 'openerp.web.page.FieldCharReadonly',
+ 'date': 'openerp.web.page.FieldCharReadonly',
+ 'datetime': 'openerp.web.page.FieldCharReadonly',
+ 'selection' : 'openerp.web.page.FieldSelectionReadonly',
+ 'many2one': 'openerp.web.page.FieldMany2OneReadonly',
+ 'many2many' : 'openerp.web.page.FieldMany2ManyReadonly',
+ 'one2many' : 'openerp.web.page.FieldOne2ManyReadonly',
+ 'one2many_list' : 'openerp.web.page.FieldOne2ManyReadonly',
+ 'reference': 'openerp.web.page.FieldReferenceReadonly',
+ 'boolean': 'openerp.web.page.FieldBooleanReadonly',
+ 'float': 'openerp.web.page.FieldCharReadonly',
+ 'integer': 'openerp.web.page.FieldCharReadonly',
+ 'float_time': 'openerp.web.page.FieldCharReadonly'
+ });
+};
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index 5a26ef58b03..f583dd259e7 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -75,6 +75,10 @@ session.web.ActionManager = session.web.Widget.extend({
}
},
do_action: function(action, on_close) {
+ if (!action.type) {
+ console.error("No type for action", action);
+ return;
+ }
var type = action.type.replace(/\./g,'_');
var popup = action.target === 'new';
action.flags = _.extend({
@@ -85,12 +89,24 @@ session.web.ActionManager = session.web.Widget.extend({
pager : !popup
}, action.flags || {});
if (!(type in this)) {
- console.log("Action manager can't handle action of type " + action.type, action);
+ console.error("Action manager can't handle action of type " + action.type, action);
return;
}
return this[type](action, on_close);
},
+ null_action: function() {
+ this.dialog_stop();
+ this.content_stop();
+ },
ir_actions_act_window: function (action, on_close) {
+ if (_(['base.module.upgrade', 'base.setup.installer'])
+ .contains(action.res_model)) {
+ var old_close = on_close;
+ on_close = function () {
+ session.webclient.do_reload();
+ if (old_close) { old_close(); }
+ };
+ }
if (action.target === 'new') {
if (this.dialog == null) {
this.dialog = new session.web.Dialog(this, { title: action.name, width: '80%' });
@@ -121,12 +137,6 @@ session.web.ActionManager = session.web.Widget.extend({
if (!this.dialog && on_closed) {
on_closed();
}
- if (this.dialog && action.context) {
- var model = action.context.active_model;
- if (model === 'base.module.upgrade' || model === 'base.setup.installer' || model === 'base.module.upgrade') {
- session.webclient.do_reload();
- }
- }
this.dialog_stop();
},
ir_actions_server: function (action, on_closed) {
@@ -186,12 +196,12 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
this.model = dataset ? dataset.model : undefined;
this.dataset = dataset;
this.searchview = null;
- this.last_search = false;
this.active_view = null;
this.views_src = _.map(views, function(x) {return x instanceof Array? {view_id: x[0], view_type: x[1]} : x;});
this.views = {};
this.flags = this.flags || {};
this.registry = session.web.views;
+ this.views_history = [];
},
render: function() {
return session.web.qweb.render(this.template, {
@@ -211,6 +221,7 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
var views_ids = {};
_.each(this.views_src, function(view) {
self.views[view.view_type] = $.extend({}, view, {
+ deferred : $.Deferred(),
controller : null,
options : _.extend({
sidebar_id : self.element_id + '_sidebar_' + view.view_type,
@@ -230,11 +241,15 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
* Asks the view manager to switch visualization mode.
*
* @param {String} view_type type of view to display
+ * @param {Boolean} [no_store=false] don't store the view being switched to on the switch stack
* @returns {jQuery.Deferred} new view loading promise
*/
- on_mode_switch: function(view_type) {
+ on_mode_switch: function(view_type, no_store) {
var self = this,
view_promise;
+ if (!no_store) {
+ this.views_history.push(view_type);
+ }
this.active_view = view_type;
var view = this.views[view_type];
if (!view.controller) {
@@ -245,17 +260,19 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
controller.set_embedded_view(view.embedded_view);
}
controller.do_switch_view.add_last(this.on_mode_switch);
+ controller.do_prev_view.add_last(this.on_prev_view);
var container = $("#" + this.element_id + '_view_' + view_type);
view_promise = controller.appendTo(container);
this.views[view_type].controller = controller;
+ this.views[view_type].deferred.resolve();
$.when(view_promise).then(function() {
self.on_controller_inited(view_type, controller);
if (self.searchview && view.controller.searchable !== false) {
- self.do_searchview_search();
+ self.searchview.ready.then(self.searchview.do_search);
}
});
} else if (this.searchview && view.controller.searchable !== false) {
- self.do_searchview_search();
+ this.searchview.ready.then(this.searchview.do_search);
}
if (this.searchview) {
@@ -263,7 +280,7 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
}
this.$element
- .find('.views-switchers button').removeAttr('disabled')
+ .find('.oe_vm_switch button').removeAttr('disabled')
.filter('[data-view-type="' + view_type + '"]')
.attr('disabled', true);
@@ -278,12 +295,30 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
}
}
$.when(view_promise).then(function () {
- self.$element.find('.oe_view_title:first').text(
+ self.$element.find('.oe_view_title_text:first').text(
self.display_title());
});
return view_promise;
},
/**
+ * Returns to the view preceding the caller view in this manager's
+ * navigation history (the navigation history is appended to via
+ * on_mode_switch)
+ *
+ * @param {Boolean} [created=false] returning from a creation
+ * @returns {$.Deferred} switching end signal
+ */
+ on_prev_view: function (created) {
+ var current_view = this.views_history.pop();
+ var previous_view = this.views_history[this.views_history.length - 1];
+ // APR special case: "If creation mode from list (and only from a list),
+ // after saving, go to page view (don't come back in list)"
+ if (created && current_view === 'form' && previous_view === 'list') {
+ return this.on_mode_switch('page');
+ }
+ return this.on_mode_switch(previous_view, true);
+ },
+ /**
* Sets up the current viewmanager's search view.
*
* @param {Number|false} view_id the view to use or false for a default one
@@ -304,20 +339,15 @@ session.web.ViewManager = session.web.Widget.extend(/** @lends session.web.View
do_searchview_search: function(domains, contexts, groupbys) {
var self = this,
controller = this.views[this.active_view].controller;
- if (domains || contexts) {
- this.rpc('/web/session/eval_domain_and_context', {
- domains: [this.action.domain || []].concat(domains || []),
- contexts: [this.action.context || {}].concat(contexts || []),
- group_by_seq: groupbys || []
- }, function (results) {
- self.dataset.context = results.context;
- self.dataset.domain = results.domain;
- self.last_search = [results.domain, results.context, results.group_by];
- controller.do_search(results.domain, results.context, results.group_by);
- });
- } else if (this.last_search) {
- controller.do_search.apply(controller, this.last_search);
- }
+ this.rpc('/web/session/eval_domain_and_context', {
+ domains: [this.action.domain || []].concat(domains || []),
+ contexts: [this.action.context || {}].concat(contexts || []),
+ group_by_seq: groupbys || []
+ }, function (results) {
+ self.dataset.context = results.context;
+ self.dataset.domain = results.domain;
+ controller.do_search(results.domain, results.context, results.group_by);
+ });
},
/**
* Event launched when a controller has been inited.
@@ -375,10 +405,16 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
}
this.dataset = dataset;
this.flags = this.action.flags || {};
- if (action.res_model == 'board.board' && action.views.length == 1 && action.views) {
- // Not elegant but allows to avoid form chrome (pager, save/new
- // buttons, sidebar, ...) displaying
- this.flags.search_view = this.flags.pager = this.flags.sidebar = this.flags.action_buttons = false;
+ if (action.res_model == 'board.board' && action.view_mode === 'form') {
+ // Special case for Dashboards
+ _.extend(this.flags, {
+ views_switcher : false,
+ display_title : false,
+ search_view : false,
+ pager : false,
+ sidebar : false,
+ action_buttons : false
+ });
}
// setup storage for session-wise menu hiding
@@ -411,21 +447,18 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
var main_view_loaded = this._super();
var manager_ready = $.when(searchview_loaded, main_view_loaded);
- if (searchview_loaded && this.action['auto_search'] !== false) {
- // schedule auto_search
- manager_ready.then(this.searchview.do_search);
- }
this.$element.find('.oe_get_xml_view').click(function () {
- // TODO: add search view?
- $('<pre>').text(session.web.json_node_to_xml(
- self.views[self.active_view].controller.fields_view.arch, true))
- .dialog({ width: '95%'});
+ var view = self.views[self.active_view].controller,
+ view_id = view.fields_view.view_id;
+ if (view_id) {
+ view.on_sidebar_edit_resource('ir.ui.view', view_id);
+ }
});
if (this.action.help && !this.flags.low_profile) {
var Users = new session.web.DataSet(self, 'res.users'),
- header = this.$element.find('.oe-view-manager-header');
- header.delegate('blockquote button', 'click', function() {
+ $tips = this.$element.find('.oe_view_manager_menu_tips');
+ $tips.delegate('blockquote button', 'click', function() {
var $this = $(this);
//noinspection FallthroughInSwitchStatementJS
switch ($this.attr('name')) {
@@ -442,7 +475,7 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
if (!(user && user.id === self.session.uid)) {
return;
}
- header.find('blockquote').toggle(user.menu_tips);
+ $tips.find('blockquote').toggle(user.menu_tips);
});
}
}
@@ -459,10 +492,15 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
return manager_ready;
},
- on_mode_switch: function (view_type) {
+ on_mode_switch: function (view_type, no_store) {
var self = this;
+ var switched = $.when(this._super(view_type, no_store)).then(function () {
+ self.$element.find('.oe-view-manager-logs:first')
+ .addClass('oe-folded').removeClass('oe-has-more')
+ .find('ul').empty();
+ });
return $.when(
- this._super(view_type),
+ switched,
this.shortcut_check(this.views[view_type])
).then(function() {
var controller = self.views[self.active_view].controller,
@@ -470,10 +508,10 @@ session.web.ViewManagerAction = session.web.ViewManager.extend(/** @lends oepner
view_id = (fvg && fvg.view_id) || '--';
self.$element.find('.oe_get_xml_view span').text(view_id);
if (!self.action.name && fvg) {
- self.$element.find('.oe_view_title').text(fvg.arch.attrs.string || fvg.name);
+ self.$element.find('.oe_view_title_text').text(fvg.arch.attrs.string || fvg.name);
}
- var $title = self.$element.find('.oe_view_title'),
+ var $title = self.$element.find('.oe_view_title_text'),
$search_prefix = $title.find('span.oe_searchable_view');
if (controller.searchable !== false) {
if (!$search_prefix.length) {
@@ -575,25 +613,29 @@ session.web.Sidebar = session.web.Widget.extend({
});
},
add_default_sections: function() {
+ var self = this,
+ view = this.widget_parent,
+ view_manager = view.widget_parent,
+ action = view_manager.action;
if (this.session.uid === 1) {
this.add_section(_t('Customize'), 'customize');
this.add_items('customize', [
{
label: _t("Manage Views"),
- callback: this.widget_parent.on_sidebar_manage_views,
+ callback: view.on_sidebar_manage_views,
title: _t("Manage views of the current object")
}, {
label: _t("Edit Workflow"),
- callback: this.widget_parent.on_sidebar_edit_workflow,
+ callback: view.on_sidebar_edit_workflow,
title: _t("Manage views of the current object"),
classname: 'oe_hide oe_sidebar_edit_workflow'
}, {
label: _t("Customize Object"),
- callback: this.widget_parent.on_sidebar_customize_object,
+ callback: view.on_sidebar_customize_object,
title: _t("Manage views of the current object")
}, {
label: _t("Translate"),
- callback: this.widget_parent.on_sidebar_translate,
+ callback: view.on_sidebar_translate,
title: _t("Technical translation")
}
]);
@@ -603,16 +645,36 @@ session.web.Sidebar = session.web.Widget.extend({
this.add_items('other', [
{
label: _t("Import"),
- callback: this.widget_parent.on_sidebar_import
+ callback: view.on_sidebar_import
}, {
label: _t("Export"),
- callback: this.widget_parent.on_sidebar_export
+ callback: view.on_sidebar_export
}, {
label: _t("View Log"),
- callback: this.widget_parent.on_sidebar_view_log,
+ callback: view.on_sidebar_view_log,
classname: 'oe_hide oe_sidebar_view_log'
}
]);
+
+ if (session.connection.debug) {
+ this.add_section("Debug", 'debug');
+ if (action && action.id) {
+ this.add_items('debug', [{
+ label: "Edit Action",
+ callback: function() {
+ view.on_sidebar_edit_resource(action.type, action.id);
+ }
+ }]);
+ }
+ if (view_manager.searchview && view_manager.searchview.view_id) {
+ this.add_items('debug', [{
+ label: "Edit SearchView",
+ callback: function() {
+ view.on_sidebar_edit_resource('ir.ui.view', view_manager.searchview.view_id);
+ }
+ }]);
+ }
+ }
},
add_toolbar: function(toolbar) {
@@ -915,7 +977,19 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
if (action_data.special) {
return handler({result: {"type":"ir.actions.act_window_close"}});
} else if (action_data.type=="object") {
- return dataset.call_button(action_data.name, [[record_id], context], handler);
+ var args = [[record_id]], additional_args = [];
+ if (action_data.args) {
+ try {
+ // Warning: quotes and double quotes problem due to json and xml clash
+ // Maybe we should force escaping in xml or do a better parse of the args array
+ additional_args = JSON.parse(action_data.args.replace(/'/g, '"'));
+ args = args.concat(additional_args);
+ } catch(e) {
+ console.error("Could not JSON.parse arguments", action_data.args);
+ }
+ }
+ args.push(context);
+ return dataset.call_button(action_data.name, args, handler);
} else if (action_data.type=="action") {
return this.rpc('/web/action/load', { action_id: parseInt(action_data.name, 10), context: context, do_not_eval: true}, handler);
} else {
@@ -933,8 +1007,16 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
this.embedded_view = embedded_view;
this.options.sidebar = false;
},
- do_switch_view: function(view) {
- },
+ /**
+ * Switches to a specific view type
+ *
+ * @param {String} view view type to switch to
+ */
+ do_switch_view: function(view) { },
+ /**
+ * Cancels the switch to the current view, switches to the previous one
+ */
+ do_prev_view: function () { },
do_search: function(view) {
},
@@ -953,7 +1035,14 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
console.log('Todo');
},
on_sidebar_customize_object: function() {
- console.log('Todo');
+ var self = this;
+ this.rpc('/web/dataset/search_read', {
+ model: 'ir.model',
+ fields: ['id'],
+ domain: [['model', '=', self.dataset.model]]
+ }, function (result) {
+ self.on_sidebar_edit_resource('ir.model', result.ids[0]);
+ });
},
on_sidebar_import: function() {
var import_view = new session.web.DataImport(this, this.dataset);
@@ -969,11 +1058,29 @@ session.web.View = session.web.Widget.extend(/** @lends session.web.View# */{
domain : [['type', '!=', 'object'], '|', ['name', '=', this.dataset.model], ['name', 'ilike', this.dataset.model + ',']],
views: [[false, 'list'], [false, 'form']],
type : 'ir.actions.act_window',
- auto_search : true,
view_type : "list",
view_mode : "list"
});
},
+ on_sidebar_edit_resource: function(model, id, domain) {
+ var action = {
+ res_model : model,
+ type : 'ir.actions.act_window',
+ view_type : 'form',
+ view_mode : 'form',
+ target : 'new',
+ flags : {}
+ }
+ if (id) {
+ action.res_id = id,
+ action.views = [[false, 'form']];
+ } else if (domain) {
+ action.views = [[false, 'list'], [false, 'form']];
+ action.domain = domain;
+ action.flags.views_switcher = true;
+ }
+ this.do_action(action);
+ },
on_sidebar_view_log: function() {
},
sidebar_context: function () {
diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml
index 24defe23e2e..393cb46143c 100644
--- a/addons/web/static/src/xml/base.xml
+++ b/addons/web/static/src/xml/base.xml
@@ -414,11 +414,12 @@
</t>
<t t-name="ViewManager">
<table class="view-manager-main-table">
+ <tbody>
<tr>
<td class="view-manager-main-content">
<div class="oe-view-manager-header">
<h2 class="oe_view_title" t-if="self.flags.display_title !== false">
- <t t-esc="self.display_title()"/>
+ <span class="oe_view_title_text"><t t-esc="self.display_title()"/></span>
</h2>
<div class="oe_vm_switch">
<t t-if="views.length != 1" t-foreach="views" t-as="view">
@@ -439,22 +440,31 @@
</t>
</td>
</tr>
+ </tbody>
</table>
</t>
<t t-extend="ViewManager" t-name="ViewManagerAction">
- <t t-jquery=".oe-view-manager-header" t-operation="prepend">
- <blockquote t-if="self.action.help and !self.flags.low_profile
- and !(self.action.id in self.session.hidden_menutips)">
- <p><t t-esc="self.action.help"/></p>
- <div>
- <button type="button" name="hide">Hide this tip</button>
- <button type="button" name="disable">Disable all tips</button>
- </div>
- </blockquote>
- <a class="oe-shortcut-toggle" title="Add / Remove Shortcut..."
- href="javascript: void(0)"> </a>
- <button t-if="self.session.debug" class="oe_get_xml_view">
+ <t t-jquery=".view-manager-main-table tbody" t-operation="prepend">
+ <tr>
+ <td class="oe_view_manager_menu_tips" colspan="2">
+ <blockquote t-if="self.action.help and !self.flags.low_profile
+ and !(self.action.id in self.session.hidden_menutips)">
+ <p><t t-esc="self.action.help"/></p>
+ <div>
+ <button type="button" name="hide">Hide this tip</button>
+ <button type="button" name="disable">Disable all tips</button>
+ </div>
+ </blockquote>
+ </td>
+ </tr>
+ </t>
+ <t t-jquery="h2.oe_view_title" t-operation="prepend">
+ <a t-if="self.flags.display_title !== false" class="oe-shortcut-toggle" title="Add / Remove Shortcut..."
+ href="javascript: void(0)"> </a>
+ </t>
+ <t t-jquery="h2.oe_view_title" t-operation="after">
+ <button t-if="self.session.debug and self.flags.display_title !== false" class="oe_get_xml_view">
View#<span></span>
</button>
</t>
@@ -530,16 +540,17 @@
t-att-id="'treerow_' + record.id"
t-att-data-id="record.id" t-att-data-level="level + 1">
<t t-set="children" t-value="record[children_field]"/>
- <t t-set="has_children" t-value="children and children.length"/>
+ <t t-set="class" t-value="children and children.length ? 'treeview-tr' : 'treeview-td'"/>
<td t-foreach="fields_view" t-as="field"
t-if="!field.attrs.modifiers.tree_invisible"
t-att-data-id="record.id"
t-att-style="color_for(record) + (!field_index ? 'background-position: ' + 19*level + 'px; padding-left: ' + 19*level + 'px;' : '')"
- t-att-class="!field_index and has_children ? 'treeview-tr' : 'treeview-td'">
+ t-att-class="class">
<span t-if="!field.attrs.modifiers.invisible">
<t t-esc="render(record[field.attrs.name], fields[field.attrs.name])" />
</span>
+ <t t-set="class" t-value="'treeview-td'"/>
</td>
</tr>
@@ -625,18 +636,9 @@
</td>
</t>
- <t t-if="options.radio">
- <th t-if="options.selectable" class="oe-record-selector" width="1">
- <input type="radio" name ="radiogroup"/>
- </th>
- </t>
- <t t-if="!options.radio">
- <th t-if="options.selectable" class="oe-record-selector" width="1">
- <input type="checkbox"/>
- </th>
- </t>
-
-
+ <th t-if="options.selectable" class="oe-record-selector" width="1">
+ <input t-att-type="options.radio? 'radio': 'checkbox'" name ="radiogroup" t-att-checked="options.select_view_id == record.get('id')? true: null"/>
+ </th>
<t t-foreach="columns" t-as="column">
<t t-set="align" t-value="column.type === 'integer' or column.type == 'float'"/>
<td t-if="!column.meta and column.invisible !== '1'" t-att-title="column.help"
@@ -647,7 +649,7 @@
</td>
</t>
<td t-if="options.deletable" class='oe-record-delete' width="1">
- <button type="button" name="delete">♻</button>
+ <button type="button" name="delete"></button>
</td>
</tr>
<t t-name="ListView.row.form">
@@ -657,14 +659,8 @@
<t t-name="FormView">
<div class="oe_form_header">
<div class="oe_form_buttons" t-if="widget.options.action_buttons !== false">
- <button type="button" class="oe_form_button_save oe_form_on_editable">Save</button>
- <button type="button" class="oe_form_button_toggle">
- <span class="oe_form_on_editable">Cancel</span>
- <span class="oe_form_on_readonly">Edit</span>
- </button>
- <button type="button" class="oe_form_button_new oe_form_on_readonly">Create</button>
- <button type="button" class="oe_form_button_duplicate oe_form_on_readonly">Duplicate</button>
- <button type="button" class="oe_form_button_delete oe_form_on_readonly">Delete</button>
+ <button type="button" class="oe_form_button_save">Save</button>
+ <button type="button" class="oe_form_button_cancel">Cancel</button>
</div>
<div class="oe_form_pager" t-if="widget.options.pager !== false">
<button type="button" data-pager-action="first">First</button>
@@ -678,6 +674,14 @@
</div>
<t t-raw="frame.render()"/>
</t>
+<t t-name="PageView" t-extend="FormView">
+ <t t-jquery=".oe_form_buttons" t-operation="inner">
+ <button type="button" class="oe_form_button_edit">Edit</button>
+ <button type="button" class="oe_form_button_create">Create</button>
+ <button type="button" class="oe_form_button_duplicate">Duplicate</button>
+ <button type="button" class="oe_form_button_delete">Delete</button>
+ </t>
+</t>
<t t-name="FormView.sidebar.attachments">
<div class="oe-sidebar-attachments-toolbar">
<div class="oe-binary-file-set" style="float: right">
@@ -722,7 +726,6 @@
<t t-foreach="row" t-as="td">
<td t-att-colspan="td.colspan gt 1 ? td.colspan : undefined"
t-att-width="td.width"
- t-att-nowrap="td.nowrap or td.is_field_m2o? 'true' : undefined"
t-att-valign="td.table ? 'top' : undefined"
t-attf-class="oe_form_frame_cell #{td.classname} #{td.element_class}"
>
@@ -732,6 +735,11 @@
</tr>
</table>
</t>
+<t t-name="WidgetFrame.readonly" t-extend="WidgetFrame">
+ <t t-jquery="&gt;table">
+ this.attr('class', this.attr('class')+' oe_form_readonly');
+ </t>
+</t>
<t t-name="WidgetGroup">
<t t-if="widget.string">
<fieldset class="oe_group_box">
@@ -854,15 +862,15 @@
t-att-name="widget.name"
t-att-id="widget.element_id"
t-attf-class="field_#{widget.type} #{_(['integer', 'float', 'float_time']).contains(widget.type) ? 'oe-number' : ''}"
- t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
+ style="width: 100%"
/>
- <img class="oe_field_translate" t-if="widget.field.translate" t-att-src='widget.session.server + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
+ <img class="oe_field_translate oe_input_icon" t-if="widget.field.translate" t-att-src='widget.session.server + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
</t>
<t t-name="FieldChar.readonly">
<div
t-att-id="widget.element_id"
t-attf-class="field_#{widget.type} #{_(['integer', 'float', 'float_time']).contains(widget.type) ? 'oe-number' : ''}"
- t-attf-style="width: #{widget.field.translate ? '99' : '100'}%">
+ style="width: 100%">
</div>
</t>
<t t-name="FieldURI.readonly">
@@ -871,7 +879,7 @@
<t t-name="FieldEmail">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
- <td width="100%">
+ <td width="100%" style="position: relative">
<t t-call="FieldChar"/>
</td>
<td width="16">
@@ -885,7 +893,7 @@
<t t-name="FieldUrl">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
- <td width="100%">
+ <td width="100%" style="position: relative">
<t t-call="FieldChar"/>
</td>
<td width="16">
@@ -901,9 +909,9 @@
t-att-name="widget.name"
t-att-id="widget.element_id"
t-attf-class="field_#{widget.type}"
- t-attf-style="width: #{widget.field.translate ? '99' : '100'}%"
+ style="width: 100%"
></textarea>
- <img class="oe_field_translate" t-if="widget.field.translate" t-att-src='widget.session.server + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
+ <img class="oe_field_translate oe_input_icon" t-if="widget.field.translate" t-att-src='widget.session.server + "/web/static/src/img/icons/terp-translate.png"' width="16" height="16" border="0"/>
</t>
<t t-name="web.datetimepicker">
<div class="oe_datepicker_root">
@@ -1131,15 +1139,17 @@
</form>
</t>
<t t-name="SearchView.managed-filters">
- <option value="_filters">-- Filters --</option>
- <t t-set="i" t-value="0"/>
- <t t-foreach="filters" t-as="filter">
- <option t-att-value="'get:' + i"><t t-esc="filter.name"/></option>
- <t t-set="i" t-value="i+1"/>
- </t>
- <option value="_actions">-- Actions --</option>
- <option value="save_filter">Save Filter</option>
- <option value="manage_filters">Manage Filters</option>
+ <option/>
+ <optgroup label="-- Filters --">
+ <t t-foreach="filters" t-as="filter">
+ <option t-attf-value="get:#{filter_index}"><t t-esc="filter.name"/></option>
+ </t>
+ </optgroup>
+ <optgroup label="-- Actions --">
+ <option value="save_filter">Save Filter</option>
+ <option value="add_to_dashboard">Add to Dashboard</option>
+ <option value="manage_filters">Manage Filters</option>
+ </optgroup>
</t>
<t t-name="SearchView.managed-filters.add">
<div>
@@ -1148,6 +1158,16 @@
<p>(Any existing filter with the same name will be replaced)</p>
</div>
</t>
+<t t-name="SearchView.add_to_dashboard">
+ <div class="oe_forms">
+ <p><b>Select Dashboard to add this filter to:</b></p>
+ <select style="width: 100%; margin-right: 1em;">
+ <option t-foreach="dashboards" t-as="menu" t-att-value="menu.id" t-att-selected="(menu.id == selected_menu_id) || undefined"><t t-esc="menu.name"/></option>
+ </select>
+ <p><b>Title of new Dashboard item:</b></p>
+ <input type="text" style="width: 100%; margin-right: 1em;"/>
+ </div>
+</t>
<t t-name="SearchView.render_lines">
<table class="oe-searchview-render-line" border="0" cellspacing="0" cellpadding="0"
t-foreach="lines" t-as="line">
@@ -1369,6 +1389,18 @@
<button type="button" class="oe_formopenpopup-form-save">Save</button>
<button type="button" class="oe_formopenpopup-form-close">Cancel</button>
</t>
+<t t-extend="ListView.row">
+ <!-- adds front & back padding to row being rendered after edition, if
+ necessary (if not selectable add front padding and if not deletable
+ add back padding), otherwise the row being added is missing columns
+ -->
+ <t t-jquery="&gt; :first" t-operation="before">
+ <td t-if="edited and !options.selectable" class="oe-listview-padding"/>
+ </t>
+ <t t-jquery="&gt; :last" t-operation="after">
+ <td t-if="edited and !options.deletable" class="oe-listview-padding"/>
+ </t>
+</t>
<t t-name="ListView.row.frame" t-extend="WidgetFrame">
<t t-jquery="tr">
$(document.createElement('t'))
@@ -1380,10 +1412,8 @@
.replaceAll(this)
.after($(document.createElement('td')).append(
$(document.createElement('button')).attr({
- 'class': 'oe-edit-row-save', 'type': 'button'}).text('Save')))
- .before($(document.createElement('td')).append(
- $(document.createElement('button')).attr({
- 'class': 'oe-edit-row-cancel', 'type': 'button'}).text('Cancel')))
+ 'class': 'oe-edit-row-save', 'type': 'button'})
+ .html(' ')))
.unwrap();
</t>
</t>
@@ -1392,51 +1422,70 @@
<t t-call="view_editor.row"/>
</table>
</t>
-<tr t-name="view_editor.row" class="oe_view_editor_row" t-att-id="'viewedit-' + rec.id" t-att-level="rec.level" t-foreach="data" t-as="rec">
- <td class="oe_view_editor_colum" width="85%">
- <table class="oe_view_editor_tree_grid">
- <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='widget.session.server + "/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 align="left" class="oe_view_editor_colum" width="15%">
- <table width="100%">
- <tr>
- <td width="20%">
- <img t-if="rec.att_list.length"
- id="side-add" t-att-src='widget.session.server + "/web/static/src/img/icons/gtk-add.png"' style="cursor: pointer;"/>
- </td>
- <td width="20%">
- <img id="side-remove" t-att-src='widget.session.server + "/web/static/src/img/icons/gtk-remove.png"' style="cursor: pointer;"/>
- </td>
- <td width="20%">
- <img t-if="rec.att_list.length"
- id="side-edit" t-att-src='widget.session.server + "/web/static/src/img/icons/gtk-edit.png"' style="cursor: pointer;"/>
- </td>
- <td width="20%">
- <img t-if="rec.att_list.length"
- id="side-up" t-att-src='widget.session.server + "/web/static/src/img/icons/gtk-go-up.png"' style="cursor: pointer;"/>
- </td>
- <td width="20%">
- <img t-if="rec.att_list.length"
- id="side-down" t-att-src='widget.session.server + "/web/static/src/img/icons/gtk-go-down.png"' style="cursor: pointer;"/>
- </td>
- </tr>
- </table>
- </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-name="view_editor.row">
+ <tr class="oe_view_editor_row" t-att-id="'viewedit-' + rec.id" t-att-level="rec.level" t-foreach="data" t-as="rec">
+ <td class="oe_view_editor_colum" width="85%">
+ <table class="oe_view_editor_tree_grid">
+ <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"
+ src="/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 align="left" class="oe_view_editor_colum" width="15%">
+ <table width="100%">
+ <tr>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-add" src="/web/static/src/img/icons/gtk-add.png" style="cursor: pointer;"/>
+ </td>
+ <td width="20%">
+ <img id="side-remove" src="/web/static/src/img/icons/gtk-remove.png" style="cursor: pointer;"/>
+ </td>
+ <td width="20%">
+ <img t-if="rec.att_list.length and !_.include(no_properties, rec.att_list[0])"
+ id="side-edit" src="/web/static/src/img/icons/gtk-edit.png" style="cursor: pointer;"/>
+ </td>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-up" src="/web/static/src/img/icons/gtk-go-up.png" style="cursor: pointer;"/>
+ </td>
+ <td width="20%">
+ <img t-if="rec.att_list.length"
+ id="side-down" src="/web/static/src/img/icons/gtk-go-down.png" style="cursor: pointer;"/>
+ </td>
+ </tr>
+ </table>
+ </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>
@@ -1634,7 +1683,7 @@
</table>
</t>
<t t-name="ImportView.error">
- <p style="white-space:pre-line;">The import failed due to:<t t-esc="error.message"/></p>
+ <p style="white-space:pre;">The import failed due to:<t t-esc="error.message"/></p>
<t t-if="error.preview">
<p>Here is a preview of the file we could not import:</p>
<pre><t t-esc="error.preview"/></pre>