Coverage Report

Created: 2025-11-24 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wt/src/Wt/WJavaScriptHandle.h
Line
Count
Source
1
// This may look like C code, but it's really -*- C++ -*-
2
/*
3
 * Copyright (C) 2015 Emweb bv, Herent, Belgium.
4
 *
5
 * See the LICENSE file for terms of use.
6
 */
7
#ifndef WJAVASCRIPT_HANDLE_H_
8
#define WJAVASCRIPT_HANDLE_H_
9
10
#include <cassert>
11
12
#include <Wt/WException.h>
13
#include <Wt/WJavaScriptExposableObject.h>
14
15
namespace Wt {
16
17
/*! \class WJavaScriptHandle Wt/WJavaScriptHandle.h Wt/WJavaScriptHandle.h
18
 *  \brief A handle to a JavaScript representation of an object.
19
 *
20
 *  A %WJavaScriptHandle allows to access and modify an object in JavaScript.
21
 *  This is useful to avoid server roundtrips when frequently updating something,
22
 *  e.g. to interact with and animate a WPaintedWidget.
23
 *
24
 *  You can use the value() of a %WJavaScriptHandle just as you would normally,
25
 *  with the exception that it will be \link WJavaScriptExposableObject::isJavaScriptBound()
26
 *  JavaScript bound\endlink, and so will any copies you make of it. You should
27
 *  not modify a JavaScript bound object, as this will not change its client side
28
 *  representation. Use the handle's setValue() method instead.
29
 *
30
 *  You can access (and modify) the value of a handle on the client side using jsRef().
31
 *
32
 *  You can update the value from the server with setValue(). Changes on the
33
 *  client side will be synced back to the server.
34
 *
35
 *  Currently, only WPaintedWidget allows the use of \link WJavaScriptExposableObject
36
 *  JavaScript exposable objects\endlink.
37
 *
38
 *  \sa WJavaScriptExposableObject, WPaintedWidget
39
 */
40
template <typename T>
41
class WJavaScriptHandle
42
{
43
public:
44
  /*! \brief Create an invalid WJavaScriptHandle
45
   *
46
   * The handle will be invalid until a valid WJavaScriptHandle
47
   * is copy-assigned to it.
48
   */
49
  WJavaScriptHandle() noexcept
50
    : value_(nullptr), id_(0)
51
  { }
52
53
  /*! \brief Copy constructor
54
   */
55
  WJavaScriptHandle(const WJavaScriptHandle &handle) noexcept
56
    : value_(handle.value_), id_(handle.id_)
57
  {
58
    assert(value_ == nullptr ||
59
           value_->clientBinding_ != nullptr);
60
  }
61
62
  /*! \brief Copy assignment operator
63
   */
64
  WJavaScriptHandle &operator=(const WJavaScriptHandle &handle) noexcept
65
  {
66
    assert(handle.value_ == nullptr ||
67
           handle.value_->clientBinding_ != nullptr);
68
69
    value_ = handle.value_;
70
    id_ = handle.id_;
71
72
    return (*this);
73
  }
74
75
  /*! \brief Move constructor
76
   */
77
  WJavaScriptHandle(WJavaScriptHandle &&handle) noexcept
78
    : value_(handle.value_), id_(handle.id_)
79
  {
80
    assert(handle.value_ == nullptr ||
81
           handle.value_->clientBinding_ != nullptr);
82
83
    handle.value_ = nullptr;
84
    handle.id_ = 0;
85
  }
86
87
  /*! \brief Move assignment operator
88
   */
89
  WJavaScriptHandle &operator=(WJavaScriptHandle &&handle) noexcept
90
  {
91
    if (this == &handle)
92
      return *this;
93
94
    assert(handle.value_ == nullptr ||
95
           handle.value_->clientBinding_ != nullptr);
96
97
    value_ = handle.value_;
98
    id_ = handle.id_;
99
    handle.value_ = nullptr;
100
    handle.id_ = 0;
101
102
    return *this;
103
  }
104
105
  /*! \brief Destructor
106
   */
107
  ~WJavaScriptHandle()
108
  { }
109
110
  /*! \brief Returns whether this is a valid handle
111
   *
112
   * A handle is not valid if it is not connected to a JavaScript
113
   * representation.  To make a WJavaScriptHandle valid, a valid
114
   * WJavaScriptHandle has to be copy-assigned to it. The various
115
   * createJS... methods in WPaintedWidget return a valid handle.
116
   */
117
  bool isValid() const noexcept {
118
    return value_;
119
  }
120
121
  /*! \brief Returns the JavaScript representation of the object.
122
   *
123
   * You can access and modify the value of this handle through its jsRef().
124
   *
125
   * \throw WException The handle is \link isValid() invalid\endlink
126
   */
127
  std::string jsRef() const {
128
    if (!value_) {
129
      throw WException("Can't retrieve the value of an invalid handle!");
130
    }
131
    return value_->clientBinding_->jsRef_;
132
  }
133
134
  /*! \brief Set the value for this handle.
135
   *
136
   * The value may not be JavaScript bound, i.e. related to another WJavaScriptHandle.
137
   * The change to the value will be synced to the client side equivalent.
138
   *
139
   * \throw WException The handle is \link isValid() invalid\endlink
140
   * \throw WException Trying to assign a JavaScript bound value
141
   */
142
  void setValue(const T& v)
143
  {
144
    if (!value_) {
145
      throw WException("Can't assign a value to an invalid handle!");
146
    }
147
    if (v.isJavaScriptBound()) throw WException("Can not assign a JavaScript bound value to a WJavaScriptHandle!");
148
    // Rescue the binding from being overridden by the assignment, and deleted
149
    WJavaScriptExposableObject::JSInfo *binding = value_->clientBinding_;
150
    value_->clientBinding_ = nullptr;
151
152
    bool changed = !value_->closeTo(v);
153
    (*value_) = v;
154
155
    value_->clientBinding_ = binding;
156
    if (changed)
157
      value_->clientBinding_->context_->dirty_[id_] = true;
158
  }
159
160
  /*! \brief Get the value for this handle.
161
   *
162
   * \warning You should not modify this value or any copy of it on the server side,
163
   *          because this will not be synced to the client side. Use setValue() instead.
164
   *
165
   * \throw WException The handle is \link isValid() invalid\endlink
166
   */
167
  const T& value() const {
168
    if (!value_) {
169
      throw WException("Can't retrieve the value from an invalid handle!");
170
    }
171
    return *value_;
172
  }
173
174
private:
175
  friend class WJavaScriptObjectStorage;
176
177
  WJavaScriptHandle(int id, T *t) noexcept
178
0
    : value_(t), id_(id)
179
0
  {
180
    assert(t != nullptr && t->clientBinding_ != nullptr);
181
0
  }
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WTransform>::WJavaScriptHandle(int, Wt::WTransform*)
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WBrush>::WJavaScriptHandle(int, Wt::WBrush*)
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WPen>::WJavaScriptHandle(int, Wt::WPen*)
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WPainterPath>::WJavaScriptHandle(int, Wt::WPainterPath*)
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WRectF>::WJavaScriptHandle(int, Wt::WRectF*)
Unexecuted instantiation: Wt::WJavaScriptHandle<Wt::WPointF>::WJavaScriptHandle(int, Wt::WPointF*)
182
183
  T *value_;
184
  int id_;
185
};
186
187
}
188
189
#endif // WJAVASCRIPT_HANDLE_H_