[IMP] web: add new date range picker field widget
Adds a new widget to support start & end date or datetime. closes odoo/odoo#33266 Signed-off-by: VincentSchippefilt <VincentSchippefilt@users.noreply.github.com>
This commit is contained in:
committed by
Vincent Schippefilt
parent
125dbf0dfd
commit
cda93a5c19
@@ -232,8 +232,12 @@
|
||||
<field name="auto_confirm" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_begin"/>
|
||||
<field name="date_end"/>
|
||||
<label for="date_begin" string="Date"/>
|
||||
<div class="o_row">
|
||||
<field name="date_begin" widget="daterange" nolabel="1" class="oe_inline" options="{'related_end_date': 'date_end'}"/>
|
||||
<i class="fa fa-long-arrow-right mx-2" aria-label="Arrow icon" title="Arrow"/>
|
||||
<field name="date_end" widget="daterange" nolabel="1" class="oe_inline" options="{'related_start_date': 'date_begin'}"/>
|
||||
</div>
|
||||
<field name="date_tz"/>
|
||||
</group>
|
||||
<group>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Date Range Picker
|
||||
|
||||

|
||||
|
||||
This date range picker component creates a dropdown menu from which a user can
|
||||
select a range of dates. I created it while building the UI for [Improvely](http://www.improvely.com),
|
||||
which needed a way to select date ranges for reports.
|
||||
|
||||
Features include limiting the selectable date range, localizable strings and date formats,
|
||||
a single date picker mode, a time picker, and predefined date ranges.
|
||||
|
||||
## [Documentation and Live Usage Examples](http://www.daterangepicker.com)
|
||||
|
||||
## [See It In a Live Application](https://awio.iljmp.com/5/drpdemogh)
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2019 Dan Grossman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,410 @@
|
||||
.daterangepicker {
|
||||
position: absolute;
|
||||
color: inherit;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
width: 278px;
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
margin-top: 7px;
|
||||
top: 100px;
|
||||
left: 20px;
|
||||
z-index: 3001;
|
||||
display: none;
|
||||
font-family: arial;
|
||||
font-size: 15px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.daterangepicker:before, .daterangepicker:after {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
content: '';
|
||||
}
|
||||
|
||||
.daterangepicker:before {
|
||||
top: -7px;
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker:after {
|
||||
top: -6px;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
border-left: 6px solid transparent;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:before {
|
||||
right: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensleft:after {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:before {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.openscenter:after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:before {
|
||||
left: 9px;
|
||||
}
|
||||
|
||||
.daterangepicker.opensright:after {
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up {
|
||||
margin-top: -7px;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:before {
|
||||
top: initial;
|
||||
bottom: -7px;
|
||||
border-bottom: initial;
|
||||
border-top: 7px solid #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker.drop-up:after {
|
||||
top: initial;
|
||||
bottom: -6px;
|
||||
border-bottom: initial;
|
||||
border-top: 6px solid #fff;
|
||||
}
|
||||
|
||||
.daterangepicker.single .daterangepicker .ranges, .daterangepicker.single .drp-calendar {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.daterangepicker.single .drp-selected {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-calendar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .drp-buttons {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.daterangepicker.auto-apply .drp-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar {
|
||||
display: none;
|
||||
max-width: 270px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
padding: 8px 0 8px 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.single .calendar-table {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span, .daterangepicker .calendar-table .prev span {
|
||||
color: #fff;
|
||||
border: solid black;
|
||||
border-width: 0 2px 2px 0;
|
||||
border-radius: 0;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .next span {
|
||||
transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table .prev span {
|
||||
transform: rotate(135deg);
|
||||
-webkit-transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table th, .daterangepicker .calendar-table td {
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
min-width: 32px;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid transparent;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table {
|
||||
border: 1px solid #fff;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-table table {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.daterangepicker td.available:hover, .daterangepicker th.available:hover {
|
||||
background-color: #eee;
|
||||
border-color: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.daterangepicker td.week, .daterangepicker th.week {
|
||||
font-size: 80%;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date {
|
||||
background-color: #fff;
|
||||
border-color: transparent;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.daterangepicker td.in-range {
|
||||
background-color: #ebf4f8;
|
||||
border-color: transparent;
|
||||
color: #000;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date {
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.end-date {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.daterangepicker td.start-date.end-date {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.daterangepicker td.active, .daterangepicker td.active:hover {
|
||||
background-color: #357ebd;
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.daterangepicker th.month {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker td.disabled, .daterangepicker option.disabled {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.daterangepicker select.monthselect, .daterangepicker select.yearselect {
|
||||
font-size: 12px;
|
||||
padding: 1px;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.daterangepicker select.monthselect {
|
||||
margin-right: 2%;
|
||||
width: 56%;
|
||||
}
|
||||
|
||||
.daterangepicker select.yearselect {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect {
|
||||
width: 50px;
|
||||
margin: 0 auto;
|
||||
background: #eee;
|
||||
border: 1px solid #eee;
|
||||
padding: 2px;
|
||||
outline: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-time {
|
||||
text-align: center;
|
||||
margin: 4px auto 0 auto;
|
||||
line-height: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.daterangepicker .calendar-time select.disabled {
|
||||
color: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons {
|
||||
clear: both;
|
||||
text-align: right;
|
||||
padding: 8px;
|
||||
border-top: 1px solid #ddd;
|
||||
display: none;
|
||||
line-height: 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-selected {
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-buttons .btn {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.single.rtl .drp-calendar.left {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.single.ltr .drp-calendar.left {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.rtl .drp-calendar.right {
|
||||
border-right: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker.show-ranges.ltr .drp-calendar.left {
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges {
|
||||
float: none;
|
||||
text-align: left;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.daterangepicker.show-calendar .ranges {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges ul {
|
||||
list-style: none;
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li {
|
||||
font-size: 12px;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges li.active {
|
||||
background-color: #08c;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Larger Screen Styling */
|
||||
@media (min-width: 564px) {
|
||||
.daterangepicker {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges ul {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.daterangepicker.single .ranges ul {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.daterangepicker.single .drp-calendar.left {
|
||||
clear: none;
|
||||
}
|
||||
|
||||
.daterangepicker.single .ranges, .daterangepicker.single .drp-calendar {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.daterangepicker {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
clear: left;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left .calendar-table {
|
||||
border-right: none;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.right .calendar-table {
|
||||
border-left: none;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left .calendar-table {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges, .daterangepicker .drp-calendar {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 730px) {
|
||||
.daterangepicker .ranges {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.daterangepicker .ranges {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.daterangepicker.rtl .ranges {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.daterangepicker .drp-calendar.left {
|
||||
clear: none !important;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@ var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
var view_dialogs = require('web.view_dialogs');
|
||||
var field_utils = require('web.field_utils');
|
||||
var time = require('web.time');
|
||||
|
||||
require("web.zoomodoo");
|
||||
|
||||
@@ -554,6 +555,121 @@ var LinkButton = AbstractField.extend({
|
||||
},
|
||||
});
|
||||
|
||||
var FieldDateRange = InputField.extend({
|
||||
className: 'o_field_date_range',
|
||||
tagName: 'span',
|
||||
jsLibs: [
|
||||
'/web/static/lib/daterangepicker/daterangepicker.js',
|
||||
'/web/static/src/js/libs/daterangepicker.js',
|
||||
],
|
||||
cssLibs: [
|
||||
'/web/static/lib/daterangepicker/daterangepicker.css',
|
||||
],
|
||||
supportedFieldTypes: ['date', 'datetime'],
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.isDateField = this.formatType === 'date';
|
||||
this.dateRangePickerOptions = _.defaults(
|
||||
{},
|
||||
this.nodeOptions.picker_options || {},
|
||||
{
|
||||
timePicker: !this.isDateField,
|
||||
timePicker24Hour: _t.database.parameters.time_format.search('%H') !== -1,
|
||||
autoUpdateInput: false,
|
||||
timePickerIncrement: 10,
|
||||
locale: {
|
||||
format: this.isDateField ? time.getLangDateFormat() : time.getLangDatetimeFormat(),
|
||||
},
|
||||
}
|
||||
);
|
||||
this.relatedEndDate = this.nodeOptions.related_end_date;
|
||||
this.relatedStartDate = this.nodeOptions.related_start_date;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
destroy: function () {
|
||||
if (this.$pickerContainer) {
|
||||
this.$pickerContainer.remove();
|
||||
}
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
* @param {Object} picker
|
||||
*/
|
||||
_applyChanges: function (ev, picker) {
|
||||
var changes = {};
|
||||
var displayStartDate = field_utils.format[this.formatType](picker.startDate, {}, {timezone: false});
|
||||
var displayEndDate = field_utils.format[this.formatType](picker.endDate, {}, {timezone: false});
|
||||
var changedStartDate = picker.startDate;
|
||||
var changedEndDate = picker.endDate;
|
||||
if (this.isDateField) {
|
||||
// In date mode, the library will give moment object of start and end date having
|
||||
// time at 00:00:00. So, Odoo will consider it as UTC. To fix this added browser
|
||||
// timezone offset in dates to get a correct selected date.
|
||||
changedStartDate = picker.startDate.add(session.getTZOffset(picker.startDate), 'minutes');
|
||||
changedEndDate = picker.endDate.startOf('day').add(session.getTZOffset(picker.endDate), 'minutes');
|
||||
}
|
||||
if (this.relatedEndDate) {
|
||||
this.$el.val(displayStartDate);
|
||||
changes[this.name] = this._parseValue(changedStartDate);
|
||||
changes[this.relatedEndDate] = this._parseValue(changedEndDate);
|
||||
}
|
||||
if (this.relatedStartDate) {
|
||||
this.$el.val(displayEndDate);
|
||||
changes[this.name] = this._parseValue(changedEndDate);
|
||||
changes[this.relatedStartDate] = this._parseValue(changedStartDate);
|
||||
}
|
||||
this.trigger_up('field_changed', {
|
||||
dataPointID: this.dataPointID,
|
||||
viewType: this.viewType,
|
||||
changes: changes,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
_renderEdit: function () {
|
||||
this._super.apply(this, arguments);
|
||||
var self = this;
|
||||
var startDate;
|
||||
var endDate;
|
||||
if (this.relatedEndDate) {
|
||||
startDate = this._formatValue(this.value);
|
||||
endDate = this._formatValue(this.recordData[this.relatedEndDate]);
|
||||
}
|
||||
if (this.relatedStartDate) {
|
||||
startDate = this._formatValue(this.recordData[this.relatedStartDate]);
|
||||
endDate = this._formatValue(this.value);
|
||||
}
|
||||
this.dateRangePickerOptions.startDate = startDate || moment();
|
||||
this.dateRangePickerOptions.endDate = endDate || moment();
|
||||
|
||||
this.$el.daterangepicker(this.dateRangePickerOptions);
|
||||
this.$el.on('apply.daterangepicker', this._applyChanges.bind(this));
|
||||
this.$el.off('keyup.daterangepicker');
|
||||
this.$pickerContainer = this.$el.data('daterangepicker').container;
|
||||
|
||||
// Prevent from leaving the edition of a row in editable list view
|
||||
this.$pickerContainer.on('click', function (ev) {
|
||||
ev.stopPropagation();
|
||||
if ($(ev.target).hasClass('applyBtn')) {
|
||||
self.$el.data('daterangepicker').hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
var FieldDate = InputField.extend({
|
||||
description: _lt("Date"),
|
||||
className: "o_field_date",
|
||||
@@ -3101,6 +3217,7 @@ return {
|
||||
LinkButton: LinkButton,
|
||||
FieldDate: FieldDate,
|
||||
FieldDateTime: FieldDateTime,
|
||||
FieldDateRange: FieldDateRange,
|
||||
FieldDomain: FieldDomain,
|
||||
FieldFloat: FieldFloat,
|
||||
FieldFloatTime: FieldFloatTime,
|
||||
|
||||
@@ -24,6 +24,7 @@ registry
|
||||
.add('boolean', basic_fields.FieldBoolean)
|
||||
.add('date', basic_fields.FieldDate)
|
||||
.add('datetime', basic_fields.FieldDateTime)
|
||||
.add('daterange', basic_fields.FieldDateRange)
|
||||
.add('domain', basic_fields.FieldDomain)
|
||||
.add('text', basic_fields.FieldText)
|
||||
.add('list.text', basic_fields.ListFieldText)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
odoo.define('web.daterangepicker.extensions', function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Don't allow user to select off days(Dates which are out of current calendar).
|
||||
*/
|
||||
var clickDateFunction = daterangepicker.prototype.clickDate;
|
||||
daterangepicker.prototype.clickDate = function (ev) {
|
||||
if (!$(ev.target).hasClass('off')) {
|
||||
clickDateFunction.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
// Restore date range picker style
|
||||
.daterangepicker {
|
||||
.drp-calendar {
|
||||
.calendar-table {
|
||||
thead {
|
||||
tr:first-child {
|
||||
color: #FFFFFF;
|
||||
background-color: $o-brand-odoo;
|
||||
th {
|
||||
&.prev, &.next {
|
||||
span {
|
||||
color: #FFFFFF;
|
||||
border-color: #FFFFFF;
|
||||
}
|
||||
&:hover {
|
||||
background-color: darken($o-brand-odoo, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tr:last-child {
|
||||
color: $o-datepicker-week-color;
|
||||
background-color: $o-datepicker-week-bg-color;
|
||||
}
|
||||
th {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
border-bottom: 1px solid $o-datepicker-week-bg-color;
|
||||
td {
|
||||
border-width: 0px;
|
||||
&:not(.off) {
|
||||
&.in-range {
|
||||
background-color: gray('200');
|
||||
}
|
||||
&.available:hover {
|
||||
background-color: gray('200');
|
||||
}
|
||||
&.active, &.active:hover {
|
||||
background-color: $o-brand-primary;
|
||||
}
|
||||
}
|
||||
&.off:hover {
|
||||
background: #FFFFFF;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.calendar-time {
|
||||
select {
|
||||
&.hourselect, &.minuteselect, &.secondselect, &.ampmselect {
|
||||
display: initial;
|
||||
-webkit-appearance: menulist-button;
|
||||
-moz-appearance: menulist-button;
|
||||
appearance: menulist-button;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.drp-buttons {
|
||||
.drp-selected {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2578,6 +2578,174 @@ QUnit.module('basic_fields', {
|
||||
});
|
||||
|
||||
|
||||
QUnit.module('FieldDateRange');
|
||||
|
||||
QUnit.test('Datetime field', async function (assert) {
|
||||
assert.expect(19);
|
||||
|
||||
this.data.partner.fields.datetime_end = {string: 'Datetime End', type: 'datetime'};
|
||||
this.data.partner.records[0].datetime_end = '2017-03-13 00:00:00';
|
||||
|
||||
var form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form>' +
|
||||
'<field name="datetime" widget="daterange" options="{\'related_end_date\': \'datetime_end\'}"/>' +
|
||||
'<field name="datetime_end" widget="daterange" options="{\'related_start_date\': \'datetime\'}"/>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
session: {
|
||||
getTZOffset: function () {
|
||||
return 330;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Check date display correctly in readonly
|
||||
assert.strictEqual(form.$('.o_field_date_range:first').text(), '02/08/2017 15:30:00',
|
||||
"the start date should be correctly displayed in readonly");
|
||||
assert.strictEqual(form.$('.o_field_date_range:last').text(), '03/13/2017 05:30:00',
|
||||
"the end date should be correctly displayed in readonly");
|
||||
|
||||
// Edit
|
||||
await testUtils.form.clickEdit(form);
|
||||
|
||||
// Check date range picker initialization
|
||||
assert.containsN(document.body, '.daterangepicker', 2,
|
||||
"should initialize 2 date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first').css('display'), 'block',
|
||||
"date range picker should be opened initially");
|
||||
assert.strictEqual($('.daterangepicker:last').css('display'), 'none',
|
||||
"date range picker should be closed initially");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.left .active.start-date').text(), '8',
|
||||
"active start date should be '8' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.left .hourselect').val(), '15',
|
||||
"active start date hour should be '15' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.left .minuteselect').val(), '30',
|
||||
"active start date minute should be '30' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.right .active.end-date').text(), '13',
|
||||
"active end date should be '13' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.right .hourselect').val(), '5',
|
||||
"active end date hour should be '5' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .drp-calendar.right .minuteselect').val(), '30',
|
||||
"active end date minute should be '30' in date range picker");
|
||||
|
||||
// Close picker
|
||||
await testUtils.dom.click($('.daterangepicker:first .cancelBtn'));
|
||||
assert.strictEqual($('.daterangepicker:first').css('display'), 'none',
|
||||
"date range picker should be closed");
|
||||
|
||||
// Try to check with end date
|
||||
await testUtils.dom.click(form.$('.o_field_date_range:last'));
|
||||
assert.strictEqual($('.daterangepicker:last').css('display'), 'block',
|
||||
"date range picker should be opened");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.left .active.start-date').text(), '8',
|
||||
"active start date should be '8' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.left .hourselect').val(), '15',
|
||||
"active start date hour should be '15' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.left .minuteselect').val(), '30',
|
||||
"active start date minute should be '30' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.right .active.end-date').text(), '13',
|
||||
"active end date should be '13' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.right .hourselect').val(), '5',
|
||||
"active end date hour should be '5' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .drp-calendar.right .minuteselect').val(), '30',
|
||||
"active end date minute should be '30' in date range picker");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('Date field', async function (assert) {
|
||||
assert.expect(18);
|
||||
|
||||
this.data.partner.fields.date_end = {string: 'Date End', type: 'date'};
|
||||
this.data.partner.records[0].date_end = '2017-02-08';
|
||||
|
||||
var form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form>' +
|
||||
'<field name="date" widget="daterange" options="{\'related_end_date\': \'date_end\'}"/>' +
|
||||
'<field name="date_end" widget="daterange" options="{\'related_start_date\': \'date\'}"/>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
session: {
|
||||
getTZOffset: function () {
|
||||
return 330;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Check date display correctly in readonly
|
||||
assert.strictEqual(form.$('.o_field_date_range:first').text(), '02/03/2017',
|
||||
"the start date should be correctly displayed in readonly");
|
||||
assert.strictEqual(form.$('.o_field_date_range:last').text(), '02/08/2017',
|
||||
"the end date should be correctly displayed in readonly");
|
||||
|
||||
// Edit
|
||||
await testUtils.form.clickEdit(form);
|
||||
|
||||
// Check date range picker initialization
|
||||
assert.containsN(document.body, '.daterangepicker', 2,
|
||||
"should initialize 2 date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first').css('display'), 'block',
|
||||
"date range picker should be opened initially");
|
||||
assert.strictEqual($('.daterangepicker:last').css('display'), 'none',
|
||||
"date range picker should be closed initially");
|
||||
assert.strictEqual($('.daterangepicker:first .active.start-date').text(), '3',
|
||||
"active start date should be '3' in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:first .active.end-date').text(), '8',
|
||||
"active end date should be '8' in date range picker");
|
||||
|
||||
// Change date
|
||||
await testUtils.dom.triggerMouseEvent($('.daterangepicker:first .drp-calendar.left .available:contains("16")'), 'mousedown');
|
||||
await testUtils.dom.triggerMouseEvent($('.daterangepicker:first .drp-calendar.right .available:contains("12")'), 'mousedown');
|
||||
await testUtils.dom.click($('.daterangepicker:first .applyBtn'));
|
||||
|
||||
// Check date after change
|
||||
assert.strictEqual($('.daterangepicker:first').css('display'), 'none',
|
||||
"date range picker should be closed");
|
||||
assert.strictEqual(form.$('.o_field_date_range:first').val(), '02/16/2017',
|
||||
"the date should be '02/16/2017'");
|
||||
assert.strictEqual(form.$('.o_field_date_range:last').val(), '03/12/2017',
|
||||
"'the date should be '03/12/2017'");
|
||||
|
||||
// Try to change range with end date
|
||||
await testUtils.dom.click(form.$('.o_field_date_range:last'));
|
||||
assert.strictEqual($('.daterangepicker:last').css('display'), 'block',
|
||||
"date range picker should be opened");
|
||||
assert.strictEqual($('.daterangepicker:last .active.start-date').text(), '16',
|
||||
"start date should be a 16 in date range picker");
|
||||
assert.strictEqual($('.daterangepicker:last .active.end-date').text(), '12',
|
||||
"end date should be a 12 in date range picker");
|
||||
|
||||
// Change date
|
||||
await testUtils.dom.triggerMouseEvent($('.daterangepicker:last .drp-calendar.left .available:contains("13")'), 'mousedown');
|
||||
await testUtils.dom.triggerMouseEvent($('.daterangepicker:last .drp-calendar.right .available:contains("18")'), 'mousedown');
|
||||
await testUtils.dom.click($('.daterangepicker:last .applyBtn'));
|
||||
|
||||
// Check date after change
|
||||
assert.strictEqual($('.daterangepicker:last').css('display'), 'none',
|
||||
"date range picker should be closed");
|
||||
assert.strictEqual(form.$('.o_field_date_range:first').val(), '02/13/2017',
|
||||
"the start date should be '02/13/2017'");
|
||||
assert.strictEqual(form.$('.o_field_date_range:last').val(), '03/18/2017',
|
||||
"the end date should be '03/18/2017'");
|
||||
|
||||
// Save
|
||||
await testUtils.form.clickSave(form);
|
||||
|
||||
// Check date after save
|
||||
assert.strictEqual(form.$('.o_field_date_range:first').text(), '02/13/2017',
|
||||
"the start date should be '02/13/2017' after save");
|
||||
assert.strictEqual(form.$('.o_field_date_range:last').text(), '03/18/2017',
|
||||
"the end date should be '03/18/2017' after save");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.module('FieldDate');
|
||||
|
||||
QUnit.test('date field: toggle datepicker [REQUIRE FOCUS]', async function (assert) {
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/animation.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/rainbow.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/datepicker.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/daterangepicker.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/banner.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/colorpicker.scss"/>
|
||||
<link rel="stylesheet" type="text/scss" href="/web/static/src/scss/keyboard.scss"/>
|
||||
|
||||
@@ -1651,6 +1651,23 @@ order.
|
||||
|
||||
<field name="datetimefield" options='{"datepicker": {"daysOfWeekDisabled": [0, 6]}}'/>
|
||||
|
||||
- daterange (FieldDateRange)
|
||||
This widget allow user to select start and end date into single picker.
|
||||
|
||||
- Supported field types: *date*, *datetime*
|
||||
|
||||
Options:
|
||||
|
||||
- related_start_date: apply on end date field to get start date value which
|
||||
is used to display range in the picker.
|
||||
- related_end_date: apply on start date field to get end date value which
|
||||
is used to display range in the picker.
|
||||
- picker_options: extra settings for picker.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<field name="start_date" widget="daterange" options='{"related_end_date": "end_date"}'/>
|
||||
|
||||
- monetary (FieldMonetary)
|
||||
This is the default field type for fields of type 'monetary'. It is used to
|
||||
display a currency. If there is a currency fields given in option, it will
|
||||
|
||||
Reference in New Issue
Block a user