+++ /dev/null
-# -*- coding: utf-8 -*-
-#######################################################################################
-# Plinn - http://plinn.org #
-# Copyright (C) 2005-2007 BenoƮt PIN <benoit.pin@ensmp.fr> #
-# #
-# 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('<img(.*?)>', 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('<img(.*?)src(.*?)=(.*?)"(?P<src>(.*?))"(.*?)>|<a(.*?)href(.*?)=(.*?)"(?P<href>(.*?))"(.*?)>', re.IGNORECASE)
-EMPTY_PLINN_DOCUMENT = '<plinn><rectangle width="800" height="600" elementKey="DIV_ELEMENT" ddOptions="2" ratio="undefined" visibility="visible"><upperLeftCorner><point x="0" y="0"/></upperLeftCorner><rawData/></rectangle></plinn>'
-
-
-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('<div class="plinn_document"/>')
- htmlDomDoc = htmlDom.documentElement
-
- self._transformRectangles(plinnElement, htmlDomDoc)
- firstChildStyle = htmlDomDoc.firstChild.getAttribute('style')
- htmlDomDoc.setAttribute('style', firstChildStyle.replace('absolute', 'relative'))
-
- if mergeLayers :
- mergedDom = minidom.parseString('<div class="plinn_document"/>')
- 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 '<img src="%(src)s/getThumbnail" width="%(width)s" height="%(height)s" alt="%(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