X-Git-Url: https://scm.cri.ensmp.fr/git/PlinnDocument.git/blobdiff_plain/57a4d385a1d2806d5877f53b1fdb0bd94efa2dbb:/PlinnDocument.py..3b91dbcbb0b99d3d796a01813018db0e540bd0ec:/Products/PlinnDocument/static/gitweb.js diff --git a/PlinnDocument.py b/PlinnDocument.py deleted file mode 100644 index 3267069..0000000 --- a/PlinnDocument.py +++ /dev/null @@ -1,273 +0,0 @@ -# -*- coding: utf-8 -*- -####################################################################################### -# Plinn - http://plinn.org # -# Copyright (C) 2005-2007 BenoƮt PIN # -# # -# 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 Globals import InitializeClass -from AccessControl import ClassSecurityInfo -from Products.CMFCore.permissions import View, ModifyPortalContent -from Products.CMFCore.utils import getToolByName -from Products.CMFDefault.Document import Document -from OFS.PropertyManager import PropertyManager -from OFS.Folder import Folder -from OFS.Image import File, cookId -from zope.component.factory import Factory -from zope.interface import implements -from Products.Photo import Photo -from Products.Plinn.utils import makeValidId -from interfaces import IPlinnDocument -from cStringIO import StringIO -from sets import Set -import xml.dom.minidom as minidom -import re - -imgPattern = re.compile('', re.IGNORECASE) -imgWidthPattern = re.compile('style\s*=\s*".*width\s*:\s*([0-9]+)px') -imgHeightPattern = re.compile('style\s*=\s*".*height\s*:\s*([0-9]+)px') -imgSrcPattern = re.compile('src\s*=\s*"(.*)"') - -imgOrLinkPattern = re.compile('(.*?))"(.*?)>|(.*?))"(.*?)>', re.IGNORECASE) -EMPTY_PLINN_DOCUMENT = '' - - -def addPlinnDocument(self, id, title='', description='', text=''): - """ Add a Plinn Document """ - o = PlinnDocument(id, title, description, text) - self._setObject(id,o) - -class PlinnDocument(Document) : - """ Plinn document - WYSIWYG editor - based on XML and javascript - """ - implements(IPlinnDocument) - - security = ClassSecurityInfo() - - _cookedTexts = {} - - def __init__(self, id, title='', description='', text='') : - self.attachments = Folder('attachments') - Document.__init__(self, id, title=title, description=description, text_format='html', text=text) - - security.declareProtected(View, 'EditableBody') - def EditableBody(self, mergeLayers=True): - """ Transforms XML to HTML """ - - if self.text : - if not self._cookedTexts.has_key(self.absolute_url()) : - plinnElement = minidom.parseString(self.text).documentElement - - htmlDom = minidom.parseString('
') - htmlDomDoc = htmlDom.documentElement - - self._transformRectangles(plinnElement, htmlDomDoc) - firstChildStyle = htmlDomDoc.firstChild.getAttribute('style') - htmlDomDoc.setAttribute('style', firstChildStyle.replace('absolute', 'relative')) - - if mergeLayers : - mergedDom = minidom.parseString('
') - mergedDomDoc = mergedDom.documentElement - for layer in htmlDomDoc.childNodes : - for foreignchild in layer.childNodes : - child = mergedDom.importNode(foreignchild, True) - mergedDomDoc.appendChild(child) - - mergedDomDoc.setAttribute('style', htmlDomDoc.getAttribute('style')) - htmlDom = mergedDom - - htmlText = htmlDom.toprettyxml().replace('<', '<').replace('>', '>').replace('"', '"').replace('&', '&') - htmlText = htmlText.encode('utf8') - htmlText = htmlText.split('\n', 1)[1] - - htmlText = imgOrLinkPattern.sub(self._convertSrcOrHref, htmlText) - self._cookedTexts[self.absolute_url()] = htmlText - return htmlText - else : - return self._cookedTexts[self.absolute_url()] - else : - return '' - - def _convertSrcOrHref(self, m) : - dict = m.groupdict() - if dict['src'] : - tag = m.group().replace(dict['src'], self._genAbsoluteUrl(dict['src'])) - if not tag.endswith('/>') : - tag = tag[:-1] + '/>' - return tag - elif dict['href'] : - return m.group().replace(dict['href'], self._genAbsoluteUrl(dict['href'])) - else: - return m.group() - - def _genAbsoluteUrl(self, relUrl) : - if relUrl.find('attachments/') >=0 : - return self.absolute_url() + '/' + relUrl[relUrl.rindex('attachments/'):] - else : - return relUrl - - - security.declareProtected(ModifyPortalContent, 'XMLBody') - def XMLBody(self, REQUEST=None) : - """ return raw xml text """ - - if REQUEST is not None : - RESPONSE = REQUEST['RESPONSE'] - RESPONSE.setHeader('content-type', 'text/xml; charset=utf-8') - - manager = getToolByName(self, 'caching_policy_manager', None) - if manager is not None: - view_name = 'XMLBody' - headers = manager.getHTTPCachingHeaders( - self, view_name, {} - ) - - for key, value in headers: - if key == 'ETag': - RESPONSE.setHeader(key, value, literal=1) - else: - RESPONSE.setHeader(key, value) - if headers: - RESPONSE.setHeader('X-Cache-Headers-Set-By', - 'CachingPolicyManager: %s' % - '/'.join(manager.getPhysicalPath())) - - - return Document.EditableBody(self) or EMPTY_PLINN_DOCUMENT - - - security.declareProtected(ModifyPortalContent, 'addAttachment') - def addAttachment(self, file, formId) : - """ Add attachment """ - id, title = cookId('', '', file) - - id = makeValidId(self.attachments, id) - - if formId == 'ImageUploadForm': - fileOb = Photo(id, title, file, thumb_height=300, thumb_width=300) - else : - fileOb = File(id, title, '') - fileOb.manage_upload(file) - - self.attachments._setObject(id, fileOb) - fileOb = getattr(self.attachments, id) - return fileOb - - - def _transformRectangles(self, inNode, outNode) : - - for node in [ node for node in inNode.childNodes if node.nodeName == 'rectangle' ] : - if node.getAttribute('visibility') == 'hidden' : - continue - - divRect = outNode.ownerDocument.createElement('div') - outNode.appendChild(divRect) - - styleAttr = 'position:absolute' - styleAttr += ';width:%spx' % node.getAttribute('width') - styleAttr += ';height:%spx' % node.getAttribute('height') - - for subNode in node.childNodes : - if subNode.nodeName == 'upperLeftCorner' : - for point in subNode.childNodes : - if point.nodeName == 'point' : - styleAttr += ';left:%spx' % point.getAttribute('x') - styleAttr += ';top:%spx' % point.getAttribute('y') - divRect.setAttribute('style', styleAttr) - break - - elif subNode.nodeName == 'rawData' : - rawData = subNode.firstChild - if rawData : - textNode = outNode.ownerDocument.createTextNode(self.getElementTransform(node.getAttribute('elementKey'))(node, rawData.nodeValue)) - divRect.appendChild(textNode) - - self._transformRectangles(node, divRect) - - - security.declarePrivate('renderImg') - def renderImg(self, node, raw) : - width = int(node.getAttribute('width')) - height = int(node.getAttribute('height')) - - photoId = raw.split('/')[-2] - photo = self._resizePhoto(photoId, width, height) - - alt = 'image' - return '%(alt)s' % \ - {'src' : photo.absolute_url(), 'width' : width, 'height' : height, 'alt' : alt} - - - security.declarePrivate('renderEpozImg') - def renderEpozImg(self, node, raw): - for img in imgPattern.findall(raw) : - width = imgWidthPattern.findall(img) - if width : width = int(width[0]) - - height = imgHeightPattern.findall(img) - if height : height = int(height[0]) - - if not (width or height) : continue # default size - - photoId = imgSrcPattern.findall(img)[0].split('/')[-2] - self._resizePhoto(photoId, width, height) - - return raw - - - def _resizePhoto(self, photoId, width, height): - photo = getattr(self.attachments, photoId) - - nts = [width, height] - landscape = width > height - if landscape : - nts.reverse() - - thumbSize = {'width': photo.thumb_width, 'height': photo.thumb_height} - - if thumbSize['width'] != nts[0] or thumbSize['height'] != nts[1] > 1 : - photo.manage_editProperties(thumb_width=nts[0], thumb_height=nts[1]) - - return photo - - - security.declarePrivate('getElementTransform') - def getElementTransform(self, elementKey) : - transforms = {'IMG_ELEMENT': self.renderImg, - 'EPOZ_ELEMENT': self.renderEpozImg} - return transforms.get(elementKey, lambda node, raw : raw) - - def _edit(self, text): - """ Edit the Document and cook the body. - """ - Document._edit(self, text) - self._removeUnusedAttachments() - self._cookedTexts = {} - - - def _removeUnusedAttachments(self) : - if not(self.attachments.objectIds() and self.XMLBody()) : return - - reAttachments = re.compile('|'.join( [r'\b%s\b' % id for id in self.attachments.objectIds()] )) - xml = self.XMLBody() - attSet = Set(self.attachments.objectIds()) - useSet = Set(reAttachments.findall(xml)) - self.attachments.manage_delObjects([att for att in attSet - useSet]) - - -InitializeClass(PlinnDocument) -PlinnDocumentFactory = Factory(PlinnDocument) \ No newline at end of file