1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickwebview_p.h"
5#include "qquickwebviewloadrequest_p.h"
6#include "qquickwebviewsettings_p.h"
7#include <QtWebView/private/qwebviewloadrequest_p.h>
8#include <QtQml/qqmlengine.h>
9#include <QtCore/qmutex.h>
10
11namespace {
12
13class CallbackStorage
14{
15public:
16 int insertCallback(const QJSValue &callback)
17 {
18 QMutexLocker locker(&m_mtx);
19 const int nextId = qMax(a: ++m_counter, b: 0);
20 if (nextId == 0)
21 m_counter = 1;
22
23 m_callbacks.insert(key: nextId, value: callback);
24 return nextId;
25 }
26
27 QJSValue takeCallback(int callbackId)
28 {
29 QMutexLocker lock(&m_mtx);
30 return m_callbacks.take(key: callbackId);
31 }
32
33private:
34 QMutex m_mtx;
35 int m_counter;
36 QHash<int, QJSValue> m_callbacks;
37};
38
39} // namespace
40
41Q_GLOBAL_STATIC(CallbackStorage, callbacks)
42
43/*!
44 \qmltype WebView
45 \inqmlmodule QtWebView
46 \ingroup qtwebview
47 \brief A component for displaying web content.
48
49 WebView is a component for displaying web content which is implemented using native
50 APIs on the platforms where this is available, thus it does not necessarily require
51 including a full web browser stack as part of the application.
52
53 To make the Qt WebView module function correctly across all platforms, it is necessary
54 to call \l {qtwebview-initialize}{QtWebView::initialize}() right after creating the
55 QGuiApplication instance.
56
57 \note Due to platform limitations overlapping the WebView and other QML components
58 is not supported.
59*/
60
61QQuickWebView::QQuickWebView(QQuickItem *parent)
62 : QQuickViewController(parent)
63 , m_webView(new QWebView(this))
64 , m_settings(new QQuickWebViewSettings(m_webView->getSettings(), this))
65{
66 setView(m_webView);
67 connect(sender: m_webView, signal: &QWebView::titleChanged, context: this, slot: &QQuickWebView::titleChanged);
68 connect(sender: m_webView, signal: &QWebView::urlChanged, context: this, slot: &QQuickWebView::urlChanged);
69 connect(sender: m_webView, signal: &QWebView::loadProgressChanged, context: this, slot: &QQuickWebView::loadProgressChanged);
70 connect(sender: m_webView, signal: &QWebView::loadingChanged, context: this, slot: &QQuickWebView::onLoadingChanged);
71 connect(sender: m_webView, signal: &QWebView::requestFocus, context: this, slot: &QQuickWebView::onFocusRequest);
72 connect(sender: m_webView, signal: &QWebView::javaScriptResult, context: this, slot: &QQuickWebView::onRunJavaScriptResult);
73 connect(sender: m_webView, signal: &QWebView::httpUserAgentChanged, context: this, slot: &QQuickWebView::httpUserAgentChanged);
74 connect(sender: m_webView, signal: &QWebView::cookieAdded, context: this, slot: &QQuickWebView::cookieAdded);
75 connect(sender: m_webView, signal: &QWebView::cookieRemoved, context: this, slot: &QQuickWebView::cookieRemoved);
76}
77
78QQuickWebView::~QQuickWebView() { }
79
80/*!
81 \qmlproperty url QtWebView::WebView::httpUserAgent
82 \since QtWebView 1.14
83 The user agent in use.
84
85 \note on WinRT, this property affects all WebViews of the application.
86*/
87
88void QQuickWebView::setHttpUserAgent(const QString &userAgent)
89{
90 m_webView->setHttpUserAgent(userAgent);
91}
92
93QString QQuickWebView::httpUserAgent() const
94{
95 return m_webView->httpUserAgent();
96}
97
98/*!
99 \qmlproperty url QtWebView::WebView::url
100
101 The URL of currently loaded web page. Changing this will trigger
102 loading new content.
103
104 The URL is used as-is. URLs that originate from user input should
105 be parsed with QUrl::fromUserInput().
106
107 \note The WebView does not support loading content through the Qt Resource system.
108*/
109
110void QQuickWebView::setUrl(const QUrl &url)
111{
112 m_webView->setUrl(url);
113}
114
115/*!
116 \qmlproperty string QtWebView::WebView::title
117 \readonly
118
119 The title of the currently loaded web page.
120*/
121
122QString QQuickWebView::title() const
123{
124 return m_webView->title();
125}
126
127QUrl QQuickWebView::url() const
128{
129 return m_webView->url();
130}
131
132/*!
133 \qmlproperty bool QtWebView::WebView::canGoBack
134 \readonly
135
136 Holds \c true if it's currently possible to navigate back in the web history.
137*/
138
139bool QQuickWebView::canGoBack() const
140{
141 return m_webView->canGoBack();
142}
143
144/*!
145 \qmlproperty bool QtWebView::WebView::canGoForward
146 \readonly
147
148 Holds \c true if it's currently possible to navigate forward in the web history.
149*/
150
151bool QQuickWebView::canGoForward() const
152{
153 return m_webView->canGoForward();
154}
155
156/*!
157 \qmlproperty int QtWebView::WebView::loadProgress
158 \readonly
159
160 The current load progress of the web content, represented as
161 an integer between 0 and 100.
162*/
163int QQuickWebView::loadProgress() const
164{
165 return m_webView->loadProgress();
166}
167
168/*!
169 \qmlproperty bool QtWebView::WebView::loading
170 \readonly
171
172 Holds \c true if the WebView is currently in the process of loading
173 new content, \c false otherwise.
174
175 \sa loadingChanged()
176*/
177
178/*!
179 \qmlsignal QtWebView::WebView::loadingChanged(WebViewLoadRequest loadRequest)
180
181 This signal is emitted when the state of loading the web content changes.
182 By handling this signal it's possible, for example, to react to page load
183 errors.
184
185 The \a loadRequest parameter holds the \e url and \e status of the request,
186 as well as an \e errorString containing an error message for a failed
187 request.
188
189 \sa WebViewLoadRequest
190*/
191bool QQuickWebView::isLoading() const
192{
193 return m_webView->isLoading();
194}
195
196/*!
197 \qmlmethod void QtWebView::WebView::goBack()
198
199 Navigates back in the web history.
200*/
201void QQuickWebView::goBack()
202{
203 m_webView->goBack();
204}
205
206/*!
207 \qmlmethod void QtWebView::WebView::goForward()
208
209 Navigates forward in the web history.
210*/
211void QQuickWebView::goForward()
212{
213 m_webView->goForward();
214}
215
216/*!
217 \qmlmethod void QtWebView::WebView::reload()
218
219 Reloads the current \l url.
220*/
221void QQuickWebView::reload()
222{
223 m_webView->reload();
224}
225
226/*!
227 \qmlmethod void QtWebView::WebView::stop()
228
229 Stops loading the current \l url.
230*/
231void QQuickWebView::stop()
232{
233 m_webView->stop();
234}
235
236/*!
237 \qmlmethod void QtWebView::WebView::loadHtml(string html, url baseUrl)
238
239 Loads the specified \a html content to the web view.
240
241 This method offers a lower-level alternative to the \l url property,
242 which references HTML pages via URL.
243
244 External objects such as stylesheets or images referenced in the HTML
245 document should be located relative to \a baseUrl. For example, if \a html
246 is retrieved from \c http://www.example.com/documents/overview.html, which
247 is the base URL, then an image referenced with the relative url, \c diagram.png,
248 should be at \c{http://www.example.com/documents/diagram.png}.
249
250 \note The WebView does not support loading content through the Qt Resource system.
251
252 \sa url
253*/
254void QQuickWebView::loadHtml(const QString &html, const QUrl &baseUrl)
255{
256 m_webView->loadHtml(html, baseUrl);
257}
258
259/*!
260 \qmlmethod void QtWebView::WebView::runJavaScript(string script, variant callback)
261
262 Runs the specified JavaScript.
263 In case a \a callback function is provided, it will be invoked after the \a script
264 finished running.
265
266 \badcode
267 runJavaScript("document.title", function(result) { console.log(result); });
268 \endcode
269*/
270void QQuickWebView::runJavaScript(const QString &script, const QJSValue &callback)
271{
272 const int callbackId = callback.isCallable() ? callbacks->insertCallback(callback) : -1;
273 runJavaScriptPrivate(script, callbackId);
274}
275
276void QQuickWebView::runJavaScriptPrivate(const QString &script, int callbackId)
277{
278 m_webView->runJavaScriptPrivate(script, callbackId);
279}
280
281/*!
282 \qmlmethod void QtWebView::WebView::setCookie(string domain, string name, string value)
283 \since QtWebView 6.3
284 Adds a cookie with the specified \a domain, \a name and \a value.
285
286 The \l cookieAdded signal will be emitted when the cookie is added.
287*/
288/*!
289 \qmlsignal QtWebView::WebView::cookieAdded(string domain, string name)
290
291 This signal is emitted when a cookie is added.
292
293 The parameters provide information about the \a domain and the \a name of the added cookie.
294
295 \note When Qt WebEngine module is used as backend, cookieAdded signal will be emitted for any
296 cookie added to the underlying QWebEngineCookieStore, including those added by websites.
297 In other cases cookieAdded signal is only emitted for cookies explicitly added with \l setCookie().
298*/
299void QQuickWebView::setCookie(const QString &domain, const QString &name, const QString &value)
300{
301 m_webView->setCookie(domain, name, value);
302}
303
304/*!
305 \qmlmethod void QtWebView::WebView::deleteCookie(string domain, string name)
306 \since QtWebView 6.3
307 Deletes a cookie with the specified \a domain and \a name.
308
309 The \l cookieRemoved signal will be emitted when the cookie is deleted.
310*/
311/*!
312 \qmlsignal QtWebView::WebView::cookieRemoved(string domain, string name)
313
314 This signal is emitted when a cookie is deleted.
315
316 The parameters provide information about the \a domain and the \a name of the deleted cookie.
317*/
318void QQuickWebView::deleteCookie(const QString &domain, const QString &name)
319{
320 m_webView->deleteCookie(domain, name);
321}
322
323/*!
324 \qmlmethod void QtWebView::WebView::deleteAllCookies()
325 \since QtWebView 6.3
326 Deletes all the cookies.
327*/
328void QQuickWebView::deleteAllCookies()
329{
330 m_webView->deleteAllCookies();
331}
332
333void QQuickWebView::itemChange(ItemChange change, const ItemChangeData &value)
334{
335 if (change == QQuickItem::ItemActiveFocusHasChanged) {
336 m_webView->setFocus(value.boolValue);
337 }
338 QQuickItem::itemChange(change, value);
339}
340
341void QQuickWebView::onRunJavaScriptResult(int id, const QVariant &variant)
342{
343 if (id == -1)
344 return;
345
346 QJSValue callback = callbacks->takeCallback(callbackId: id);
347 if (callback.isUndefined())
348 return;
349
350 QQmlEngine *engine = qmlEngine(this);
351 if (engine == 0) {
352 qWarning(msg: "No JavaScript engine, unable to handle JavaScript callback!");
353 return;
354 }
355
356 QJSValueList args;
357 args.append(t: engine->toScriptValue(value: variant));
358 callback.call(args);
359}
360
361void QQuickWebView::onFocusRequest(bool focus)
362{
363 setFocus(focus);
364}
365
366void QQuickWebView::onLoadingChanged(const QWebViewLoadRequestPrivate &loadRequest)
367{
368 QQuickWebViewLoadRequest qqLoadRequest(loadRequest);
369 Q_EMIT loadingChanged(loadRequest: &qqLoadRequest);
370}
371
372QJSValue QQuickWebView::takeCallback(int id)
373{
374 return callbacks->takeCallback(callbackId: id);
375}
376
377/*!
378 \qmlproperty WebViewSettings WebView::settings
379 \readonly
380 \since QtWebView 6.5
381
382 Settings object for the WebView.
383
384 \sa WebViewSettings
385*/
386
387QQuickWebViewSettings *QQuickWebView::settings() const
388{
389 return m_settings;
390}
391

source code of qtwebview/src/quick/qquickwebview.cpp