Browse Source

Merge pull request #656 from smurf-U/10.0-web_widget_timepicker

[10.0][MIG]migrate web_widget_timepicker
pull/652/merge
Moises Lopez - https://www.vauxoo.com/ 7 years ago
committed by GitHub
parent
commit
49d2725e37
  1. 26
      web_widget_timepicker/README.rst
  2. 8
      web_widget_timepicker/__manifest__.py
  3. 5
      web_widget_timepicker/static/src/css/web_widget_timepicker.css
  4. 30
      web_widget_timepicker/static/src/js/web_widget_timepicker.js
  5. 4
      web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.css
  6. 219
      web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.js
  7. 4
      web_widget_timepicker/static/src/xml/web_widget_timepicker.xml
  8. 28
      web_widget_timepicker/views/web_widget_timepicker_assets.xml

26
web_widget_timepicker/README.rst

@ -2,7 +2,6 @@
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
=============================== ===============================
Timepicker widget in form views Timepicker widget in form views
=============================== ===============================
@ -52,16 +51,10 @@ See the available options at `jquery-timepicker <https://github.com//jonthornton
.. |formview| image:: ./images/form_view.png .. |formview| image:: ./images/form_view.png
Known issues / Roadmap
======================
* No validation on options.
Credits Credits
======= =======
* The module uses the `jquery-timepicker <https://cdnjs.com//libraries//jquery-timepicker>`_ plugin by Jon Thornton. This software is made available under the open source MIT License. © 2014 Jon Thornton and contributors
* The module uses the `jquery-timepicker <https://github.com//jonthornton//jquery-timepicker#timepicker-plugin-for-jquery>`_. plugin by Jon Thornton. This software is made available under the open source MIT License. © 2014 Jon Thornton and contributors
* Odoo Community Association (OCA) * Odoo Community Association (OCA)
@ -70,3 +63,20 @@ Contributors
------------ ------------
* Michael Fried <Michael.Fried@vividlab.de> * Michael Fried <Michael.Fried@vividlab.de>
* Kaushal Prajapati <kbprajapati@live.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

8
web_widget_timepicker/__manifest__.py

@ -3,12 +3,14 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ {
"name": "Web Timepicker Widget", "name": "Web Timepicker Widget",
"version": "9.0.1.0.0",
"author": "VividLab, Odoo Community Association (OCA)",
"version": "10.0.1.0.0",
"author": "VividLab, "
"Odoo Community Association (OCA), "
"Kaushal Prajapati",
"license": "AGPL-3", "license": "AGPL-3",
"category": "Web", "category": "Web",
"website": "http://www.vividlab.de", "website": "http://www.vividlab.de",
'installable': False,
'installable': True,
"depends": [ "depends": [
"web", "web",
], ],

5
web_widget_timepicker/static/src/css/web_widget_timepicker.css

@ -1,3 +1,6 @@
.oe_form_editable .oe_form .oe_form_field_time input {
.o_form_editable .o_form_field_time input {
width: 6em; width: 6em;
} }
.o_form_field_time{
display: -webkit-inline-box !important;
}

30
web_widget_timepicker/static/src/js/web_widget_timepicker.js

@ -3,22 +3,22 @@ odoo.define('web_widget_timepicker', function (require) {
var core = require('web.core'); var core = require('web.core');
var formats = require('web.formats'); var formats = require('web.formats');
var common = require('web.form_common');
var common = require('web.form_common');
var TimePickerField = common.AbstractField.extend(common.ReinitializeFieldMixin, { var TimePickerField = common.AbstractField.extend(common.ReinitializeFieldMixin, {
is_field_number: true,
is_field_number: true,
template: "TimePickerField", template: "TimePickerField",
internal_format: 'float_time', internal_format: 'float_time',
widget_class: 'oe_form_field_time',
widget_class: 'o_form_field_time',
events: { events: {
'change input': 'store_dom_value', 'change input': 'store_dom_value',
}, },
init: function (field_manager, node) { init: function (field_manager, node) {
this._super(field_manager, node); this._super(field_manager, node);
this.internal_set_value(0); this.internal_set_value(0);
this.options = _.defaults( this.options, {
this.options = _.defaults(this.options, {
step: 15, step: 15,
selectOnBlur: true, selectOnBlur: true,
timeFormat: 'H:i', timeFormat: 'H:i',
@ -27,14 +27,14 @@ odoo.define('web_widget_timepicker', function (require) {
}, },
initialize_content: function() { initialize_content: function() {
if(!this.get("effective_readonly")) { if(!this.get("effective_readonly")) {
this.$el.find('input').timepicker(this.options);
this.setupFocus(this.$('input'));
}
this.$el.find('input').timepicker(this.options);
this.setupFocus(this.$('input'));
}
}, },
is_syntax_valid: function() { is_syntax_valid: function() {
if (!this.get("effective_readonly") && this.$("input").size() > 0) { if (!this.get("effective_readonly") && this.$("input").size() > 0) {
try { try {
this.parse_value(this.$('input').val(),'');
this.parse_value(this.$('input').val(), '');
return true; return true;
} catch(e) { } catch(e) {
return false; return false;
@ -55,28 +55,28 @@ odoo.define('web_widget_timepicker', function (require) {
height: height, height: height,
width: width width: width
}); });
},
},
store_dom_value: function () { store_dom_value: function () {
if (!this.get('effective_readonly')) { if (!this.get('effective_readonly')) {
this.internal_set_value( this.internal_set_value(
this.parse_value( this.parse_value(
this.$('input').val(),''));
this.$('input').val(), ''));
} }
}, },
parse_value: function(val, def) { parse_value: function(val, def) {
return formats.parse_value(val, {"widget": this.internal_format}, def);
return formats.parse_value(val, {"widget": this.internal_format}, def);
}, },
format_value: function(val, def) { format_value: function(val, def) {
return formats.format_value(val, {"widget": this.internal_format}, def); return formats.format_value(val, {"widget": this.internal_format}, def);
}, },
render_value: function() { render_value: function() {
var show_value = this.format_value(this.get('value'),'');
var show_value = this.format_value(this.get('value'), '');
if (!this.get("effective_readonly")) { if (!this.get("effective_readonly")) {
this.$input = this.$el.find('input'); this.$input = this.$el.find('input');
this.$input.val(show_value); this.$input.val(show_value);
} else { } else {
this.$(".oe_form_time_content").text(show_value);
this.$(".o_form_time_content").text(show_value);
} }
}, },
}); });
@ -84,6 +84,6 @@ odoo.define('web_widget_timepicker', function (require) {
core.form_widget_registry.add('timepicker', TimePickerField); core.form_widget_registry.add('timepicker', TimePickerField);
return { return {
TimePickerField: TimePickerField,
TimePickerField: TimePickerField,
}; };
}); });

4
web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.css

@ -1,6 +1,6 @@
.ui-timepicker-wrapper { .ui-timepicker-wrapper {
overflow-y: auto; overflow-y: auto;
height: 150px;
max-height: 150px;
width: 6.5em; width: 6.5em;
background: #fff; background: #fff;
border: 1px solid #ddd; border: 1px solid #ddd;
@ -69,4 +69,4 @@ li.ui-timepicker-selected .ui-timepicker-duration,
.ui-timepicker-list li.ui-timepicker-disabled:hover, .ui-timepicker-list li.ui-timepicker-disabled:hover,
.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { .ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
background: #f2f2f2; background: #f2f2f2;
}
}

219
web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.js

@ -1,5 +1,5 @@
/*! /*!
* jquery-timepicker v1.10.1 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
* jquery-timepicker v1.11.11 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
* Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/ * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
* License: MIT * License: MIT
*/ */
@ -30,6 +30,58 @@
hrs: 'hrs' hrs: 'hrs'
}; };
var _DEFAULTS = {
appendTo: 'body',
className: null,
closeOnWindowScroll: false,
disableTextInput: false,
disableTimeRanges: [],
disableTouchKeyboard: false,
durationTime: null,
forceRoundTime: false,
maxTime: null,
minTime: null,
noneOption: false,
orientation: 'l',
roundingFunction: function(seconds, settings) {
if (seconds === null) {
return null;
} else if (typeof settings.step !== "number") {
// TODO: nearest fit irregular steps
return seconds;
} else {
var offset = seconds % (settings.step*60); // step is in minutes
var start = settings.minTime || 0;
// adjust offset by start mod step so that the offset is aligned not to 00:00 but to the start
offset -= start % (settings.step * 60);
if (offset >= settings.step*30) {
// if offset is larger than a half step, round up
seconds += (settings.step*60) - offset;
} else {
// round down
seconds -= offset;
}
return _moduloSeconds(seconds, settings);
}
},
scrollDefault: null,
selectOnBlur: false,
show2400: false,
showDuration: false,
showOn: ['click', 'focus'],
showOnFocus: true,
step: 30,
stopScrollPropagation: false,
timeFormat: 'g:ia',
typeaheadHighlight: true,
useSelect: false,
wrapHours: true
};
var methods = { var methods = {
init: function(options) init: function(options)
{ {
@ -39,13 +91,13 @@
// pick up settings from data attributes // pick up settings from data attributes
var attributeOptions = []; var attributeOptions = [];
for (var key in $.fn.timepicker.defaults) {
for (var key in _DEFAULTS) {
if (self.data(key)) { if (self.data(key)) {
attributeOptions[key] = self.data(key); attributeOptions[key] = self.data(key);
} }
} }
var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
var settings = $.extend({}, _DEFAULTS, options, attributeOptions);
if (settings.lang) { if (settings.lang) {
_lang = $.extend(_lang, settings.lang); _lang = $.extend(_lang, settings.lang);
@ -70,8 +122,10 @@
if (settings.disableTextInput) { if (settings.disableTextInput) {
self.on('keydown.timepicker', _disableTextInputHandler); self.on('keydown.timepicker', _disableTextInputHandler);
} }
self.on('cut.timepicker', _keyuphandler);
self.on('paste.timepicker', _keyuphandler);
_formatValue.call(self.get(0));
_formatValue.call(self.get(0), null, 'initial');
} }
}); });
}, },
@ -165,6 +219,11 @@
} }
} }
// if not found or disabled, intelligently find first selectable element
if (!selected.length || selected.hasClass('ui-timepicker-disabled')) {
selected = list.find('li:not(.ui-timepicker-disabled):first');
}
if (selected && selected.length) { if (selected && selected.length) {
var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight(); var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
list.scrollTop(topOffset); list.scrollTop(topOffset);
@ -243,6 +302,8 @@
self.data('timepicker-settings', settings); self.data('timepicker-settings', settings);
_formatValue.call(self.get(0), {'type':'change'}, 'initial');
if (list) { if (list) {
list.remove(); list.remove();
self.data('timepicker-list', false); self.data('timepicker-list', false);
@ -308,7 +369,9 @@
prettyTime = value; prettyTime = value;
} }
_setTimeValue(self, prettyTime);
self.val(prettyTime);
_formatValue.call(self.get(0), {'type':'change'}, 'initial');
if (self.data('timepicker-list')) { if (self.data('timepicker-list')) {
_setSelected(self, self.data('timepicker-list')); _setSelected(self, self.data('timepicker-list'));
} }
@ -507,8 +570,8 @@
row.text(timeString); row.text(timeString);
} else { } else {
var row = $('<li />'); var row = $('<li />');
row.addClass(timeInt % 86400 < 43200 ? 'ui-timepicker-am' : 'ui-timepicker-pm');
row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
row.addClass((timeInt % _ONE_DAY) < (_ONE_DAY / 2) ? 'ui-timepicker-am' : 'ui-timepicker-pm');
row.data('time', _moduloSeconds(timeInt, settings));
row.text(timeString); row.text(timeString);
} }
@ -570,7 +633,7 @@
appendTo.append(wrapped_list); appendTo.append(wrapped_list);
_setSelected(self, list); _setSelected(self, list);
list.on('mousedown touchstart', 'li', function(e) {
list.on('mousedown click', 'li', function(e) {
// hack: temporarily disable the focus handler // hack: temporarily disable the focus handler
// to deal with the fact that IE fires 'focus' // to deal with the fact that IE fires 'focus'
@ -592,8 +655,8 @@
if (_selectValue(self)) { if (_selectValue(self)) {
self.trigger('hideTimepicker'); self.trigger('hideTimepicker');
list.on('mouseup.timepicker touchend.timepicker', 'li', function(e) {
list.off('mouseup.timepicker touchend.timepicker');
list.on('mouseup.timepicker click.timepicker', 'li', function(e) {
list.off('mouseup.timepicker click.timepicker');
wrapped_list.hide(); wrapped_list.hide();
}); });
} }
@ -640,13 +703,21 @@
// event handler to decide whether to close timepicker // event handler to decide whether to close timepicker
function _closeHandler(e) function _closeHandler(e)
{ {
if (e.target == window) {
// mobile Chrome fires focus events against window for some reason
return;
}
var target = $(e.target); var target = $(e.target);
var input = target.closest('.ui-timepicker-input');
if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
methods.hide();
$(document).unbind('.ui-timepicker');
$(window).unbind('.ui-timepicker');
if (target.closest('.ui-timepicker-input').length || target.closest('.ui-timepicker-wrapper').length) {
// active timepicker was focused. ignore
return;
} }
methods.hide();
$(document).unbind('.ui-timepicker');
$(window).unbind('.ui-timepicker');
} }
function _hideKeyboard(self) function _hideKeyboard(self)
@ -685,7 +756,8 @@
{ {
list.find('li').removeClass('ui-timepicker-selected'); list.find('li').removeClass('ui-timepicker-selected');
var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
var settings = self.data('timepicker-settings');
var timeValue = _time2int(_getTimeValue(self), settings);
if (timeValue === null) { if (timeValue === null) {
return; return;
} }
@ -699,19 +771,26 @@
list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight()); list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
} }
selected.addClass('ui-timepicker-selected');
if (settings.forceRoundTime || selected.data('time') === timeValue) {
selected.addClass('ui-timepicker-selected');
}
} }
} }
function _formatValue(e, origin) function _formatValue(e, origin)
{ {
if (this.value === '' || origin == 'timepicker') {
if (origin == 'timepicker') {
return; return;
} }
var self = $(this); var self = $(this);
if (this.value === '') {
_setTimeValue(self, null, origin);
return;
}
if (self.is(':focus') && (!e || e.type != 'change')) { if (self.is(':focus') && (!e || e.type != 'change')) {
return; return;
} }
@ -726,8 +805,8 @@
var rangeError = false; var rangeError = false;
// check that the time in within bounds // check that the time in within bounds
if (settings.minTime !== null && seconds < settings.minTime
&& settings.maxTime !== null && seconds > settings.maxTime) {
if ((settings.minTime !== null && settings.maxTime !== null)
&& (seconds < settings.minTime || seconds > settings.maxTime)) {
rangeError = true; rangeError = true;
} }
@ -740,17 +819,21 @@
}); });
if (settings.forceRoundTime) { if (settings.forceRoundTime) {
seconds = settings.roundingFunction(seconds, settings);
var roundSeconds = settings.roundingFunction(seconds, settings);
if (roundSeconds != seconds) {
seconds = roundSeconds;
origin = null;
}
} }
var prettyTime = _int2time(seconds, settings); var prettyTime = _int2time(seconds, settings);
if (rangeError) { if (rangeError) {
if (_setTimeValue(self, prettyTime, 'error')) {
if (_setTimeValue(self, prettyTime, 'error') || e && e.type == 'change') {
self.trigger('timeRangeError'); self.trigger('timeRangeError');
} }
} else { } else {
_setTimeValue(self, prettyTime);
_setTimeValue(self, prettyTime, origin);
} }
} }
@ -779,7 +862,7 @@
self.data('ui-timepicker-value', value); self.data('ui-timepicker-value', value);
if (source == 'select') { if (source == 'select') {
self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker'); self.trigger('selectTime').trigger('changeTime').trigger('change', 'timepicker');
} else if (source != 'error') {
} else if (['error', 'initial'].indexOf(source) == -1) {
self.trigger('changeTime'); self.trigger('changeTime');
} }
@ -830,6 +913,7 @@
case 13: // return case 13: // return
if (_selectValue(self)) { if (_selectValue(self)) {
_formatValue.call(self.get(0), {'type':'change'});
methods.hide.apply(this); methods.hide.apply(this);
} }
@ -909,6 +993,17 @@
return true; return true;
} }
if (e.type === 'paste' || e.type === 'cut') {
setTimeout(function () {
if (settings.typeaheadHighlight) {
_setSelected(self, list);
} else {
list.hide();
}
}, 0);
return;
}
switch (e.keyCode) { switch (e.keyCode) {
case 96: // numpad numerals case 96: // numpad numerals
@ -1124,10 +1219,11 @@
return null; return null;
} }
var unboundedHour = parseInt(time[2]*1, 10);
var hour = (unboundedHour > 24) ? unboundedHour % 24 : unboundedHour;
var hour = parseInt(time[2]*1, 10);
var ampm = time[1] || time[5]; var ampm = time[1] || time[5];
var hours = hour; var hours = hour;
var minutes = ( time[3]*1 || 0 );
var seconds = ( time[4]*1 || 0 );
if (hour <= 12 && ampm) { if (hour <= 12 && ampm) {
var isPm = (ampm == _lang.pm || ampm == _lang.PM); var isPm = (ampm == _lang.pm || ampm == _lang.PM);
@ -1137,10 +1233,17 @@
} else { } else {
hours = (hour + (isPm ? 12 : 0)); hours = (hour + (isPm ? 12 : 0));
} }
} else if (settings) {
var t = hour * 3600 + minutes * 60 + seconds;
if (t >= _ONE_DAY + (settings.show2400 ? 1 : 0)) {
if (settings.wrapHours === false) {
return null;
}
hours = hour % 24;
}
} }
var minutes = ( time[3]*1 || 0 );
var seconds = ( time[4]*1 || 0 );
var timeInt = hours*3600 + minutes*60 + seconds; var timeInt = hours*3600 + minutes*60 + seconds;
// if no am/pm provided, intelligently guess based on the scrollDefault // if no am/pm provided, intelligently guess based on the scrollDefault
@ -1158,6 +1261,14 @@
return ("0" + n).slice(-2); return ("0" + n).slice(-2);
} }
function _moduloSeconds(seconds, settings) {
if (seconds == _ONE_DAY && settings.show2400) {
return seconds;
}
return seconds%_ONE_DAY;
}
// Plugin entry // Plugin entry
$.fn.timepicker = function(method) $.fn.timepicker = function(method)
{ {
@ -1172,54 +1283,4 @@
else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); } else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); } else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
}; };
// Global defaults
$.fn.timepicker.defaults = {
appendTo: 'body',
className: null,
closeOnWindowScroll: false,
disableTextInput: false,
disableTimeRanges: [],
disableTouchKeyboard: false,
durationTime: null,
forceRoundTime: false,
maxTime: null,
minTime: null,
noneOption: false,
orientation: 'l',
roundingFunction: function(seconds, settings) {
if (seconds === null) {
return null;
} else if (typeof settings.step !== "number") {
// TODO: nearest fit irregular steps
return seconds;
} else {
var offset = seconds % (settings.step*60); // step is in minutes
if (offset >= settings.step*30) {
// if offset is larger than a half step, round up
seconds += (settings.step*60) - offset;
} else {
// round down
seconds -= offset;
}
if (seconds == _ONE_DAY && settings.show2400) {
return seconds;
}
return seconds%_ONE_DAY;
}
},
scrollDefault: null,
selectOnBlur: false,
show2400: false,
showDuration: false,
showOn: ['click', 'focus'],
showOnFocus: true,
step: 30,
stopScrollPropagation: false,
timeFormat: 'g:ia',
typeaheadHighlight: true,
useSelect: false
};
}));
}));

4
web_widget_timepicker/static/src/xml/web_widget_timepicker.xml

@ -2,7 +2,7 @@
<templates id="template" xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-name="TimePickerField"> <t t-name="TimePickerField">
<span t-att-class="'oe_form_field '+widget.widget_class" t-att-style="widget.node.attrs.style">
<span t-att-class="'o_form_field '+widget.widget_class" t-att-style="widget.node.attrs.style">
<t t-if="!widget.get('effective_readonly')"> <t t-if="!widget.get('effective_readonly')">
<input t-att-type="'text'" <input t-att-type="'text'"
class="o_timepicker_input" class="o_timepicker_input"
@ -14,7 +14,7 @@
<span class="fa fa-clock-o o_timepicker_button"/> <span class="fa fa-clock-o o_timepicker_button"/>
</t> </t>
<t t-if="widget.get('effective_readonly')"> <t t-if="widget.get('effective_readonly')">
<span class="oe_form_time_content"></span>
<span class="o_form_time_content"/>
</t> </t>
</span> </span>
</t> </t>

28
web_widget_timepicker/views/web_widget_timepicker_assets.xml

@ -1,14 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="web_widget_timepicker_assets_backend" name="web_widget_timepicker assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.js"></script>
<script type="text/javascript" src="/web_widget_timepicker/static/src/js/web_widget_timepicker.js"></script>
<link rel="stylesheet" href="/web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.css"/>
<link rel="stylesheet" href="/web_widget_timepicker/static/src/css/web_widget_timepicker.css"/>
</xpath>
</template>
</data>
</openerp>
<odoo>
<template id="web_widget_timepicker_assets_backend"
name="web_widget_timepicker assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript"
src="/web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.js"/>
<script type="text/javascript"
src="/web_widget_timepicker/static/src/js/web_widget_timepicker.js"/>
<link rel="stylesheet"
href="/web_widget_timepicker/static/src/lib/jquery.timepicker/jquery.timepicker.css"/>
<link rel="stylesheet"
href="/web_widget_timepicker/static/src/css/web_widget_timepicker.css"/>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save