diff --git a/django_select2/fields.py b/django_select2/fields.py index e735ff4..70e88e3 100644 --- a/django_select2/fields.py +++ b/django_select2/fields.py @@ -346,8 +346,11 @@ class ModelChoiceFieldMixin(object): def __init__(self, *args, **kwargs): queryset = kwargs.pop('queryset', None) + # This filters out kwargs not supported by Field but are still passed as it is required + # by other codes. If new args are added to Field then make sure they are added here too. kargs = extract_some_key_val(kwargs, [ 'empty_label', 'cache_choices', 'required', 'label', 'initial', 'help_text', + 'validators', 'localize', ]) kargs['widget'] = kwargs.pop('widget', getattr(self, 'widget', None)) kargs['to_field_name'] = kwargs.pop('to_field_name', 'pk') diff --git a/django_select2/static/js/heavy_data.js b/django_select2/static/js/heavy_data.js index 09ab76b..c65d03d 100644 --- a/django_select2/static/js/heavy_data.js +++ b/django_select2/static/js/heavy_data.js @@ -38,11 +38,12 @@ if (!window['django_select2']) { } return results; }, - setCookie: function (c_name, value) { + /*setCookie: function (c_name, value) { document.cookie = c_name + "=" + escape(value); }, getCookie: function (c_name) { - var i, x, y, ARRcookies = document.cookie.split(";"); + var i, x, y, + ARRcookies = document.cookie.split(";"); for (i = 0; i < ARRcookies.length; i++) { x = ARRcookies[i].substr(0,ARRcookies[i].indexOf("=")); @@ -55,9 +56,8 @@ if (!window['django_select2']) { }, delCookie: function (c_name, isStartsWithPattern) { var i, x, ARRcookies; - if (!isStartsWithPattern) { - document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; + document.cookie = c_name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; } else { ARRcookies = document.cookie.split(";"); @@ -70,25 +70,59 @@ if (!window['django_select2']) { } } }, - onValChange: function () { - var e = $(this), res, id = e.attr('id'); - - res = django_select2.getValText(e, false); + setData: function (c_name, value) { + var store = django_select2.store; + django_select2.setCookie(django_select2.HEAVY_VAL_TXT_SET_KEY, true); + if (store && store.enabled) { + store.set(c_name, value); + } else { + django_select2.setCookie(c_name, value); + } + }, + getData: function (c_name) { + var store = django_select2.store; + + if (store && store.enabled) { + return store.get(c_name); + } else { + return django_select2.getCookie(c_name); + } + }, + delData: function (c_name, isStartsWithPattern) { + isStartsWithPattern = typeof(isStartsWithPattern) === 'undefined' ? true : isStartsWithPattern; + var store = django_select2.store; + + if (store && store.enabled) { + if (!isStartsWithPattern) { + store.remove(c_name); + } else { + store.removeAllStartsWith(c_name); + } + } else { + django_select2.delCookie(c_name, isStartsWithPattern); + } + },*/ + onValChange: function () { + var e = $(this);//, res, id = e.attr('id'); + django_select2.updateText(e); + + //django_select2.delData('heavy_val:' + id + ':'); + //django_select2.delData('heavy_txt:' + id + ':'); + + /*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. + // HTML5 localstore or cookies are used to persist selection's text. + // This is needed when the form springs back if there are any + // validation failures. $(res[0]).each(function (idx) { var txt = res[1][idx]; if (typeof(txt) !== 'undefined') { - django_select2.setCookie(id + '_heavy_val:' + idx, this); - django_select2.setCookie(id + '_heavy_txt:' + idx, txt); + django_select2.setData('heavy_val:' + id + ':' + idx, this); + django_select2.setData('heavy_txt:' + id + ':' + idx, txt); } }); - } else { - django_select2.delCookie(id + '_heavy_val:', true); - django_select2.delCookie(id + '_heavy_txt:', true); - } + }*/ }, prepareValText: function (vals, txts, isMultiple) { var data = [] @@ -105,7 +139,37 @@ if (!window['django_select2']) { } } }, - getValText: function ($e, isGetFromCookieAllowed) { + 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 = []; + $(val).each(function (idx) { + var i, value = this, id; + + for (i in data) { + id = data [i].id; + if (id instanceof String) { + id = id.valueOf(); + } + if (id == value) { + txt.push(data[i].text); + } + } + }); + } + } else { + txt = data.text; + } + $e.txt(txt); + } else { + $e.txt(''); + } + }, + getValText: function ($e, isGetFromClientStoreAllowed) { 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. @@ -117,7 +181,7 @@ if (!window['django_select2']) { } } - if (txt || txt === 0) { + if (txt === 0 || (txt && val.length === txt.length)) { return [val, txt]; } @@ -146,21 +210,21 @@ if (!window['django_select2']) { } } - if (isGetFromCookieAllowed) { + /*if (isGetFromClientStoreAllowed) { txt = []; $(val).each(function (idx) { - var value = this, cookieVal; + var value = this, clientLocalVal; - cookieVal = django_select2.getCookie(id + '_heavy_val:' + idx); + clientLocalVal = django_select2.getData('heavy_val:' + id + ':' + idx); - if (cookieVal == value) { - txt.push(django_select2.getCookie(id + '_heavy_txt:' + idx)); + if (clientLocalVal == value) { + txt.push(django_select2.getData('heavy_txt:' + id + ':' + idx)); } }); if (txt || txt === 0) { return [val, txt]; } - } + }*/ } return null; @@ -175,7 +239,7 @@ if (!window['django_select2']) { if (val || val === 0) { // Value is set so need to get the text. - data = django_select2.getValText(e); + data = django_select2.getValText(e, false); if (data && data[0]) { data = django_select2.prepareValText(data[0], data[1], !!e.attr('multiple')); } @@ -184,6 +248,7 @@ if (!window['django_select2']) { e.val(null); // Nulling out set value so as not to confuse users. } callback(data); // Change for 2.3.x + django_select2.updateText(e); }, onMultipleHiddenChange: function () { var $e = $(this), valContainer = $e.data('valContainer'), name = $e.data('name'), vals = $e.val(); @@ -219,7 +284,13 @@ if (!window['django_select2']) { var args = Array.prototype.slice.call(arguments); return f.apply($('#' + id).get(0), args); } - } + }, + logErr: function () { + if (console && console.error) { + args = Array.prototype.slice.call(arguments); + console.error.apply(console, args); + } + }, }; (function( $ ){ @@ -236,12 +307,18 @@ if (!window['django_select2']) { } } this.attr('txt', val); + } else { + this.removeAttr('txt'); } return this; } else { val = this.attr('txt'); - if (val && this.attr('multiple')) { - val = val.split(django_select2.MULTISEPARATOR); + if (this.attr('multiple')) { + if (val) { + val = val.split(django_select2.MULTISEPARATOR); + } else { + val = []; + } } return val; } diff --git a/django_select2/static/js/store.js b/django_select2/static/js/store.js new file mode 100644 index 0000000..7227dec --- /dev/null +++ b/django_select2/static/js/store.js @@ -0,0 +1,191 @@ +/* Copyright (c) 2010-2012 Marcus Westin (MODDED by AppleGrew for Django_Select2) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +;(function(){ + var store = {}, + win = window, + doc = win.document, + localStorageName = 'localStorage', + namespace = '__storejs__', + storage + + store.disabled = false + store.set = function(key, value) {} + store.get = function(key) {} + store.remove = function(key) {} + store.removeAllStartsWith = function(keyStartsWith) {} // - AppleGrew + store.clear = function() {} + store.transact = function(key, defaultVal, transactionFn) { + var val = store.get(key) + if (transactionFn == null) { + transactionFn = defaultVal + defaultVal = null + } + if (typeof val == 'undefined') { val = defaultVal || {} } + transactionFn(val) + store.set(key, val) + } + store.getAll = function() {} + + store.serialize = function(value) { + return JSON.stringify(value) + } + store.deserialize = function(value) { + if (typeof value != 'string') { return undefined } + try { return JSON.parse(value) } + catch(e) { return value || undefined } + } + + // Functions to encapsulate questionable FireFox 3.6.13 behavior + // when about.config::dom.storage.enabled === false + // See https://github.com/marcuswestin/store.js/issues#issue/13 + function isLocalStorageNameSupported() { + try { return (localStorageName in win && win[localStorageName]) } + catch(err) { return false } + } + + if (isLocalStorageNameSupported()) { + storage = win[localStorageName] + store.set = function(key, val) { + if (val === undefined) { return store.remove(key) } + storage.setItem(key, store.serialize(val)) + return val + } + store.get = function(key) { return store.deserialize(storage.getItem(key)) } + store.remove = function(key) { storage.removeItem(key) } + store.clear = function() { storage.clear() } + store.getAll = function() { + var ret = {} + for (var i=0; idocument.w=window