1+ import json
2+ from types import SimpleNamespace
3+
14from django import apps , forms
25from django .conf import settings as django_settings
3- from django .contrib .admin .widgets import SELECT2_TRANSLATIONS
6+ from django .contrib .admin .widgets import SELECT2_TRANSLATIONS , AutocompleteMixin
47from django .contrib .contenttypes .models import ContentType
58from django .contrib .sites .models import Site
69from django .core .exceptions import ObjectDoesNotExist , ValidationError
710from django .db import models
811from django .db .models .fields .related import ManyToOneRel
12+ from django .urls import reverse
913from django .utils .encoding import force_str
1014from django .utils .translation import get_language
1115from django .utils .translation import gettext as _
12- from django_select2 .forms import HeavySelect2Widget , Select2Widget
1316
1417# from djangocms_link.validators import IntranetURLValidator
1518from entangled .forms import EntangledModelForm
@@ -56,30 +59,9 @@ def __init__(self, *args, **kwargs):
5659)
5760
5861
59- class Select2jqWidget (HeavySelect2Widget if MINIMUM_INPUT_LENGTH else Select2Widget ):
60- """Make jQuery available to Select2 widget"""
61-
62+ class Select2jqWidget (AutocompleteMixin , forms .Select ):
6263 empty_label = _ ("Select a destination" )
6364
64- @property
65- def media (self ):
66- extra = ".min"
67- i18n_name = SELECT2_TRANSLATIONS .get (get_language ())
68- i18n_file = (
69- ("admin/js/vendor/select2/i18n/%s.js" % i18n_name ,) if i18n_name else ()
70- )
71- return forms .Media (
72- js = ("admin/js/vendor/select2/select2.full%s.js" % extra ,)
73- + i18n_file
74- + ("djangocms_frontend/js/django_select2.js" ,),
75- css = {
76- "screen" : (
77- "admin/css/vendor/select2/select2%s.css" % extra ,
78- "djangocms_frontend/css/select2.css" ,
79- ),
80- },
81- )
82-
8365 def __init__ (self , * args , ** kwargs ):
8466 if MINIMUM_INPUT_LENGTH :
8567 if "attrs" in kwargs :
@@ -88,9 +70,52 @@ def __init__(self, *args, **kwargs):
8870 )
8971 else :
9072 kwargs ["attrs" ] = {"data-minimum-input-length" : MINIMUM_INPUT_LENGTH }
91- kwargs .setdefault ("data_view" , "dcf_autocomplete:ac_view" )
73+ kwargs .setdefault ("admin_site" , None )
74+ kwargs .setdefault (
75+ "field" ,
76+ SimpleNamespace (name = "" , model = SimpleNamespace (
77+ _meta = SimpleNamespace (app = "djangocms_frontend" , label = "link" )
78+ ))
79+ ) # Fake field properties for autocomplete field (unused by link)
9280 super ().__init__ (* args , ** kwargs )
9381
82+ def get_url (self ):
83+ return reverse ("dcf_autocomplete:ac_view" )
84+
85+ def build_attrs (self , base_attrs , extra_attrs = None ):
86+ """
87+ Set select2's AJAX attributes.
88+
89+ Attributes can be set using the html5 data attribute.
90+ Nested attributes require a double dash as per
91+ https://select2.org/configuration/data-attributes#nested-subkey-options
92+ """
93+ attrs = super (forms .Select , self ).build_attrs (base_attrs , extra_attrs = extra_attrs )
94+ attrs .setdefault ("class" , "" )
95+ i18n_name = getattr (self , "i18n_name" , SELECT2_TRANSLATIONS .get (get_language ())) # Django 3.2 compat
96+ attrs .update (
97+ {
98+ "data-ajax--cache" : "true" ,
99+ "data-ajax--delay" : 250 ,
100+ "data-ajax--type" : "GET" ,
101+ "data-ajax--url" : self .get_url (),
102+ "data-theme" : "admin-autocomplete" ,
103+ "data-app-label" : "app" ,
104+ "data-model-name" : "model" ,
105+ "data-field-name" : "field" ,
106+ "data-allow-clear" : json .dumps (not self .is_required ),
107+ "data-placeholder" : "" , # Allows clearing of the input.
108+ "lang" : i18n_name ,
109+ "class" : attrs ["class" ]
110+ + (" " if attrs ["class" ] else "" )
111+ + "admin-autocomplete" ,
112+ }
113+ )
114+ return attrs
115+
116+ def optgroups (self , name , value , attr = None ):
117+ return super (forms .Select , self ).optgroups (name , value )
118+
94119
95120class SmartLinkField (forms .ChoiceField ):
96121 widget = Select2jqWidget
0 commit comments