--- /dev/null
+# -*- coding: utf-8 -*-
+#######################################################################################
+# Plinn - http://plinn.org #
+# Copyright © 2005-2009 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. #
+#######################################################################################
+"""
+Adapter to plug PlinnDocument to historycal interface.
+
+$Id: HistoryAdapters.py 647 2009-06-30 12:55:44Z pin $
+$URL: http://svn.cri.ensmp.fr/svn/PlinnDocument/branches/CMF-2.1/HistoryAdapters.py $
+"""
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.CMFCore.permissions import ModifyPortalContent
+from Products.Plinn.HistoryAdapters import DocumentHistory
+
+class PlinnDocumentHistory(DocumentHistory) :
+
+ security = ClassSecurityInfo()
+
+ security.declareProtected(ModifyPortalContent, 'restore')
+ def restore(self, key):
+ rev = self.getHistoricalRevisionByKey(key)[0]
+ self._content.edit(rev.Format(), rev.XMLBody())
+
+InitializeClass(PlinnDocumentHistory)
--- /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
--- /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 Products.CMFCore import utils
+from Products.CMFCore.permissions import AddPortalContent
+
+import PlinnDocument
+
+contentClasses = (PlinnDocument.PlinnDocument,)
+contentConstructors = (PlinnDocument.addPlinnDocument,)
+
+def initialize(registrar) :
+ utils.ContentInit(
+ 'Plinn Content',
+ content_types = contentClasses,
+ permission = AddPortalContent,
+ extra_constructors = contentConstructors,
+ ).initialize(registrar)
\ No newline at end of file
--- /dev/null
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five"
+ xmlns:cmf="http://namespaces.zope.org/cmf"
+ xmlns:genericsetup="http://namespaces.zope.org/genericsetup">
+
+ <cmf:registerDirectory directory="skins" name="plinn_document" recursive="True"/>
+
+ <five:registerClass
+ class=".PlinnDocument.PlinnDocument"
+ meta_type="Plinn Document"
+ permission="cmf.AddPortalContent"
+ />
+ <utility
+ component=".PlinnDocument.PlinnDocumentFactory"
+ name="plinndocument"
+ />
+
+ <genericsetup:registerProfile
+ name="default"
+ title="Plinn Document"
+ description="Adds Plinn document content type."
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ for="Products.CMFCore.interfaces.ISiteRoot"
+ />
+
+ <adapter
+ provides="Products.Plinn.interfaces.IContentHistory"
+ for=".interfaces.IPlinnDocument"
+ factory=".HistoryAdapters.PlinnDocumentHistory"/>
+
+</configure>
\ No newline at end of file
--- /dev/null
+from zope.interface import Interface
+
+class IPlinnDocument(Interface):
+ """ Plinn document
+ """
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="CMF Types Tool">
+ <object name="Plinn Document" meta_type="Factory-based Type Information"/>
+</object>
--- /dev/null
+<?xml version="1.0"?>
+<object name="Plinn Document" meta_type="Factory-based Type Information"
+ i18n:domain="plinn" xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title">Plinn Document</property>
+ <property name="description">Plinn Documents contain text and images that can be layout with WYSIWYG and drag&drop editor.</property>
+ <property name="content_icon">plinn_doc.gif</property>
+ <property name="content_meta_type">Plinn Document</property>
+ <property name="product"></property>
+ <property name="factory">plinndocument</property>
+ <property name="immediate_view">object/edit</property>
+ <property name="global_allow">True</property>
+ <property name="filter_content_types">True</property>
+ <property name="allowed_content_types"></property>
+ <property name="allow_discussion">False</property>
+ <alias from="info" to="content_info"/>
+ <alias from="gethtml" to="source_html"/>
+ <alias from="(Default)" to="plinndocument_view"/>
+ <alias from="view" to="plinndocument_view"/>
+ <action action_id="view" title="View" condition_expr=""
+ url_expr="string:${object_url}/plinndocument_view"
+ category="object" visible="True">
+ <permission value="View"/>
+ </action>
+ <action action_id="edit" title="Edit" condition_expr=""
+ url_expr="string:${object_url}/plinndocument_edit_form"
+ category="object" visible="True">
+ <permission value="Modify portal content"/>
+ </action>
+ <action action_id="localroles" title="Share"
+ condition_expr=""
+ url_expr="string:${object_url}/folder_localrole_form"
+ category="object" visible="True">
+ <permission value="Set Local Roles"/>
+ </action>
+ <action action_id="history" title="Status history"
+ condition_expr=""
+ url_expr="string:${object_url}/content_status_history"
+ category="object" visible="True">
+ <permission value="Request review"/>
+ <permission value="Review portal content"/>
+ </action>
+</object>
--- /dev/null
+// (c) Benoît PIN 2006-2007
+// http://plinn.org
+// Licence GPL
+
+function HSVColor(h, s, v) {
+ this.h = h; // 0-360°
+ this.s = s; // 0-100%
+ this.v = v; // 0-100%
+}
+
+HSVColor.prototype.toRGBString = function() {
+ var rgb = this.toRGB();
+ return "rgb(" + String(rgb[0]) + ", " + String(rgb[1]) + ", " + String(rgb[2]) + ")";
+};
+
+HSVColor.prototype.toRGB = function () {
+ var h = this.h; var s = this.s/100.0;
+ var v = this.v/100.0;
+ if( s == 0 ) // achromatic (grey)
+ r = g = b = v;
+
+ h = h/60; // sector 0 to 5
+ var i = Math.floor( h );
+ var f = h - i; // factorial part of h
+ var p = v * ( 1 - s );
+ var q = v * ( 1 - s * f );
+ var t = v * ( 1 - s * ( 1 - f ) );
+ switch( i ) {
+ case 0:
+ r = v;
+ g = t;
+ b = p;
+ break;
+ case 1:
+ r = q;
+ g = v;
+ b = p;
+ break;
+ case 2:
+ r = p;
+ g = v;
+ b = t;
+ break;
+ case 3:
+ r = p;
+ g = q;
+ b = v;
+ break;
+ case 4:
+ r = t;
+ g = p;
+ b = v;
+ break;
+ default: // case 5:
+ r = v;
+ g = p;
+ b = q;
+ break;
+ }
+
+ r = Math.round(r*255);
+ g = Math.round(g*255);
+ b = Math.round(b*255);
+ return [r, g, b];
+};
+
+
+function ColorIterator(baseH, baseS, baseV, step) {
+ this.baseColor = new HSVColor(baseH, baseS, baseV);
+ this.currentH = baseH;
+ this.step = step;
+}
+
+ColorIterator.prototype.next = function() {
+ var c = new HSVColor(this.currentH, this.baseColor.s, this.baseColor.v);
+ this.currentH += this.step;
+
+ if (this.currentH >= 360)
+ this.currentH -= 360;
+
+ return c;
+};
+
+function setBorderColor(ob, colorString) {
+ var s = ob.style;
+ s.borderBottomColor = colorString;
+ s.borderLeftColor = colorString;
+ s.borderRightColor = colorString;
+ s.borderTopColor = colorString;
+}
+
+
+function setBorderStyle(ob, borderStyle) {
+ var s= ob.style;
+ s.borderBottomStyle = borderStyle;
+ s.borderLeftStyle = borderStyle;
+ s.borderRightStyle = borderStyle;
+ s.borderTopStyle = borderStyle;
+}
+
+
+function setBorderWidth(ob, borderWidth) {
+ var s= ob.style;
+ s.borderBottomWidth = borderWidth;
+ s.borderLeftWidth = borderWidth;
+ s.borderRightWidth = borderWidth;
+ s.borderTopWidth = borderWidth;
+}
+
+function zfill(number, digits) {
+ number = Math.floor(number);
+ var nStr = String(number);
+ while (nStr.length < digits)
+ nStr = "0" + nStr;
+ return nStr;
+}
+
--- /dev/null
+[default]
+cache=HTTPCache
--- /dev/null
+// (c) Benoît PIN 2006-2007
+// http://plinn.org
+// Licence GPL
+
+function ddEventDispatch() {
+ addListener(document, 'mousedown', raisemousedown);
+ addListener(document, 'mousemove', raisemousemove);
+ addListener(document, 'mouseup', raisemouseup);
+}
+
+
+function getRectangleNode() {
+ var docid = document.id;
+ docid = document.id.slice(DocPrefixLength);
+ var frameId = IFramePrefix + docid;
+ iframe = window.parent.document.getElementById(frameId);
+ if (!iframe)
+ iframe = window.parent.document.getElementById("EpozEditor");
+ return iframe.parentNode;
+}
+
+var raisemousedown, raisemousemove, raisemouseup;
+
+if (browser.isIE55 || browser.isIE6up) {
+ raisemousedown = function() {
+ var rect = getRectangleNode();
+ rect.fireEvent('onmousedown', window.event);
+ };
+
+ raisemousemove = function() {
+ var rect = getRectangleNode();
+ rect.fireEvent('onmousemove', window.event);
+ rect.fireEvent('onmouseover', window.event);
+ };
+
+ raisemouseup = function() {
+ var rect = getRectangleNode();
+ rect.fireEvent('onmouseup', window.event);
+ };
+}
+else if (browser.isDOM2Event) {
+ // initMouseEvent("eventType", bubblesFlas, cancelableFlag, view, detailVal, screenX, screenY, clientX, clientY, ctrlKeyFlag, altKeyFlag, shiftKeyFlag, metaKeyFlag, buttonCode, relatedTargetNodeRef)
+
+ raisemousedown = function(e) {
+ var event = document.createEvent("MouseEvents");
+ var rect = getRectangleNode()
+ event.initMouseEvent("mousedown", true, true, window.parent, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, rect);
+ rect.dispatchEvent(event);
+ };
+
+
+ raisemousemove = function(e) {
+ var overEvent = document.createEvent("MouseEvents");
+ overEvent.initMouseEvent("mouseover", true, true, window.parent, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, rect);
+ var event = document.createEvent("MouseEvents");
+ var rect = getRectangleNode()
+ event.initMouseEvent("mousemove", true, true, window.parent, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, rect);
+ rect.dispatchEvent(event);
+ rect.dispatchEvent(overEvent);
+ };
+
+
+ raisemouseup = function(e) {
+ var event = document.createEvent("MouseEvents");
+ var rect = getRectangleNode()
+ event.initMouseEvent("mouseup", true, true, window.parent, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, rect);
+ rect.dispatchEvent(event);
+ };
+}
--- /dev/null
+[default]
+cache=HTTPCache
--- /dev/null
+// (c) Benoît PIN 2006-2007
+// http://plinn.org
+// Licence GPL
+
+// Global variables
+var CURRENT_LAYER;
+var LAYER_MANAGER;
+var XML_OUTPUT;
+var PLINN_DOCUMENT_URL;
+var GLOBAL_DD_CONTROLER;
+
+function initPlinn(root_container, xmlDataUrl) {
+ PLINN_DOCUMENT_URL = document.getElementById("PlinnDocumentUrl").innerHTML;
+ form_path = PLINN_DOCUMENT_URL+'/'; // for epoz
+ initElementsPool();
+ initWidgets();
+ var imp = new XMLImport(xmlDataUrl, root_container);
+ GLOBAL_DD_CONTROLER = new GlobalPlinnDDControler(root_container);
+}
+
+
+function initWidgets() {
+ // Global control widgets
+ XML_OUTPUT = document.getElementById("xml_output")
+}
+
+function initLayerManager(root_container) {
+ LAYER_MANAGER = new LayerManager(root_container, new ColorIterator(240, 80, 60, 83)); // todo : move in config file
+}
+
+function Point(x, y) {
+ this.x = x;
+ this.y = y;
+}
+Point.prototype.difference = function(point) { return new Point(this.x - point.x, this.y - point.y); };
+Point.prototype.addition = function(point) { return new Point(this.x + point.x, this.y + point.y); };
+Point.prototype.toString = function() { return "(" + String(this.x) + ", " + String(this.y) + ")"; };
+
+
+function GlobalPlinnDDControler(root_container) {
+ this.root_container = root_container;
+ this.dragInProgress = false;
+
+ this.currentRect = null;
+ this.dragAllowed = null;
+ this.resizeAllowed = null;
+ this.scalable = null;
+ this.deleteAllowed = null;
+
+
+ //Constants
+ this.DRAG_MODE = 0;
+ this.RESIZE_MODE = 1;
+
+ this.mode = this.DRAG_MODE;
+ this.ddEventCaptureElmt = document;
+
+ // event listeners
+ var thisControler = this;
+ with (this.root_container) {
+ onmouseover = function(evt){thisControler.onmouseover(evt);};
+ onmouseout = function(evt){thisControler.onmouseout(evt);};
+ }
+ with (this.ddEventCaptureElmt) {
+ onmousedown = function(evt){thisControler.onmousedown(evt);};
+ onmousemove = function(evt){thisControler.onmousemove(evt);};
+ onmouseup = function(evt){thisControler.onmouseup(evt);};
+ }
+}
+
+GlobalPlinnDDControler.prototype.onmouseover = function(evt) {
+ if (this.dragInProgress) return;
+ var ob = getTargetedObject(evt);
+ var rect = ob.rectangle;
+ if (!rect) return;
+ rect.showHandles();
+};
+
+GlobalPlinnDDControler.prototype.onmouseout = function(evt) {
+ if (this.dragInProgress) return;
+ var ob = getTargetedObject(evt);
+ var rect = ob.rectangle;
+ if (!rect) return;
+ rect.hideHandles();
+};
+
+GlobalPlinnDDControler.prototype.onmousedown = function(evt) {
+ var ob = getTargetedObject(evt);
+ var rect = ob.rectangle;
+
+ if (!rect) return;
+
+ this.currentRect = rect;
+ this.setDDOptions(rect.ddOptions);
+
+ var evt = getEventObject(evt);
+ if (this.deleteAllowed && (
+ (evt.shiftKey && evt.altKey) ||
+ (ob.tagName == "IMG" && ob.className=="rectangle_delimg")) ) {
+ if (confirm(PlinnLang["Do you realy want to delete ?"])) {
+ var hostDiv = rect.hostDiv;
+ hostDiv.parentNode.removeChild(hostDiv);
+ }
+ return;
+ }
+
+ this.originalClickPoint = new Point(evt.screenX, evt.screenY);
+ this.originalSize = new Point(rect.width, rect.height);
+ this.offsetPoint = rect.upperLeftCorner.difference(this.originalClickPoint);
+
+ if (evt.shiftKey || (ob.tagName == "SPAN" && ob.className=="resize_handle")) {
+ this.mode = this.RESIZE_MODE;
+ this.startDrag(evt, rect);
+ }
+ else if(evt.altKey || (ob.tagName == "DIV" && ob.className=="rectangle_header")){
+ this.mode = this.DRAG_MODE;
+ this.startDrag(evt, rect);
+ }
+};
+
+GlobalPlinnDDControler.prototype.onmousemove = function(evt) {
+ var evt = getEventObject(evt);
+ if (this.dragInProgress) {
+ var rectangle = this.currentRect;
+ if (this.dragAllowed && (this.mode == this.DRAG_MODE)) {
+ var relativeEvtPoint = new Point(evt.screenX, evt.screenY).addition(this.offsetPoint);
+ rectangle.moveTo(relativeEvtPoint);
+ }
+ else if (this.resizeAllowed && (this.mode == this.RESIZE_MODE)) {
+ var delta = new Point(evt.screenX, evt.screenY).difference(this.originalClickPoint);
+ var size = this.originalSize.addition(delta);
+ if (this.scalable) {
+ size = new Point(size.x, Math.round(size.x * rectangle.ratio));
+ }
+
+ rectangle.resizeTo(size);
+ }
+ if (browser.isIE) {
+ try {document.selection.clear();}
+ catch (e){return;}
+ }
+ }
+};
+
+GlobalPlinnDDControler.prototype.onmouseup = function(evt) {
+ this.drop()
+ var rectangle = this.currentRect;
+ if (rectangle && rectangle.ondrop)
+ rectangle.ondrop();
+};
+
+
+GlobalPlinnDDControler.prototype.startDrag = function(evt, rect) {
+ disablePropagation(evt);
+ disableDefault(evt);
+ this.dragInProgress = true;
+};
+
+GlobalPlinnDDControler.prototype.drop = function() {this.dragInProgress = false;};
+
+GlobalPlinnDDControler.prototype.setDDOptions = function(options){
+ this.dragAllowed = (options & 1) == 1;
+ this.resizeAllowed = (options & 2) == 2;
+ this.scalable = (options & 4) == 4;
+ this.deleteAllowed = (options & 8) == 8;
+};
+
+
+
+function LayerManager(main_space, colorIterator) {
+ this.space = main_space;
+ this.layers = new Array();
+ this.defaultLayerWidth = 800;
+ this.defaultLayerHeight = 600;
+ this.colorIterator = colorIterator;
+ this.layerSelector = document.getElementById('layerSelector');
+ var thisManager = this;
+
+ // add layer selector commands
+ // separator between layers list and layer commandes
+ var sepOpt = document.createElement("option");
+ sepOpt.innerHTML = "--------";
+ sepOpt.disabled = "disabled";
+ sepOpt.style.color = "#888";
+
+ // new layer command
+ var addLayerOpt = document.createElement("option");
+ addLayerOpt.value = "add";
+ addLayerOpt.innerHTML = PlinnLang["New layer"];
+ addLayerOpt.style.color = "#000";
+
+ // remove layer command
+ var removeLayerOpt = document.createElement("option");
+ removeLayerOpt.value = "rm";
+ removeLayerOpt.innerHTML = PlinnLang["Remove layer"];
+ removeLayerOpt.disabled = "disabled";
+
+ with (this.layerSelector) {
+ appendChild(sepOpt);
+ appendChild(addLayerOpt);
+ appendChild(removeLayerOpt);
+ }
+ addListener(this.layerSelector, 'change', function(){thisManager.activateLayer();});
+}
+
+LayerManager.prototype.addLayer = function(position) {
+ var color = this.colorIterator.next();
+ var mode = 6; // resize and delete
+ if (this.layers.length <= 1)
+ mode = 2; // resize only
+ var l = new Rectangle(new Point(0, 0), this.defaultLayerWidth, this.defaultLayerHeight, "DIV_ELEMENT", 2);
+ setBorderColor(l, color.toRGBString());
+ l.onresize = resizeOnMouseMove;
+ l.ondrop = resizeOnDrop;
+ l.style.overflow = "hidden";
+ l.draw(this.space, position);
+ var index = this.layers.push(l) - 1;
+
+ var opt = document.createElement("option");
+ strId = String(index);
+ opt.value = strId;
+ opt.id = "layer_" + strId;
+ opt.innerHTML = PlinnLang["Layer "] + strId;
+ opt.style.color = color.toRGBString();
+ this.layerSelector.insertBefore(opt, this.layerSelector.childNodes[this.layers.length-1]);
+
+ // If there's only one layer, the remove command is disabled.
+ if (this.layers.length > 1) {
+ var rmCommand = this.layerSelector.childNodes[this.layerSelector.length -1]
+ rmCommand.removeAttribute("disabled");
+ rmCommand.style.color="#000";
+ }
+ this.activateLayer(index);
+};
+
+LayerManager.prototype.activateLayer = function(index) {
+ var layerSelector = this.layerSelector;
+ var index = (index != null) ? index : layerSelector.value;
+ // handle commands
+ index = ( Number(index) || Number(index ) == 0 ) ? Number(index) : index
+
+ if (typeof(index) == typeof('')) {
+ switch (index) {
+ case "add" :
+ this.addLayer();
+ break;
+ case "rm" :
+ this.removeCurrentLayer();
+ break;
+ };
+ return;
+ }
+
+ CURRENT_LAYER = this.layers[index];
+ this._syncLayerStatusImage();
+ var opt = document.getElementById("layer_" + String(index));
+ layerSelector.selectedIndex = opt.index;
+ layerSelector.style.color = opt.style.color;
+ this.putCurrentLayerOnTop();
+};
+
+
+LayerManager.prototype.putCurrentLayerOnTop = function() {
+ for(var i = 0 ; i < this.layers.length ; i++) {
+ layer = this.layers[i];
+ if (layer == CURRENT_LAYER)
+ layer.style.zIndex = String(this.layers.length);
+ else
+ layer.style.zIndex = String(i);
+ }
+};
+
+LayerManager.prototype.toggleLayerVisibility = function(){
+ var currentVisibility = CURRENT_LAYER.style.visibility;
+ if (currentVisibility == "hidden")
+ CURRENT_LAYER.style.visibility = "visible";
+ else
+ CURRENT_LAYER.style.visibility = "hidden";
+
+ this._syncLayerStatusImage();
+};
+
+LayerManager.prototype._syncLayerStatusImage = function() {
+ var layerStatusImage = document.getElementById("layer_status");
+ if (CURRENT_LAYER.style.visibility == "hidden") {
+ layerStatusImage.src = "plinn_icons/hidden_layer.gif";
+ layerStatusImage.title = PlinnLang["Show layer"];
+ }
+ else {
+ layerStatusImage.src = "plinn_icons/visible_layer.gif";
+ layerStatusImage.title = PlinnLang["Hide layer"];
+ }
+};
+
+LayerManager.prototype.removeCurrentLayer = function() {
+ var layersLength = this.layers.length;
+ var layerSelector = this.layerSelector;
+ var layer, deletedLayerIndex;
+ for (var i = 0 ; i < layersLength ; i++) {
+ layer = this.layers[i];
+ if (layer == CURRENT_LAYER) {
+ if (confirm(PlinnLang["confirm_layer_delete"] + i + "\" ?")) {
+ this.space.removeChild(layer.hostDiv);
+ this.layers.splice(i, 1);
+ layerSelector.removeChild(layerSelector.childNodes[i]);
+ deletedLayerIndex = i;
+ break;
+ }
+ else {
+ this.activateLayer(i);
+ return;
+ }
+ }
+ }
+
+ // update layer indexes
+ for (var i = 0 ; i < this.layers.length ; i++) {
+ layerSelector.childNodes[i].value = String(i);
+ layerSelector.childNodes[i].id = "layer_" + String(i);
+ layerSelector.childNodes[i].innerHTML = PlinnLang["Layer "] + String(i);
+ }
+
+ if (this.layers.length == 1) {
+ var removeCmdOpt = layerSelector.childNodes[layerSelector.childNodes.length - 1];
+ removeCmdOpt.disabled = "disabled";
+ removeCmdOpt.style.color = "#888";
+ }
+
+ if (deletedLayerIndex == 0)
+ this.layers[0].style.position = "relative";
+
+ // activate previous layer
+ this.activateLayer((deletedLayerIndex > 0) ? --deletedLayerIndex : 0);
+
+};
+
+function resizeOnMouseMove() {
+ if (LAYER_MANAGER.layers.length > 5)
+ return; // to expensive
+ else
+ _resizeAllLayers(this);
+}
+
+function resizeOnDrop() { _resizeAllLayers(this);}
+
+function _resizeAllLayers(layer) {
+ var layers = LAYER_MANAGER.layers;
+ var size = new Point(layer.width, layer.height);
+ var l;
+ for(var i = 0 ; i < layers.length ; i++) {
+ l = layers[i];
+ if (layer != l)
+ l.resizeTo(size, true);
+ }
+ LAYER_MANAGER.defaultLayerWidth = size.x;
+ LAYER_MANAGER.defaultLayerHeight = size.y;
+}
+
+function CreateAttachmentLink(data) {
+ // data like that : "title[attachment/a_file]
+ var title = data.split("\[", 1)[0];
+ var url =data.match(/\[(.*)\]/)[1];
+ var link ="<a href=\"" + url + "\">" + title + "</a>";
+ InsertHTML(link);
+}
\ No newline at end of file
--- /dev/null
+[default]
+cache=HTTPCache
--- /dev/null
+// (c) Benoît PIN 2006-2007
+// http://plinn.org
+// Licence GPL
+
+var ELEMENTS_POOL = {};
+
+function initElementsPool() {
+ // Element pool (for cloning)
+ ELEMENTS_POOL["DIV_ELEMENT"] = {"node" : document.getElementById("div"),
+ "beforeDraw" : null,
+ "getRawData" : null,
+ "putData" : null };
+
+ imgBeforeDraw = function() {
+ if (!this.node.src) {
+ var dispatch = document.getElementById("ImgDispatcher");
+ var strRatio = dispatch.value.split("_", 1)[0];
+ var src = dispatch.value.substring(strRatio.length+1);
+ this.ratio = new Number(strRatio).valueOf();
+ this.node.src = PLINN_DOCUMENT_URL + '/' + src;
+ var w = this.width;
+ var size = (this.ratio > 1) ?
+ new Point(w, Math.round(w * this.ratio)) :
+ new Point(Math.round(w / this.ratio), w);
+
+ this.resizeTo(size);
+ }
+ }
+
+ ELEMENTS_POOL["IMG_ELEMENT"] = {"node" : document.getElementById("img"),
+ "beforeDraw" : imgBeforeDraw,
+ "getRawData" : function() {
+ var src = this.node.src;
+ src = src.split('/');
+ return "attachments/" + src[src.length - 2] + "/getThumbnail";
+ },
+ "putData" : function(raw) {
+ this.node.src = PLINN_DOCUMENT_URL+"/attachments/"+raw;
+ }
+ };
+
+ epozBeforeDraw = function() {
+ var rect = this
+ var iframe = this.node.childNodes[0];
+ var name = String(Math.floor(Math.random() * 10000));
+ addListener(iframe, 'load', function(){initTextRectangle(iframe, name, rect);});
+
+ var ta = this.node.childNodes[1];
+ ta.name = name;
+ ta.id = name;
+ }
+
+ ELEMENTS_POOL["EPOZ_ELEMENT"] = {"node" : document.getElementById("epoz"),
+ "beforeDraw" : epozBeforeDraw,
+ "getRawData" : function() {
+ return this.node.childNodes[0].contentWindow.document.body.innerHTML;
+ },
+ "putData" : function(raw) {
+ this.node.childNodes[1].value = raw;
+ }
+ };
+
+ for (var i = 0 ; i < ELEMENTS_POOL.length ; i++)
+ ELEMENTS_POOL[i].removeAttribute("id");
+}
+
+function Rectangle(upperLeftCorner, width, height, elementKey, ddOptions, ratio) {
+ this.meta_type = "Rectangle"; // ;-)
+ this.upperLeftCorner = upperLeftCorner;
+ this.width = width;
+ this.height = height;
+ this.elementKey = elementKey;
+ this.node = ELEMENTS_POOL[elementKey]["node"].cloneNode(true);
+ with (this.node.style) {
+ width="100%";
+ height="100%";
+ }
+ this.beforeDraw = ELEMENTS_POOL[elementKey]["beforeDraw"];
+ this.getRawData = ELEMENTS_POOL[elementKey]["getRawData"];
+ this.ddOptions = (!ddOptions) ? 11 : ddOptions; // 11-> drag, resize, delete
+ this.ratio = ratio;
+
+ this.hostDiv = document.createElement("div");
+ this.hostDiv.appendChild(this.node);
+
+ this.resizeHandle = document.createElement("span");
+ this.resizeHandle.className = "resize_handle";
+ this.hostDiv.appendChild(this.resizeHandle);
+
+ if((this.ddOptions & 8) == 8) { // move allowed
+ this.movDelHandle = document.createElement("div");
+ this.movDelHandle.className = "rectangle_header";
+ var delImg = document.createElement("img");
+ delImg.src = "delete_rectangle.gif";
+ delImg.className = "rectangle_delimg";
+ delImg.onmouseover=function(){this.src="delete_rectangle_hover.gif";}
+ delImg.onmouseout=function(){this.src="delete_rectangle.gif";}
+ this.movDelHandle.appendChild(delImg);
+ this.hostDiv.appendChild(this.movDelHandle);
+ this.movDelHandle.rectangle = this;
+ delImg.rectangle = this;
+
+ }
+
+ // backward references
+ this.style = this.hostDiv.style;
+ this.node.rectangle = this;
+ this.hostDiv.rectangle = this;
+ this.resizeHandle.rectangle = this;
+}
+
+Rectangle.prototype.showHandles = function() {
+ if (this.resizeHandle)
+ this.resizeHandle.style.visibility = "visible";
+ if (this.movDelHandle)
+ this.movDelHandle.style.visibility = "visible";
+};
+
+Rectangle.prototype.hideHandles = function() {
+ if (this.resizeHandle)
+ this.resizeHandle.style.visibility = "hidden";
+ if (this.movDelHandle)
+ this.movDelHandle.style.visibility = "hidden";
+};
+
+Rectangle.prototype._mac_moveDelHandle = function() {
+ // fix height
+ var epozWindow = this.node.childNodes[0].contentWindow;
+ if (epozWindow.scrollMaxY)
+ this.resizeHandle.style.right = "15px";
+ else
+ this.resizeHandle.style.right = "0px";
+
+ // fix width
+ if (epozWindow.scrollMaxX)
+ this.resizeHandle.style.bottom = "15px";
+ else
+ this.resizeHandle.style.bottom = "0px";
+};
+
+
+Rectangle.prototype.draw = function(container, position) {
+ if (this.beforeDraw)
+ this.beforeDraw();
+ var style = this.style;
+ style.left = String(this.upperLeftCorner.x) + "px";
+ style.top = String(this.upperLeftCorner.y) + "px";
+ style.width = String(this.width) + "px";
+ style.height = String(this.height) + "px";
+
+ style.display="block";
+ var pos;
+ if (!position)
+ pos = "absolute";
+ else
+ pos = position;
+ style.position = pos;
+ setBorderStyle(this, "solid");
+ setBorderWidth(this, "1px");
+ style.visibility = "inherit";
+/* style.overflow = "hidden";*/
+ if (container.meta_type == "Rectangle")
+ setBorderColor(this, container.style.borderTopColor);
+
+ container.appendChild(this.hostDiv);
+};
+
+
+Rectangle.prototype.moveTo = function(upperLeftCorner) {
+ this.upperLeftCorner = upperLeftCorner;
+ var style = this.style;
+ style.left = String(this.upperLeftCorner.x) + "px";
+ style.top = String(this.upperLeftCorner.y) + "px";
+};
+
+Rectangle.prototype.resizeTo = function(size, cancelOnresize) {
+ if (size.x >= 10)
+ this.width = size.x;
+ if (size.y >= 10)
+ this.height = size.y;
+
+ var style = this.style;
+ style.width = String(this.width) + "px";
+ style.height = String(this.height) + "px";
+ if (this.onresize && !cancelOnresize)
+ this.onresize();
+};
+
+Rectangle.prototype.appendChild = function(node) {
+ this.node.appendChild(node);
+};
+
+Rectangle.prototype.setId = function(id) {
+ this.node.id = id;
+};
+
+
+
+function initTextRectangle(iframe, name, rect) {
+ var ta = iframe.nextSibling; // ta -> textarea
+ var data = ta.value;
+
+ if (browser.isGecko) {
+ // Just a few cleanups for Mozilla
+ data = data.replace(/<strong>/ig,'<b>');
+ data = data.replace(/<strong(\s[^>]*)>/ig,'<b$1>');
+ data = data.replace(/<\/strong>/ig,'</b>');
+
+ data = data.replace(/<em>/ig,'<i>');
+ data = data.replace(/<em(\s[^>]*)>/ig,'<i$1>');
+ data = data.replace(/<\/em>/ig,'</i>');
+ }
+
+ // change iframe id
+ iframe.id = IFramePrefix + name;
+ iframe.style.border = "0px none transparent";
+
+
+ iframe.contentWindow.document.body.innerHTML = data;
+ iframe.contentWindow.document.id = DocPrefix + name;
+ addListener(iframe, "click", handlePlinnEpozRedirect);
+ if (browser.isMac) {
+ addListener(iframe.contentWindow.document, 'overflow', function(){rect._mac_moveDelHandle();});
+ addListener(iframe.contentWindow.document, 'underflow', function(){rect._mac_moveDelHandle();});
+ }
+
+ if (browser.isGecko) {
+ scriptExpr = 'EnableDesignMode("' + iframe.id + '");';
+ window.setTimeout(scriptExpr, 10);
+ }
+}
+
+// « overloads »
+
+function handlePlinnEpozRedirect(evt) {
+ redirectPlinnEpoz(getTargetedObject(evt));
+}
+
+function redirectPlinnEpoz(iframe) {
+ if(EpozElement) {
+ if (EpozElement == iframe)
+ return;
+ unwrapPlinnEpozVariables();
+ }
+
+ // update Epoz variables
+ wrapPlinnEpozVariables(iframe);
+ EpozElement.contentWindow.focus();
+}
+
+function wrapPlinnEpozVariables(iframe) {
+ fieldId = iframe.contentWindow.document.id.slice(DocPrefixLength);
+
+ iframe.id = Epoz ;
+ EpozElement=iframe;
+ EpozTextArea = document.getElementById(fieldId);
+}
+
+
+function unwrapPlinnEpozVariables() {
+ if (!EpozElement) // no redirection happens yet.
+ return;
+ try {
+ fieldId = EpozElement.contentWindow.document.id.slice(DocPrefixLength);
+ }
+ catch (e) { }
+
+ EpozElement.id = IFramePrefix + fieldId;
+}
--- /dev/null
+[default]
+cache=HTTPCache
--- /dev/null
+##parameters=
+form = context.REQUEST.form
+formId = form.get('formId')
+epozInsert = form.get('epozInsert', False)
+file = form.get('file', None)
+fileOb = None
+
+if file : fileOb = context.addAttachment(file, formId)
+
+onload = None
+if fileOb is not None :
+ if fileOb.meta_type == 'Photo' :
+ fileUrl = 'attachments/%s/getThumbnail' % fileOb.getId()
+ if epozInsert :
+ onload = "dispatchImageAndHideUploadForm('%s', '%s', true);" % (fileUrl, formId)
+ else :
+ ratio = float(fileOb.height)/fileOb.width
+ dispatchValue = "%f_%s" % (ratio, fileUrl)
+ onload = "dispatchImageAndHideUploadForm('%s','%s', false);" % (dispatchValue, formId)
+ else :
+ dispatchValue = '%s[%s]' % (fileOb.getId(), 'attachments/'+fileOb.getId())
+ onload = "dispatchFileAndHideUploadForm('%s', '%s');" % (dispatchValue, formId)
+
+hideFormCode = "hideUploadForm('%s');" % formId
+
+return context.plinn_attachment_template(onload=onload,
+ hideFormCode=hideFormCode,
+ formId=formId)
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml"
+ tal:define="portal_url nocall:here/portal_url;
+ dummy python:request.RESPONSE.setHeader('Content-Type', 'text/html;;charset=utf-8')">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <script type="text/javascript" defer="defer" tal:attributes="src here/epoz_script_detect.js/absolute_url"></script>
+ <script type="text/javascript" defer="defer" tal:attributes="src here/javascript_events_api.js/absolute_url"></script>
+ <link href="." rel="stylesheet" media="screen" tal:attributes="href here/zpt_stylesheet.css/absolute_url" />
+ <link href="." rel="stylesheet" media="screen" tal:attributes="href string:${portal_url}/plinn_style.css" />
+ <style>
+ body {background:#ccc;}
+ </style>
+ <script type="text/javascript">
+ //<!--
+ function hideUploadForm(formId) {
+ window.parent.document.getElementById(formId).style.visibility = "hidden" ;
+ }
+
+ function dispatchImageAndHideUploadForm(imgUrl, formId, epozInsert) {
+ var dispatcherId = (epozInsert) ? "EpozImgDispatcher" : "ImgDispatcher";
+ var dispatch = window.parent.document.getElementById(dispatcherId);
+ dispatch.value = imgUrl;
+ raiseMouseEvent(dispatch, 'click');
+ window.parent.document.getElementById(formId).style.visibility = "hidden" ;
+ }
+
+ function dispatchFileAndHideUploadForm(data, formId) {
+ var dispatch = window.parent.document.getElementById("AttachmentDispatcher");
+ dispatch.value = data;
+ raiseMouseEvent(dispatch, 'click');
+ window.parent.document.getElementById(formId).style.visibility = "hidden" ;
+ }
+ //-->
+ </script>
+ <title>Image upload form</title>
+ </head>
+
+ <body tal:attributes="onload options/onload"
+ i18n:domain="plinn">
+ <h3 i18n:translate="" tal:condition="python:options['formId']=='ImageUploadForm'">Insert image</h3>
+ <h3 i18n:translate="" tal:condition="python:options['formId']=='FileUploadForm'">Insert file</h3>
+ <form action="plinn_attachment_form" method="post" enctype="multipart/form-data">
+ <input type="hidden" name="formId" tal:attributes="value options/formId" />
+ <input type="file" name="file" size="16"/><input type="submit" name="upload" value="Upload" i18n:attributes="value" /><br>
+ <label tal:condition="python:options['formId']=='ImageUploadForm'">
+ <input type="checkbox" name="epozInsert:bool" value="True" />
+ <span i18n:translate="" tal:omit-tag="">Insert inside text</span>
+ </label>
+ </form>
+ <button onclick="hideUploadForm();" i18n:translate="" tal:attributes="onclick options/hideFormCode">Cancel</button>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns:tal="http://xml.zope.org/namespaces/tal"
+xmlns:metal="http://xml.zope.org/namespaces/metal">
+<head>
+<base tal:attributes="href python:here.absolute_url()+'/'" />
+<meta http-equiv="Content-Type"
+ tal:define="dummy python:request.RESPONSE.setHeader('Content-Type', 'text/html;; charset=%s' % request.get('charset','utf-8'))"
+ tal:attributes="content python: 'text/html;; charset=%s' % request.get('charset','utf-8')" />
+<style media="all" type="text/css">
+a {
+ text-decoration:none;
+ border-bottom:1px solid #369;
+}
+<!--
+ a[name] {
+ border:1px solid grey;
+ background: lightgrey url(misc_/Epoz/epoz_button_anchor.gif) -2px -3px no-repeat;
+ padding: 1px 0px 1px 20px;
+ margin: 5px;
+ }
+
+ a[name]:after {
+ content: attr(name);
+ }
+-->
+</style>
+<style tal:condition="python: request.get('css')" type="text/css" media="all"
+ tal:content="string:@import url(${request/css});"></style>
+<style tal:condition="python: request.get('customcss')" type="text/css" media="all"
+ tal:content="string:@import url(${request/customcss});"></style>
+<script type="text/javascript" tal:attributes="src here/epoz_script_detect.js/absolute_url"></script>
+<script type="text/javascript" tal:attributes="src here/epoz_iframe_trigger.js/absolute_url"></script>
+<script type="text/javascript" tal:attributes="src here/javascript_events_api.js/absolute_url"></script>
+<script type="text/javascript" tal:attributes="src here/dd_trigger.js/absolute_url"></script>
+<script type="text/javascript"><!--
+ ddEventDispatch();
+//-->
+</script>
+</head>
+<body class="plinn_document" contentEditable="true">
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<!--
+ function init() {
+ initPlinn(document.getElementById("&dtml-main_space;"), "&dtml-xmlDataUrl;");
+ }
+ //window.addEventListener("load", init, true);
+
+//
+-->
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>Plinn macros</title>
+ </head>
+
+ <body>
+<div id="EpozToolbar" metal:define-macro="EpozToolbar" i18n:domain="epoz">
+<select id="formatblock" onchange="SelectFormat(this)" style="margin-bottom: 2px" >
+ <option value="" i18n:translate="">Normal</option>
+ <option value="<p>" i18n:translate="">Paragraph</option>
+ <option value="<h1>" i18n:translate="">Heading1</option>
+ <option value="<h2>" i18n:translate="">Heading2</option>
+ <option value="<h3>" i18n:translate="">Heading3</option>
+ <option value="<h4>" i18n:translate="">Heading4</option>
+ <option value="<h5>" i18n:translate="">Heading5</option>
+ <option value="<h6>" i18n:translate="">Heading6</option>
+ <option value="<pre>" i18n:translate="">Formatted</option>
+</select>
+<img tal:attributes="src here/epoz_button_bold.gif/absolute_url" width="23" height="22" alt="Bold" title="Bold" onclick="FormatText('bold', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_italic.gif/absolute_url" width="23" height="22" alt="Italic" title="Italic" onclick="FormatText('italic', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_underline.gif/absolute_url" width="23" height="22" alt="Underline" title="Underline" onclick="FormatText('underline', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_strikethrough.gif/absolute_url" width="23" height="22" alt="Strikethrough" title="Strikethrough" onclick="FormatText('strikethrough', '');" i18n:attributes="alt ; title"
+/> <img tal:attributes="src here/epoz_button_subscript.gif/absolute_url" width="23" height="22" alt="Subscript" title="Subscript" onclick="FormatText('subscript', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_superscript.gif/absolute_url" width="23" height="22" alt="Superscript" title="Superscript" onclick="FormatText('superscript', '');" i18n:attributes="alt ; title"
+/> <img tal:attributes="src here/epoz_button_unformat.gif/absolute_url" width="23" height="22" alt="RemoveFormat" title="RemoveFormat" onclick="FormatText('removeformat', '');" i18n:attributes="alt ; title"
+/> <img tal:attributes="src here/epoz_button_textcolor.gif/absolute_url" width="23" height="22" alt="TextColor" title="TextColor" onclick="SetTextColor();" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_bgcolor.gif/absolute_url" width="23" height="22" alt="BackColor" title="BackColor" onclick="SetBackColor();" i18n:attributes="alt ; title"
+/> <img tal:attributes="src here/epoz_button_left_just.gif/absolute_url" width="23" height="22" alt="AlignLeft" title="AlignLeft" onclick="FormatText('justifyleft', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_centre.gif/absolute_url" width="23" height="22" alt="Center" title="Center" onclick="FormatText('justifycenter', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_right_just.gif/absolute_url" width="23" height="22" alt="AlignRight" title="AlignRight" onclick="FormatText('justifyright', '');" i18n:attributes="alt ; title"
+/> <img tal:attributes="src here/epoz_button_numbered_list.gif/absolute_url" width="23" height="22" alt="OrderedList" title="OrderedList" onclick="FormatText('insertorderedlist', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_list.gif/absolute_url" width="23" height="22" alt="UnorderedList" title="UnorderedList" onclick="FormatText('insertunorderedlist', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_outdent.gif/absolute_url" width="23" height="22" alt="Outdent" title="Outdent" onclick="FormatText('outdent', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_indent.gif/absolute_url" width="23" height="22" alt="Indent" title="Indent" onclick="FormatText('indent', '');" i18n:attributes="alt ; title"
+/>
+
+<img tal:attributes="src here/plinn_image_upload.gif/absolute_url" width="23" height="22" alt="InsertImage" title="InsertImage"
+onclick="document.getElementById('ImageUploadForm').style.visibility='visible';" i18n:attributes="alt ; title"
+/><span style="position:relative;vertical-align:top;z-index:1000"><span id="ImageUploadForm"><div style="position:relative;vertical-align:top"><div
+ style="position:absolute;width:23px;height:7px;top:-9px;left:288px;background:#ccc;border-left: 1px solid #aaa;border-right: 1px solid #aaa;float:left"><!-- --></div></div>
+ <iframe tal:attributes="src string:${here/absolute_url}/plinn_attachment_form?formId=ImageUploadForm"
+ style="width:100% ; height:100% ; border:none" frameborder="0"></iframe></span>
+</span>
+
+<img tal:attributes="src here/plinn_file_upload.gif/absolute_url" width="23" height="22" alt="InsertFile" title="InsertFile"
+onclick="document.getElementById('FileUploadForm').style.visibility='visible';" i18n:attributes="alt ; title"
+/><span style="position:relative;vertical-align:top;z-index:1000"><span id="FileUploadForm"><div style="position:relative;vertical-align:top"><div
+ style="position:absolute;width:23px;height:7px;top:-9px;left:288px;background:#ccc;border-left: 1px solid #aaa;border-right: 1px solid #aaa;float:left"><!-- --></div></div>
+ <iframe tal:attributes="src string:${here/absolute_url}/plinn_attachment_form?formId=FileUploadForm"
+ style="width:100% ; height:100% ; border:none" frameborder="0"></iframe></span>
+</span>
+
+<img tal:attributes="src here/epoz_button_hyperlink.gif/absolute_url" width="23" height="22" alt="InsertLink" title="InsertLink" onclick="CreateLink();" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_anchor.gif/absolute_url" width="23" height="22" alt="InsertAnchor" title="InsertAnchor" onclick="CreateAnchor();" i18n:attributes="alt ; title"
+/>
+<img tal:attributes="src here/epoz_button_hr.gif/absolute_url" width="23" height="22" alt="InsertRule" title="InsertRule" onclick="FormatText('inserthorizontalrule', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_table.gif/absolute_url" width="23" height="22" alt="InsertTable" title="InsertTable" i18n:attributes="alt ; title" onclick="window.open('epoz_script_table.html','EpozTable','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=220,height=220')"
+/> <img tal:attributes="src here/epoz_button_undo.gif/absolute_url" width="23" height="22" alt="Undo" title="Undo" onclick="FormatText('undo', '');" i18n:attributes="alt ; title"
+/><img tal:attributes="src here/epoz_button_redo.gif/absolute_url" width="23" height="22" alt="Redo" title="Redo" onclick="FormatText('redo', '');" i18n:attributes="alt ; title" />
+</div> </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+var PlinnLang=[];
+<tal:block define="messages python:[
+ 'Do you realy want to delete ?'
+, 'confirm_layer_delete'
+, 'Layer '
+, 'New layer'
+, 'Remove layer'
+, 'Hide layer'
+, 'Show layer'
+] ;
+charset request/form/charset;
+dummy python:request.RESPONSE.setHeader('Content-Type', 'text/javascript;;charset=' + charset)
+"
+i18n:domain="plinn"
+>
+<tal:block repeat="m messages">PlinnLang["<tal:block replace="m" />"]="<tal:block content="m" i18n:translate="" tal:omit-tag="" />";</tal:block>
+</tal:block>
\ No newline at end of file
--- /dev/null
+[default]
+cache=HTTPCache
--- /dev/null
+## Script (Python) "plinndocument_edit"
+##parameters=text='', file='', SafetyBelt='', **kw
+##title=Edit a document
+##
+
+from Products.CMFDefault.exceptions import EditingConflict, ResourceLockedError
+
+if text != context.text :
+ try:
+ context.edit( 'html', text, file, safety_belt = SafetyBelt)
+ return context.setStatus(True, 'Document changed.')
+ except (ResourceLockedError, EditingConflict), msg:
+ return context.setStatus(False, msg)
+else :
+ return context.setStatus(False, 'Nothing to change.')
--- /dev/null
+##parameters=change='', change_and_view='', ajax=''
+
+form = context.REQUEST.form
+if change and \
+ context.plinndocument_edit_control(**form) and \
+ context.setRedirect(context, 'object/edit', ajax=ajax) :
+ return
+elif change_and_view and \
+ context.plinndocument_edit_control(**form) and \
+ context.setRedirect(context, 'object/view', ajax=ajax) :
+ return
+
+return context.plinndocument_edit_template()
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml" metal:use-macro="here/main_template/macros/master" i18n:domain="plinn">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <metal:block metal:fill-slot="javascript_head_slot">
+ <script type="text/javascript" tal:attributes="src python:'%s/%s?charset=%s' % (portal_url, 'epoz_multilingual.js', here.default_charset)"></script>
+ <script type="text/javascript" tal:attributes="src here/vcXMLRPC.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src here/epoz_script_main.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src here/epoz_redirect.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src here/color_utils.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src string:${portal_url}/plinn_multilingual.js?charset=utf-8"></script>
+ <script type="text/javascript" tal:attributes="src here/layout_controlers.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src here/layout_objects.js/absolute_url"></script>
+ <script type="text/javascript" tal:attributes="src here/xml_io.js/absolute_url"></script>
+ </metal:block>
+ </head>
+
+ <body>
+ <div metal:fill-slot="header">
+ <div metal:use-macro="here/widgets/macros/generic_header">generic_header macro</div>
+ </div>
+
+<div metal:fill-slot="main" tal:omit-tag="">
+ <!-- tools -->
+ <span id="PlinnDocumentUrl" tal:content="here/absolute_url" style="display:none"></span>
+ <img width="25" height="25" alt="Add text" title="Add text" tal:attributes="src here/plinn_icons/textarea.gif/absolute_url" onclick="new Rectangle(new Point(30, 30), 300, 200, 'EPOZ_ELEMENT').draw(CURRENT_LAYER);" />
+ <input type="hidden" id="ImgDispatcher" value=""
+ onclick="new Rectangle(new Point(30, 30), 200, 200, 'IMG_ELEMENT', 15).draw(CURRENT_LAYER);"/>
+ <input type="hidden" id="EpozImgDispatcher" value=""
+ onclick="CreateImage(PLINN_DOCUMENT_URL+'/'+this.value);">
+ <input type="hidden" id="AttachmentDispatcher" value="" onclick="CreateAttachmentLink(this.value);" />
+ <select id="layerSelector"></select>
+ <img id="layer_status" width="13" height="11" onclick="LAYER_MANAGER.toggleLayerVisibility();"
+ tal:attributes="src here/plinn_icons/visible_layer.gif/absolute_url" alt="Toggle layer visibility" title="Hide layer" />
+
+ <div metal:use-macro="here/plinn_macros/macros/EpozToolbar"></div>
+
+ <!-- main wysiwyg document node -->
+ <form style="margin:0"><div id="main_space" style="position:relative"></div></form>
+
+ <!-- elements for cloning -->
+ <div id="elements_pool" style="display:none">
+ <div id="div"></div>
+ <img id="img" alt="image" />
+ <div id="epoz"><iframe src="plinn_blank_iframe.html?charset=utf8&css=zpt_stylesheet.css&customcss=plinn_style.css"
+ style="width:100% ; height:100% ; border:none ; background:transparent" allowTransparency="true" frameborder="no"></iframe><textarea style="display:none"></textarea></div>
+ </div>
+ <form action="." style="margin:0" method="post" enctype="multipart/form-data" id="plinn_document_form"
+ tal:attributes="action string:${here/absolute_url}/plinndocument_edit_form">
+ <input type="hidden" name="onBeforeSubmit" value="_plinnDocumentBeforeSubmit" />
+ <textarea id="xml_output" name="text" style="display:none" rows="1" cols="1"></textarea>
+ <br/><input type="submit" value="Save" name="change_and_view" i18n:attributes="value" />
+ </form>
+ <script type="text/javascript">
+ //<!--
+ initPlinn(document.getElementById("main_space"), document.getElementById("PlinnDocumentUrl").innerHTML+ "/XMLBody");
+ var plinnDocumentForm = document.getElementById('plinn_document_form');
+ if ((AJAX_CONFIG & 2) == 2) {
+ var fm = new FormManager(plinnDocumentForm);
+ fm.onBeforeSubmit = _plinnDocumentBeforeSubmit;
+ }
+ else {
+ addListener(plinnDocumentForm, 'submit', _plinnDocumentBeforeSubmit);
+ }
+ //-->
+ </script>
+</div>
+ </body>
+</html>
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml"
+ metal:use-macro="here/main_template_view/macros/master">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>Plinn document edit</title>
+ </head>
+
+ <body metal:fill-slot="main" tal:omit-tag="">
+ <p tal:replace="structure context/EditableBody"></p>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+// (c) Benoît PIN 2006-2007
+// http://plinn.org
+// Licence GPL
+
+function XMLExport() {
+ this.domDoc = Sarissa.getDomDocument('http://plinn.org/namespaces/plinn_document/1.0', 'plinn');
+ this.rootNode = this.domDoc.documentElement;
+}
+
+XMLExport.prototype.getXML = function() {
+ this.exportDocument();
+ var s = new XMLSerializer();
+ XML_OUTPUT.value = s.serializeToString(this.domDoc);
+};
+
+
+XMLExport.prototype.exportDocument = function() {
+ this.exportRectangles(LAYER_MANAGER.space, this.rootNode);
+};
+
+XMLExport.prototype.exportRectangles = function(baseObj, baseNode) {
+ var doc = this.domDoc;
+ var childs = baseObj.childNodes;
+
+ for(var i = 0 ; i < childs.length ; i++) {
+ rectObj = childs[i].rectangle;
+ if (!rectObj)
+ continue;
+
+ // rectangle
+ var rectEl = doc.createElement("rectangle");
+ rectEl.setAttribute("width", rectObj.width);
+ rectEl.setAttribute("height", rectObj.height);
+ rectEl.setAttribute("elementKey", rectObj.elementKey);
+ rectEl.setAttribute("ddOptions", rectObj.ddOptions);
+ rectEl.setAttribute("ratio", rectObj.ratio);
+ rectEl.setAttribute("visibility", rectObj.style.visibility);
+
+ // upperLeftCorner
+ var ulc = doc.createElement("upperLeftCorner");
+ var point = doc.createElement("point");
+ point.setAttribute("x", rectObj.upperLeftCorner.x);
+ point.setAttribute("y", rectObj.upperLeftCorner.y);
+ ulc.appendChild(point);
+ rectEl.appendChild(ulc);
+
+ // raw data
+ var rdata = doc.createElement("rawData");
+ if (rectObj.getRawData) {
+ var rawEl = doc.createTextNode(rectObj.getRawData());
+ rdata.appendChild(rawEl);
+ }
+ rectEl.appendChild(rdata);
+
+ baseNode.appendChild(rectEl);
+
+ this.exportRectangles(rectObj.node, rectEl);
+ }
+};
+
+function XMLImport(url, root_container) {
+ this.root_container = root_container;
+ var thisImporter = this;
+ var req = new XMLHttpRequest();
+
+ req.onreadystatechange = function() {
+ if(req.readyState == 4)
+ thisImporter.constructDocument(req);
+ }
+ req.open("GET", url, true);
+ req.send(null);
+}
+
+XMLImport.prototype.constructDocument = function(req) {
+ var rootNode = req.responseXML.documentElement;
+ var layerElements = rootNode.childNodes;
+ initLayerManager(this.root_container, true);
+ var layerElement;
+ for (var i = 0 ; i < layerElements.length ; i++) {
+ layerElement = layerElements[i];
+ if (i==0) { // initialize LAYER_MANAGER from first layer data
+ LAYER_MANAGER.defaultLayerWidth = parseInt(layerElement.getAttribute("width"));
+ LAYER_MANAGER.defaultLayerHeight = parseInt(layerElement.getAttribute("height"));
+ LAYER_MANAGER.addLayer("relative");
+ }
+ else
+ LAYER_MANAGER.addLayer();
+
+ // common part
+ if (layerElement.getAttribute("visibility") == "hidden")
+ LAYER_MANAGER.toggleLayerVisibility();
+
+ this.constructRectangles(CURRENT_LAYER, layerElement)
+ }
+};
+
+XMLImport.prototype.constructRectangles = function(baseObj, baseNode) {
+ var rectangleElements = baseNode.childNodes;
+ var rectE, rect, ulcE, ulc, rawDataE, rawData, putFunc;
+
+ for (var i = 0 ; i < rectangleElements.length ; i ++) {
+ rectE = rectangleElements[i];
+ if (rectE.nodeName != "rectangle")
+ continue;
+ ulcE = rectE.childNodes[0].childNodes[0];
+ rawDataE = rectE.childNodes[1]
+
+ ulc = new Point( parseInt(ulcE.getAttribute("x")), parseInt(ulcE.getAttribute("y")) )
+ rect = new Rectangle(ulc,
+ parseInt(rectE.getAttribute("width")),
+ parseInt(rectE.getAttribute("height")),
+ rectE.getAttribute("elementKey"),
+ parseInt(rectE.getAttribute("ddOptions")),
+ parseFloat(rectE.getAttribute("ratio")));
+
+ putFunc = ELEMENTS_POOL[rectE.getAttribute("elementKey")]["putData"]
+ if (putFunc)
+ putFunc.apply(rect, [rawDataE.childNodes[0].nodeValue]);
+
+ rect.draw(baseObj);
+ }
+};
+
+/* utils */
+function _plinnDocumentBeforeSubmit() {
+ with (GLOBAL_DD_CONTROLER.ddEventCaptureElmt) {
+ onmousedown=null;
+ onmousemouse=null;
+ onmouseup=null;
+ }
+ new XMLExport().getXML();
+}
\ No newline at end of file
--- /dev/null
+[default]
+cache=HTTPCache