Commit f5060164 authored by Jérome Perrin's avatar Jérome Perrin

Enable codemirror diff view for web pages

ERP5's Code mirror supports viewing history of editions using codemirror's merge mode ( http://codemirror.net/demo/merge.html ).

This was enabled for portal_components, but not for web pages.

This moves the methods used by the components in a mixin class and make `TextDocument` class use this mixin.

This way, we can benefit from diff view on web pages as well:

![ERP5-history-on-web-pages](/uploads/2bd381948266da46225ae26fd807bd51/ERP5-history-on-web-pages.png)

@romain @vincentB @katomaso unless this interfere with your work of making codemirror works in renderjs ui, I think we can enable this. It does not include any change to codemirror code, just enable everywhere what was available only on components.

@klaus I did not check, but we probably want this enabled for PyData Script as well.

/reviewed-on nexedi/erp5!449
parents 3e9ef826 5c510642
...@@ -42,6 +42,7 @@ from string import Template ...@@ -42,6 +42,7 @@ from string import Template
# Mixin Import # Mixin Import
from Products.ERP5.mixin.cached_convertable import CachedConvertableMixin from Products.ERP5.mixin.cached_convertable import CachedConvertableMixin
from Products.ERP5.mixin.base_convertable import BaseConvertableFileMixin from Products.ERP5.mixin.base_convertable import BaseConvertableFileMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from Products.ERP5Type.Utils import guessEncodingFromText from Products.ERP5Type.Utils import guessEncodingFromText
from lxml import html as etree_html from lxml import html as etree_html
...@@ -49,7 +50,7 @@ from lxml import etree ...@@ -49,7 +50,7 @@ from lxml import etree
from Products.ERP5Type.ImageUtil import transformUrlToDataURI from Products.ERP5Type.ImageUtil import transformUrlToDataURI
class TextDocument(CachedConvertableMixin, BaseConvertableFileMixin, class TextDocument(CachedConvertableMixin, BaseConvertableFileMixin, TextContentHistoryMixin,
TextContent, File): TextContent, File):
"""A TextDocument impletents IDocument, IFile, IBaseConvertable, ICachedconvertable """A TextDocument impletents IDocument, IFile, IBaseConvertable, ICachedconvertable
and ITextConvertable and ITextConvertable
......
...@@ -28,13 +28,14 @@ ...@@ -28,13 +28,14 @@
############################################################################## ##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
import zope.interface import zope.interface
from Products.ERP5Type.interfaces.component import IComponent from Products.ERP5Type.interfaces.component import IComponent
class DocumentComponent(ComponentMixin): class DocumentComponent(ComponentMixin, TextContentHistoryMixin):
""" """
ZODB Component for Documents in bt5 only for now (which used to be installed ZODB Component for Documents in bt5 only for now (which used to be installed
in INSTANCE_HOME/Document) but this will also be used later on for Documents in INSTANCE_HOME/Document) but this will also be used later on for Documents
......
...@@ -28,13 +28,14 @@ ...@@ -28,13 +28,14 @@
############################################################################## ##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
import zope.interface import zope.interface
from Products.ERP5Type.interfaces.component import IComponent from Products.ERP5Type.interfaces.component import IComponent
class ExtensionComponent(ComponentMixin): class ExtensionComponent(ComponentMixin, TextContentHistoryMixin):
""" """
ZODB Component for Extensions previously defined in the bt5 and installed in ZODB Component for Extensions previously defined in the bt5 and installed in
INSTANCE_HOME/Extensions INSTANCE_HOME/Extensions
......
...@@ -28,13 +28,14 @@ ...@@ -28,13 +28,14 @@
############################################################################## ##############################################################################
from Products.ERP5Type.mixin.component import ComponentMixin from Products.ERP5Type.mixin.component import ComponentMixin
from Products.ERP5Type.mixin.text_content_history import TextContentHistoryMixin
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
import zope.interface import zope.interface
from Products.ERP5Type.interfaces.component import IComponent from Products.ERP5Type.interfaces.component import IComponent
class TestComponent(ComponentMixin): class TestComponent(ComponentMixin, TextContentHistoryMixin):
""" """
ZODB Component for Live Tests only (previously defined in the bt5 and ZODB Component for Live Tests only (previously defined in the bt5 and
installed in INSTANCE_HOME/tests) as other kind of Tests should be installed in INSTANCE_HOME/tests) as other kind of Tests should be
......
...@@ -385,48 +385,4 @@ class ComponentMixin(PropertyRecordableMixin, Base): ...@@ -385,48 +385,4 @@ class ComponentMixin(PropertyRecordableMixin, Base):
return new_component return new_component
security.declareProtected(Permissions.ModifyPortalContent,
'getTextContentHistoryRevisionDictList')
def getTextContentHistoryRevisionDictList(self, limit=100):
"""
TODO
"""
history_dict_list = self._p_jar.db().history(self._p_oid, size=limit)
if history_dict_list is None:
# Storage doesn't support history
return ()
from struct import unpack
from OFS.History import historicalRevision
previous_text_content = None
result = []
for history_dict in history_dict_list:
text_content = historicalRevision(self, history_dict['tid']).getTextContent()
if text_content and text_content != previous_text_content:
history_dict['time'] = history_dict['time']
history_dict['user_name'] = history_dict['user_name'].strip()
history_dict['key'] = '.'.join(map(str, unpack(">HHHH", history_dict['tid'])))
del history_dict['tid']
del history_dict['size']
result.append(history_dict)
previous_text_content = text_content
return result
security.declareProtected(Permissions.ModifyPortalContent,
'getTextContentHistory')
def getTextContentHistory(self, key):
"""
TODO
"""
from struct import pack
from OFS.History import historicalRevision
serial = apply(pack, ('>HHHH',) + tuple(map(int, key.split('.'))))
rev = historicalRevision(self, serial)
return rev.getTextContent()
InitializeClass(ComponentMixin) InitializeClass(ComponentMixin)
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2017 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type import Permissions
class TextContentHistoryMixin:
"""Mixin that provides access to history of edit of the text content property.
To be used with erp5_code_mirror
"""
security = ClassSecurityInfo()
security.declareProtected(Permissions.ModifyPortalContent,
'getTextContentHistoryRevisionDictList')
def getTextContentHistoryRevisionDictList(self, limit=100):
"""Returns the history of edition as a list of dictionnaries.
"""
history_dict_list = self._p_jar.db().history(self._p_oid, size=limit)
if history_dict_list is None:
# Storage doesn't support history
return ()
from struct import unpack
from OFS.History import historicalRevision
previous_text_content = None
result = []
for history_dict in history_dict_list:
text_content = historicalRevision(self, history_dict['tid'])._baseGetTextContent()
if text_content and text_content != previous_text_content:
history_dict['time'] = history_dict['time']
history_dict['user_name'] = history_dict['user_name'].strip()
history_dict['key'] = '.'.join(map(str, unpack(">HHHH", history_dict['tid'])))
del history_dict['tid']
del history_dict['size']
result.append(history_dict)
previous_text_content = text_content
return result
security.declareProtected(Permissions.ModifyPortalContent,
'getTextContentHistory')
def getTextContentHistory(self, key):
"""Returns the text content of a previous version of the document.
"""
from struct import pack
from OFS.History import historicalRevision
serial = apply(pack, ('>HHHH',) + tuple(map(int, key.split('.'))))
rev = historicalRevision(self, serial)
return rev._baseGetTextContent()
InitializeClass(TextContentHistoryMixin)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment