Browse Source

Provide the host environment with access to web view DOM. Fixes #92

Neal Wilson 11 years ago
parent
commit
174df9ef82
2 changed files with 184 additions and 2 deletions
  1. 4
    2
      src/Typica.pro
  2. 180
    0
      src/webview.w

+ 4
- 2
src/Typica.pro View File

@@ -20,12 +20,14 @@ HEADERS += moc_typica.cpp \
20 20
     helpmenu.h \
21 21
     abouttypica.h \
22 22
     units.h \
23
-    webview.h
23
+    webview.h \
24
+    webelement.h
24 25
 SOURCES += typica.cpp \
25 26
     helpmenu.cpp \
26 27
     abouttypica.cpp \
27 28
     units.cpp \
28
-    webview.cpp
29
+    webview.cpp \
30
+    webelement.cpp
29 31
 
30 32
 RESOURCES += \
31 33
     resources.qrc

+ 180
- 0
src/webview.w View File

@@ -32,6 +32,8 @@ class TypicaWebView : public QWebView
32 32
 		Q_INVOKABLE void setHtml(const QString &html, const QUrl &baseUrl = QUrl());
33 33
 		Q_INVOKABLE void setContent(QIODevice *device);
34 34
 		Q_INVOKABLE QString saveXml();
35
+		Q_INVOKABLE QWebElement documentElement();
36
+		Q_INVOKABLE QWebElement findFirstElement(const QString &selector);
35 37
 	signals:
36 38
 		void scriptLinkClicked(const QString &link);
37 39
 	private slots:
@@ -190,3 +192,181 @@ void addWebViewToLayout(QDomElement element, QStack<QWidget *> *widgetStack,
190 192
 @<Header files to include@>=
191 193
 #include "webview.h"
192 194
 
195
+@* Web View DOM Access.
196
+
197
+\noindent Two methods in |TypicaWebView| provide access to the DOM for the
198
+currently displayed page. These are simple wrappers. The |QWebElement| is also
199
+
200
+@<TypicaWebView implementation@>=
201
+QWebElement TypicaWebView::documentElement()
202
+{
203
+	return page()->mainFrame()->documentElement();
204
+}
205
+
206
+QWebElement TypicaWebView::findFirstElement(const QString &selector)
207
+{
208
+	return page()->mainFrame()->findFirstElement(selector);
209
+}
210
+
211
+@ In order to call these methods we need to be able to convert a |QWebElement|
212
+to and from a |QScriptValue|.
213
+
214
+@<Function prototypes for scripting@>=
215
+QScriptValue QWebElement_toScriptValue(QScriptEngine *engine, const QWebElement &element);
216
+void QWebElement_fromScriptValue(const QScriptValue &value, QWebElement &element);
217
+
218
+@ The implementation simply packs these in a variant.
219
+
220
+@<Functions for scripting@>=
221
+QScriptValue QWebElement_toScriptValue(QScriptEngine *engine, const QWebElement &element)
222
+{
223
+	QVariant var;
224
+	var.setValue(element);
225
+	QScriptValue object = engine->newVariant(var);
226
+	return object;
227
+}
228
+
229
+void QWebElement_fromScriptValue(const QScriptValue &value, QWebElement &element)
230
+{
231
+	element = value.toVariant().value<QWebElement>();
232
+}
233
+
234
+@ These methods must be registered with the engine.
235
+
236
+@<Set up the scripting engine@>=
237
+qScriptRegisterMetaType(engine, QWebElement_toScriptValue, QWebElement_fromScriptValue);
238
+
239
+@ As |QWebElement| by itself is not well suited for scripting, we must provide
240
+a way to attach useful properties to the returned object. We do this with a
241
+simple wrapper class.
242
+
243
+@(webelement.h@>=
244
+#include <QWebElement>
245
+#include <QObject>
246
+
247
+#ifndef TypicaWebElementHeader
248
+#define TypicaWebElementHeader
249
+
250
+class TypicaWebElement : public QObject
251
+{
252
+	Q_OBJECT
253
+	public:
254
+		TypicaWebElement(QWebElement element);
255
+		Q_INVOKABLE void appendInside(const QString &markup);
256
+		Q_INVOKABLE void appendOutside(const QString &markup);
257
+		Q_INVOKABLE void prependInside(const QString &markup);
258
+		Q_INVOKABLE void prependOutside(const QString &markup);
259
+		Q_INVOKABLE void removeFromDocument();
260
+		Q_INVOKABLE void replace(const QString &markup);
261
+		Q_INVOKABLE void setInnerXml(const QString &markup);
262
+		Q_INVOKABLE void setOuterXml(const QString &markup);
263
+		Q_INVOKABLE void setPlainText(const QString &text);
264
+	private:
265
+		QWebElement e;
266
+};
267
+
268
+#endif
269
+
270
+@ A constructor is required for creating this wrapper for the host environment.
271
+
272
+@<Function prototypes for scripting@>=
273
+QScriptValue constructWebElement(QScriptContext *context,
274
+                                 QScriptEngine *engine);
275
+
276
+@ The script engine is informed of this function.
277
+
278
+@<Set up the scripting engine@>=
279
+constructor = engine->newFunction(constructWebElement);
280
+engine->globalObject().setProperty("WebElement", constructor);
281
+
282
+@ A specialization of the |argument()| template method is required to
283
+pass the |QWebElement| through to the wrapper constructor.
284
+
285
+@<Functions for scripting@>=
286
+template<> QWebElement argument(int arg, QScriptContext *context)
287
+{
288
+	return qscriptvalue_cast<QWebElement>(context->argument(arg));
289
+}
290
+
291
+@ Our wrapper constructor takes a single argument which is the |QWebElement| to
292
+wrap.
293
+
294
+@<Functions for scripting@>=
295
+QScriptValue constructWebElement(QScriptContext *context,
296
+                                 QScriptEngine *engine)
297
+{
298
+	QWebElement element = argument<QWebElement>(0, context);
299
+	QScriptValue object = engine->newQObject(new TypicaWebElement(element));
300
+	return object;
301
+}
302
+
303
+@ The |TypicaWebElement| constructor just keeps a copy of the element passed as
304
+an argument.
305
+
306
+@<TypicaWebElement implementation@>=
307
+TypicaWebElement::TypicaWebElement(QWebElement element) : e(element)
308
+{
309
+	/* Nothing needs to be done here. */
310
+}
311
+
312
+@ Everything else is a simple wrapper around the equivalent |QWebElement|
313
+method.
314
+
315
+@<TypicaWebElement implementation@>=
316
+void TypicaWebElement::appendInside(const QString &markup)
317
+{
318
+	e.appendInside(markup);
319
+}
320
+
321
+void TypicaWebElement::appendOutside(const QString &markup)
322
+{
323
+	e.appendOutside(markup);
324
+}
325
+
326
+void TypicaWebElement::prependInside(const QString &markup)
327
+{
328
+	e.prependInside(markup);
329
+}
330
+
331
+void TypicaWebElement::prependOutside(const QString &markup)
332
+{
333
+	e.prependOutside(markup);
334
+}
335
+
336
+void TypicaWebElement::removeFromDocument()
337
+{
338
+	e.removeFromDocument();
339
+}
340
+
341
+void TypicaWebElement::replace(const QString &markup)
342
+{
343
+	e.replace(markup);
344
+}
345
+
346
+void TypicaWebElement::setInnerXml(const QString &markup)
347
+{
348
+	e.setInnerXml(markup);
349
+}
350
+
351
+void TypicaWebElement::setOuterXml(const QString &markup)
352
+{
353
+	e.setOuterXml(markup);
354
+}
355
+
356
+void TypicaWebElement::setPlainText(const QString &text)
357
+{
358
+	e.setPlainText(text);
359
+}
360
+
361
+@ Implementation is in a separate file.
362
+
363
+@(webelement.cpp@>=
364
+#include "webelement.h"
365
+
366
+@<TypicaWebElement implementation@>@;
367
+
368
+@ Another header is required.
369
+
370
+@<Header files to include@>=
371
+#include "webelement.h"
372
+

Loading…
Cancel
Save