-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathREADME
1140 lines (748 loc) · 30.3 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
NAME
Template::Flute - Modern designer-friendly HTML templating Engine
VERSION
Version 0.027
SYNOPSIS
use Template::Flute;
my ($cart, $flute, %values);
$cart = [{...},{...}];
$values{cost} = ...
$flute = new Template::Flute(specification_file => 'cart.xml',
template_file => 'cart.html',
iterators => {cart => $cart},
values => \%values,
autodetect => {
disable => [qw/Foo::Bar/],
}
);
print $flute->process();
DESCRIPTION
Template::Flute enables you to completely separate web design and
programming tasks for dynamic web applications.
Templates are designed to be designer-friendly; there's no inline code
or mini templating language for your designers to learn - instead,
standard HTML and CSS classes are used, leading to HTML that can easily
be understood and edited by WYSIWYG editors and hand-coding designers
alike.
An example is easier than a wordy description:
Given the following template snippet:
<div class="customer_name">Mr A Test</div>
<div class="customer_email">someone@example.com</div>
and the following specification:
<specification name="example" description="Example">
<value name="customer_name" />
<value name="email" class="customer_email" />
</specification>
Processing the above as follows:
$flute = Template::Flute->new(
template_file => 'template.html',
specification_file => 'spec.xml',
);
$flute->set_values({
customer_name => 'Bob McTest',
email => 'bob@example.com',
});;
print $flute->process;
The resulting output would be:
<div class="customer_name">Bob McTest</div>
<div class="email">bob@example.com</div>
In other words, rather than including a templating language within your
templates which your designers must master and which could interfere
with previews in WYSIWYG tools, CSS selectors in the template are tied
to your data structures or objects by a specification provided by the
programmer.
Workflow
The easiest way to use Template::Flute is to pass all necessary
parameters to the constructor and call the process method to generate
the HTML.
You can also break it down in separate steps:
1. Parse specification
Parse specification based on your specification format (e.g with
Template::Flute::Specification::XML or
Template::Flute::Specification::Scoped.).
$xml_spec = new Template::Flute::Specification::XML;
$spec = $xml_spec->parse(q{<specification name="cart" description="Cart">
<list name="cart" class="cartitem" iterator="cart">
<param name="name" field="title"/>
<param name="quantity"/>
<param name="price"/>
</list>
<value name="cost"/>
</specification>});
2. Parse template
Parse template with Template::Flute::HTML object.
$template = new Template::Flute::HTML;
$template->parse(q{<html>
<head>
<title>Cart Example</title>
</head>
<body>
<table class="cart">
<tr class="cartheader">
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
</tr>
<tr class="cartitem">
<td class="name">Sample Book</td>
<td><input class="quantity" name="quantity" size="3" value="10"></td>
<td class="price">$1</td>
</tr>
<tr class="cartheader"><th colspan="2"></th><th>Total</th>
</tr>
<tr>
<td colspan="2"></td><td class="cost">$10</td>
</tr>
</table>
</body></html>},
$spec);
3. Produce HTML output
$flute = new Template::Flute(template => $template,
iterators => {cart => $cart},
values => {cost => '84.94'});
$flute->process();
CONSTRUCTOR
new
Create a Template::Flute object with the following parameters:
specification_file
Specification file name.
specification_parser
Select specification parser. This can be either the full class name
like MyApp::Specification::Parser or the last part for classes
residing in the Template::Flute::Specification namespace.
specification
Specification object or specification as string.
template_file
HTML template file.
template
Template::Flute::HTML object or template as string.
filters
Hash reference of filter functions.
i18n
Template::Flute::I18N object.
translate_attributes
An arrayref of attribute names to translate. If the name has a dot,
it is interpreted as tagname + attribute, so placeholder" will
unconditionally translate all the placeholders, while
input.placeholder only the placeholder found on the input tag.
Additional dotted values compose conditions for attributes. E.g.
input.value.type.submit means all the value attributes with attribute
type set to submit.
Defaults to ['input.value.type.submit', 'placeholder']
iterators
Hash references of iterators.
values
Hash reference of values to be used by the process method.
auto_iterators
Builds iterators automatically from values.
autodetect
A configuration option. It should be an hashref with a key disable
and a value with an arrayref with a list of classes for objects which
should be considered plain hashrefs instead. Example:
my $flute = Template::Flute->new(....
autodetect => { disable => [qw/My::Object/] },
....
);
Doing so, if you pass a value holding a My::Object object, and you
have a specification with something like this:
<specification>
<value name="name" field="object.method"/>
</specification>
The value will be $object-{method}>, not $object-$method>.
The object is checked with isa.
Classical example: Dancer::Session::Abstract.
uri
Base URI for your template. This adjusts the links in the HTML tags
a, base, img, link and script.
email_cids
This is meant to be used on HTML emails. When this is set to an hash
reference (which should be empty), the hash will be populated with
the following values:
cid1 => { filename => 'foo.png' },
cid2 => { filename => 'foo2.gif' },
and in the body the images src attribute will be replaced with
cid:cid1.
The cid names are arbitrary and assigned by the template. The code
should look at the reference values which were modified.
cids
Optional hashref with options for the CID replacement behaviour.
By default, if the source looks like an HTTP/HTTPS URI, the image
source is not altered and no CID is assigned.
If you pass a base_url value in this hashref, the URI matching it
will be converted to cids and the rest of the path will be added to
the email_cids hashref.
Example:
my $cids = {};
$flute = Template::Flute->new(template => $template,
specification => $spec,
email_cids => $cids,
cids => {
base_url => 'http://example.com/'
});
Say the template contains images with source
http://example.com/image.png, the email_cids hashref will contain a
cid with filename "image.png".
METHODS
BUILD
Force creation of template class as soon as object is instantiated.
process [HASHREF]
Processes HTML template, manipulates the HTML tree based on the
specification, values and iterators.
Returns HTML output.
process_template
Processes HTML template and returns Template::Flute::HTML object.
filter ELEMENT VALUE
Runs the filter used by ELEMENT on VALUE and returns the result.
value NAME
Returns the value for NAME.
set_values HASHREF
Sets hash reference of values to be used by the process method. Same as
passing the hash reference as values argument to the constructor.
template
Returns HTML template object, see Template::Flute::HTML for details.
specification
Returns specification object, see Template::Flute::Specification for
details.
patterns
Returns all patterns found in the specification.
scopes
SPECIFICATION
The specification ties the elements in the HTML template to the data
(variables, lists, forms) which is added to the template.
The default format for the specification is XML implemented by the
Template::Flute::Specification::XML module. You can use the
Config::Scoped format implemented by
Template::Flute::Specification::Scoped module or write your own
specification parser class.
COMMON ATTRIBUTES
Common attributes for specification elements are:
name
Name of element.
<value name="dancefloor"/>
class
Class of corresponding elements in the HTML template.
<value name="dancefloor" class="dancefloor-link"/>
If this attribute is omitted, the value of the name attribute is used
to relate to the class in the HTML template.
id
Id of corresponding element in the HTML template. Overrides the class
attribute for the specification element.
<value name="dancefloor" id="dancefloor-link"/>
target
HTML attribute to fill the value instead of replacing the body of the
HTML element.
<value name="dancefloor" class="dancefloor-link" target="href"/>
joiner
String placed between the text and the appended value. The joiner
isn't added if the value is empty.
ELEMENTS
Possible elements in the specification are:
container
The first container is only shown in the output if the value
billing_address is set:
<container name="billing" value="billing_address" class="billingWrapper">
</container>
The second container is shown if the value warnings or the value
errors is set:
<container name="account_errors" value="warnings|errors" class="infobox">
<value name="warnings"/>
<value name="errors"/>
</container>
list
separator
Separator elements for list are added after any list item in the
output with the exception of the last one.
Example specification, HTML template and output:
<specification>
<list name="list" iterator="tokens">
<param name="key"/>
<separator name="sep"/>
</list>
</specification>
<div class="list"><span class="key">KEY</span></div><span class="sep"> | </span>
<div class="list"><span class="key">FOO</span></div><span class="sep"> | </span>
<div class="list"><span class="key">BAR</span></div>
param
Param elements are replaced with the corresponding value from the
list iterator.
The following operations are supported for param elements:
append
Appends the param value to the text found in the HTML template.
prepend
Prepends the param value to the text found in the HTML template.
target
The attribute to operate on. See below target for value for
details.
toggle
When the args attribute is set to tree, it doesn't interpolate
anything and just shows corresponding HTML element if param value
is set.
With target attribute, it simply toggles the target attribute.
Otherwise, if value is true, shows the HTML element and set its
content to the value. If value is false, removes the HTML element.
So, if your element has children elements, you probably want to use
the args="tree" attribute (see below for an example).
Other attributes for param elements are:
filter
Applies filter to param value.
increment
Uses value from increment instead of a value from the iterator.
<param name="pos" increment="1">
value
Value elements are replaced with a single value present in the values
hash passed to the constructor of this class or later set with the
set_values method.
The following operations are supported for value elements:
append
Appends the value to the text found in the HTML template.
prepend
Prepends the value to the text found in the HTML template.
hook
Insert HTML residing in value as subtree of the corresponding HTML
element. HTML will be parsed with XML::Twig. See "INSERT HTML" for
an example.
keep
Preserves the text inside of the HTML element if value is false in
the Perl sense.
toggle
Only shows corresponding HTML element if value is set.
Other attributes for value elements are:
target
Specify the attribute to operate on instead of the tag content. It
can be a named attribute (e.g., href), the wildcard character(*,
meaning all the attributes found in the HTML template), or a comma
separated list (e.g., alt,title).
filter
Applies filter to value.
include
Processes the template file named in this attribute. This implies
the hook operation. See "INCLUDE FILES" for more information.
form
Form elements are tied through specification to HTML forms.
Attributes for form elements in addition to class and id are:
link
The link attribute can only have the value name and allows to base
the relationship between form specification elements and HTML form
tags on the name HTML attribute instead of class, which is usually
more convenient.
input
filter
sort
i18n
skip
This attribute (which can be provided to param or value specification
elements) supports the following values:
empty
Do not replace the template string if the value or parameter is
undefined, empty or just whitespace.
E.g.
<value name="cartline" skip="empty"/>
<list name="items" iterator="items">
<param name="category" skip="empty"/>
</list>
pattern
You can define patterns in your specification to interpolate the
strings instead of replacing them.
A pattern is defined by the attributes name and type and its content.
type can be only string or regexp.
The interpolation happens if the value and param elements of the
specification have an attribute pattern set with the pattern's name.
Given this HTML:
<p class="cartline">There are 123 items in your shopping cart.</p>
<ul>
<li class="items">
<span class="number">1</span>
<span class="category">in category 123</span>
</li>
</ul>
And this specification:
<specification>
<pattern name="pxt" type="string">123</pattern>
<list name="items" iterator="items">
<param name="number"/>
<param name="category" pattern="pxt"/>
</list>
<value name="cartline" pattern="pxt"/>
</specification>
In this example, in the cartline and category classes' text, only the
template text "123" will be replaced by the value, not the whole
element content, yielding such output:
<p class="cartline">There are 42 items in your shopping cart.</p>
<ul>
<li class="items">
<span class="number">1</span>
<span class="category">in category tofu</span>
</li>
<li class="items">
<span class="number">2</span>
<span class="category">in category pizza</span>
</li>
</ul>
Note: All matches of the pattern are subject to replacement, starting
with version 0.025.
SIMPLE OPERATORS
append
Appends the value to the text inside a HTML element or to an attribute
if target has been specified. This can be used in value and param
specification elements.
The example shows how to add a HTML class to elements in a list:
HTML:
<ul class="nav-sub">
<li class="category"><a href="" class="catname">Medicine</a></li>
</ul>
XML:
<specification>
<list name="category" iterator="categories">
<param name="name" class="catname"/>
<param name="catname" field="uri" target="href"/>
<param name="css" class="catname" target="class" op="append" joiner=" "/>
</list>
</specification>
CONTAINERS
Conditional processing like IF or ELSE is done with the help of
containers.
Display image only if present
In this example we want to show an image only on a certain condition:
HTML:
<span class="banner-box">
<img class="banner" src=""/>
</span>
XML:
<container name="banner-box" value="banner">
<value name="banner" target="src"/>
</container>
Source code:
if ($organization eq 'Big One') {
$values{banner} = 'banners/big_one.png';
}
Display link in a list only if present
In this example we want so show a link only if an URL is available:
HTML:
<div class="linklist">
<span class="name">Name</span>
<div class="link">
<a href="#" class="url">Goto ...</a>
</div>
</div>
XML:
<specification name="link">
<list name="links" class="linklist" iterator="links">
<param name="name"/>
<param name="url" target="href"/>
<container name="link" class="link" value="url"/>
</list>
</specification>
Source code:
@records = ({name => 'Link', url => 'http://localhost/'},
{name => 'No Link'},
{name => 'Another Link', url => 'http://localhost/'},
);
$flute = Template::Flute->new(specification => $spec_xml,
template => $template,
iterators => {links => \@records});
$output = $flute->process();
ITERATORS
Template::Flute uses iterators to retrieve list elements and insert
them into the document tree. This abstraction relieves us from worrying
about where the data actually comes from. We basically just need an
array of hash references and an iterator class with a next and a count
method. For your convenience you can create an iterator from
Template::Flute::Iterator class very easily.
DROPDOWNS
Iterators can be used for dropdowns (HTML <select> elements) as well.
Template:
<select class="color"></select>
Specification:
<value name="color" iterator="colors"/>
Code:
@colors = ({value => 'red', label => 'Red'},
{value => 'black', label => 'Black'});
$flute = Template::Flute->new(template => $html,
specification => $spec,
iterators => {colors => \@colors},
values => {color => 'black'},
);
HTML output:
<select class="color">
<option value="red">Red</option>
<option value="black" selected="selected">Black</option>
</select>
Default value for dropdowns
You can specify the dropdown item which is selected by default with the
iterator_default) attribute.
Template:
<select class="color"></select>
Specification:
<value name="color" iterator="colors" iterator_default="black"/>
Code:
@colors = ({value => 'red', label => 'Red'},
{value => 'black', label => 'Black'});
$flute = Template::Flute->new(template => $html,
specification => $spec,
iterators => {colors => \@colors},
);
HTML output:
<select class="color">
<option value="red">Red</option>
<option value="black" selected="selected">Black</option>
</select>
Custom iterators for dropdowns
By default, the iterator for a dropdown is an arrayref of hashrefs with
two hardcoded keys: value and (optionally) label. You can override this
behaviour in the specification with iterator_value_key and
iterator_name_key to use your own hashref's keys from the iterator,
instead of value and label.
Specification:
<specification>
<value name="color" iterator="colors"
iterator_value_key="code" iterator_name_key="name"/>
</specification>
Template:
<html>
<select class="color">
<option value="example">Example</option>
</select>
</html>
Code:
@colors = ({code => 'red', name => 'Red'},
{code => 'black', name => 'Black'},
);
$flute = Template::Flute->new(template => $html,
specification => $spec,
iterators => {colors => \@colors},
values => { color => 'black' },
);
$out = $flute->process();
Output:
<html>
<head></head>
<body>
<select class="color">
<option value="red">Red</option>
<option selected="selected" value="black">Black</option>
</select>
</body>
</html>
Limit lists
Sometimes you may wish to limit the number or iterations through you
list.
Specification:
<specification>
<list name="images" iterator="images" limit="1">
<param name="image" target="src" field="image_url" />
</list>
</specification>
Template:
<div class="images">
<img class="image" src="/images/bottle.jpg" />
</div>
Code:
$images = [
{ image_url => '/images/bottle1.jpg' },
{ image_url => '/images/bottle2.jpg' },
{ image_url => '/images/bottle3.jpg' },
];
$flute = Template::Flute->new(
template => $html,
specification => $spec,
values => { images => $images },
);
$out = $flute->process;
Output:
<html><head></head><body>
<div class="images">
<img class="image" src="/images/bottle1.jpg" />
</div>
</body></html>
LISTS
Lists can be accessed after parsing the specification and the HTML
template through the HTML template object:
$flute->template->lists();
$flute->template->list('cart');
Only lists present in the specification and the HTML template can be
addressed in this way.
See Template::Flute::List for details about lists.
OBJECTS AND STRUCTURES
You can pass objects and hashrefs as values. To access a key or an
accessor, you have to use a dotted notation with field. An example for
both hashrefs and objects follows.
Specification:
<specification>
<value name="object" field="myobject.method" />
<value name="struct" field="mystruct.key" />
</specification>
HTML:
<html>
<body>
<span class="object">Welcome back!</span>
<span class="struct">Another one</span>
</body>
</html>
Code:
package My::Object;
sub new {
my $class = shift;
bless {}, $class;
}
sub method {
return "Hello from the method";
}
package main;
my $flute = Template::Flute->new(
specification => $spec,
template => $html,
values => {
myobject => My::Object->new,
mystruct => { key => "Hello from hash" },
}
);
process will return:
<html>
<head></head>
<body>
<span class="object">Hello from the method</span>
<span class="struct">Hello from hash</span>
</body>
</html>
Sometimes you need to treat an object like an hashref. How to do that
is explained under the autodetect option for the constructor.
FORMS
Forms can be accessed after parsing the specification and the HTML
template through the HTML template object:
$flute->template->forms();
$flute->template->form('edit_content');
Only forms present in the specification and the HTML template can be
addressed in this way.
See Template::Flute::Form for details about forms.
FILTERS
Filters are used to change the display of value and param elements in
the resulting HTML output:
<value name="billing_address" filter="eol"/>
<param name="price" filter="currency"/>
The following filters are included:
upper
Uppercase filter, see Template::Flute::Filter::Upper.
strip
Strips whitespace at the beginning at the end, see
Template::Flute::Filter::Strip.
eol
Filter preserving line breaks, see Template::Flute::Filter::Eol.
nobreak_single
Filter replacing missing text with no-break space, see
Template::Flute::Filter::NobreakSingle.
currency
Currency filter, see Template::Flute::Filter::Currency. Requires
Number::Format module.
date
Date filter, see Template::Flute::Filter::Date. Requires DateTime and
DateTime::Format::ISO8601 modules.
country_name
Country name filter, see Template::Flute::Filter::CountryName.
Requires Locales module.
language_name
Language name filter, see Template::Flute::Filter::LanguageName.
Requires Locales module.
json_var
JSON to Javascript variable filter, see
Template::Flute::Filter::JsonVar. Requires JSON module.
lower_dash
Replaces spaces with dashes (-) and makes lowercase. see
Template::Flute::Filter::LowerDash.
markdown
Turns text in Markdown format into HTML. see
Template::Flute::Filter::Markdown.
Requires Text::Markdown and HTML::Scrubber modules.
Filter classes are loaded at runtime for efficiency and to keep the
number of dependencies for Template::Flute as small as possible.
See above for prerequisites needed by the included filter classes.
Chained Filters
Filters can also be chained:
<value name="note" filter="upper eol"/>
Example template:
<div class="note">
This is a note.
</div>