Add new TimeFieldRenderer, make it default for Time fields
Uses a jQuery UI widget similar to datepicker: https://fgelinas.com/code/timepicker/
This commit is contained in:
parent
e13a58e808
commit
0f3f39d5c6
|
@ -137,6 +137,7 @@ def make_pyramid_config(settings):
|
|||
formalchemy.FieldSet.default_renderers[sa.Boolean] = renderers.YesNoFieldRenderer
|
||||
formalchemy.FieldSet.default_renderers[sa.Date] = renderers.DateFieldRenderer
|
||||
formalchemy.FieldSet.default_renderers[sa.DateTime] = renderers.DateTimeFieldRenderer
|
||||
formalchemy.FieldSet.default_renderers[sa.Time] = renderers.TimeFieldRenderer
|
||||
formalchemy.FieldSet.default_renderers[GPCType] = renderers.GPCFieldRenderer
|
||||
|
||||
return config
|
||||
|
|
|
@ -30,7 +30,7 @@ from .core import CustomFieldRenderer, DateFieldRenderer
|
|||
|
||||
from .common import (AutocompleteFieldRenderer,
|
||||
DecimalFieldRenderer, CurrencyFieldRenderer,
|
||||
DateTimeFieldRenderer, DateTimePrettyFieldRenderer,
|
||||
DateTimeFieldRenderer, DateTimePrettyFieldRenderer, TimeFieldRenderer,
|
||||
EnumFieldRenderer, YesNoFieldRenderer)
|
||||
|
||||
from .people import (PersonFieldRenderer, PersonFieldLinkRenderer,
|
||||
|
|
|
@ -26,7 +26,14 @@ Common Field Renderers
|
|||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
|
||||
from rattail.time import localtime
|
||||
|
||||
import formalchemy
|
||||
from formalchemy import helpers
|
||||
from formalchemy.fields import FieldRenderer, SelectFieldRenderer, CheckBoxFieldRenderer
|
||||
from pyramid.renderers import render
|
||||
|
||||
|
@ -102,6 +109,51 @@ class DateTimePrettyFieldRenderer(formalchemy.DateTimeFieldRenderer):
|
|||
return pretty_datetime(self.request.rattail_config, value)
|
||||
|
||||
|
||||
class TimeFieldRenderer(formalchemy.TimeFieldRenderer):
|
||||
"""
|
||||
Custom renderer for time fields. In edit mode, renders a simple text
|
||||
input, which is expected to become a 'timepicker' widget in the UI.
|
||||
However the particular magic required for that lives in 'tailbone.js'.
|
||||
"""
|
||||
format = '%I:%M %p'
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('class_', 'timepicker')
|
||||
return helpers.text_field(self.name, value=self.value, **kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
return self.render_value(self.raw_value)
|
||||
|
||||
def render_value(self, value):
|
||||
value = self.convert_value(value)
|
||||
if isinstance(value, datetime.time):
|
||||
return value.strftime(self.format)
|
||||
return ''
|
||||
|
||||
def convert_value(self, value):
|
||||
if isinstance(value, datetime.datetime):
|
||||
if not value.tzinfo:
|
||||
value = pytz.utc.localize(value)
|
||||
return localtime(self.request.rattail_config, value).time()
|
||||
return value
|
||||
|
||||
def stringify_value(self, value, as_html=False):
|
||||
if not as_html:
|
||||
return self.render_value(value)
|
||||
return super(TimeFieldRenderer, self).stringify_value(value, as_html=as_html)
|
||||
|
||||
def _serialized_value(self):
|
||||
return self.params.getone(self.name)
|
||||
|
||||
def deserialize(self):
|
||||
value = self._serialized_value()
|
||||
if value:
|
||||
try:
|
||||
return datetime.datetime.strptime(value, self.format).time()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
class EnumFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Renderer for simple enumeration fields.
|
||||
|
|
57
tailbone/static/css/jquery.ui.timepicker.css
vendored
Normal file
57
tailbone/static/css/jquery.ui.timepicker.css
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Timepicker stylesheet
|
||||
* Highly inspired from datepicker
|
||||
* FG - Nov 2010 - Web3R
|
||||
*
|
||||
* version 0.0.3 : Fixed some settings, more dynamic
|
||||
* version 0.0.4 : Removed width:100% on tables
|
||||
* version 0.1.1 : set width 0 on tables to fix an ie6 bug
|
||||
*/
|
||||
|
||||
.ui-timepicker-inline { display: inline; }
|
||||
|
||||
#ui-timepicker-div { padding: 0.2em; }
|
||||
.ui-timepicker-table { display: inline-table; width: 0; }
|
||||
.ui-timepicker-table table { margin:0.15em 0 0 0; border-collapse: collapse; }
|
||||
|
||||
.ui-timepicker-hours, .ui-timepicker-minutes { padding: 0.2em; }
|
||||
|
||||
.ui-timepicker-table .ui-timepicker-title { line-height: 1.8em; text-align: center; }
|
||||
.ui-timepicker-table td { padding: 0.1em; width: 2.2em; }
|
||||
.ui-timepicker-table th.periods { padding: 0.1em; width: 2.2em; }
|
||||
|
||||
/* span for disabled cells */
|
||||
.ui-timepicker-table td span {
|
||||
display:block;
|
||||
padding:0.2em 0.3em 0.2em 0.5em;
|
||||
width: 1.2em;
|
||||
|
||||
text-align:right;
|
||||
text-decoration:none;
|
||||
}
|
||||
/* anchors for clickable cells */
|
||||
.ui-timepicker-table td a {
|
||||
display:block;
|
||||
padding:0.2em 0.3em 0.2em 0.5em;
|
||||
width: 1.2em;
|
||||
cursor: pointer;
|
||||
text-align:right;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
|
||||
/* buttons and button pane styling */
|
||||
.ui-timepicker .ui-timepicker-buttonpane {
|
||||
background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0;
|
||||
}
|
||||
.ui-timepicker .ui-timepicker-buttonpane button { margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
||||
/* The close button */
|
||||
.ui-timepicker .ui-timepicker-close { float: right }
|
||||
|
||||
/* the now button */
|
||||
.ui-timepicker .ui-timepicker-now { float: left; }
|
||||
|
||||
/* the deselect button */
|
||||
.ui-timepicker .ui-timepicker-deselect { float: left; }
|
||||
|
||||
|
1496
tailbone/static/js/lib/jquery.ui.timepicker.js
vendored
Normal file
1496
tailbone/static/js/lib/jquery.ui.timepicker.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -112,6 +112,13 @@ $(function() {
|
|||
$('input[type=submit]').button();
|
||||
$('input[type=reset]').button();
|
||||
|
||||
/*
|
||||
* Apply timepicker behavior to text inputs which are marked for it.
|
||||
*/
|
||||
$('input[type=text].timepicker').timepicker({
|
||||
showPeriod: true
|
||||
});
|
||||
|
||||
/*
|
||||
* When filter labels are clicked, (un)check the associated checkbox.
|
||||
*/
|
||||
|
|
|
@ -131,6 +131,7 @@
|
|||
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')}
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.menubar.js'))}
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.loadmask.min.js'))}
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/lib/jquery.ui.timepicker.js'))}
|
||||
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
|
||||
</%def>
|
||||
|
||||
|
@ -139,6 +140,7 @@
|
|||
${self.jquery_theme()}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.ui.menubar.css'))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.loadmask.css'))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.ui.timepicker.css'))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.ui.tailbone.css'))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))}
|
||||
${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))}
|
||||
|
|
Loading…
Reference in a new issue