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:
Lance Edgar 2016-03-24 00:06:04 -05:00
parent e13a58e808
commit 0f3f39d5c6
7 changed files with 1616 additions and 1 deletions

View file

@ -137,6 +137,7 @@ def make_pyramid_config(settings):
formalchemy.FieldSet.default_renderers[sa.Boolean] = renderers.YesNoFieldRenderer formalchemy.FieldSet.default_renderers[sa.Boolean] = renderers.YesNoFieldRenderer
formalchemy.FieldSet.default_renderers[sa.Date] = renderers.DateFieldRenderer formalchemy.FieldSet.default_renderers[sa.Date] = renderers.DateFieldRenderer
formalchemy.FieldSet.default_renderers[sa.DateTime] = renderers.DateTimeFieldRenderer formalchemy.FieldSet.default_renderers[sa.DateTime] = renderers.DateTimeFieldRenderer
formalchemy.FieldSet.default_renderers[sa.Time] = renderers.TimeFieldRenderer
formalchemy.FieldSet.default_renderers[GPCType] = renderers.GPCFieldRenderer formalchemy.FieldSet.default_renderers[GPCType] = renderers.GPCFieldRenderer
return config return config

View file

@ -30,7 +30,7 @@ from .core import CustomFieldRenderer, DateFieldRenderer
from .common import (AutocompleteFieldRenderer, from .common import (AutocompleteFieldRenderer,
DecimalFieldRenderer, CurrencyFieldRenderer, DecimalFieldRenderer, CurrencyFieldRenderer,
DateTimeFieldRenderer, DateTimePrettyFieldRenderer, DateTimeFieldRenderer, DateTimePrettyFieldRenderer, TimeFieldRenderer,
EnumFieldRenderer, YesNoFieldRenderer) EnumFieldRenderer, YesNoFieldRenderer)
from .people import (PersonFieldRenderer, PersonFieldLinkRenderer, from .people import (PersonFieldRenderer, PersonFieldLinkRenderer,

View file

@ -26,7 +26,14 @@ Common Field Renderers
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
import datetime
import pytz
from rattail.time import localtime
import formalchemy import formalchemy
from formalchemy import helpers
from formalchemy.fields import FieldRenderer, SelectFieldRenderer, CheckBoxFieldRenderer from formalchemy.fields import FieldRenderer, SelectFieldRenderer, CheckBoxFieldRenderer
from pyramid.renderers import render from pyramid.renderers import render
@ -102,6 +109,51 @@ class DateTimePrettyFieldRenderer(formalchemy.DateTimeFieldRenderer):
return pretty_datetime(self.request.rattail_config, value) 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): class EnumFieldRenderer(SelectFieldRenderer):
""" """
Renderer for simple enumeration fields. Renderer for simple enumeration fields.

View 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; }

File diff suppressed because it is too large Load diff

View file

@ -112,6 +112,13 @@ $(function() {
$('input[type=submit]').button(); $('input[type=submit]').button();
$('input[type=reset]').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. * When filter labels are clicked, (un)check the associated checkbox.
*/ */

View file

@ -131,6 +131,7 @@
${h.javascript_link('https://code.jquery.com/ui/1.11.4/jquery-ui.min.js')} ${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.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.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'))} ${h.javascript_link(request.static_url('tailbone:static/js/tailbone.js'))}
</%def> </%def>
@ -139,6 +140,7 @@
${self.jquery_theme()} ${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.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.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/jquery.ui.tailbone.css'))}
${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))} ${h.stylesheet_link(request.static_url('tailbone:static/css/base.css'))}
${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))} ${h.stylesheet_link(request.static_url('tailbone:static/css/layout.css'))}