-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #166 from Vineg/master
Added support for multiple fragments definition
- Loading branch information
Showing
10 changed files
with
342 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
/Classes | ||
/node_modules | ||
npm-debug.log | ||
bin | ||
|
||
# IDEs | ||
/.idea | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
source/nz/net/ultraq/thymeleaf/fragments/CollectFragmentProcessor.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
* Copyright 2012, Emanuel Rabina (http://www.ultraq.net.nz/) | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package nz.net.ultraq.thymeleaf.fragments | ||
|
||
import org.slf4j.Logger | ||
import org.slf4j.LoggerFactory | ||
import org.thymeleaf.context.ITemplateContext | ||
import org.thymeleaf.engine.AttributeName | ||
import org.thymeleaf.engine.Text | ||
import org.thymeleaf.model.IProcessableElementTag | ||
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor | ||
import org.thymeleaf.processor.element.IElementTagStructureHandler | ||
import org.thymeleaf.templatemode.TemplateMode | ||
|
||
import nz.net.ultraq.thymeleaf.models.ElementMerger | ||
|
||
/** | ||
* Processor produced from FragmentProcessor in order to separate include and define logic to avoid ambiguity | ||
* | ||
* @authors Emanuel Rabina, George Vinokhodov | ||
*/ | ||
class CollectFragmentProcessor extends AbstractAttributeTagProcessor { | ||
|
||
private static final Logger logger = LoggerFactory.getLogger(CollectFragmentProcessor) | ||
|
||
private static boolean warned = false | ||
|
||
static final String PROCESSOR_DEFINE = 'define' | ||
static final String PROCESSOR_COLLECT = 'collect' | ||
static final int PROCESSOR_PRECEDENCE = 1 | ||
|
||
/** | ||
* Constructor, sets this processor to work on the 'collect' attribute. | ||
* | ||
* @param templateMode | ||
* @param dialectPrefix | ||
*/ | ||
CollectFragmentProcessor(TemplateMode templateMode, String dialectPrefix) { | ||
|
||
super(templateMode, dialectPrefix, null, false, PROCESSOR_COLLECT, true, PROCESSOR_PRECEDENCE, true) | ||
} | ||
|
||
/** | ||
* Inserts the content of <code>:define</code> fragments into the encountered collect placeholder. | ||
* | ||
* @param context | ||
* @param model | ||
* @param attributeName | ||
* @param attributeValue | ||
* @param structureHandler | ||
*/ | ||
@Override | ||
@SuppressWarnings('AssignmentToStaticFieldFromInstanceMethod') | ||
protected void doProcess(ITemplateContext context, IProcessableElementTag tag, | ||
AttributeName attributeName, String attributeValue, IElementTagStructureHandler structureHandler) { | ||
|
||
// Emit a warning if found in the <head> section | ||
if (templateMode == TemplateMode.HTML && | ||
context.elementStack.any { element -> element.elementCompleteName == 'head' }) { | ||
if (!warned) { | ||
logger.warn( | ||
'You don\'t need to put the layout:fragment/data-layout-fragment attribute into the <head> section - ' + | ||
'the decoration process will automatically copy the <head> section of your content templates into your layout page.' | ||
) | ||
warned = true | ||
} | ||
} | ||
|
||
// All :define fragments we collected, :collect fragments included to determine where to stop. | ||
// Fragments after :collect are preserved for the next :collect event | ||
Queue fragments = FragmentMap.get(context)[(attributeValue)] | ||
|
||
// Replace the tag body with the fragment | ||
if (fragments) { | ||
def modelFactory = context.modelFactory | ||
def merger = new ElementMerger(context) | ||
def replacementModel = modelFactory.createModel(tag) | ||
def first = true | ||
while (!fragments.empty) { | ||
def fragment = fragments.poll() | ||
if (fragment.get(0).getAttributeValue(dialectPrefix, CollectFragmentProcessor.PROCESSOR_COLLECT)) { | ||
break | ||
} | ||
if (first) { | ||
replacementModel = merger.merge(replacementModel, fragment) | ||
first = false | ||
} else { | ||
def firstEvent = true | ||
fragment.each { | ||
event -> | ||
if (firstEvent) { | ||
firstEvent = false | ||
replacementModel.add(new Text('\n')) | ||
replacementModel.add(modelFactory.removeAttribute(event, | ||
dialectPrefix, PROCESSOR_DEFINE)) | ||
} else { | ||
replacementModel.add(event) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Remove the layout:collect attribute - Thymeleaf won't do it for us | ||
// when using StructureHandler.replaceWith(...) | ||
replacementModel.replace(0, modelFactory.removeAttribute(replacementModel.first(), | ||
dialectPrefix, PROCESSOR_COLLECT)) | ||
|
||
structureHandler.replaceWith(replacementModel, true) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
...traq/thymeleaf/tests/decorators/xml/Document-XmlDecoration-MultipleElements-Nested.thtest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
|
||
# Test that standard decoration can occur on XML documents. | ||
|
||
%TEMPLATE_MODE XML | ||
|
||
|
||
%INPUT | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<root xmlns="http://www.example.org/" | ||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" | ||
layout:decorate="~{Layout}"> | ||
<item layout:define="item"> | ||
<name>Tomatoes</name> | ||
<price>3.99</price> | ||
</item> | ||
</root> | ||
|
||
%INPUT[Layout] | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<root xmlns="http://www.example.org/" | ||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" | ||
layout:decorate="~{Common}"> | ||
<item layout:define="item"> | ||
<name>Apples</name> | ||
<price>2.75</price> | ||
</item> | ||
</root> | ||
|
||
%INPUT[Common] | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<root xmlns="http://www.example.org/" | ||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> | ||
<list> | ||
<item layout:collect="item"></item> | ||
<item> | ||
<name>Potatoes</name> | ||
<price>4.99</price> | ||
</item> | ||
</list> | ||
</root> | ||
|
||
%OUTPUT | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<root xmlns="http://www.example.org/"> | ||
<list> | ||
<item> | ||
<name>Apples</name> | ||
<price>2.75</price> | ||
</item> | ||
<item> | ||
<name>Tomatoes</name> | ||
<price>3.99</price> | ||
</item> | ||
<item> | ||
<name>Potatoes</name> | ||
<price>4.99</price> | ||
</item> | ||
</list> | ||
</root> |
Oops, something went wrong.