Item10890: Template parser makes it impossible to override some .tmpl templates with TopicTemplates.
Priority: Urgent
Current State: Closed
Released In: 2.0.0
Target Release: major
Applies To: Engine
Component:
Branches:
For BaseSkin I would like to implement the template files as txt files in System web. Unfortunately, this does not work for a template like
formtables
.
Let's say I have a skin path
mycompany,basejs,basecssgrid,basecss,base,pattern
.
This is what happens in the parser:
name=formtables
template=/Users/me/Sites/foswiki/core/templates/$web/$name.$skin.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.lostboys.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.basejs.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.basecssgrid.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.basecss.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.base.tmpl
file=/Users/me/Sites/foswiki/core/templates/Main/formtables.pattern.tmpl
template=/Users/me/Sites/foswiki/core/templates/$name.$skin.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.lostboys.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.basejs.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.basecssgrid.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.basecss.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.base.tmpl
file=/Users/me/Sites/foswiki/core/templates/formtables.pattern.tmpl
So it stops at
formtables.pattern.tmpl
, without looking further in
System.BaseSkinFormtablesTemplate
, even if
base
is written before
pattern
.
The documentation on TemplatePath says: "This path is expanded to a sequence of file names. The first file on this list that is found is taken to be the requested template file."
So literally taken it looks like it works as intended. But was this also intended to prevent txt files to override tmpl files? I cannot expect users to change their TemplatePath setting.
--
ArthurClemens - 17 Jun 2011
Diving further into the code. The way it is programmed looks orderly but is in fact not what you would expect, as skin author. I feel backed by this comment in
TemplateTests.pm
, "It sure is counter-intuitive to not consider the skin templates first":
sub test_directLookupInUsertopic {
my $this = shift;
my $data;
# To verify a use case raised by Michael Daum: $web.$script looks up
# template topic $script in $web, no further searching is done
# Note the order in which templates are found. It sure is
# counter-intuitive to not consider the skin templates first.
This has also been voiced in
Item4463 (without followup). That topic lists an older discussion at
TemplatePathIsCounterintuitive, where the original problem was not resolved.
But this is the crux:
consider the skin templates first.
So you need to discern:
- Skin templates, such as System.MyskinViewTemplate, view.myskin.tmpl, etc.
- Fallback templates, such as view.tmpl
We also need to
consider the skin path before the template path.
The changes I propose to the template parsing takes care of this. The basic idea is:
- Collect candidate template files
- Sort the candidate template files on
- Having 'skin' in the template path: yes has highest priority
- The order in the skin path: more specific has higher priority
- The order in the template path
- Go through the sorted candidates and pick the first one that is a valid file
This results in one unit test change (in
test_directLookupInUsertopic
):
write_topic( 'Web', 'SkinSkinTestTemplate',
'the Web.SkinSkinTestTemplate template' );
$data = $tmpls->readTemplate( 'web.test', skins => 'skin' );
$this->assert_str_equals( 'the Web.SkinSkinTestTemplate template', $data );
write_template( 'web.test', 'the web.test.tmpl template' );
$data = $tmpls->readTemplate( 'web.test', skins => 'skin' );
$this->assert_str_equals( 'the web.test.tmpl template', $data );
becomes the way around:
write_template( 'web.test', 'the web.test.tmpl template' );
$data = $tmpls->readTemplate( 'web.test', skins => 'skin' );
$this->assert_str_equals( 'the web.test.tmpl template', $data );
write_topic( 'Web', 'SkinSkinTestTemplate',
'the Web.SkinSkinTestTemplate template' );
$data = $tmpls->readTemplate( 'web.test', skins => 'skin' );
$this->assert_str_equals( 'the Web.SkinSkinTestTemplate template', $data );
In other words:
- if the 2 template files
templates/web.test.tmpl
and Web.SkinSkinTestTemplate
exist,
- if the skin path is
skin
,
- in the old situation:
templates/web.test.tmpl
was used (because templates
was earlier in the template path)
- in the new situation:
Web.SkinSkinTestTemplate
is used (because skin
is defined in the skin path)
And:
- if the 2 template files
templates/formtables.default.tmpl
and System.NewSkinFormtablesTemplate
exist,
- if the skin path is
new,default
,
- in the old situation:
templates/default.tmpl
was used (because templates
was earlier in the template path)
- in the new situation:
Web.SkinSkinTestTemplate
is used (because new
is defined earlier in the skin path)
The skin path has precedence over the template path in finding the template file.
--
ArthurClemens - 17 Jun 2011