changeset ebf7626f0631 in sao:default
details: https://hg.tryton.org/sao?cmd=changeset;node=ebf7626f0631
description:
Use tempusdominus and Popper for date time picker
issue9455
review327751002
diffstat:
CHANGELOG | 1 +
Gruntfile.js | 2 +-
bower.json | 5 +-
index.html | 3 +-
src/sao.js | 33 ++++++++++++++++++++
src/sao.less | 6 +++-
src/screen.js | 35 +++++++++------------
src/view/form.js | 89 ++++++++++++++++++++++---------------------------------
src/view/tree.js | 5 +++
9 files changed, 101 insertions(+), 78 deletions(-)
diffs (426 lines):
diff -r 0e62c2943fee -r ebf7626f0631 CHANGELOG
--- a/CHANGELOG Sat Sep 12 01:25:35 2020 +0200
+++ b/CHANGELOG Sat Sep 12 09:58:20 2020 +0200
@@ -1,3 +1,4 @@
+* Use tempusdominus and Popper for date time picker
* Support PYSON comparison of date and datetime
* Customize bootstrap default style
* Set field's name as input's name attribute
diff -r 0e62c2943fee -r ebf7626f0631 Gruntfile.js
--- a/Gruntfile.js Sat Sep 12 01:25:35 2020 +0200
+++ b/Gruntfile.js Sat Sep 12 09:58:20 2020 +0200
@@ -106,7 +106,7 @@
'bower_components/bootstrap',
'bower_components/bootstrap/less',
'bower_components/bootstrap-rtl-ondemand/less',
-
'bower_components/eonasdan-bootstrap-datetimepicker/src/less',
+ 'bower_components/tempusdominus-bootstrap-3/src/less/',
]
},
files: {
diff -r 0e62c2943fee -r ebf7626f0631 bower.json
--- a/bower.json Sat Sep 12 01:25:35 2020 +0200
+++ b/bower.json Sat Sep 12 09:58:20 2020 +0200
@@ -18,14 +18,15 @@
"jquery": "^3",
"bootstrap": "^3.3.7",
"moment": "^2.10",
- "eonasdan-bootstrap-datetimepicker": "^4.17",
"gettext.js": "^0.7",
"c3": "^0.7",
"papaparse": "^5.0",
"fullcalendar": "^3.10.2",
"mousetrap": "^1.6",
"bootstrap-rtl-ondemand": "^3.3.4-ondemand",
- "Sortable": "sortablejs#^1.8.4"
+ "Sortable": "sortablejs#^1.8.4",
+ "tempusdominus-bootstrap-3":
"bootstrap-datetimepicker-v5-alpha#^5.0.0-alpha8",
+ "popper.js": "https://unpkg.com/popper.js"
},
"devDependencies": {
"qunit": "^1.18"
diff -r 0e62c2943fee -r ebf7626f0631 index.html
--- a/index.html Sat Sep 12 01:25:35 2020 +0200
+++ b/index.html Sat Sep 12 09:58:20 2020 +0200
@@ -13,7 +13,8 @@
<script type="text/javascript"
src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script type="text/javascript"
src="bower_components/moment/min/moment.min.js"></script>
<script type="text/javascript"
src="bower_components/moment/min/locales.min.js"></script>
- <script type="text/javascript"
src="bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js"></script>
+ <script type="text/javascript"
src="bower_components/popper.js/index.js"></script>
+ <script type="text/javascript"
src="bower_components/tempusdominus-bootstrap-3/build/js/tempusdominus-bootstrap-3.js"></script>
<script type="text/javascript"
src="bower_components/gettext.js/dist/gettext.min.js"></script>
<script type="text/javascript"
src="bower_components/d3/d3.min.js"></script>
<script type="text/javascript"
src="bower_components/c3/c3.min.js"></script>
diff -r 0e62c2943fee -r ebf7626f0631 src/sao.js
--- a/src/sao.js Sat Sep 12 01:25:35 2020 +0200
+++ b/src/sao.js Sat Sep 12 09:58:20 2020 +0200
@@ -1146,4 +1146,37 @@
jQuery('.modal.in:visible:last').focus()
.next('.modal-backdrop.in').removeClass('hidden');
}
+
+ // XXX: use Popper to place popup
+ // cherry picked from tempusdominus-core.js
+ $.fn.datetimepicker.prototype.constructor.Constructor.prototype._place =
function _place(e) {
+ var self = (e && e.data && e.data.picker) || this;
+ if (self._options.sideBySide) {
+ self._element.append(self.widget);
+ return;
+ }
+ if (self._options.widgetParent) {
+ self._options.widgetParent.append(self.widget);
+ } else if (self._element.is('input')) {
+ self._element.after(self.widget).parent();
+ } else {
+ self._element.children().first().after(self.widget);
+ }
+
+ var reference = self.component[0];
+
+ if (!reference) {
+ reference = self._element;
+ }
+
+ // ReSharper disable once ConstructorCallNotUsed
+ new Popper(reference, self.widget[0], {
+ placement: 'bottom-start'
+ });
+ };
+
+ // XXX: Ensure to always return a date
+
$.fn.datetimepicker.prototype.constructor.Constructor.prototype._getLastPickedDate
= function _getLastPickedDate() {
+ return this._dates[this._getLastPickedDateIndex()] || this.getMoment();
+ };
}());
diff -r 0e62c2943fee -r ebf7626f0631 src/sao.less
--- a/src/sao.less Sat Sep 12 01:25:35 2020 +0200
+++ b/src/sao.less Sat Sep 12 09:58:20 2020 +0200
@@ -2,7 +2,7 @@
this repository contains the full copyright notices and license terms. */
@import "bootstrap";
@import "bootstrap-rtl";
-@import "bootstrap-datetimepicker-build";
+@import "_tempusdominus-bootstrap-3";
@import "sao-variables";
html[theme="default"] {
@import "theme";
@@ -681,6 +681,10 @@
}
}
+.bootstrap-datetimepicker-widget.dropdown-menu {
+ z-index: 2000;
+}
+
@media screen and (max-width: @screen-xs-max) {
.treeview {
height: calc(100vh - 370px);
diff -r 0e62c2943fee -r ebf7626f0631 src/screen.js
--- a/src/screen.js Sat Sep 12 01:25:35 2020 +0200
+++ b/src/screen.js Sat Sep 12 09:58:20 2020 +0200
@@ -636,56 +636,51 @@
Sao.ScreenContainer.BetweenDates, {
build_entry: function(placeholder, el) {
var entry = jQuery('<div/>', {
- 'class': 'input-group input-group-sm'
+ 'class': 'input-group input-group-sm',
+ 'data-target-input': 'nearest',
}).appendTo(el);
+ entry.uniqueId();
jQuery('<span/>', {
'class': 'input-group-btn'
}).append(jQuery('<button/>', {
- 'class': 'datepickerbutton btn btn-default',
+ 'class': 'btn btn-default',
type: 'button',
'tabindex': -1,
'aria-label': Sao.i18n.gettext("Open the calendar"),
'title': Sao.i18n.gettext("Open the calendar"),
+ 'data-target': '#' + entry.attr('id'),
+ 'data-toggle': 'datetimepicker',
}).append(Sao.common.ICONFACTORY.get_icon_img('tryton-date')
)).appendTo(entry);
jQuery('<input/>', {
- 'class': 'form-control input-sm',
+ 'class': ('form-control input-sm datetimepicker-input ' +
+ 'mousetrap'),
type: 'text',
placeholder: placeholder,
+ 'data-target': '#' + entry.attr('id'),
}).appendTo(entry);
entry.datetimepicker({
- 'locale': moment.locale(),
+ 'locale': Sao.common.moment_format(this.format),
'keyBinds': null,
- });
- entry.data('DateTimePicker').format(this.format);
- // We must set the overflow of the modal-body
- // containing the input to visible to prevent vertical
scrollbar
- // inherited from the auto overflow-x
- // (see
http://www.w3.org/TR/css-overflow-3/#overflow-properties)
- entry.on('dp.hide', function() {
- entry.closest('.modal-body').css('overflow', '');
- });
- entry.on('dp.show', function() {
- entry.closest('.modal-body').css('overflow', 'visible');
+ 'useCurrent': false,
});
var mousetrap = new Mousetrap(el[0]);
mousetrap.bind('enter', function(e, combo) {
- entry.data('DateTimePicker').date();
+ entry.datetimepicker('date');
});
mousetrap.bind('=', function(e, combo) {
e.preventDefault();
- entry.data('DateTimePicker').date(moment());
+ entry.datetimepicker('date', moment());
});
Sao.common.DATE_OPERATORS.forEach(function(operator) {
mousetrap.bind(operator[0], function(e, combo) {
e.preventDefault();
- var dp = entry.data('DateTimePicker');
- var date = dp.date();
+ var date = entry.datetimepicker('date');
date.add(operator[1]);
- dp.date(date);
+ entry.datetimepicker('date', date);
});
});
return entry;
diff -r 0e62c2943fee -r ebf7626f0631 src/view/form.js
--- a/src/view/form.js Sat Sep 12 01:25:35 2020 +0200
+++ b/src/view/form.js Sat Sep 12 09:58:20 2020 +0200
@@ -1566,16 +1566,21 @@
this.date = this.labelled = jQuery('<div/>', {
'class': ('input-group input-group-sm ' +
'input-icon input-icon-primary'),
+ 'data-target-input': 'nearest',
}).appendTo(this.el);
+ this.date.uniqueId();
Sao.common.ICONFACTORY.get_icon_img('tryton-date')
.appendTo(jQuery('<div/>', {
- 'class': 'datepickerbutton icon-input icon-primary',
+ 'class': 'icon-input icon-primary',
'aria-label': Sao.i18n.gettext("Open the calendar"),
'title': Sao.i18n.gettext("Open the calendar"),
+ 'data-target': '#' + this.date.attr('id'),
+ 'data-toggle': 'datetimepicker',
}).appendTo(this.date));
this.input = jQuery('<input/>', {
'type': 'text',
- 'class': 'form-control input-sm mousetrap',
+ 'class': 'form-control input-sm datetimepicker-input
mousetrap',
+ 'data-target': '#' + this.date.attr('id'),
'name': attributes.name,
}).appendTo(this.date);
this.date.datetimepicker({
@@ -1584,32 +1589,18 @@
'useCurrent': false,
});
this.date.css('max-width', this._width);
- this.date.on('dp.change', this.focus_out.bind(this));
- // We must set the overflow of the treeview and modal-body
- // containing the input to visible to prevent vertical scrollbar
- // inherited from the auto overflow-x
- // (see http://www.w3.org/TR/css-overflow-3/#overflow-properties)
- this.date.on('dp.hide', function() {
- this.date.closest('.treeview').css('overflow', '');
- this.date.closest('.modal-body').css('overflow', '');
- this.date.closest('.form-group_').css('overflow', 'auto');
- }.bind(this));
- this.date.on('dp.show', function() {
- this.date.closest('.treeview').css('overflow', 'visible');
- this.date.closest('.modal-body').css('overflow', 'visible');
- this.date.closest('.form-group_').css('overflow', 'visible');
- }.bind(this));
+ this.date.on('change.datetimepicker', this.focus_out.bind(this));
var mousetrap = new Mousetrap(this.el[0]);
mousetrap.bind('enter', function(e, combo) {
if (!this.date.find('input').prop('readonly')) {
- this.date.data('DateTimePicker').date();
+ this.date.datetimepicker('date');
}
}.bind(this));
mousetrap.bind('=', function(e, combo) {
if (!this.date.find('input').prop('readonly')) {
e.preventDefault();
- this.date.data('DateTimePicker').date(moment());
+ this.date.datetimepicker('date', moment());
}
}.bind(this));
@@ -1619,10 +1610,9 @@
return;
}
e.preventDefault();
- var dp = this.date.data('DateTimePicker');
- var date = dp.date();
+ var date = this.date.datetimepicker('date');
date.add(operator[1]);
- dp.date(date);
+ this.date.datetimepicker('date', date);
}.bind(this));
}.bind(this));
},
@@ -1630,7 +1620,7 @@
return this.field.date_format(this.record);
},
get_value: function() {
- var value = this.date.data('DateTimePicker').date();
+ var value = this.date.datetimepicker('date');
if (value) {
value.isDate = true;
}
@@ -1640,8 +1630,8 @@
var record = this.record;
var field = this.field;
if (record && field) {
- this.date.data('DateTimePicker').format(
- Sao.common.moment_format(this.get_format()));
+ this.date.datetimepicker(
+ 'format', Sao.common.moment_format(this.get_format()));
}
Sao.View.Form.Date._super.display.call(this);
var value;
@@ -1650,11 +1640,11 @@
} else {
value = null;
}
- this.date.off('dp.change');
+ this.date.off('change.datetimepicker');
try {
- this.date.data('DateTimePicker').date(value);
+ this.date.datetimepicker('date', value);
} finally {
- this.date.on('dp.change', this.focus_out.bind(this));
+ this.date.on('change.datetimepicker',
this.focus_out.bind(this));
}
},
focus: function() {
@@ -1686,7 +1676,7 @@
return field.date_format(record) + ' ' + field.time_format(record);
},
get_value: function() {
- var value = this.date.data('DateTimePicker').date();
+ var value = this.date.datetimepicker('date');
if (value) {
value.isDateTime = true;
}
@@ -1701,7 +1691,7 @@
return this.field.time_format(this.record);
},
get_value: function() {
- var value = this.date.data('DateTimePicker').date();
+ var value = this.date.datetimepicker('date');
if (value) {
value.isTime = true;
}
@@ -4788,64 +4778,57 @@
Sao.View.Form.Dict.Date._super.create_widget.call(this);
this.date = this.input.parent();
this.date.addClass('input-icon input-icon-primary');
+ this.date.attr('data-target-input', 'nearest');
+ this.date.uniqueId();
Sao.common.ICONFACTORY.get_icon_img('tryton-date')
.appendTo(jQuery('<div/>', {
- 'class': 'datepickerbutton icon-input icon-primary',
+ 'class': 'icon-input icon-primary',
'aria-label': Sao.i18n.gettext("Open the calendar"),
'title': Sao.i18n.gettext("Open the calendar"),
+ 'data-target': '#' + this.date.attr('id'),
+ 'data-toggle': 'datetimepicker',
}).prependTo(this.date));
+ this.input.addClass('datetimepicker-input');
+ this.input.data('target', '#' + this.date.attr('id'));
this.date.datetimepicker({
'format': Sao.common.moment_format(this.format),
'locale': moment.locale(),
'keyBinds': null,
'useCurrent': false,
});
- this.date.on('dp.change',
+ this.date.on('change.datetimepicker',
this.parent_widget.focus_out.bind(this.parent_widget));
- // We must set the overflow of the treeview and modal-body
- // containing the input to visible to prevent vertical scrollbar
- // inherited from the auto overflow-x
- // (see http://www.w3.org/TR/css-overflow-3/#overflow-properties)
- this.date.on('dp.hide', function() {
- this.date.closest('.treeview').css('overflow', '');
- this.date.closest('.modal-body').css('overflow', '');
- }.bind(this));
- this.date.on('dp.show', function() {
- this.date.closest('.treeview').css('overflow', 'visible');
- this.date.closest('.modal-body').css('overflow', 'visible');
- }.bind(this));
var mousetrap = new Mousetrap(this.el[0]);
mousetrap.bind(['enter', '='], function(e, combo) {
if (e.which != Sao.common.RETURN_KEYCODE) {
e.preventDefault();
}
- this.date.data('DateTimePicker').date(moment());
+ this.date.datetimepicker('date', moment());
}.bind(this));
Sao.common.DATE_OPERATORS.forEach(function(operator) {
mousetrap.bind(operator[0], function(e, combo) {
e.preventDefault();
- var dp = this.date.data('DateTimePicker');
- var date = dp.date();
+ var date = this.date.datetimepicker('date');
date.add(operator[1]);
- dp.date(date);
+ this.date.datetimepicker('date', date);
}.bind(this));
}.bind(this));
},
get_value: function() {
- var value = this.date.data('DateTimePicker').date();
+ var value = this.date.datetimepicker('date');
if (value) {
value.isDate = true;
}
return value;
},
set_value: function(value) {
- this.date.off('dp.change');
+ this.date.off('change.datetimepicker');
try {
- this.date.data('DateTimePicker').date(value);
+ this.date.datetimepicker('date', value);
} finally {
- this.date.on('dp.change',
+ this.date.on('change.datetimepicker',
this.parent_widget.focus_out.bind(this.parent_widget));
}
}
@@ -4855,7 +4838,7 @@
class_: 'dict-datetime',
format: '%x %X',
get_value: function() {
- var value = this.date.data('DateTimePicker').date();
+ var value = this.date.datetimepicker('date');
if (value) {
value.isDateTime = true;
}
diff -r 0e62c2943fee -r ebf7626f0631 src/view/tree.js
--- a/src/view/tree.js Sat Sep 12 01:25:35 2020 +0200
+++ b/src/view/tree.js Sat Sep 12 09:58:20 2020 +0200
@@ -2559,6 +2559,11 @@
init: function(view, attributes) {
Sao.View.EditableTree.Date._super.init.call(
this, view, attributes);
+ // XXX: click event does not work in editable
+ // so we manage it ourselves to toggle the picker.
+
this.date.find('.icon-input').removeAttr('data-toggle').click(function() {
+ this.date.datetimepicker('toggle');
+ }.bind(this));
Sao.View.EditableTree.editable_mixin(this);
}
});