Package turbogears :: Package widgets :: Module big_widgets

Source Code for Module turbogears.widgets.big_widgets

  1  import itertools 
  2  from datetime import datetime 
  3   
  4  from turbogears import validators, expose 
  5  from turbojson import jsonify 
  6  from turbogears.widgets.base import CSSLink, JSLink, CSSSource, JSSource, \ 
  7                                      Widget, WidgetsList, static, mochikit, \ 
  8                                      CoreWD 
  9  from turbogears.widgets.i18n import CalendarLangFileLink 
 10  from turbogears.widgets.forms import FormField, CompoundFormField, TextField, \ 
 11                                      HiddenField, TableForm, CheckBox, \ 
 12                                      RadioButtonList 
 13  from turbogears.widgets.rpc import RPC 
 14   
 15  __all__ = ["CalendarDatePicker", "CalendarDateTimePicker", 
 16      "AutoCompleteField", "AutoCompleteTextField", 
 17      "LinkRemoteFunction", "RemoteForm", "AjaxGrid", "URLLink"] 
18 19 20 -class CalendarDatePicker(FormField):
21 """Use a Javascript calendar system to allow picking of calendar dates.""" 22 23 template = """ 24 <span xmlns:py="http://purl.org/kid/ns#" class="${field_class}"> 25 <input type="text" id="${field_id}" class="${field_class}" name="${name}" value="${strdate}" py:attrs="attrs"/> 26 <input type="button" id="${field_id}_trigger" class="date_field_button" value="${button_text}"/> 27 <script type="text/javascript"> 28 Calendar.setup({ 29 inputField : "${field_id}", 30 ifFormat : "${format}", 31 button : "${field_id}_trigger" 32 <span py:if="picker_shows_time" py:replace="', showsTime : true'"/> 33 }); 34 </script> 35 </span> 36 """ 37 params = ["attrs", "skin", "picker_shows_time", "button_text", 38 "format", "calendar_lang"] 39 params_doc = {'attrs': 'Extra attributes', 40 'skin': 'For alternate skins, such as "calendar-blue" or "skins/aqua/theme"', 41 'picker_shows_time': 'Whether the calendar should let you pick a time, too', 42 'button_text': 'Text for the button that will show the calendar picker', 43 'format': 'The date format (default is mm/dd/yyyy)', 44 'calendar_lang': 'The language to be used in the calendar picker.'} 45 attrs = {} 46 skin = "calendar-system" 47 picker_shows_time = False 48 button_text = "Choose" 49 format = "%m/%d/%Y" 50 calendar_lang = None 51 _default = None 52
53 - def __init__(self, name=None, default=None, not_empty=True, 54 calendar_lang=None, validator=None, format=None, **kw):
55 super(CalendarDatePicker, self).__init__(name, **kw) 56 self.not_empty = not_empty 57 if default is not None or not self.not_empty: 58 self._default = default 59 if format is not None: 60 self.format = format 61 if validator is None: 62 self.validator = validators.DateTimeConverter( 63 format=self.format, not_empty=self.not_empty) 64 else: 65 self.validator = validator 66 if calendar_lang: 67 self.calendar_lang = calendar_lang 68 javascript = [JSLink(static, "calendar/calendar.js"), 69 JSLink(static, "calendar/calendar-setup.js")] 70 javascript.append(CalendarLangFileLink(static, 71 language=self.calendar_lang)) 72 self.javascript = self.javascript + javascript 73 if self.skin: 74 css = [CSSLink(static, "calendar/%s.css" % self.skin)] 75 self.css = self.css + css
76
77 - def _get_default(self):
78 if self._default is None and self.not_empty: 79 return datetime.now() 80 return self._default
81 default = property(_get_default) 82
83 - def update_params(self, d):
84 super(CalendarDatePicker, self).update_params(d) 85 if hasattr(d['value'], 'strftime'): 86 d['strdate'] = d['value'].strftime(d['format']) 87 else: 88 d['strdate'] = d['value']
89
90 91 -class CalendarDatePickerDesc(CoreWD):
92 93 name = "Calendar" 94 for_widget = CalendarDatePicker("date_picker")
95
96 97 -class CalendarDateTimePicker(CalendarDatePicker):
98 """Javascript calendar system to allow picking of dates with times.""" 99 100 format = "%Y/%m/%d %H:%M" 101 picker_shows_time = True
102
103 104 -class CalendarDateTimePickerDesc(CoreWD):
105 106 name = "Calendar with time" 107 for_widget = CalendarDateTimePicker("datetime_picker")
108
109 110 -class AutoComplete(Widget):
111 """Mixin class for autocomplete fields. 112 113 Performs Ajax-style autocompletion by requesting search 114 results from the server as the user types. 115 116 """ 117 javascript = [mochikit, JSLink(static,"autocompletefield.js")] 118 css = [CSSLink(static,"autocompletefield.css")] 119 params = ["search_controller", "search_param", "result_name", "attrs", 120 "only_suggest", "complete_delay", "take_focus", "min_chars", "show_spinner"] 121 params_doc = {'attrs': 'Extra attributes', 122 'search_controller': 'Name of the controller returning the auto completions', 123 'search_param': 'Name of the search parameter ("*" passes all form fields)', 124 'result_name': 'Name of the result list returned by the controller', 125 'only_suggest': 'If true, pressing enter does not automatically submit the first list item.', 126 'complete_delay': 'Delay (in seconds) before loading new auto completions', 127 'take_focus': 'If true, take focus on load.', 128 'min_chars': 'Minimum number of characters to type before autocomplete activates', 129 'show_spinner': 'If false, the spinner (load indicator) is not shown.'} 130 attrs = {} 131 search_controller = "" 132 search_param = "searchString" 133 result_name = "textItems" 134 only_suggest = False 135 complete_delay = 0.200 136 take_focus = False 137 min_chars = 1 138 show_spinner = True
139
140 141 -class AutoCompleteField(CompoundFormField, AutoComplete):
142 """Text field with auto complete functionality and hidden key field.""" 143 144 template = """ 145 <span xmlns:py="http://purl.org/kid/ns#" id="${field_id}" class="${field_class}"> 146 <script type="text/javascript"> 147 AutoCompleteManager${field_id} = new AutoCompleteManager('${field_id}', 148 '${text_field.field_id}', '${hidden_field.field_id}', 149 '${search_controller}', '${search_param}', '${result_name}',${str(only_suggest).lower()}, 150 '${show_spinner and tg.url([tg.widgets, 'turbogears.widgets/spinner.gif']) or None}', 151 ${complete_delay}, ${str(take_focus).lower()}, ${min_chars}); 152 addLoadEvent(AutoCompleteManager${field_id}.initialize); 153 </script> 154 ${text_field.display(value_for(text_field), **params_for(text_field))} 155 <img py:if="show_spinner" id="autoCompleteSpinner${field_id}" 156 src="${tg.url([tg.widgets, 'turbogears.widgets/spinnerstopped.png'])}" alt=""/> 157 <span class="autoTextResults" id="autoCompleteResults${field_id}"/> 158 ${hidden_field.display(value_for(hidden_field), **params_for(hidden_field))} 159 </span> 160 """ 161 162 member_widgets = ["text_field", "hidden_field"] 163 text_field = TextField(name="text") 164 hidden_field = HiddenField(name="hidden")
165
166 167 -class AutoCompleteFieldDesc(CoreWD):
168 169 name = "AutoCompleteField" 170 171 codes = """AK AL AR AS AZ CA CO CT DC DE FL FM GA GU HI IA ID IL IN KS 172 KY LA MA MD ME MH MI MN MO MP MS MT NC ND NE NH NJ NM NV NY OH 173 OK OR PA PR PW RI SC SD TN TX UM UT VA VI VT WA WI WV WY""".split() 174 175 states = """Alaska Alabama Arkansas American_Samoa Arizona 176 California Colorado Connecticut District_of_Columbia 177 Delaware Florida Federated_States_of_Micronesia Georgia Guam 178 Hawaii Iowa Idaho Illinois Indiana Kansas Kentucky Louisiana 179 Massachusetts Maryland Maine Marshall_Islands Michigan 180 Minnesota Missouri Northern_Mariana_Islands Mississippi 181 Montana North_Carolina North_Dakota Nebraska New_Hampshire 182 New_Jersey New_Mexico Nevada New_York Ohio Oklahoma Oregon 183 Pennsylvania Puerto_Rico Palau Rhode_Island South_Carolina 184 South_Dakota Tennessee Texas U.S._Minor_Outlying_Islands 185 Utah Virginia Virgin_Islands_of_the_U.S. Vermont Washington 186 Wisconsin West_Virginia Wyoming""".split() 187 states = map(lambda s: s.replace('_', ' '), states) 188 189 state_code = dict(zip(codes, states)) 190 191 template = """ 192 <form xmlns:py="http://purl.org/kid/ns#" onsubmit="if ( 193 this.elements[0].value &amp;&amp; this.elements[1].value) 194 alert('The alpha code for '+this.elements[0].value 195 +' is '+this.elements[1].value+'.');return false"><table> 196 <tr><th>State</th><td py:content="for_widget.display()"/> 197 <td><input type="submit" value="Show alpha code"/></td></tr> 198 </table></form> 199 """ 200 201 full_class_name = "turbogears.widgets.AutoCompleteField" 202
203 - def __init__(self, *args, **kw):
204 super(AutoCompleteFieldDesc, self).__init__(*args, **kw) 205 self.for_widget = AutoCompleteField(name="state_and_code", 206 search_controller="%s/search" % self.full_class_name, 207 search_param="state", result_name="states")
208 209 @expose(format="json")
210 - def search(self, state):
211 states = [] 212 code = state.upper() 213 if code in self.state_code: 214 states.append((self.state_code[code], code)) 215 else: 216 states.extend([s for s in zip(self.states, self.codes) 217 if s[0].lower().startswith(state.lower())]) 218 return dict(states=states)
219
220 221 -class AutoCompleteTextField(TextField, AutoComplete):
222 """Text field with auto complete functionality.""" 223 224 template = """ 225 <span xmlns:py="http://purl.org/kid/ns#" class="${field_class}"> 226 <script type="text/javascript"> 227 AutoCompleteManager${field_id} = new AutoCompleteManager('${field_id}', '${field_id}', null, 228 '${search_controller}', '${search_param}', '${result_name}', ${str(only_suggest).lower()}, 229 '${show_spinner and tg.url([tg.widgets, 'turbogears.widgets/spinner.gif']) or None}', 230 ${complete_delay}, ${str(take_focus).lower()}, ${min_chars}); 231 addLoadEvent(AutoCompleteManager${field_id}.initialize); 232 </script> 233 <input type="text" name="${name}" class="${field_class}" id="${field_id}" 234 value="${value}" py:attrs="attrs"/> 235 <img py:if="show_spinner" id="autoCompleteSpinner${field_id}" 236 src="${tg.url([tg.widgets, 'turbogears.widgets/spinnerstopped.png'])}" alt=""/> 237 <span class="autoTextResults" id="autoCompleteResults${field_id}"/> 238 </span> 239 """
240
241 242 -class AutoCompleteTextFieldDesc(CoreWD):
243 244 name = "AutoCompleteTextField" 245 246 states = AutoCompleteFieldDesc.states 247 state_code = AutoCompleteFieldDesc.state_code 248 249 template = """ 250 <table xmlns:py="http://purl.org/kid/ns#"> 251 <tr><th>State</th><td py:content="for_widget.display()"/></tr> 252 </table> 253 """ 254 255 full_class_name = "turbogears.widgets.AutoCompleteTextField" 256
257 - def __init__(self, *args, **kw):
258 super(AutoCompleteTextFieldDesc, self).__init__(*args, **kw) 259 self.for_widget = AutoCompleteTextField(name="state_only", 260 search_controller="%s/search" % self.full_class_name, 261 search_param="state", result_name="states")
262 263 @expose(format="json")
264 - def search(self, state):
265 states = [] 266 code = state.upper() 267 if code in self.state_code: 268 states.append(self.state_code[code]) 269 else: 270 states.extend([s for s in self.states 271 if s.lower().startswith(state.lower())]) 272 return dict(states=states)
273
274 275 -class LinkRemoteFunction(RPC):
276 """Link with remote execution. 277 278 Returns a link that executes a POST asynchronously 279 and updates a DOM Object with the result of it. 280 281 """ 282 template = """ 283 <a xmlns:py="http://purl.org/kid/ns#" name="${name}" 284 py:attrs="attrs" py:content="value" onclick="${js}" href="#"/> 285 """ 286 287 params = ["attrs"] 288 attrs = {}
289
290 291 -class LinkRemoteFunctionDesc(CoreWD):
292 293 name = "AJAX remote function" 294 295 states = AutoCompleteFieldDesc.states 296 297 template = """ 298 <div id="items"> 299 ${for_widget.display("States starting with the letter 'N'", update="items")} 300 </div> 301 """ 302 303 full_class_name = "turbogears.widgets.LinkRemoteFunction" 304
305 - def __init__(self, *args, **kw):
306 super(LinkRemoteFunctionDesc, self).__init__(*args, **kw) 307 self.for_widget = LinkRemoteFunction( 308 name="linkrf", action="%s/search_linkrf" % self.full_class_name, 309 data = dict(state_starts_with="N"))
310 311 @expose()
312 - def search_linkrf(self, state_starts_with):
313 return '<br/>'.join(filter( 314 lambda item: item.startswith(state_starts_with), self.states))
315
316 317 -class RemoteForm(RPC, TableForm):
318 """AJAX table form. 319 320 A TableForm that submits the data asynchronously and loads the resulting 321 HTML into a DOM object 322 323 """
324 - def update_params(self, d):
325 super(RemoteForm, self).update_params(d) 326 d['form_attrs']['onSubmit'] = "return !remoteFormRequest(this, '%s', %s);" % ( 327 d.get("update", ''), jsonify.encode(self.get_options(d)))
328
329 330 -class RemoteFormDesc(CoreWD):
331 332 name = "AJAX Form" 333
334 - class TestFormFields(WidgetsList):
335 name = TextField() 336 age = TextField() 337 check = CheckBox() 338 radio = RadioButtonList(options=list(enumerate( 339 "Python Java Pascal Ruby".split())), default=3)
340 341 template = """ 342 <div> 343 ${for_widget.display()} 344 <div id="post_data">&nbsp;</div> 345 </div> 346 """ 347 full_class_name = "turbogears.widgets.RemoteForm" 348
349 - def __init__(self, *args, **kw):
350 super(RemoteFormDesc, self).__init__(*args, **kw) 351 self.for_widget = RemoteForm( 352 fields = self.TestFormFields(), 353 name="remote_form", 354 update = "post_data", 355 action = "%s/post_data_rf" % self.full_class_name, 356 before = "alert('pre-hook')", 357 confirm = "Confirm?", 358 )
359 360 @expose()
361 - def post_data_rf(self, **kw):
362 return """Received data:<br/>%r""" % kw
363 364 365 ajaxgridcounter = itertools.count()
366 367 -class AjaxGrid(Widget):
368 """AJAX updateable datagrid based on widget.js grid""" 369 370 template = """<div id="${id}" xmlns:py="http://purl.org/kid/ns#"> 371 <a py:if="refresh_text" 372 href="#" 373 onclick="javascript:${id}_AjaxGrid.refresh(${defaults});return false;"> 374 ${refresh_text} 375 </a> 376 <div id="${id}_update"></div> 377 <script type="text/javascript"> 378 addLoadEvent(partial(${id}_AjaxGrid.refresh, ${defaults})); 379 </script> 380 </div> 381 """ 382 383 params = ["refresh_text", "id", "defaults"] 384 385 defaults = {} 386 refresh_text = "Update" 387 id = "ajaxgrid_%d" % ajaxgridcounter.next() 388
389 - def __init__(self, refresh_url, *args, **kw):
390 super(AjaxGrid, self).__init__(*args, **kw) 391 target = "%s_update" % self.id 392 self.javascript = [ 393 mochikit, 394 JSLink("turbogears", "js/widget.js"), 395 JSLink(static, "ajaxgrid.js"), 396 JSSource(""" 397 %(id)s_AjaxGrid = new AjaxGrid('%(refresh_url)s', '%(target)s'); 398 """ % dict(id=self.id, refresh_url=refresh_url, target=target) 399 ), 400 ]
401
402 - def update_params(self, d):
403 super(AjaxGrid, self).update_params(d) 404 d["defaults"] = jsonify.encode(d["defaults"])
405
406 407 -class AjaxGridDesc(CoreWD):
408 409 name = "AJAX Grid" 410 411 @staticmethod
412 - def facgen(n):
413 total = 1 414 yield 0, 1 415 for x in xrange(1, n+1): 416 total *= x 417 yield x, total
418 419 full_class_name = "turbogears.widgets.AjaxGrid" 420
421 - def __init__(self, *args, **kw):
422 super(AjaxGridDesc, self).__init__(*args, **kw) 423 self.for_widget = AjaxGrid( 424 refresh_url = "%s/update" % self.full_class_name, 425 # Dummy default params, just POC 426 defaults = dict(), 427 ) 428 self.update_count = itertools.count()
429 430 @expose(format="json")
431 - def update(self):
432 return dict( 433 headers = ["N", "fact(N)"], 434 rows = list(self.facgen(self.update_count.next())), 435 )
436 455