1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3 * Copyright (C) 2009 Emweb bv, Herent, Belgium.
4 *
5 * See the LICENSE file for terms of use.
6 */
7 #ifndef WTEMPLATE_H_
8 #define WTEMPLATE_H_
9
10 #include <Wt/WInteractWidget.h>
11 #include <Wt/WString.h>
12
13 namespace Wt {
14
15 class EscapeOStream;
16
17 /*! \brief Enumeration that indicates how a widget's ID may be set.
18 *
19 * \sa setWidgetIdMode()
20 */
21 enum class TemplateWidgetIdMode {
22 /*!
23 * Do not set the widget ID.
24 */
25 None,
26
27 /*!
28 * Use setObjectName() to add a 'data-object-name' attribute. This is
29 * a safe choice since it does not affect the ID.
30 */
31 SetObjectName,
32
33 /*!
34 * Use setId() to set the ID as the varName.
35 *
36 * \warning You must be careful that there are no two widgets with
37 * the same ID in yor application.
38 */
39 SetId
40 };
41
42 /*! \class WTemplate Wt/WTemplate.h Wt/WTemplate.h
43 * \brief A widget that renders an XHTML template.
44 *
45 * The XHTML template may contain references to variables which
46 * replaced by strings are widgets.
47 *
48 * Since the template text may be supplied by a WString, you can
49 * conveniently store the string in a message resource bundle, and
50 * make it localized by using WString::tr().
51 *
52 * Placeholders (for variables and functions) are delimited by:
53 * <tt>${...}</tt>. To use a literal <tt>"${"</tt>, use
54 * <tt>"$${"</tt>.
55 * Place holder names can contain '_', '-', '.' and alfanumeric characters.
56 *
57 * Usage example:
58 * \if cpp
59 * \code
60 * WString userName = ...;
61 *
62 * auto t = std::make_unique<WTemplate>();
63 * t->setTemplateText("<div> How old are you, ${friend} ? ${age-input} </div>");
64 *
65 * t->bindString("friend", userName, TextFormat::Plain);
66 * ageEdit_ = t->bindWidget("age-input", std::make_unique<WLineEdit>());
67 * \endcode
68 * \elseif java
69 * \code
70 * WString userName = ...;
71 *
72 * WTemplate t = new WTemplate();
73 * t.setTemplateText("<div> How old are you, ${friend} ? ${age-input} </div>");
74 *
75 * t.bindString("friend", userName, TextFormat::Plain);
76 * t.bindWidget("age-input", ageEdit_ = new WLineEdit());
77 * \endcode
78 * \endif
79 *
80 * There are currently three syntactic constructs defined: variable
81 * place holders, functions and conditional blocks.
82 *
83 * <h3>A. Variable placeholders</h3>
84 *
85 * <tt>${var}</tt> defines a placeholder for the variable "var", and
86 * gets replaced with whatever is bound to that variable:
87 * - a widget, using bindWidget()
88 * - a string value, using bindString() or bindInt()
89 * - or in general, the result of resolveString() and resolveWidget()
90 * methods.
91 *
92 * Optionally, additional arguments can be specified using the following
93 * syntax:
94 *
95 * <tt>${var arg1="A value" arg2='A second value'}</tt>
96 *
97 * The arguments can thus be simple strings or quoted strings
98 * (single or double quoted). These arguments are applied to a
99 * resolved widget in applyArguments() and currently supports only
100 * style classes.
101 *
102 * You can bind widgets and values to variables using bindWidget(),
103 * bindString() or bindInt() or by reimplementing the resolveString()
104 * and resolveWidget() methods.
105 *
106 * \note The use of XML comments (<tt><!\-- ... \--></tt>)
107 * around variables that are bound to widgets will result in bad
108 * behaviour since the template parser is ignorant about these
109 * comments and the corresponding widgets will believe that they
110 * are rendered but aren't actually.
111 *
112 * <h3>B. %Functions</h3>
113 *
114 * <tt>${fun:arg}</tt> defines a placeholder for applying a function
115 * "fun" to an argument "arg".
116 *
117 * Optionally, additional arguments can be specified as with a
118 * variable placeholder.
119 *
120 * Functions are resolved by resolveFunction(), and the default implementation
121 * considers functions bound with addFunction().
122 * There are currently three functions that are generally useful:
123 * - \link Functions::tr\endlink : resolves a localized strings, this is
124 * convenient to create a language neutral template, which contains
125 * translated strings
126 * - \link Functions::id\endlink : resolves the id of a bound widget, this
127 * is convenient to bind <label> elements to a form widget using its
128 * for attribute.
129 * - \link Functions::block\endlink : recursively renders another string as
130 * macro block optional arguments substituted before processing template
131 * substitution.
132 *
133 * For example, the following template uses the "tr" function to translate
134 * the age-label using the "age-label" internationalized key.
135 *
136 * \if cpp
137 * \code
138 * auto t = std::make_unique<WTemplate>();
139 * t->addFunction("tr", &WTemplate::Functions::tr);
140 * t->setTemplateText("<div> ${tr:age-label} ${age-input} </div>");
141 * ageEdit_ = t->bindWidget("age-input", std::make_unique<WLineEdit>());
142 * \endcode
143 * \elseif java
144 * \code
145 * WTemplate t = new WTemplate();
146 * t.setTemplateText("<div> ${tr:age-label} ${age-input} </div>");
147 * t.addFunction("tr", WTemplate.Functions.tr);
148 * t.bindWidget("age-input", ageEdit = new WLineEdit());
149 * \endcode
150 * \endif
151 *
152 * <h3>C. Conditional blocks</h3>
153 *
154 * <tt>${<cond>}</tt> starts a conditional block with a condition name
155 * "cond", and must be closed by a balanced <tt>${</cond>}</tt>.
156 *
157 * For example:
158 * \if cpp
159 * \code
160 * auto t = std::make_unique<WTemplate>();
161 * t->setTemplateText("<div> ${<if-register>} Register ... ${</if-register>}</div>");
162 * t->setCondition("if-register", true);
163 * \endcode
164 * \elseif java
165 * \code
166 * WTemplate t = new WTemplate();
167 * t.setTemplateText("<div> ${<if-register>} Register ... ${</if-register>}</div>");
168 * t.setCondition("if-register", true);
169 * \endcode
170 * \endif
171 *
172 * Conditions are set using setCondition().
173 *
174 * \if cpp
175 * The template can return a bound widget using resolve(), which already
176 * tries to cast the widget to the proper type.
177 * \endif
178 *
179 * <h3>CSS</h3>
180 *
181 * This widget does not provide styling,
182 * and can be styled using inline or external CSS as appropriate.
183 */
184 class WT_API WTemplate : public WInteractWidget
185 {
186 private:
187 bool _tr(const std::vector<WString>& args,
188 std::ostream& result);
189 bool _block(const std::vector<WString>& args,
190 std::ostream& result);
191 bool _while(const std::vector<WString>& args,
192 std::ostream& result);
193 bool _id(const std::vector<WString>& args,
194 std::ostream& result);
195
196 public:
197 /*! \brief Typedef for enum Wt::TemplateWidgetIdMode */
198 typedef TemplateWidgetIdMode WidgetIdMode;
199
200 #ifndef WT_TARGET_JAVA
201 /*! \brief A function type
202 *
203 * \sa addFunction()
204 * \sa Functions::tr, Functions::id, Functions::block, Functions::while_f
205 */
206 typedef std::function<bool(WTemplate *t, const std::vector<WString>& args,
207 std::ostream& result)> Function;
208
209 #else
210 /*! \brief A function interface type
211 *
212 * \sa addFunction()
213 * \sa Functions::tr, Functions::id, Functions::block, Functions::while_f
214 */
215 class Function {
216 public:
217 virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
218 std::ostream& result) const = 0;
219
220 };
221
222 private:
223 class TrFunction : public Function {
224 public:
225 virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
226 std::ostream& result) const;
227 };
228
229 class BlockFunction : public Function {
230 public:
231 virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
232 std::ostream& result) const;
233 };
234
235 class WhileFunction : public Function {
236 public:
237 virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
238 std::ostream& result) const;
239 };
240
241 class IdFunction : public Function {
242 public:
243 virtual bool evaluate(WTemplate *t, const std::vector<WString>& args,
244 std::ostream& result) const;
245 };
246 public:
247 #endif
248 /*! \brief A collection of predefined functions
249 *
250 * \sa addFunction()
251 */
252 struct WT_API Functions
253 {
254 /*! \brief A function that resolves to a localized string.
255 *
256 * For example, when bound to the function <tt>"tr"</tt>, template
257 * that contains the placeholder
258 * \code
259 * ... ${tr:name} ...
260 * \endcode
261 * will be resolved to the value of:
262 * \code
263 * WString::tr("name")
264 * \endcode
265 *
266 * \sa addFunction()
267 */
268 #ifndef WT_TARGET_JAVA
269 static bool tr(WTemplate *t, const std::vector<WString>& args,
270 std::ostream& result);
271 #else
272 static Function& tr = TrFunction();
273 #endif
274
275 /*! \brief A function that renders a macro block.
276 *
277 * The function will consider the first argument as the key
278 * for a localized string that is a macro block, and additional arguments
279 * as positional parameters in that block.
280 *
281 * For example, a template that contains:
282 * \code
283 * ...
284 * ${block:form-field category}
285 * ...
286 * \endcode
287 *
288 * would look-up the following message:
289 *
290 * \code
291 * <message id="form-field">
292 * <div class="control-group">
293 * ${{1}-info}
294 * </div>
295 * </message>
296 * \endcode
297 *
298 * and render as:
299 *
300 * \code
301 * ...
302 * <div class="control-group">
303 * ${category-info}
304 * </div>
305 * ...
306 * \endcode
307 */
308 #ifndef WT_TARGET_JAVA
309 static bool block(WTemplate *t, const std::vector<WString>& args,
310 std::ostream& result);
311 #else
312 static Function& block = BlockFunction();
313 #endif
314
315 /*! \brief A function that renders a macro block as long as the given condition is true
316 *
317 * The function will consider the first argument as the condition, and the
318 * second argument as the key for a localized string that is a macro block.
319 *
320 * Just like the block() function, you can provide additional arguments, so the third
321 * argument will be what is filled in into <tt>{1}</tt> in the macro block, etc.
322 */
323 #ifndef WT_TARGET_JAVA
324 static bool while_f(WTemplate *t, const std::vector<WString>& args,
325 std::ostream& result);
326 #else
327 static Function& while_f = WhileFunction();
328 #endif
329
330 /*! \brief A function that resolves the id of a bound widget
331 *
332 * For example, when bound to the function <tt>"id"</tt>, template text
333 * that contains a place-holder
334 * \code
335 * ... ${id:name} ...
336 * \endcode
337 *
338 * will be resolved to the value of:
339 * \if cpp
340 * \code
341 * t->resolveWidget("name")->id()
342 * \endcode
343 * \elseif java
344 * \code
345 * t.resolveWidget("name").id()
346 * \endcode
347 * \endif
348 *
349 * This is useful for binding labels to input elements.
350 *
351 * \sa addFunction()
352 */
353 #ifndef WT_TARGET_JAVA
354 static bool id(WTemplate *t, const std::vector<WString>& args,
355 std::ostream& result);
356 #else
357 static Function& id = IdFunction();
358 #endif // WT_TARGET_JAVA
359 };
360
361 /*! \brief Creates a template widget.
362 */
363 WTemplate();
364
365 /*! \brief Creates a template widget with given template.
366 *
367 * The \p templateText must be proper XHTML, and this is checked
368 * unless the XHTML is resolved from a message resource bundle. This
369 * behavior is similar to a WText when configured with the
370 * Wt::TextFormat::XHTML textformat.
371 */
372 WTemplate(const WString& text);
373
374 virtual ~WTemplate();
375
376 /*! \brief Returns the template.
377 *
378 * \sa setTemplateText()
379 */
templateText()380 virtual WString templateText() const { return text_; }
381
382 /*! \brief Sets the template text.
383 *
384 * The \p text must be proper XHTML, and this is checked unless the
385 * XHTML is resolved from a message resource bundle or TextFormat is
386 * Wt::TextFormat::UnsafeXHTML. This behavior is similar to a WText when
387 * configured with the Wt::TextFormat::XHTML textformat.
388 *
389 * Changing the template text does not clear() bound widgets or
390 * values.
391 *
392 * \sa clear()
393 */
394 void setTemplateText(const WString& text,
395 TextFormat textFormat = TextFormat::XHTML);
396
397 /*! \brief Sets how the varName should be reflected on bound widgets.
398 *
399 * To easily identify a widget in the browser, it may be convenient
400 * to reflect the varName, either through the object name (recommended)
401 * or the widget's ID.
402 *
403 * The default value is TemplateWidgetIdMode::None which does not reflect the
404 * varName on the bound widget.
405 */
406 void setWidgetIdMode(TemplateWidgetIdMode mode);
407
408 /*! \brief Returns how the varName is reflected on a bound widget.
409 *
410 * \sa setWidgetIdMode()
411 */
widgetIdMode()412 TemplateWidgetIdMode widgetIdMode() const { return widgetIdMode_; }
413
414 /*! \brief Binds a string value to a variable.
415 *
416 * Each occurrence of the variable within the template will be
417 * substituted by its value.
418 *
419 * \note Depending on the \p textFormat, the \p value is validated according
420 * as for a WText. The default (TextFormat::XHTML) filters "active" content, to avoid
421 * XSS-based security risks.
422 *
423 * \sa bindWidget(), bindInt()
424 * \sa resolveString()
425 */
426 virtual void bindString(const std::string& varName, const WString& value,
427 TextFormat textFormat = TextFormat::XHTML);
428
429 /*! \brief Binds an integer value to a variable.
430 *
431 * \sa bindString()
432 */
433 void bindInt(const std::string& varName, int value);
434
435 /*! \brief Binds a widget to a variable.
436 *
437 * The corresponding variable reference within the template will be
438 * replaced with the widget (rendered as XHTML). Since a single
439 * widget may be instantiated only once in a template, the variable
440 * \p varName may occur at most once in the template, and the
441 * \p widget must not yet be bound to another variable.
442 *
443 * The widget is reparented to the WTemplate, so that it is deleted
444 * when the WTemplate is deleted.
445 *
446 * If a widget was already bound to the variable, it is deleted
447 * first. If previously a string or other value was bound to the
448 * variable, it is removed.
449 *
450 * You may also pass a \c nullptr \p widget, which will resolve to an empty
451 * string.
452 *
453 * \sa bindString()
454 * \sa resolveWidget()
455 */
456 virtual
457 #ifndef WT_TARGET_JAVA
458 void
459 #else // WT_TARGET_JAVA
460 WWidget*
461 #endif // WT_TARGET_JAVA
462 bindWidget(const std::string& varName,
463 std::unique_ptr<WWidget> widget);
464
465 /*! \brief Binds a widget to a variable, returning a raw pointer.
466 *
467 * This is implemented as:
468 *
469 * \code
470 * Widget *result = widget.get();
471 * bindWidget(varName, std::unique_ptr<WWidget>(std::move(widget)));
472 * return result;
473 * \endcode
474 */
475 template <typename Widget>
bindWidget(const std::string & varName,std::unique_ptr<Widget> widget)476 Widget *bindWidget(const std::string& varName,
477 std::unique_ptr<Widget> widget)
478 #ifndef WT_TARGET_JAVA
479 {
480 Widget *result = widget.get();
481 bindWidget(varName, std::unique_ptr<WWidget>(std::move(widget)));
482 return result;
483 }
484 #else // WT_TARGET_JAVA
485 ;
486 #endif // WT_TARGET_JAVA
487
488 #ifndef WT_TARGET_JAVA
489 /*! \brief Creates a new widget with the given arguments, and binds it, returning a raw pointer.
490 *
491 * This is implemented as:
492 *
493 * \code
494 * std::unique_ptr<Widget> w{new Widget(std::forward<Args>(args)...)};
495 * Widget *result = w.get();
496 * bindWidget(varName, std::unique_ptr<WWidget>(std::move(w)));
497 * return result;
498 * \endcode
499 *
500 * This is a useful shorthand for creating and binding a widget in one go.
501 */
502 template <typename Widget, typename ...Args>
bindNew(const std::string & varName,Args &&...args)503 Widget *bindNew(const std::string& varName,
504 Args&& ...args)
505 {
506 std::unique_ptr<Widget> w{new Widget(std::forward<Args>(args)...)};
507 Widget *result = w.get();
508 bindWidget(varName, std::unique_ptr<WWidget>(std::move(w)));
509 return result;
510 }
511 #else // WT_TARGET_JAVA
512 template <typename Widget>
513 Widget *bindNew(const std::string& varName);
514 template <typename Widget, typename Arg1>
515 Widget *bindNew(const std::string& varName, Arg1 arg1);
516 template <typename Widget, typename Arg1, typename Arg2>
517 Widget *bindNew(const std::string& varName, Arg1 arg1, Arg2 arg2);
518 template <typename Widget, typename Arg1, typename Arg2, typename Arg3>
519 Widget *bindNew(const std::string& varName, Arg1 arg1, Arg2 arg2, Arg3 arg3);
520 template <typename Widget, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
521 Widget *bindNew(const std::string& varName, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4);
522 #endif // WT_TARGET_JAVA
523
524 using WWidget::removeWidget;
525
526 /*! \brief Unbinds a widget by variable name.
527 *
528 * This removes a previously bound widget and unbinds the
529 * corresponding variable, effectively undoing the effect of
530 * bindWidget().
531 *
532 * If this template does not contain a widget for the given
533 * \p varName, \c nullptr is returned.
534 */
535 std::unique_ptr<WWidget> removeWidget(const std::string& varName);
536
537 /*! \brief Unbinds a widget by widget pointer.
538 *
539 * This removes a previously bound widget and unbinds the
540 * corresponding variable, effectively undoing the effect of
541 * bindWidget().
542 *
543 * If this template does not contain the given widget,
544 * \c nullptr is returned.
545 */
546 virtual std::unique_ptr<WWidget> removeWidget(WWidget *widget) override;
547
548 /*! \brief Binds an empty string to a variable.
549 *
550 * If a widget was bound to the variable, it is deleted first.
551 *
552 * \sa bindString()
553 */
554 void bindEmpty(const std::string& varName);
555
556 /*! \brief Binds a function.
557 *
558 * Functions are useful to automatically resolve placeholders.
559 *
560 * The syntax for a function 'fun' applied to a single argument
561 * 'bla' is:
562 *
563 * <tt>${fun:bla}</tt>
564 *
565 * There are three predefined functions, which can be bound using:
566 * \if cpp
567 * \code
568 * WTemplate *t = ...;
569 * t->addFunction("id", &WTemplate::Functions::id);
570 * t->addFunction("tr", &WTemplate::Functions::tr);
571 * t->addFunction("block", &WTemplate::Functions::block);
572 * \endcode
573 * \else
574 * \code
575 * WTemplate t = ...;
576 * t.addFunction("id", WTemplate.Functions.id);
577 * t.addFunction("tr", WTemplate.Functions.tr);
578 * t.addFunction("block", WTemplate.Functions.block);
579 * \endcode
580 * \endif
581 */
582 #ifndef WT_TARGET_JAVA
583 void addFunction(const std::string& name, const Function& function);
584 #else
585 void addFunction(const std::string& name, const Function *function);
586 #endif
587
588 /*! \brief Sets a condition.
589 *
590 * This enables or disables the inclusion of a conditional block.
591 *
592 * The default value of all conditions is \c false.
593 */
594 void setCondition(const std::string& name, bool value);
595
596 /*! \brief Returns a condition value.
597 *
598 * \sa setCondition()
599 */
600 virtual bool conditionValue(const std::string& name) const;
601
602 /*! \brief Returns the set of conditions set to true.
603 */
conditionsSet()604 std::set<std::string> conditionsSet() { return conditions_; }
605
606 /*! \brief Resolves the string value for a variable name.
607 *
608 * This is the main method used to resolve variables in the template
609 * text, during rendering.
610 *
611 * The default implementation considers first whether a string was
612 * bound using bindString(). If so, that string is returned. If
613 * not, it will attempt to resolve a widget with that variable name
614 * using resolveWidget(), and render it as XHTML. If that fails too,
615 * handleUnresolvedVariable() is called, passing the initial arguments.
616 *
617 * You may want to reimplement this method to provide on-demand
618 * loading of strings for your template.
619 *
620 * The result stream expects a UTF-8 encoded string value.
621 *
622 * \warning When specializing this class, you need to make sure that
623 * you append proper XHTML to the \p result, without unsafe active
624 * contents. The format() methods may be used for this purpose.
625 *
626 * \sa renderTemplate()
627 */
628 virtual void resolveString(const std::string& varName,
629 const std::vector<WString>& args,
630 std::ostream& result);
631
632 /*! \brief Handles a variable that could not be resolved.
633 *
634 * This method is called from resolveString() for variables that could
635 * not be resolved.
636 *
637 * The default implementation implementation writes
638 * "??" + varName + "??" to the result stream.
639 *
640 * The result stream expects a UTF-8 encoded string value.
641 *
642 * \warning When specializing this class, you need to make sure that
643 * you append proper XHTML to the \p result, without unsafe active
644 * contents. The format() methods may be used for this purpose.
645 *
646 * \sa resolveString()
647 */
648 virtual void handleUnresolvedVariable(const std::string& varName,
649 const std::vector<WString>& args,
650 std::ostream& result);
651
652 /*! \brief Resolves a widget for a variable name.
653 *
654 * The default implementation returns a widget that was bound using
655 * bindWidget().
656 *
657 * You may want to reimplement this method to create widgets
658 * on-demand. All widgets that are returned by this method are
659 * reparented to the WTemplate, so they will be deleted when the
660 * template is destroyed, but they are not deleted by clear() (unless
661 * bind was called on them as in the example below).
662 *
663 * This method is typically used for delayed binding of widgets.
664 * Usage example:
665 * \if cpp
666 * \code
667 * if (Wt::WWidget *known = WTemplate::resolveWidget(varName)) {
668 * return known;
669 * } else {
670 * if (varName == "age-input") {
671 * // widget only created when used
672 * return bindWidget(varName, std::make_unique<Wt::WLineEdit>());
673 * }
674 * return nullptr;
675 * }
676 * \endcode
677 * \elseif java
678 * \code
679 * if (WWidget known = super.resolveWidget(varName)) {
680 * return known;
681 * } else {
682 * if (varName == "age-input") {
683 * WWidget w = new WLineEdit(); // widget only created when used
684 * bindWidget(varName, w);
685 * return w;
686 * }
687 * }
688 * \endcode
689 * \endif
690 */
691 virtual WWidget *resolveWidget(const std::string& varName);
692
693 std::vector<WWidget *> widgets() const;
694 std::string varName(WWidget *w) const;
695
696 /*! \brief Resolves a function call.
697 *
698 * This resolves a function with name \p name, and one or more arguments
699 * \p args, and writes the result into the stream \p result. The method
700 * returns whether a function was matched and applied.
701 *
702 * The default implementation considers functions that were bound
703 * using addFunction().
704 *
705 * \sa addFunction()
706 */
707 virtual bool resolveFunction(const std::string& name,
708 const std::vector<WString>& args,
709 std::ostream& result);
710
711 /*! \brief Returns a widget for a variable name.
712 *
713 * This is a convience method, which calls resolveWidget() and dynamic casts
714 * the result to type \p T. You may use this method to fetch widgets
715 * that have previously been bound using bindWidget().
716 *
717 * If the cast fails, a null pointer is returned.
718 */
719 template <typename T> T resolve(const std::string& varName);
720
721 /*! \brief Erases all variable bindings.
722 *
723 * Removes all strings and deletes all widgets that were previously
724 * bound using bindString() and bindWidget().
725 *
726 * This also resets all conditions set using setCondition(), but
727 * does not remove functions added with addFunction()
728 */
729 virtual void clear();
730
731 /*! \brief Enables internal path anchors in the XHTML template.
732 *
733 * Anchors to internal paths are represented differently depending
734 * on the session implementation (plain HTML, Ajax or HTML5
735 * history). By enabling this option, anchors which reference an
736 * internal path (by referring a URL of the form
737 * <tt>href="#/..."</tt>), are re-encoded to link to the internal
738 * path.
739 *
740 * The default value is \c false.
741 *
742 * \sa WAnchor::setRefInternalPath()
743 */
744 void setInternalPathEncoding(bool enabled);
745
746 /*! \brief Returns whether internal paths are enabled.
747 *
748 * \sa setInternalPathEncoding()
749 */
hasInternalPathEncoding()750 bool hasInternalPathEncoding() const { return encodeInternalPaths_; }
751
752 /*! \brief Configures when internal path encoding is done.
753 *
754 * By default, the internal path encoding (if enabled) is done on
755 * the template text before placeholders are being resolved. In some
756 * rare situations, you may want to postpone the internal path
757 * encoding until after placeholders have been resolved, e.g. if a
758 * placeholder was used to provide the string for an anchor href.
759 *
760 * The default value is \c true
761 */
762 void setEncodeTemplateText(bool on);
763
764 /*! \brief Returns whether internal path encoding is done on the template text.
765 * \sa setEncodeTemplateText()
766 */
encodeTemplateText()767 bool encodeTemplateText() const { return encodeTemplateText_; }
768
769 virtual void refresh() override;
770
771 /*! \brief Renders the template into the given result stream.
772 *
773 * The default implementation will call renderTemplateText() with the
774 * templateText().
775 */
776 virtual void renderTemplate(std::ostream& result);
777
778 /*! \brief Renders a template into the given result stream.
779 *
780 * The default implementation will parse the template, and resolve variables
781 * by calling resolveString().
782 *
783 * You may want to reimplement this method to manage resources that are
784 * needed to load content on-demand (e.g. database objects), or support
785 * a custom template language.
786 *
787 * Return: true if rendered successfully.
788 * \sa getErrorText()
789 */
790 bool renderTemplateText(std::ostream& result, const WString& templateText);
791
792 /*! \brief Renders the errors during renderring.
793 * \sa renderTemplateText()
794 */
getErrorText()795 std::string getErrorText() {return errorText_;}
796
797 protected:
798 /*! \brief Applies arguments to a resolved widget.
799 *
800 * Currently only a <tt>class</tt> argument is handled, which adds
801 * one or more style classes to the widget \p w, using
802 * WWidget::addStyleClass().
803 */
804 virtual void applyArguments(WWidget *w, const std::vector<WString>& args);
805
806 virtual void updateDom(DomElement& element, bool all) override;
807 virtual DomElementType domElementType() const override;
808 virtual void propagateRenderOk(bool deep) override;
809 virtual void iterateChildren(const HandleWidgetMethod& method) const override;
810
811 /*! \brief Utility method to safely format an XHTML string.
812 *
813 * The string is formatted according to the indicated \p
814 * textFormat. It is recommended to use this method when
815 * specializing resolveString() to avoid security risks.
816 */
817 void format(std::ostream& result, const std::string& s,
818 TextFormat textFormat = TextFormat::Plain);
819
820 /*! \brief Utility method to safely format an XHTML string.
821 *
822 * The string is formatted according to the indicated \p
823 * textFormat. It is recommended to use this method when
824 * specializing resolveString() to avoid security risks.
825 */
826 void format(std::ostream& result, const WString& s,
827 TextFormat textFormat = TextFormat::Plain);
828
829 virtual void enableAjax() override;
830
831 /*! \brief Notifies the template that it has changed and must be rerendered.
832 *
833 * If you update a WTemplate with e.g bindWidget or setCondition,
834 * or change the template text, the template will automatically be
835 * rerendered.
836 *
837 * However, if you create a subclass of WTemplate and override resolveString or
838 * resolveWidget, you will have to notify the WTemplate if it has changed with
839 * a call to reset().
840 */
841 void reset();
842
843 private:
844 typedef std::map<std::string, Function> FunctionMap;
845 typedef std::map<std::string, WString> StringMap;
846 typedef std::map<std::string, std::unique_ptr<WWidget> > WidgetMap;
847 typedef std::set<std::string> ConditionSet;
848
849 std::set<WWidget *> *previouslyRendered_;
850 std::vector<WWidget *> *newlyRendered_;
851
852 FunctionMap functions_;
853 StringMap strings_;
854 WidgetMap widgets_;
855 ConditionSet conditions_;
856
857 WString text_;
858 std::string errorText_;
859
860 bool encodeInternalPaths_, encodeTemplateText_, changed_;
861 TemplateWidgetIdMode widgetIdMode_;
862
863 std::string encode(const std::string& text) const;
864 static std::size_t parseArgs(const std::string& text,
865 std::size_t pos,
866 std::vector<WString>& result);
867 void unrenderWidget(WWidget *w, DomElement &el);
868
869 EscapeOStream* plainTextNewLineEscStream_;
870 };
871
resolve(const std::string & varName)872 template <typename T> T WTemplate::resolve(const std::string& varName)
873 {
874 WWidget *w = resolveWidget(varName);
875 return dynamic_cast<T>(w);
876 }
877
878
879 }
880
881 #endif // WTEMPLATE_H_
882