Ticket #15220: 15220-selectfilter-r16355.patch

File 15220-selectfilter-r16355.patch, 10.9 KB (added by dbunskoek, 13 years ago)
  • django/contrib/admin/media/js/selectfilter.js

     
     1(function($) {
     2        var settings = {
     3                'name': '',
     4                'verbose_name': '',
     5                'is_stacked': 0,
     6                'admin_media_prefix': '',
     7                'select': function select(options, from, to) {
     8                        SelectBox.move(from.attr('id'), to.attr('id'));
     9                        SelectBox.sort(to.attr('id'));
     10                        SelectBox.redisplay(to.attr('id'));
     11                },
     12                'deselect': function deselect(options, from, to) {
     13                        SelectBox.move(from.attr('id'), to.attr('id'));
     14                        SelectBox.sort(to.attr('id'));
     15                        SelectBox.redisplay(to.attr('id'));
     16                }
     17        };
     18
     19        var methods = {
     20                init: function(options) {
     21                        $.extend(settings, options);
     22                        var choices = this;
     23                        var stack_class = settings.is_stacked ? 'selector stacked' : 'selector';
     24                        var selector = $('<div>').addClass(stack_class);
     25
     26                        choices.parent().append(selector);
     27                        choices.attr({
     28                                'id': choices.attr('id') + '_from',
     29                                'name': choices.attr('name') + '_old'
     30                        });
     31
     32                        var search = $('<input>').attr({
     33                                'id': 'id_' + settings.name + '_input',
     34                                'type': 'text'
     35                        });
     36
     37                        $('<div>').addClass('selector-available')
     38                                .append($('<h2>').text(gettext('Available ') + settings.verbose_name))
     39                                .append(
     40                                        $('<p>').addClass('selector-filter')
     41                                                .append(
     42                                                        $('<label>').attr('for', search.attr('id')).css({'width': "16px", 'padding': "2px"})
     43                                                                .append(
     44                                                                        $('<img>').attr('src', settings.admin_media_prefix + 'img/admin/selector-search.gif')
     45                                                                )
     46                                                )
     47                                                .append(search)
     48                                ).append(choices)
     49                                .append($('<a>').addClass('selector-chooseall').text(gettext('Choose all')).attr('href', '#'))
     50                                .appendTo(selector);
     51
     52                        $('<ul>').addClass('selector-chooser')
     53                                .append($('<li>')
     54                                        .append($('<a>').addClass('selector-add').text(gettext('Add')))
     55                                )
     56                                .append($('<li>')
     57                                        .append($('<a>').addClass('selector-remove').text(gettext('Remove')))
     58                                )
     59                                .appendTo(selector);
     60
     61                        var selected = $('<select>').addClass('filtered').attr({
     62                                'id': 'id_' + settings.name + '_to',
     63                                'multiple': 'multiple',
     64                                'name': settings.name
     65                        });
     66
     67                        $('<div>').addClass('selector-chosen')
     68                                .append($('<h2>').text('Chosen ' + settings.verbose_name))
     69                                .append(
     70                                        $('<p>').addClass('selector-filter')
     71                                                .text(gettext('Select your choice(s) and click '))
     72                                                .append(
     73                                                        $('<img>').attr({
     74                                                                'src': settings.admin_media_prefix + 'img/admin/selector-add.gif',
     75                                                                'alt': gettext('Add')
     76                                                        })
     77                                                )
     78                                ).append(selected)
     79                                .append(
     80                                        $('<a>').addClass('selector-clearall')
     81                                                .text(gettext('Clear all'))
     82                                                .attr('href', '#')
     83                                ).appendTo(selector);
     84
     85                        SelectBox.init(choices.attr('id'));
     86                        SelectBox.init(selected.attr('id'));
     87
     88                        // If this is a saved instance, move the already selected options across
     89                        // to the selected list.
     90                        settings.select(choices.children().filter(':selected'), choices, selected);
     91
     92                        // Hook up selection events.
     93                        $(search).keyup(function(event) {
     94                                if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) {
     95                                        settings.select(choices.children().filter(':selected'), choices, selected);
     96                                        return false;
     97                                }
     98                                SelectBox.filter(choices.attr('id'), $(this).val());
     99                                return true;
     100                        });
     101                        $('.selector-chooseall').click(function() {
     102                                settings.select(choices.children(), choices, selected);
     103                                return false;
     104                        });
     105
     106                        $('.selector-clearall').click(function() {
     107                                settings.deselect(selected.children(), selected, choices);
     108                                return false;
     109                        });
     110
     111                        $('.selector-add').click(function() {
     112                                settings.select(choices.children().filter(':selected'), choices, selected);
     113                                return false;
     114                        });
     115
     116                        $('.selector-remove').click(function() {
     117                                settings.deselect(selected.children().filter(':selected'), selected, choices);
     118                                return false;
     119                        });
     120
     121                        choices.dblclick(function() {
     122                                settings.select(choices.children().filter(':selected'), choices, selected);
     123                        });
     124
     125                        selected.dblclick(function() {
     126                                settings.deselect(selected.children().filter(':selected'), selected, choices);
     127                        });
     128
     129                        choices.keydown(function(event) {
     130                                event.which = event.which ? event.which : event.keyCode;
     131                                switch(event.which) {
     132                                        case 13:
     133                                                // Enter pressed - don't submit the form but move the current selection.
     134                                                settings.select(choices.children().filter(':selected'), choices, selected);
     135                                                this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
     136                                                return false;
     137                                        case 39:
     138                                                // Right arrow - move across (only when horizontal)
     139                                                if (!settings.is_stacked) {
     140                                                        settings.select(choices.children().filter(':selected'), choices, selected);
     141                                                        this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
     142                                                        return false;
     143                                                }
     144                                }
     145                                return true;
     146                        });
     147
     148                        selected.keydown(function(event) {
     149                                event.which = event.which ? event.which : event.keyCode;
     150                                switch(event.which) {
     151                                        case 13:
     152                                                // Enter pressed - don't submit the form but move the current selection.
     153                                                settings.select(selected.children().filter(':selected'), selected, choices);
     154                                                this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
     155                                                return false;
     156                                        case 37:
     157                                                // Left arrow - move across (only when horizontal)
     158                                                if (!settings.is_stacked) {
     159                                                        settings.select(selected.children().filter(':selected'), selected, choices);
     160                                                        this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
     161                                                        return false;
     162                                                }
     163                                }
     164                                return true;
     165                        });
     166
     167                        $('form').submit(function() {
     168                                selected.children().each(function(i, option) {
     169                                        $(option).attr('selected', 'selected');
     170                                });
     171                                return true;
     172                        });
     173                }
     174        };
     175
     176        $.fn.selectFilter = function(method) {
     177                if (methods[method]) {
     178                        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
     179                } else if (typeof method === 'object' || !method ) {
     180                        return methods.init.apply(this, arguments);
     181                } else {
     182                        $.error('Method ' + method + ' does not exist on jQuery.selectFilter');
     183                }
     184        };
     185})(django.jQuery);
  • django/contrib/admin/options.py

     
    13211321            js.append('js/urlify.js')
    13221322            js.append('js/prepopulate.min.js')
    13231323        if self.filter_vertical or self.filter_horizontal:
    1324             js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
     1324            js.extend(['js/SelectBox.js' , 'js/selectfilter.js'])
    13251325        return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
    13261326    media = property(_media)
    13271327
  • django/contrib/admin/widgets.py

     
    2222    catalog has been loaded in the page
    2323    """
    2424    class Media:
    25         js = (settings.ADMIN_MEDIA_PREFIX + "js/core.js",
    26               settings.ADMIN_MEDIA_PREFIX + "js/SelectBox.js",
    27               settings.ADMIN_MEDIA_PREFIX + "js/SelectFilter2.js")
     25        js = (settings.ADMIN_MEDIA_PREFIX + 'js/SelectBox.js',
     26              settings.ADMIN_MEDIA_PREFIX + "js/selectfilter.js",)
    2827
    2928    def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
    3029        self.verbose_name = verbose_name
     
    3534        if attrs is None: attrs = {}
    3635        attrs['class'] = 'selectfilter'
    3736        if self.is_stacked: attrs['class'] += 'stacked'
     37        id_ = attrs.get('id', 'id_%s' % name)
    3838        output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
    39         output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
    40         # TODO: "id_" is hard-coded here. This should instead use the correct
    41         # API to determine the ID dynamically.
    42         output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % \
    43             (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
     39        output.append(u'''
     40<script type="text/javascript">
     41(function($) {
     42    $(function() {
     43        $("#%(id)s").selectFilter({
     44            'name': "%(name)s",
     45            'verbose_name': "%(verbose_name)s",
     46            'is_stacked': %(is_stacked)s,
     47            'admin_media_prefix': "%(admin_media_prefix)s"
     48        });
     49    });
     50})(django.jQuery);
     51</script>''' % {
     52            'id': id_,
     53            'name': name,
     54            'verbose_name': self.verbose_name.replace('"', '\\"'),
     55            'is_stacked': int(self.is_stacked),
     56            'admin_media_prefix': settings.ADMIN_MEDIA_PREFIX
     57        })
    4458        return mark_safe(u''.join(output))
    4559
    4660class AdminDateWidget(forms.DateInput):
     
    131145            url = u''
    132146        if "class" not in attrs:
    133147            attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook.
     148        id_ = attrs.get('id', 'id_%s' % name)
    134149        output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
    135         # TODO: "id_" is hard-coded here. This should instead use the correct
    136         # API to determine the ID dynamically.
    137         output.append(u'<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
    138             (related_url, url, name))
     150        output.append(u'<a href="%s%s" class="related-lookup" id="lookup_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
     151            (related_url, url, id_))
    139152        output.append(u'<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" /></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup')))
    140153        if value:
    141154            output.append(self.label_for_value(value))
     
    238251        self.widget.choices = self.choices
    239252        output = [self.widget.render(name, value, *args, **kwargs)]
    240253        if self.can_add_related:
    241             # TODO: "id_" is hard-coded here. This should instead use the correct
    242             # API to determine the ID dynamically.
    243             output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
    244                 (related_url, name))
     254            id_ = self.attrs.get('id', 'id_%s' % name)
     255            output.append(u'<a href="%s" class="add-another" id="add_%s" onclick="return showAddAnotherPopup(this);"> ' % \
     256                (related_url, id_))
    245257            output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="%s"/></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
    246258        return mark_safe(u''.join(output))
    247259
Back to Top