I'm trying to get viewlet belowcontenttitle for an object by its URL.
Something like below, but using object URL instead of 'plone'.
id="viewlet-below-content-title" tal:content="structure provider:plone.belowcontenttitle"
Can I do it using restrictedTraverse?
Your best bet is to create a new view for the belowcontenttitle viewlet; template:
<div tal:content="structure provider:plone.belowcontenttitle"/>
registered with:
<browser:page
for="*"
name="belowcontenttitle"
permission="zope2.View"
template="template_shown_above.pt"
/>
Then you can use that view with a simple traverse:
<div tal:replace="structure context/path/to/other/object/##belowcontenttitle" />
This looks up the view in the context of the other object; the template is rendered and returned, replacing the div.
Related
If a view is registered like this, with the template definition in zcml:
<browser:page
name="original-view"
class=".original_view.View"
permission="zope2.View"
for="*"
template="original_template.pt"
/>
and i want to customize only his class in my product, is there a way to do it without customizing also the template?
You have to wrap the browser:page by <configure package='XXXX'>
That means your then in scope of this packge.
Example:
<configure package="original.package.browser">
<!-- custom view -->
<browser:page
name="original-view"
class="your.package.browser.View" <!-- Full dotted name to you custom view class -->
permission="zope2.View"
for="*"
layer="your.package.interfaces.IYourPackageLayer" <!-- You should provide a browserlayer, otherwise you got a configuration conflict -->
template="original_template.pt" <!-- template from original.package.browser -->
/>
</configure>
EDIT:
As #sdupton mentioned, I updated the example code snipped with a layer
If you can't use a layer (BrowserLayer) you can put the code, without layer attribute into a overrides.zcml
You can also specify a more precise Interface in the for attribute
How do I call a method which is in the filesystem from a TAL Portlet (made available by collective.portlet.tal)?
This is how I did it: I defined a new BrowserView (createPictMenu.py in my case) and then registered it as the renderer for a new portlet component:
class AddressTAL(BrowserView)
def my_address()
address_bar = ViewTemplatePageFile('templates/address_left.pt') # this
is the page template I want for my new portlet.
And in configure.zcml:
<plone:portlet
name="collective.portlet.tal.TALPortlet"
interface="collective.portlet.tal.talportlet.ITALPortlet"
assignment="collective.portlet.tal.talportlet.Assignment"
view_permission="zope2.View"
edit_permission="cmf.ManagePortal"
renderer=".browser.createPictMenu.AddressTAL"
addview="collective.portlet.tal.talportlet.AddForm"
editview="collective.portlet.tal.talportlet.EditForm"
/>
Then I went to localhost:8080/myproject/##manage-portlets and selected the TAL Portlet option from the Add Portlet dropdown list. I informed title as address and for description I inserted the snippet below to call address_tal():
<span tal:define="global li view/myaddress">
<span tal:replace="structure li" />
</span>
Unfortunately, it didn't work. Please help.
You should have registered your class AddressTAL with a browser:view directive, not a plone:portlet one. Like this:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
name="address-view"
class=".browser.createPictMenu.AddressTAL"
for="*"
permission="zope2.View"
/>
</configure>
And then call it with:
<div tal:define="my_address python:context.restrictedTraverse('##address-view').my_address()" >
Your method returns <span tal:content="my_address" />
</div>
Or:
<div tal:define="address_view context/##address-view" >
Your method returns <span tal:content="address_view/my_address" />
</div>
It's of very little information or matter that the method is on the file system. That's where it should be. Having it in the ZODB is possible but a bad idea.
But there are many types of methods, and how you call them from TAL differs.
You can have what in the ZMI is called "Script (Python) methods" that are accessed through portal_skins, you can have methods on content objects and you can have methods on views. These are all callable from TAL.
For methods that are neither of these, you will have to create a method of the above type that you can call, which in turn then calls the method you want to call. For a portlet the obvious place to create that method is by adding a method on the Renderer, which is a type of view, and which you can call from the portlets template.
In your case, the method you want to call is a method on the renderer already. That means you just call it.
<p tal:content="view/myaddress" />
Note that you have forgotten the self parameter in the definition. Also, please follow PEP8.
Is it possible to render Razor in Html.Raw()? I have a dynamic page being generated that uses the Html.Raw() method to render the page that is created in the controller. Inside this page I have an image tag that should retrieve the image via Url.Action.
var image = string.Format("<img src=\"#Url.Action(\"GetImage\", \"ImageUtility\")?id={0}\" alt=\"{1}\" />", Image.ImageId, Image.Name);
As you can see this would render the following without the razor being rendered:
<img src="#Url.Action("GetImage", "ImageUtility")?id=10000" alt="Image Name" />
Try wrapping Url.Action with parenthesis.
See this answer and #Igor's comment related to.
Once again back with a Plone question.
I have Plone 4 installed and I need to show the Document action icons at the top instead of bottom. having trouble in getting this to work. can someone help.
If you just need to move that viewlet (with same class and template), first you have to register a viewlet with same class to your desired viewletmanager (let's say for ex. plone.app.layout.viewlets.interfaces.IAboveContentBody):
<browser:viewlet
name="plone.abovecontenttitle.documentactions"
manager="plone.app.layout.viewlets.interfaces.IAboveContentBody"
class="plone.app.layout.viewlets.content.DocumentActionsViewlet"
permission="zope2.View"
/>
and then add this in your genericsetup profile (file viewlets.xml) :
<?xml version="1.0"?>
<object>
<order manager="plone.abovecontentbody" skinname="Plone Default">
<!-- this will place your viewlet before all the others.
you can also use a viewlet's name for a relative position -->
<viewlet name="plone.abovecontenttitle.documentactions" insert-before="*"/>
</order>
<hidden manager="plone.belowcontentbody" skinname="Plone Default">
<viewlet name="plone.abovecontenttitle.documentactions"/>
</hidden>
</object>
More info:
http://plone.org/documentation/kb/customization-for-developers/viewlets
http://collective-docs.readthedocs.org/en/latest/views/viewlets.html
How can I write the freemarker templates like this:
<#import "spring.ftl" as s>
<#s.form path="object" action="/new.do" method="POST">
<#s.formInput "name"/> <!-- I want this resolved as "object.name" -->
<!--
100s of other properties...
-->
</#s.form>
instead of this:
<#import "spring.ftl" as s>
<form action="/new.do" method="POST">
<#s.formInput "object.name"/>
<!--
100s of other properties...
-->
</form>
You can bind the object like this:
<#s.bind "object"/>
Then you can use your first example
<#s.formInput "name"/>
As far as I can tell, spring.ftl doesn't support nested paths. It is conceivable that one could write one's own nestedPath macro that functioned similar to the nestedPath JSP tag. You'd probably need a bind macro that recognized it as well, and maybe more to get all the form input macros working.
Or, maybe it's possible to import and use the JSP tags themselves instead of spring.ftl or custom macros.