diff --git a/django_select2/fields.py b/django_select2/fields.py
index 7619c1e..6e5566d 100644
--- a/django_select2/fields.py
+++ b/django_select2/fields.py
@@ -492,6 +492,7 @@ class HeavySelect2FieldBaseMixin(object):
# could have directly set field_id on it.
if hasattr(self, 'field_id'):
self.widget.field_id = self.field_id
+ self.widget.attrs['data-select2-id'] = self.field_id
# Widget should have been instantiated by now.
self.widget.field = self
diff --git a/django_select2/static/js/heavy_data.js b/django_select2/static/js/heavy_data.js
index 188505c..d23a46e 100644
--- a/django_select2/static/js/heavy_data.js
+++ b/django_select2/static/js/heavy_data.js
@@ -1,7 +1,7 @@
if (!window['django_select2']) {
// This JS file can be included multiple times. So, as not to overwrite previous states, we run this only once.
- var django_select2 = {
+ window.django_select2 = {
MULTISEPARATOR: String.fromCharCode(31), // We use this unprintable char as separator,
// since this can't be entered by user.
get_url_params: function (term, page, context) {
@@ -59,14 +59,14 @@ if (!window['django_select2']) {
updateText: function ($e) {
var val = $e.select2('val'), data = $e.select2('data'), txt = $e.txt(), isMultiple = !!$e.attr('multiple'),
diff;
-
+
if (val || val === 0) { // Means value is set. A numerical 0 is also a valid value.
if (isMultiple) {
if (val.length !== txt.length) {
txt = [];
jQuery(val).each(function (idx) {
var i, value = this, id;
-
+
for (i in data) {
id = data [i].id;
if (id instanceof String) {
@@ -109,12 +109,12 @@ if (!window['django_select2']) {
return [val, txt];
}
}
-
+
if (res) {
txt = [];
jQuery(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.
diff --git a/django_select2/static/js/heavy_data.min.js b/django_select2/static/js/heavy_data.min.js
index 083db23..3d326f9 100644
--- a/django_select2/static/js/heavy_data.min.js
+++ b/django_select2/static/js/heavy_data.min.js
@@ -1 +1 @@
-if(!window.django_select2){var django_select2={MULTISEPARATOR:String.fromCharCode(31),get_url_params:function(c,e,b){var d=$(this).data("field_id"),a={term:c,page:e,context:b};if(d){a.field_id=d}return a},process_results:function(d,c,b){var a;if(d.err&&d.err.toLowerCase()==="nil"){a={results:d.results};if(b){a.context=b}if(d.more===true||d.more===false){a.more=d.more}}else{a={results:[]}}if(a.results){$(this).data("results",a.results)}else{$(this).removeData("results")}return a},onValChange:function(){django_select2.updateText($(this))},prepareValText:function(d,a,c){var b=[];$(d).each(function(e){b.push({id:this,text:a[e]})});if(c){return b}else{if(b.length>0){return b[0]}else{return null}}},updateText:function(b){var f=b.select2("val"),d=b.select2("data"),a=b.txt(),c=!!b.attr("multiple"),e;if(f||f===0){if(c){if(f.length!==a.length){a=[];$(f).each(function(g){var h,j=this,k;for(h in d){k=d[h].id;if(k instanceof String){k=k.valueOf()}if(k==j){a.push(d[h].text)}}})}}else{a=d.text}b.txt(a)}else{b.txt("")}},getValText:function(b){var g=b.select2("val"),c=b.data("results"),a=b.txt(),e=!!b.attr("multiple"),d,h=b.attr("id");if(g||g===0){if(!e){g=[g];if(a||a===0){a=[a]}}if(a===0||(a&&g.length===a.length)){return[g,a]}d=b.data("userGetValText");if(d){a=d(b,g,e);if(a||a===0){return[g,a]}}if(c){a=[];$(g).each(function(f){var j,k=this;for(j in c){if(c[j].id==k){g[f]=c[j].id;a.push(c[j].text)}}});if(a||a===0){return[g,a]}}}return null},onInit:function(b,f){b=$(b);var d=b.attr("id"),a=null,c=b.select2("val");if(!c&&c!==0){c=b.data("initVal")}if(c||c===0){a=django_select2.getValText(b);if(a&&a[0]){a=django_select2.prepareValText(a[0],a[1],!!b.attr("multiple"))}}if(!a){b.val(null)}f(a);django_select2.updateText(b)},createSearchChoice:function(a,b){if(!b||$(b).filter(function(){return this.text.localeCompare(a)===0}).length===0){return{id:a,text:a}}},onMultipleHiddenChange:function(){var b=$(this),d=b.data("valContainer"),a=b.data("name"),c=b.val();d.empty();if(c){c=c.split(django_select2.MULTISEPARATOR);$(c).each(function(){var e=$('').appendTo(d);e.attr("name",a);e.val(this)})}},initMultipleHidden:function(a){var b;a.data("name",a.attr("name"));a.attr("name","");b=$("
").insertAfter(a).css({display:"none"});a.data("valContainer",b);a.change(django_select2.onMultipleHiddenChange);if(a.val()){a.change()}},convertArrToStr:function(a){return a.join(django_select2.MULTISEPARATOR)},runInContextHelper:function(a,b){return function(){var c=Array.prototype.slice.call(arguments,0);return a.apply($("#"+b).get(0),c)}},logErr:function(){if(console&&console.error){args=Array.prototype.slice.call(arguments);console.error.apply(console,args)}}};(function(b){if(b){for(var a in django_select2){var c=django_select2[a];if(typeof(c)=="function"){django_select2[a]=(function(d,e){return function(){console.log("Function "+d+" called for object: ",this);return e.apply(this,arguments)}}(a,c))}}}}(false));(function(a){a.fn.txt=function(b){if(typeof(b)!=="undefined"){if(b){if(b instanceof Array){if(this.attr("multiple")){b=django_select2.convertArrToStr(b)}else{b=b[0]}}this.attr("txt",b)}else{this.removeAttr("txt")}return this}else{b=this.attr("txt");if(this.attr("multiple")){if(b){b=b.split(django_select2.MULTISEPARATOR)}else{b=[]}}return b}}})(jQuery)};
\ No newline at end of file
+if(!window.django_select2){window.django_select2={MULTISEPARATOR:String.fromCharCode(31),get_url_params:function(c,e,b){var d=$(this).data("field_id"),a={term:c,page:e,context:b};if(d){a.field_id=d}return a},process_results:function(d,c,b){var a;if(d.err&&d.err.toLowerCase()==="nil"){a={results:d.results};if(b){a.context=b}if(d.more===true||d.more===false){a.more=d.more}}else{a={results:[]}}if(a.results){$(this).data("results",a.results)}else{$(this).removeData("results")}return a},onValChange:function(){django_select2.updateText($(this))},prepareValText:function(d,a,c){var b=[];$(d).each(function(e){b.push({id:this,text:a[e]})});if(c){return b}else{if(b.length>0){return b[0]}else{return null}}},updateText:function(b){var f=b.select2("val"),d=b.select2("data"),a=b.txt(),c=!!b.attr("multiple"),e;if(f||f===0){if(c){if(f.length!==a.length){a=[];$(f).each(function(g){var h,j=this,k;for(h in d){k=d[h].id;if(k instanceof String){k=k.valueOf()}if(k==j){a.push(d[h].text)}}})}}else{a=d.text}b.txt(a)}else{b.txt("")}},getValText:function(b){var g=b.select2("val"),c=b.data("results"),a=b.txt(),e=!!b.attr("multiple"),d,h=b.attr("id");if(g||g===0){if(!e){g=[g];if(a||a===0){a=[a]}}if(a===0||(a&&g.length===a.length)){return[g,a]}d=b.data("userGetValText");if(d){a=d(b,g,e);if(a||a===0){return[g,a]}}if(c){a=[];$(g).each(function(f){var j,k=this;for(j in c){if(c[j].id==k){g[f]=c[j].id;a.push(c[j].text)}}});if(a||a===0){return[g,a]}}}return null},onInit:function(b,f){b=$(b);var d=b.attr("id"),a=null,c=b.select2("val");if(!c&&c!==0){c=b.data("initVal")}if(c||c===0){a=django_select2.getValText(b);if(a&&a[0]){a=django_select2.prepareValText(a[0],a[1],!!b.attr("multiple"))}}if(!a){b.val(null)}f(a);django_select2.updateText(b)},createSearchChoice:function(a,b){if(!b||$(b).filter(function(){return this.text.localeCompare(a)===0}).length===0){return{id:a,text:a}}},onMultipleHiddenChange:function(){var b=$(this),d=b.data("valContainer"),a=b.data("name"),c=b.val();d.empty();if(c){c=c.split(django_select2.MULTISEPARATOR);$(c).each(function(){var e=$('').appendTo(d);e.attr("name",a);e.val(this)})}},initMultipleHidden:function(a){var b;a.data("name",a.attr("name"));a.attr("name","");b=$("
").insertAfter(a).css({display:"none"});a.data("valContainer",b);a.change(django_select2.onMultipleHiddenChange);if(a.val()){a.change()}},convertArrToStr:function(a){return a.join(django_select2.MULTISEPARATOR)},runInContextHelper:function(a,b){return function(){var c=Array.prototype.slice.call(arguments,0);return a.apply($("#"+b).get(0),c)}},logErr:function(){if(console&&console.error){args=Array.prototype.slice.call(arguments);console.error.apply(console,args)}}};(function(b){if(b){for(var a in django_select2){var c=django_select2[a];if(typeof(c)=="function"){django_select2[a]=(function(d,e){return function(){console.log("Function "+d+" called for object: ",this);return e.apply(this,arguments)}}(a,c))}}}}(false));(function(a){a.fn.txt=function(b){if(typeof(b)!=="undefined"){if(b){if(b instanceof Array){if(this.attr("multiple")){b=django_select2.convertArrToStr(b)}else{b=b[0]}}this.attr("txt",b)}else{this.removeAttr("txt")}return this}else{b=this.attr("txt");if(this.attr("multiple")){if(b){b=b.split(django_select2.MULTISEPARATOR)}else{b=[]}}return b}}})(jQuery)};
diff --git a/django_select2/util.py b/django_select2/util.py
index e5ed971..a706f5e 100644
--- a/django_select2/util.py
+++ b/django_select2/util.py
@@ -10,62 +10,6 @@ from django.utils.encoding import force_unicode
logger = logging.getLogger(__name__)
-class JSVar(unicode):
- """
- A JS variable.
-
- This is a simple Unicode string. This class type acts as a marker that this string is a JS variable name,
- so it must not be quoted by :py:func:`.convert_py_to_js_data` while rendering the JS code.
- """
- pass
-
-
-class JSFunction(JSVar):
- """
- A JS function name.
-
- From rendering point of view, rendering this is no different from :py:class:`JSVar`. After all, a JS variable
- can refer a function instance, primitive constant or any other object. They are still all variables.
-
- .. tip:: Do use this marker for JS functions. This will make the code clearer, and the purpose more easier to
- understand.
- """
- pass
-
-
-class JSFunctionInContext(JSVar):
- """
- A JS function name to run in context of some other HTML DOM element.
-
- Like :py:class:`JSFunction`, this too flags the string as JS function, but with a special requirement. The JS function
- needs to be invoked in the context of a HTML DOM, such that, ``this`` inside the function refers to that DOM instead of
- ``window``.
-
- .. tip:: JS functions of this type are wrapped inside special another JS function -- ``django_select2.runInContextHelper``.
- """
- pass
-
-
-def render_js_script(inner_code):
- """
- This wraps ``inner_code`` string inside the following code block::
-
-
-
- :rtype: :py:obj:`unicode`
- """
- return u"""
- """ % inner_code
-
-
def extract_some_key_val(dct, keys):
"""
Gets a sub-set of a :py:obj:`dict`.
@@ -86,110 +30,6 @@ def extract_some_key_val(dct, keys):
return edct
-def convert_to_js_str(val):
- val = force_unicode(val).replace('\'', '\\\'')
- return u"'%s'" % val
-
-def convert_py_to_js_data(val, id_):
- """
- Converts Python data type to JS data type.
-
- Practically what this means is, convert ``False`` to ``false``, ``True`` to ``true`` and so on.
- It also takes care of the conversion of :py:class:`.JSVar`, :py:class:`.JSFunction`
- and :py:class:`.JSFunctionInContext`. It takes care of recursively converting lists and dictionaries
- too.
-
- :param val: The Python data to convert.
- :type val: Any
-
- :param id_: The DOM id of the element in which context :py:class:`.JSFunctionInContext` functions
- should run. (This is not needed if ``val`` contains no :py:class:`.JSFunctionInContext`)
- :type id_: :py:obj:`str`
-
- :rtype: :py:obj:`unicode`
- """
- if type(val) == types.BooleanType:
- return u'true' if val else u'false'
- elif type(val) in [types.IntType, types.LongType, types.FloatType]:
- return force_unicode(val)
- elif isinstance(val, JSFunctionInContext):
- return u"django_select2.runInContextHelper(%s, '%s')" % (val, id_)
- elif isinstance(val, JSVar):
- return val # No quotes here
- elif isinstance(val, dict):
- return convert_dict_to_js_map(val, id_)
- elif isinstance(val, list):
- return convert_to_js_arr(val, id_)
- else:
- return convert_to_js_str(val)
-
-
-def convert_dict_to_js_map(dct, id_):
- """
- Converts a Python dictionary to JS map.
-
- :param dct: The Python dictionary to convert.
- :type dct: :py:obj:`dict`
-
- :param id_: The DOM id of the element in which context :py:class:`.JSFunctionInContext` functions
- should run. (This is not needed if ``dct`` contains no :py:class:`.JSFunctionInContext`)
- :type id_: :py:obj:`str`
-
- :rtype: :py:obj:`unicode`
- """
- out = u'{'
- is_first = True
- for name in dct:
- if not is_first:
- out += u", "
- else:
- is_first = False
-
- out += u"%s: " % convert_to_js_str(name)
- out += convert_py_to_js_data(dct[name], id_)
-
- return out + u'}'
-
-
-def convert_to_js_arr(lst, id_):
- """
- Converts a Python list (or any iterable) to JS array.
-
- :param lst: The Python iterable to convert.
- :type lst: :py:obj:`list` or Any iterable
-
- :param id_: The DOM id of the element in which context :py:class:`.JSFunctionInContext` functions
- should run. (This is not needed if ``lst`` contains no :py:class:`.JSFunctionInContext`)
- :type id_: :py:obj:`str`
-
- :rtype: :py:obj:`unicode`
- """
- out = u'['
- is_first = True
- for val in lst:
- if not is_first:
- out += u", "
- else:
- is_first = False
-
- out += convert_py_to_js_data(val, id_)
-
- return out + u']'
-
-
-def convert_to_js_string_arr(lst):
- """
- Converts a Python list (or any iterable) of strings to JS array.
-
- :py:func:`convert_to_js_arr` can always be used instead of this. However, since it
- knows that it only contains strings, it cuts down on unnecessary computations.
-
- :rtype: :py:obj:`unicode`
- """
- lst = [convert_to_js_str(l) for l in lst]
- return u"[%s]" % (",".join(lst))
-
-
### Auto view helper utils ###
from . import __ENABLE_MULTI_PROCESS_SUPPORT as ENABLE_MULTI_PROCESS_SUPPORT, \
diff --git a/django_select2/widgets.py b/django_select2/widgets.py
index 75a7e5e..c070286 100644
--- a/django_select2/widgets.py
+++ b/django_select2/widgets.py
@@ -1,638 +1,658 @@
-"""
-Contains all the Django widgets for Select2.
-"""
-
-import logging
-from itertools import chain
-import util
-
-from django import forms
-from django.core.validators import EMPTY_VALUES
-from django.utils.encoding import force_unicode
-from django.utils.safestring import mark_safe
-from django.core.urlresolvers import reverse
-from django.utils.datastructures import MultiValueDict, MergeDict
-
-from .util import render_js_script, convert_to_js_string_arr, JSVar, JSFunction, JSFunctionInContext, \
- convert_dict_to_js_map, convert_to_js_arr
-
-from . import __RENDER_SELECT2_STATICS as RENDER_SELECT2_STATICS
-
-logger = logging.getLogger(__name__)
-
-
-def get_select2_js_libs():
- from django.conf import settings
- if settings.configured and settings.DEBUG:
- return ('js/select2.js', )
- else:
- return ('js/select2.min.js', )
-
-def get_select2_heavy_js_libs():
- libs = get_select2_js_libs()
-
- from django.conf import settings
- if settings.configured and settings.DEBUG:
- return libs + ('js/heavy_data.js', )
- else:
- return libs + ('js/heavy_data.min.js', )
-
-def get_select2_css_libs(light=False):
- from django.conf import settings
- from . import __BOOTSTRAP
- if __BOOTSTRAP:
- if settings.configured and settings.DEBUG:
- if light:
- return ('css/select2.css', 'css/select2-bootstrap.css')
- else:
- return ('css/select2.css', 'css/extra.css', 'css/select2-bootstrap.css')
- else:
- if light:
- return ('css/select2-bootstrapped.min.css',)
- else:
- return ('css/all-bootstrapped.min.css',)
- else:
- if settings.configured and settings.DEBUG:
- if light:
- return ('css/select2.css',)
- else:
- return ('css/select2.css', 'css/extra.css')
- else:
- if light:
- return ('css/select2.min.css',)
- else:
- return ('css/all.min.css',)
-
-### Light mixin and widgets ###
-
-class Select2Mixin(object):
- """
- The base mixin of all Select2 widgets.
-
- This mixin is responsible for rendering the necessary JavaScript and CSS codes which turns normal ``