Skip to content

Commit c3ed8d3

Browse files
committed
rename to select url field
1 parent c42a2ec commit c3ed8d3

File tree

5 files changed

+195
-0
lines changed

5 files changed

+195
-0
lines changed

select_url_field/__init__.py

Whitespace-only changes.

select_url_field/choice_with_other.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from django import forms
2+
from django.conf import settings
3+
from django.utils.encoding import force_unicode
4+
5+
OTHER_CHOICE = '__other__'
6+
OTHER_CHOICE_DISPLAY = '' # 'Other:'
7+
8+
class ChoiceWithOtherWidget(forms.MultiWidget):
9+
"""MultiWidget for use with ChoiceWithOtherField."""
10+
def __init__(self, choices, attrs=None):
11+
widgets = [
12+
forms.Select(choices=choices),
13+
forms.TextInput(attrs={'size':'80'})
14+
]
15+
self.choices = choices
16+
super(ChoiceWithOtherWidget, self).__init__(widgets, attrs=attrs)
17+
18+
def decompress(self, value):
19+
if value:
20+
choices = [c[0] for c in self.choices]
21+
provided_choices, other_choice = choices[:-1], choices[-1:]
22+
if value in provided_choices:
23+
return [value, '']
24+
else:
25+
return [OTHER_CHOICE, value]
26+
return ['', '']
27+
28+
def format_output(self, rendered_widgets):
29+
"""Format the output by substituting the "other" choice into the first widget."""
30+
return '<div class="choice_with_other_wrapper">%s %s</div>' % \
31+
(rendered_widgets[0], rendered_widgets[1])
32+
33+
def _media(self):
34+
js_list = ['%sadmin/choice_with_other.js' % settings.STATIC_URL, ]
35+
return forms.Media(js=js_list)
36+
media = property(_media)
37+
38+
39+
class ChoiceWithOtherField(forms.MultiValueField):
40+
41+
def __init__(self, *args, **kwargs):
42+
choices = list(kwargs.pop('choices'))
43+
has_empty_choice = False
44+
for c in choices:
45+
if not c[0]:
46+
has_empty_choice = True
47+
break
48+
if not has_empty_choice:
49+
choices.insert(0, ('', '---------'))
50+
choices.append((OTHER_CHOICE, OTHER_CHOICE_DISPLAY))
51+
fields = [
52+
forms.ChoiceField(choices=choices),
53+
forms.CharField(required=False)
54+
]
55+
widget = ChoiceWithOtherWidget(choices=choices)
56+
self._was_required = kwargs.pop('required', True)
57+
kwargs['required'] = False
58+
super(ChoiceWithOtherField, self).__init__(widget=widget, fields=fields, *args, **kwargs)
59+
60+
def compress(self, value):
61+
if self._was_required and (not value or value[0] in (None, '')):
62+
raise forms.ValidationError(self.error_messages['required'])
63+
if not value:
64+
return ''
65+
66+
return value[1] #value[0] is ignored. Only ever take the value from the text field. The select menu is now just a way to correctly fill in the text field.
67+

select_url_field/fields.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import re
2+
import os.path
3+
4+
from django import forms
5+
from django.core.exceptions import ValidationError
6+
from django.core.validators import URLValidator
7+
from django.db import models
8+
from django.db import IntegrityError
9+
from django.template.defaultfilters import filesizeformat
10+
from django.utils.translation import ugettext_lazy as _
11+
from django.utils.encoding import smart_unicode
12+
from django.utils import importlib
13+
14+
from select_url_field.choice_with_other import ChoiceWithOtherField
15+
16+
class SelectURLField(models.CharField):
17+
description = _("URL")
18+
19+
def __init__(self, verbose_name=None, name=None, **kwargs):
20+
kwargs['max_length'] = kwargs.get('max_length', 200)
21+
# handle choices option:
22+
# from custom_site.url_choices import get_url_choices
23+
# link = SelectURLField(blank=True, choices=get_url_choices)
24+
self._has_choices = False
25+
if 'choices' in kwargs:
26+
self._has_choices = True
27+
self._url_choices = kwargs.pop('choices')
28+
29+
models.CharField.__init__(self, verbose_name, name, **kwargs)
30+
self.validators.append(SelectURLValidator())
31+
32+
def formfield(self, **kwargs):
33+
# As with CharField, this will cause URL validation to be performed twice
34+
defaults = {
35+
'form_class': SelectURLFormField,
36+
}
37+
defaults.update(kwargs)
38+
## when choices given, use them.
39+
## when not, use global settings.
40+
if self._has_choices:
41+
if callable(self._url_choices):
42+
choices = self._url_choices()
43+
else:
44+
choices = self._url_choices
45+
else:
46+
from django.conf import settings
47+
mod_path, func_name = settings.URL_CHOICES_FUNC.rsplit('.', 1)
48+
mod = importlib.import_module(mod_path)
49+
choices_func = getattr(mod, func_name)
50+
choices = choices_func()
51+
required = not self.blank
52+
return ChoiceWithOtherField(choices=choices, required=required)
53+
54+
55+
def to_python(self, value):
56+
from django.conf import settings
57+
if value:
58+
domain = getattr(settings, 'SITE_DOMAIN', '')
59+
if domain:
60+
domain_pattern = r'^(?:http|ftp)s?://' + domain
61+
domain_regex = re.compile(domain_pattern, re.IGNORECASE)
62+
#match = domain_regex.search(value)
63+
value = domain_regex.sub('', value)
64+
return super(SelectURLField, self).to_python(value)
65+
66+
#We need IxxyURLField so this is backwards compatible
67+
IxxyURLField = SelectURLField
68+
69+
class SelectURLValidator(object):
70+
code = 'invalid'
71+
regex = re.compile(r'(?:[/?]\S+)$', re.IGNORECASE)
72+
73+
def __init__(self):
74+
self.url_validator = URLValidator()
75+
76+
def __call__(self, value):
77+
try:
78+
#OK if it's a valid url
79+
self.url_validator(value)
80+
except ValidationError, e:
81+
#Not a valid url, see it's a path
82+
if not self.regex.search(smart_unicode(value)):
83+
raise e
84+
85+
class SelectURLFormField(forms.CharField):
86+
default_error_messages = {
87+
'invalid': _(u'Enter a valid URL.'),
88+
}
89+
90+
def __init__(self, max_length=None, min_length=None, *args, **kwargs):
91+
super(SelectURLFormField, self).__init__(max_length, min_length, *args, **kwargs)
92+
self.validators.append(SelectURLValidator())
93+
94+
95+
from south.modelsinspector import add_introspection_rules
96+
add_introspection_rules([], ["^select_url_field\.fields\.IxxyURLField"])
97+
add_introspection_rules([], ["^select_url_field\.fields\.SelectURLField"])

select_url_field/models.py

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
(function($) {
2+
var OTHER_CHOICE = '__other__'; //See
3+
$(function(){
4+
var wrappers = $('.choice_with_other_wrapper');
5+
wrappers.each(function(){
6+
var select = $('select', this);
7+
var text_input = $('input', this);
8+
select.change(function(){
9+
if(select.val() == OTHER_CHOICE){
10+
;
11+
}else{
12+
text_input.val(select.val());
13+
}
14+
});
15+
text_input.keyup(function(){
16+
var match = false;
17+
$(select).find('option').each(function(){
18+
if($(this).attr('value') == text_input.val()){
19+
match = true;
20+
}
21+
})
22+
if(!match){
23+
select.val(OTHER_CHOICE);
24+
}else{
25+
select.val(text_input.val());
26+
}
27+
});
28+
select.change();
29+
})
30+
})
31+
})(django.jQuery);

0 commit comments

Comments
 (0)