datefieldplugin/0000755000000000000000000000000013116261261012713 5ustar rootrootdatefieldplugin/1.0/0000755000000000000000000000000013040762547013222 5ustar rootrootdatefieldplugin/1.0/AUTHORS0000644000000000000000000000037511713424431014267 0ustar rootrootFounder: coderanger Maintainer: doki_pen Contributers: * butterflow * coderanger * doki_pen * rjollos * remy.blank@pobox.com * terje If you were left off of this lift by accident, please email me and I will correct it. datefieldplugin/1.0/.gitignore0000644000000000000000000000004211303305405015170 0ustar rootroot*.egg-info *.pyc .stgit-edit.diff datefieldplugin/1.0/setup.cfg0000644000000000000000000000002712576120422015033 0ustar rootroot[egg_info] tag_build = datefieldplugin/1.0/COPYING0000644000000000000000000000263512437634671014270 0ustar rootrootCopyright (C) 2007-2008 Noah Kantrowitz All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. datefieldplugin/1.0/setup.py0000644000000000000000000000175013040762547014737 0ustar rootroot#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (C) 2007-2008 Noah Kantrowitz # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. # from setuptools import setup setup( name='TracDateField', version='3.0.0', author='Noah Kantrowitz', author_email='noah@coderanger.net', maintainer='Ryan J Ollos', maintainer_email='ryan.j.ollos@gmail.com', description='Add custom date fields to Trac tickets.', license='3-Clause BSD', keywords='trac plugin ticket', url='https://trac-hacks.org/wiki/DateFieldPlugin', packages=['datefield'], package_data={'datefield': [ 'htdocs/css/*.css', 'htdocs/js/*.js', 'htdocs/css/images/*.png' ]}, install_requires=['Trac'], classifiers=[ 'Framework :: Trac', ], entry_points={ 'trac.plugins': [ 'datefield.filter = datefield.filter', ] }, ) datefieldplugin/1.0/datefield/0000755000000000000000000000000013040762547015143 5ustar rootrootdatefieldplugin/1.0/datefield/__init__.py0000644000000000000000000000007513040762547017256 0ustar rootrootimport pkg_resources pkg_resources.require('Trac>=1.0,<1.2') datefieldplugin/1.0/datefield/filter.py0000644000000000000000000001672712437634671017024 0ustar rootroot#!/usr/bin/env python # -*- coding: utf-8 -*- # # Copyright (C) 2007-2008 Noah Kantrowitz # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. # from trac.core import * from trac.web.api import IRequestFilter, ITemplateStreamFilter from trac.web.chrome import Chrome, ITemplateProvider, add_script, \ add_script_data, add_stylesheet from trac.ticket.api import ITicketManipulator from trac.config import Option, IntOption, BoolOption, ListOption from genshi.builder import tag from genshi.filters.transform import Transformer import time from traceback import format_exc import re class DateFieldModule(Component): """A module providing a JS date picker for custom fields.""" date_format = Option('datefield', 'format', default='dmy', doc='The format to use for dates. Valid values are dmy, mdy, and ymd.') first_day = IntOption('datefield', 'first_day', default=0, doc='First day of the week. 0 == Sunday.') date_sep = Option('datefield', 'separator', default='/', doc='The separator character to use for dates.') show_week = BoolOption('datefield', 'weeknumbers', default='false', doc='Show ISO8601 week number in calendar?') show_panel = BoolOption('datefield', 'panel', default='false', doc='Show button panel at bottom? (Today, Done)') change_month = BoolOption('datefield', 'change_month', default='false', doc='Show a month dropdown in datepicker?') change_year = BoolOption('datefield', 'change_year', default='false', doc='Show a year dropdown in datepicker?') num_months = IntOption('datefield', 'months', default='1', doc='Number of months visible in datepicker') match_req = ListOption('datefield', 'match_request', default='', doc='Additional request paths to match (use input class="datepick")') implements(IRequestFilter, ITemplateProvider, ITemplateStreamFilter, ITicketManipulator) # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): def attr_callback(name, event): attrs = event[1][1] return ' '.join(filter(None, (attrs.get('class'), 'datepick'))) if filename == 'ticket.html': for field in list(self._date_fields()): stream = stream | Transformer( '//input[@name="field_' + field + '"]' ).attr('class', attr_callback) return stream # IRequestFilter methods def pre_process_request(self, req, handler): return handler def post_process_request(self, req, template, data, content_type): if template == 'ticket.html': format = { 'dmy': 'dd%smm%syy', 'mdy': 'mm%sdd%syy', 'ymd': 'yy%smm%sdd', }.get(self.date_format, 'dd%smm%syy') format %= (self.date_sep, self.date_sep) add_script_data(req, {'datefield': { 'calendar': req.href.chrome('common', 'ics.png'), 'format': format, 'first_day': self.first_day, 'show_week': self.show_week, 'show_panel': self.show_panel, 'num_months': self.num_months, 'change_month': self.change_month, 'change_year': self.change_year }}) add_script(req, 'datefield/js/datefield.js') Chrome(self.env).add_jquery_ui(req) return template, data, content_type # ITemplateProvider methods def get_htdocs_dirs(self): from pkg_resources import resource_filename return [('datefield', resource_filename(__name__, 'htdocs'))] def get_templates_dirs(self): return [] # ITicketManipulator methods def prepare_ticket(self, req, ticket, fields, actions): pass def validate_ticket(self, req, ticket): # dmy mdy ymd for field in self._date_fields(): try: val = (ticket[field] or u'').strip() date_empty = self.config['ticket-custom'] \ .getbool(field + '.date_empty') if not val and date_empty: continue if self.date_sep and len(self.date_sep.strip()) > 0: if len(val.split(self.date_sep)) != 3: raise Exception # Token exception to force failure else: if re.match('.*[^\d].*', val.strip()): raise Exception format = self.date_sep.join(['%'+c for c in self.date_format]) try: time.strptime(val, format) except ValueError: time.strptime(val, format.replace('y', 'Y')) except Exception: self.log.warn("DateFieldModule: Got an exception, assuming " "it is a validation failure.\n%s", format_exc()) yield field, 'Field %s does not seem to look like a date. ' \ 'The correct format is %s.' % \ (field, self.date_sep.join([c.upper()*(c == 'y' and 4 or 2) for c in self.date_format])) # Internal methods def _date_fields(self): # XXX: Will this work when there is no ticket-custom section? for key, value in self.config['ticket-custom'].options(): if key.endswith('.date') and value == "true": yield key.split('.', 1)[0] class CustomFieldAdminTweak(Component): implements(ITemplateStreamFilter, IRequestFilter) # IRequestFilter methods def pre_process_request(self, req, handler): if req.method == "POST" and \ req.href.endswith(u'/admin/ticket/customfields'): if req.args.get('type') == 'date': req.args['type'] = 'text' self.config.set('ticket-custom', '%s.date' % req.args.get('name'), 'true') self.config.set('ticket-custom', '%s.date_empty' % req.args.get('name'), req.args.get('date_empty', 'false')) return handler def post_process_request(self, template, content_type): return template, content_type # ITemplateStreamFilter methods def filter_stream(self, req, method, filename, stream, data): if filename == "customfieldadmin.html": add_script(req, 'datefield/js/customfield-admin.js') add_stylesheet(req, 'datefield/css/customfield-admin.css') stream = stream | Transformer('.//select[@id="type"]').append( tag.option('Date', value='date', id="date_type_option") ) stream = stream | Transformer( './/form[@id="addcf"]/fieldset/div[@class="buttons"]' ).before( tag.div( tag.input( id="date_empty", type="checkbox", name="date_empty" ), tag.label('Allow empty date'), for_="date_empty", class_="field", id="date_empty_option" ) ) return stream datefieldplugin/1.0/datefield/htdocs/0000755000000000000000000000000012576117723016432 5ustar rootrootdatefieldplugin/1.0/datefield/htdocs/js/0000755000000000000000000000000012576117723017046 5ustar rootrootdatefieldplugin/1.0/datefield/htdocs/js/datefield.js0000644000000000000000000000120212576117723021320 0ustar rootrootjQuery(document).ready(function($) { var $fields = $('.datepick'); $fields.datepicker({ firstDay: datefield['first_day'], dateFormat: datefield['format'], showOn: "both", weekHeader: 'W', showWeek: datefield['show_week'], showButtonPanel: datefield['show_panel'], numberOfMonths: datefield['num_months'], changeMonth: datefield['change_month'], changeYear: datefield['change_year'], buttonImage: datefield['calendar'], buttonImageOnly: true }); $fields.each(function() { var $field = $(this); if ($field.val() == "") { $field.datepicker('setDate', '-0d'); } }) }); datefieldplugin/1.0/datefield/htdocs/js/customfield-admin.js0000644000000000000000000000036712437634671023020 0ustar rootrootjQuery(document).ready(function($) { $('#date_empty_option').hide(); $('#type').change(function() { if ($('#type').val() == 'date') { $('#date_empty_option').show(); } else { $('#date_empty_option').hide(); } }); }); datefieldplugin/1.0/datefield/htdocs/css/0000755000000000000000000000000012437634671017224 5ustar rootrootdatefieldplugin/1.0/datefield/htdocs/css/images/0000755000000000000000000000000011713110562020451 5ustar rootrootdatefieldplugin/1.0/datefield/htdocs/css/images/ui-bg_flat_75_ffffff_40x100.png0000644000000000000000000000026211670534030025724 0ustar rootrootPNG  IHDR(ddrzyIDATh1 R 7(ȚV`%X V`%X V`%X V`%X V`%X V`%X V`%X V`%X V`%X V`%X V`%X V`%X Vj)2NIENDB`datefieldplugin/1.0/datefield/htdocs/css/images/ui-icons_004276_256x240.png0000644000000000000000000001042111670544633024553 0ustar rootrootPNG  IHDRIJPLTEBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtBtY<NtRNS2P."Tp@f` <BHJZ&0R,4j8D|($ blߝF>n~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?sn~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?sn~hhHIDATx]b۶H儒-{iZK:glkn-tIqq? E$dK>$>;PZsVh!Sy0E0}H)-t koܪKp\RϠ .E7 ) *V;~Pe Bx*,=$zDؾ JҸٻ9{ ǸHpqW@"2'B[$ @TiH/b٥96!XHq`DE*R HV!%;" i] dddddddd4y5  Rb@(8CdŪݡ,@T@ibrq0alX!pe, =4bW { 5Ƭhu~(Q^@3="b5XC@JCT76q_5 @,r šɩD)T|O@ ON-ՙ [n@RXIm݋(F @?=0puL;g$@6η K`>п @h գKVn"a" %l@.v$/U^ G:#`` uTtK~ŋZ5T%kxk]\*Q ,҇B44 OXK|yg+_M(lоEO V$T1BXb-|?@ fBXr%'@ҹA\IJ,}BBc\V rh(]tI^}oצo S3 ";ʙb}"߰ ){b$Gwwݾab")T@pF_er6JvШ"mޭM-d76x˰6ӥ;/`>KrP\_^u1%OTM.}Q3.Nس})>-w`a+sy$t)NbFFFFBejnNVn4,A*X*5>PGa 3 {oB &<L[ Nc.öi=`Q@d ͆I.Il`\t[< Cit484-r +f쑱BCB MH iy }>rxp|z;BǏ;burcK4tz1G~`ؚK| ̔>ۡO$~ Ao)0pzz }i`;ADm8n:cfA@s7L Z/..h8or? N93B~o_'`opO- :TG L;7]`B%˛>*wTpM0H}&t ^1'Oqr'2P͡+z,tIW''|en=dzgRm[NStK{҉mؓVt6ҲR`ζN&}B U(rۗ&1%Q''?l׸+&r{jN಻4) `N狌. ߭ ǣ)q 2?n3Hb`} .`pqY1e_bu7e+N_F(DT,L}LLrmP5|x芥1cx DAb`M(7NED~Mz +4BXd.Mzv͈Pd8p<6?8N*x.6ڍ6GFZ)O !lSshssNp8`'0/<s}.@Ǩs7ξO۟VDa5av]m1+3y6۠>@u50Ps51==p *KVҫ܂ݻc$N4(Xr2###c- 賟Lδ>]5.sYs1f0;'̨Yg銛{@9 `aC(=%bo2=n1 jBoS$n#m=i0ci9}oI qT]W%.(؅]z\x f"]o'u䫵tk{v;AC3ֆwwR_#X (xҋ/q%W hpk_IX'b/fXKi"#####QCLi2t 5L0 QiH2;yTOok;ע ٶ`RNg{zy!Kxm?A(vU~mL(`o/!nmX-{v[ dw=n「sdwzn(}Oy~ m ?XU;,V'+ V&JRZ]᧭:zC'-߆@y 4u `Vۓwъ#zP@Q N>2/{\o)W~a3xLw :_Q;=pּdt\'8~3SRP6y+XQ*޺r ̗ѭ*޺r gl/\U^u$|mbVnw \V|D͊NVNy7k<;/E}?E*dzgO ~g/96f cD}% g$QG7o)U Jo,O@0߾Q(;bw:5 NwRN5Iy'K?}:9mֽ*@f@jU9mҫÍ{$ؗ}dFp|%!DdF>}G{@FFFFFFƦQܞH 3 u Mo~vy}mwz<7nP9rWku=|_nz쿳}@IXn?s