--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+from Globals import InitializeClass, DTMLFile
+from Products.CMFCore.utils import getToolByName
+
+from AccessControl import ClassSecurityInfo
+from Products.CMFCore.permissions import View, ModifyPortalContent
+from Products.CMFCore.DynamicType import DynamicType
+from Products.PageTemplates.Expressions import getEngine
+from Products.PageTemplates.Expressions import SecureModuleImporter
+
+class BaseSlot(DynamicType) :
+ """Slot"""
+
+ _isMosaicSlot = 1
+ _editableFields = []
+ _indexableFields = []
+
+ security = ClassSecurityInfo()
+
+ security.declarePublic('callAction')
+ def callAction(self, actionId, *args, **kw) :
+ """call action from action definitions"""
+ typeTool = getToolByName(self, 'portal_types')
+
+ # !!! id et meta_type doivent etre identiques dans la fti.
+ typeInfo = typeTool.getTypeInfo(self)
+ actionInfo = typeInfo.getActionInfo('object/%s' % actionId)
+ zpt = getattr(self, actionInfo['url'])
+ return zpt(object=self, block=self.aq_parent, *args, **kw)
+
+ security.declareProtected(ModifyPortalContent, 'edit')
+ def edit(self, **kw) :
+ """ Edit Slot"""
+ for fieldName in self._editableFields :
+ if kw.has_key(fieldName) :
+ setattr(self, fieldName, kw[fieldName])
+
+ security.declareProtected(View, 'getBlock')
+ def getBlock(self) :
+ """ Return the block object where the slot is located """
+ return self.aq_parent
+
+ security.declareProtected(View, 'getExprContext')
+ def getExprContext(self, REQUEST=None) :
+ """Return an expression context customized for expressions properties from slot information"""
+ block = self.aq_parent
+ while block.meta_type != 'Mosaic Block' :
+ block = block.aq_parent
+ data = {
+ 'portal' : self.portal_url.getPortalObject(),
+ 'slot' : self,
+ 'block' : self.aq_parent,
+ 'here' : None,
+ 'request' : REQUEST,
+ 'modules' : SecureModuleImporter,
+ 'nothing' : None,
+ }
+ return getEngine().getContext(data)
+
+ security.declareProtected(View, 'SearchableText')
+ def SearchableText(self) :
+ """ Return full text for indexation """
+ text = ''
+ for fieldName in self._indexableFields :
+ field = getattr(self, fieldName)
+ if callable(field) :
+ text += ' %s' % field()
+ else :
+ text += ' %s' % field
+
+ return text
+
+ def _initDefaultValues(self) :
+ pass
+
+ def indexObject(self): pass
+ def unindexObject(self): pass
+ def reindexObject(self, idxs=[]): pass
+ def reindexObjectSecurity(self): pass
+ def notifyWorkflowCreated(self): pass
+
+
+InitializeClass(BaseSlot)
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+from OFS.SimpleItem import SimpleItem
+from OFS.PropertyManager import PropertyManager
+from OFS.Image import cookId
+from Globals import InitializeClass
+from Products.CMFCore.utils import getToolByName
+
+from Products.CMFCore.permissions import View, ModifyPortalContent
+from AccessControl import ClassSecurityInfo
+from Products.Plinn.File import File
+from BaseSlot import BaseSlot
+
+factory_type_information = ( {'id' : 'File Slot',
+ 'meta_type' : 'File Slot',
+ 'description' : "File Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/bin_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addFileSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_file_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_file_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+ )
+
+class FileSlot(BaseSlot, File) :
+ """File Slot"""
+ meta_type = 'File Slot'
+
+ filename = ''
+ _indexableFields = ('title',)
+
+ security = ClassSecurityInfo()
+
+ security.declareProtected(ModifyPortalContent, 'edit')
+ def edit(self, title='', file='') :
+ """ Edit file slot """
+ self.title = title
+ if file :
+ self._edit(file = file)
+ self.filename = cookId(None, None, file)[1]
+
+
+ security.declareProtected(View, 'SearchableText')
+ def SearchableText(self) :
+ """ Return full text for indexation """
+ return BaseSlot.SearchableText(self) + File.SearchableText(self)
+
+
+InitializeClass(FileSlot)
+
+def addFileSlot(dispatcher, id, title='', file=''):
+ """
+ Add a new FileSlot object.
+ """
+ o = FileSlot(id, title=title, file=file)
+ dispatcher.Destination()._setObject(id, o)
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+from OFS.Image import cookId
+from Globals import InitializeClass
+
+from Products.CMFCore.permissions import View, ModifyPortalContent
+from AccessControl import ClassSecurityInfo
+from Products.Photo import Photo
+from BaseSlot import BaseSlot
+
+factory_type_information = ( {'id' : 'Image Slot',
+ 'meta_type' : 'Image Slot',
+ 'description' : "Image Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/photo_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addImageSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_image_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_image_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+ )
+
+class ImageSlot(BaseSlot, Photo) :
+ """Slot"""
+ meta_type = 'Image Slot'
+ manage_options = Photo.manage_options
+
+ _indexableFields = ('title',)
+
+ security = ClassSecurityInfo()
+
+
+ def __init__(self, parentContainer, id, title='', file='',
+ content_type='', precondition='', blankThumbnail = '', **kw) :
+ blankThumbnailOb = None
+ if blankThumbnail :
+ blankThumbnailOb = parentContainer.restrictedTraverse(blankThumbnail)
+ Photo.__init__(self, id, title=title, file=file,
+ defaultBlankThumbnail = blankThumbnailOb, **kw)
+
+
+ # This method is overloaded to manage file upload.
+ # It's necessary to use manage_upload method from image
+ # because manage_upload invoke update_data and the overload of
+ # update_data in Photo product update the internal thumbnail image.
+ security.declareProtected(ModifyPortalContent, 'edit')
+ def edit(self, title='', thumb_width='440', thumb_height='440', file='', REQUEST=None):
+ """ Edit image slot"""
+ if file :
+ self.manage_upload(file=file)
+
+ if self.thumb_height != thumb_height or thumb_width != thumb_width :
+ if thumb_width <= thumb_height :
+ self.manage_editProperties(thumb_width=thumb_width, thumb_height=thumb_height)
+ else :
+ self.manage_editProperties(thumb_width=thumb_height, thumb_height=thumb_width)
+ if title :
+ self.manage_editProperties(title = title, no_refresh = 1)
+
+ view = index_html = __call__ = Photo.index_html
+
+InitializeClass(ImageSlot)
+
+def addImageSlot(dispatcher, id, file='', title='',
+ precondition='', content_type='', REQUEST=None, **kw) :
+ """
+ Add a new Photo object.
+ Creates a new Photo object 'id' with the contents of 'file'.
+ """
+ id=str(id)
+ title=str(title)
+ content_type=str(content_type)
+ precondition=str(precondition)
+
+ id, title = cookId(id, title, file)
+ parentContainer = dispatcher.Destination()
+
+ # First, we create the image without data:
+ parentContainer._setObject(id, ImageSlot(parentContainer, id,title,'',content_type, precondition, **kw))
+
+ # Now we "upload" the data. By doing this in two steps, we
+ # can use a database trick to make the upload more efficient.
+ if file:
+ parentContainer._getOb(id).manage_upload(file)
+ if content_type:
+ parentContainer._getOb(id).content_type=content_type
+
+ if REQUEST is not None:
+ try: url=dispatcher.DestinationURL()
+ except: url=REQUEST['URL1']
+ REQUEST.RESPONSE.redirect('%s/manage_main' % url)
+ return id
--- /dev/null
+# -*- coding: utf-8 -*-
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+
+
+from Products.CMFCore.PortalFolder import PortalFolder
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from AccessControl.Permission import Permission
+from Products.CMFCore.utils import getToolByName
+from Products.CMFCore.permissions import View, ModifyPortalContent, AccessContentsInformation
+from random import randrange
+from DateTime import DateTime
+from types import InstanceType, StringType, DictType
+from MosaicBlockInformation import RuleError
+
+from OFS.Moniker import Moniker, loadMoniker
+from OFS.CopySupport import _cb_encode, _cb_decode#, cookie_path
+from MosaicBlockInformation import RuleError
+
+
+class MosaicBlock(PortalFolder) :
+ """ Block class for 'Mosaic Document' """
+
+ meta_type = 'Mosaic Block'
+ _properties = ({'id' : 'xpos', 'type' : 'int', 'mode' : 'w'},
+ {'id' : 'minimized', 'type' : 'boolean', 'mode' : 'w'},)
+
+ def __init__( self, id, title='', xpos = 0):
+ PortalFolder.__init__(self, id, title)
+ self.manage_changeProperties(xpos=xpos)
+ self.manage_changeProperties(minimized=0)
+
+ security = ClassSecurityInfo()
+
+
+ ## Utils methods
+
+ def _getRootBlock(self) :
+ """Return the root block object ie :
+ the first block in the tree which have a "_isRootBlock = 1" flag"""
+
+ urlTool = getToolByName(self, 'portal_url')
+ portalObject = urlTool.getPortalObject()
+
+ block = self
+ while block != portalObject :
+ if hasattr(block.aq_self, '_isRootBlock') :
+ return block
+ else :
+ block = block.aq_parent
+ return None
+
+ def _getSelfRules(self) :
+ """Return block rules informations"""
+ mosTool = getToolByName(self, 'mosaic_tool')
+ myTi = mosTool.getTypeInfo(self)
+ ruleDic = {}
+ for rule in myTi.objectValues(['Rule Information']) :
+ ruleDic[rule.getId()] = rule
+ return ruleDic
+
+ def _allowedMoves(self, block) :
+ if type(block) == StringType :
+ block = getattr(self, block)
+ rules = self._getSelfRules()[block.portal_type]
+ move_dic = {'global' : rules.allowMove,
+ 'rightLeft' : rules.allowMoveRightAndLeft,
+ 'upDown' : rules.allowMoveUpAndDown,
+ }
+ return move_dic
+
+ security.declarePrivate('_getParentRules')
+ def _getParentRules(self) :
+ """Return block rules informations"""
+ mosTool = getToolByName(self, 'mosaic_tool')
+ parentTi = mosTool.getTypeInfo(self.aq_parent)
+ return parentTi.objectValues(['Rule Information'])
+
+ def _redirectAfterEdit(self, REQUEST, rootBlock=None, blockId=None) :
+ if rootBlock is None :
+ rootBlock = self._getRootBlock()
+
+ if REQUEST.get('ajax') :
+ url = rootBlock.getActionInfo('object_ajax/edit')['url']
+ elif REQUEST.SESSION.get('editBoxes') :
+ utool = getToolByName(self, 'portal_url')
+ url = utool() + '/manage_boxes'
+ else :
+ url = rootBlock.getActionInfo('object/edit')['url'] + (blockId and '#' + blockId or '')
+ return REQUEST.RESPONSE.redirect(url)
+
+ security.declareProtected(ModifyPortalContent, 'getAllowedBlocks')
+ def getAllowedBlocks(self) :
+ """Return a list with allowed blocks"""
+ rules = self._getSelfRules()
+ mosTool = getToolByName(self, 'mosaic_tool')
+ allowedBlocks = ()
+ for ruleId in rules.keys() :
+ ti = mosTool.getTypeInfo(ruleId)
+ try :
+ if ti.isConstructionAllowed(self) :
+ allowedBlocks += ({'id' : ti.id, 'title' : ti.title},)
+ except :
+ continue
+ return allowedBlocks
+
+ security.declareProtected(ModifyPortalContent, 'haveRules')
+ def haveRules(self) :
+ """ return 1 if type info from self have rules """
+ mosTool = getToolByName(self, 'mosaic_tool')
+ myTi = mosTool.getTypeInfo(self)
+ if myTi.objectValues(['Rule Information']) :
+ return 1
+ else :
+ return 0
+
+
+ security.declareProtected(View, 'getSlots')
+ def getSlots(self) :
+ """return slots"""
+ return [ob for ob in self.objectValues() if hasattr(ob, '_isMosaicSlot')]
+
+ security.declareProtected(View, 'getSlotsDic')
+ def getSlotsDic(self) :
+ """return slots in dictionary"""
+ slots = self.getSlots()
+ slotDic = {}
+ for slot in slots :
+ slotDic[slot.getId()] = slot
+ return slotDic
+
+ security.declarePublic('Title')
+ def Title(self) :
+ """Return title"""
+ return self.getProperty('title', d='') or (hasattr(self, 'caption') and self.caption.text) or ''
+
+ title = Title
+
+ security.declareProtected(ModifyPortalContent, 'setTitle')
+ def setTitle(self, title) :
+ if hasattr(self, 'caption') :
+ self.caption.text = title
+ self.title = title
+
+ def title_or_id(self) :
+ """Return title or id"""
+ return self.Title() or self.id
+
+ ## Methods for displaying
+
+ security.declareProtected(View, 'getBlocksTable')
+ def getBlocksTable(self, filteredTypes=[]) :
+ """return blocks ordered in a 2 dimensions table"""
+ blocks = self.objectValues(['Mosaic Block',])
+
+ if filteredTypes :
+ blocks = [block for block in blocks if block.portal_type in filteredTypes]
+
+ #blocks.sort(lambda x, y : cmp(x.xpos, y.xpos)) inutile ???
+ rows = 0
+ try :
+ cols = blocks[-1].xpos
+ except :
+ cols = 0
+ columnsTable = [] # columns list
+ rules = self._getSelfRules()
+ for xpos in range(cols + 1) :
+ colBlockList = [ block for block in blocks if block.xpos == xpos ] # opt : baliser les debuts de colonne
+ colBlockListLength = len(colBlockList)
+
+ # build a column by iterating over blocks with the position xpos
+ colBlockInfoList = []
+ for blockIndex in range(colBlockListLength) :
+ block = colBlockList[blockIndex]
+ blockRule = rules[block.portal_type]
+ moveDic = {'up' : 0,
+ 'down' : 0,
+ 'left' : 0,
+ 'right' : 0}
+ if blockRule.allowMoveUpAndDown :
+ moveDic['up'] = blockIndex > 0
+ moveDic['down'] = blockIndex < colBlockListLength - 1
+ if blockRule.allowMoveRightAndLeft :
+ moveDic['left'] = xpos > 0
+ moveDic['right'] = 1
+
+ # every block will be displayed in a cell in a table
+ colBlockInfoList.append({'block' : block,
+ 'col' : block.xpos,
+ 'moves' : moveDic,
+ 'mode' : blockRule.mode})
+
+ # append the new column in the column list ie : columnsTable
+ if colBlockListLength > rows :
+ rows = colBlockListLength
+ columnsTable.append(colBlockInfoList)
+
+ # Now the max number of rows in known.
+ # We can determine rowspan attributes,
+ # Building lines for an easy iterating over <tr> tag
+
+ linesTable = []
+ cols += 1
+ for lineIndex in range(rows) :
+ line = []
+ for columnIndex in range(cols) :
+ try :
+ blockInfo = columnsTable[columnIndex][lineIndex]
+ if lineIndex == rows - 1 :
+ blockInfo.update({'lastOne' : 1})
+ line.append(blockInfo)
+
+ except :
+ if lineIndex and linesTable[lineIndex - 1][columnIndex]['block'] is not None :
+ linesTable[lineIndex - 1][columnIndex].update({'rowspan' : rows - lineIndex + 1,
+ 'lastOne' : 1})
+
+ if lineIndex and linesTable[lineIndex - 1][columnIndex].get('rowspan') :
+ rowspan = -1 # flag for ignoring td insertion
+ else :
+ rowspan = rows - lineIndex
+ line.append({'block' : None,
+ 'col' : columnIndex,
+ 'rowspan' : rowspan})
+
+ linesTable.append(line)
+
+ tableInfo = {'rows' : rows,
+ 'cols' : cols,
+ 'lines' : linesTable,
+ 'columns' : columnsTable}
+ return tableInfo
+
+ security.declareProtected(View, 'callTemplate')
+ def callTemplate(self, displayAction='renderer', **kw) :
+ """ Return block template name from block meta fti """
+ mosTool = getToolByName(self, 'mosaic_tool')
+ mfti = mosTool.getTypeInfo(self)
+ templateObj = self.restrictedTraverse(mfti.template)
+ return templateObj(block = self, displayAction = displayAction, **kw)
+
+ security.declareProtected(ModifyPortalContent, 'toggle_minimized')
+ def toggle_minimized(self, REQUEST = None) :
+ "toggle minimized property"
+ if not self.minimized :
+ self.minimized = 1
+ else :
+ self.minimized = 0
+ if REQUEST is not None:
+ return self._redirectAfterEdit(REQUEST, blockId = self.id)
+
+ security.declareProtected(View, 'ypos')
+ def ypos(self) :
+ """ Return the position of self into
+ the parent block """
+ return self.aq_parent.getObjectPosition(self.id)
+
+ ## Block edition methods
+
+ security.declareProtected(ModifyPortalContent, 'addBlock')
+ def addBlock(self, blockType, xpos, id='', beforeBlock='', afterBlock='', REQUEST=None) :
+ """ add a new block type """
+ mosTool = getToolByName(self, 'mosaic_tool')
+ blockId = id or str(int(DateTime()))+str(randrange(1000,10000))
+ mosTool.constructContent(blockType,
+ self,
+ blockId,
+ xpos=xpos,
+ beforeBlock=beforeBlock,
+ afterBlock=afterBlock)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+ else :
+ return blockId
+
+ security.declareProtected(ModifyPortalContent, 'saveBlock')
+ def saveBlock(self, REQUEST=None, **kw) :
+ """ Save block content """
+ mosTool = getToolByName(self, 'mosaic_tool')
+ ti = mosTool.getTypeInfo(self)
+ slotIds = ti.objectIds(['Slot Information',])
+
+ if REQUEST is not None: kw.update(REQUEST.form)
+ dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) in [InstanceType, DictType] ]
+
+ # iteration over slots for applying edit method
+ # an exception is raised when a slot name is not defined in the portal type
+ for slotId, kwords in dicArgsListItems :
+ if slotId in slotIds :
+ slot = getattr(self, slotId) # could raise an exception
+ kwArgs = {}
+ for k in kwords.keys() : #kwords is an InstanceType not a DictType...
+ kwArgs[k] = kwords[k]
+ slot.edit(**kwArgs)
+ else :
+ raise KeyError, "this slot : '%s' is not defined in the type information" % slotId
+
+ rootBlock = self._getRootBlock()
+ if rootBlock is not None :
+ rootBlock.reindexObject()
+
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, rootBlock = rootBlock, blockId = self.getId())
+
+ security.declareProtected(View, 'SearchableText')
+ def SearchableText(self) :
+ blocks = self.objectValues(['Mosaic Block',])
+ slots = [ slot for slot in self.objectValues() if hasattr(slot, '_isMosaicSlot') ]
+ text = ''
+
+ for slot in slots :
+ text += ' %s' % slot.SearchableText()
+ for block in blocks :
+ text += ' %s' % block.SearchableText()
+
+ return text
+
+ security.declareProtected(ModifyPortalContent, 'deleteBlock')
+ def deleteBlock(self, blockId, REQUEST=None) :
+ """ Delete the blockId """
+ old_pos = self.getObjectPosition(blockId)
+ if old_pos != 0 :
+ redirectBlockId = self._objects[old_pos -1]['id']
+ else :
+ redirectBlockId = self.getId()
+
+ self.manage_delObjects([blockId,])
+
+ if REQUEST :
+ # évite des appels répétitifs à reindexObject lorsque deleBlock est appelée
+ # par deleteBlocks
+ rootBlock = self._getRootBlock()
+ rootBlock.reindexObject()
+ return self._redirectAfterEdit(REQUEST, blockId = redirectBlockId)
+ else :
+ return redirectBlockId
+
+ security.declareProtected(ModifyPortalContent, 'deleteBlocks')
+ def deleteBlocks(self, blockIds, REQUEST=None) :
+ """ Delete block id list"""
+ redirectBlockId = ''
+ for blockId in blockIds :
+ redirectBlockId = self.deleteBlock(blockId)
+
+ rootBlock = self._getRootBlock()
+ rootBlock.reindexObject()
+ if REQUEST :
+ return self._redirectAfterEdit(REQUEST, rootBlock = rootBlock, blockId = redirectBlockId)
+
+
+ ## cut and paste methods
+
+ security.declareProtected(ModifyPortalContent, 'pushCp')
+ def pushCp(self, blockId, REQUEST) :
+ """ push block in clipboard """
+ previousCp = None
+ oblist = []
+ if REQUEST.has_key('__cp') :
+ previousCp = REQUEST['__cp']
+ previousCp = _cb_decode(previousCp)
+ oblist = previousCp[1]
+
+ block = getattr(self, blockId)
+ m = Moniker(block)
+ oblist.append(m.dump())
+ cp=(0, oblist)
+ cp=_cb_encode(cp)
+
+ resp=REQUEST['RESPONSE']
+ resp.setCookie('__cp', cp, path='/')
+ REQUEST['__cp'] = cp
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+ security.declareProtected(ModifyPortalContent, 'pasteBlocks')
+ def pasteBlocks(self, REQUEST) :
+ """ check rules and paste blocks from cp """
+
+ if REQUEST.has_key('__cp') :
+ cp = REQUEST['__cp']
+ cp = _cb_decode(cp)
+ mosTool = getToolByName(self, 'mosaic_tool')
+ app = self.getPhysicalRoot()
+ self_fti = getattr(mosTool, self.portal_type)
+
+
+ # paste element one by one for
+ # checking rules on every iteration
+ for mdata in cp[1] :
+ m = loadMoniker(mdata)
+ ob = m.bind(app)
+ ob_type = ob.portal_type
+ ob_fti = getattr(mosTool, ob_type)
+ isBlock = (ob_fti.meta_type == 'Mosaic Block Information')
+ isRootBlock = getattr(ob, '_isRootBlock', 0) # a block witch have this attribute is a content type
+
+ if isBlock and not isRootBlock and ob_fti.isConstructionAllowed(self) :
+ # internal copy and paste handling
+ cp = (0, [m.dump(),])
+ cp=_cb_encode(cp)
+ self.manage_pasteObjects(cb_copy_data = cp)
+
+ _reOrderBlocks(self)
+
+ self.flushCp(REQUEST)
+ return self._redirectAfterEdit(REQUEST, blockId = self.getId())
+
+ security.declarePublic('flushCp')
+ def flushCp(self, REQUEST) :
+ """ Expire cp cookie """
+ REQUEST.RESPONSE.expireCookie('__cp', path='/')
+
+ security.declareProtected(ModifyPortalContent, 'getCpInfos')
+ def getCpInfos(self, REQUEST) :
+ """ Return information about loaded objects in cp """
+ if REQUEST.has_key('__cp') :
+ cp = REQUEST['__cp']
+ cp = _cb_decode(cp)
+ return len(cp[1])
+ else :
+ return 0
+
+
+ ## moves methods
+
+ security.declareProtected(ModifyPortalContent, 'moveLeft')
+ def moveLeft(self, blockId, REQUEST=None) :
+ """Move block left"""
+ move_dic = self._allowedMoves(blockId)
+ if not(move_dic['global'] or move_dic['rightLeft']) :
+ raise RuleError, "It's not allowed to move this block in this context"
+ block = getattr(self, blockId)
+ if block.xpos > 0 :
+ block.xpos -= 1
+ _reOrderBlocks(self)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+
+
+ security.declareProtected(ModifyPortalContent, 'moveRight')
+ def moveRight(self, blockId, REQUEST=None) :
+ """Move block Right"""
+ move_dic = self._allowedMoves(blockId)
+ if not (move_dic['global'] or move_dic['rightLeft']) :
+ raise RuleError, "It's not allowed to move this block in this context"
+ block = getattr(self, blockId)
+ block.xpos += 1
+ _reOrderBlocks(self)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+
+ security.declareProtected(ModifyPortalContent, 'moveUp')
+ def moveUp(self, blockId, REQUEST=None) :
+ """Move block Up"""
+ move_dic = self._allowedMoves(blockId)
+ if not(move_dic['global'] or move_dic['upDown']) :
+ raise RuleError, "It's not allowed to move this block in this context"
+ self.moveObjectsUp(blockId)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+
+ security.declareProtected(ModifyPortalContent, 'moveDown')
+ def moveDown(self, blockId, REQUEST=None) :
+ """Move block left"""
+ move_dic = self._allowedMoves(blockId)
+ if not(move_dic['global'] or move_dic['upDown']) :
+ raise RuleError, "It's not allowed to move this block in this context"
+ self.moveObjectsDown(blockId)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+ security.declareProtected(ModifyPortalContent, 'movesUp')
+ def movesUp(self, blockIds = [], REQUEST=None) :
+ """move blocks up"""
+ for blockId in blockIds :
+ self.moveUp(blockId)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+ security.declareProtected(ModifyPortalContent, 'movesDown')
+ def movesDown(self, blockIds = [], REQUEST=None) :
+ """move blocks down"""
+ for blockId in blockIds :
+ self.moveDown(blockId)
+ if REQUEST is not None :
+ return self._redirectAfterEdit(REQUEST, blockId = blockId)
+
+
+InitializeClass(MosaicBlock)
+
+def _reOrderBlocks(container) :
+ # This method order blocks.
+ # It's useful when a left or right move or a block creation in a middle of a column happens.
+ blocks = list(container.objectValues(['Mosaic Block',]))
+
+ # get the maximum value for xpos attribute
+ blocks.sort(lambda b1, b2 : cmp(b1.xpos, b2.xpos))
+ rows = 0
+ try :
+ cols = blocks[-1].xpos
+ except :
+ cols = 0
+
+ blockPosition = 0
+ for xpos in range(cols + 1) :
+ colBlockList = [ block for block in blocks if block.xpos == xpos ]
+ colBlockListLength = len(colBlockList)
+
+ for blockIndex in range(colBlockListLength) :
+ block = colBlockList[blockIndex]
+ container.moveObjectToPosition(block.getId(), blockPosition)
+ blockPosition += 1
+
+
+def addMosaicBlock(dispatcher, id, xpos=0, beforeBlock='', afterBlock='') :
+ """Add a new mosaicBlock"""
+ parentBlock = dispatcher.Destination()
+ parentBlock._setObject(id, MosaicBlock(id, xpos=xpos))
+ if beforeBlock :
+ position = parentBlock.getObjectPosition(beforeBlock)
+ parentBlock.moveObjectToPosition(id, position)
+
+ elif afterBlock :
+ position = parentBlock.getObjectPosition(afterBlock)
+ parentBlock.moveObjectToPosition(id, position + 1)
+ else :
+ try : _reOrderBlocks(parentBlock)
+ except : pass
+
--- /dev/null
+# -*- coding: utf-8 -*-
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+
+from OFS.ObjectManager import ObjectManager
+from OFS.SimpleItem import SimpleItem
+from OFS.PropertyManager import PropertyManager
+from Globals import InitializeClass, DTMLFile
+from Products.CMFCore.TypesTool import FactoryTypeInformation
+from Products.CMFCore.utils import getToolByName
+from types import InstanceType
+
+from AccessControl import ClassSecurityInfo, Unauthorized
+from Products.CMFCore.permissions import View, ModifyPortalContent, \
+ ManagePortal
+
+
+class RuleError(Exception) :
+ def __init__(self, errorMessage) :
+ self.errorMessage = errorMessage
+
+ def __str__(self) :
+ return self.errorMessage
+
+addMosaicBlockInformationForm = DTMLFile('dtml/addMosaicBlockForm', globals())
+
+def addMosaicBlockInformation(self, id=None, blockType = '', metaFti = None, REQUEST=None) :
+ """Add a MosaicBlock"""
+ mosaicTool = self.mosaic_tool
+ if blockType :
+ metaFtis = mosaicTool.getDefaultBlockMetaFtis()
+ if not metaFtis.has_key(blockType) :
+ raise ValueError, "Unknown block type : %s" % blockType
+ else :
+ blockFti = metaFtis[blockType]
+ elif metaFti :
+ blockFti = metaFti.copy()
+ else :
+ raise AttributeError, """
+ You must specify a default block type or a meta factory type information
+ """
+ if not id :
+ id = blockFti['id']
+ else :
+ blockFti['id'] = id
+
+ mb = MosaicBlockInformation(blockFti)
+ self._setObject(id, mb)
+
+ if REQUEST is not None:
+ REQUEST.RESPONSE.redirect('%s/manage_main' % self.absolute_url())
+ return id
+
+
+class MosaicBlockInformation(ObjectManager, FactoryTypeInformation) :
+ """Base Block"""
+
+ meta_type = "Mosaic Block Information"
+
+ isPrincipiaFolderish = 0
+
+ security = ClassSecurityInfo()
+
+ _fti_properties = FactoryTypeInformation._properties
+
+ _properties = (_fti_properties[:5] +
+ ({'id':'template', 'type': 'string', 'mode':'w',
+ 'label':'Template'},
+ {'id':'notify_wf', 'type': 'boolean', 'mode':'w',
+ 'label':'Notify Workflow Created'},) +
+ _fti_properties[5:]
+ )
+
+
+ manage_slotsForm = DTMLFile('dtml/slotsForm', globals())
+ manage_rulesForm = DTMLFile('dtml/rulesForm', globals())
+ manage_options = (FactoryTypeInformation.manage_options[:1] +
+ ({'label' : 'Slots', 'action' : 'manage_slotsForm'},) +
+ ({'label' : 'Rules', 'action' : 'manage_rulesForm'},) +
+ FactoryTypeInformation.manage_options[1:]
+ )
+
+
+ def __init__(self, blockFti) :
+ FactoryTypeInformation.__init__(self, **blockFti)
+
+ # init Slots informations
+ for slot in blockFti['slots'] :
+ slotInfo = SlotInfo(slot['id'], slot['type'], slotArgs = slot['args'])
+ self._setObject(slot['id'], slotInfo)
+
+ # init Rules informations
+ for rule in blockFti['rules'] :
+ ruleInfo = RuleInfo(rule['blockType'], rule['maxNbInstance'], rule['allowMove'], rule['mode'])
+ self._setObject(rule['blockType'], ruleInfo)
+
+
+ security.declareProtected(ManagePortal, 'manage_addSlot')
+ def manage_addSlot(self, id, type, REQUEST=None) :
+ """Add a slot contruction information"""
+ slotInfo = SlotInfo(id, type)
+ self._setObject(id, slotInfo)
+ if REQUEST :
+ return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+ security.declareProtected(ManagePortal, 'saveSlots')
+ def saveSlots(self, REQUEST=None, **kw) :
+ """Save slots from ZMI form"""
+ # actualy the ':record' casting in an input form create an InstanceType instead of DictType
+ kw.update(REQUEST.form)
+ dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
+ for key, args in dicArgsListItems :
+ slotToEdit = getattr(self, key)
+ if key != args['id'] :
+ self.manage_renameObject(key, args['id'])
+ slotToEdit.id = args['id']
+ slotToEdit.type = args['type']
+ if REQUEST is not None:
+ return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_slotsForm?manage_tabs_message=Saved changes.')
+
+ security.declareProtected(ManagePortal, 'deleteSlots')
+ def deleteSlots(self, slotSelection=None, REQUEST=None) :
+ """Delete slots"""
+ if slotSelection :
+ self.manage_delObjects(ids=slotSelection)
+ if REQUEST :
+ return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+
+
+ security.declareProtected(ManagePortal, 'manage_addSlot')
+ def manage_addRule(self, id, maxNbInstance, allowMove, mode, REQUEST=None) :
+ """Add a rule information"""
+ ruleInfo = RuleInfo(id, maxNbInstance, allowMove, mode)
+ self._setObject(id, ruleInfo)
+ if REQUEST :
+ return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+ security.declareProtected(ManagePortal, 'saveSlots')
+ def saveRules(self, REQUEST=None, **kw) :
+ """Save rules from ZMI form"""
+ # actualy the ':record' casting in an input form create an InstanceType instead of DictType
+ kw.update(REQUEST.form)
+ dicArgsListItems = [ (argKey, kw[argKey]) for argKey in kw.keys() if type(kw[argKey]) == InstanceType ]
+ for key, kwords in dicArgsListItems :
+ ruleToEdit = getattr(self, key)
+ if key != kwords['id'] :
+ self.manage_renameObject(key, kwords['id'])
+ #slotToEdit.id = args['id']
+ kwArgs = {}
+
+ for k in kwords.keys() : #kwords is an InstanceType not a DictType...
+ kwArgs[k] = kwords[k]
+
+ ruleToEdit.edit(**kwArgs)
+
+ if REQUEST is not None:
+ return REQUEST.RESPONSE.redirect(REQUEST['URL1'] + '/manage_rulesForm?manage_tabs_message=Saved changes.')
+
+ security.declareProtected(ManagePortal, 'deleteSlots')
+ def deleteRules(self, ruleSelection=None, REQUEST=None) :
+ """Delete rules"""
+ if ruleSelection :
+ self.manage_delObjects(ids=ruleSelection)
+ if REQUEST :
+ return REQUEST.RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+
+
+ def _checkConstructionRules(self, container) :
+ """Check """
+ typesTool = getToolByName(self, 'mosaic_tool')
+ container_ti = typesTool.getTypeInfo(container)
+ rules = container_ti.objectValues(['Rule Information',])
+ container_subObjs = container.objectValues()
+
+ if self.getId() in map(lambda x : x.getId(), rules) :
+ maxNbInstance = container_ti._getOb(self.getId()).maxNbInstance
+ if maxNbInstance :
+ if maxNbInstance <= len( [sob for sob in container_subObjs if sob.portal_type == self.getId()]) :
+ raise RuleError, "It's not allowed to add a new '%s', the quota is exceeded in this block" % \
+ self.getId()
+ else :
+ return 1
+ else :
+ return 1 # pas de limitation du nombre d'instance
+ else :
+ raise RuleError, "'%s' block type construction is not authorized in '%s'" % \
+ (self.getId(), container_ti.getId())
+
+
+ security.declarePublic('isConstructionAllowed')
+ def isConstructionAllowed ( self, container ):
+ """
+ check factory, permissions and rules
+ """
+ if FactoryTypeInformation.isConstructionAllowed ( self, container ) :
+ typesTool = getToolByName(self, 'mosaic_tool')
+ container_ti = typesTool.getTypeInfo(container)
+ if hasattr(container_ti, '_checkConstructionRules') :
+ try :
+ return self._checkConstructionRules(container)
+ except RuleError :
+ return 0
+ return 1
+ else :
+ return 0
+
+
+ def _getFactoryMethod(self, container, check_security=1):
+ # pas très beau cette surcharge mais
+ # FactoryTypeInformation ne vérifie pas la
+ # possibilité de création par un appel à isConstructionAllowed.
+
+ if not check_security : return FactoryTypeInformation._getFactoryMethod(self, container)
+
+ if self.isConstructionAllowed(container) :
+ return FactoryTypeInformation._getFactoryMethod(self, container)
+
+ raise Unauthorized, ('Cannot create %s' % self.getId())
+
+
+ security.declarePrivate('_finishConstruction')
+ def _finishConstruction(self, ob) :
+ """Finish the construction of a content block object."""
+ if hasattr(ob, '_setPortalTypeName'):
+ ob._setPortalTypeName(self.getId())
+
+ typesTool = getToolByName(self, 'portal_types')
+
+ # Add and init slots in block
+ for si in self.objectValues(['Slot Information',]) :
+ kw = {}
+ for key, value in si.propertyItems() :
+ kw[key] = value
+
+ typesTool.constructContent(si.type, ob, si.id, **kw)
+
+ if self.notify_wf :
+ ob.notifyWorkflowCreated()
+ return ob
+
+
+InitializeClass(MosaicBlockInformation)
+
+def addSlotInfo(dispatcher, id, type, slotArgs) :
+ pass
+
+class SlotInfo(SimpleItem, PropertyManager) :
+ """Encapsulate slot informations"""
+ meta_type="Slot Information"
+ _properties = ()
+ property_extensible_schema__ = 1
+
+ manage_propertiesForm = DTMLFile('dtml/properties', globals())
+ manage_options = PropertyManager.manage_options + SimpleItem.manage_options
+
+ def __init__(self, id, type, slotArgs={}) :
+ self.id = id
+ self.type = type
+ for argId in slotArgs.keys() :
+ self.manage_addProperty(argId, slotArgs[argId]['value'], slotArgs[argId]['type'])
+
+InitializeClass(PropertyManager)
+
+
+def addRuleInfo(dispatcher, id, **kw) :
+ pass
+
+class RuleInfo(SimpleItem):
+ """Encapsulate block rule informations"""
+ meta_type = 'Rule Information'
+
+ def __init__(self, id, maxNbInstance,
+ allowMove, mode,
+ allowMoveUpAndDown=0,
+ allowMoveRightAndLeft=0) :
+ self.id = id # actualy Block Type name info
+ self.maxNbInstance = maxNbInstance
+ if allowMove :
+ self.allowMoveUpAndDown = 1
+ self.allowMoveRightAndLeft = 1
+ else :
+ self.allowMoveUpAndDown = allowMoveUpAndDown
+ self.allowMoveRightAndLeft = allowMoveRightAndLeft
+ self.allowMove = allowMove
+ self.mode = mode
+
+ security = ClassSecurityInfo()
+
+ security.declareProtected(ManagePortal, 'edit')
+ def edit(self, **kw) :
+ for key in kw.keys() :
+ if hasattr(self, key) :
+ setattr(self, key, kw[key])
+
+InitializeClass(RuleInfo)
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+
+
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+from Products.CMFCore.permissions import View, ModifyPortalContent, AccessContentsInformation
+from Products.CMFCore.PortalContent import PortalContent
+from Products.CMFDefault.DublinCore import DefaultDublinCoreImpl
+from Products.CMFCore.utils import getToolByName
+
+from MosaicBlock import MosaicBlock
+
+factory_type_information = (
+ {'id': 'Mosaic Document',
+ 'title': '_mosaic_document_',
+ 'content_icon': 'mosaic_icon.png',
+ 'product': 'MosaicDocument',
+ 'factory': 'addMosaicDocument',
+ 'meta_type': 'Mosaic Document',
+ 'immediate_view': 'mosaicdocument_edit_form',
+ 'allow_discussion': 0,
+ 'filter_content_types': 0,
+ 'actions': ({'id': 'view',
+ 'name': 'View',
+ 'action': 'mosaicdocument_view',
+ 'permissions': (View,)},
+
+ {'id': 'edit',
+ 'name': 'Edit',
+ 'action': 'mosaicdocument_edit_form',
+ 'permissions': (ModifyPortalContent,)},
+
+ {'id': 'metadata',
+ 'name': 'Metadata',
+ 'action': 'metadata_edit_form',
+ 'visible': 0,
+ 'permissions': (ModifyPortalContent, )},
+
+ ),
+ },
+ )
+
+
+class MosaicDocument(MosaicBlock, PortalContent, DefaultDublinCoreImpl) :
+ """
+ Mosaic Document
+ """
+ meta_type = 'Mosaic Document'
+ _isRootBlock = 1
+ isPrincipiaFolderish = 0
+
+ security = ClassSecurityInfo()
+
+ def indexObject(self) :
+ if getattr(self, 'noIndex', None) : return
+ PortalContent.indexObject(self)
+
+ unindexObject = PortalContent.unindexObject
+
+ def reindexObject(self, idxs=[]) :
+ if getattr(self, 'noIndex', None) : return
+ PortalContent.reindexObject(self, idxs=idxs)
+
+ setTitle = DefaultDublinCoreImpl.setTitle
+ setDescription = DefaultDublinCoreImpl.setDescription
+
+ Title = DefaultDublinCoreImpl.Title
+ Description = DefaultDublinCoreImpl.Description
+ Type = DefaultDublinCoreImpl.Type
+
+
+ def __init__(self, id, rules=None, initSubObjects=None, **kw) :
+ DefaultDublinCoreImpl.__init__(self, **kw)
+ self.id = id
+ self._blockRules = rules
+ self._initSubObjects(initSubObjects)
+
+ def _initSubObjects(self, subObjects) :
+ pass
+
+ security.declareProtected(View, 'SearchableText')
+ def SearchableText(self) :
+ """
+ Sets new permissions/roles after this object changed levels
+ or after one of its levels changed of reviewers/readers.
+ """
+ return '%s %s %s' % (self.title, self.description, MosaicBlock.SearchableText(self))
+
+
+InitializeClass(MosaicDocument)
+
+# factory
+def addMosaicDocument(dispatcher, id, REQUEST=None, **kw) :
+ """Ajoute Mosaic Document"""
+ ob = MosaicDocument(id, **kw)
+ dispatcher.Destination()._setObject(id, ob)
+ if REQUEST :
+ REQUEST.RESPONSE.redirect(dispatcher.DestinationURL() + 'manage_main')
+
+
+
+
+from Products.CMFCore.Expression import Expression as CMFExpression
+
+class Expression(CMFExpression) :
+ def __call__(self, econtext=None) :
+ """ render the result of expression if an expression context is given
+ else the source text
+ """
+ if econtext :
+ return CMFExpression.__call__(self, econtext)
+ else :
+ return self.text
+
+ def __len__(self) : return 0
\ No newline at end of file
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+"""
+ Mosaic Tool
+"""
+
+from Globals import InitializeClass
+from Products.CMFCore.TypesTool import TypesTool
+from Products.CMFCore.permissions import ManagePortal
+from MosaicBlockInformation import MosaicBlockInformation
+from AccessControl import ClassSecurityInfo
+
+
+allowedTypes = ['Mosaic Block Information']
+
+class MosaicTool(TypesTool):
+ """
+ Mosaic Tool
+ """
+
+ id = 'mosaic_tool'
+ meta_type = 'Mosaic Tool'
+
+ def filtered_meta_types(self, user=None):
+ # Filters the list of available meta types.
+ allowed = {}
+ for name in allowedTypes:
+ allowed[name] = 1
+
+ all = TypesTool.inheritedAttribute('filtered_meta_types')(self)
+ meta_types = []
+ for meta_type in self.all_meta_types():
+ if allowed.get(meta_type['name']):
+ meta_types.append(meta_type)
+ return meta_types
+
+
+InitializeClass(MosaicTool)
\ No newline at end of file
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+
+from Globals import InitializeClass
+from Products.CMFCore.permissions import View, ModifyPortalContent
+from BaseSlot import BaseSlot
+from OFS.SimpleItem import SimpleItem
+
+factory_type_information = ( {'id' : 'Spacer Slot',
+ 'meta_type' : 'Spacer Slot',
+ 'description' : "Spacer Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/spacer_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addSpacerSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_spacer_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_spacer_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+ )
+
+
+class SpacerSlot(BaseSlot, SimpleItem) :
+ """Spacer Slot"""
+ meta_type = 'Spacer Slot'
+
+ _editableFields = ('nbOfSpaces',)
+ _indexableFields = ()
+
+ def __init__(self, id, nbOfSpaces = 3) :
+ self.id = id
+ self.nbOfSpaces = nbOfSpaces
+
+InitializeClass(SpacerSlot)
+
+def addSpacerSlot(dispatcher, id, nbOfSpaces = 3) :
+ """Add a new SpacerSlot object"""
+
+ o = SpacerSlot(id, nbOfSpaces)
+ dispatcher.Destination()._setObject(id, o)
--- /dev/null
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+
+from Products.CMFCore.permissions import View, ModifyPortalContent
+
+factory_type_information = ( {'id' : 'String Slot',
+ 'meta_type' : 'String Slot',
+ 'description' : "String Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/str_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addStringSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_string_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_string_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+
+ {'id' : 'Text Slot',
+ 'meta_type' : 'Text Slot',
+ 'description' : "Text Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/txt_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addStringSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_text_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_text_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+
+ {'id' : 'List Slot',
+ 'meta_type' : 'List Slot',
+ 'description' : "List Slot for Mosaic Document",
+ 'icon' : 'mosaic_tool/str_icon.gif',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addStringSlot',
+ 'immediate_view' : 'view',
+ 'actions' :
+ ({'id' : 'view',
+ 'name' : 'View',
+ 'action' : 'slot_list_view',
+ 'permissions' : (View, )
+ },
+
+ {'id' : 'edit',
+ 'name' : 'Edit',
+ 'action' : 'slot_text_form',
+ 'permissions' : (ModifyPortalContent, )
+ },
+ )
+ },
+ )
+
+from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
+from Products.CMFCore.Expression import Expression
+from Products.CMFDefault.Document import Document
+from OFS.PropertyManager import PropertyManager
+from BaseSlot import BaseSlot
+
+class StringSlot(BaseSlot, Document, PropertyManager) :
+ """String Slot"""
+ meta_type = 'String Slot'
+ _editableFields = ('text', 'text_format', 'size', 'cols', 'rows')
+ _indexableFields = ('text',)
+
+ manage_options = Document.manage_options[:2] + PropertyManager.manage_options + Document.manage_options[2:]
+
+ _properties = ({'id' : 'choices', 'type' : 'lines', 'mode' : 'w'},
+ {'id' : 'castOperator', 'type' : 'string', 'mode' : 'w'},
+ {'id' : 'size', 'type' : 'int', 'mode' : 'w'},
+ {'id' : 'cols', 'type' : 'int', 'mode' : 'w'},
+ {'id' : 'rows', 'type' : 'int', 'mode' : 'w'},
+ {'id' : 'url_expression', 'type': 'expr', 'mode' : 'w'})
+
+ security = ClassSecurityInfo()
+
+
+ def __init__(self, id, text='', text_format='plain',
+ choices = [], castOperator = 'string', size = 60,
+ cols=50, rows=50, url_expression = None) :
+
+ Document.__init__(self, id, text_format = text_format, text = text)
+
+ self.choices = choices
+ self.castOperator = castOperator
+ self.size = size
+ self.cols = cols
+ self.rows = rows
+ if url_expression is None :
+ self.url_expression = Expression("python:None")
+ else :
+ self.url_expression = url_expression
+
+ security.declareProtected(ModifyPortalContent, 'setFormat')
+ def setFormat(self, format):
+ """ Set text format and Dublin Core resource format.
+ """
+ value = str(format)
+ if value == 'text/html' or value == 'html':
+ self.text_format = 'html'
+ elif value == 'text/plain':
+ if self.text_format not in ('structured-text', 'plain'):
+ self.text_format = 'structured-text'
+ elif value == 'plain':
+ self.text_format = 'plain'
+ else:
+ self.text_format = 'structured-text'
+
+
+InitializeClass(StringSlot)
+
+
+def addStringSlot(dispatcher, id, text='', text_format='plain',
+ choices = [], castOperator = 'string', size=60,
+ cols=50, rows=50, url_expression = None) :
+ """
+ Add a new TextSlot object.
+ """
+ stringSlot = StringSlot(id,
+ text=text,
+ text_format=text_format,
+ choices=choices,
+ castOperator=castOperator,
+ size=size,
+ cols=cols,
+ rows=rows,
+ url_expression=url_expression)
+ parentContainer = dispatcher.Destination()
+ parentContainer._setObject(id, stringSlot)
--- /dev/null
+# -*- coding: utf-8 -*-
+# (c) 2003 Centre de Recherche en Informatique ENSMP Fontainebleau <http://cri.ensmp.fr>
+# (c) 2003 Benoît PIN <mailto:pin@cri.ensmp.fr>
+
+from Products.CMFCore.DirectoryView import registerDirectory
+from Products.CMFCore import utils
+from Products.CMFCore.permissions import AddPortalContent, ManagePortal
+
+
+import MosaicDocument
+import MosaicBlock
+import ImageSlot, StringSlot, FileSlot, SpacerSlot
+
+import MosaicTool
+from MosaicBlockInformation import \
+ MosaicBlockInformation, addMosaicBlockInformationForm, addMosaicBlockInformation, \
+ SlotInfo, addSlotInfo, \
+ RuleInfo, addRuleInfo
+
+contentClasses = (
+ MosaicDocument.MosaicDocument,
+ MosaicBlock.MosaicBlock,
+ ImageSlot.ImageSlot,
+ StringSlot.StringSlot,
+ FileSlot.FileSlot,
+ SpacerSlot.SpacerSlot
+ )
+
+contentConstructors = (
+ MosaicDocument.addMosaicDocument,
+ MosaicBlock.addMosaicBlock,
+ ImageSlot.addImageSlot,
+ StringSlot.addStringSlot,
+ FileSlot.addFileSlot,
+ SpacerSlot.addSpacerSlot
+ )
+
+fti = (
+ MosaicDocument.factory_type_information +
+ ImageSlot.factory_type_information +
+ StringSlot.factory_type_information +
+ FileSlot.factory_type_information +
+ SpacerSlot.factory_type_information +
+ ()
+ )
+
+for path in ('default_blocks', 'default_slots', 'skins') :
+ registerDirectory(path, globals())
+
+def initialize(registrar) :
+ utils.ContentInit(
+ 'Mosaic Document',
+ content_types = contentClasses,
+ permission = AddPortalContent,
+ extra_constructors = contentConstructors,
+ fti = fti,
+ ).initialize(registrar)
+
+ utils.ToolInit(
+ 'Mosaic Tool',
+ tools = (MosaicTool.MosaicTool, ),
+ icon = 'tool.gif',
+ ).initialize(registrar)
+
+ registrar.registerClass(
+ MosaicBlockInformation,
+ constructors = (addMosaicBlockInformationForm, addMosaicBlockInformation),
+ icon = 'dtml/block_icon.gif')
+
+ registrar.registerClass(
+ SlotInfo,
+ constructors=(addSlotInfo,)
+ )
+
+ registrar.registerClass(
+ RuleInfo,
+ constructors=(addRuleInfo,)
+ )
+
+
+## monkey patching ZPublisher.Converters
+from ZPublisher.Converters import type_converters
+type_converters.update({'expr' : MosaicDocument.Expression})
\ No newline at end of file
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml" tal:omit-tag="">
+
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>tree_block_template</title>
+ </head>
+
+ <body tal:define="here nocall:options/here;
+ block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;
+ boxTitle nocall:slots/boxTitle;
+ categories nocall:slots/categories;" tal:omit-tag="" i18n:domain="plinn">
+ <div tal:condition="python:displayAction=='edit'">
+ <h3 i18n:translate="">Action box settings</h3>
+ <form action="." metal:use-macro="here/block_utils/macros/block_form">
+ <table metal:fill-slot="html_block_content">
+ <tr><td i18n:translate="">Box title:</td></tr>
+ <tr>
+ <td tal:content="structure python:boxTitle.callAction(displayAction)">title slot here</td>
+ </tr>
+ <tr><td i18n:translate="">Categories:</td></tr>
+ <tr>
+ <td tal:content="structure python:categories.callAction(displayAction)">categories slot here</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <div tal:condition="python:displayAction=='view'">
+<table cellspacing="0"
+ tal:define="allActions python:here.portal_actions.listFilteredActionsFor( here );
+ filteredActionsList python:[];
+ dummy python:[ filteredActionsList.extend(l) for l in [ allActions.get(key, []) for key in categories.text or allActions.keys() ] ]"
+ tal:condition="filteredActionsList"
+ tal:attributes="class python:'_'.join(categories.text)">
+ <tr>
+ <th tal:content="structure python:boxTitle.callAction(displayAction)">
+ Box title
+ </th>
+ </tr>
+ <tr>
+ <td>
+ <ul>
+ <li tal:repeat="action filteredActionsList"><a href="." tal:content="action/title" tal:attributes="href action/url" i18n:translate="">action</a></li>
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="
+ block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;
+ block_class python:displayAction == 'edit' and 'container_block_form' or 'container_block_view';"
+ tal:omit-tag="">
+ <div tal:attributes="class block_class">
+ <div metal:use-macro="here/block_canvas/macros/canvas">
+ Appel de block_canvas pour afficher les blocks contenus
+ </div>
+ </div>
+</div>
\ No newline at end of file
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;"
+ i18n:domain="plinn">
+<div tal:condition="python:displayAction == 'edit'" tal:omit-tag="">
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <div metal:fill-slot="html_block_content"
+ tal:content="structure python:slots['file'].callAction(displayAction)"></div>
+ </form>
+</div>
+<div tal:condition="python:displayAction != 'edit'" tal:omit-tag="">
+ <div tal:content="structure python:slots['file'].callAction(displayAction)"></div>
+</div>
+</div>
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;" tal:omit-tag="">
+ <div tal:condition="python:displayAction == 'edit'" >
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0" metal:fill-slot="html_block_content">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['image'].callAction(displayAction)"></td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <table border="0" cellspacing="4" cellpadding="0" tal:condition="python:displayAction != 'edit'">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['image'].callAction(displayAction)"></td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;" tal:omit-tag="">
+
+ <div tal:condition="python:displayAction == 'edit'">
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0" metal:fill-slot="html_block_content">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['section'].callAction(displayAction)">Text</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <h2 tal:condition="python:displayAction != 'edit'"
+ tal:content="structure python:slots['section'].callAction(displayAction)">Text</h2>
+
+</div>
\ No newline at end of file
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;" tal:omit-tag="">
+
+ <div tal:condition="python:displayAction == 'edit'">
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0" metal:fill-slot="html_block_content">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['space'].callAction(displayAction)">Text</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <table border="0" cellspacing="4" cellpadding="0" tal:condition="python:displayAction != 'edit'">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['space'].callAction(displayAction)">Text</td>
+ </tr>
+ </table>
+</div>
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;" tal:omit-tag="">
+
+ <div tal:condition="python:displayAction == 'edit'">
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0" metal:fill-slot="html_block_content">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['text'].callAction(displayAction)">Text</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <table border="0" cellspacing="4" cellpadding="0" tal:condition="python:displayAction != 'edit'">
+ <tr>
+ <td valign="top" tal:content="structure python:slots['text'].callAction(displayAction)">Text</td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
--- /dev/null
+<div tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;" tal:omit-tag="">
+ <div tal:condition="python:displayAction == 'edit'">
+ <form metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0"
+ metal:fill-slot="html_block_content">
+ <tr>
+ <td valign="top" width="215" tal:content="structure python:slots['image'].callAction(displayAction)">Image 1</td>
+ <td width="1"> </td>
+ <td valign="top" width="215" tal:content="structure python:slots['image2'].callAction(displayAction)">Image 2</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <table border="0" cellspacing="4" cellpadding="0"
+ tal:condition="python:displayAction != 'edit'">
+ <tr>
+ <td valign="top" width="215" tal:content="structure python:slots['image'].callAction(displayAction)">Image 1</td>
+ <td width="1"> </td>
+ <td valign="top" width="215" tal:content="structure python:slots['image2'].callAction(displayAction)">Image 2</td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
--- /dev/null
+<html>
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ <title>block_utils</title>
+ <link href="../../CriSIT/default_skins/main_stylesheet.css.css" rel="stylesheet" media="screen">
+ </head>
+
+ <body bgcolor="#ffffff" i18n:domain="plinn">
+<br/>
+<pre>block_form</pre>
+<br/>
+<hr/>
+ <form metal:define-macro="block_form" class="block_form" action="."
+ method="post" enctype="multipart/form-data"
+ tal:attributes="action block/absolute_url;
+ class python:exists('block_form_class') and block_form_class or 'block_form' ">
+ <div metal:define-slot="html_block_content">Rendu HTML du block</div>
+ <input type="submit" value="Valider"
+ name="saveBlock:method"
+ tal:attributes="value python:exists('submit_action') and submit_action or 'Validate'"
+ i18n:attributes="value" />
+ <input type="hidden" name="noAjax" value="1" tal:condition="request/SESSION/editBoxes|nothing" />
+ </form>
+<br/>
+<pre>add_block_form</pre>
+<br/>
+<hr/>
+ <div metal:define-macro="add_block_form" tal:define="allowedBlocks baseBlock/getAllowedBlocks" tal:omit-tag="">
+ <form action="." method="get"
+ tal:attributes="action baseBlock/absolute_url">
+ <span metal:define-slot="additional_fields">
+ <input type="hidden" name="xpos:int" value="0" />
+ </span>
+ <span i18n:translate="">Insert new block:
+ </span>
+ <select name="blockType" class="mosaic_input">
+ <option tal:repeat="bt allowedBlocks" tal:attributes="value bt/id" tal:content="bt/title" i18n:translate="">BlokcType</option>
+ </select>
+ <input type="submit" name="addBlock:method" value="Add" i18n:attributes="value" />
+ <input type="hidden" name="noAjax" value="1" tal:condition="request/SESSION/editBoxes|nothing" />
+ </form>
+ </div>
+
+<br/>
+<pre>move_table</pre>
+ <br/>
+ <table cellspacing="2" cellpadding="0" metal:define-macro="move_table" class="move_table">
+ <tr>
+ <td tal:condition="blockInfo/moves/left"><a href="." tal:attributes="href string:${baseBlock/absolute_url}/moveLeft?blockId=${block/getId}" title="Move right" i18n:attributes="title"><img src="../skins/img_box_moveleft.png" alt="Move left" name="moveLeft:method" height="12" width="12" border="0" tal:attributes="src string:img_box_moveleft.png" i18n:attributes="alt"/></a></td>
+ <td tal:condition="blockInfo/moves/up"><a href="." tal:attributes="href string:${baseBlock/absolute_url}/moveUp?blockId=${block/getId}" title="Move up" i18n:attributes="title"><img src="../skins/img_box_moveup.png" alt="Move up" name="moveUp:method" height="12" width="12" border="0" tal:attributes="src string:img_box_moveup.png" i18n:attributes="alt"/></a></td>
+ <td tal:condition="blockInfo/moves/down"><a href="." tal:attributes="href string:${baseBlock/absolute_url}/moveDown?blockId=${block/getId}" title="Move down" i18n:attributes="title"><img src="../skins/img_box_movedown.png" alt="Move down" name="moveDown:method" height="12" width="12" border="0" tal:attributes="src string:img_box_movedown.png" i18n:attributes="alt"/></a></td>
+ <td tal:condition="blockInfo/moves/right"><a href="." tal:attributes="href string:${baseBlock/absolute_url}/moveRight?blockId=${block/getId}" title="Move right" i18n:attributes="title"><img src="../skins/img_box_moveright.png" alt="Move right" name="moveRight:method" height="12" width="12" border="0" tal:attributes="src string:img_box_moveright.png" i18n:attributes="alt"/></a></td>
+ <td width="20px"> </td>
+ <td><a href="." tal:attributes="href string:${baseBlock/absolute_url}/pushCp?blockId=${block/getId}" title="Copy" i18n:attributes="title"><img src="../skins/copy.png" alt="Copy" height="13" width="15" border="0" tal:attributes="src string:copy.png" i18n:attributes="alt"/></a></td>
+ <td tal:condition="python:here.cb_dataValid() and block.haveRules()"><a href="." tal:attributes="href string:${block/absolute_url}/pasteBlocks" title="Paste" i18n:attributes="title"><img src="../skins/paste.png" alt="Paste" height="14" width="16" border="0" tal:attributes="src string:paste.png" i18n:attributes="alt"/></a></td>
+ <td width="67" tal:condition="python:'d' in blockInfo['mode']"> </td>
+ <td tal:condition="python:'d' in blockInfo['mode']"><a href="." tal:attributes="href string:${baseBlock/absolute_url}/deleteBlock?blockId=${block/getId}" title="Delete" i18n:attributes="title"><img src="../skins/img_box_delete.png" alt="" height="12" width="12" border="0" tal:attributes="src string:img_box_delete.png"/></a></td>
+ </tr>
+ </table>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+##parameters=
+View = 'View'
+ModifyPortalContent = 'Modify portal content'
+
+
+# Mosaic Document regular fti
+mosaicDocument_fti = {'id' : 'Mosaic Document',
+ 'title' : 'Mosaic Document',
+ 'content_icon' : 'mosaic_icon.png',
+ 'product' : 'MosaicDocument',
+ 'factory' : 'addMosaicDocument',
+ 'meta_type' : 'Mosaic Document',
+ 'immediate_view' : 'metadata_edit_form',
+ 'allow_discussion' : 1,
+ 'filter_content_types' : 0,
+ 'actions' : (
+ {'id': 'view',
+ 'title': 'View',
+ 'action': 'mosaicdocument_view',
+ 'visible' : 1,
+ 'permissions': (View,)},
+
+ {'id': 'edit',
+ 'title': 'Edit',
+ 'action': 'mosaicdocument_edit_form',
+ 'visible' : 1,
+ 'permissions': (ModifyPortalContent,)},
+
+ {'id': 'metadata',
+ 'title': 'Metadata',
+ 'action': 'metadata_edit_form',
+ 'visible': 1,
+ 'permissions': ()},),
+ }
+
+# fixed fti part for basic blocks definitions
+fixedFtiPart = {'product' : 'MosaicDocument',
+ 'factory' : 'addMosaicBlock',
+ 'immediate_view' : 'view',
+ 'filter_content_types' : 1,
+ }
+
+defaultActions = ({'id' : 'view',
+ 'title' : 'view',
+ 'action' : 'view',
+ 'permissions' : (View,),
+ 'category' : 'object',
+ },)
+
+# basic blocks definitions
+metaFtis = (
+ {'id': 'Image Block',
+ 'title': 'Image block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Image Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_image_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'image',
+ 'type': 'Image Slot',
+ 'args':
+ {'thumb_width' : {'type' : 'int', 'value' : 440},
+ 'thumb_height' : {'type' : 'int', 'value' : 440},
+ 'blankThumbnail' : {'type' : 'string', 'value' : 'mosaic_tool/no_image.jpg'},
+ }
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'Two Images Block',
+ 'title': 'Two images block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Two Images Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_two_images_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'image',
+ 'type': 'Image Slot',
+ 'args':
+ {'thumb_width' : {'type' : 'int', 'value' : 440},
+ 'thumb_height' : {'type' : 'int', 'value' : 440},
+ 'blankThumbnail' : {'type' : 'string', 'value' : 'mosaic_tool/no_image.jpg'},
+ }
+ },
+ {'id': 'image2',
+ 'type': 'Image Slot',
+ 'args':
+ {'thumb_width' : {'type' : 'int', 'value' : 440},
+ 'thumb_height' : {'type' : 'int', 'value' : 440},
+ 'blankThumbnail' : {'type' : 'string', 'value' : 'mosaic_tool/no_image.jpg'},
+ }
+ }
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'Text Block',
+ 'title': 'Text block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Text Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_text_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id' : 'text',
+ 'type' : 'Text Slot',
+ 'args' :
+ {'text' : {'type' : 'text', 'value' : ''},
+ 'text_format' : {'type' : 'string', 'value' : 'structured-text'},
+ 'cols' : {'type' : 'int', 'value' : 68},
+ 'rows' : {'type' : 'int', 'value' : 20},
+ }
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'File Block',
+ 'title': 'File Block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'File Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_file_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'file',
+ 'type': 'File Slot',
+ 'args': {},
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'Spacer Block',
+ 'title': 'Spacer block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Spacer Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_spacer_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'space',
+ 'type': 'Spacer Slot',
+ 'args': {'nbOfSpaces' : {'type' : 'int', 'value' : 3},},
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'Section Block',
+ 'title': 'Section block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Section Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/block_section_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'section',
+ 'type': 'String Slot',
+ 'args':
+ {'text' : {'type' : 'string', 'value' : ''},
+ 'size' : {'type' : 'int', 'value' : 60},
+ 'choices' : {'type' : 'lines', 'value' : []},
+ 'castOperator' : {'type' : 'string', 'value' : 'string'},
+ },
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+
+ {'id': 'Container Block',
+ 'title': 'Container block',
+ 'icon': 'mosaic_tool/image_block_icon.gif',
+ 'meta_type': 'Container Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'actions' : defaultActions,
+ },
+
+## Boxes blocks
+ {'id': 'Tree Box Block',
+ 'title': 'Tree Box Block',
+ 'icon': 'mosaic_tool/tree_block_icon.gif',
+ 'meta_type': 'Tree Box Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/tree_block_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'rootObject',
+ 'type': 'String Slot',
+ 'args':
+ {'text' : {'type' : 'expr', 'value' : 'portal'},
+ 'size' : {'type' : 'int', 'value' : 45},
+ 'castOperator' : {'type' : 'string', 'value' : 'expr'},
+ },
+ },
+ {'id': 'filteredMetaTypes',
+ 'type': 'List Slot',
+ 'args':
+ {'text' : {'type' : 'lines', 'value' : 'Plinn Folder'},
+ 'cols' : {'type' : 'int', 'value' : 15},
+ 'rows' : {'type' : 'int', 'value' : 5},
+ 'castOperator' : {'type' : 'string', 'value' : 'lines'},
+ },
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ {'id': 'Action Box Block',
+ 'title': 'Action Box Block',
+ 'icon': 'mosaic_tool/action_block_icon.gif',
+ 'meta_type': 'Action Box Block',
+ 'filter_content_types': 1,
+ 'allowed_content_types': (),
+ 'template' : 'mosaic_tool/action_block_template',
+ 'notify_wf' : 0,
+ 'slots' : (
+ {'id': 'boxTitle',
+ 'type': 'String Slot',
+ 'args':
+ {'text' : {'type' : 'string', 'value' : ''},
+ 'size' : {'type' : 'int', 'value' : 45},
+ 'castOperator' : {'type' : 'string', 'value' : 'string'},
+ },
+ },
+ {'id': 'categories',
+ 'type': 'String Slot',
+ 'args':
+ {'text' : {'type' : 'tokens', 'value' : 'global'},
+ 'size' : {'type' : 'int', 'value' : 45},
+ 'castOperator' : {'type' : 'string', 'value' : 'tokens'},
+ },
+ },
+ ),
+ 'rules' : (),
+ 'actions' : defaultActions,
+ },
+
+ )
+
+metaFtisDic = {}
+for mfti in metaFtis :
+ tempDic = mfti.copy()
+ mfti.update(fixedFtiPart)
+ metaFtisDic[tempDic['id']] = mfti
+
+# adding Mosaic Document block definition
+metaFtisDic[mosaicDocument_fti['id']] = mosaicDocument_fti
+
+def completeMetaFti(dummyFti,
+ metaFtis,
+ slots = (),
+ template = '',
+ notify_wf = 0) :
+ allRules = ()
+ for mfti in metaFtis :
+ rulesDic = {'blockType' : mfti['id'],
+ 'maxNbInstance' : 0,
+ 'allowMove' : 1,
+ 'mode' : 'wd',
+ },
+ allRules += rulesDic
+
+ ftiExtension = {'rules' : allRules,
+ 'slots' : (),
+ 'template' : template,
+ 'notify_wf' : 1,
+ }
+ ftiExtension.update(dummyFti)
+ return ftiExtension
+
+# complete meta fti for Mosaic Document block definition
+metaFtisDic[mosaicDocument_fti['id']] = completeMetaFti(metaFtisDic[mosaicDocument_fti['id']],
+ metaFtis,
+ notify_wf = 1)
+
+# Idem for Container Block definition
+metaFtisDic['Container Block'] = completeMetaFti(metaFtisDic['Container Block'],
+ metaFtis,
+ template = 'mosaic_tool/block_container_template')
+
+return metaFtisDic
--- /dev/null
+// (c) Benoît PIN 2006
+// http://plinn.org
+// Licence GPL
+
+var TreeMaker;
+
+(function() {
+/* root -> base node (typically a tbody or a table)
+* filter -> comma separated list of portal_types
+*/
+TreeMaker = function (root, filter, baseImgUrl) {
+ this.root = root;
+ var tm = this;
+ this.root.onclick = function(evt) { tm.refreshTree(evt); };
+ this.filter = filter;
+ this.baseImgUrl = baseImgUrl;
+ this.depthCpt = new Array();
+ this._lastAniImg = null;
+
+ // preload images
+ var images = ['pl.gif', 'pl_ani.gif', 'mi.gif', 'mi_ani.gif'], img;
+ for (var i=0 ; i < images.length ; i++) {
+ img = new Image();
+ img.src = this.baseImgUrl + images[i];
+ }
+}
+
+/*
+* expand / collapse handler
+* object loading trigger
+*/
+TreeMaker.prototype.refreshTree = function (evt) {
+ var target = getTargetedObject(evt);
+ if (target.blur)
+ target.blur();
+
+ if (target.tagName == 'IMG') {
+ target.parentNode.blur();
+ var srcParts = target.src.split("/");
+ var imgId = srcParts[srcParts.length-1];
+ var parentTd = target.parentNode.parentNode;
+ var parentRow = parentTd.parentNode;
+
+
+ switch (imgId) {
+ case "pl.gif" :
+ case "pl_ani.gif" :
+ var linkCell = parentTd.nextSibling;
+ while (linkCell.nodeType != 1)
+ linkCell = linkCell.nextSibling;
+
+ var obUrl = linkCell.getElementsByTagName("A")[0].href;
+
+ var req = new XMLHttpRequest();
+ var tm = this;
+ req.onreadystatechange = function() {
+ switch (req.readyState) {
+ case 1:
+ showProgressImage();
+ break;
+ case 4:
+ hideProgressImage();
+ tm.importRows(req, parentRow);
+ };
+ };
+ req.open("POST", obUrl + "/xml_nav_tree", true);
+ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
+ req.send("filter=" + this.filter);
+
+ target.src = this.baseImgUrl + "mi_ani.gif";
+ this._lastAniImg = target;
+
+
+ window.setTimeout(function(){tm._removeLastAniImg();}, 500);
+ break;
+
+ case "mi.gif" :
+ case "mi_ani.gif" :
+ this.removeChildNodes(parentRow);
+ target.src = this.baseImgUrl + "pl_ani.gif";
+ this._lastAniImg = target;
+ var tm = this;
+ window.setTimeout(function(){tm._removeLastAniImg();}, 500);
+ break;
+ } // end switch (imgId)
+ disableDefault(evt);
+ disablePropagation(evt);
+ }
+};
+
+
+TreeMaker.prototype._removeLastAniImg = function() {
+ if (this._lastAniImg) {
+ this._lastAniImg.src = this._lastAniImg.src.replace("_ani", "");
+ }
+};
+
+
+/*
+* expand the tree: sends request and imports rows based on xml response.
+*/
+TreeMaker.prototype.importRows = function(req, parentRow) {
+ var rows = req.responseXML.documentElement.getElementsByTagName("row");
+ var clickedCells = parentRow.getElementsByTagName("TD");
+ var row, newRow, indentCell, stateCell, linkCell, img, a, indentValue, colspan,
+ incTableDepth=false, cols, linkCellColSpan;
+
+ for (var i = 0 ; i < rows.length ; i++ ) {
+ row = rows[i];
+
+
+ newRow = document.createElement("TR");
+ indentCell = document.createElement("TD");
+ stateCell = document.createElement("TD");
+ stateCell.width = "16";
+ linkCell = document.createElement("TD");
+ linkCell.width = "99%";
+
+
+ if (clickedCells.length == 3) {
+ indentValue = parseInt(clickedCells[0].getAttribute("colspan"));
+ colspan = parseInt(clickedCells[2].getAttribute("colspan"));
+ }
+ else {
+ indentValue = 0;
+ colspan = parseInt(clickedCells[1].getAttribute("colspan"));
+ }
+
+ cols = indentValue + colspan;
+
+ if (colspan == 1)
+ incTableDepth = true;
+
+ indentCell.colSpan = indentValue + 1;
+ if (!this.depthCpt[indentValue])
+ this.depthCpt[indentValue] = 1;
+ else
+ this.depthCpt[indentValue] += 1;
+
+ // IE : it's not possible to set colSpan attr to 0 :-(((
+ linkCellColSpan = cols - indentValue - 1
+ if (linkCellColSpan == 0)
+ linkCell.nullColSpan = true;
+ else
+ linkCell.colSpan = linkCellColSpan;
+
+ img = document.createElement("IMG");
+ img.src = row.getAttribute("icon");
+ img.height = row.getAttribute("height");
+ img.width = row.getAttribute("width");
+ a = document.createElement("A");
+
+ a.setAttribute("href", row.getAttribute("url"));
+ a.setAttribute("title", row.getAttribute("description"));
+ a.innerHTML = row.childNodes[0].nodeValue;
+
+ if (row.getAttribute("state") == "-1") {
+ var stateLink = document.createElement("A");
+ stateLink.href = ".";
+ var stateImg = document.createElement("IMG");
+ stateImg.src = this.baseImgUrl + "pl.gif";
+ stateImg.border = "0";
+ stateImg.height = "16";
+ stateImg.width = "16";
+ stateLink.appendChild(stateImg)
+ stateCell.appendChild(stateLink);
+ }
+ else
+ stateCell.innerHTML = " ";
+
+ linkCell.appendChild(img);
+ linkCell.appendChild(a);
+ newRow.appendChild(indentCell);
+ newRow.appendChild(stateCell);
+ newRow.appendChild(linkCell);
+
+
+ this.root.insertBefore(newRow, parentRow.nextSibling);
+ } //end for
+
+ if (incTableDepth) {
+ var rows = this.root.getElementsByTagName("TR");
+ var cells, lastCell, lastColspan;
+ for (var i = 0 ; i < rows.length ; i++) {
+ cells = rows[i].getElementsByTagName("TD");
+ lastCell = cells[cells.length - 1];
+
+ if (lastCell.nullColSpan) {
+ lastCell.nullColSpan = false;
+ lastColspan = 0;
+ }
+ else
+ lastColspan = parseInt(lastCell.getAttribute("colspan"));
+
+ lastCell.colSpan = lastColspan + 1;
+ }
+ }
+};
+
+/*
+* collapse the tree: removes deeper rows after the 'baseRow' passed.
+*/
+TreeMaker.prototype.removeChildNodes = function(baseRow) {
+ var baseCells = baseRow.getElementsByTagName("TD");
+ var baseColSpan = baseCells[baseCells.length-1].colSpan;
+ var nextRow = baseRow.nextSibling;
+ var tbody = baseRow.parentNode;
+ var depthCpt = this.depthCpt;
+ var nextCells, nextRow2;
+
+ while (nextRow) {
+ if (nextRow.nodeType == 1) {
+ nextCells = nextRow.getElementsByTagName("TD");
+ if (nextCells.length == 3 && nextCells[2].colSpan < baseColSpan) {
+ nextRow2 = nextRow.nextSibling;
+ depthCpt[nextCells[0].colSpan-1] -= 1;
+ tbody.removeChild(nextRow);
+ nextRow = nextRow2;
+ continue;
+ }
+ break;
+ }
+ nextRow = nextRow.nextSibling; // text node
+ }
+
+ // recalc colspans for Safari
+ var maxDepth = depthCpt.length - 1;
+ var depthReduction = 0;
+ while (depthCpt[maxDepth - depthReduction] == 0) {
+ depthCpt.pop();
+ depthReduction++;
+ }
+
+ if (depthReduction) {
+ var rows = tbody.getElementsByTagName("TR");
+ var cells, lastCell, lastColspan;
+ for (var i = 0 ; i < rows.length ; i++) {
+ cells = rows[i].getElementsByTagName("TD");
+ lastCell = cells[cells.length - 1];
+ lastCell.colSpan = parseInt(lastCell.colSpan) - depthReduction;
+ }
+ }
+};
+})();
\ No newline at end of file
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml" tal:omit-tag="">
+
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>tree_block_template</title>
+ </head>
+
+ <body tal:define="block nocall:options/block;
+ slots block/getSlotsDic;
+ displayAction options/displayAction;
+ rootObject nocall:slots/rootObject;
+ filteredMetaTypes nocall:slots/filteredMetaTypes;"
+ tal:omit-tag=""
+ i18n:domain="plinn">
+ <div tal:condition="python:displayAction=='edit'" tal:omit-tag="">
+ <h3 i18n:translate="">Tree box settings</h3>
+ <form action="." metal:use-macro="here/block_utils/macros/block_form">
+ <table border="0" cellspacing="4" cellpadding="0" metal:fill-slot="html_block_content">
+ <tr>
+ <td i18n:translate="">Root object expression:</td>
+ </tr>
+ <tr>
+ <td valign="top" tal:content="structure python:rootObject.callAction(displayAction)">
+ rootObject slot here
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" i18n:translate="">
+ Filter (meta_type list) :
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" tal:content="structure python:filteredMetaTypes.callAction(displayAction)">filteredMetaTypes slot here</td>
+ </tr>
+ </table>
+ </form>
+ </div>
+ <div tal:define="treeRoot python:rootObject.text(rootObject.getExprContext());
+ treeDict python:block.make_nav_tree(rootObject=treeRoot, filtered_meta_types=filteredMetaTypes.text );
+ tree treeDict/tree;
+ rows treeDict/rows;
+ height tree/height;
+ rootNode python:rows.pop(0);
+ box_id string:tree_box_${rootNode/object/id};
+ portal_url here/portal_url"
+ tal:condition="python:displayAction=='view' and rows"
+ tal:omit-tag=""
+ tal:on-error="string:Path Error">
+ <script type="text/javascript" tal:attributes="src here/tree_block_script.js/absolute_url"></script>
+ <table class="tree_box" cellspacing="0">
+ <tr>
+ <th>
+ <table>
+ <tr>
+ <td width="16" tal:condition="nothing">
+ <a title="collapse all" href="." tal:attributes="href string:?collapse_all=${rootNode/object/id}" i18n:attributes="title"><img src="../skins/collapse_all.gif" alt="collapse all" height="16" width="16" border="0" tal:attributes="src here/collapse_all.gif/absolute_url" i18n:attributes="alt" /></a>
+ </td>
+ <th tal:content="rootNode/object/title_or_id" style="border : none">Root Node</th>
+ </tr>
+ </table>
+ </th>
+ </tr>
+
+ <tr>
+ <td>
+ <table cellspacing="0">
+ <tbody tal:attributes="id box_id">
+ <tr tal:repeat="row rows">
+ <td tal:define="indent python: row.depth - 1" tal:attributes="colspan indent" tal:condition="indent"> </td>
+ <td tal:define="state row/state ; rlink row/branch ; msg python:state > 0 and 'collapse' or 'expand'" width="16"
+ ><a href="#" tal:condition="state" tal:attributes="name row/id ; href rlink/link ; title msg" i18n:attributes="title"
+ ><img src="/p_/pl" alt="" tal:attributes="src python:'%s/%s' % (portal_url, state > 0 and 'mi.gif' or 'pl.gif') ; alt msg" i18n:attributes="alt" border="0" height="16" width="16" /></a>
+ <a href="#" tal:attributes="name row/id ; href rlink/link" tal:condition="not:state"> </a>
+ </td>
+ <td colspan="1" tal:define="obj nocall: row/object; url obj/absolute_url; description obj/Description"
+ tal:attributes="colspan python: height - row.depth"
+ width="99%" tal:on-error="string:erreur"
+ ><a href="." tal:attributes="href url; title description"
+ ><img src="." alt="" tal:define="icon python:here.restrictedTraverse(obj.icon())" tal:attributes="src icon/absolute_url; height icon/height; width icon/width" border="0" />
+ <span tal:replace="obj/title_or_id">Title</span></a></td>
+ </tr>
+ </tbody>
+ </table>
+ <tal:include content="structure python:here.inline_tree_script(box_id=box_id, filter_str=','.join(filteredMetaTypes.text))" />
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<html tal:omit-tag="">
+ <head tal:replace="nothing">
+ <title>slot_file_form</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ </head>
+ <body tal:define="object nocall:options/object;
+ title python:object and object.title or ''"
+ i18n:domain="plinn"
+ tal:omit-tag="">
+ <h3 i18n:translate="" style="display : inline">File</h3>
+ <span i18n:translate="" tal:omit-tag="">Title</span> :
+ <input type="text" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'title')) + ':record:string' ;
+ value title" />
+ <span>
+ (
+ <span i18n:translate="" tal:omit-tag="">Source file: </span>
+ <span tal:condition="python:object.filename is None or object.filename == '' or object.filename == 'file'" i18n:translate="">None</span>
+ <span tal:condition="python:not(object.filename is None or object.filename == '' or object.filename == 'file')" tal:content="object/filename">File name</span>
+ )
+ </span><br/>
+ <input type="file" size="16" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'file')) + ':record'" />
+ <input type="hidden" name="noAjax" value="1" />
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="object nocall:options/object;
+ show_type options/show_type|python:1;
+ show_preview options/show_preview|python:1;
+ link_title python:object.title or object.filename;
+ filename python:object.title and object.filename;"
+ i18n:domain="plinn">
+ <h3 i18n:translate="" style="display:inline">File</h3>
+ <a target="_blank" tal:attributes="href string:${object/absolute_url}/index_html" tal:content="link_title">Download</a>
+ (<span tal:condition="filename" tal:replace="filename">filename</span>)
+</div>
\ No newline at end of file
--- /dev/null
+<html tal:omit-tag="">
+
+ <head tal:replace="nothing">
+ <title>slot_image_form</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ </head>
+
+ <body tal:define="object nocall:options/object;
+ thumbnail object/thumbnail;
+ width thumbnail/width;
+ height thumbnail/height;
+ showSize object/get_size;
+ src string:${object/absolute_url}/thumbnail;
+ title python:object and object.title or ''"
+ i18n:domain="plinn"
+ tal:omit-tag="">
+ <div>
+ <div tal:condition="showSize" tal:omit-tag="">
+ <span i18n:translate="" tal:omit-tag="">width / height:</span>
+ <input type="text" name="textfieldName" size="4" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'thumb_width')) + ':record:int'; value width;"
+ tal:condition="showSize" /> /
+ <input type="text" name="textfieldName" size="4" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'thumb_height')) + ':record:int';
+ value height;" /><br/></div>
+ <img tal:attributes="src src;
+ height height;
+ width width;
+ alt python:title or 'place holder for an image'" /><br/>
+ <small i18n:translate="">Title :</small>
+ <input type="text" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'title')) + ':record:string' ; value title" />
+ <br/>
+ <span i18n:translate="">Change image:</span>
+ <br/>
+ <input class="mosaic_input" type="file"
+ tal:attributes="name python:'.'.join((object.getId(), 'file')) + ':record'" />
+ <input type="hidden" name="noAjax" value="1" />
+ </div>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<html tal:omit-tag="">
+<head tal:replace="nothing">
+ <title>slot_image_render</title>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ </head>
+<body tal:define="object nocall:options/object;
+ thumbnail object/thumbnail;
+ src thumbnail/absolute_url;
+ width thumbnail/width;
+ height thumbnail/height;
+ title object/title|nothing;"
+ i18n:domain="plinn"
+ tal:omit-tag="">
+ <div class="image">
+ <a title="Click to see image full-size" target="image_view" i18n:attributes="title"
+ tal:attributes="href string:${object/absolute_url}/getJpegImage;
+ onClick string:window.open('${object/absolute_url}/getJpegImage', 'image_view', 'toolbar=no,scrollbars=yes,,resizable=1,width=${object/width},height=${object/height}')">
+ <img border="0"
+ tal:attributes="
+ width width;
+ height height;
+ src src;
+ alt python:title or ''" />
+ </a>
+ <div tal:condition="title" tal:content="title" class="caption">title</div>
+ </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<html tal:omit-tag="">
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
+ <title>slot_text_form</title>
+ </head>
+ <body tal:define="object nocall:options/object;
+ cols object/cols;
+ rows object/rows;
+ text object/text|nothing;"
+ tal:omit-tag="">
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr>
+ <td align="center">
+ <input type="text" name="cols:int" size="2" tabindex="2" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.id, 'cols')) + ':record:int';
+ value cols" />
+ </td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><textarea tabindex="1" tal:attributes="name python:'.'.join((object.id, 'text')) + ':record:text' ;
+ cols cols ;
+ rows rows"
+ class="mosaic_input"
+ tal:content="text"></textarea></td>
+ <td>
+ <input type="text" name="rows:int" size="2" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.id, 'rows')) + ':record:int';
+ value rows" />
+ </td>
+ </tr>
+ </table>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="object nocall:options/object;">
+ <ul>
+ <li tal:repeat="item object/text" tal:content="item">Item</li>
+ </ul>
+</div>
--- /dev/null
+<html tal:omit-tag="">
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=iso-8859-1">
+ <title>slot_spacer_form</title>
+ </head>
+ <body tal:define="object nocall:options/object;
+ nbOfSpaces object/nbOfSpaces;"
+ i18n:domain="plinn"
+ tal:omit-tag="">
+ <div>
+ <span i18n:translate="" tal:omit-tag="">Number of br:</span>
+ <input type="text" name="cols:int" size="2" tabindex="2" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.id, 'nbOfSpaces')) + ':record:int';
+ value nbOfSpaces" />
+ </div>
+ <br tal:repeat="br python:range(nbOfSpaces)" />
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="object nocall:options/object;
+ nbOfSpaces object/nbOfSpaces"
+ tal:omit-tag="">
+ <br tal:repeat="br python:range(nbOfSpaces)" />
+</div>
\ No newline at end of file
--- /dev/null
+<html tal:omit-tag="">
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ <title>slot_string_form</title>
+ </head>
+ <body tal:define="object nocall:options/object;
+ size object/size;
+ castOperator object/castOperator;
+ choices object/choices;
+ text python:(castOperator == 'tokens' and [' '.join(object.text),] or [object.text,])[0];"
+ tal:omit-tag="">
+ <input type="text" class="mosaic_input"
+ tal:condition="not:choices"
+ tal:attributes="name python:'.'.join((object.getId(), 'text')) + ':'.join(('', 'record', castOperator)) ;
+ size size;
+ value text;" />
+
+ <select tal:condition="choices" class="mosaic_input"
+ tal:attributes="name python:'.'.join((object.getId(), 'text')) + ':'.join(('', 'record', castOperator)) ; ">
+ <option tal:attributes="value choice ;
+ selected python:str(choice) == str(text)"
+ tal:content="choice" tal:repeat="choice choices">Choice</option>
+ </select>
+ </body>
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="object nocall:options/object;
+ text object/text;
+ ec object/getExprContext;
+ url python:object.url_expression(ec);"
+ tal:omit-tag="">
+ <a href="." tal:omit-tag="not:url" tal:attributes="href url">
+ <span tal:replace="text">text</span>
+ </a>
+</div>
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml" tal:omit-tag="">
+
+ <head tal:replace="nothing">
+ <meta http-equiv="content-type" content="text/html;charset=utf-8" />
+ <title>slot_text_form</title>
+ </head>
+
+ <body tal:define="object nocall:options/object;
+ cols object/cols;
+ rows object/rows;
+ castOperator object/castOperator|string:text;
+ text python:(castOperator=='lines' and ['\n'.join(object.text),] or [object.text,])[0]" tal:omit-tag="">
+ <table border="0" cellspacing="2" cellpadding="0">
+ <tr>
+ <td align="center">
+ <input class="mosaic_input" type="text" name="cols:int" size="2"
+ tal:attributes="name python:'.'.join((object.id, 'cols')) + ':record:int'; value cols" />
+ </td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>
+ <textarea class="mosaic_input" tabindex="1" tal:attributes="name python:'.'.join((object.id, 'text')) + ':record:' + castOperator ;
+ cols cols ;
+ rows rows" tal:content="text"></textarea>
+ </td>
+ <td>
+ <input class="mosaic_input" type="text" name="rows:int" size="2" tal:attributes="name python:'.'.join((object.id, 'rows')) + ':record:int'; value rows" />
+ </td>
+ </tr>
+ </table>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<div tal:define="object nocall:options/object;
+ text_format object/text_format;">
+ <div tal:condition="python:text_format == 'structured-text'"
+ class="slot_text">
+ <p tal:replace="structure python:here.portal_transforms.convert('st_to_html', object.text)">Structured text</p>
+ </div>
+ <div tal:condition="python:text_format != 'structured-text' "
+ class="slot_text">
+ <p tal:replace="structure object/text">plain text</p>
+ </div>
+</div>
--- /dev/null
+CMF-1.5.5 http://zope.org/Products/CMF
+Plinn-1.0 | http://plinn.org
+Photo-1.1 |
\ No newline at end of file
--- /dev/null
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _,
+ form_title='Add Mosaic Block'
+ )">
+<p class="form-help">
+ Le Mosaic Block regroupe des slots ou bien d'autres blocs.
+</p>
+
+<FORM ACTION="addMosaicBlockInformation" METHOD="POST">
+
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">Id</div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id" size="40" />
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">Block type : </div>
+ </td>
+ <td align="left" valign="top">
+ <select name="blockType" size="1">
+ <dtml-in "mosaic_tool.getDefaultBlockMetaFtis().keys()">
+ <option value="<dtml-var sequence-item>"><dtml-var sequence-item></option>
+ </dtml-in>
+ </select>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td align="left" valign="top">
+ </td>
+ <td align="left" valign="top">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit"
+ value="Add" />
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>
--- /dev/null
+<dtml-var manage_page_header>
+
+<dtml-var "manage_form_title(this(), _,
+ form_title='Add Slot'
+ )">
+<p class="form-help">
+ Le slot est la plus petite pièce du Mosaic Document
+</p>
+
+<FORM ACTION="addSlot" METHOD="POST">
+
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Id
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id" size="40" />
+ </td>
+ </tr>
+
+ <tr>
+ <td align="left" valign="top">
+ </td>
+ <td align="left" valign="top">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit"
+ value="Add" />
+ </div>
+ </td>
+ </tr>
+</table>
+</form>
+
+<dtml-var manage_page_footer>
--- /dev/null
+<dtml-if management_page_charset>
+ <dtml-comment>
+ A site-global encoding specification in a property.
+ Note that this feature only works if there are no unicode objects
+ around. This means that this feature is not likely to be supported
+ in all future versions of zope.
+ </dtml-comment>
+ <dtml-call "REQUEST.set('management_page_charset',
+ _['management_page_charset'])">
+ <dtml-call "REQUEST.set('management_page_charset_tag','')">
+<dtml-else>
+ <dtml-comment>
+ Thankfully no site-global encoding specification in a property.
+ We can set UTF-8, and unicode properties will work.
+ </dtml-comment>
+ <dtml-call "REQUEST.set('management_page_charset','UTF-8')">
+ <dtml-call "REQUEST.set('management_page_charset_tag','UTF-8:')">
+</dtml-if>
+
+<dtml-if "REQUEST.get('management_page_charset',None)=='UTF-8'">
+<dtml-var "u' '">
+</dtml-if>
+<dtml-var manage_page_header>
+<dtml-with "_(management_view='Properties')">
+<dtml-var manage_tabs>
+</dtml-with>
+
+<dtml-if Principia-Version>
+<p>
+<em>You are currently working in version &dtml-Principia-Version;</em>
+</p>
+</dtml-if Principia-Version>
+
+<form action="&dtml-URL1;" method="post">
+<dtml-if propertyMap>
+<p class="form-help">
+Properties allow you to assign simple values to Zope objects. To change
+property values, edit the values and click "Save Changes".
+</p>
+
+<table cellspacing="0" cellpadding="2" border="0">
+<tr class="list-header">
+ <td align="left" valign="top" width="16">
+
+ </td>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Name
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Value
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Type
+ </div>
+ </td>
+</tr>
+
+<dtml-in propertyMap mapping>
+<dtml-let type="not _.has_key('type') and 'string' or type">
+<tr>
+ <td align="left" valign="top" width="16">
+ <dtml-if "'d' in _['sequence-item'].get('mode', 'awd')">
+ <input type="checkbox" name="_ids:<dtml-var "REQUEST['management_page_charset_tag']">string:list" value="&dtml-id;"
+ id="cb-&dtml-id;">
+ <dtml-else>
+ </dtml-if>
+ </td>
+ <td align="left" valign="top">
+ <div class="form-label">
+ <label for="cb-&dtml-id;"><dtml-var "propertyLabel(id)" html_quote></label>
+ </div>
+ </td>
+ <td align="left" valign="top">
+
+ <dtml-if "'w' in _['sequence-item'].get('mode', 'awd')">
+ <dtml-if "type == 'int'">
+ <input type="text" name="&dtml-id;:&dtml-type;"
+ size="35" value="<dtml-if "hasProperty(id)"><dtml-var "'%s' % getProperty(id)" html_quote></dtml-if>">
+ <dtml-elif "type == 'long'">
+ <input type="text" name="&dtml-id;:&dtml-type;" size="35"
+ value="<dtml-if "hasProperty(id)"><dtml-var "('%s' % getProperty(id))" html_quote></dtml-if>">
+ <dtml-elif "type in ('float', 'date')">
+ <input type="text" name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">&dtml-type;" size="35"
+ value="<dtml-var "getProperty(id)" html_quote>">
+ <dtml-elif "type in ['string','ustring']">
+ <input type="text" name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">&dtml-type;" size="35"
+ value="<dtml-var "getProperty(id)" html_quote>">
+ <dtml-elif "type=='boolean'">
+ <input type="checkbox" name="&dtml-id;:boolean" size="35"
+ <dtml-if "getProperty(id)">CHECKED</dtml-if>>
+ <dtml-elif "type in ['tokens','utokens']">
+ <input type="text" name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">&dtml-type;" size="35"
+ value="<dtml-in "getProperty(id)">&dtml-sequence-item; </dtml-in>">
+ <dtml-elif "type in ['text','utext']">
+ <textarea name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">&dtml-type;" rows="6" cols="35"><dtml-var "getProperty(id)" html_quote></textarea>
+ <dtml-elif "type in ['lines','ulines']">
+ <textarea name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">&dtml-type;" rows="6" cols="35"><dtml-in
+ "getProperty(id)">&dtml-sequence-item;<dtml-if
+ sequence-end><dtml-else><dtml-var "'\n'"></dtml-if></dtml-in></textarea>
+
+ <dtml-elif "type=='selection'">
+
+ <dtml-if "hasProperty(select_variable)">
+ <div class="form-element">
+ <select name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">text">
+ <dtml-in "getProperty(select_variable)">
+ <option
+ <dtml-if "_['sequence-item']==getProperty(id)">SELECTED</dtml-if>
+ >&dtml-sequence-item;</option>
+ </dtml-in>
+ </select>
+ </div>
+ <dtml-elif "_.has_key(select_variable)">
+ <div class="form-element">
+ <select name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">text">
+ <dtml-in "_[select_variable]">
+ <option
+ <dtml-if "_['sequence-item']==getProperty(id)">SELECTED</dtml-if>
+ >&dtml-sequence-item;</option>
+ </dtml-in>
+ </select>
+ </div>
+ <dtml-else>
+ <div class="form-text">
+ No value for &dtml-select_variable;.
+ </div>
+ </dtml-if>
+
+ <dtml-elif "type=='multiple selection'">
+
+ <dtml-if "hasProperty(select_variable)">
+ <div class="form-element">
+ <select name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">list:string" multiple
+ size="<dtml-var "_.min(7, _.len(getProperty(select_variable)))">">
+ <dtml-in "getProperty(select_variable)">
+ <option<dtml-if
+ "getProperty(id) and (_['sequence-item'] in getProperty(id))"
+ > SELECTED</dtml-if
+ >>&dtml-sequence-item;</option>
+ </dtml-in>
+ </select>
+ </div>
+ <dtml-elif "_.has_key(select_variable)">
+ <div class="form-element">
+ <select name="&dtml-id;:<dtml-var "REQUEST['management_page_charset_tag']">list:string" multiple
+ size="<dtml-var "_.min(7, _.len(_[select_variable]))">">
+ <dtml-in "_[select_variable]">
+ <option<dtml-if
+ "getProperty(id) and (_['sequence-item'] in getProperty(id))"
+ > SELECTED</dtml-if
+ >>&dtml-sequence-item;</option>
+ </dtml-in>
+ </select>
+ </div>
+ <dtml-else>
+ <div class="form-text">
+ No value for &dtml-select_variable;.
+ </div>
+ </dtml-if>
+ <dtml-elif "type=='expr'">
+ <input type="text" name="<dtml-var id>:<dtml-var "REQUEST['management_page_charset_tag']"><dtml-var type>" size="35"
+ value="<dtml-var "getProperty(id).text" html_quote>">
+ <dtml-else>
+ <em>Unknown property type</em>
+ </dtml-if>
+ <dtml-else>
+ <table border="1">
+ <tr><td><dtml-var "getProperty(id)" html_quote></td></tr>
+ </table>
+ </dtml-if>
+ </td>
+ <td align="left" valign="top">
+ <div class="list-item">
+ &dtml-type;
+ </div>
+ </td>
+
+ <dtml-if "id=='title'">
+ <td align="center" valign="top">
+ <div class="list-item"><b>Warning:</b> be aware that removing 'title' without re-adding it might be dangerous.</div>
+ </td>
+ </dtml-if>
+</tr>
+</dtml-let>
+</dtml-in>
+<tr>
+ <td colspan="2"> </td>
+ <td align="left" valign="top">
+ <div class="form-element">
+ <input name="manage_editProperties:method" type="submit"
+ class="form-element" value="Save Changes" />
+<dtml-if property_extensible_schema__>
+ <input name="manage_delProperties:method" type="submit"
+ class="form-element" value="Delete" />
+ </div>
+ </td>
+ <td>
+ <dtml-comment>
+ This needs some community review before exposing it officially.
+ <input type="submit" name="manage_propertyTypeForm:method" value="Change Names/Types">
+ </dtml-comment>
+ </td>
+<dtml-else>
+ <td> </td>
+</dtml-if>
+ </td>
+</tr>
+</table>
+
+<dtml-else>
+<p class="form-help">
+Properties allow you to assign simple values to Zope objects. There are
+currently no properties defined for this item. <dtml-if
+property_extensible_schema__>To add a property, enter a name, type
+and value and click the "Add" button.
+</dtml-if>
+</p>
+
+</dtml-if>
+</form>
+
+<dtml-if property_extensible_schema__>
+
+<form action="&dtml-URL1;/manage_addProperty" method="post">
+
+<p class="form-help">
+To add a new property, enter a name, type and value for the new
+property and click the "Add" button.
+</p>
+
+<table>
+<tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Name
+ </div>
+ </td>
+ <td align="left" valign="top">
+ <input type="text" name="id:<dtml-var "REQUEST['management_page_charset_tag']">string" size="30" value=""/>
+ </td>
+ <td align="left" valign="top" class="form-label">
+ Type
+ </td>
+ <td align="left" valign="top">
+ <div class="form-element">
+ <select name="type">
+ <option>boolean</option>
+ <option>date</option>
+ <option>float</option>
+ <option>int</option>
+ <option>lines</option>
+ <option>long</option>
+ <option>expr</option>
+ <option selected>string</option>
+ <dtml-if "REQUEST['management_page_charset'] == 'UTF-8'">
+ <option>ustring</option>
+ <option>text</option>
+ <option>tokens</option>
+ <option>utext</option>
+ <option>utokens</option>
+ <option>ulines</option>
+ </dtml-if>
+ <option>selection</option>
+ <option>multiple selection</option>
+ </select>
+ </div>
+ </td>
+</tr>
+<tr>
+ <td align="left" valign="top">
+ <div class="form-label">
+ Value
+ </div>
+ </td>
+ <td colspan=2 align="left" valign="top">
+ <dtml-if "REQUEST['management_page_charset'] == 'UTF-8'">
+ <input type="text" name="value:UTF-8:ustring" size="30" />
+ <dtml-else>
+ <input type="text" name="value:string" size="30" />
+ </dtml-if>
+ </td>
+ <td align="right" valign="top">
+ <div class="form-element">
+ <input class="form-element" type="submit" name="submit" value=" Add " />
+ </div>
+ </td>
+</tr>
+</table>
+</form>
+</dtml-if>
+
+<dtml-var manage_page_footer>
+
+
--- /dev/null
+<dtml-let form_title="'Actions'">
+<dtml-if manage_page_header>
+ <dtml-var manage_page_header>
+<dtml-else>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+ <html lang="en">
+ <head>
+ <title>&dtml-form_title;</title>
+ </head>
+ <body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
+ <h3>&dtml-form_title;</h3>
+</dtml-if>
+</dtml-let>
+<dtml-var manage_tabs>
+
+<dtml-let mbis="[ct.id for ct in mosaic_tool.listTypeInfo() if ct.meta_type == 'Mosaic Block Information']"
+ availMbis="[ct.id for ct in mosaic_tool.listTypeInfo() if ct.meta_type == 'Mosaic Block Information' and ct.id not in objectIds(['Rule Information',])]">
+<dtml-if "objectIds(['Rule Information',])">
+<form action="&dtml-absolute_url;" method="POST">
+<dtml-in "objectValues(['Rule Information',])">
+<dtml-let currentSlot="_['sequence-item']">
+ <table>
+ <tr>
+ <td>
+ <input type="checkbox" name="ruleSelection:list"
+ value="<dtml-var "_['sequence-item'].id">">
+ </td>
+ <td class="form-label">
+ Block type
+ </td>
+ <td>
+ <dtml-let blockId="_['sequence-item'].id">
+ <select name="<dtml-var "blockId+'.id:record'">">
+ <dtml-in "[blockId,] + availMbis">
+ <option value="<dtml-var sequence-item>" <dtml-if "blockId == _['sequence-item']">selected</dtml-if>>
+ <dtml-var sequence-item>
+ </option>
+ </dtml-in>
+ </select>
+ </dtml-let>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Max intances nb
+ </td>
+ <td>
+ <input type="text"
+ name="<dtml-var "_['sequence-item'].id + '.maxNbInstance:int:record'">"
+ value="<dtml-var "_['sequence-item'].maxNbInstance">">
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Allow Move
+ </td>
+ <td>
+ <select name="<dtml-var "_['sequence-item'].id + '.allowMove:int:record'">">
+ <option value="1" <dtml-if "_['sequence-item'].allowMove">selected</dtml-if>>yes</option>
+ <option value="0" <dtml-if "not _['sequence-item'].allowMove">selected</dtml-if>>no</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Allow Move right and left
+ </td>
+ <td>
+ <select name="<dtml-var "_['sequence-item'].id + '.allowMoveRightAndLeft:int:record'">">
+ <option value="1" <dtml-if "_['sequence-item'].allowMoveRightAndLeft">selected</dtml-if>>yes</option>
+ <option value="0" <dtml-if "not _['sequence-item'].allowMoveRightAndLeft">selected</dtml-if>>no</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Allow Move up and down
+ </td>
+ <td>
+ <select name="<dtml-var "_['sequence-item'].id + '.allowMoveUpAndDown:int:record'">">
+ <option value="1" <dtml-if "_['sequence-item'].allowMoveUpAndDown">selected</dtml-if>>yes</option>
+ <option value="0" <dtml-if "not _['sequence-item'].allowMoveUpAndDown">selected</dtml-if>>no</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Mode
+ </td>
+ <td>
+ <select name="<dtml-var "_['sequence-item'].id + '.mode:record'">"
+ <option value="wd" <dtml-if "_['sequence-item'].mode == 'wd'">selected</dtml-if>>wd</option>
+ <option value="w" <dtml-if "_['sequence-item'].mode == 'w'">selected</dtml-if>>w</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3"><hr></td>
+ </tr>
+ </table>
+</dtml-let>
+</dtml-in>
+<div>
+ <input type="submit" name="saveRules:method" value="Save">
+ <input type="submit" name="deleteRules:method" value="Delete">
+</div>
+</form>
+</dtml-if>
+
+<dtml-if availMbis>
+<h3 class="form-help">Add a rule</h3>
+<form action="manage_addRule" method="POST">
+<table>
+ <tr>
+ <td class="form-label">
+ Block type
+ </td>
+ <td class="form-label">
+ <select name="id">
+ <dtml-in availMbis>
+ <option value="<dtml-var sequence-item>"><dtml-var sequence-item></option>
+ </dtml-in>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="form-label">
+ Max intances nb
+ </td>
+ <td class="form-label">
+ <input type="text" name="maxNbInstance:int" value="0">
+ </td>
+ </tr>
+ <tr>
+ <tr>
+ <td class="form-label">
+ Allow Move
+ </td>
+ <td>
+ <select name="allowMove:int">
+ <option value="1" selected>yes</option>
+ <option value="0">no</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="form-label">
+ Mode
+ </td>
+ <td>
+ <select name="mode">"
+ <option value="wd" selected>wd</option>
+ <option value="w">w</option>
+ </select>
+ </td>
+ </tr>
+ </tr>
+ <td colspan="2"><input type="submit" value="Add"></td>
+ </tr>
+</table>
+</form>
+</dtml-if>
+</dtml-let>
+<dtml-if manage_page_footer>
+ <dtml-var manage_page_footer>
+<dtml-else>
+ </body></html>
+</dtml-if>
--- /dev/null
+<dtml-let form_title="'Actions'">
+<dtml-if manage_page_header>
+ <dtml-var manage_page_header>
+<dtml-else>
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
+ <html lang="en">
+ <head>
+ <title>&dtml-form_title;</title>
+ </head>
+ <body bgcolor="#FFFFFF" link="#000099" vlink="#555555">
+ <h3>&dtml-form_title;</h3>
+</dtml-if>
+</dtml-let>
+<dtml-var manage_tabs>
+<dtml-if "objectIds(['Slot Information',])">
+<form action="&dtml-absolute_url;" method="POST">
+<dtml-in "objectValues(['Slot Information',])">
+<dtml-let currentSlot="_['sequence-item']">
+ <table>
+ <tr>
+ <td>
+ <input type="checkbox" name="slotSelection:list"
+ value="<dtml-var "_['sequence-item'].id">">
+ </td>
+ <td class="form-label">
+ Id
+ </td>
+ <td>
+ <input type="text"
+ name="<dtml-var "_['sequence-item'].id + '.id:record'">"
+ value="<dtml-var "_['sequence-item'].id">">
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label">
+ Type
+ </td>
+ <td>
+ <input type="text"
+ name="<dtml-var "_['sequence-item'].id + '.type:record'">"
+ value="<dtml-var "_['sequence-item'].type">">
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="form-label" valign="top">
+ Arguments
+ </td>
+ <td>
+ <table border="1">
+ <tr>
+ <th>Id</th>
+ <th>Type</th>
+ <th>Value</th>
+ </tr>
+ <dtml-in "_['sequence-item'].propertyMap()">
+ <tr>
+ <td><dtml-var "_['sequence-item']['id']"></td>
+ <td><dtml-var "_['sequence-item']['type']"></td>
+ <td><dtml-var "currentSlot.getProperty(_['sequence-item']['id'])"></td>
+ </tr>
+ </dtml-in>
+ <tr>
+ <td colspan="3">
+ <div class="std-text">
+ <a href="<dtml-var "currentSlot.absolute_url() + '/manage_propertiesForm'">">
+ Edit arguments...
+ </a>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="3"><hr></td>
+ </tr>
+ </table>
+</dtml-let>
+</dtml-in>
+<div>
+ <input type="submit" name="saveSlots:method" value="Save">
+ <input type="submit" name="deleteSlots:method" value="Delete">
+</div>
+</form>
+</dtml-if>
+<h3 class="form-help">Add a slot</h3>
+<form action="manage_addSlot" method="POST">
+<table>
+ <tr>
+ <td class="form-label">
+ Id
+ </td>
+ <td class="form-label">
+ <input type="text" name="id">
+ </td>
+ </tr>
+ <tr>
+ <td class="form-label">
+ Type
+ </td>
+ <td class="form-label">
+ <input type="text" name="type">
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <input type="submit" value="Add">
+ </td>
+ </tr>
+</table>
+</form>
+<dtml-if manage_page_footer>
+ <dtml-var manage_page_footer>
+<dtml-else>
+ </body></html>
+</dtml-if>
--- /dev/null
+from Products.CMFCore.utils import getToolByName
+from Products.GenericSetup.utils import importObjects, exportObjects
+
+def importMosaicTool(context):
+ """Import mosaic tool and content types from XML files.
+ """
+ site = context.getSite()
+ tool = getToolByName(site, 'mosaic_tool')
+
+ importObjects(tool, 'mosaic_tool/', context)
+
+def exportMosaicTool(context):
+ """Export mosaic tool content types as a set of XML files.
+ """
+ site = context.getSite()
+ tool = getToolByName(site, 'mosaic_tool', None)
+ if tool is None:
+ logger = context.getLogger('mosaictool')
+ logger.info('Nothing to export.')
+ return
+
+ exportObjects(tool, 'mosaic_tool/', context)
\ No newline at end of file
--- /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
+
\ No newline at end of file
--- /dev/null
+<html>
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+ <title>block_canvas</title>
+ </head>
+
+ <body tal:define="baseBlock nocall:block;
+ tableInfo baseBlock/getBlocksTable;
+ rows tableInfo/rows;
+ cols tableInfo/cols;
+ lines tableInfo/lines;
+ allowedBlocks python:(displayAction != 'edit' and [(),] or [baseBlock.getAllowedBlocks()])[0];"
+ tal:omit-tag="" i18n:domain="plinn" metal:define-macro="canvas">
+ <table width="100%">
+
+ <tr tal:condition="python:not rows and displayAction == 'edit'">
+ <td>
+ <form metal:use-macro="here/block_utils/macros/add_block_form">Formulaire de création du premier block</form>
+ </td>
+ </tr>
+
+ <tr tal:repeat="line lines">
+ <span tal:repeat="blockInfo line" tal:omit-tag="">
+ <td valign="top" tal:condition="python:blockInfo.get('rowspan', 1) > 0"
+ tal:attributes="rowspan python:blockInfo.get('rowspan', 1)"
+ tal:define="block blockInfo/block">
+ <div tal:condition="block" tal:omit-tag="">
+
+ <div tal:condition="python:displayAction == 'edit'" tal:omit-tag="">
+ <form metal:use-macro="here/block_utils/macros/add_block_form">Formulaire de création d'un block au dessus
+ <span metal:fill-slot="additional_fields" tal:omit-tag="">
+ <input type="hidden" name="xpos:int" value="0" tal:attributes="value blockInfo/col" />
+ <input type="hidden" name="beforeBlock" value="hiddenValue" tal:attributes="value block/getId|nothing" />
+ </span>
+ </form>
+ </div>
+
+ <a name="anchor" tal:attributes="name block/getId"></a>
+ <div tal:condition="python:displayAction == 'edit'" tal:omit-tag="">
+ <span metal:use-macro="here/block_utils/macros/move_table">tableau des boutons de délacement</span>
+ </div>
+ <div tal:replace="structure python:block.callTemplate(displayAction=displayAction, baseBlock=baseBlock, blockInfo=blockInfo, here=here)">
+ <h2>Rendu HTML du block</h2>
+ </div>
+ <div tal:condition="python:displayAction == 'edit' and blockInfo.get('lastOne')"
+ tal:omit-tag="">
+ <form metal:use-macro="here/block_utils/macros/add_block_form">Formulaire de création d'un block au dessus
+ <span tal:omit-tag="" metal:fill-slot="additional_fields">
+ <input type="hidden" name="xpos:int" value="0" tal:attributes="value blockInfo/col" />
+ <input type="hidden" name="afterBlock" value="hiddenValue" tal:attributes="value block/getId|nothing" />
+ </span>
+ </form>
+ </div>
+ </div>
+
+ <div tal:condition="python:not block and displayAction == 'edit'">
+ <form metal:use-macro="here/block_utils/macros/add_block_form">Formulaire de création du premier block
+ <span tal:omit-tag="" metal:fill-slot="additional_fields">
+ <input type="hidden" name="xpos:int" value="0" tal:attributes="value blockInfo/col" />
+ </span>
+ </form>
+ </div>
+
+ </td>
+ </span>
+ </tr>
+ </table>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<script type="text/javascript">
+//<!--
+new TreeMaker(document.getElementById("&dtml-box_id;"), "&dtml-filter_str;", portal_url()+'/');
+//-->
+</script>
--- /dev/null
+##parameters=rootObject, filtered_meta_types=[], userid=''
+
+req = context.REQUEST
+resp = req.RESPONSE
+collapse_all = False
+if req.form.get('collapse_all', '') == rootObject.id or req.get('just_login', False) :
+ collapse_all = True
+
+from Products.CMFCore.permissions import View
+
+def getSubObjects(object) :
+ if getattr(object, 'isPortalContent', False) :
+ return []
+ childs = list(object.listNearestFolderContents(contentFilter={'portal_type':filtered_meta_types}, userid=userid))
+ childs.sort(lambda x, y : cmp(x.title_or_id().lower(), y.title_or_id().lower()))
+ return childs
+
+
+
+from ZTUtils import SimpleTreeMaker
+stateName = rootObject.id + userid + '_tree'
+cookieName = stateName + '-state'
+stm = SimpleTreeMaker(stateName)
+stm.setChildAccess(function=getSubObjects)
+#stm.setStateFunction(expandIfUnauthorized)
+
+tree, rows = stm.cookieTree(rootObject)
+cookieValue = resp.cookies[cookieName]['value']
+resp.setCookie(cookieName, cookieValue, path = '/')
+
+return {'tree' : tree, 'rows' : rows}
\ No newline at end of file
--- /dev/null
+<html xmlns="http://www.w3.org/1999/xhtml" metal:use-macro="here/main_template/macros/master">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ </head>
+
+ <body i18n:domain="plinn">
+ <div metal:fill-slot="header">
+ <div metal:use-macro="here/widgets/macros/generic_header">
+ generic_header macro</div>
+ </div>
+ <div tal:define="block nocall:here ; displayAction string:edit" tal:omit-tag="" metal:fill-slot="main">
+ <div><a title="Paste" href="." tal:attributes="href string:${block/absolute_url}/pasteBlocks" tal:condition="python:here.cb_dataValid() and block.haveRules()" i18n:attributes="title"><img src="paste.png" alt="Paste" height="14" width="16" tal:attributes="src string:paste.png" border="0" i18n:attributes="alt" /></a></div>
+ <div metal:use-macro="here/block_canvas/macros/canvas">Block Canvas</div>
+ </div>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+<html metal:use-macro="here/main_template_view/macros/master" xmlns="http://www.w3.org/1999/xhtml">
+
+ <head>
+ <meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />
+ <title>Visualisation d'un document mosaïque</title>
+ </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="" tal:define="block nocall:here;
+ displayAction string:view">
+ <div metal:use-macro="here/block_canvas/macros/canvas">Block Canvas here</div>
+ </div>
+ </body>
+
+</html>
\ No newline at end of file
--- /dev/null
+##parameters=filter=''
+
+def replaceXMLEntities(text) :
+ for c, ent in (('<', '<'), ('>', '>'), ('&', '&')) :
+ text = text.replace(c, ent)
+ return text
+
+from string import maketrans
+rmBadAttrChars = maketrans('<&"', ' ')
+
+filter = filter.split(',')
+
+root = context
+context.REQUEST.RESPONSE.setHeader('content-type', 'text/xml; charset=utf-8')
+print '<xml>'
+for ob in context.listNearestFolderContents(contentFilter={'portal_type':filter}) :
+ icon = context.restrictedTraverse(ob.getIcon())
+ state = 0
+ if not getattr(ob, 'isPortalContent', False) :
+ state = ob.listNearestFolderContents(contentFilter={'portal_type':filter}) and "-1" or "0"
+ row = '<row id="%(id)s" url="%(url)s" icon="%(icon)s" height="%(height)d" width="%(width)d" state="%(state)s" description="%(description)s">%(title)s</row>' % {
+ 'id' : ob.getId(),
+ 'url' : ob.absolute_url(),
+ 'title' : ' '+replaceXMLEntities(ob.title_or_id()),
+ 'description' : ob.Description().translate(rmBadAttrChars),
+ 'icon' : icon.absolute_url(),
+ 'height' : icon.height,
+ 'width' : icon.width,
+ 'state' : state
+ }
+ print row
+
+
+print '</xml>'
+
+return printed
\ No newline at end of file
--- /dev/null
+1.0
\ No newline at end of file