mirror of
https://github.com/Hopiu/django-select2.git
synced 2026-03-25 09:30:23 +00:00
v2.0.1
* Auto field register fix. * Prevent multiple execution of heavy_data.js.
This commit is contained in:
parent
0349cc5049
commit
4e240ce415
9 changed files with 248 additions and 221 deletions
|
|
@ -1,4 +1,4 @@
|
|||
__version__ = "2.0"
|
||||
__version__ = "2.0.1"
|
||||
|
||||
from django.conf import settings
|
||||
if settings.configured:
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ class AutoViewFieldMixin(object):
|
|||
if logger.isEnabledFor(logging.INFO):
|
||||
logger.info("Registering auto field: %s", name)
|
||||
|
||||
from .util import register_field
|
||||
id_ = register_field(name, self)
|
||||
from . import util
|
||||
id_ = util.register_field(name, self)
|
||||
self.widget.field_id = id_
|
||||
super(AutoViewFieldMixin, self).__init__(*args, **kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,243 +1,246 @@
|
|||
if (!window['django_select2']) {
|
||||
// This JS file can be included multiple times. So, as not to ovverwrite previous states, we run this only once.
|
||||
|
||||
var django_select2 = {
|
||||
MULTISEPARATOR: String.fromCharCode(0), // We use this unprintable char as separator, since this can't be entered by user.
|
||||
get_url_params: function (term, page, context) {
|
||||
var field_id = $(this).data('field_id'),
|
||||
res = {
|
||||
'term': term,
|
||||
'page': page,
|
||||
'context': context
|
||||
};
|
||||
if (field_id) {
|
||||
res['field_id'] = field_id;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
process_results: function (data, page, context) {
|
||||
var results;
|
||||
if (data.err && data.err.toLowerCase() === 'nil') {
|
||||
results = {
|
||||
'results': data.results
|
||||
};
|
||||
if (context) {
|
||||
results['context'] = context;
|
||||
var django_select2 = {
|
||||
MULTISEPARATOR: String.fromCharCode(0), // We use this unprintable char as separator, since this can't be entered by user.
|
||||
get_url_params: function (term, page, context) {
|
||||
var field_id = $(this).data('field_id'),
|
||||
res = {
|
||||
'term': term,
|
||||
'page': page,
|
||||
'context': context
|
||||
};
|
||||
if (field_id) {
|
||||
res['field_id'] = field_id;
|
||||
}
|
||||
if (data.more === true || data.more === false) {
|
||||
results['more'] = data.more;
|
||||
return res;
|
||||
},
|
||||
process_results: function (data, page, context) {
|
||||
var results;
|
||||
if (data.err && data.err.toLowerCase() === 'nil') {
|
||||
results = {
|
||||
'results': data.results
|
||||
};
|
||||
if (context) {
|
||||
results['context'] = context;
|
||||
}
|
||||
if (data.more === true || data.more === false) {
|
||||
results['more'] = data.more;
|
||||
}
|
||||
} else {
|
||||
results = {'results':[]};
|
||||
}
|
||||
} else {
|
||||
results = {'results':[]};
|
||||
}
|
||||
if (results.results) {
|
||||
$(this).data('results', results.results);
|
||||
} else {
|
||||
$(this).removeData('results');
|
||||
}
|
||||
return results;
|
||||
},
|
||||
setCookie: function (c_name, value) {
|
||||
document.cookie = c_name + "=" + escape(value);
|
||||
},
|
||||
getCookie: function (c_name) {
|
||||
var i, x, y, ARRcookies = document.cookie.split(";");
|
||||
|
||||
for (i = 0; i < ARRcookies.length; i++) {
|
||||
x = ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
|
||||
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
|
||||
x = x.replace(/^\s+|\s+$/g,"");
|
||||
if (x == c_name) {
|
||||
return unescape(y);
|
||||
if (results.results) {
|
||||
$(this).data('results', results.results);
|
||||
} else {
|
||||
$(this).removeData('results');
|
||||
}
|
||||
}
|
||||
},
|
||||
delCookie: function (c_name, isStartsWithPattern) {
|
||||
var i, x, ARRcookies;
|
||||
|
||||
if (!isStartsWithPattern) {
|
||||
document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
} else {
|
||||
ARRcookies = document.cookie.split(";");
|
||||
return results;
|
||||
},
|
||||
setCookie: function (c_name, value) {
|
||||
document.cookie = c_name + "=" + escape(value);
|
||||
},
|
||||
getCookie: function (c_name) {
|
||||
var i, x, y, ARRcookies = document.cookie.split(";");
|
||||
|
||||
for (i = 0; i < ARRcookies.length; i++) {
|
||||
x = ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
|
||||
y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
|
||||
x = x.replace(/^\s+|\s+$/g,"");
|
||||
if (x.indexOf(c_name) == 0) {
|
||||
document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
if (x == c_name) {
|
||||
return unescape(y);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onValChange: function () {
|
||||
var e = $(this), res, id = e.attr('id');
|
||||
},
|
||||
delCookie: function (c_name, isStartsWithPattern) {
|
||||
var i, x, ARRcookies;
|
||||
|
||||
res = django_select2.getValText(e, false);
|
||||
|
||||
if (res && res[1]) {
|
||||
// Cookies are used to persist selection's text. This is needed
|
||||
// when the form springs back if there is any validation failure.
|
||||
$(res[0]).each(function (idx) {
|
||||
django_select2.setCookie(id + '_heavy_val:' + idx, this);
|
||||
django_select2.setCookie(id + '_heavy_txt:' + idx, res[1][idx]);
|
||||
});
|
||||
} else {
|
||||
django_select2.delCookie(id + '_heavy_val:', true);
|
||||
django_select2.delCookie(id + '_heavy_txt:', true);
|
||||
}
|
||||
},
|
||||
prepareValText: function (vals, txts, isMultiple) {
|
||||
var data = []
|
||||
$(vals).each(function (index) {
|
||||
data.push({id: this, text: txts[index]});
|
||||
});
|
||||
if (isMultiple) {
|
||||
return data;
|
||||
} else {
|
||||
if (data.length > 0) {
|
||||
return data[0];
|
||||
if (!isStartsWithPattern) {
|
||||
document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
getValText: function ($e, isGetFromCookieAllowed) {
|
||||
var val = $e.select2('val'), res = $e.data('results'), txt = $e.txt(), isMultiple = !!$e.attr('multiple'),
|
||||
f, id = $e.attr('id');
|
||||
if (val || val === 0) { // Means value is set. A numerical 0 is also a valid value.
|
||||
ARRcookies = document.cookie.split(";");
|
||||
|
||||
if (!isMultiple) {
|
||||
val = [val];
|
||||
if (txt || txt === 0) {
|
||||
txt = [txt];
|
||||
for (i = 0; i < ARRcookies.length; i++) {
|
||||
x = ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
|
||||
x = x.replace(/^\s+|\s+$/g,"");
|
||||
if (x.indexOf(c_name) == 0) {
|
||||
document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onValChange: function () {
|
||||
var e = $(this), res, id = e.attr('id');
|
||||
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
|
||||
f = $e.data('userGetValText');
|
||||
if (f) {
|
||||
txt = f($e, val, isMultiple);
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
}
|
||||
res = django_select2.getValText(e, false);
|
||||
|
||||
if (res) {
|
||||
txt = [];
|
||||
$(val).each(function (idx) {
|
||||
var i, value = this;
|
||||
|
||||
for (i in res) {
|
||||
if (res[i].id == value) {
|
||||
val[idx] = res[i].id; // To set it to correct data type.
|
||||
txt.push(res[i].text);
|
||||
}
|
||||
}
|
||||
if (res && res[1]) {
|
||||
// Cookies are used to persist selection's text. This is needed
|
||||
// when the form springs back if there is any validation failure.
|
||||
$(res[0]).each(function (idx) {
|
||||
django_select2.setCookie(id + '_heavy_val:' + idx, this);
|
||||
django_select2.setCookie(id + '_heavy_txt:' + idx, res[1][idx]);
|
||||
});
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
} else {
|
||||
django_select2.delCookie(id + '_heavy_val:', true);
|
||||
django_select2.delCookie(id + '_heavy_txt:', true);
|
||||
}
|
||||
|
||||
if (isGetFromCookieAllowed) {
|
||||
txt = [];
|
||||
$(val).each(function (idx) {
|
||||
var value = this, cookieVal;
|
||||
|
||||
cookieVal = django_select2.getCookie(id + '_heavy_val:' + idx);
|
||||
|
||||
if (cookieVal == value) {
|
||||
txt.push(django_select2.getCookie(id + '_heavy_txt:' + idx));
|
||||
}
|
||||
});
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
},
|
||||
onInit: function (e, callback) {
|
||||
e = $(e);
|
||||
var id = e.attr('id'), data = null, val = e.select2('val');
|
||||
|
||||
if (!val && val !== 0) {
|
||||
val = e.data('initVal');
|
||||
}
|
||||
|
||||
if (val || val === 0) {
|
||||
// Value is set so need to get the text.
|
||||
data = django_select2.getValText(e);
|
||||
if (data && data[0]) {
|
||||
data = django_select2.prepareValText(data[0], data[1], !!e.attr('multiple'));
|
||||
}
|
||||
}
|
||||
if (!data) {
|
||||
e.val(null); // Nulling out set value so as not to confuse users.
|
||||
}
|
||||
callback(data); // Change for 2.3.x
|
||||
},
|
||||
onMultipleHiddenChange: function () {
|
||||
var $e = $(this), valContainer = $e.data('valContainer'), name = $e.data('name'), vals = $e.val();
|
||||
valContainer.empty();
|
||||
if (vals) {
|
||||
vals = vals.split(django_select2.MULTISEPARATOR);
|
||||
$(vals).each(function () {
|
||||
var inp = $('<input type="hidden">').appendTo(valContainer);
|
||||
inp.attr('name', name);
|
||||
inp.val(this);
|
||||
},
|
||||
prepareValText: function (vals, txts, isMultiple) {
|
||||
var data = []
|
||||
$(vals).each(function (index) {
|
||||
data.push({id: this, text: txts[index]});
|
||||
});
|
||||
}
|
||||
},
|
||||
initMultipleHidden: function ($e) {
|
||||
var valContainer;
|
||||
if (isMultiple) {
|
||||
return data;
|
||||
} else {
|
||||
if (data.length > 0) {
|
||||
return data[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
getValText: function ($e, isGetFromCookieAllowed) {
|
||||
var val = $e.select2('val'), res = $e.data('results'), txt = $e.txt(), isMultiple = !!$e.attr('multiple'),
|
||||
f, id = $e.attr('id');
|
||||
if (val || val === 0) { // Means value is set. A numerical 0 is also a valid value.
|
||||
|
||||
$e.data('name', $e.attr('name'));
|
||||
$e.attr('name', '');
|
||||
|
||||
valContainer = $('<div>').insertAfter($e).css({'display': 'none'});
|
||||
$e.data('valContainer', valContainer);
|
||||
|
||||
$e.change(django_select2.onMultipleHiddenChange);
|
||||
if ($e.val()) {
|
||||
$e.change();
|
||||
}
|
||||
},
|
||||
convertArrToStr: function (arr) {
|
||||
return arr.join(django_select2.MULTISEPARATOR);
|
||||
},
|
||||
runInContextHelper: function (f, id) {
|
||||
return function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return f.apply($('#' + id).get(0), args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(function( $ ){
|
||||
// This sets or gets the text lables for an element. It merely takes care returing array or single
|
||||
// value, based on if element is multiple type.
|
||||
$.fn.txt = function(val) {
|
||||
if (typeof(val) !== 'undefined') {
|
||||
if (val) {
|
||||
if (val instanceof Array) {
|
||||
if (this.attr('multiple')) {
|
||||
val = django_select2.convertArrToStr(val);
|
||||
} else {
|
||||
val = val[0]
|
||||
if (!isMultiple) {
|
||||
val = [val];
|
||||
if (txt || txt === 0) {
|
||||
txt = [txt];
|
||||
}
|
||||
}
|
||||
this.attr('txt', val);
|
||||
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
|
||||
f = $e.data('userGetValText');
|
||||
if (f) {
|
||||
txt = f($e, val, isMultiple);
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
txt = [];
|
||||
$(val).each(function (idx) {
|
||||
var i, value = this;
|
||||
|
||||
for (i in res) {
|
||||
if (res[i].id == value) {
|
||||
val[idx] = res[i].id; // To set it to correct data type.
|
||||
txt.push(res[i].text);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
}
|
||||
|
||||
if (isGetFromCookieAllowed) {
|
||||
txt = [];
|
||||
$(val).each(function (idx) {
|
||||
var value = this, cookieVal;
|
||||
|
||||
cookieVal = django_select2.getCookie(id + '_heavy_val:' + idx);
|
||||
|
||||
if (cookieVal == value) {
|
||||
txt.push(django_select2.getCookie(id + '_heavy_txt:' + idx));
|
||||
}
|
||||
});
|
||||
if (txt || txt === 0) {
|
||||
return [val, txt];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
val = this.attr('txt');
|
||||
if (val && this.attr('multiple')) {
|
||||
val = val.split(django_select2.MULTISEPARATOR);
|
||||
return null;
|
||||
},
|
||||
onInit: function (e, callback) {
|
||||
e = $(e);
|
||||
var id = e.attr('id'), data = null, val = e.select2('val');
|
||||
|
||||
if (!val && val !== 0) {
|
||||
val = e.data('initVal');
|
||||
}
|
||||
return val;
|
||||
|
||||
if (val || val === 0) {
|
||||
// Value is set so need to get the text.
|
||||
data = django_select2.getValText(e);
|
||||
if (data && data[0]) {
|
||||
data = django_select2.prepareValText(data[0], data[1], !!e.attr('multiple'));
|
||||
}
|
||||
}
|
||||
if (!data) {
|
||||
e.val(null); // Nulling out set value so as not to confuse users.
|
||||
}
|
||||
callback(data); // Change for 2.3.x
|
||||
},
|
||||
onMultipleHiddenChange: function () {
|
||||
var $e = $(this), valContainer = $e.data('valContainer'), name = $e.data('name'), vals = $e.val();
|
||||
valContainer.empty();
|
||||
if (vals) {
|
||||
vals = vals.split(django_select2.MULTISEPARATOR);
|
||||
$(vals).each(function () {
|
||||
var inp = $('<input type="hidden">').appendTo(valContainer);
|
||||
inp.attr('name', name);
|
||||
inp.val(this);
|
||||
});
|
||||
}
|
||||
},
|
||||
initMultipleHidden: function ($e) {
|
||||
var valContainer;
|
||||
|
||||
$e.data('name', $e.attr('name'));
|
||||
$e.attr('name', '');
|
||||
|
||||
valContainer = $('<div>').insertAfter($e).css({'display': 'none'});
|
||||
$e.data('valContainer', valContainer);
|
||||
|
||||
$e.change(django_select2.onMultipleHiddenChange);
|
||||
if ($e.val()) {
|
||||
$e.change();
|
||||
}
|
||||
},
|
||||
convertArrToStr: function (arr) {
|
||||
return arr.join(django_select2.MULTISEPARATOR);
|
||||
},
|
||||
runInContextHelper: function (f, id) {
|
||||
return function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
return f.apply($('#' + id).get(0), args);
|
||||
}
|
||||
}
|
||||
};
|
||||
})( jQuery );
|
||||
|
||||
(function( $ ){
|
||||
// This sets or gets the text lables for an element. It merely takes care returing array or single
|
||||
// value, based on if element is multiple type.
|
||||
$.fn.txt = function(val) {
|
||||
if (typeof(val) !== 'undefined') {
|
||||
if (val) {
|
||||
if (val instanceof Array) {
|
||||
if (this.attr('multiple')) {
|
||||
val = django_select2.convertArrToStr(val);
|
||||
} else {
|
||||
val = val[0]
|
||||
}
|
||||
}
|
||||
this.attr('txt', val);
|
||||
}
|
||||
return this;
|
||||
} else {
|
||||
val = this.attr('txt');
|
||||
if (val && this.attr('multiple')) {
|
||||
val = val.split(django_select2.MULTISEPARATOR);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
})( jQuery );
|
||||
}
|
||||
|
|
@ -207,7 +207,15 @@ class HeavySelect2MultipleWidget(HeavySelect2Mixin, MultipleSelect2HiddenInput):
|
|||
|
||||
### Auto Heavy widgets ###
|
||||
|
||||
class AutoHeavySelect2Mixin(HeavySelect2Mixin):
|
||||
class AutoHeavySelect2Mixin(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
if hasattr(self.__class__, 'field_id'): # By the time AutoViewFieldMixin runs widget is not instantiated
|
||||
# so it sets the value on the widget class.
|
||||
self.field_id = getattr(self.__class__, 'field_id')
|
||||
delattr(self.__class__, 'field_id')
|
||||
|
||||
super(AutoHeavySelect2Mixin, self).__init__(*args, **kwargs)
|
||||
|
||||
def render_inner_js_code(self, id_, *args):
|
||||
js = u"$('#%s').data('field_id', '%s');" % (id_, self.field_id)
|
||||
js += super(AutoHeavySelect2Mixin, self).render_inner_js_code(id_, *args)
|
||||
|
|
|
|||
BIN
testapp/test.db
BIN
testapp/test.db
Binary file not shown.
|
|
@ -8,5 +8,6 @@
|
|||
<ul>
|
||||
<li><a href="{% url 'test_single_value_model_field' %}">Test single selection model fields</a></li>
|
||||
<li><a href="{% url 'test_multi_values_model_field' %}">Test multi selection model fields</a></li>
|
||||
<li><a href="{% url 'test_mixed_form' %}">Test mixed form</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ class ClassRoomChoices(AutoModelSelect2MultipleField):
|
|||
queryset = ClassRoom.objects
|
||||
search_fields = ['number__icontains', ]
|
||||
|
||||
class ClassRoomSingleChoices(AutoModelSelect2Field):
|
||||
queryset = ClassRoom.objects
|
||||
search_fields = ['number__icontains', ]
|
||||
|
||||
class EmployeeForm(forms.ModelForm):
|
||||
manager = EmployeeChoices(required=False)
|
||||
|
|
@ -27,6 +30,13 @@ class DeptForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = Dept
|
||||
|
||||
class MixedForm(forms.Form):
|
||||
emp1 = EmployeeChoices()
|
||||
rooms1 = ClassRoomChoices()
|
||||
emp2 = EmployeeChoices()
|
||||
rooms2 = ClassRoomChoices()
|
||||
rooms3 = ClassRoomSingleChoices()
|
||||
|
||||
# These are just for testing Auto registration of fields
|
||||
EmployeeChoices() # Should already be registered
|
||||
EmployeeChoices(auto_id="EmployeeChoices_CustomAutoId") # Should get registered
|
||||
|
|
|
|||
|
|
@ -6,4 +6,6 @@ urlpatterns = patterns("",
|
|||
|
||||
url(r'multi/model/field/$', 'testmain.views.test_multi_values_model_field', name='test_multi_values_model_field'),
|
||||
url(r'multi/model/field/([0-9]+)/$', 'testmain.views.test_multi_values_model_field1', name='test_multi_values_model_field1'),
|
||||
|
||||
url(r'mixed/form/$', 'testmain.views.test_mixed_form', name='test_mixed_form'),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from django.http import HttpResponseRedirect
|
|||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.template import RequestContext
|
||||
|
||||
from .forms import EmployeeForm, DeptForm
|
||||
from .forms import EmployeeForm, DeptForm, MixedForm
|
||||
from .models import Employee, Dept
|
||||
|
||||
def test_single_value_model_field(request):
|
||||
|
|
@ -43,3 +43,6 @@ def test_multi_values_model_field1(request, id):
|
|||
form = DeptForm(instance=dept)
|
||||
return render_to_response('form.html', RequestContext(request, {'form': form}))
|
||||
|
||||
def test_mixed_form(request):
|
||||
return render_to_response('form.html', RequestContext(request, {'form': MixedForm()}))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue