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>&lt;!\-- ... \--&gt;</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 &lt;label&gt; 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>${&lt;cond&gt;}</tt> starts a conditional block with a condition name
155  * "cond", and must be closed by a balanced <tt>${&lt;/cond&gt;}</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