Code

Ticket #15220: 15220-selectfilter-r16355.patch

File 15220-selectfilter-r16355.patch, 10.9 KB (added by dbunskoek, 3 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