1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  */
7 #ifndef WWEB_WIDGET_H_
8 #define WWEB_WIDGET_H_
9 
10 #include <set>
11 #include <bitset>
12 
13 #include <Wt/WString.h>
14 #include <Wt/WWidget.h>
15 #include <Wt/WEvent.h>
16 
17 #ifdef WT_CNOR
18 #include <Wt/WJavaScript.h>
19 #endif // WT_CNOR
20 
21 namespace Wt {
22 
23 class WStringStream;
24 class WApplication;
25 
26 /*! \brief Enumeration for a DOM element type.
27  *
28  * For internal use only.
29  */
30 enum class DomElementType {
31   A, BR, BUTTON, COL,
32   COLGROUP,
33   DIV, FIELDSET, FORM,
34   H1, H2, H3, H4,
35 
36   H5, H6, IFRAME, IMG,
37   INPUT, LABEL, LEGEND, LI,
38   OL,
39 
40   OPTION, UL, SCRIPT, SELECT,
41   SPAN, TABLE, TBODY, THEAD,
42   TFOOT, TH, TD, TEXTAREA,
43   OPTGROUP,
44 
45   TR, P, CANVAS,
46   MAP, AREA, STYLE,
47 
48   OBJECT, PARAM,
49 
50   AUDIO, VIDEO, SOURCE,
51 
52   B, STRONG, EM, I, HR,
53   UNKNOWN,
54   OTHER
55 };
56 
57 class WCssDecorationStyle;
58 class WContainerWidget;
59 class DomElement;
60 
61 #ifndef WT_CNOR
62 template <typename... A> class JSignal;
63 #endif
64 
65 #ifdef WT_TARGET_JAVA
66 struct HandleWidgetMethod {
67   HandleWidgetMethod();
68   HandleWidgetMethod(void (*)(WWidget*));
69   void handle(WWidget *) const;
70 };
71 #endif // WT_TARGET_JAVA
72 
73 /*! \class WWebWidget Wt/WWebWidget.h Wt/WWebWidget.h
74  *  \brief A base class for widgets with an HTML counterpart.
75  *
76  * All descendants of %WWebWidget implement a widget which corresponds
77  * almost one-on-one with an HTML element. These widgets provide most
78  * capabilities of these HTML elements, but rarely make no attempt to
79  * do anything more.
80  *
81  * \sa WCompositeWidget
82  */
83 class WT_API WWebWidget : public WWidget
84 {
85 public:
86   /*! \brief Construct a WebWidget.
87    */
88   WWebWidget();
89   virtual ~WWebWidget() override;
90 
91   virtual std::vector<WWidget *> children() const override;
92 
93   /*! \brief %Signal emitted when children have been added or removed.
94    *
95    * \sa children()
96    */
97   Signal<>& childrenChanged();
98 
99   virtual void setPositionScheme(PositionScheme scheme) override;
100   virtual PositionScheme positionScheme() const override;
101   virtual void setOffsets(const WLength& offset,
102 			  WFlags<Side> sides = AllSides) override;
103   virtual WLength offset(Side s) const override;
104   virtual void resize(const WLength& width, const WLength& height) override;
105   virtual WLength width() const override;
106   virtual WLength height() const override;
107   virtual void setMinimumSize(const WLength& width, const WLength& height) override;
108   virtual WLength minimumWidth() const override;
109   virtual WLength minimumHeight() const override;
110   virtual void setMaximumSize(const WLength& width, const WLength& height) override;
111   virtual WLength maximumWidth() const override;
112   virtual WLength maximumHeight() const override;
113   virtual void setLineHeight(const WLength& height) override;
114   virtual WLength lineHeight() const override;
115   virtual void setFloatSide(Side s) override;
116   virtual Side floatSide() const override;
117   virtual void setClearSides(WFlags<Side> sides) override;
118   virtual WFlags<Side> clearSides() const override;
119   virtual void setMargin(const WLength& margin, WFlags<Side> sides = AllSides)
120     override;
121   virtual WLength margin(Side side) const override;
122   virtual void setHiddenKeepsGeometry(bool enabled) override;
123   virtual bool hiddenKeepsGeometry() const override;
124   virtual void setHidden(bool hidden, const WAnimation& animation = WAnimation()) override;
125   virtual bool isHidden() const override;
126   virtual bool isVisible() const override;
127   virtual void setDisabled(bool disabled) override;
128   virtual bool isDisabled() const override;
129   virtual bool isEnabled() const override;
130   virtual void setPopup(bool popup) override;
131   virtual bool isPopup() const override;
132   virtual void setInline(bool isInline) override;
133   virtual bool isInline() const override;
134   virtual void setDecorationStyle(const WCssDecorationStyle& style) override;
135   virtual WCssDecorationStyle& decorationStyle() override;
136   virtual const WCssDecorationStyle& decorationStyle() const override;
137   virtual void setStyleClass(const WT_USTRING& styleClass) override;
138   void setStyleClass(const char *styleClass);
139   virtual WT_USTRING styleClass() const override;
140   virtual void addStyleClass(const WT_USTRING& styleClass,
141 			     bool force = false) override;
142   void addStyleClass(const char *styleClass, bool force = false);
143   virtual void removeStyleClass(const WT_USTRING& styleClass,
144 				bool force = false) override;
145   void removeStyleClass(const char *styleClass, bool force = false);
146   virtual bool hasStyleClass(const WT_USTRING& styleClass) const override;
147   virtual void setVerticalAlignment(AlignmentFlag alignment,
148 				    const WLength& length = WLength()) override;
149   virtual AlignmentFlag verticalAlignment() const override;
150   virtual WLength verticalAlignmentLength() const override;
151   virtual void setToolTip(const WString& text,
152 			  TextFormat textFormat = TextFormat::Plain)
153     override;
154   virtual void setDeferredToolTip(bool enable,
155                                   TextFormat textFormat = TextFormat::Plain)
156     override;
157   virtual WString toolTip() const override;
158   virtual void refresh() override;
159   virtual void setAttributeValue(const std::string& name,
160 				 const WT_USTRING& value) override;
161   virtual WT_USTRING attributeValue(const std::string& name) const override;
162   virtual void setJavaScriptMember(const std::string& name,
163 				   const std::string& value) override;
164   virtual std::string javaScriptMember(const std::string& name) const override;
165   virtual void callJavaScriptMember(const std::string& name,
166 				    const std::string& args) override;
167   virtual void load() override;
168   virtual bool loaded() const override;
169   virtual int zIndex() const override;
170 
171   virtual void setId(const std::string& id) override;
172   virtual WWidget *find(const std::string& name) override;
173   virtual WWidget *findById(const std::string& id) override;
174   virtual void setSelectable(bool selectable) override;
175   virtual void doJavaScript(const std::string& javascript) override;
176   virtual const std::string id() const override;
177 
178 #ifdef WT_TARGET_JAVA
179   /*! \brief Create DOM element for widget
180    *
181    * This is an internal function, and should not be called directly,
182    * or be overridden!
183    */
184 #endif
185   virtual DomElement *createDomElement(WApplication *app);
186 #ifdef WT_TARGET_JAVA
187   /*! \brief Get DOM changes for this widget
188    *
189    * This is an internal function, and should not be called directly,
190    * or be overridden!
191    */
192 #endif
193   virtual void getDomChanges(std::vector<DomElement *>& result,
194 			     WApplication *app);
195   virtual DomElementType domElementType() const = 0;
196 
197   DomElement *createStubElement(WApplication *app);
198   DomElement *createActualElement(WWidget *self, WApplication *app);
199 
200   /*! \brief Change the way the widget is loaded when invisible.
201    *
202    * By default, invisible widgets are loaded only after visible content.
203    * For tiny widgets this may lead to a performance loss, instead of the
204    * expected increase, because they require many more DOM manipulations
205    * to render, reducing the overall responsiveness of the application.
206    *
207    * Therefore, this is disabled for some widgets like WImage, or
208    * empty WContainerWidgets.
209    *
210    * You may also want to disable deferred loading when JavaScript event
211    * handling expects the widget to be loaded.
212    *
213    * Usually the default settings are fine, but you may want to change
214    * the behaviour.
215    *
216    * \sa WApplication::setTwoPhaseRenderingThreshold()
217    */
218   void setLoadLaterWhenInvisible(bool);
219 
220   /*!
221    * \brief returns the current html tag name
222    *
223    * \sa setHtmlTagName()
224    */
225   std::string htmlTagName() const;
226 
227   /*!
228    * \brief set the custom HTML tag name
229    *
230    * The custom tag will replace the actual tag.
231    * The tag is not tested to see if
232    * it is a valid one and a closing tag will always be added.
233    *
234    * \sa htmlTagName()
235    */
236   void setHtmlTagName(const std::string & tag);
237 
238   static WString escapeText(const WString& text, bool newlinesToo = false);
239   static std::string& escapeText(std::string& text, bool newlinestoo = false);
240   static std::string& unescapeText(std::string& text);
241 #ifdef WT_TARGET_JAVA
242   static std::string& doUnescapeText(std::string& text);
243 #endif // WT_TARGET_JAVA
244   static bool removeScript(WString& text);
245 
246   /*! \brief Turn a CharEncoding::UTF8 encoded string into a JavaScript string literal
247    *
248    * The \p delimiter may be a single or double quote.
249    */
250   static std::string jsStringLiteral(const std::string& v,
251 				     char delimiter = '\'');
252   static std::string jsStringLiteral(const WString& v,
253 				     char delimiter = '\'');
254 
255   static std::string resolveRelativeUrl(const std::string& url);
256 
257   void setFormObject(bool how);
258   static bool canOptimizeUpdates();
259   void setZIndex(int zIndex);
260 
261   bool isRendered() const;
262 
263   virtual void setCanReceiveFocus(bool enabled) override;
264   virtual bool canReceiveFocus() const override;
265   virtual bool setFirstFocus() override;
266   virtual void setFocus(bool focus) override;
267   virtual bool hasFocus() const override;
268   virtual void setTabIndex(int index) override;
269   virtual int tabIndex() const override;
270 
271   /*! \brief %Signal emitted when the widget lost focus.
272    *
273    * This signals is only emitted for a widget that canReceiveFocus()
274    */
275   EventSignal<>& blurred();
276 
277   /*! \brief %Signal emitted when the widget recieved focus.
278    *
279    * This signals is only emitted for a widget that canReceiveFocus()
280    */
281   EventSignal<>& focussed();
282 
283 #ifndef WT_TARGET_JAVA
284   using WWidget::setFocus;
285 #endif
286 
287   virtual bool scrollVisibilityEnabled() const final override;
288   virtual void setScrollVisibilityEnabled(bool enabled) final override;
289   virtual int scrollVisibilityMargin() const final override;
290   virtual void setScrollVisibilityMargin(int margin) final override;
291   virtual Signal<bool> &scrollVisibilityChanged() final override;
292   virtual bool isScrollVisible() const final override;
293 
294   virtual void setThemeStyleEnabled(bool enabled) final override;
295   virtual bool isThemeStyleEnabled() const final override;
296 
297   virtual void setObjectName(const std::string& name) override;
298 
299   virtual int baseZIndex() const final override;
300   void setBaseZIndex(int zIndex);
301 
302 protected:
303   typedef std::map<std::string, WObject *> FormObjectsMap;
304 #ifndef WT_TARGET_JAVA
305   typedef std::function<void (WWidget *)> HandleWidgetMethod;
306 #endif
307 
308   void repaint(WFlags<RepaintFlag> flags = None);
309 
310   virtual void iterateChildren(const HandleWidgetMethod& method) const;
311   virtual void getFormObjects(FormObjectsMap& formObjects);
312   virtual void doneRerender();
313   virtual void updateDom(DomElement& element, bool all);
314   virtual bool domCanBeSaved() const;
315   virtual void propagateRenderOk(bool deep = true);
316   virtual std::string renderRemoveJs(bool recursive) override;
317 
318   virtual void propagateSetEnabled(bool enabled) override;
319   virtual void propagateSetVisible(bool visible) override;
320   virtual bool isStubbed() const override;
321   virtual void enableAjax() override;
322 
323   virtual void setHideWithOffsets(bool how = true) override;
324   virtual WStatelessSlot *getStateless(Method method) override;
325 
326   WWidget *selfWidget();
327 
328   void doLoad(WWidget *w);
329   void widgetAdded(WWidget *child);
330   void widgetRemoved(WWidget *child, bool renderRemove);
331 
332 #ifndef WT_TARGET_JAVA
333   template <class Widget>
manageWidget(std::unique_ptr<Widget> & managed,std::unique_ptr<Widget> w)334   std::unique_ptr<WWidget> manageWidget(std::unique_ptr<Widget>& managed,
335 					std::unique_ptr<Widget> w)
336 #else // WT_TARGET_JAVA
337   std::unique_ptr<WWidget> manageWidget(std::unique_ptr<WWidget> managed, std::unique_ptr<WWidget> w)
338 #endif // WT_TARGET_JAVA
339   {
340     if (managed)
341       widgetRemoved(managed.get(), true);
342     std::unique_ptr<WWidget> result = std::move(managed);
343     managed = std::move(w);
344     if (managed)
345       widgetAdded(managed.get());
346     return result;
347   }
348 
349   virtual void render(WFlags<RenderFlag> flags) override;
350 
351   virtual void signalConnectionsChanged() override;
352 
353   void beingDeleted();
354 
355 private:
356   /*
357    * Booleans packed in a bitset.
358    */
359   static const int BIT_INLINE = 0;
360   static const int BIT_HIDDEN = 1;
361   static const int BIT_LOADED = 2;
362   static const int BIT_RENDERED = 3;
363   static const int BIT_STUBBED = 4;
364   static const int BIT_FORM_OBJECT = 5;
365   static const int BIT_FLEX_BOX = 6;
366   static const int BIT_FLEX_BOX_CHANGED = 7;
367   static const int BIT_GEOMETRY_CHANGED = 8;
368   static const int BIT_HIDE_WITH_OFFSETS = 9;
369   static const int BIT_BEING_DELETED = 10;
370   static const int BIT_DONOT_STUB = 11;
371   static const int BIT_FLOAT_SIDE_CHANGED = 12;
372   static const int BIT_REPAINT_TO_AJAX = 13;
373   static const int BIT_HIDE_WITH_VISIBILITY = 14;
374   static const int BIT_HIDDEN_CHANGED = 15;
375   static const int BIT_ENABLED = 16; // caches isEnabled() for WInteractWidget
376   static const int BIT_TOOLTIP_CHANGED = 17;
377   static const int BIT_MARGINS_CHANGED = 18;
378   static const int BIT_STYLECLASS_CHANGED = 19;
379   static const int BIT_SET_UNSELECTABLE = 20;
380   static const int BIT_SET_SELECTABLE = 21;
381   static const int BIT_SELECTABLE_CHANGED = 22;
382   static const int BIT_WIDTH_CHANGED = 23;
383   static const int BIT_HEIGHT_CHANGED = 24;
384   static const int BIT_DISABLED = 25;
385   static const int BIT_DISABLED_CHANGED = 26;
386   static const int BIT_CONTAINS_LAYOUT = 27;
387   static const int BIT_ZINDEX_CHANGED = 28;
388   static const int BIT_TOOLTIP_DEFERRED = 29;
389   static const int BIT_GOT_FOCUS        = 30;
390   static const int BIT_TABINDEX_CHANGED = 31;
391   static const int BIT_SCROLL_VISIBILITY_ENABLED = 32;
392   // BIT_SCROLL_VISIBILITY_LOADED makes sure that scrollVisibility.remove is never
393   // called for widgets that never had scroll visibility enabled
394   static const int BIT_SCROLL_VISIBILITY_LOADED = 33;
395   static const int BIT_IS_SCROLL_VISIBLE = 34; // tracks whether the widget is currently "scroll visible"
396   // Tracks whether scroll visibility is enabled/disabled, and whether the
397   // scroll visibility margin has been modified.
398   static const int BIT_SCROLL_VISIBILITY_CHANGED = 35;
399   static const int BIT_THEME_STYLE_DISABLED = 36;
400   static const int BIT_OBJECT_NAME_CHANGED = 37;
401 
402   static const char *FOCUS_SIGNAL;
403   static const char *BLUR_SIGNAL;
404 
405   static const int DEFAULT_BASE_Z_INDEX;
406   static const int Z_INDEX_INCREMENT;
407 
408   std::string elementTagName_;
409 
410 #ifndef WT_TARGET_JAVA
411   static const std::bitset<38> AllChangeFlags;
412 #endif // WT_TARGET_JAVA
413 
414   void loadToolTip();
415 
416   /*
417    * Frequently used attributes.
418    */
419   std::bitset<38> flags_;
420   std::unique_ptr<WLength> width_;
421   std::unique_ptr<WLength> height_;
422 
423   /*
424    * id_ is separate instead of in OtherImpl,
425    * because it is accessed when OtherImpl is being destroyed,
426    * from the destructor of jsScrollVisibilityChanged_
427    */
428   std::unique_ptr<std::string> id_;
429 
430   /*
431    * Data only stored transiently, during event handling.
432    */
433   struct TransientImpl {
434     std::vector<std::string> childRemoveChanges_;
435     std::vector<WT_USTRING> addedStyleClasses_, removedStyleClasses_;
436     std::vector<std::string> attributesSet_;
437 
438     int addedChildren_;
439     bool specialChildRemove_;
440     WAnimation animation_;
441 
442     TransientImpl();
443     ~TransientImpl();
444   };
445 
446   std::unique_ptr<TransientImpl> transientImpl_;
447 
448   struct LayoutImpl {
449     PositionScheme positionScheme_;
450     Side floatSide_;
451     WFlags<Side> clearSides_;
452     WLength offsets_[4]; // left, right, top, bottom
453     WLength minimumWidth_, minimumHeight_, maximumWidth_, maximumHeight_;
454     int baseZIndex_;
455     int	zIndex_; // -1 = wants popup
456     AlignmentFlag verticalAlignment_;
457     WLength verticalAlignmentLength_, margin_[4], lineHeight_;
458 
459     LayoutImpl();
460   };
461 
462   std::unique_ptr<LayoutImpl> layoutImpl_;
463 
464   struct LookImpl {
465     std::unique_ptr<WCssDecorationStyle> decorationStyle_;
466     WT_USTRING styleClass_;
467     std::unique_ptr<WString> toolTip_;
468     TextFormat toolTipTextFormat_;
469     JSignal<> loadToolTip_;
470 
471     LookImpl(WWebWidget *w);
472     ~LookImpl();
473   };
474 
475   mutable std::unique_ptr<LookImpl> lookImpl_;
476 
477   struct DropMimeType {
478     WT_USTRING hoverStyleClass;
479 
480     DropMimeType();
481     DropMimeType(const WT_USTRING& hoverStyleClass);
482   };
483 
484   enum class JavaScriptStatementType {
485     SetMember,
486     CallMethod,
487     Statement
488   };
489 
490   struct OtherImpl {
491     struct Member {
492       std::string name;
493       std::string value;
494     };
495 
496     struct JavaScriptStatement {
497       JavaScriptStatement(JavaScriptStatementType type,
498 			  const std::string& data);
499 
500       JavaScriptStatementType type;
501       std::string data;
502     };
503 
504     std::unique_ptr<std::string> elementTagName_;
505     std::unique_ptr<std::map<std::string, WT_USTRING> > attributes_;
506     std::unique_ptr<std::vector<Member> > jsMembers_;
507     std::unique_ptr<std::vector<JavaScriptStatement> > jsStatements_;
508     std::unique_ptr<JSignal<int, int> > resized_;
509     int tabIndex_;
510 
511     // drag source id, drag mime type
512     std::unique_ptr<JSignal<std::string, std::string, WMouseEvent> > dropSignal_;
513     std::unique_ptr<JSignal<std::string, std::string, WTouchEvent> > dropSignal2_;
514 
515     typedef std::map<std::string, DropMimeType> MimeTypesMap;
516     std::unique_ptr<MimeTypesMap> acceptedDropMimeTypes_;
517     Signal<> childrenChanged_;
518 
519     int scrollVisibilityMargin_;
520     Signal<bool> scrollVisibilityChanged_;
521     std::unique_ptr<JSignal<bool> > jsScrollVisibilityChanged_;
522 
523     OtherImpl(WWebWidget *const self);
524     ~OtherImpl();
525   };
526 
527   std::unique_ptr<OtherImpl> otherImpl_;
528 
529   void renderOk();
530   void calcZIndex();
531 
532   virtual bool needsToBeRendered() const override;
533   virtual void getSDomChanges(std::vector<DomElement *>& result,
534 			      WApplication *app) override;
535   void getSFormObjects(FormObjectsMap& formObjects);
536 
537   WWebWidget *parentWebWidget() const;
538 
539   /*
540    * Drag & drop stuff.
541    */
542   bool setAcceptDropsImpl(const std::string& mimeType,
543 			  bool accept,
544 			  const WT_USTRING& hoverStyleClass);
545   void setImplementLayoutSizeAware(bool aware);
546   JSignal<int, int>& resized();
547 
548   void addJavaScriptStatement(JavaScriptStatementType type,
549 			      const std::string& data);
550   int indexOfJavaScriptMember(const std::string& name) const;
551   void declareJavaScriptMember(DomElement& element,
552 			       const std::string& name,
553 			       const std::string& value);
554   WString storedToolTip() const;
555   void undoSetFocus();
556 
557   void jsScrollVisibilityChanged(bool visible);
558 
559   void emitChildrenChanged();
560 
561 protected:
562   virtual void setParentWidget(WWidget *parent) override;
563   void setRendered(bool rendered);
564 
565   void setId(DomElement *element, WApplication *app);
webWidget()566   virtual WWebWidget *webWidget() override { return this; }
567 
568   EventSignal<> *voidEventSignal(const char *name, bool create);
569   EventSignal<WKeyEvent> *keyEventSignal(const char *name, bool create);
570   EventSignal<WMouseEvent> *mouseEventSignal(const char *name, bool create);
571   EventSignal<WScrollEvent> *scrollEventSignal(const char *name, bool create);
572   EventSignal<WTouchEvent> *touchEventSignal(const char *name, bool create);
573   EventSignal<WGestureEvent> *gestureEventSignal(const char *name, bool create);
574 
575   void updateSignalConnection(DomElement& element, EventSignalBase& signal,
576 			      const char *name, bool all);
577 
578   virtual void parentResized(WWidget *parent, WFlags<Orientation> directions);
579   void containsLayout();
580   void setFlexBox(bool enabled);
581 
582   /*
583    * WWebWidget ended up with more friends than me...
584    */
585   friend class WebRenderer;
586   friend class WebSession;
587 
588   friend class WApplication;
589   friend class WCompositeWidget;
590   friend class WContainerWidget;
591   friend class WCssDecorationStyle;
592   friend class WCssTemplateRule;
593   friend class WDialog;
594   friend class WFont;
595   friend class WGLWidget;
596   friend class WInteractWidget;
597   friend class WLeafletMap;
598   friend class JSlot;
599   friend class WTable;
600   friend class WViewWidget;
601   friend class WWidget;
602   friend class WTemplate;
603   friend class WWidgetItem;
604   friend class FlexLayoutImpl;
605 };
606 
607 }
608 
609 #endif // WWEB_WIDGET_H_
610