I am trying to make a page template for my dexterity product using summary_view as a starting point. However customising summary view or coping the body of summary view into my type's template yeilds:
Macro expansion failed
<type 'exceptions.KeyError'>: 'standard_view'
Is there a problem with this path, or do I have to do something else to make this template available:
<metal:block use-macro="context/standard_view/macros/content-core">
You have to add a macros method to your BrowserView.
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
class MyView(BrowserView):
template = ViewPageTemplateFile('my-template.pt')
#property
def macros(self):
self.template.macros
Related
It seems that when I use the portal_factory tool for creating an instance of a type it disregards the view I've specified to override base_edit.
Here's what I've got setup:
Alias from edit to base_edit in the types tool.
View class that renders the view.
ZCML that that hooks on the view class to the appropriate interface.
Content class that implements the appropriate interface.
I know my overridden base_edit view works because it renders:
Once the object has been created it renders.
When I disable the portal_factory tool for the type.
When I use another name like custom_edit it also renders the overridden view, despite the type being enabled in the portal_factory tool.
Changing the alias to ##base_edit works too.
this way zope traversing makes an adapter lookup instead of attribute access and your edit view will be used.
afaik the ## forces an adapter lookup, without ## the first object thru acquisition is called and then an adapter
cc #juriejan
You don't need to customized the base_edit.cpt, you simply need to create a new CMF skin template called yourtypenamenormalized_edit.pt, where "yourtypenamenormalized" is your portal_type name lowercase and without spaces.
The original Archetype base_edit.cpt will look for a template called this way before applying all default macros.
After that I suggest you to fill this new template with all the code you'll find inside the default template, that is edit_macro.pt, then start to apply your changes.
Commonly the only macro you'll want to override is the body macro.
My question is quite simple....
In Plone 4 (4.2) what I need to setup to make a default view, for example a simple page, to be shown in the navigation tree.
The navigation tree uses the INavigationQueryBuilder component to find all elements shown. The default implementation filters out anything used as a default page.
You'll have to provide your own implementation instead; but you can re-use the original implementation. All you have to do is alter the generated query a little; normally, if no more specific query is present, the is_default_page index is used to filter out default pages. But if your altered query adds a search for that index, then it'll not try to add a more specific filter. Setting it to search for (True, False) means it'll return both default and non-default pages, effectively neutralizing the filter.
The implementation then becomes:
from plone.app.portlets.portlets.navigation import QueryBuilder, INavigationPortlet
from zope.component import adapts
from zope.interface import implements, Interface
class INonDefaultPageFilteringNavigationPortlet(INavigationPortlet):
pass
class DontFilterDefaultQueryBuilder(QueryBuilder):
implements(INavigationQueryBuilder)
adapts(Interface, INavigationPortlet)
def __init__(self, context, portlet):
super(DontFilterDefaultQueryBuilder, self).__init__(context, portlet)
self.query['is_default_page'] = (True, False) # Don't filter out default pages
You'll have to register this as an adapter, and add the INonDefaultPageFilteringNavigationPortlet to your portlet to 'activate' this builder:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:five="http://namespaces.zope.org/five">
<adapter factory=".yourmodule.DontFilterDefaultQueryBuilder" />
<five:implements
class="plone.app.portlets.portlets.navigation.Assignment"
interface=".yourmodule.INonDefaultPageFilteringNavigationPortlet" />
</configure>
All with the caveat that this is untested, but it should work.
You might also create a link in the folder, set destination to './idOfPage1' and set the link as defaultview of the folder.
Users without editing-rights will be redirected to Page1 then and the page itself will be shown in the navportlet.
We have object which is let say xyz and its view is xyz_view which dexerity expect page template file. Is there any way to override default page type to controller page template rather?
So view should be xyz_view.cpt rather then xyz_view.pt ?
Regards,
There is no realistic scenario for using controller page templates for dexterity forms. There is also no scenario that I can think of where it would be easier than using z3c.form.
Include a form that submits to itself inside your view template and use the 'update()' method to process the request and redirect on some condition:
class View(grok.View):
grok.context(IMyType)
grok.requires('zope2.View')
def update():
if 'form.button.Submit' in self.request:
input_value = self.request.get('input_value', None)
if input_value is not None:
self.request.response.redirect(self.context.absolute_url() + "##process-this")
See the five.grok manual instructions about simple views for more information
NOTE
Due to the successful outcome of this thread, the documentation at the provided link has been updated. It no longer contains the incomplete information as described.
I'm having an issue taking viewlets that appear in the plone.portalheader viewletManager and adding them to specific locations (not utilizing the linear concatenation). My goal is to make the html code look identical to my html template mockup. I do not want nor require the viewlets to change positions and I would like to see a couple of those elements wind up in the same overarching markup.
I have been reading the following documentation, but it seems to be in conflict with my set up (which is Plone 4.1):
http://collective-docs.readthedocs.org/en/latest/views/viewlets.html#rendering-viewlets-with-accurate-layout
I'm not sure if that particular page is outdated or incorrect (it looks like most references to "tab" were replaced with spaces. eg, <table> is now < le>) or if I'm doing something wrong (which I wouldn't put it past me).
It looks like when I want to call the new header created from the example, citing something.header fails inside my portal_header.pt file. If someone can eyeball the example and let me know if there are any important parts missing, that would be a huge help to me.
Including my code:
theme/browser/configure.zcml (portion):
<!-- The portal header -->
<browser:viewlet
name="plone.header"
manager="plone.app.layout.viewlets.interfaces.IPortalTop"
layer=".interfaces.IThemeSpecific"
class=".header.HeaderViewlet"
template="templates/portal_header.pt"
permission="zope2.View"
/>
theme/browser/templates/portal_header.pt:
<header>
<div class="container_12">
<div tal:replace="structure provider:theme.header" />
</div>
</header>
theme/browser/header.py:
from Acquisition import aq_inner
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from plone.app.layout.viewlets import common as base
#import plonetheme.something.browser.viewlets.common as something #left over from original article
def render_viewlet(factory, context, request):
context = aq_inner(context)
viewlet = factory(context, request, None, None).__of__(context)
viewlet.update()
return viewlet.render()
class HeaderViewlet(base.ViewletBase):
index = ViewPageTemplateFile('header_items.pt')
def update(self):
base.ViewletBase.update(self)
self.subviewlets = {}
def renderViewlet(self, viewlet_class):
return render_viewlet(viewlet_class, self.context, self.request)
def render(self):
self.subviewlets["logo"] = self.renderViewlet(base.LogoViewlet)
self.subviewlets["search"] = self.renderViewlet(base.SearchBoxViewlet)
return self.index()
theme/browser/header_items.pt:
<header>
<div class="container_12">
<div tal:replace="structure view/subviewlets/logo" />
<div tal:replace="structure view/subviewlets/search" />
</div>
</header
That's all I have modified per the article I listed above. I'm unsure if I should modify viewlets.xml.
From what I understand of the article, it wants to override and replace the plone.portalheader in portal_header.pt with theme.header by utilizing the class provided in header.py. However, I'm not modifying viewlets.xml which is where I believe the problem lies. Or it could like with the fact that I'm replacing plone.portalheader with theme.header and I'm not changing the name of the viewlet in configure.zcml from plone.header to theme.header.
I've tried a whole bunch of permutations on what I believe to be the solution and I can't get anything to work, even trying to modify viewlets.xml.
When I follow the example I get an error message that says:
ContentProviderLookupError(u'theme.header',)
TAL provider: expression will only render portlet managers or viewlet managers. It does not work with viewlets. That's why there is render_viewlet(factory, context, request) shortcut in the example.
What you want to is to
create a viewlet which contains all of your layout (done, HeaderViewlet)
place this viewlet in good known viewlet manager (use /##manage-viewlet to figure out which) - this is not done
then in this new viewlet render subviewlets as you do
If you need to create a new viewlet manager (ugh, pain in the ass and shitty job) you can follow instructions here:
http://opensourcehacker.com/2011/11/29/creating-a-viewlet-manager-in-plone/
I'm using Plone 4.0.5, and I've spent the day trying to understand plone.app.contentmenu.
I have a custom folder based archetypes type, and I've written a view for it. When using the default base_view (site/MyObject/base_view), everything works as expected. Using my own custom view though, the menus start disappearing, and I haven't been able to figure it out.
First, my zcml,
<browser:page
for="my.product.interfaces.IMyType"
name="view"
class="my.product.browser.mytype.MyTypeViewView"
permission="zope.Public"
/>
The view itself is as simple as possible:
class MyTypeViewView(BrowserView):
template = ViewPageTemplateFile("templates/mytype_view.pt")
def __call__(self):
return self.template()
And the view template has also been slimmed down to nothing:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
lang="en"
metal:use-macro="context/main_template/macros/master"
i18n:domain="plone">
<body>
<metal:content-core fill-slot="content-core">
hi there.
</metal:content-core>
</body>
</html>
If I access site/MyObject/view, the template shows "hi there", but plone-contentmenu-actions and plone-contentmenu-workflow disappear. plone-contentmenu-factories however, remains. if I then modify the ZCML to set name="view_test", and visit site/MyObject/view_test, none of the menus at all display.
I have five different views for this type, and I want the workflow menu to display on all of them (or at the very least, my main view, so that I can test more easily until I figure it out).
If I rename my view to base_view and visit the object URL directly, I still don't have a workflow menu available.
I guess my question should be:
What exactly are the rules plone works with to decide which menus to display, and when? What code should I be reading?
-- edit:
I've added this function to my View:
def __init__(self, context, request):
super(MyTypeViewView, self).__init__(context, request)
alsoProvides(self, IViewView)
alsoProvides(self.context, IViewView)
if I place a breakpoint in my call code, I get this:
>>> IViewView.providedBy(self)
True
>>> IViewView.providedBy(self.context)
True
I'm pretty sure I only needed to apply IViewView to the view itself, but regardless, this doesn't change anything for me.
Plone applied the IViewView marker interface to the view which are canonical for an object - the one you get clicking the view tab. Certain parts of the interface are restricted to that interface - see the section "Restricting a viewlet to the canonical view" in http://plone.org/products/dexterity/documentation/manual/five.grok/browser-components/viewlets
Since you already have a view Class (MyTypeViewView) for your page it's more straight-forward to make it implement the interface instead of make instances of it provide it:
from plone.app.layout.globals.interfaces import IViewView
class MyTypeViewView(BrowserView):
interface.implements(IViewView)
...
Although I think that this won't solve your problem since I do have lots of custom views that do not implement IViewView but display all actions nicely.
I guess you simply need to add your views to the available default views for your type in portal_types tool and you're fine.