1. Matthew Schinckel
  2. django-weekday-field

Commits

Matthew Schinckel  committed 88af561

Added an AdvancedWeekdayFormField.
This has (Any/All, Weekday, Weekend) in addition to the
regular day choices, and contains a nice script so that
changing the selection in a page ensures they grouped
ones update as well.

  • Participants
  • Parent commits f075f68
  • Branches default

Comments (0)

Files changed (5)

File setup.py

View file
  • Ignore whitespace
     packages = [
         "weekday_field",
     ],
+    package_data = {
+        '': ['static/weekday_field/js/*.js'],
+    },
     classifiers = [
         'Programming Language :: Python',
         'License :: OSI Approved :: BSD License',

File weekday_field/forms.py

View file
  • Ignore whitespace
 from django import forms
 
-import utils
 import operator
 
+from weekday_field import utils, widgets
+
 class WeekdayFormField(forms.TypedMultipleChoiceField):
     def __init__(self, *args, **kwargs):
         if 'choices' not in kwargs:
         super(WeekdayFormField, self).__init__(*args, **kwargs)
         
     def clean(self, value):
-      value = super(WeekdayFormField, self).clean(value)
-      return value
+        if isinstance(value, basestring):
+            value = map(int, value.split(','))
+        value = super(WeekdayFormField, self).clean(value)
+        return value
+
+class AdvancedWeekdayFormField(WeekdayFormField):
+    def __init__(self, *args, **kwargs):
+        if 'choices' not in kwargs:
+            kwargs['choices'] = utils.ADVANCED_DAY_CHOICES
+        if 'widget' not in kwargs:
+            kwargs['widget'] = widgets.ToggleCheckboxes
+        super(AdvancedWeekdayFormField, self).__init__(*args, **kwargs)
+    
+    def clean(self, value):
+        value = super(AdvancedWeekdayFormField, self).clean(value)
+        if map(int,value) == range(7):
+            return []
+        return value
 
 class BitwiseWeekdayFormField(WeekdayFormField):
-  def __init__(self, *args, **kwargs):
-    if 'short' in kwargs:
-      if kwargs['short']:
-        kwargs['choices'] = [(x[0],x[1]) for x in utils.BITWISE_DAY_CHOICES]
-      del kwargs['short']
-    else:
-      kwargs['choices'] = [(x[0],x[2]) for x in utils.BITWISE_DAY_CHOICES]
-    super(BitwiseWeekdayFormField, self).__init__(*args, **kwargs)
+    def __init__(self, *args, **kwargs):
+        if 'short' in kwargs:
+            if kwargs['short']:
+                kwargs['choices'] = [(x[0],x[1]) for x in utils.BITWISE_DAY_CHOICES]
+            del kwargs['short']
+        else:
+            kwargs['choices'] = [(x[0],x[2]) for x in utils.BITWISE_DAY_CHOICES]
+        super(BitwiseWeekdayFormField, self).__init__(*args, **kwargs)
 
-  def clean(self,value):
-    value = [int(x) for x in value]
-    if len(value) != 0:
-      value = reduce(operator.or_, value)
-    else:
-      value = 0
-    return value
+    def clean(self,value):
+        value = [int(x) for x in value]
+        if len(value) != 0:
+            value = reduce(operator.or_, value)
+        else:
+            value = 0
+        return value

File weekday_field/static/weekday_field/js/checkbox-wigdet.js

View file
  • Ignore whitespace
+function changeHandler(evt) {
+  var $target = $(evt.target);
+  var targetValue = evt.target.value;
+  var targetChecked = !!$target.attr('checked');
+  
+  var $others = $('[name=' + $target.attr('name') + ']');
+  var $anyAll = $('[value="None"]');
+  
+  if (targetValue === 'None') {
+    $others.attr('checked', true);
+    $target.attr('disabled', true);
+    return;
+  }
+  
+  // Otherwise, whenever we deselect any, deselect the "All" item.
+  if (!targetChecked) {
+    $others.filter('[value="None"]').attr('checked', false);
+  }
+  if (targetValue.match(',')) {
+    // This was a multiple box.
+    $others.filter(function(i, el) {
+      return targetValue.match(el.value);
+    }).attr('checked', targetChecked);
+  } else {
+    // This was a single choice.
+    if (!targetChecked) {
+      // And it was a deselection.
+      $others.filter(function(i, el) {
+        return el.value.match(targetValue);
+      }).attr('checked', false);
+    } else {
+      // Only check multiple ones if they all match.
+      var value_ = $others.filter(function(i, el) {
+        return !el.value.match(',');
+      }).filter(':checked');
+      var value = [];
+      
+      $.each(value_, function(i, el){
+        value.push(el.value);
+      });
+      value = value.sort().join();
+      
+      $others.filter(function(i, el) {
+        return value.match(el.value);
+      }).attr('checked', true);
+    }  
+  }
+  
+  // If we deselected everything, select everything.
+  if ($others.filter(':checked').length === 0) {
+    $others.attr('checked', true);
+  } else {
+    // Now check for all to be selected.
+    if ($others.filter(':not(:checked)').length === 1) {
+      if ($others.filter(':not(:checked)')[0].value === 'None') {
+        $others.attr('checked', true);
+      }  
+    }
+  }
+  
+  $anyAll.attr('disabled', !!$anyAll.attr('checked'));
+}

File weekday_field/utils.py

View file
  • Ignore whitespace
     (32, "F","Friday"),
     (64, "Sa","Saturday"),
 )
+
+ADVANCED_DAY_CHOICES = (
+    (None, "Any day"),
+    ("0,1,2,3,4", "Weekdays"),
+    ("5,6", "Weekends"),
+) + DAY_CHOICES

File weekday_field/widgets.py

View file
  • Ignore whitespace
+from django.forms.widgets import CheckboxSelectMultiple
+from django.utils.safestring import mark_safe
+
+class ToggleCheckboxes(CheckboxSelectMultiple):
+    class Media:
+        js = (
+            'weekday_field/js/checkbox-widget.js',
+        )
+    
+    def render(self, name, value, attrs=None):
+        if isinstance(value, basestring):
+            value = map(int, value.split(','))
+        if not value or value == range(7):
+            value = [str(x[0]) for x in self.choices]
+        if all([x in value for x in range(5)]):
+            value.append('0,1,2,3,4')
+        if 5 in value and 6 in value:
+            value.append('5,6')
+        result = super(ToggleCheckboxes, self).render(name, value, attrs)
+        result = result.replace(
+            " Weekends</label></li>", 
+            " Weekends</label></li></ul><ul>")
+        return mark_safe(result)
+        
+    def value_from_datadict(self, data, files, name):
+        if name not in data:
+            return []
+        value = data.getlist(name)
+        if 'None' in value:
+            return []
+        
+        value = set([x for sub in value for x in sub.split(',')])
+        return ",".join(sorted(value))