sandino / django-trumbowyg

Django-related reusable app for integrating Trumbowyg WYSIWYG editor http://alex-d.github.io/Trumbowyg/
MIT License
19 stars 11 forks source link

jQuery doesn't work in the admin #17

Open ataylor32 opened 1 month ago

ataylor32 commented 1 month ago

The trumbowyg/widgets.py file includes //ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js (source). This doesn't work well in the admin for a couple reasons:

  1. The admin already includes jQuery, so it's a waste to load another copy
  2. The admin namespaces jQuery to django.jQuery (documentation), so using $ doesn't work
ataylor32 commented 1 month ago

It looks like this won't be an easy fix. Here is how to reproduce the problem:

  1. Create a virtual environment, activate it, and install Django 4.2.14 and django-trumbowyg

  2. Run the following commands:

    django-admin startproject testproject
    cd testproject
    python manage.py startapp blog
  3. Edit the testproject/settings.py file, adding both trumbowyg and blog to INSTALLED_APPS

  4. Edit the testproject/urls.py file, changing from django.urls import path to from django.urls import include, path and adding path('trumbowyg/', include('trumbowyg.urls')), to the urlpatterns list

  5. Edit the blog/models.py file and set its contents to this:

    from django.conf import settings
    from django.db import models
    
    class Post(models.Model):
        author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        title = models.CharField(max_length=255)
        body = models.TextField()
        created = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            ordering = ("-created",)
    
        def __str__(self):
            return self.title
  6. Edit the blog/admin.py file and set its contents to this:

    from django.contrib import admin
    from django.db import models
    from trumbowyg.widgets import TrumbowygWidget
    
    from .models import Post
    
    @admin.register(Post)
    class PostAdmin(admin.ModelAdmin):
        autocomplete_fields = ("author",)
        formfield_overrides = {
            models.TextField: {"widget": TrumbowygWidget},
        }
        list_display = (
            "author",
            "title",
            "created",
        )
  7. Run the following commands:

    python manage.py makemigrations
    python manage.py migrate
    python manage.py createsuperuser
    python manage.py runserver
  8. Go to http://localhost:8000/admin/blog/post/add/ and notice that the "Body" field does not have Trumbowyg applied to it

  9. Edit the blog/admin.py file and comment out the autocomplete_fields = ("author",) line

  10. Go to http://localhost:8000/admin/blog/post/add/ again and notice that the "Body" field now has Trumbowyg applied to it

What's happening is the <script>s are getting loaded in a different order, depending on whether or not the autocomplete_fields = ("author",) line is present.

The order of the <script>s when the autocomplete_fields = ("author",) line is present (django.jQuery is version 3.1.1 and django.jQuery.fn.trumbowyg exists, but jQuery is version 3.6.4 and jQuery.fn.trumbowyg does not exist):

<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="/static/admin/js/vendor/select2/select2.full.js"></script>
<script src="/static/trumbowyg/trumbowyg.min.js"></script> 👈
<script src="/static/admin/js/vendor/select2/i18n/en.js"></script>
<script src="/static/trumbowyg/plugins/upload/trumbowyg.upload.js"></script> 👈
<script src="/static/admin/js/jquery.init.js"></script> 👈
<script src="/static/trumbowyg/langs/en_us.min.js"></script>
<script src="/static/admin/js/core.js"></script>
<script src="/static/admin/js/autocomplete.js"></script>
<script src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script src="/static/admin/js/actions.js"></script>
<script src="/static/admin/js/urlify.js"></script>
<script src="/static/admin/js/prepopulate.js"></script>
<script src="/static/admin/js/vendor/xregexp/xregexp.js"></script>

The order of the <script>s when the autocomplete_fields = ("author",) line is not present (django.jQuery is version 3.1.1 and django.jQuery.fn.trumbowyg does not exist, and jQuery is version 3.6.4 and jQuery.fn.trumbowyg exists):

<script src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="/static/admin/js/jquery.init.js"></script> 👈
<script src="/static/trumbowyg/trumbowyg.min.js"></script> 👈
<script src="/static/admin/js/core.js"></script>
<script src="/static/trumbowyg/plugins/upload/trumbowyg.upload.js"></script> 👈
<script src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script src="/static/trumbowyg/langs/en_us.min.js"></script>
<script src="/static/admin/js/actions.js"></script>
<script src="/static/admin/js/urlify.js"></script>
<script src="/static/admin/js/prepopulate.js"></script>
<script src="/static/admin/js/vendor/xregexp/xregexp.js"></script>

This behavior also exists with Django 5.0.7 (the only difference is jQuery is version 3.7.1 instead of 3.6.4).