Skip to content

Commit

Permalink
Merge pull request #20 from jaap3/modernize-js
Browse files Browse the repository at this point in the history
Modernize js
  • Loading branch information
jaap3 committed May 20, 2020
2 parents ac108c7 + 3d4e85d commit 607aee8
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 52 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ python:
- 3.7
env:
- DJANGO_VERSION=\>=2.2,\<3.0
- DJANGO_VERSION=\>=3.0a,\<3.1
- DJANGO_VERSION=\>=3.0\<3.1
- DJANGO_VERSION=\>=3.1a,\<3.2
install:
- pip install --upgrade pip
- pip install --upgrade Django$DJANGO_VERSION
Expand Down
14 changes: 12 additions & 2 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
History
-------

1.5.1 (unreleased)
1.6 (unreleased)
^^^^^^^^^^^^^^^^^^

- Nothing changed yet.
* init.js no longer depends on jQuery.
This might a backwards incompatible change for:

- Users that have defined their own init script that dependeds on
the ``$e`` var. This var has been replaced by ``field`` which is
a plain DOM node instead of a jQuery object.
- Users that depended on the implicit load of Django's bundled
version of jQuery now have explicitly load it themselves.

* Verified TinyMCE init/config works with TinyMCE 4 and 5

* Tested and verified to work with Django 3.1

1.5.0 (2019-12-04)
^^^^^^^^^^^^^^^^^^
Expand Down
24 changes: 17 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Django Rich Text Field
A Django model field and widget that renders a customizable rich
text/WYSIWYG widget.

Works in Django's admin interface and "normal" forms.

Supports global `editor settings`_, reusable `editor profiles`_
and per `field & widget settings`_. There's built-in support for
pluggable server side `content sanitizers`_.
Expand Down Expand Up @@ -42,7 +44,7 @@ Add the urls to the project's urlpatterns::
Configure ``django-richtextfield`` in ``settings.py``::

DJRICHTEXTFIELD_CONFIG = {
'js': ['//tinymce.cachefly.net/4.1/tinymce.min.js'],
'js': ['//cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js'],
'init_template': 'djrichtextfield/init/tinymce.js',
'settings': {
'menubar': False,
Expand All @@ -67,6 +69,15 @@ or forms::
content = forms.CharField(widget=RichTextWidget())


When using the editor outside of the admin make sure to include
``form.media`` in the ``<head>`` of the template::

<head>
...
{{ form.media }}
...
</head>

Configuration
-------------

Expand All @@ -82,7 +93,7 @@ Javascript souce(s)
A list of required javascript files. These can be URLs to a CDN or paths
relative to your ``STATIC_URL`` e.g.::

'js': ['//cdn.ckeditor.com/4.4.4/standard/ckeditor.js']
'js': ['//cdn.ckeditor.com/4.14.0/standard/ckeditor.js']

or::

Expand All @@ -94,12 +105,12 @@ CSS souce(s)
^^^^^^^^^^^^

``'css'``
A dictionary of CSS files required for various forms of output media.
A dictionary of CSS files required.
These can be URLs to a CDN or paths relative to your ``STATIC_URL`` e.g.::

'css': {
'all': [
'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css'
'https://cdn.example.com/css/editor.css'
]
}

Expand Down Expand Up @@ -282,9 +293,8 @@ would like this::
The init template has the following Javascript variables available from the
outer scope:

``$e``
jQuery wrapped textarea to be replaced (using the jQuery version bundled
with Django's admin)
``field``
DOM node of the textarea to be replaced
``id``
The ``id`` attribute of the textarea
``default_settings``
Expand Down
52 changes: 25 additions & 27 deletions djrichtextfield/templates/djrichtextfield/init.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
(function ($) {
(function (d) {
var default_settings = {{ default_settings }};

function initField($e) {
if ($e.parents('.empty-form').length == 0) { // Don't do empty inlines
var id = $e.attr('id');
var custom_settings = {};
if ($e.attr('data-field-settings')) {
custom_settings = $.parseJSON($e.attr('data-field-settings'));
}
var settings = $.extend({}, default_settings, custom_settings);
{% include init_template %}
function initField(field) {
if (field.closest('.empty-form')) return; // Don't do empty inlines
var id = field.id;
var custom_settings = {};
if (field.dataset.fieldSettings) {
custom_settings = JSON.parse(field.dataset.fieldSettings);
}
var settings = Object.assign({}, default_settings, custom_settings);
{% include init_template %}
}

$(function () {
// initialize the editors on load
$('textarea.djrichtextfield').each(function () {
initField($(this));
});
function initFields(parent) {
var richTextFields = parent.querySelectorAll('textarea.djrichtextfield');
for (var i = 0; i < richTextFields.length; i++) {
initField(richTextFields[i])
}
}

addEventListener('DOMContentLoaded', function () {
initFields(d);

// initialize the editor after adding an inline
// XXX: We don't use jQuery's click event as it won't work in Django 1.4
document.body.addEventListener("click", function(ev) {
if(!ev.target.parentNode || ev.target.parentNode.className.indexOf("add-row") === -1) {
return;
}
var $addRow = $(ev.target.parentNode);
setTimeout(function() { // We have to wait until the inline is added
$('textarea.djrichtextfield', $addRow.parent()).each(function () {
initField($(this));
});
d.body.addEventListener('click', function(evt) {
// initialize the editor after adding an inline
var addRow = evt.target.closest('.add-row');
if(!addRow) return;
setTimeout(function() {
initFields(addRow.parentNode);
}, 0);
}, true);
});
}(django.jQuery));
})(document);
4 changes: 2 additions & 2 deletions djrichtextfield/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.conf.urls import url
from django.urls import path

from djrichtextfield.views import InitView

urlpatterns = [
url('^init.js$', InitView.as_view(), name='djrichtextfield_init')
path('init.js', InitView.as_view(), name='djrichtextfield_init')
]
6 changes: 1 addition & 5 deletions djrichtextfield/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ def __init__(self, attrs=None, field_settings=None, sanitizer=None):

@property
def media(self):
extra = '' if django_settings.DEBUG else '.min'
js = [
'admin/js/vendor/jquery/jquery%s.js' % extra,
'admin/js/jquery.init.js'
]
js = []
js.extend(settings.CONFIG['js'])
js.append(reverse(self.INIT_URL))
return Media(js=js, css=settings.CONFIG['css'])
Expand Down
Empty file modified manage.py
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions testproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

# Django Rich Text Field
TINYMCE_CONFIG = {
'js': ['//tinymce.cachefly.net/4.1/tinymce.min.js'],
'js': ['//cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js'],
'init_template': 'djrichtextfield/init/tinymce.js',
'settings': {
'menubar': False,
Expand All @@ -75,7 +75,7 @@
}

CKEDITOR_CONFIG = {
'js': ['//cdn.ckeditor.com/4.4.4/standard/ckeditor.js'],
'js': ['//cdn.ckeditor.com/4.14.0/standard/ckeditor.js'],
'init_template': 'djrichtextfield/init/ckeditor.js',
'settings': {
'toolbar': [
Expand Down
6 changes: 6 additions & 0 deletions testproject/testapp/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

from djrichtextfield.widgets import RichTextWidget

from .models import Comment


class CommentForm(forms.ModelForm):
content = forms.CharField(widget=RichTextWidget(field_settings='mini'))

class Meta:
model = Comment
exclude = ['post']
10 changes: 10 additions & 0 deletions testproject/testapp/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db import models
from django.urls import reverse

from djrichtextfield.models import RichTextField

Expand All @@ -8,6 +9,12 @@ class Post(models.Model):
lead = RichTextField(field_settings='mini')
content = RichTextField()

def get_absolute_url(self):
return reverse('post_detail', kwargs={'pk': self.pk})

def get_add_comment_url(self):
return reverse('post_add_comment', kwargs={'pk': self.pk})

def __str__(self):
return self.title

Expand All @@ -16,5 +23,8 @@ class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField()

def get_absolute_url(self):
return '{}#c{}'.format(reverse('post_detail', kwargs={'pk': self.post.pk}), self.pk)

def __str__(self):
return 'Comment on "%s"' % self.post.title
20 changes: 20 additions & 0 deletions testproject/testapp/templates/testapp/comment_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Comment on {{ post.title }}</title>
{{ form.media }}
</head>
<body>
<article>
<h1>Comment on {{ post.title }}</h1>

<form method="post">
<div>{% csrf_token %}</div>
{{ form.as_p }}

<p><input type="submit" value="Comment"></p>
</form>
</article>
</body>
</html>
36 changes: 36 additions & 0 deletions testproject/testapp/templates/testapp/post_detail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{{ post.title }}</title>
</head>
<body>
<article>
<h1>{{ post.title }}</h1>

<div>{{ post.lead|safe }}</div>

<hr>

<div>{{ post.content|safe }}</div>
</article>

<aside>
<h2>Comments</h2>

<ul>
{% for comment in post.comment_set.all %}
<li id="c{{ comment.pk }}">
{{ comment.content|safe }}
</li>
{% empty %}
<li>
<p>No comments yet</p>
</li>
{% endfor %}
</ul>

<p><a href="{{ post.get_add_comment_url }}">Add a comment</a></p>
</aside>
</body>
</html>
18 changes: 18 additions & 0 deletions testproject/testapp/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.shortcuts import get_object_or_404
from django.views.generic import UpdateView, DetailView

from .forms import CommentForm
from .models import Comment, Post


class PostDetail(DetailView):
model = Post


class CommentCreateView(UpdateView):
model = Comment
form_class = CommentForm

def get_object(self):
post = get_object_or_404(Post, pk=self.kwargs['pk'])
return Comment(post=post)
11 changes: 8 additions & 3 deletions testproject/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from django.conf.urls import include, url
from django.urls import include, path
from django.contrib import admin

from .testapp.views import CommentCreateView, PostDetail


admin.autodiscover()

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^djrichtextfield/', include('djrichtextfield.urls'))
path('admin/', admin.site.urls),
path('djrichtextfield/', include('djrichtextfield.urls')),
path('post/<int:pk>/', PostDetail.as_view(), name='post_detail'),
path('post/<int:pk>/comment/', CommentCreateView.as_view(), name='post_add_comment')
]
15 changes: 12 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[tox]
envlist = py36-dj22, py37-dj22,
py36-dj30, py37-dj30
py36-dj30, py37-dj30,
py36-dj31, py37-dj31

[testenv]
commands = python -W module manage.py test testproject
Expand All @@ -15,11 +16,19 @@ deps = Django>=2.2,<3.0

[testenv:py36-dj30]
basepython = python3.6
deps = Django>=3.0a,<3.1
deps = Django>=3.0,<3.1

[testenv:py37-dj30]
basepython = python3.7
deps = Django>=3.0a,<3.1
deps = Django>=3.0,<3.1

[testenv:py36-dj31]
basepython = python3.6
deps = Django>=3.1a,<3.2

[testenv:py37-dj31]
basepython = python3.7
deps = Django>=3.1a,<3.2

[testenv:flake8]
commands = flake8 djrichtextfield testproject
Expand Down

0 comments on commit 607aee8

Please sign in to comment.