Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to repeat items with no new line inserted #110

Closed
anthonygerrard opened this issue Apr 25, 2012 · 23 comments
Closed

Add support to repeat items with no new line inserted #110

anthonygerrard opened this issue Apr 25, 2012 · 23 comments
Labels

Comments

@anthonygerrard
Copy link

tal:repeat always inserts a new line inbetween repeating elements. Whitespace is sometimes important in HTML and unnecessary whitespace can cause styling problems in some older browsers.

It would be great if Chameleon could support repeating elements, or text, all on the same line.

The equivalent bug in zope.tal project is https://bugs.launchpad.net/zope3/+bug/229931

It seems tricky to do this in a backwards compatible way. A rule that would make sense to me would be that if the repeating element is the first non white space element on its line then add a new line otherwise don't.

e.g.

    <ul><li tal:repeat="item items" tal:content="item"></li></ul>

would result in

    <ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>

but

    <ul>
        <li tal:repeat="item items" tal:content="item"></li>
    </ul>

would result in

    <ul>
        <li>item 1</li>
        <li>item 2</li>
        <li>item 3</li>
    </ul>
@malthe
Copy link
Owner

malthe commented Apr 27, 2012

I have actually experimented quite a bit with this, but got stuck in details and issues.

It's not impossible to pull it off, and your syntax is pretty good I think.

@anthonygerrard
Copy link
Author

An alternative to the above syntax might be:

  • if the start tag of the repeating element is the first non white space element on its line then prefix each repeated element with the same amount of white space that proceeds the start tag
  • if the end tag of the element is the last non white space element on its line then suffix each element with the same amount of white space that succeeds the element plus a new line

@goodwillcoding
Copy link

@malthe @anthonygerrard
Is there any movement on this. The workaround above does not seem to work as of 2.13-1

When I do

<span tal:repeat="item ('h', 'e', 'l', 'l', 'o')" tal:content="item"></span>

I always get:

<span>h</span>
<span>e</span>
<span>l</span>
<span>l</span>
<span>o</span>

I need to generate a continuos line with spans adjustent and I can not seem to do that in anyway in Chameleon

@goodwillcoding
Copy link

@malthe
Copy link
Owner

malthe commented Nov 11, 2013

What happens if you do e.g. <tal:block><span tal:repeat="..." /></tal:block>?

@goodwillcoding
Copy link

So this:

<tal:block><span tal:repeat="n range(3)" tal:content="n"></span></tal:block>

Produces this (with newlines):

  <span>0</span>
  <span>1</span>
  <span>2</span>

@goodwillcoding
Copy link

@malthe
Also I know this is marked as a feature but techinicall its a bug, since there is absolutely no way to generate consecutive spans right now and have continuous text.

In short, insteat if "hello" I always get "h e l l o"

@goodwillcoding
Copy link

@malthe

Also based on this https://mail.zope.org/pipermail/zpt/2002-November/004078.html it appears that zpt supported that as functionality way back

@goodwillcoding
Copy link

@malthe
Okie, so I managed to test "tal:block" enclose work around in zope.tal and Chameleon and results are different.

pip install zope.pagetemplates chameleon

test.pt

<tal:block><span tal:repeat="n python:range(3)" tal:content="n"></span></tal:block>

test.py

#!/usr/bin/env python

from zope.pagetemplate.pagetemplatefile import PageTemplateFile
zpt_pt = PageTemplateFile('./test.pt')
print "==== Zope.TAL ===="
print zpt_pt()


from chameleon import PageTemplateFile
chameleon_pt = PageTemplateFile('./test.pt')
print "==== Chameleon ===="
print chameleon_pt()

output:

==== Zope.TAL ====
<span>0</span><span>1</span><span>2</span>

==== Chameleon ====
<span>0</span>
<span>1</span>
<span>2</span>

@goodwillcoding
Copy link

@malthe

so the question is whether to implement "tal:whitespace=false" fix described in the ubuntu bug or to fix the Chameleon tal:block behaviour.

Btw, I've looked over the block code and I have no clue how to do the latter. Meanwhile I have a patched code chameleon, but I am really at a loss how what to do next.

Do you think this is something you can address?

@malthe
Copy link
Owner

malthe commented Nov 11, 2013

Sure, I just have to fit it into my schedule. I think Zope's behavior is
right. But this is a hard thing to get exactly right.

On Monday, November 11, 2013, goodwillcoding wrote:

@malthe https://github.com/malthe

so the question is whether to implement "tal:whitespace=false" fix
described in the ubuntu bug or to fix the Chameleon tal:block behaviour.

Btw, I've looked over the block code and I have no clue how to do the
latter. Meanwhile I have a patched code chameleon, but I am really at a
loss how what to do next.

Do you think this is something you can address?


Reply to this email directly or view it on GitHubhttps://github.com//issues/110#issuecomment-28230032
.


Malthe Borch
mborch@gmail.com

@goodwillcoding
Copy link

@malthe

The fix does work for "tal" namespace. However I did miss a scenario in the original test. As it appears zope.tal might be doing this for any "tal:repeat"

test.pt:

<span tal:repeat="n python:range(3)" tal:content="n" />

test.py:

#!/usr/bin/env python

from zope.pagetemplate.pagetemplatefile import PageTemplateFile
zpt_pt = PageTemplateFile('./test.pt')
print "==== Zope.TAL ===="
print zpt_pt()

from chameleon import PageTemplateFile
chameleon_pt = PageTemplateFile('./test.pt')
print "==== Chameleon ===="
print chameleon_pt()

output:

==== Zope.TAL ====
<span>0</span><span>1</span><span>2</span>

==== Chameleon ====
<span>0</span>
<span>1</span>
<span>2</span>

@goodwillcoding
Copy link

Expanding on the test a little more, seem the logic is conditional:

test.pt

<span tal:repeat="n python:range(3)" tal:content="n" />
<div tal:repeat="n python:range(3)" tal:content="n" />
<tal:block tal:repeat="n python:range(3)" tal:content="n" />

output:

==== Zope.TAL ====
<span>0</span><span>1</span><span>2</span>
<div>0</div>
<div>1</div>
<div>2</div>
0
1
2

==== Chameleon ====
<span>0</span>
<span>1</span>
<span>2</span>
<div>0</div>
<div>1</div>
<div>2</div>
012

@goodwillcoding
Copy link

As you said this was tricky as shown by more tests:

test.pt:

<tal:block tal:repeat="n python:range(3)"><span tal:content="n" /></tal:block>
<span tal:repeat="n python:range(3)" tal:content="n" />
<div tal:repeat="n python:range(3)" tal:content="n" />
<li tal:repeat="n python:range(3)" tal:content="n" />
<table>
<tr tal:repeat="n python:range(3)" tal:content="n" />
</table>
<tal:block tal:repeat="n python:range(3)" tal:content="n" />
<tal:item tal:repeat="n python:range(3)" tal:content="n" /

output:

==== Zope.TAL ====
<span>0</span><span>1</span><span>2</span>
<span>0</span>
<span>1</span>
<span>2</span>
<div>0</div>
<div>1</div>
<div>2</div>
<li>0</li>
<li>1</li>
<li>2</li>
<table>
<tr>0</tr>
<tr>1</tr>
<tr>2</tr>
</table>
0
1
2
0
1
2

==== Chameleon ====
<span>0</span><span>1</span><span>2</span>
<span>0</span>
<span>1</span>
<span>2</span>
<div>0</div>
<div>1</div>
<div>2</div>
<li>0</li>
<li>1</li>
<li>2</li>
<table>
<tr>0</tr>
<tr>1</tr>
<tr>2</tr>
</table>
012
012

@malthe
Copy link
Owner

malthe commented Nov 13, 2013

Zope also has this HTML mode where it behaves differently depending on the tag. We do support some of that via configuration options but obviously not all of it.

@malthe malthe reopened this Nov 13, 2013
@malthe
Copy link
Owner

malthe commented Nov 13, 2013

The question is whether the current fix is enough to let you do what you want. It doesn't always make sense to replicate every last Zopeism out there.

@goodwillcoding
Copy link

@malthe

Ok the commonality seems to be presence of tal:content so far in every use case I have thought off.

Basically the conditionally the conditional here :

if start['namespace'] == TAL:
should be:

if start['namespace'] == TAL and (not ns.has_key((TAL, 'content'))):

This also passes all the current tests, though I am sure if this is the fix a few more tests can be added. If you are ok with the fix I'll try to do a PR with proper tests.

@goodwillcoding
Copy link

@malthe

That said its possible the bug wih zope.tal because the fix you did actually has greater flexibility IMHO, so I am ok with keeping it.

@malthe
Copy link
Owner

malthe commented Nov 13, 2013

I feel that we do need a few more tests, but yes, what I like about "my" fix is that it's fairly easy to explain the rule, i.e. if it's the TAL namespace, then there's no repeat space. That kind of makes sense I think.

@sdouche
Copy link

sdouche commented Dec 5, 2013

Hi Malthe,
since the upgrade to 2.14, I have this:

Traceback (most recent call last):
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.publisher-3.13.0-py2.7.egg/zope/publisher/publish.py", line 132, in publish
    result = publication.callObject(request, obj)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.app.publication-3.14.0-py2.7.egg/zope/app/publication/zopepublication.py", line 205, in callObject
    return mapply(ob, request.getPositionalArguments(), request)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.publisher-3.13.0-py2.7.egg/zope/publisher/publish.py", line 107, in mapply
    return debug_call(obj, args)
   - __traceback_info__: <security proxied z3c.pagelet.zcml.WidgetsPagelet instance at 0x7f1c287d7b10>
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.publisher-3.13.0-py2.7.egg/zope/publisher/publish.py", line 113, in debug_call
    return obj(*args)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pagelet-2.0.0a1-py2.7.egg/z3c/pagelet/browser.py", line 61, in __call__
    return layout(self)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 271, in __call__
    return bound_pt(**kwargs)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 295, in __call__
    return self.im_func(**kw)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 124, in render
    return self.render(**context)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 163, in render
    return base_renderer(**context)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/zpt/template.py", line 258, in render
    return super(PageTemplate, self).render(**vars)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/template.py", line 170, in render
    self._render(stream, econtext, rcontext)
  File "layout_1cf42383ed54e51738e4eb58077ae3f5.py", line 531, in render
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/expressions.py", line 74, in render_content_provider
    return cp.render()
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pagelet-2.0.0a1-py2.7.egg/z3c/pagelet/provider.py", line 41, in render
    return self.__parent__.render()
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pagelet-2.0.0a1-py2.7.egg/z3c/pagelet/browser.py", line 45, in render
    return self.template()
  File "/home/sdouche/src/sact/main/sact.nova/eggs/sact.nevrax-0.35.0.1dev_r201312041517-py2.7.egg/sact/nevrax/gui/view.py", line 73, in get_template_from_context
    return view_instance.context.html_template(view_instance)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.browserpage-3.12.2-py2.7.egg/zope/browserpage/viewpagetemplatefile.py", line 83, in __call__
    return self.im_func(im_self, *args, **kw)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.browserpage-3.12.2-py2.7.egg/zope/browserpage/viewpagetemplatefile.py", line 51, in __call__
    sourceAnnotations=getattr(debug_flags, 'sourceAnnotations', 0),
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.pagetemplate-3.6.3-py2.7.egg/zope/pagetemplate/pagetemplate.py", line 132, in pt_render
    strictinsert=0, sourceAnnotations=sourceAnnotations
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.ptcompat-2.0.0a1-py2.7.egg/z3c/ptcompat/engine.py", line 47, in __call__
    return self.template.render(**context.vars)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 163, in render
    return base_renderer(**context)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/zpt/template.py", line 258, in render
    return super(PageTemplate, self).render(**vars)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/template.py", line 188, in render
    raise_with_traceback(exc, tb)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/template.py", line 170, in render
    self._render(stream, econtext, rcontext)
  File "e1ac401b3335be57fe35402e66f931fb.py", line 164, in render
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/expressions.py", line 101, in path_traverse
    next = getattr(base, name, _marker)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/sact.nevrax-0.35.0.1dev_r201312041517-py2.7.egg/sact/nevrax/form/view.py", line 56, in form
    name=self.context.form_descriptor.view_name)()
  File "/home/sdouche/src/sact/main/sact.nova/eggs/sact.nevrax-0.35.0.1dev_r201312041517-py2.7.egg/sact/nevrax/form/form.py", line 234, in __call__
    return self._template()
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.browserpage-3.12.2-py2.7.egg/zope/browserpage/viewpagetemplatefile.py", line 83, in __call__
    return self.im_func(im_self, *args, **kw)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.browserpage-3.12.2-py2.7.egg/zope/browserpage/viewpagetemplatefile.py", line 51, in __call__
    sourceAnnotations=getattr(debug_flags, 'sourceAnnotations', 0),
  File "/home/sdouche/src/sact/main/sact.nova/eggs/zope.pagetemplate-3.6.3-py2.7.egg/zope/pagetemplate/pagetemplate.py", line 132, in pt_render
    strictinsert=0, sourceAnnotations=sourceAnnotations
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.ptcompat-2.0.0a1-py2.7.egg/z3c/ptcompat/engine.py", line 47, in __call__
    return self.template.render(**context.vars)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/z3c.pt-3.0.0a1-py2.7.egg/z3c/pt/pagetemplate.py", line 163, in render
    return base_renderer(**context)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/zpt/template.py", line 258, in render
    return super(PageTemplate, self).render(**vars)
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/template.py", line 170, in render
    self._render(stream, econtext, rcontext)
  File "54abc3247b63a1adbb9cc429bb27bfe1.py", line 1072, in render
  File "/home/sdouche/src/sact/main/sact.nova/eggs/Chameleon-2.14-py2.7.egg/chameleon/tal.py", line 462, in __call__
    iterable = tuple(iterable)
TypeError: 'NoneType' object is not iterable

 - Expression: "provider:pagelet"
 - Filename:   ... .1dev_r201312041517-py2.7.egg/sact/nevrax/skin/layout.pt
 - Location:   (line 79: col 50)
 - Source:     ... " tal:content="structure provider:pagelet">
                                            ^^^^^^^^^^^^^^^^
 - Expression: "view/form"
 - Filename:   ... .7.egg/sact/nevrax/gui/templates/default_widgets_page.pt
 - Location:   (line 8: col 30)
 - Source:     <div tal:content="structure view/form" />
                                           ^^^^^^^^^
 - Arguments:  repeat: {...} (0)
               context: <type BcaDashboard at 0x618fd30>
               views: <ViewMapper - at 0x7f1c28405890>
               modules: <TraversableModuleImporter - at 0x35217d0>
               args: <tuple - at 0x7f1c44c81050>
               nothing: <NoneType - at 0x7ac070>
               target_language: <NoneType - at 0x7ac070>
               default: <object - at 0x7f1c44c44580>
               request: <BrowserRequest - at 0x7f1c0003bd10>
               loop: {...} (0)
               template: <ViewPageTemplateFile - at 0x6112cd0>
               translate: <function translate at 0x7f1c286825f0>
               options: {...} (0)
               view: <WidgetsPagelet default_view at 0x7f1c287d7b10>

@ampsport
Copy link

@malthe @sdouche I just saw the same issue. This might actually break quite a bit of code in Plone, since I know many of us rely on it to err nicely when the loop is empty. 2.14 release has the issue. I'll open a new ticket.

@malthe
Copy link
Owner

malthe commented Apr 25, 2014

@sdouche, can you move that traceback to the issue that @eleddy added just now – #172.

@malthe
Copy link
Owner

malthe commented Dec 5, 2016

I think this is fixed or at least resolved.

@malthe malthe closed this as completed Dec 5, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants