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 WANCHOR_H_
8 #define WANCHOR_H_
9 
10 #include <Wt/WContainerWidget.h>
11 #include <Wt/WJavaScript.h>
12 #include <Wt/WImage.h>
13 #include <Wt/WLink.h>
14 
15 namespace Wt {
16 
17   namespace Impl {
18     class AreaWidget;
19   }
20 
21 /*! \class WAnchor Wt/WAnchor.h Wt/WAnchor.h
22  *  \brief A widget that represents an HTML anchor (to link to other documents).
23  *
24  * Use an anchor to link to another web page, document, internal
25  * application path or a resource (which specifies
26  * application-dependent content that may be generated by your
27  * application on demand). The anchor may contain a label text, an
28  * image, or any other widget (as it inherits from
29  * WContainerWidget).
30  *
31  * If you link to a document or external url, and do not want the
32  * application to terminate when the user follows the anchor, you must
33  * use \link WLink.setTarget(LinkTarget)
34  * link.setTarget(LinkTarget::NewWindow)\endlink. Even for non-HTML
35  * documents, this may be important since pending Ajax requests are
36  * cancelled if documents are not served within the browser window in
37  * certain browsers.
38  *
39  * \if cpp
40  * Usage example:
41  * \code
42  * WAnchor *a;
43  *
44  * // Create an anchor that links to a URL
45  * a = addWidget(std::make_unique<Wt::WAnchor>("https://www.webtoolkit.eu/", "Wt web toolkit"));
46  *
47  * // Create an anchor that links to an internal path
48  * a = addWidget(std::make_unique<Wt::WAnchor>(
49  *       WLink(LinkType::InternalPath, "/docs/" + myDocName()), "Doc"));
50  * //   and listen to the corresponding change in internal path
51  * WApplication::instance()->internalPathChanged().connect(this, &DocsListWidget::onInternalPathChange);
52  *
53  * // Create an anchor that links to a resource
54  * WResource *r = addChild(std::make_unique<PdfResource>()); // serializes to a PDF file.
55  * a = addWidget(std::make_unique<Wt::WAnchor>(r, "PDF version"));
56  * \endcode
57  * \endif
58  *
59  * %WAnchor is an \link WWidget::setInline(bool) inline \endlink widget.
60  *
61  * <h3>CSS</h3>
62  *
63  * The widget corresponds to the HTML <tt>&lt;a&gt;</tt> tag and does
64  * not provide styling. It can be styled using inline or external CSS
65  * as appropriate.
66  */
67 class WT_API WAnchor : public WContainerWidget
68 {
69 public:
70   /*! \brief Creates an anchor.
71    */
72   WAnchor();
73 
74   /*! \brief Creates an anchor for the given link.
75    *
76    * The \p link may point to a URL, a dynamic resource, or an
77    * internal path.
78    *
79    * \sa setLink()
80    */
81   WAnchor(const WLink& link);
82 
83   /*! \brief Creates an anchor for the given link with a text.
84    *
85    * The \p link may point to a URL, a dynamic resource, or an
86    * internal path.
87    *
88    * \sa setLink(), setText()
89    */
90   WAnchor(const WLink& link, const WString& text);
91 
92   /*! \brief Creates an anchor for the given link with an image.
93    *
94    * \if cpp
95    * Ownership of the image is transferred to the anchor.
96    * \endif
97    *
98    * \sa setLink(), setImage()
99    */
100   WAnchor(const WLink& link, std::unique_ptr<WImage> image);
101 
102   /*! \brief Sets the link.
103    *
104    * The link may hold a URL, a resource, or an internal path.
105    *
106    * When the link points to a \link LinkType::Resource resource\endlink,
107    * the contents of the link may be generated by your application on
108    * demand.
109    *
110    * When the link points to an \link LinkType::InternalPath internal
111    * path\endlink, activating the anchor will change the \link
112    * WApplication::internalPath() application's internal path\endlink
113    * or open a new session with the given path as \link
114    * WEnvironment::internalPath() initial path\endlink). This is the
115    * easiest way to let the application participate in browser
116    * history, and generate URLs that are bookmarkable and search
117    * engine friendly.
118    */
119   void setLink(const WLink& link);
120 
121   /*! \brief Returns the link.
122    *
123    * \sa setLink()
124    */
link()125   const WLink& link() const { return linkState_.link; }
126 
127   /*! \brief Sets the label text
128    *
129    * If no text was previously set, a new WText widget is added using
130    * addWidget().
131    */
132   void setText(const WString& text);
133 
134   /*! \brief Returns the label text.
135    *
136    * Returns an empty string if no label was set.
137    *
138    * \sa setText()
139    */
140   const WString& text() const;
141 
142   /*! \brief Configures text word wrapping.
143    *
144    * When \p wordWrap is \c true, the text set with setText() may be
145    * broken up over multiple lines. When \p wordWrap is \c false, the
146    * text will displayed on a single line, unless the text contains
147    * <tt>&lt;br /&gt;</tt> tags or other block-level tags.
148    *
149    * The default value is \c true.
150    *
151    * \sa wordWrap()
152    */
153   void setWordWrap(bool wordWrap);
154 
155   /*! \brief Configures the text format.
156    *
157    * The default text format is TextFormat::XHTML.
158    *
159    * \sa WText::setTextFormat()
160    */
161   void setTextFormat(TextFormat format);
162 
163   /*! \brief Returns the text format.
164    *
165    * \sa setTextFormat()
166    */
167   TextFormat textFormat() const;
168 
169   /*! \brief Returns whether the widget may break lines.
170    *
171    * \sa setWordWrap(bool)
172    */
173   bool wordWrap() const;
174 
175   /*! \brief Sets an image.
176    *
177    * If an image was previously set, it is deleted. The \p image
178    * is added using addWidget().
179    */
180   void setImage(std::unique_ptr<WImage> image);
181 
182   /*! \brief Returns the image.
183    *
184    * Returns \c 0 if no image is set.
185    *
186    * \sa setImage()
187    */
image()188   WImage *image() const { return image_.get(); }
189 
190   virtual bool canReceiveFocus() const override;
191   virtual int tabIndex() const override;
192   virtual bool setFirstFocus() override;
193 
194 private:
195   static const int BIT_LINK_CHANGED = 0;
196   static const int BIT_TARGET_CHANGED = 1;
197 
198   struct WT_API LinkState {
199     LinkState();
200     ~LinkState();
201 
202     WLink link;
203     JSlot *clickJS;
204   };
205 
206   LinkState linkState_;
207 
208   observing_ptr<WText> text_;
209   observing_ptr<WImage> image_;
210   std::bitset<2> flags_;
211 
212   void resourceChanged();
213 
214   static bool renderHRef(WInteractWidget *widget,
215 			 LinkState& linkState, DomElement& element);
216   static void renderHTarget(LinkState& linkState, DomElement& element,
217 			    bool all);
218   static void renderUrlResolution(WWidget *widget, DomElement& element,
219 				  bool all);
220 
221 protected:
222   virtual void updateDom(DomElement& element, bool all) override;
223   virtual DomElementType domElementType() const override;
224   virtual void propagateRenderOk(bool deep) override;
225   virtual void propagateSetEnabled(bool enabled) override;
226   virtual void enableAjax() override;
227 
228   friend class WAbstractArea;
229   friend class WPushButton;
230   friend class Impl::AreaWidget;
231 };
232 
233 }
234 
235 #endif // WANCHOR_H_
236