jrief / django-formset

The missing widgets and form manipulation library for Django
https://django-formset.fly.dev/
MIT License
317 stars 30 forks source link

RichText not rendering correctly and format buttons not working with Bootstrap #152

Closed jamiecash closed 1 month ago

jamiecash commented 1 month ago

I have a fairly simple model and have implemented the RichText functionality as follows:

class Lesson(models.Model):
    name = models.CharField(max_length=100)
    image = models.ImageField(upload_to='lessons/images/', blank=True, null=True)
    description = RichTextField(max_length=1000, blank=True)
class LessonForm(forms.ModelForm):
    image = FileField(required=False)

    class Meta:
        model = models.Lesson
        fields = ['name', 'subject', 'image', 'description', 'length']#'description', 'length', 'tutors']
        widgets = {
            'description': widgets.RichTextarea(control_elements=[
               controls.Bold(),

           ], attrs={'maxlength': 1000}),
        }

The rich text dropdown for headings is displaying as a bulleted list and none of the format buttons can be clicked. The form also can't be submitted. When replacing RichText with CharField the form works as expected.

The form field renders as follows ![image](https://github.com/user-attachments/assets/47a32b77-b1c2-48c4-8284-087ceda8af5e

I have tested tht l CSS and JS files in my page are reachable

<!-- Load stylesheets -->
--
  | <link rel="stylesheet" href="/static/css/bootstrap.min.css" />
  | <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&amp;display=swap" />
  | <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
  | <link href="/static/formset/css/bootstrap5-extra.css" rel="stylesheet">
  | <link href="/static/formset/css/collections.css" rel="stylesheet">
  | <link rel="stylesheet" href="/static/css/tutoringhub.css" />
  |  
  | <!--Load JavaScript-->
  | <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
  | integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
  | crossorigin="anonymous"></script>
  | <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  | <script type="module" src="/static/formset/js/django-formset.js"></script>
  | <script src="/static/js/bold-and-bright.js"></script>
  | <script src="/static/js/tutoringhub.js"></script>

The HTML generated for the field is as follows:

<div class="dj-richtext-wrapper"><div role="menubar"><button type="button" richtext-click="heading" aria-label="Heading" aria-haspopup="true" aria-expanded="false"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M17 11V4h2v17h-2v-8H7v8H5V4h2v7z"></path></svg></button><ul role="menu" aria-labelledby="Heading"><li><a richtext-click="heading:1"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M13 20h-2v-7H4v7H2V4h2v7h7V4h2v16zm8-12v12h-2v-9.796l-2 .536V8.67L19.5 8H21z"></path></svg></a></li><li><a richtext-click="heading:2"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M4 4v7h7V4h2v16h-2v-7H4v7H2V4h2zm14.5 4c2.071 0 3.75 1.679 3.75 3.75 0 .857-.288 1.648-.772 2.28l-.148.18L18.034 18H22v2h-7v-1.556l4.82-5.546c.268-.307.43-.709.43-1.148 0-.966-.784-1.75-1.75-1.75-.918 0-1.671.707-1.744 1.606l-.006.144h-2C14.75 9.679 16.429 8 18.5 8z"></path></svg></a></li><li><a richtext-click="heading:3"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M22 8l-.002 2-2.505 2.883c1.59.435 2.757 1.89 2.757 3.617 0 2.071-1.679 3.75-3.75 3.75-1.826 0-3.347-1.305-3.682-3.033l1.964-.382c.156.806.866 1.415 1.718 1.415.966 0 1.75-.784 1.75-1.75s-.784-1.75-1.75-1.75c-.286 0-.556.069-.794.19l-1.307-1.547L19.35 10H15V8h7zM4 4v7h7V4h2v16h-2v-7H4v7H2V4h2z"></path></svg></a></li><li><a richtext-click="heading:4"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M13 20h-2v-7H4v7H2V4h2v7h7V4h2v16zm9-12v8h1.5v2H22v2h-2v-2h-5.5v-1.34l5-8.66H22zm-2 3.133L17.19 16H20v-4.867z"></path></svg></a></li><li><a richtext-click="heading:5"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M22 8v2h-4.323l-.464 2.636c.33-.089.678-.136 1.037-.136 2.21 0 4 1.79 4 4s-1.79 4-4 4c-1.827 0-3.367-1.224-3.846-2.897l1.923-.551c.24.836 1.01 1.448 1.923 1.448 1.105 0 2-.895 2-2s-.895-2-2-2c-.63 0-1.193.292-1.56.748l-1.81-.904L16 8h6zM4 4v7h7V4h2v16h-2v-7H4v7H2V4h2z"></path></svg></a></li><li><a richtext-click="heading:6"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0H24V24H0z"></path><path d="M21.097 8l-2.598 4.5c2.21 0 4.001 1.79 4.001 4s-1.79 4-4 4-4-1.79-4-4c0-.736.199-1.426.546-2.019L18.788 8h2.309zM4 4v7h7V4h2v16h-2v-7H4v7H2V4h2zm14.5 10.5c-1.105 0-2 .895-2 2s.895 2 2 2 2-.895 2-2-.895-2-2-2z"></path></svg></a></li></ul><button type="button" richtext-click="bold" aria-label="Bold"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M 8.5,10.5 H 12 c 3.087038,0 3,-4 0,-4 H 8.5 Z m 9.5,5 C 18,17.985281 15.985281,20 13.5,20 H 6 V 4 h 6.5 c 3.957973,1.659e-4 5.987881,4.7420209 3.256,7.606 1.389334,0.804513 2.244538,2.288544 2.244,3.894 z m -9.5,-2 v 4 H 13 c 3,0 3,-4 0,-4 z"></path></svg></button><button type="button" richtext-click="italic" aria-label="Italic"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M15 20H7v-2h2.927l2.116-12H9V4h8v2h-2.927l-2.116 12H15z"></path></svg></button><button type="button" richtext-click="bulletList" aria-label="Bullet List"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M8 4h13v2H8V4zm-5-.5h3v3H3v-3zm0 7h3v3H3v-3zm0 7h3v3H3v-3zM8 11h13v2H8v-2zm0 7h13v2H8v-2z"></path></svg></button><button type="button" richtext-click="horizontalRule" aria-label="Horizontal Rule"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path d="M2 11H4V13H2V11ZM6 11H18V13H6V11ZM20 11H22V13H20V11Z"></path></svg></button><i role="separator" aria-label=""><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1.25 24" width="5" height="24" fill="currentColor"><path d="M 0,0 H 24 V 24 H 0 Z" fill="none"></path><path d="M 0.125,23 V 1 h 1 v 22 z"></path></svg></i><button type="button" richtext-click="clearFormat" aria-label="Clear Format"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M12.651 14.065L11.605 20H9.574l1.35-7.661-7.41-7.41L4.93 3.515 20.485 19.07l-1.414 1.414-6.42-6.42zm-.878-6.535l.27-1.53h-1.8l-2-2H20v2h-5.927L13.5 9.257 11.773 7.53z"></path></svg></button><button type="button" richtext-click="undo" aria-label="Undo"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M5.828 7l2.536 2.536L6.95 10.95 2 6l4.95-4.95 1.414 1.414L5.828 5H13a8 8 0 1 1 0 16H4v-2h9a6 6 0 1 0 0-12H5.828z"></path></svg></button><button type="button" richtext-click="redo" aria-label="Redo"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentColor"><path fill="none" d="M0 0h24v24H0z"></path><path d="M18.172 7H11a6 6 0 1 0 0 12h9v2h-9a8 8 0 1 1 0-16h7.172l-2.536-2.536L17.05 1.05 22 6l-4.95 4.95-1.414-1.414L18.172 7z"></path></svg></button></div><textarea is="django-richtext" name="description" cols="40" rows="10" form="id_lessonform" id="id_description" data-content="{&quot;type&quot;: &quot;doc&quot;}" class="form-control"></textarea></div>
jamiecash commented 1 month ago

This appears to be an issue with the google fonts CSS. When this is removed, the rich text widget renders correctly.

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800&amp;display=swap" />
jrief commented 1 month ago

Did you find any errors in the browser console?

jamiecash commented 1 month ago

Did you find any errors in the browser console?

Yes. See below

Uncaught TypeError: Cannot read properties of undefined (reading 'getValue')
    at get value (RichtextArea-2WHCQ2VL.js:98:31958)
    at Ve.aggregateValue (django-formset.js:19:4225)
    at new Ve (django-formset.js:19:2144)
    at Ne.assignFieldsToForms (django-formset.js:19:35294)
    at Ne.connectedCallback (django-formset.js:19:33565)
    at HTMLElement.connectedCallback (django-formset.js:19:43868)
    at django-formset.js:19:49437
jamiecash commented 1 month ago

Did you find any errors in the browser console?

Yes. See below

Uncaught TypeError: Cannot read properties of undefined (reading 'getValue')
    at get value (RichtextArea-2WHCQ2VL.js:98:31958)
    at Ve.aggregateValue (django-formset.js:19:4225)
    at new Ve (django-formset.js:19:2144)
    at Ne.assignFieldsToForms (django-formset.js:19:35294)
    at Ne.connectedCallback (django-formset.js:19:33565)
    at HTMLElement.connectedCallback (django-formset.js:19:43868)
    at django-formset.js:19:49437

The following warning also appears whether google fonts is included or not.


chunk-65OJRBX6.js:1 Could not traverse CSS import 
CSSImportRule
 DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
    at n (http://127.0.0.1:8000/static/formset/js/chunk-65OJRBX6.js:1:991)
    at Object.i [as convertPseudoClasses] (http://127.0.0.1:8000/static/formset/js/chunk-65OJRBX6.js:1:407)
    at http://127.0.0.1:8000/static/formset/js/django-formset.js:19:44070
```
jrief commented 1 month ago

The documentation states:

When loading CSS files from other domains such as a CDN or Google Fonts, then use <link href="https://cdn.somedomain.xyz" crossorigin="anonymous">. This is because django-formset parses some CSS rules, but Google Chrome refuses to do that for files from foreign origins.

did you follow these instructions?