Using external method in TAL page template

classic Classic list List threaded Threaded
4 messages Options
rbruch rbruch
Reply | Threaded
Open this post in threaded view
|

Using external method in TAL page template

Hi all,

I've got what I hope will be an easy question to answer.

In a Plone 4.2.7 site (using Archetypes), I'm trying to extend the
Related Items viewlet to show images for the items it displays. I've
successfully registered a custom viewlet class in my old-style theme's
browser/configure.zcml.

     <!-- Customized relateditems viewlet registration -->
     <browser:viewlet
         name="plone.belowcontentbody.relateditems"
         manager="plone.app.layout.viewlets.interfaces.IBelowContentBody"
         class=".viewlets.ContentRelatedItems"
         permission="zope2.View"
         layer=".interfaces.IThemeSpecific"
         />

I've also successfully written a method in my theme's viewlets.py that
uses lxml to parse content items' body HTML for images and returns a
path to the first image.

<!-- Excerpt from viewlets.py -->
class ContentRelatedItems(content.ContentRelatedItems):
     render = ViewPageTemplateFile('templates/document_relateditems.pt')

     def my_get_image(self):
         context = aq_inner(self.context)
         text = context.getText()
         tree = html.fromstring(text)
         imgs = tree.xpath('//img')
         if imgs:
             my_img = imgs[0]
             my_img_path = my_img.attrib['src']
             return my_img_path
         return None

Now we come to the question. The way the viewlet works is that the
ContentRelatedItems class has a method, "related_items" that returns a
list of brains to the template, document_relateditems.pt. The template
uses TAL to loop through the brains and render various fields from the
brains.

I'm trying to stick my method into the TAL loop to return an image path
for each item that's returned by related_items. (This excerpt is kind of
long but I wanted to show the context in the template for reference.)

<!-- Excerpt of document_relateditems.pt -->
<div class="relatedItems"
      tal:define="related view/related_items"
      tal:condition="related">
     <dl id="relatedItemBox"
               tal:define="ploneview nocall:context/@@plone;
                           normalizeString nocall:ploneview/normalizeString;
                           tools nocall:context/@@plone_tools;
                           wf_tool tools/workflow;
                           getInfoFor python:wf_tool.getInfoFor;
                           site_properties
context/portal_properties/site_properties;
                           use_view_action
site_properties/typesUseViewActionInListings|python:();">
         <dt i18n:translate="label_related_items">Related content</dt>
         <tal:related repeat="item related">
             <dd tal:define="
          [ TRYING TO ADD REFERENCE TO METHOD IN HERE ]
                     desc                item/Description;
                     item_icon           python:ploneview.getIcon(item);
                     item_type           item/portal_type;
                     item_type_class     python:'contenttype-' +
normalizeString(item_type);
                     item_wf_state       item/review_state|python:
getInfoFor(item, 'review_state', '');
                     item_wf_state_class python: 'state-' +
normalizeString(item_wf_state);
                     item_url            item/getURL|item/absolute_url;
                     item_url            python:(item_type in
use_view_action) and item_url+'/view' or item_url">
[ Some output ]
             </dd>


I've tried a few different things in the tal:define part of the <dd>
element:

image_path item/my_get_image (item has no attribute my_get_image)
image_path my_get_image() (my_get_image is undefined)
image_path view/my_get_image (returns image path from the "host" item
not the related item)

I'm sure I'm just missing something trivial. I did find this:

Helper views and tools
https://developer.plone.org/misc/context.html

But I wasn't sure if I needed to pull out the method into its own
structure since it's already in my custom viewlets.py.

Thanks for any help! Let me know if I should provide more of my code or
information.

Full original files for reference:
Class
https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/content.py#L112
Template
https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/document_relateditems.pt

-Rick

--
Rick Bruch, Web Computing Specialist
Northwest Center for Public Health Practice
University of Washington School of Public Health
Phone: 206.543.3696
1107 NE 45th Street, Suite 400
Seattle, WA 98105


------------------------------------------------------------------------------
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
_______________________________________________
Plone-Users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-users
khink khink
Reply | Threaded
Open this post in threaded view
|

Re: Using external method in TAL page template

You want view/my_get_image. Use pdb to find why it doesn't do what you want.

On 04/24/2014 09:23 PM, Rick Bruch wrote:

> Hi all,
>
> I've got what I hope will be an easy question to answer.
>
> In a Plone 4.2.7 site (using Archetypes), I'm trying to extend the
> Related Items viewlet to show images for the items it displays. I've
> successfully registered a custom viewlet class in my old-style theme's
> browser/configure.zcml.
>
>       <!-- Customized relateditems viewlet registration -->
>       <browser:viewlet
>           name="plone.belowcontentbody.relateditems"
>           manager="plone.app.layout.viewlets.interfaces.IBelowContentBody"
>           class=".viewlets.ContentRelatedItems"
>           permission="zope2.View"
>           layer=".interfaces.IThemeSpecific"
>           />
>
> I've also successfully written a method in my theme's viewlets.py that
> uses lxml to parse content items' body HTML for images and returns a
> path to the first image.
>
> <!-- Excerpt from viewlets.py -->
> class ContentRelatedItems(content.ContentRelatedItems):
>       render = ViewPageTemplateFile('templates/document_relateditems.pt')
>
>       def my_get_image(self):
>           context = aq_inner(self.context)
>           text = context.getText()
>           tree = html.fromstring(text)
>           imgs = tree.xpath('//img')
>           if imgs:
>               my_img = imgs[0]
>               my_img_path = my_img.attrib['src']
>               return my_img_path
>           return None
>
> Now we come to the question. The way the viewlet works is that the
> ContentRelatedItems class has a method, "related_items" that returns a
> list of brains to the template, document_relateditems.pt. The template
> uses TAL to loop through the brains and render various fields from the
> brains.
>
> I'm trying to stick my method into the TAL loop to return an image path
> for each item that's returned by related_items. (This excerpt is kind of
> long but I wanted to show the context in the template for reference.)
>
> <!-- Excerpt of document_relateditems.pt -->
> <div class="relatedItems"
>        tal:define="related view/related_items"
>        tal:condition="related">
>       <dl id="relatedItemBox"
>                 tal:define="ploneview nocall:context/@@plone;
>                             normalizeString nocall:ploneview/normalizeString;
>                             tools nocall:context/@@plone_tools;
>                             wf_tool tools/workflow;
>                             getInfoFor python:wf_tool.getInfoFor;
>                             site_properties
> context/portal_properties/site_properties;
>                             use_view_action
> site_properties/typesUseViewActionInListings|python:();">
>           <dt i18n:translate="label_related_items">Related content</dt>
>           <tal:related repeat="item related">
>               <dd tal:define="
>            [ TRYING TO ADD REFERENCE TO METHOD IN HERE ]
>                       desc                item/Description;
>                       item_icon           python:ploneview.getIcon(item);
>                       item_type           item/portal_type;
>                       item_type_class     python:'contenttype-' +
> normalizeString(item_type);
>                       item_wf_state       item/review_state|python:
> getInfoFor(item, 'review_state', '');
>                       item_wf_state_class python: 'state-' +
> normalizeString(item_wf_state);
>                       item_url            item/getURL|item/absolute_url;
>                       item_url            python:(item_type in
> use_view_action) and item_url+'/view' or item_url">
> [ Some output ]
>               </dd>
>
>
> I've tried a few different things in the tal:define part of the <dd>
> element:
>
> image_path item/my_get_image (item has no attribute my_get_image)
> image_path my_get_image() (my_get_image is undefined)
> image_path view/my_get_image (returns image path from the "host" item
> not the related item)
>
> I'm sure I'm just missing something trivial. I did find this:
>
> Helper views and tools
> https://developer.plone.org/misc/context.html
>
> But I wasn't sure if I needed to pull out the method into its own
> structure since it's already in my custom viewlets.py.
>
> Thanks for any help! Let me know if I should provide more of my code or
> information.
>
> Full original files for reference:
> Class
> https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/content.py#L112
> Template
> https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/document_relateditems.pt
>
> -Rick
>



------------------------------------------------------------------------------
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
_______________________________________________
Plone-Users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-users
Daniel Jowett Daniel Jowett
Reply | Threaded
Open this post in threaded view
|

Re: Using external method in TAL page template

In reply to this post by rbruch
Hi Rick,

   your immediate problem is the context in my_get_image() is your "host"
object as you call it.  Perhaps you can change that method to:
i)  accept a brain as parameter
ii) call getObject() to get the related object
iii) Do your lxml magic on that.
In which case
image_path python: view.my_get_image(item)
in the template is what you want.

whether that works or not is left as an exercise for the reader ;-)
However, this does mean loading all the related items as objects, which (for Archetypes) isn't that effecient

If I was doing that from scratch I would try a different approach:
add a new index for the relevant types called "first_image_url" using elements of your method (see
https://developer.plone.org/searching_and_indexing/indexing.html#adding-index-using-add-on-product-installer
And especially https://pypi.python.org/pypi/plone.indexer)
Then:

 image_path item/first_image_url

should work in the template once you've Reindexed everything.

But that's a much longer way round.

HTH

Daniel

On 24/04/14 20:23, Rick Bruch wrote:
Hi all,

I've got what I hope will be an easy question to answer.

In a Plone 4.2.7 site (using Archetypes), I'm trying to extend the 
Related Items viewlet to show images for the items it displays. I've 
successfully registered a custom viewlet class in my old-style theme's 
browser/configure.zcml.

     <!-- Customized relateditems viewlet registration -->
     <browser:viewlet
         name="plone.belowcontentbody.relateditems"
         manager="plone.app.layout.viewlets.interfaces.IBelowContentBody"
         class=".viewlets.ContentRelatedItems"
         permission="zope2.View"
         layer=".interfaces.IThemeSpecific"
         />

I've also successfully written a method in my theme's viewlets.py that 
uses lxml to parse content items' body HTML for images and returns a 
path to the first image.

<!-- Excerpt from viewlets.py -->
class ContentRelatedItems(content.ContentRelatedItems):
     render = ViewPageTemplateFile('templates/document_relateditems.pt')

     def my_get_image(self):
         context = aq_inner(self.context)
         text = context.getText()
         tree = html.fromstring(text)
         imgs = tree.xpath('//img')
         if imgs:
             my_img = imgs[0]
             my_img_path = my_img.attrib['src']
             return my_img_path
         return None

Now we come to the question. The way the viewlet works is that the 
ContentRelatedItems class has a method, "related_items" that returns a 
list of brains to the template, document_relateditems.pt. The template 
uses TAL to loop through the brains and render various fields from the 
brains.

I'm trying to stick my method into the TAL loop to return an image path 
for each item that's returned by related_items. (This excerpt is kind of 
long but I wanted to show the context in the template for reference.)

<!-- Excerpt of document_relateditems.pt -->
<div class="relatedItems"
      tal:define="related view/related_items"
      tal:condition="related">
     <dl id="relatedItemBox"
               tal:define=[hidden email]>
         <dt i18n:translate="label_related_items">Related content</dt>
         <tal:related repeat="item related">
             <dd tal:define="
          [ TRYING TO ADD REFERENCE TO METHOD IN HERE ]
                     desc                item/Description;
                     item_icon           python:ploneview.getIcon(item);
                     item_type           item/portal_type;
                     item_type_class     python:'contenttype-' + 
normalizeString(item_type);
                     item_wf_state       item/review_state|python: 
getInfoFor(item, 'review_state', '');
                     item_wf_state_class python: 'state-' + 
normalizeString(item_wf_state);
                     item_url            item/getURL|item/absolute_url;
                     item_url            python:(item_type in 
use_view_action) and item_url+'/view' or item_url">
[ Some output ]
             </dd>


I've tried a few different things in the tal:define part of the <dd> 
element:

image_path item/my_get_image (item has no attribute my_get_image)
image_path my_get_image() (my_get_image is undefined)
image_path view/my_get_image (returns image path from the "host" item 
not the related item)

I'm sure I'm just missing something trivial. I did find this:

Helper views and tools
https://developer.plone.org/misc/context.html

But I wasn't sure if I needed to pull out the method into its own 
structure since it's already in my custom viewlets.py.

Thanks for any help! Let me know if I should provide more of my code or 
information.

Full original files for reference:
Class
https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/content.py#L112
Template
https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/document_relateditems.pt

-Rick


--
Daniel Jowett

Jowett Enterprises Ltd
Tel: 0333 3 553 773
Mobile: 07870 667 126
[hidden email]
www.jowettenterprises.com

------------------------------------------------------------------------------
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
_______________________________________________
Plone-Users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-users
rbruch rbruch
Reply | Threaded
Open this post in threaded view
|

Re: Using external method in TAL page template

Thanks Daniel,

I ended up going with your first suggestion. For now I'm not worrying
about the performance hit of getObject() because we're limiting the
display of related items to 3. Also so far testing hasn't shown any
noticeable slowdown at least on our dev server.

I opted not to go with your second idea since I was so far down the road
with the first approach, but it looks solid for when/if we need
something that will work more generally throughout the site.

For reference, here is my revised method:

     def my_get_image(self, brain):
         object = brain.getObject()
         text = object.getText()
         tree = html.fromstring(text)
         imgs = tree.xpath('//img')
         if imgs:
             my_img = imgs[0]
             my_img_path = my_img.attrib['src']
             return my_img_path
         return None

And in the template:

     <div tal:define="image_path python: view.my_get_image(item)"
          etc...
          <img tal:attributes="src string:$image_path;
               etc...


Thanks again for the tips!

-Rick


Daniel Jowett wrote:

> Hi Rick,
>
>     your immediate problem is the context in my_get_image() is your "host"
> object as you call it.  Perhaps you can change that method to:
> i)  accept a brain as parameter
> ii) call getObject() to get the related object
> iii) Do your lxml magic on that.
> In which case
>
> image_path python: view.my_get_image(item)
>
> in the template is what you want.
>
> whether that works or not is left as an exercise for the reader ;-)
> However, this does mean loading all the related items as objects, which
> (for Archetypes) isn't that effecient
>
> If I was doing that from scratch I would try a different approach:
> add a new index for the relevant types called "first_image_url" using
> elements of your method (see
> https://developer.plone.org/searching_and_indexing/indexing.html#adding-index-using-add-on-product-installer
> And especially https://pypi.python.org/pypi/plone.indexer)
> Then:
>
>   image_path item/first_image_url
>
> should work in the template once you've Reindexed everything.
>
> But that's a much longer way round.
>
> HTH
>
> Daniel
>
> On 24/04/14 20:23, Rick Bruch wrote:
>> Hi all,
>>
>> I've got what I hope will be an easy question to answer.
>>
>> In a Plone 4.2.7 site (using Archetypes), I'm trying to extend the
>> Related Items viewlet to show images for the items it displays. I've
>> successfully registered a custom viewlet class in my old-style theme's
>> browser/configure.zcml.
>>
>>       <!-- Customized relateditems viewlet registration -->
>>       <browser:viewlet
>>           name="plone.belowcontentbody.relateditems"
>>           manager="plone.app.layout.viewlets.interfaces.IBelowContentBody"
>>           class=".viewlets.ContentRelatedItems"
>>           permission="zope2.View"
>>           layer=".interfaces.IThemeSpecific"
>>           />
>>
>> I've also successfully written a method in my theme's viewlets.py that
>> uses lxml to parse content items' body HTML for images and returns a
>> path to the first image.
>>
>> <!-- Excerpt from viewlets.py -->
>> class ContentRelatedItems(content.ContentRelatedItems):
>>       render = ViewPageTemplateFile('templates/document_relateditems.pt')
>>
>>       def my_get_image(self):
>>           context = aq_inner(self.context)
>>           text = context.getText()
>>           tree = html.fromstring(text)
>>           imgs = tree.xpath('//img')
>>           if imgs:
>>               my_img = imgs[0]
>>               my_img_path = my_img.attrib['src']
>>               return my_img_path
>>           return None
>>
>> Now we come to the question. The way the viewlet works is that the
>> ContentRelatedItems class has a method, "related_items" that returns a
>> list of brains to the template, document_relateditems.pt. The template
>> uses TAL to loop through the brains and render various fields from the
>> brains.
>>
>> I'm trying to stick my method into the TAL loop to return an image path
>> for each item that's returned by related_items. (This excerpt is kind of
>> long but I wanted to show the context in the template for reference.)
>>
>> <!-- Excerpt of document_relateditems.pt -->
>> <div class="relatedItems"
>>        tal:define="related view/related_items"
>>        tal:condition="related">
>>       <dl id="relatedItemBox"
>>                 tal:define="ploneview nocall:context/@@plone;
>>                             normalizeString nocall:ploneview/normalizeString;
>>                             tools nocall:context/@@plone_tools;
>>                             wf_tool tools/workflow;
>>                             getInfoFor python:wf_tool.getInfoFor;
>>                             site_properties
>> context/portal_properties/site_properties;
>>                             use_view_action
>> site_properties/typesUseViewActionInListings|python:();">
>>           <dt i18n:translate="label_related_items">Related content</dt>
>>           <tal:related repeat="item related">
>>               <dd tal:define="
>>            [ TRYING TO ADD REFERENCE TO METHOD IN HERE ]
>>                       desc                item/Description;
>>                       item_icon           python:ploneview.getIcon(item);
>>                       item_type           item/portal_type;
>>                       item_type_class     python:'contenttype-' +
>> normalizeString(item_type);
>>                       item_wf_state       item/review_state|python:
>> getInfoFor(item, 'review_state', '');
>>                       item_wf_state_class python: 'state-' +
>> normalizeString(item_wf_state);
>>                       item_url            item/getURL|item/absolute_url;
>>                       item_url            python:(item_type in
>> use_view_action) and item_url+'/view' or item_url">
>> [ Some output ]
>>               </dd>
>>
>>
>> I've tried a few different things in the tal:define part of the <dd>
>> element:
>>
>> image_path item/my_get_image (item has no attribute my_get_image)
>> image_path my_get_image() (my_get_image is undefined)
>> image_path view/my_get_image (returns image path from the "host" item
>> not the related item)
>>
>> I'm sure I'm just missing something trivial. I did find this:
>>
>> Helper views and tools
>> https://developer.plone.org/misc/context.html
>>
>> But I wasn't sure if I needed to pull out the method into its own
>> structure since it's already in my custom viewlets.py.
>>
>> Thanks for any help! Let me know if I should provide more of my code or
>> information.
>>
>> Full original files for reference:
>> Class
>> https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/content.py#L112
>> Template
>> https://github.com/plone/plone.app.layout/blob/2.2.x/plone/app/layout/viewlets/document_relateditems.pt
>>
>> -Rick
>>
>
> --
> Daniel Jowett
>
> *Jowett Enterprises Ltd*
> Tel: 0333 3 553 773
> Mobile: 07870 667 126
> [hidden email]
> www.jowettenterprises.com

------------------------------------------------------------------------------
"Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE
Instantly run your Selenium tests across 300+ browser/OS combos.  Get
unparalleled scalability from the best Selenium testing platform available.
Simple to use. Nothing to install. Get started now for free."
http://p.sf.net/sfu/SauceLabs
_______________________________________________
Plone-Users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/plone-users