Skip to content

Commit

Permalink
Added django CMS history integration
Browse files Browse the repository at this point in the history
  • Loading branch information
czpython committed Jan 9, 2017
1 parent 00710ca commit e3c5510
Show file tree
Hide file tree
Showing 13 changed files with 248 additions and 67 deletions.
128 changes: 128 additions & 0 deletions djangocms_text_ckeditor/cms_plugins.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import json
from distutils.version import LooseVersion

import cms
Expand Down Expand Up @@ -41,6 +42,126 @@ def _user_can_change_placeholder(request, placeholder):
return placeholder.has_change_permission(request)


def post_add_plugin(operation, **kwargs):
from djangocms_history.actions import ADD_PLUGIN
from djangocms_history.helpers import get_bound_plugins, get_plugin_data
from djangocms_history.models import dump_json

text_plugin = kwargs['plugin']
new_plugin_ids = set(text_plugin._get_inline_plugin_ids())

if not new_plugin_ids:
# User has not embedded any plugins on the text
return

new_plugins = CMSPlugin.objects.filter(pk__in=new_plugin_ids)
new_plugins = get_bound_plugins(new_plugins)

# Extend the recorded added plugins to include the inline plugins (if any)
action = operation.actions.only('post_action_data').get(action=ADD_PLUGIN, order=1)
post_data = json.loads(action.post_action_data)
post_data['plugins'].extend(get_plugin_data(plugin) for plugin in new_plugins)
action.post_action_data = dump_json(post_data)
action.save(update_fields=['post_action_data'])


def pre_change_plugin(operation, **kwargs):
from djangocms_history.actions import ADD_PLUGIN, DELETE_PLUGIN
from djangocms_history.helpers import get_bound_plugins, get_plugin_data

old_text_plugin = kwargs['old_plugin']
old_plugin_ids = set(old_text_plugin._get_inline_plugin_ids())

new_text_plugin = kwargs['new_plugin']
new_plugin_ids = set(new_text_plugin._get_inline_plugin_ids())

added_plugin_ids = new_plugin_ids.difference(old_plugin_ids)
deleted_plugin_ids = old_plugin_ids.difference(new_plugin_ids)
plugin_ids = added_plugin_ids | deleted_plugin_ids

if added_plugin_ids == deleted_plugin_ids:
# User has not added or removed embedded plugins
return

order = 1

# This app is a special case.
# We know the old and new tree orders because inline plugins
# have already been set on the database when this pre operation
# is executed.
old_tree = (
old_text_plugin
.cmsplugin_set
.filter(pk__in=old_plugin_ids)
.order_by('position')
.values_list('pk', flat=True)
)
old_tree = list(old_tree)

new_tree = (
new_text_plugin
.cmsplugin_set
.filter(pk__in=new_plugin_ids)
.order_by('position')
.values_list('pk', flat=True)
)
new_tree = list(new_tree)

plugins = CMSPlugin.objects.filter(pk__in=plugin_ids)
bound_plugins = list(get_bound_plugins(plugins))

if added_plugin_ids:
order += 1

pre_action_data = {
'order': old_tree,
'parent_id': old_text_plugin.pk,
}

post_plugin_data = [get_plugin_data(plugin) for plugin in bound_plugins
if plugin.pk in added_plugin_ids]
post_action_data = {
'order': new_tree,
'parent_id': old_text_plugin.pk,
'plugins': post_plugin_data,
}

operation.create_action(
action=ADD_PLUGIN,
language=old_text_plugin.language,
placeholder=kwargs['placeholder'],
pre_data=pre_action_data,
post_data=post_action_data,
order=order,
)

if deleted_plugin_ids:
order += 1
deleted_plugins = [plugin for plugin in bound_plugins if plugin.pk in deleted_plugin_ids]
pre_plugin_data = [get_plugin_data(plugin) for plugin in deleted_plugins]
pre_action_data = {
'order': old_tree,
'parent_id': old_text_plugin.pk,
'plugins': pre_plugin_data,
}

post_plugin_data = [get_plugin_data(plugin, only_meta=True) for plugin in deleted_plugins]
post_action_data = {
'order': new_tree,
'parent_id': old_text_plugin.pk,
'plugins': post_plugin_data,
}

operation.create_action(
action=DELETE_PLUGIN,
language=old_text_plugin.language,
placeholder=kwargs['placeholder'],
pre_data=pre_action_data,
post_data=post_action_data,
order=order,
)


class TextPlugin(CMSPluginBase):
model = Text
name = settings.TEXT_PLUGIN_NAME
Expand All @@ -51,6 +172,13 @@ class TextPlugin(CMSPluginBase):
ckeditor_configuration = settings.TEXT_CKEDITOR_CONFIGURATION
disable_child_plugins = True

# These are executed by the djangocms-history app
# We use them to inject inline plugin data
operation_handler_callbacks = {
'post_add_plugin': post_add_plugin,
'pre_change_plugin': pre_change_plugin,
}

def get_editor_widget(self, request, plugins, plugin):
"""
Returns the Django form Widget to be used for
Expand Down
9 changes: 9 additions & 0 deletions djangocms_text_ckeditor/compat.py
@@ -1,5 +1,11 @@
from distutils.version import LooseVersion

import cms
import django

cms_version = LooseVersion(cms.__version__)


if django.VERSION < (1, 7):
from django.utils.module_loading import import_by_path
import_string = import_by_path
Expand All @@ -12,3 +18,6 @@
LTE_DJANGO_1_7 = True
else:
LTE_DJANGO_1_7 = False

LTE_CMS_3_3 = cms_version < LooseVersion('3.4')
LTE_CMS_3_4 = cms_version < LooseVersion('3.5')
10 changes: 0 additions & 10 deletions djangocms_text_ckeditor/fields.py
Expand Up @@ -3,9 +3,7 @@
from django.db import models
from django.forms.fields import CharField
from django.utils.safestring import mark_safe
from django.utils.six import add_metaclass

from .compat import LTE_DJANGO_1_7
from .html import clean_html
from .widgets import TextEditorWidget

Expand Down Expand Up @@ -65,11 +63,6 @@ def to_python(self, value):
# because it's handled by (from_db_value)
if value is None:
return value

if LTE_DJANGO_1_7:
# could be that value is already marked safe
# this is ok because mark_safe is idempotent
value = mark_safe(value)
return value

def formfield(self, **kwargs):
Expand All @@ -92,6 +85,3 @@ def formfield(self, **kwargs):
def clean(self, value, model_instance):
value = super(HTMLField, self).clean(value, model_instance)
return clean_html(value, full=False)

if LTE_DJANGO_1_7:
HTMLField = add_metaclass(models.SubfieldBase)(HTMLField)
1 change: 1 addition & 0 deletions djangocms_text_ckeditor/html.py
Expand Up @@ -45,6 +45,7 @@ def _get_default_parser():
return html5lib.HTMLParser(tree=treebuilders.getTreeBuilder("dom"),
**opts)


DEFAULT_PARSER = _get_default_parser()


Expand Down
5 changes: 4 additions & 1 deletion djangocms_text_ckeditor/models.py
Expand Up @@ -78,13 +78,16 @@ def save(self, *args, **kwargs):
super(AbstractText, self).save(update_fields=('body',))

def clean_plugins(self):
ids = plugin_tags_to_id_list(self.body)
ids = self._get_inline_plugin_ids()
unbound_plugins = self.cmsplugin_set.exclude(pk__in=ids)

for plugin in unbound_plugins:
# delete plugins that are not referenced in the text anymore
plugin.delete()

def _get_inline_plugin_ids(self):
return plugin_tags_to_id_list(self.body)

def post_copy(self, old_instance, ziplist):
"""
Fix references to plugins
Expand Down
Expand Up @@ -277,9 +277,10 @@
$(dialog.parts.title.$).text(this.options.lang.edit);

var textPluginUrl = window.location.href;
var path = encodeURIComponent(window.location.pathname);
var childPluginUrl = textPluginUrl.replace(
/(add-plugin|edit-plugin).*$/,
'edit-plugin/' + id + '/?_popup=1&no_preview'
'edit-plugin/' + id + '/?_popup=1&no_preview&cms_history=0&cms_path=' + path
);

$(dialog.parts.contents.$).find('iframe').attr('src', childPluginUrl)
Expand Down Expand Up @@ -309,7 +310,9 @@
placeholder_id: this.options.placeholder_id,
plugin_type: item.attr('rel'),
plugin_parent: this.options.plugin_id,
plugin_language: this.options.plugin_language
plugin_language: this.options.plugin_language,
cms_path: window.location.pathname,
cms_history: 0
};

that.addPluginDialog(item, data);
Expand Down

Large diffs are not rendered by default.

Expand Up @@ -7,7 +7,7 @@
{% block extrahead %}
<script>window.CKEDITOR_BASEPATH = "{{ CKEDITOR_BASEPATH }}";</script>
<script src="{% static_with_version "cms/js/dist/bundle.admin.base.min.js" %}"></script>
<script src="{% static "djangocms_text_ckeditor/js/dist/bundle-c4bd52725a.cms.ckeditor.min.js" %}"></script>
<script src="{% static "djangocms_text_ckeditor/js/dist/bundle-0cf66229ed.cms.ckeditor.min.js" %}"></script>
{% endblock %}

<script>
Expand Down
55 changes: 55 additions & 0 deletions djangocms_text_ckeditor/tests/base.py
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from cms.models import Page
from cms.test_utils.testcases import CMSTestCase
from cms.utils.urlutils import admin_reverse

from django.utils.http import urlencode
from djangocms_helper.base_test import BaseTestCase as _BaseTestCase

from ..compat import LTE_CMS_3_3


class BaseTestCase33(CMSTestCase, _BaseTestCase):

def get_admin_url(self, model, action, *args):
opts = model._meta
url_name = "{}_{}_{}".format(opts.app_label, opts.model_name, action)
return admin_reverse(url_name, args=args)

def get_add_plugin_uri(self, placeholder, plugin_type, language='en', parent=None):
endpoint = placeholder.get_add_url()
data = {
'plugin_type': plugin_type,
'placeholder_id': placeholder.pk,
'plugin_language': language,
}

if parent:
data['plugin_parent'] = parent.pk
return endpoint + '?' + urlencode(data)

def get_change_plugin_uri(self, plugin, container=None, language=None):
container = container or Page
return self.get_admin_url(container, 'edit_plugin', plugin.pk)

def get_move_plugin_uri(self, plugin, container=None, language=None):
container = container or Page
return self.get_admin_url(container, 'move_plugin')

def get_copy_plugin_uri(self, plugin, container=None, language=None):
container = container or Page
return self.get_admin_url(container, 'copy_plugins')

def get_copy_placeholder_uri(self, placeholder, container=None, language=None):
container = container or Page
return self.get_admin_url(container, 'copy_plugins')

def get_delete_plugin_uri(self, plugin, container=None, language=None):
container = container or Page
return self.get_admin_url(container, 'delete_plugin', plugin.pk)


if LTE_CMS_3_3:
BaseTestCase = BaseTestCase33
else:
BaseTestCase = type('BaseTestCase', (CMSTestCase, _BaseTestCase), {})

0 comments on commit e3c5510

Please sign in to comment.