def get_content_links(obj): refs = set() if ILayoutAware.providedBy(obj): behavior_data = ILayoutAware(obj) # get data from tile data annotations = IAnnotations(obj) for key in annotations.keys(): if key.startswith(ANNOTATIONS_KEY_PREFIX): data = annotations[key] refs |= get_tile_data_links(obj, data) if not behavior_data.contentLayout and behavior_data.content: dom = fromstring(behavior_data.content) for el in dom.cssselect('.mosaic-text-tile .mosaic-tile-content'): links = extractLinks(tostring(el)) refs |= li.getObjectsFromLinks(obj, links) try: # scan more than just this we probably should... value = obj.text.raw links = extractLinks(value) refs |= li.getObjectsFromLinks(obj, links) except AttributeError: pass if getattr(obj, 'image'): if IReferenceNamedImage.providedBy(obj.image): sub_obj = uuidToObject(obj.image.reference) if sub_obj: objid = get_ref(obj) if objid: refs.add(RelationValue(objid)) return refs
def get_layout_name(self, context, default_layout='index.html'): adapted = ILayoutAware(context, None) selected = None if adapted is not None: selected = adapted.pageSiteLayout if selected is None: context = aq_parent(context) while not ISiteRoot.providedBy(context): adapted = ILayoutAware(context, None) if adapted and adapted.sectionSiteLayout: selected = adapted.sectionSiteLayout break context = aq_parent(context) if selected is None: if ISiteRoot.providedBy(context): # check if a default layout is set try: selected = context.portal_registry[ 'castle.cms.default_layout'] or default_layout # noqa except (AttributeError, KeyError): selected = default_layout else: selected = default_layout return selected
def onLayoutEdited(obj, event): """ need to get the layout because you need to know what are acceptible storage values """ lookup = ILayoutAware(obj) layout = lookup.content_layout() if not layout: return tree = fromstring(layout) tile_keys = [] for el in utils.bodyTileXPath(tree): tile_url = el.attrib.get('data-tile', '') if 'plone.app.standardtiles.field' in tile_url: continue tile_keys.append( ANNOTATIONS_KEY_PREFIX + '.' + tile_url.split('?')[0].split('/')[-1] ) annotations = IAnnotations(obj) for key in list(annotations.keys()): if key.startswith(ANNOTATIONS_KEY_PREFIX) and key not in tile_keys: del annotations[key]
def deletelayout(self): layout_resources = queryResourceDirectory( CONTENT_LAYOUT_RESOURCE_NAME, 'custom') # find directory layout_path = self.request.form.get('layout') filename = layout_path.split('/')[-1] directory = layout_resources for part in layout_path.replace('custom/', '').split('/')[:-1]: directory = directory[part] del directory[filename] # now to modify manifest to not include if MANIFEST_FILENAME in directory.listDirectory(): manifest = loadManifest(directory.readFile(MANIFEST_FILENAME)) removeLayout(manifest, filename) directory.writeFile(MANIFEST_FILENAME, dumpManifest(manifest)) # now reassign if provided replacement = self.request.form.get('replacement') if replacement: replacement = self._get_layout_path(replacement) catalog = api.portal.get_tool('portal_catalog') for brain in catalog(layout=self._get_layout_path(layout_path)): obj = brain.getObject() layout_data = ILayoutAware(obj, None) if layout_data: layout_data.contentLayout = replacement obj.reindexObject(idxs=['layout']) return json.dumps({ 'success': True, 'user_layouts': getUserContentLayoutsForType(self.context.portal_type), 'available_layouts': getContentLayoutsForType(self.context.portal_type) })
def setDefaultLayoutForNewPage(obj, event): """When a new page is created, set its layout based on the default in the FTI """ layoutAware = ILayoutAware(obj, None) if layoutAware is None: return # Initialise object layoutAware.content = ILayoutAware['content'].missing_value layoutAware.pageSiteLayout = ILayoutAware['pageSiteLayout'].missing_value layoutAware.sectionSiteLayout = ILayoutAware['sectionSiteLayout'].missing_value portal_type = obj.portal_type template = getDefaultPageLayout(portal_type) if template is None: raise ValueError("Cannot find layout template for %s" % portal_type) templatePath = urlparse.urljoin(obj.absolute_url_path(), template) try: layoutAware.content = resolveResource(templatePath) except: LOGGER.exception("Could not resolve default page layout %s" % portal_type)
def get(self): available = dict([(t.value, t.title) for t in AvailableSiteLayouts(self.context)]) applied = 'index.html' applied_context = getSite() context = self.context adapted = context_adapted = ILayoutAware(context) selected = adapted.pageSiteLayout if selected is None: context = aq_parent(context) while not ISiteRoot.providedBy(context): adapted = ILayoutAware(context, None) if adapted and adapted.sectionSiteLayout: selected = adapted.sectionSiteLayout break context = aq_parent(context) if selected: applied = selected applied_context = context return { 'success': True, 'available': available, 'applied': applied, 'context': utils.get_path(self.context), 'applied_context': utils.get_path(applied_context), 'page_layout': context_adapted.pageSiteLayout, 'section_layout': context_adapted.sectionSiteLayout, 'folder': IDexterityContainer.providedBy(self.context) }
def handleAdd(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return typeName = self.tileType.__name__ context = self.context # Look up if our context supports tiles, if not # pick default view instead if not ILayoutAware(context, None): default_page_view = getMultiAdapter((context, self.request), name='default_page') default_page = default_page_view.getDefaultPage() context = default_page and context[default_page] or context context = ILayoutAware(context, None) # Traverse to a new tile in the context, with no data tile = context.restrictedTraverse( '@@%s/%s' % (typeName, self.tileId,)) dataManager = ITileDataManager(tile) dataManager.set(data) # Look up the URL - we need to do this after we've set the data to # correctly account for transient tiles tileURL = absoluteURL(tile, self.request) contextURL = absoluteURL(tile.context, self.request) tileRelativeURL = tileURL if tileURL.startswith(contextURL): tileRelativeURL = '.' + tileURL[len(contextURL):] notify(ObjectCreatedEvent(tile)) notify(ObjectAddedEvent(tile, self.context, self.tileId)) IStatusMessage(self.request).addStatusMessage( _(u"Tile created at ${url}", mapping={'url': tileURL}), type=u'info', ) # Calculate the edit URL and append some data in a JSON structure, # to help the UI know what to do. url = getEditTileURL(tile, self.request) tileDataJson = {} tileDataJson['action'] = "save" tileDataJson['mode'] = "add" tileDataJson['url'] = tileRelativeURL tileDataJson['tile_type'] = typeName tileDataJson['id'] = tile.id url = appendJSONData(url, 'tiledata', tileDataJson) self.request.response.redirect(url)
def recursive_create_path(path): if path in ('/', ''): folder = site else: path = path.lstrip('/') folder = traverse(path) if folder is not None and not IFolder.providedBy(folder): api.content.delete(folder) folder = None if folder is None: # Need to create folders up to where we want content # we'll walk it up create folders as needed folder = site for part in path.split('/'): try: ob = folder[part] if not IFolder.providedBy(ob): api.content.delete(ob) raise KeyError() else: folder = ob except (KeyError, AttributeError): fpath = os.path.join(args.export_directory, relpath(folder), part, '__folder__') if os.path.exists(fpath): fi = open(fpath) data = mjson.loads(fi.read()) fi.close() importtype = get_import_type( data, fpath[len(args.export_directory):], None) creation_data = importtype.get_data() creation_data['container'] = folder creation_data['id'] = part try: folder = api.content.create(**creation_data) except api.exc.InvalidParameterError: logger.error( 'Error creating content {}'.format(fpath), exc_info=True) return importtype.post_creation(folder) if data['state']: try: api.content.transition(folder, to_state=data['state']) except: # maybe workflows do not match up pass folder.reindexObject() else: folder = api.content.create(type='Folder', id=part, title=part.capitalize(), container=folder) bdata = ILayoutAware(folder) bdata.contentLayout = '++contentlayout++castle/folder-query.html' return folder
def save(self): adapted = ILayoutAware(self.context) data = self.request.form.get('data') if not data: return data = json.loads(data) adapted.pageSiteLayout = data['page_layout'] adapted.sectionSiteLayout = data['section_layout'] return {'success': True}
def add_body_classes(self, original_context, context, request, tree, result, raw=False): ''' Dynamically add useful body classes for theming and JS. ''' body_classes = '' if raw: # this is a content layout likely plone_layout = queryMultiAdapter((original_context, request), name='plone_layout') if plone_layout: body_classes += ' ' + plone_layout.bodyClass(None, None) else: content_body = body_xpath(result) if len(content_body) > 0: body_classes += ' ' + content_body[0].attrib.get('class', '') body = body_xpath(tree)[0] from plone.app.blocks.layoutbehavior import ILayoutAware if ILayoutAware.providedBy(context): body_classes += ' template-layout' adapted = ILayoutAware(context, None) if adapted is not None: layout = getattr(adapted, 'contentLayout', None) if layout: # Transform ++contentlayout++default/document.html # into layout-default-document names = LAYOUT_NAME.findall(layout) if len(names) == 1: body_classes += ' layout-' + names[0].replace('/', '-') else: body_classes += ' layout-custom' try: body_classes += ' selected-layout-%s ' % original_context.getLayout( ) # noqa except Exception: pass classes = '%s %s' % (body.attrib.get('class', ''), body_classes) body.attrib['class'] = classes plone_view = queryMultiAdapter((original_context, request), name='plone') if plone_view: try: body.attrib.update(plone_view.patterns_settings()) except AttributeError: plone_view = queryMultiAdapter((context, request), name='plone') if plone_view: body.attrib.update(plone_view.patterns_settings())
def deletelayout(self): layout_resources = queryResourceDirectory( CONTENT_LAYOUT_RESOURCE_NAME, 'custom') layout_path = self.request.form.get('layout') if len(layout_path.split('/')) <= 2: sm = getSecurityManager() # this is a global layout, need to check permissions if not sm.checkPermission('Plone: Manage Content Layouts', api.portal.get()): raise Unauthorized("User not allowed to delete global layout") else: # check this user is allowed to delete this template user_dir = 'custom/user-layouts/{0:s}'.format( api.user.get_current().getId()) if not layout_path.startswith(user_dir): raise Unauthorized("You are not allowed to delete this layout") # find directory filename = layout_path.split('/')[-1] directory = layout_resources for part in layout_path.replace('custom/', '').split('/')[:-1]: directory = directory[part] del directory[filename] # now to modify manifest to not include if MANIFEST_FILENAME in directory.listDirectory(): manifest = loadManifest(directory.readFile(MANIFEST_FILENAME)) removeLayout(manifest, filename) directory.writeFile(MANIFEST_FILENAME, dumpManifest(manifest)) # now reassign if provided replacement = self.request.form.get('replacement') if replacement: replacement = self._get_layout_path(replacement) catalog = api.portal.get_tool('portal_catalog') for brain in catalog(layout=self._get_layout_path(layout_path)): obj = brain.getObject() layout_data = ILayoutAware(obj, None) if layout_data: layout_data.contentLayout = replacement obj.reindexObject(idxs=['layout']) return json.dumps( { 'success': True, 'user_layouts': getUserContentLayoutsForType( self.context.portal_type ), 'available_layouts': getContentLayoutsForType( self.context.portal_type, self.context ) } )
def deletelayout(self): layout_resources = queryResourceDirectory( CONTENT_LAYOUT_RESOURCE_NAME, 'custom') layout_path = self.request.form.get('layout') if len(layout_path.split('/')) <= 2: sm = getSecurityManager() # this is a global layout, need to check permissions if not sm.checkPermission('Plone: Manage Content Layouts', api.portal.get()): raise Unauthorized("User not allowed to delete global layout") else: # check this user is allowed to delete this template user_dir = 'custom/user-layouts/{}'.format( api.user.get_current().getId()) if not layout_path.startswith(user_dir): raise Unauthorized("You are not allowed to delete this layout") # find directory filename = layout_path.split('/')[-1] directory = layout_resources for part in layout_path.replace('custom/', '').split('/')[:-1]: directory = directory[part] del directory[filename] # now to modify manifest to not include if MANIFEST_FILENAME in directory.listDirectory(): manifest = loadManifest(directory.readFile(MANIFEST_FILENAME)) removeLayout(manifest, filename) directory.writeFile(MANIFEST_FILENAME, dumpManifest(manifest)) # now reassign if provided replacement = self.request.form.get('replacement') if replacement: replacement = self._get_layout_path(replacement) catalog = api.portal.get_tool('portal_catalog') for brain in catalog(layout=self._get_layout_path(layout_path)): obj = brain.getObject() layout_data = ILayoutAware(obj, None) if layout_data: layout_data.contentLayout = replacement obj.reindexObject(idxs=['layout']) return json.dumps( { 'success': True, 'user_layouts': getUserContentLayoutsForType( self.context.portal_type ), 'available_layouts': getContentLayoutsForType( self.context.portal_type ) } )
def create_plain_folder(self, id, container): logger.info("Creating plain Folder (no __folder__ file found), %s" % id) folder = api.content.create(type='Folder', id=id, title=id.capitalize(), container=container) bdata = ILayoutAware(folder) bdata.contentLayout = '++contentlayout++castle/folder-query.html' if not args.skip_transitioning: api.content.transition(folder, to_state='published') return folder
def transform(self, result, encoding): context = getContext(self.published) layout = queryMultiAdapter( (context, self.request), name='plone_layout' ) root = result.tree.getroot() body = root.body if layout is None or body is None: return result body_class = body.attrib.get('class', '') body_classes = body_class.split() # Get default body classes if 'template-' not in body_class and 'site-' not in body_class: body_classes.extend([ n for n in layout.bodyClass(None, self.published).split() if n not in body_classes ]) # Get contentLayout body class if ( 'template-layout' in body_classes or 'template-layout_view' in body_classes ): adapted = ILayoutAware(context, None) if adapted is not None: layout = None if getattr(adapted, 'content_layout_path', False): # plone.app.blocks > 4.0.0rc1 layout = adapted.content_layout_path() else: layout = getattr(adapted, 'contentLayout', None) if layout: # Transform ++contentlayout++default/document.html # into layout-default-document names = LAYOUT_NAME.findall(layout) if len(names) == 1: body_classes.append('layout-' + names[0].replace('/', '-')) else: body_classes.append('layout-custom') body_classes.append('mosaic-grid') # Set body class body.attrib['class'] = ' '.join(body_classes) return result
def migrate_content_to_customContentLayout(context): pc = getToolByName(context, 'portal_catalog') brains = [] brains.extend(pc.unrestrictedSearchResults( object_provides=ILayoutAware.__identifier__)) brains.extend(pc.unrestrictedSearchResults( object_provides=ILayoutBehaviorAdaptable.__identifier__)) for brain in brains: ob = brain._unrestrictedGetObject() adapted = ILayoutAware(ob) if all([ not getattr(adapted, 'customContentLayout', None), getattr(adapted, 'content', None) ]): adapted.customContentLayout = adapted.content adapted.content = None
def findall_tiles(context, spec): if not isinstance(spec, list): spec = [spec] request = context.REQUEST la = ILayoutAware(context) layout = ( la.customContentLayout if la.customContentLayout is not None else la.contentLayout if la.contentLayout is not None else la.content ) if layout is None: return [] possible_urls = re.findall(r"(@@[\w\.]+/\w+)", layout) urls = [] for name in spec: urls += [url for url in possible_urls if url.startswith("@@{}".format(name))] # TODO: maybe better to get tile data? using ITileDataManager(id)? our_tile = request.response.headers.get("x-tile-url") tiles = [context.unrestrictedTraverse(str(url)) for url in urls] # mosaic get confused if we are doing this while creating a filter tile if request.response.headers.get("x-tile-url"): if our_tile: request.response.headers["x-tile-url"] = our_tile else: del request.response.headers["x-tile-url"] return tiles
def transformIterable(self, result, encoding): if ( self.published is None or not self.request.get('plone.app.blocks.enabled', False) or not isinstance(result, XMLSerializer) ): return None context = aq_parent(aq_base(self.published)) or api.portal.get() layout = queryMultiAdapter( (context, self.request), name='plone_layout' ) root = result.tree.getroot() body = root.body if layout is None or body is None: return result body_class = body.attrib.get('class', '') body_classes = body_class.split() # Get default body classes if 'template-' not in body_class and 'site-' not in body_class: body_classes.extend([ n for n in layout.bodyClass(None, self.published).split() if n not in body_classes ]) # Get contentLayout body class if 'template-layout' in body_classes: adapted = ILayoutAware(context, None) if adapted is not None: layout = getattr(adapted, 'contentLayout', None) if layout: # Transform ++contentlayout++default/document.html # into layout-default-document names = LAYOUT_NAME.findall(layout) if len(names) == 1: body_classes.append('layout-' + names[0].replace('/', '-')) else: body_classes.append('layout-custom') # Enable mosaic-grid when no grid system is defined gridSystem = xpath1(gridXPath, result.tree) if gridSystem is None: registry = queryUtility(IRegistry) if registry: settings = registry.forInterface(IBlocksSettings, check=False) gridSystem = getattr( settings, 'default_grid_system', None) or None if gridSystem is None: body_classes.append('mosaic-grid') # Set body class body.attrib['class'] = ' '.join(body_classes) return result
def is_deco_enabled(self): try: from plone.app.blocks.layoutbehavior import ILayoutAware if ILayoutAware.providedBy(self.context): return True except: pass return False
def recursive_create_path(path): if path in ('/', ''): folder = site else: path = path.lstrip('/') folder = traverse(path) if folder is not None and not IFolder.providedBy(folder): api.content.delete(folder) folder = None if folder is None: # Need to create folders up to where we want content # we'll walk it up create folders as needed folder = site for part in path.split('/'): try: ob = folder[part] if not IFolder.providedBy(ob): logger.warn( 'Existing object in traversal path is not folderish. Removing it.' ) api.content.delete(ob) raise KeyError() else: folder = ob except (KeyError, AttributeError): fpath = os.path.join(args.export_directory, relpath(folder), part, '__folder__') imported = False if os.path.exists(fpath): imported = import_object(fpath) if not imported: logger.info( "Creating plain Folder (no __folder__ file found), %s" % part) folder = api.content.create(type='Folder', id=part, title=part.capitalize(), container=folder) bdata = ILayoutAware(folder) bdata.contentLayout = '++contentlayout++castle/folder-query.html' if not args.skip_transitioning: api.content.transition(folder, to_state='published') return folder
def _context_selected_layout(self): """Return the current layout for the layout aware context if we are on the layout aware context """ if not ILayoutAware(self.context, None): return '' selectable_layout = ISelectableBrowserDefault(self.context, None) if not selectable_layout: return '' return selectable_layout.getLayout()
def is_mosaic_edit_form(request): try: if (ILayoutAware.providedBy(request.PUBLISHED.context) and IDexterityEditForm.providedBy(request.PUBLISHED) and request.PUBLISHED.context.getLayout() == 'layout_view' and request.PUBLISHED.__name__ == 'edit'): return True except: pass return False
def get_field_data(self): from plone.dexterity.interfaces import IDexterityFTI from plone.behavior.interfaces import IBehaviorAssignable data = {} schema = getUtility(IDexterityFTI, name=self.obj.portal_type).lookupSchema() for name, field in getFieldsInOrder(schema): data[name] = getattr(self.obj, name, None) behavior_assignable = IBehaviorAssignable(self.obj) for behavior in behavior_assignable.enumerateBehaviors(): binst = behavior.interface(self.obj) bdata = {} for name, field in getFieldsInOrder(behavior.interface): bdata[name] = getattr(binst, name, None) data[behavior.interface.__identifier__] = bdata if ILayoutAware.providedBy(self.obj): from plone.tiles.data import ANNOTATIONS_KEY_PREFIX from plone.app.blocks.utils import getLayout from repoze.xmliter.utils import getHTMLSerializer from plone.app.blocks import tiles from plone.app.blocks import gridsystem from lxml.html import tostring tdata = {} annotations = IAnnotations(self.obj, {}) for key in annotations.keys(): if key.startswith(ANNOTATIONS_KEY_PREFIX): adata = annotations[key] tdata[key] = adata data['tile_data'] = tdata req = site.REQUEST layout = getLayout(self.obj) dom = getHTMLSerializer(layout) try: tiles.renderTiles(req, dom.tree, site=site, baseURL=self.obj.absolute_url() + '/layout_view') except TypeError: tiles.renderTiles(req, dom.tree, baseURL=self.obj.absolute_url() + '/layout_view') gridsystem.merge(req, dom.tree) data['rendered_layout'] = tostring(dom.tree) return data
def save(self): adapted = ILayoutAware(self.context) data = self.request.form.get('data') if not data: return data = json.loads(data) adapted.pageSiteLayout = data['page_layout'] adapted.sectionSiteLayout = data['section_layout'] parent = aq_parent(self.context) if ISiteRoot.providedBy(parent): # check if default page... if getDefaultPage(parent) == self.context.id: # also set site wide global layout setting... registry = getUtility(IRegistry) field = registry_field.TextLine(title=u'Default layout', required=False) new_record = Record(field) registry.records['castle.cms.default_layout'] = new_record registry['castle.cms.default_layout'] = data['section_layout'] return {'success': True}
def deletelayout(self): layout_resources = queryResourceDirectory( CONTENT_LAYOUT_RESOURCE_NAME, 'custom') # find directory layout_path = self.request.form.get('layout') filename = layout_path.split('/')[-1] directory = layout_resources for part in layout_path.replace('custom/', '').split('/')[:-1]: directory = directory[part] del directory[filename] # now to modify manifest to not include if MANIFEST_FILENAME in directory.listDirectory(): manifest = loadManifest(directory.readFile(MANIFEST_FILENAME)) removeLayout(manifest, filename) directory.writeFile(MANIFEST_FILENAME, dumpManifest(manifest)) # now reassign if provided replacement = self.request.form.get('replacement') if replacement: replacement = self._get_layout_path(replacement) catalog = api.portal.get_tool('portal_catalog') for brain in catalog(layout=self._get_layout_path(layout_path)): obj = brain.getObject() layout_data = ILayoutAware(obj, None) if layout_data: layout_data.contentLayout = replacement obj.reindexObject(idxs=['layout']) return json.dumps( { 'success': True, 'user_layouts': getUserContentLayoutsForType( self.context.portal_type ), 'available_layouts': getContentLayoutsForType( self.context.portal_type ) } )
def getLayoutAwareSiteLayout(context): """Get the path to the site layout for a page. This is generally only appropriate for the view of this page. For a generic template or view, use getDefaultSiteLayout(context) instead. """ layoutAware = ILayoutAware(context, None) if layoutAware is not None: if getattr(layoutAware, 'pageSiteLayout', None): return layoutAware.pageSiteLayout return getDefaultSiteLayout(context)
def on_content_created(obj, event): if obj.portal_type == 'Dashboard': return metadata = IPublication(obj, None) if metadata is not None: if metadata.effective is None: metadata.effective = localized_now(obj) _touch_contributors(obj) if obj.portal_type == 'Collection': # enable syndication on type by default settings = FeedSettings(obj) settings.enabled = True adapted = ILayoutAware(obj, None) if adapted: if not adapted.content and not adapted.contentLayout: registry = getUtility(IRegistry) try: default_layout = registry['%s.%s' % (DEFAULT_CONTENT_LAYOUT_REGISTRY_KEY, obj.portal_type.replace(' ', '-'))] adapted.contentLayout = default_layout except (KeyError, AttributeError): pass try: default_layout = registry['%s.%s' % (DEFAULT_SITE_LAYOUT_REGISTRY_KEY, obj.portal_type.replace(' ', '-'))] adapted.pageSiteLayout = default_layout except (KeyError, AttributeError): pass try: tasks.scan_links.delay('/'.join(obj.getPhysicalPath())) except CannotGetPortalError: pass obj.reindexObject()
def test_page_site_layout_is_not_acquired(self): self.registry[DEFAULT_SITE_LAYOUT_REGISTRY_KEY] = \ b'/++sitelayout++testlayout1/site.html' a1 = ILayoutAware(self.portal['f1']) a2 = ILayoutAware(self.portal['f1']['d1']) self.assertEqual(a1.site_layout(), a2.site_layout()) a1.pageSiteLayout = '/++sitelayout++testlayout2/mylayout.html' self.assertNotEqual(a1.site_layout(), a2.site_layout())
def render(self): context, request = self.context, self.request tile = getMultiAdapter((context, request), name=u'plone.deco_toolbar') tile_body = '' tree = html.fromstring(tile.index()) for el in tree.body.getchildren(): tile_body += html.tostring(el) if ILayoutAware.providedBy(self.context): return u'<div style="display:none;" ' + \ u'data-iframe="toolbar">%s</div>' % (tile_body) else: return u''
def getDefaultSiteLayout(context): """Get the path to the site layout to use by default for the given content object """ # Note: the sectionSiteLayout on context is for pages *under* context, not # necessarily context itself parent = aq_parent(aq_inner(context)) while parent is not None: layoutAware = ILayoutAware(parent, None) if layoutAware is not None: if getattr(layoutAware, 'sectionSiteLayout', None): return layoutAware.sectionSiteLayout parent = aq_parent(aq_inner(parent)) registry = queryUtility(IRegistry) if registry is None: return None return registry.get(DEFAULT_SITE_LAYOUT_REGISTRY_KEY)
def field_tiles(self, tree=None): if tree is None: layout = ILayoutAware(self).content tree = etree.HTML(layout) for tileNode in tileXPath(tree): tileId = tileNode.get('target', None) tileHref = tileNode.get('href', None) if tileHref is not None: if tileHref.startswith('./'): tileHref = tileHref[2:] try: tile = self.restrictedTraverse(tileHref) except Exception: logger.exception('Could not render tile %s' % tileHref) else: if IFieldTile.providedBy(tile): yield tileId, tile # remove the tile link from the head tileNode.getparent().remove(tileNode)
def layout(self): published = self.request.get('PUBLISHED') if isinstance(published, DefaultAddView): # Handle the special case of DX add form of layout aware context layout = None adapter = ILayoutAware(self.context, None) if adapter is not None: if getattr(adapter, 'sectionSiteLayout', None): layout = adapter.sectionSiteLayout if layout: layout = urljoin(self.context.absolute_url_path(), layout) layout = resolveResource(layout) if not layout: layout = getMultiAdapter((self.context, self.request), name='default-site-layout').index() else: layout = getMultiAdapter((self.context, self.request), name='page-site-layout').index() cooked = cook_layout(layout, self.request.get('ajax_load')) pt = ViewPageTemplateString(cooked) bound_pt = pt.__get__(self, type(self)) return bound_pt
def layoutFieldDefaultValue(context, request): if context and ILayoutAware(context, None): return getPortalTypeDefaultContentLayoutContent(context.portal_type) # XXX: Context cannot be used yet, because plone.dexterity does not # bound fields to support context aware default factories layout = absolute_path(CONTENT_LAYOUT_DEFAULT_LAYOUT) # XXX: This is a workaround for a subrequest bug, where parent_app # ends up being a view with publishTraverse returning always NotFound. try: parent_app = request.PARENTS[-1] if IWidgetsView.providedBy(parent_app): return u'' except AttributeError: pass except IndexError: pass try: return resolveResource(layout) except NotFound: return u''
def render(self): # Render fields by iterating over the form field tiles, rendering # each one, and replacing the tile with the result. layout = ILayoutAware(self.context).content layoutTree = getHTMLSerializer(layout, pretty_print=True, encoding='utf8') for tileId, tile in self.context.field_tiles(layoutTree.tree): # XXX need to include the full Plone view of the field widget = self.widgets[tile.id] widgetRenderer = getMultiAdapter((widget, self.request), name=u'ploneform-render-widget') widgetHtml = widgetRenderer() tileTree = html.fromstring(widgetHtml).getroottree() tileTarget = xpath1("//*[@id='%s']" % tileId, layoutTree.tree) if tileTarget is None: continue # clear children, but keep attributes oldAttrib = dict(tileTarget.attrib) tileTarget.clear() tileTarget.attrib.update(oldAttrib) # insert tile target with tile body tileBody = tileTree.find('body') if tileBody is not None: tileTarget.text = tileBody.text for tileBodyChild in tileBody: tileTarget.append(tileBodyChild) # TODO: # - create form tag # - fill in status message return str(layoutTree)
def tiles(site, req, tiles_data=_tiles_data): alsoProvides(req, ICastleLayer) # Sitewide slot tiles for meta_id, tiles in tiles_data.items(): meta_tile = MetaTile(site, req) alsoProvides(meta_tile, IGlobalTile) meta_tile.id = 'meta-' + meta_id meta_tile.__name__ = 'castle.cms.meta' meta_data_manager = ITileDataManager(meta_tile) meta_data = meta_data_manager.get() meta_tiles = [] for tile_data in tiles: meta_tiles.append(tile_data['meta']) tile = getMultiAdapter((site, req), name=tile_data['meta']['type']) alsoProvides(tile, IPersistentTile) tile.id = tile_data['meta']['id'] tile.__name__ = tile_data['meta']['type'] data_manager = ITileDataManager(tile) data_manager.set(tile_data['data']) meta_data['tiles'] = meta_tiles meta_data_manager.set(meta_data) frontpage = site['front-page'] adapted = ILayoutAware(frontpage, None) if adapted: adapted.pageSiteLayout = 'frontpage.html' # Tiles only for the front-page frontpage_tiles = getTileData() for tile in frontpage_tiles: fp_tile = getMultiAdapter((frontpage, req), name=tile['meta']['type']) meta = tile['meta'] fp_tile.id = meta['id'] alsoProvides(fp_tile, IPersistentTile) data_manager = ITileDataManager(fp_tile) data_manager.set(tile['data']) if 'slot' in tile: meta_tile = MetaTile(frontpage, req) alsoProvides(meta_tile, IGlobalTile) meta_tile.id = 'meta-' + tile['slot'] meta_tile.__name__ = 'castle.cms.meta' meta_data_manager = ITileDataManager(meta_tile) meta_data = meta_data_manager.get() existing_tiles = meta_data.get('tiles') or [] new_tile_id = tile['meta']['id'] if new_tile_id in [x['id'] for x in existing_tiles]: # check if the tile we're trying to install is already there. continue existing_tiles.append(meta) meta_data['tiles'] = existing_tiles meta_data['mode'] = 'show' meta_data_manager.set(meta_data) frontpageLayout = ILayoutAware(frontpage, None) if frontpageLayout: frontpageLayout.contentLayout = '/++contentlayout++castle/frontpage-layout.html' # noqa
def _getLayout(self): layout_adapter = ILayoutAware(self.context) if self.request.form.get('ajax_load'): return layout_adapter.ajax_site_layout() return layout_adapter.site_layout()
def post_creation(self, obj, pdb_if_exception=False, post_creation_data=None): if obj is None: return field_data = self.field_data bdata = ILayoutAware(obj, None) if bdata: try: bdata.contentLayout = self.layout except Exception: bdata.contentLayout = '++contentlayout++default/document.html' bdata = IRichText(obj, None) if bdata: try: bdata.text = RichTextValue(field_data['text'], 'text/html', 'text/html') except Exception: try: bdata.text = RichTextValue( field_data[ 'plone.app.contenttypes.behaviors.richtext.IRichText'] ['text'], # noqa 'text/html', 'text/html').raw except Exception: bdata.text = '' bdata = IBasic(obj, None) if bdata: try: bdata.title = field_data['title'] except Exception: try: bdata.title = field_data[ 'plone.app.content.interfaces.INameFromTitle']['title'] except Exception: bdata.description = field_data[dublin]['title'] try: bdata.description = field_data['description'] except Exception: try: bdata.description = field_data[dublin]['description'] except Exception: bdata.description = field_data[basic]['description'] else: try: obj.title = field_data['title'] obj.description = field_data['description'] except Exception: obj.title = field_data[dublin]['title'] obj.description = field_data[dublin]['description'] bdata = ICategorization(obj, None) if bdata: try: bdata.subjects = field_data['subject'] except Exception: try: bdata.subjects = self.field_data[dublin]['subjects'] except Exception: try: bdata.subjects = self.field_data[categorization][ 'subjects'] except Exception: pass # no keywords found bdata = IPublication(obj) try: if field_data['effectiveDate']: bdata.effective = pydt(field_data['effectiveDate']) except Exception: try: if field_data[dublin]['effective']: bdata.effective = pydt(field_data[dublin]['effective']) except Exception: try: if field_data[publication]['effective']: bdata.effective = pydt( field_data[publication]['effective']) except Exception: bdata.effective = None ldata = ILocation(obj, None) if ldata: if field_data.get('location'): ldata.locations = [field_data['location']] if field_data.get('newsLocation'): if ldata.locations: ldata.locations.append(field_data['newsLocation']) else: ldata.locations = [field_data['newsLocation']] try: obj.modification_date = field_data['modification_date'] except Exception: try: obj.modification_date = obj.modified() except Exception: obj.modification_date = None try: obj.creation_date = field_data['creation_date'] except Exception: try: obj.creation_date = obj.created() except Exception: obj.creation_date = None bdata = IDublinCore(obj, None) if bdata: if IDublinCore.__identifier__ in field_data: dublin_core = field_data[IDublinCore.__identifier__] bdata.expires = dublin_core['expires'] bdata.rights = dublin_core['rights'] bdata.creators = tuple(dublin_core['creators']) bdata.language = dublin_core['language'] bdata.effective = pydt(dublin_core['effective']) bdata.subjects = dublin_core['subjects'] bdata.contributors = tuple(dublin_core['contributors']) else: bdata.expires = pydt(field_data.get('expirationDate')) bdata.rights = field_data.get('rights') creators = field_data.get('creators') bdata.creators = tuple(creators) if creators else () language = field_data.get('language') bdata.language = language if language is not None else "" bdata.effective = pydt(field_data.get('effectiveDate')) bdata.subjects = field_data.get('subject') contributors = field_data.get('contributors') bdata.contributors = tuple(contributors) if contributors else ( ) bdata = ILayoutAware(obj, None) if bdata: if self.data['portal_type'] == 'Folder' and ( self.field_data.get('text') or '').strip(): bdata.content = FOLDER_DEFAULT_PAGE_LAYOUT % self.field_data[ 'text'] # need to explicitly reset contentLayout value because this data # could be overwritten bdata.contentLayout = None elif self.layout: if layoutaware in field_data and 'contentLayout' in field_data[ layoutaware]: bdata.contentLayout = field_data[layoutaware][ 'contentLayout'] if layoutaware in field_data and 'content' in field_data[ layoutaware]: bdata.content = field_data[ 'plone.app.blocks.layoutbehavior.ILayoutAware'][ 'content'] if 'rendered_layout' in self.data['data']: bdata.rendered_layout = self.data['data'][ 'rendered_layout'] inv_field_mapping = {v: k for k, v in self.fields_mapping.iteritems()} for IBehavior, field_name in self.behavior_data_mappers: original_field_name = inv_field_mapping.get(field_name, field_name) if original_field_name not in self.field_data: # data not here... continue behavior = IBehavior(obj, None) if behavior is None: # behavior not valid for obj type continue val = self.field_data[original_field_name] if field_name in self.data_converters: val = self.data_converters[field_name](val) setattr(behavior, field_name, val) # handle lead images for field_name in self.lead_image_field_names: if self.field_data.get(field_name): if field_name == 'plone.app.contenttypes.behaviors.leadimage.ILeadImage': im_obj = self.field_data.get(field_name)['image'] else: im_obj = self.field_data.get(field_name) if hasattr(im_obj, 'read'): im_data = im_obj.read() else: im_data = im_obj if not im_data: continue filename = self.field_data.get('image_filename') if not filename: if hasattr(im_obj, 'filename'): filename = im_obj.filename else: filename = self.field_data['id'] obj.image = im_data if not isinstance(obj.image, NamedBlobImage): is_stringio = isinstance(im_obj, StringIO) if is_stringio: namedblobimage_data = im_data elif isinstance(im_obj, Image): namedblobimage_data = im_data.data else: if pdb_if_exception: pdb.set_trace() logger.info(" lead image is type %s" % type(im_obj)) obj.image = NamedBlobImage(data=namedblobimage_data, contentType='', filename=filename) if hasattr(obj.image, 'contentType') and isinstance( obj.image.contentType, unicode): obj.image.contentType = obj.image.contentType.encode( 'ascii') else: if isinstance(im_obj, Image): data = im_obj.data elif hasattr(im_obj, 'buf'): data = im_obj.buf elif hasattr(im_obj, '_blob'): if hasattr(im_obj._blob, '_p_blob_uncommitted'): f = open(im_obj._blob._p_blob_uncommitted, 'r') data = f.read() f.close() else: raise Exception( "no _p_blob_uncommitted attr in im_obj._blob") else: raise Exception("no _blob attr in im_obj") if data == '' or data is None: data = base64.b64decode( 'R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' ) image_type = what('', h=data) if image_type in [ 'png', 'bmp', 'jpeg', 'xbm', 'tiff', 'gif' ]: obj.image.contentType = 'image/%s' % image_type elif image_type == 'rast': obj.image.contentType = 'image/cmu-raster' elif image_type == 'ppm': obj.image.contentType = 'image/x-portable-pixmap' elif image_type == 'pgm': obj.image.contentType = 'image/x-portable-greymap' elif image_type == 'pbm': obj.image.contentType = 'image/x-portable-bitmap' elif image_type == 'rgb': obj.image.contentType = 'image/x-rgb' else: # look at filename extension contentType, encoding = guess_type(obj.image.filename, strict=False) if contentType: obj.image.contentType = contentType else: logger.info( "Unknown image type {};" " defaulting to jpeg".format(image_type)) pdb.set_trace() obj.image.contentType = 'image/jpeg' # default for caption_field_name in self.lead_image_caption_field_names: if caption_field_name in self.field_data: obj.imageCaption = self.field_data.get( caption_field_name)
def has_layout(self): return ILayoutAware.providedBy(self.context)