Best processor for wrapping tags

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

Best processor for wrapping tags

dstarh
We have the need to take an input tag and wrap it with a few divs and we would like to do so using a processor. We don't want to lose what had been typed on the input tag and would still like to use this in combination with th:field. Basically we want < input type=text th:field="${foo}" adh:wrap="true" > the adh:wrap would just make it render a few divs around the input.
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Zemi
Administrator
Extend an AbstractAttrProcessor and manipulate the DOM to match your needs.

For an example see lines 51-55 of this processor.

Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

dstarh
That seems to get me part of the way there.  I can create a new node and place "element" as a child of it but that only ever seems to be a Copy of element.  I need to remove element from it's orig placement within the dom and have it be a child of my newly crafted node and have the new node take the place of the original element.

-- 
David Herman
Sent with Sparrow

On Monday, November 5, 2012 at 9:44 AM, Zemi [via Thymeleaf - User Forum] wrote:

Extend an AbstractAttrProcessor and manipulate the DOM to match your needs.

For an example see lines 51-55 of this processor.




If you reply to this email, your message will be added to the discussion below:
http://forum.thymeleaf.org/Best-processor-for-wrapping-tags-tp4025264p4025265.html
To unsubscribe from Best processor for wrapping tags, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Zemi
Administrator
I think you should be able to move an element inside the DOM. Could you post your code?

As an alternative, you could set the attribute processor in an outer level.

   <div adh:wrap="true" >
     < input type=text th:field="${foo}"  >
   </div>
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

dstarh
Thats the whole point of the exercise.  I want to start with this:
< input type="text" th:field="${foo}" adh:wrap="true">

and end up with:

< div class="control-group">
  <label>Foo</label>
  < div class="controls">
    < input type="text" name="foo" value="some value">
  < /div>
< /div>

-- 
David Herman

On Monday, November 5, 2012 at 11:27 AM, Zemi [via Thymeleaf - User Forum] wrote:

I think you should be able to move an element inside the DOM. Could you post your code?

As an alternative, you could set the attribute processor in an outer level.

   <div adh:wrap="true" >
     < input type=text th:field="${foo}"  >
   </div>


If you reply to this email, your message will be added to the discussion below:
http://forum.thymeleaf.org/Best-processor-for-wrapping-tags-tp4025264p4025267.html
To unsubscribe from Best processor for wrapping tags, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Emanuel
Administrator
You'll probably want to do something like this in your custom processor:

// Create the new elements tags
Element controlgroup = new Element("div");
controlgroup.setAttribute("class", "control-group");

Element label = new Element("label");
label.addChild(new Text("Foo"));

Element controls = new Element("div");
controls.setAttribute("class", "controls");

// Reorganize the DOM
NestableNode parent = input.getParent();
parent.removeChild(input);
parent.addChild(controlgroup);
controlgroup.addChild(label);
controlgroup.addChild(controls);
controls.addChild(input);

I'm not sure if with the latest Thymeleaf you can just set the 'recompute' flags to true to get the input element to be reprocessed (depends on the precedence of your custom processor).  I did see some changes to these in the release notes in previous versions, but I've still got my code cloning the element without processing information in my Layout dialect.  So instead of that last line of just adding the input element to the controls, you might need to do something like this:

controls.addChild(input.cloneNode(null, false));
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

dstarh
won't the call parent.addChild place the new control group at the end of the parent and not where element used to exist?

On Monday, November 5, 2012 at 4:34 PM, Emanuel [via Thymeleaf - User Forum] wrote:

You'll probably want to do something like this in your custom processor:

// Create the new elements tags
Element controlgroup = new Element("div");
controlgroup.setAttribute("class", "control-group");

Element label = new Element("label");
label.addChild(new Text("Foo"));

Element controls = new Element("div");
controls.setAttribute("class", "controls");

// Reorganize the DOM
NestableNode parent = input.getParent();
parent.removeChild(input);
parent.addChild(controlgroup);
controlgroup.addChild(label);
controlgroup.addChild(controls);
controls.addChild(input);

I'm not sure if with the latest Thymeleaf you can just set the 'recompute' flags to true to get the input element to be reprocessed (depends on the precedence of your custom processor).  I did see some changes to these in the release notes in previous versions, but I've still got it that you have to clone the element without processing information in my Layout dialect.  So instead of that last line of just adding the input element to the controls, you might need to do something like this:

controls.addChild(input.cloneNode(null, false));



If you reply to this email, your message will be added to the discussion below:
http://forum.thymeleaf.org/Best-processor-for-wrapping-tags-tp4025264p4025269.html
To unsubscribe from Best processor for wrapping tags, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Emanuel
Administrator
Yup, it will.  You can reorganize the lines of code, then use the insertAfter(existingNode, newNode) or insertBefore(existingNode, newNode) methods to be more precise in your element placement, eg:

// Reorganize the DOM
NestableNode parent = input.getParent();
parent.insertAfter(input, controlgroup);
parent.removeChild(input);
...

You can find all the DOM manipulation methods in the Thymeleaf API Javadocs, under the org.thymeleaf.dom package.
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

dstarh
Interesting, when I delete element I get the following error: 

Error processing template: dialect prefix "th" is set as non-lenient but attribute "th:field" has not been removed during process 

-- 
David Herman

On Monday, November 5, 2012 at 5:16 PM, Emanuel [via Thymeleaf - User Forum] wrote:

Yup, it will.  You can reorganize the lines of code, then use the insertAfter(existingNode, newNode) or insertBefore(existingNode, newNode) methods to be more precise in your element placement, eg:

// Reorganize the DOM
NestableNode parent = input.getParent();
parent.insertAfter(input, controlgroup);
parent.removeChild(input);
...

You can find all the DOM manipulation methods in the Thymeleaf API Javadocs, under the org.thymeleaf.dom package.



If you reply to this email, your message will be added to the discussion below:
http://forum.thymeleaf.org/Best-processor-for-wrapping-tags-tp4025264p4025271.html
To unsubscribe from Best processor for wrapping tags, click here.
NAML

Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Emanuel
Administrator
Odd, I think Thymeleaf is still working on the element, even though it's been removed from the DOM.  If you haven't already removed the attribute from the element, I'm not too sure what might be going on then.

element.removeAttribute(attributeName);
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

danielfernandez
Administrator
Hi,

Please note that Thymeleaf precomputes the processors that will have to be applied to each node in the DOM before actually processing it (this allows this precomputations to be cached along with the template for better performance).

So, if you are performing modifications on the DOM that might mean adding new elements that must be processed by any processors, or adding new "th:*" attributes to existing elements, you may need to use:

    element.setRecomputeProcessorsImmediately(true);

...which instructs Thymeleaf to recompute the processors to be applied to this element and its children because you have performed changes that might invalidate the current precomputations.

Regards,
Daniel.
PeZ
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

PeZ
This post was updated on .
David,

Did you manage to get this working ?

I'm trying to do something really similar to your use case and it looks like I'm also stuck with some issues.

PeZ
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

PeZ
Ok, so, this is working :

String attributeValue = element.getAttributeValue(s);
Element div = new Element("div");
div.setAttribute("class", "question");

Element label = new Element("label");
Element spanTrad = new Element("span");
Text t = new Text(s);
div.addChild(label);
//spanTrad.addChild(t);
label.addChild(spanTrad);

element.getParent().insertBefore(element, div);
element.getParent().removeChild(element);

div.addChild(element);
element.removeAttribute(s);
However, once I uncomment spanTrad.addChild(t), I've got the following error :

Problem accessing /parse/info/. Reason:

    Error during execution of processor 'org.thymeleaf.spring3.processor.attr.SpringInputGeneralFieldAttrProcessor' (info/home:20)
Caused by:

org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring3.processor.attr.SpringInputGeneralFieldAttrProcessor' (info/home:20)
        at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:223)
        at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:914)
        at org.thymeleaf.dom.Node.processNode(Node.java:875)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:639)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:621)
        at org.thymeleaf.dom.Node.processNode(Node.java:894)
        at org.thymeleaf.dom.Document.process(Document.java:93)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1243)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1148)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1095)
        at org.thymeleaf.spring3.view.ThymeleafView.renderFragment(ThymeleafView.java:221)
        at org.thymeleaf.spring3.view.ThymeleafView.render(ThymeleafView.java:146)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1208)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:992)
...
        at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
        at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
        at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
        at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.IllegalArgumentException: Input cannot be null
        at org.thymeleaf.util.Validate.notNull(Validate.java:37)
        at org.thymeleaf.standard.expression.StandardExpressionParser.parseExpression(StandardExpressionParser.java:82)
        at org.thymeleaf.standard.expression.StandardExpressionProcessor.parseExpression(StandardExpressionProcessor.java:62)
        at org.thymeleaf.spring3.util.FieldUtils.getBindStatus(FieldUtils.java:129)
        at org.thymeleaf.spring3.util.FieldUtils.getBindStatus(FieldUtils.java:107)
        at org.thymeleaf.spring3.processor.attr.AbstractSpringFieldAttrProcessor.processAttribute(AbstractSpringFieldAttrProcessor.java:96)
        at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:74)
        at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
        ... 95 more
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

danielfernandez
Administrator

Hi,

I have a theory. Maybe the problem is you are taking the element which attributes are being processed at the current moment (variable "element") and moving it to a different position in the DOM tree. Specifically to a position that has not yet been processed (because it is deeper in the tree -- inside a new "div" element).

The problem is, by doing this you are not removing the internal metainfo that declares which are the processors to be applied to your "element" node. In this metainfo, the processor which code you show us is included. But you are removing the attribute value it refers to (the "s" attribute).

So this results in the processor being executed again when the execution flow reaches that point deeper in the flow, and on exactly the same node, which should be an infinite loop... but it isn't because you removed the attribute value, and receive a NullPointer.

How to fix it? by telling thymeleaf to recompute that metainfo on your "element" node, so that the engine realises the processed attribute is there no more and does not try to execute the same processor again:

    ...
    div.addChild(element);
    element.removeAttribute(s);
    div.setRecomputeProcessorsImmediately(true);
    element.setRecomputeProcessorsImmediately(true);

How does this relate to your adding that Text node or not? That's the part I still don't get... (that's why I say this is a "theory" ;-))...

Regards,
Daniel.
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Divya
Hi,

I have new requirment,

i need to inject the spring security authorization code

 <sec:authorize access="hasRole('ROLE_ADMIN')"> 

inside java class with extends AbstractMarkupSubstitutionElementProcessor


some like this:

1. How do i apply access attribute to sec:authorize prefix
/*
        * Create the DOM structure that will be substituting our custom tag.
        * The headline will be shown inside a '<div>' tag, and so this must
        * be created first and then a Text node must be added to it.
        */
       final Element container = new Element("div");
      //sec:authorize="hasRole('ROLE_ADMIN')"
       String springDialect=Element.applyDialectPrefix("authorize", "sec");
       NestableNode parent =container.getParent();

      final Text text = new Text("some text");
       container.addChild(text);


Plz reply to this thread as it is a very urgent requirment
Reply | Threaded
Open this post in threaded view
|

Re: Best processor for wrapping tags

Divya
Hi Danial,

Plz provide a sample code for Creating a custom template modes which allows a user to use Thymeleaf for processing templates in formats different to the XML / XHTML / HTML5 that are available out-of-the-box.


Regards
Divya