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.
Related
I have a browser view my_custom_display, that can be selected for folders using the menu: Display -> my_custom_display.
The problem appears after I select the custom display and I'm trying to create new objects inside the folder with this custom display.
By default all new items seems to have my_custom_display and my solution is to manually fix it with /selectViewTemplate?templateId=folder_listing.
What is the better solution for this situations? (Set a display only for the item itself not any new child inside it.)
(It's annoying because my browser view generates errors if used in wrong place. Yes, I can improve it, but...)
Update:
In /portal_types/Folder/manage_propertiesForm I added my_custom_display in Available view methods. I need it only for specific folders.
Solved by forcing layout setting on folder creation:
<subscriber
for="Products.ATContentTypes.interfaces.IATFolder
Products.Archetypes.event.ObjectInitializedEvent"
handler="my.package.globalhandlers.set_folder_listing_by_default" />
added in configure.cfg.
Then:
def set_folder_listing_by_default(folder, event):
""" Set folder_listing as default Display for new created folders.
"""
folder.setLayout('folder_listing')
Seems not nice, but it solved my issue. :)
I have a Grid, which have a TopToolbar and BottomToolbar. In the BottomToolbar, I added a CSVDataExporter:
CSVDataExporter csvDataExporter = new CSVDataExporter();
csvDataExporter.setDataFormatNameModel(new ResourceModel("csv.export.link.name"));
csvDataExporter.setDelimiter('|');
addBottomToolbar(new ExportToolbar(this).addDataExporter(csvDataExporter));
I have the link, so I can export the table to CSV fine!
BUT! How could I change the CSV export link to be a Button, but do the same and be at the same place as it was? Thank you!
The Link is generated by your ExportToolbar using the createExportLink method. To generate something else (as in any other component) you can extend the ExportToolbar to override this method. If this is the only place where you need this functionality, you can do so by implementing an anonymous inner class.
Generally you'll want this method to return a Component that has it's own markup, like a Panel, that contains whatever you want to display as your Exportlink or -button.
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.
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.
Are there any way to declare a child component in mxml which is private/protected or even static?
Sure we can do this inside a script tag, but are there any other way?
Ashier suggests using the "Exclude" metadata tag, but Maskit offers its limitations and suggests alternative solutions:
http://blog.ashier.com/2008/03/25/hiding-properties-in-flex-components/
http://smaskit.blogspot.com/2008/07/making-mxml-subcomponent-private.html
In the strict meaning of these terms, no you can't do that using mxml. The second link posted by Luis contains some workarounds for private/protected behavior.
I found a solution to the static question. I wanted a quick memo pad that could be accessed anywhere in the mobile app, without one instance overwriting edits left open in a different screen.
I created a memo pad mxml control, and then placed it inside a declarations section in the top level application mxml. In each view that I wanted the memo to appear in, I added:
import mx.core.FlexGlobals;
import components.QuickMemo;
private var memo:QuickMemo;
In the view creation complete:
memo = FlexGlobals.topLevelApplication.memo;
In the viewActivation code, I added:
memo.visible = false;
addElement(memo);
In the viewDeactivation code, I included:
removeElement(memo);
The net effect is that only one instance of the memo exists at any time, and that one instance opens in whatever state it existed in the last view it appeared in.