Merge lp:~osomon/webbrowser-app/with-oxide into lp:webbrowser-app

Proposed by David Barth on 2014-03-28
Status: Merged
Merged at revision: 473
Proposed branch: lp:~osomon/webbrowser-app/with-oxide
Merge into: lp:webbrowser-app
Diff against target: 3771 lines (+1789/-1133)
50 files modified
CMakeLists.txt (+1/-0)
debian/control (+5/-2)
po/webbrowser-app.pot (+93/-67)
src/Ubuntu/Components/Extras/Browser/CMakeLists.txt (+1/-1)
src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml (+63/-0)
src/Ubuntu/Components/Extras/Browser/ItemSelector02.qml (+5/-2)
src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml (+58/-0)
src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml (+272/-0)
src/Ubuntu/Components/Extras/Browser/UbuntuWebView02.qml (+86/-50)
src/Ubuntu/Components/Extras/Browser/UserAgent01.qml (+90/-0)
src/Ubuntu/Components/Extras/Browser/UserAgent02.qml (+34/-62)
src/Ubuntu/Components/Extras/Browser/dummysingleton.qml (+27/-0)
src/Ubuntu/Components/Extras/Browser/plugin.cpp (+34/-0)
src/Ubuntu/Components/Extras/Browser/qmldir (+5/-1)
src/Ubuntu/Components/Extras/Browser/selection01.js (+193/-0)
src/Ubuntu/Components/Extras/Browser/selection02.js (+128/-174)
src/Ubuntu/Components/Extras/Browser/ua-override-worker.js (+46/-0)
src/app/AlertDialog.qml (+2/-2)
src/app/BeforeUnloadDialog.qml (+38/-0)
src/app/CMakeLists.txt (+2/-0)
src/app/PanelLoader.qml (+4/-1)
src/app/PromptDialog.qml (+7/-1)
src/app/WebViewImpl.qml (+14/-18)
src/app/browserapplication.cpp (+29/-2)
src/app/browserapplication.h (+3/-3)
src/app/webbrowser/BookmarksView.qml (+2/-2)
src/app/webbrowser/Browser.qml (+4/-22)
src/app/webbrowser/CMakeLists.txt (+1/-13)
src/app/webbrowser/TabsList.qml (+1/-1)
src/app/webbrowser/TimelineView.qml (+5/-5)
src/app/webbrowser/webbrowser-app.cpp (+4/-28)
src/app/webbrowser/webbrowser-app.h (+0/-5)
src/app/webbrowser/webthumbnail-provider.cpp (+0/-53)
src/app/webbrowser/webthumbnail-provider.h (+0/-39)
src/app/webbrowser/webthumbnail-utils.cpp (+0/-108)
src/app/webbrowser/webthumbnail-utils.h (+0/-51)
src/app/webbrowser/webview-thumbnailer.cpp (+0/-162)
src/app/webbrowser/webview-thumbnailer.h (+0/-64)
src/app/webcontainer/WebApp.qml (+18/-103)
src/app/webcontainer/WebViewImplWebkit.qml (+159/-0)
src/app/webcontainer/WebappContainerWebview.qml (+151/-0)
src/app/webcontainer/webapp-container.cpp (+56/-0)
src/app/webcontainer/webapp-container.h (+1/-0)
src/app/webcontainer/webapp-container.qml (+1/-0)
tests/autopilot/webbrowser_app/tests/test_tabs.py (+5/-0)
tests/unittests/qml/CMakeLists.txt (+10/-3)
tests/unittests/qml/tst_UbuntuWebView01.qml (+46/-0)
tests/unittests/qml/tst_UbuntuWebView02.qml (+3/-6)
tests/unittests/qml/tst_UserAgent.qml (+0/-82)
tests/unittests/qml/tst_UserAgent01.qml (+82/-0)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/with-oxide
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing on 2014-03-28
Ubuntu Phablet Team 2014-03-28 Pending
Review via email: mp+213256@code.launchpad.net

Commit message

Land the master Oxide support branch. See individual revisions for details.

Description of the change

Land the master Oxide support branch. See individual revisions for details.

To post a comment you must log in.
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:491
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/671/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/4342/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty-touch/3941/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-amd64-ci/173
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-armhf-ci/173
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-armhf-ci/173/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-trusty-i386-ci/173
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/3763/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/4441
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/4441/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/3943
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/3943/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-runner-mako/6220/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/5353

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/671/rebuild

review: Needs Fixing (continuous-integration)
lp:~osomon/webbrowser-app/with-oxide updated on 2014-03-28
492. By Alexandre Abreu on 2014-03-28

Make the webapp-container adaptable to the runtime context (oxide or not) and instanciate the proper web backend.
To account for the multiple potential frameworks (13.10, and soon 14.04) and avoid
    1. user having their webapps not working anymore,
    2. asking user to update their click package,
a bit of runtime behavior has been added (ack'd by Jamie Strandboge) to validate the presence of oxide.

493. By Olivier Tilloy on 2014-03-28

Clean up changelog.

PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-10-09 08:32:01 +0000
3+++ CMakeLists.txt 2014-03-28 17:03:06 +0000
4@@ -29,6 +29,7 @@
5 endif()
6
7 find_package(Qt5Core REQUIRED)
8+find_package(Qt5Gui REQUIRED)
9 find_package(Qt5Sql REQUIRED)
10 find_package(Qt5Widgets REQUIRED)
11 find_package(Qt5Quick REQUIRED)
12
13=== modified file 'debian/control'
14--- debian/control 2014-03-17 16:05:04 +0000
15+++ debian/control 2014-03-28 17:03:06 +0000
16@@ -8,8 +8,8 @@
17 hardening-wrapper,
18 python,
19 libqt5sql5-sqlite,
20- libqt5webkit5-dev,
21 libqt5webkit5-qmlwebkitplugin,
22+ liboxideqt-qmlplugin,
23 qt5-default,
24 qt5-qmake,
25 qtbase5-dev,
26@@ -19,6 +19,7 @@
27 qtdeclarative5-qtquick2-plugin,
28 qtdeclarative5-test-plugin,
29 qtdeclarative5-ubuntu-ui-toolkit-plugin,
30+ xvfb,
31 Standards-Version: 3.9.4
32 Homepage: https://launchpad.net/webbrowser-app
33 # If you aren't a member of ~phablet-team but need to upload packaging changes,
34@@ -30,7 +31,7 @@
35 Multi-Arch: foreign
36 Depends: ${misc:Depends},
37 ${shlibs:Depends},
38- libqt5webkit5-qmlwebkitplugin,
39+ liboxideqt-qmlplugin,
40 qtdeclarative5-qtquick2-plugin,
41 qtdeclarative5-ubuntu-ui-extras-browser-plugin (= ${binary:Version}),
42 qtdeclarative5-ubuntu-ui-toolkit-plugin,
43@@ -50,6 +51,7 @@
44 Depends: ${misc:Depends},
45 ${shlibs:Depends},
46 unity-webapps-qml,
47+ libqt5webkit5-qmlwebkitplugin,
48 webbrowser-app (= ${binary:Version}),
49 Description: Ubuntu web applications container
50 A lightweight webapps container tailored for Ubuntu, based on the Webkit
51@@ -62,6 +64,7 @@
52 ${shlibs:Depends},
53 libqt5sql5-sqlite,
54 libqt5webkit5-qmlwebkitplugin,
55+ liboxideqt-qmlplugin,
56 qtdeclarative5-qtquick2-plugin,
57 qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets (>= ${source:Version}),
58 qtdeclarative5-ubuntu-ui-toolkit-plugin,
59
60=== modified file 'po/webbrowser-app.pot'
61--- po/webbrowser-app.pot 2013-11-13 08:11:24 +0000
62+++ po/webbrowser-app.pot 2014-03-28 17:03:06 +0000
63@@ -8,7 +8,7 @@
64 msgstr ""
65 "Project-Id-Version: webbrowser-app\n"
66 "Report-Msgid-Bugs-To: \n"
67-"POT-Creation-Date: 2013-11-13 09:10+0100\n"
68+"POT-Creation-Date: 2014-03-26 10:59+0100\n"
69 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
70 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
71 "Language-Team: LANGUAGE <LL@li.org>\n"
72@@ -17,14 +17,6 @@
73 "Content-Type: text/plain; charset=UTF-8\n"
74 "Content-Transfer-Encoding: 8bit\n"
75
76-#: src/app/ActivityView.qml:36 src/app/Chrome.qml:127
77-msgid "Activity"
78-msgstr ""
79-
80-#: src/app/ActivityView.qml:54
81-msgid "Bookmarks"
82-msgstr ""
83-
84 #: src/app/AlertDialog.qml:24
85 msgid "JavaScript Alert"
86 msgstr ""
87@@ -57,6 +49,18 @@
88 msgid "Cancel"
89 msgstr ""
90
91+#: src/app/BeforeUnloadDialog.qml:24
92+msgid "Confirm Navigation"
93+msgstr ""
94+
95+#: src/app/BeforeUnloadDialog.qml:28
96+msgid "Leave"
97+msgstr ""
98+
99+#: src/app/BeforeUnloadDialog.qml:33
100+msgid "Stay"
101+msgstr ""
102+
103 #: src/app/CertificateVerificationDialog.qml:24
104 msgid "This connection is untrusted"
105 msgstr ""
106@@ -85,6 +89,10 @@
107 msgid "Forward"
108 msgstr ""
109
110+#: src/app/Chrome.qml:127 src/app/webbrowser/ActivityView.qml:36
111+msgid "Activity"
112+msgstr ""
113+
114 #: src/app/ConfirmDialog.qml:24
115 msgid "JavaScript Confirmation"
116 msgstr ""
117@@ -134,52 +142,6 @@
118 msgid "The website %1:%2 requires authentication."
119 msgstr ""
120
121-#. TRANSLATORS: %1 refers to the number of open tabs
122-#: src/app/TabsList.qml:37
123-#, qt-format
124-msgid "Currently viewing (%1)"
125-msgstr ""
126-
127-#: src/app/TabsList.qml:68
128-msgid "+"
129-msgstr ""
130-
131-#: src/app/TimelineView.qml:83
132-msgid "Today"
133-msgstr ""
134-
135-#: src/app/TimelineView.qml:85
136-msgid "Yesterday"
137-msgstr ""
138-
139-#: src/app/TimelineView.qml:87
140-msgid "Last 7 Days"
141-msgstr ""
142-
143-#: src/app/TimelineView.qml:89
144-msgid "This Month"
145-msgstr ""
146-
147-#: src/app/TimelineView.qml:91
148-msgid "This Year"
149-msgstr ""
150-
151-#: src/app/TimelineView.qml:93
152-msgid "Older"
153-msgstr ""
154-
155-#: src/app/TimelineView.qml:276
156-msgid "(local files)"
157-msgstr ""
158-
159-#: src/app/TimelineView.qml:278
160-msgid "(other)"
161-msgstr ""
162-
163-#: src/app/WebViewImpl.qml:52
164-msgid "This page wants to know your device’s location."
165-msgstr ""
166-
167 #. TRANSLATORS: This is a free-form list of keywords associated to the 'Back' action.
168 #. Keywords may actually be sentences, and must be separated by semi-colons.
169 #: src/app/actions/Back.qml:26
170@@ -266,24 +228,88 @@
171 msgid "Leave Page"
172 msgstr ""
173
174+#: src/app/webbrowser/ActivityView.qml:54
175+msgid "Bookmarks"
176+msgstr ""
177+
178+#. TRANSLATORS: %1 refers to the number of open tabs
179+#: src/app/webbrowser/TabsList.qml:37
180+#, qt-format
181+msgid "Currently viewing (%1)"
182+msgstr ""
183+
184+#: src/app/webbrowser/TabsList.qml:68
185+msgid "+"
186+msgstr ""
187+
188+#: src/app/webbrowser/TimelineView.qml:84
189+msgid "Today"
190+msgstr ""
191+
192+#: src/app/webbrowser/TimelineView.qml:86
193+msgid "Yesterday"
194+msgstr ""
195+
196+#: src/app/webbrowser/TimelineView.qml:88
197+msgid "Last 7 Days"
198+msgstr ""
199+
200+#: src/app/webbrowser/TimelineView.qml:90
201+msgid "This Month"
202+msgstr ""
203+
204+#: src/app/webbrowser/TimelineView.qml:92
205+msgid "This Year"
206+msgstr ""
207+
208+#: src/app/webbrowser/TimelineView.qml:94
209+msgid "Older"
210+msgstr ""
211+
212+#: src/app/webbrowser/TimelineView.qml:277
213+msgid "(local files)"
214+msgstr ""
215+
216+#: src/app/webbrowser/TimelineView.qml:279
217+msgid "(other)"
218+msgstr ""
219+
220+#: src/app/webbrowser/webbrowser-app.desktop.in:3
221+msgid "Browser"
222+msgstr ""
223+
224+#: src/app/webbrowser/webbrowser-app.desktop.in:4
225+msgid "Web Browser"
226+msgstr ""
227+
228+#: src/app/webbrowser/webbrowser-app.desktop.in:5
229+msgid "Browse the World Wide Web"
230+msgstr ""
231+
232 #. TRANSLATORS: %1 refers to the current page’s title
233-#: src/app/webapp-container.qml:44 src/app/webbrowser-app.qml:35
234+#: src/app/webbrowser/webbrowser-app.qml:35
235+#: src/app/webcontainer/webapp-container.qml:44
236 #, qt-format
237 msgid "%1 - Ubuntu Web Browser"
238 msgstr ""
239
240-#: src/app/webapp-container.qml:46 src/app/webbrowser-app.qml:37
241+#: src/app/webbrowser/webbrowser-app.qml:37
242+#: src/app/webcontainer/webapp-container.qml:46
243 msgid "Ubuntu Web Browser"
244 msgstr ""
245
246-#: src/app/webbrowser-app.desktop.in:3
247-msgid "Browser"
248-msgstr ""
249-
250-#: src/app/webbrowser-app.desktop.in:4
251-msgid "Web Browser"
252-msgstr ""
253-
254-#: src/app/webbrowser-app.desktop.in:5
255-msgid "Browse the World Wide Web"
256+#: src/app/webcontainer/AccountsLoginPage.qml:70
257+msgid "No local account found for "
258+msgstr ""
259+
260+#: src/app/webcontainer/AccountsLoginPage.qml:75
261+msgid "Skip account creation step"
262+msgstr ""
263+
264+#: src/app/webcontainer/AccountsLoginPage.qml:124
265+msgid "Add account"
266+msgstr ""
267+
268+#: src/app/webcontainer/AccountsView.qml:38
269+msgid "Select an account"
270 msgstr ""
271
272=== modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt'
273--- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-03-13 07:33:10 +0000
274+++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-03-28 17:03:06 +0000
275@@ -13,7 +13,7 @@
276
277 add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
278
279-qt5_use_modules(${PLUGIN} Core Qml)
280+qt5_use_modules(${PLUGIN} Core Gui Qml)
281
282 file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
283 install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR})
284
285=== added file 'src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml'
286--- src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml 1970-01-01 00:00:00 +0000
287+++ src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml 2014-03-28 17:03:06 +0000
288@@ -0,0 +1,63 @@
289+/*
290+ * Copyright 2013 Canonical Ltd.
291+ *
292+ * This file is part of webbrowser-app.
293+ *
294+ * webbrowser-app is free software; you can redistribute it and/or modify
295+ * it under the terms of the GNU General Public License as published by
296+ * the Free Software Foundation; version 3.
297+ *
298+ * webbrowser-app is distributed in the hope that it will be useful,
299+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
300+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301+ * GNU General Public License for more details.
302+ *
303+ * You should have received a copy of the GNU General Public License
304+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
305+ */
306+
307+import QtQuick 2.0
308+import Ubuntu.Components 0.1
309+import Ubuntu.Components.ListItems 0.1 as ListItem
310+import Ubuntu.Components.Popups 0.1
311+
312+Popover {
313+ id: itemSelector
314+
315+ property QtObject selectorModel: model
316+
317+ caller: parent
318+ contentWidth: Math.min(parent.width - units.gu(10), units.gu(40))
319+ property real listContentHeight: 0 // intermediate property to avoid binding loop
320+ contentHeight: Math.min(parent.height - units.gu(10), listContentHeight)
321+
322+ ListView {
323+ clip: true
324+ width: itemSelector.contentWidth
325+ height: itemSelector.contentHeight
326+
327+ model: selectorModel.items
328+
329+ delegate: ListItem.Standard {
330+ text: model.text
331+ enabled: model.enabled
332+ selected: model.selected
333+ onClicked: selectorModel.accept(model.index)
334+ }
335+
336+ section.property: "group"
337+ section.delegate: ListItem.Header {
338+ text: section
339+ }
340+
341+ onContentHeightChanged: itemSelector.listContentHeight = contentHeight
342+ }
343+
344+ Component.onCompleted: show()
345+
346+ onVisibleChanged: {
347+ if (!visible) {
348+ selectorModel.reject()
349+ }
350+ }
351+}
352
353=== renamed file 'src/Ubuntu/Components/Extras/Browser/ItemSelector.qml' => 'src/Ubuntu/Components/Extras/Browser/ItemSelector02.qml'
354--- src/Ubuntu/Components/Extras/Browser/ItemSelector.qml 2013-03-21 16:44:04 +0000
355+++ src/Ubuntu/Components/Extras/Browser/ItemSelector02.qml 2014-03-28 17:03:06 +0000
356@@ -42,7 +42,10 @@
357 text: model.text
358 enabled: model.enabled
359 selected: model.selected
360- onClicked: selectorModel.accept(model.index)
361+ onClicked: {
362+ selectorModel.items.select(model.index)
363+ selectorModel.accept()
364+ }
365 }
366
367 section.property: "group"
368@@ -57,7 +60,7 @@
369
370 onVisibleChanged: {
371 if (!visible) {
372- selectorModel.reject()
373+ selectorModel.cancel()
374 }
375 }
376 }
377
378=== added file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml'
379--- src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml 1970-01-01 00:00:00 +0000
380+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml 2014-03-28 17:03:06 +0000
381@@ -0,0 +1,58 @@
382+/*
383+ * Copyright 2014 Canonical Ltd.
384+ *
385+ * This file is part of webbrowser-app.
386+ *
387+ * webbrowser-app is free software; you can redistribute it and/or modify
388+ * it under the terms of the GNU General Public License as published by
389+ * the Free Software Foundation; version 3.
390+ *
391+ * webbrowser-app is distributed in the hope that it will be useful,
392+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
393+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
394+ * GNU General Public License for more details.
395+ *
396+ * You should have received a copy of the GNU General Public License
397+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
398+ */
399+
400+pragma Singleton
401+
402+import QtQuick 2.0
403+import com.canonical.Oxide 0.1
404+
405+Item {
406+ property string customUA: userAgent.defaultUA
407+
408+ property QtObject sharedContext: WebContext {
409+ dataPath: dataLocation
410+ userAgent: customUA
411+ networkRequestDelegate: uaOverrideWorker.item
412+ userAgentOverrideDelegate: networkRequestDelegate
413+ userScripts: [
414+ UserScript {
415+ context: "oxide://selection/"
416+ url: Qt.resolvedUrl("selection02.js")
417+ incognitoEnabled: true
418+ matchAllFrames: true
419+ }
420+ ]
421+ }
422+
423+ Component {
424+ id: uaOverrideWorkerComponent
425+
426+ WebContextDelegateWorker {
427+ source: Qt.resolvedUrl("ua-override-worker.js")
428+ onMessage: console.log("Overriden UA for", message.url, ":", message.override)
429+ }
430+ }
431+ Loader {
432+ id: uaOverrideWorker
433+ sourceComponent: (formFactor === "mobile") ? uaOverrideWorkerComponent : undefined
434+ }
435+
436+ UserAgent02 {
437+ id: userAgent
438+ }
439+}
440
441=== added file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml'
442--- src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml 1970-01-01 00:00:00 +0000
443+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml 2014-03-28 17:03:06 +0000
444@@ -0,0 +1,272 @@
445+/*
446+ * Copyright 2013 Canonical Ltd.
447+ *
448+ * This file is part of webbrowser-app.
449+ *
450+ * webbrowser-app is free software; you can redistribute it and/or modify
451+ * it under the terms of the GNU General Public License as published by
452+ * the Free Software Foundation; version 3.
453+ *
454+ * webbrowser-app is distributed in the hope that it will be useful,
455+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
456+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
457+ * GNU General Public License for more details.
458+ *
459+ * You should have received a copy of the GNU General Public License
460+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
461+ */
462+
463+import QtQuick 2.0
464+import QtWebKit 3.1
465+import QtWebKit.experimental 1.0
466+import Ubuntu.Components 0.1
467+import Ubuntu.Components.Extras.Browser 0.1
468+import Ubuntu.Components.Popups 0.1
469+
470+/*!
471+ \qmltype MainView
472+ \inqmlmodule Ubuntu.Components.Extras.Browser 0.1
473+ \obsolete
474+ \brief Custom Ubuntu WebView extending QtWebKit’s WebView
475+
476+ This version of UbuntuWebView is deprecated and shouldn’t be used in new
477+ code. Use version 0.2 or higher instead.
478+*/
479+WebView {
480+ id: _webview
481+
482+ signal newTabRequested(url url)
483+
484+ QtObject {
485+ property real devicePixelRatio: QtWebKitDPR
486+ onDevicePixelRatioChanged: {
487+ // Do not make this patch to QtWebKit a hard requirement.
488+ if (_webview.experimental.hasOwnProperty('devicePixelRatio')) {
489+ _webview.experimental.devicePixelRatio = devicePixelRatio
490+ }
491+ }
492+ }
493+
494+ interactive: !selection.visible
495+ maximumFlickVelocity: height * 5
496+
497+ /**
498+ * Client overridable function called before the default treatment of a
499+ * valid navigation request. This function can stop the navigation request
500+ * if it sets the 'action' field of the request to IgnoreRequest.
501+ *
502+ */
503+ function navigationRequestedDelegate(request) { }
504+
505+ UserAgent01 {
506+ id: userAgent
507+ }
508+
509+ /**
510+ * This function can be overridden by client applications that embed an
511+ * UbuntuWebView to provide a static overridden UA string.
512+ * If not overridden, the default UA string and the default override
513+ * mechanism will be used.
514+ */
515+ function getUAString() {
516+ // Note that this function used to accept a 'url' parameter to allow
517+ // embedders to implement a custom override mechanism. It was removed
518+ // after observing that no application was using it, and to simplify
519+ // the API. Embedders willing to provide a custom override mechanism
520+ // can always override (at their own risk) the onNavigationRequested
521+ // slot.
522+ return undefined
523+ }
524+ experimental.userAgent: (_webview.getUAString() === undefined) ? userAgent.defaultUA : _webview.getUAString()
525+ onNavigationRequested: {
526+ request.action = WebView.AcceptRequest;
527+
528+ navigationRequestedDelegate (request);
529+ if (request.action === WebView.IgnoreRequest)
530+ return;
531+
532+ var staticUA = _webview.getUAString()
533+ if (staticUA === undefined) {
534+ _webview.experimental.userAgent = userAgent.getUAString(request.url)
535+ } else {
536+ _webview.experimental.userAgent = staticUA
537+ }
538+ }
539+
540+ experimental.preferences.navigatorQtObjectEnabled: true
541+ experimental.userScripts: [Qt.resolvedUrl("hyperlinks.js"),
542+ Qt.resolvedUrl("selection01.js")]
543+ experimental.onMessageReceived: {
544+ var data = null
545+ try {
546+ data = JSON.parse(message.data)
547+ } catch (error) {
548+ console.debug('DEBUG:', message.data)
549+ return
550+ }
551+ if ('event' in data) {
552+ if (data.event === 'longpress') {
553+ if (('img' in data) || ('href' in data)) {
554+ contextualData.clear()
555+ if ('img' in data) {
556+ contextualData.img = data.img
557+ }
558+ if ('href' in data) {
559+ contextualData.href = data.href
560+ contextualData.title = data.title
561+ }
562+ contextualRectangle.position(data)
563+ PopupUtils.open(contextualPopover, contextualRectangle)
564+ return
565+ }
566+ }
567+ if ((data.event === 'longpress') || (data.event === 'selectionadjusted')) {
568+ selection.clearData()
569+ selection.createData()
570+ if ('html' in data) {
571+ selection.mimedata.html = data.html
572+ }
573+ // FIXME: push the text and image data in the order
574+ // they appear in the selected block.
575+ if ('text' in data) {
576+ selection.mimedata.text = data.text
577+ }
578+ if ('images' in data) {
579+ // TODO: download and cache the images locally
580+ // (grab them from the webview’s cache, if possible),
581+ // and forward local URLs.
582+ selection.mimedata.urls = data.images
583+ }
584+ selection.show(data.left, data.top, data.width, data.height)
585+ } else if (data.event === 'newtab') {
586+ newTabRequested(data.url)
587+ }
588+ }
589+ }
590+
591+ experimental.itemSelector: ItemSelector01 {}
592+
593+ property alias selection: selection
594+ property ActionList selectionActions
595+ Selection {
596+ id: selection
597+
598+ anchors.fill: parent
599+ visible: false
600+
601+ property Item __popover: null
602+ property var mimedata: null
603+
604+ Component {
605+ id: selectionPopover
606+ ActionSelectionPopover {
607+ grabDismissAreaEvents: false
608+ actions: selectionActions
609+ }
610+ }
611+
612+ function createData() {
613+ if (mimedata === null) {
614+ mimedata = Clipboard.newData()
615+ }
616+ }
617+
618+ function clearData() {
619+ if (mimedata !== null) {
620+ delete mimedata
621+ mimedata = null
622+ }
623+ }
624+
625+ function actionTriggered() {
626+ selection.visible = false
627+ }
628+
629+ function __showPopover() {
630+ __popover = PopupUtils.open(selectionPopover, selection.rect)
631+ var actions = __popover.actions.actions
632+ for (var i in actions) {
633+ actions[i].onTriggered.connect(actionTriggered)
634+ }
635+ }
636+
637+ function show(x, y, width, height) {
638+ var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
639+ rect.x = x * scale + _webview.contentX
640+ rect.y = y * scale + _webview.contentY
641+ rect.width = width * scale
642+ rect.height = height * scale
643+ visible = true
644+ __showPopover()
645+ }
646+
647+ onVisibleChanged: {
648+ if (!visible && (__popover != null)) {
649+ PopupUtils.close(__popover)
650+ __popover = null
651+ }
652+ }
653+
654+ onResized: {
655+ var message = new Object
656+ message.query = 'adjustselection'
657+ var rect = selection.rect
658+ var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
659+ message.left = (rect.x - _webview.contentX) / scale
660+ message.right = (rect.x + rect.width - _webview.contentX) / scale
661+ message.top = (rect.y - _webview.contentY) / scale
662+ message.bottom = (rect.y + rect.height - _webview.contentY) / scale
663+ _webview.experimental.postMessage(JSON.stringify(message))
664+ }
665+
666+ function copy() {
667+ Clipboard.push(mimedata)
668+ clearData()
669+ }
670+ }
671+
672+ Item {
673+ id: contextualRectangle
674+
675+ visible: false
676+
677+ function position(data) {
678+ var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
679+ x = data.left * scale
680+ y = data.top * scale
681+ width = data.width * scale
682+ height = data.height * scale
683+ }
684+ }
685+ property QtObject contextualData: QtObject {
686+ property url href
687+ property string title
688+ property url img
689+
690+ function clear() {
691+ href = ''
692+ title = ''
693+ img = ''
694+ }
695+ }
696+
697+ property ActionList contextualActions
698+ Component {
699+ id: contextualPopover
700+ ActionSelectionPopover {
701+ actions: contextualActions
702+ }
703+ }
704+
705+ Scrollbar {
706+ parent: _webview.parent
707+ flickableItem: _webview
708+ align: Qt.AlignTrailing
709+ }
710+
711+ Scrollbar {
712+ parent: _webview.parent
713+ flickableItem: _webview
714+ align: Qt.AlignBottom
715+ }
716+}
717
718=== renamed file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml' => 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView02.qml'
719--- src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml 2014-03-14 17:33:23 +0000
720+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebView02.qml 2014-03-28 17:03:06 +0000
721@@ -17,29 +17,18 @@
722 */
723
724 import QtQuick 2.0
725-import QtWebKit 3.1
726-import QtWebKit.experimental 1.0
727+import QtQuick.Window 2.0
728+import com.canonical.Oxide 0.1
729 import Ubuntu.Components 0.1
730-import Ubuntu.Components.Extras.Browser 0.1
731 import Ubuntu.Components.Popups 0.1
732+import "."
733
734 WebView {
735 id: _webview
736
737 signal newTabRequested(url url)
738
739- QtObject {
740- property real devicePixelRatio: QtWebKitDPR
741- onDevicePixelRatioChanged: {
742- // Do not make this patch to QtWebKit a hard requirement.
743- if (_webview.experimental.hasOwnProperty('devicePixelRatio')) {
744- _webview.experimental.devicePixelRatio = devicePixelRatio
745- }
746- }
747- }
748-
749- interactive: !selection.visible
750- maximumFlickVelocity: height * 5
751+ //interactive: !selection.visible
752
753 /**
754 * Client overridable function called before the default treatment of a
755@@ -49,27 +38,65 @@
756 */
757 function navigationRequestedDelegate(request) { }
758
759- UserAgent {
760- id: userAgent
761- }
762-
763 /**
764 * This function can be overridden by client applications that embed an
765 * UbuntuWebView to provide a static overridden UA string.
766 * If not overridden, the default UA string and the default override
767 * mechanism will be used.
768+ *
769+ * Note: as the UA string is a property of the shared context,
770+ * an application that embeds several UbuntuWebViews that define different
771+ * custom UA strings will result in the last view instantiated setting the
772+ * UA for all the views.
773 */
774 function getUAString() {
775- // Note that this function used to accept a 'url' parameter to allow
776- // embedders to implement a custom override mechanism. It was removed
777- // after observing that no application was using it, and to simplify
778- // the API. Embedders willing to provide a custom override mechanism
779- // can always override (at their own risk) the onNavigationRequested
780- // slot.
781 return undefined
782 }
783- experimental.userAgent: (_webview.getUAString() === undefined) ? userAgent.defaultUA : _webview.getUAString()
784- onNavigationRequested: {
785+
786+ context: UbuntuWebContext.sharedContext
787+ Component.onCompleted: {
788+ var customUA = getUAString()
789+ if (customUA !== undefined) {
790+ UbuntuWebContext.customUA = customUA
791+ }
792+ }
793+
794+ messageHandlers: [
795+ ScriptMessageHandler {
796+ msgId: "contextmenu"
797+ contexts: ["oxide://selection/"]
798+ callback: function(msg, frame) {
799+ if (('img' in msg.args) || ('href' in msg.args)) {
800+ if (internal.currentContextualMenu != null) {
801+ PopupUtils.close(internal.currentContextualMenu)
802+ }
803+ contextualData.clear()
804+ if ('img' in msg.args) {
805+ contextualData.img = msg.args.img
806+ }
807+ if ('href' in msg.args) {
808+ contextualData.href = msg.args.href
809+ contextualData.title = msg.args.title
810+ }
811+ contextualRectangle.position(msg.args)
812+ internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle)
813+ } else if (internal.currentContextualMenu != null) {
814+ PopupUtils.close(internal.currentContextualMenu)
815+ }
816+ }
817+ },
818+ ScriptMessageHandler {
819+ msgId: "scroll"
820+ contexts: ["oxide://selection/"]
821+ callback: function(msg, frame) {
822+ if (internal.currentContextualMenu != null) {
823+ PopupUtils.close(internal.currentContextualMenu)
824+ }
825+ }
826+ }
827+ ]
828+
829+ /*onNavigationRequested: {
830 request.action = WebView.AcceptRequest;
831
832 navigationRequestedDelegate (request);
833@@ -82,9 +109,9 @@
834 } else {
835 _webview.experimental.userAgent = staticUA
836 }
837- }
838+ }*/
839
840- experimental.preferences.navigatorQtObjectEnabled: true
841+ /*experimental.preferences.navigatorQtObjectEnabled: true
842 experimental.userScripts: [Qt.resolvedUrl("hyperlinks.js"),
843 Qt.resolvedUrl("selection.js")]
844 experimental.onMessageReceived: {
845@@ -133,11 +160,11 @@
846 newTabRequested(data.url)
847 }
848 }
849- }
850-
851- experimental.itemSelector: ItemSelector {}
852-
853- property alias selection: selection
854+ }*/
855+
856+ popupMenu: ItemSelector02 {}
857+
858+ /*property alias selection: selection
859 property ActionList selectionActions
860 Selection {
861 id: selection
862@@ -214,7 +241,7 @@
863 Clipboard.push(mimedata)
864 clearData()
865 }
866- }
867+ }*/
868
869 Item {
870 id: contextualRectangle
871@@ -222,11 +249,10 @@
872 visible: false
873
874 function position(data) {
875- var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
876- x = data.left * scale
877- y = data.top * scale
878- width = data.width * scale
879- height = data.height * scale
880+ x = data.left * data.scaleX
881+ y = data.top * data.scaleY
882+ width = data.width * data.scaleX
883+ height = data.height * data.scaleY
884 }
885 }
886 property QtObject contextualData: QtObject {
887@@ -249,15 +275,25 @@
888 }
889 }
890
891- Scrollbar {
892- parent: _webview.parent
893- flickableItem: _webview
894- align: Qt.AlignTrailing
895- }
896-
897- Scrollbar {
898- parent: _webview.parent
899- flickableItem: _webview
900- align: Qt.AlignBottom
901+ QtObject {
902+ id: internal
903+ property int lastLoadRequestStatus: -1
904+ property Item currentContextualMenu: null
905+ }
906+
907+ readonly property bool lastLoadSucceeded: internal.lastLoadRequestStatus === LoadEvent.TypeSucceeded
908+ readonly property bool lastLoadStopped: internal.lastLoadRequestStatus === LoadEvent.TypeStopped
909+ readonly property bool lastLoadFailed: internal.lastLoadRequestStatus === LoadEvent.TypeFailed
910+ onLoadingChanged: {
911+ if (loadEvent.url.toString() !== "data:text/html,chromewebdata") {
912+ internal.lastLoadRequestStatus = loadEvent.type
913+ }
914+ }
915+
916+ readonly property int screenOrientation: Screen.orientation
917+ onScreenOrientationChanged: {
918+ if (internal.currentContextualMenu != null) {
919+ PopupUtils.close(internal.currentContextualMenu)
920+ }
921 }
922 }
923
924=== added file 'src/Ubuntu/Components/Extras/Browser/UserAgent01.qml'
925--- src/Ubuntu/Components/Extras/Browser/UserAgent01.qml 1970-01-01 00:00:00 +0000
926+++ src/Ubuntu/Components/Extras/Browser/UserAgent01.qml 2014-03-28 17:03:06 +0000
927@@ -0,0 +1,90 @@
928+/*
929+ * Copyright 2013 Canonical Ltd.
930+ *
931+ * This file is part of webbrowser-app.
932+ *
933+ * webbrowser-app is free software; you can redistribute it and/or modify
934+ * it under the terms of the GNU General Public License as published by
935+ * the Free Software Foundation; version 3.
936+ *
937+ * webbrowser-app is distributed in the hope that it will be useful,
938+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
939+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
940+ * GNU General Public License for more details.
941+ *
942+ * You should have received a copy of the GNU General Public License
943+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
944+ */
945+
946+import QtQuick 2.0
947+import QtQuick.Window 2.0
948+import Ubuntu.Components 0.1
949+import "ua-overrides.js" as Overrides
950+
951+/*
952+ * Useful documentation:
953+ * http://en.wikipedia.org/wiki/User_agent#Format
954+ * https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
955+ * https://wiki.mozilla.org/B2G/User_Agent
956+ * https://github.com/mozilla-b2g/gaia/blob/master/build/ua-override-prefs.js
957+ * https://developers.google.com/chrome/mobile/docs/user-agent
958+ */
959+
960+// This is an Item, not a QtObject, because it needs information about the Screen.
961+Item {
962+ // %1: form factor (Mobile, Tablet, Desktop)
963+ // %2: WebKit version
964+ readonly property string _template: "Mozilla/5.0 (Ubuntu; %1) WebKit/%2"
965+
966+ // See Source/WebCore/Configurations/Version.xcconfig in QtWebKit’s source tree
967+ // TODO: determine this value at runtime
968+ readonly property string _webkitVersion: "537.21"
969+
970+ // FIXME: this is a quick hack that will become increasingly unreliable
971+ // as we support more devices, so we need a better solution for this
972+ // FIXME: only handling phone and tablet for now, need to handle desktop too
973+ readonly property string _formFactor: (Screen.width >= units.gu(60)) ? "Tablet" : "Mobile"
974+
975+ property string defaultUA: _template.arg(_formFactor).arg(_webkitVersion)
976+
977+ property var overrides: Overrides.overrides
978+
979+ function getDomain(url) {
980+ var domain = url.toString()
981+ var indexOfScheme = domain.indexOf("://")
982+ if (indexOfScheme !== -1) {
983+ domain = domain.slice(indexOfScheme + 3)
984+ }
985+ var indexOfPath = domain.indexOf("/")
986+ if (indexOfPath !== -1) {
987+ domain = domain.slice(0, indexOfPath)
988+ }
989+ return domain
990+ }
991+
992+ function getDomains(domain) {
993+ var components = domain.split(".")
994+ var domains = []
995+ for (var i = 0; i < components.length; i++) {
996+ domains.push(components.slice(i).join("."))
997+ }
998+ return domains
999+ }
1000+
1001+ function getUAString(url) {
1002+ var ua = defaultUA
1003+ var domains = getDomains(getDomain(url))
1004+ for (var i = 0; i < domains.length; i++) {
1005+ var domain = domains[i]
1006+ if (domain in overrides) {
1007+ var form = overrides[domain]
1008+ if (typeof form == "string") {
1009+ return form
1010+ } else if (typeof form == "object") {
1011+ return ua.replace(form[0], form[1])
1012+ }
1013+ }
1014+ }
1015+ return ua
1016+ }
1017+}
1018
1019=== renamed file 'src/Ubuntu/Components/Extras/Browser/UserAgent.qml' => 'src/Ubuntu/Components/Extras/Browser/UserAgent02.qml'
1020--- src/Ubuntu/Components/Extras/Browser/UserAgent.qml 2013-09-25 16:38:06 +0000
1021+++ src/Ubuntu/Components/Extras/Browser/UserAgent02.qml 2014-03-28 17:03:06 +0000
1022@@ -1,5 +1,5 @@
1023 /*
1024- * Copyright 2013 Canonical Ltd.
1025+ * Copyright 2013-2014 Canonical Ltd.
1026 *
1027 * This file is part of webbrowser-app.
1028 *
1029@@ -16,10 +16,7 @@
1030 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1031 */
1032
1033-import QtQuick 2.0
1034-import QtQuick.Window 2.0
1035-import Ubuntu.Components 0.1
1036-import "ua-overrides.js" as Overrides
1037+import QtQml 2.0
1038
1039 /*
1040 * Useful documentation:
1041@@ -30,61 +27,36 @@
1042 * https://developers.google.com/chrome/mobile/docs/user-agent
1043 */
1044
1045-// This is an Item, not a QtObject, because it needs information about the Screen.
1046-Item {
1047- // %1: form factor (Mobile, Tablet, Desktop)
1048- // %2: WebKit version
1049- readonly property string _template: "Mozilla/5.0 (Ubuntu; %1) WebKit/%2"
1050-
1051- // See Source/WebCore/Configurations/Version.xcconfig in QtWebKit’s source tree
1052- // TODO: determine this value at runtime
1053- readonly property string _webkitVersion: "537.21"
1054-
1055- // FIXME: this is a quick hack that will become increasingly unreliable
1056- // as we support more devices, so we need a better solution for this
1057- // FIXME: only handling phone and tablet for now, need to handle desktop too
1058- readonly property string _formFactor: (Screen.width >= units.gu(60)) ? "Tablet" : "Mobile"
1059-
1060- property string defaultUA: _template.arg(_formFactor).arg(_webkitVersion)
1061-
1062- property var overrides: Overrides.overrides
1063-
1064- function getDomain(url) {
1065- var domain = url.toString()
1066- var indexOfScheme = domain.indexOf("://")
1067- if (indexOfScheme !== -1) {
1068- domain = domain.slice(indexOfScheme + 3)
1069- }
1070- var indexOfPath = domain.indexOf("/")
1071- if (indexOfPath !== -1) {
1072- domain = domain.slice(0, indexOfPath)
1073- }
1074- return domain
1075- }
1076-
1077- function getDomains(domain) {
1078- var components = domain.split(".")
1079- var domains = []
1080- for (var i = 0; i < components.length; i++) {
1081- domains.push(components.slice(i).join("."))
1082- }
1083- return domains
1084- }
1085-
1086- function getUAString(url) {
1087- var ua = defaultUA
1088- var domains = getDomains(getDomain(url))
1089- for (var i = 0; i < domains.length; i++) {
1090- var domain = domains[i]
1091- if (domain in overrides) {
1092- var form = overrides[domain]
1093- if (typeof form == "string") {
1094- return form
1095- } else if (typeof form == "object") {
1096- return ua.replace(form[0], form[1])
1097- }
1098- }
1099- }
1100- return ua
1101- }
1102+QtObject {
1103+ // %1: Ubuntu version, e.g. "14.04"
1104+ // %2: optional token to specify further attributes of the platform (must start with a whitespace), e.g. "like Android"
1105+ // %3: optional hardware ID token (must start with a semi-colon if present)
1106+ // %4: WebKit version, e.g. "537.36"
1107+ // %5: Chromium version, e.g. "35.0.1870.2"
1108+ // %6: optional token to provide additional free-form information (must start with a whitespace), e.g. "Mobile"
1109+ // note #1: "Mozilla/5.0" is misinformation, but it is a legacy token that
1110+ // virtually every single UA out there has, it seems unwise to remove it
1111+ // note #2: "AppleWebKit", as opposed to plain "WebKit", does make a
1112+ // difference in the content served by certain sites (e.g. gmail.com)
1113+ readonly property string _template: "Mozilla/5.0 (Linux; Ubuntu %1%2%3) AppleWebKit/%4 Chromium/%5%6"
1114+
1115+ // FIXME: compute at build time (using lsb_release)
1116+ readonly property string _ubuntuVersion: "14.04"
1117+
1118+ readonly property string _attributes: (formFactor === "mobile") ? " like Android 4.4" : ""
1119+
1120+ readonly property string _hardwareID: ""
1121+
1122+ // See chromium/src/webkit/build/webkit_version.h.in in oxide’s source tree.
1123+ readonly property string _webkitVersion: "537.36"
1124+
1125+ // See chromium/src/chrome/VERSION in oxide’s source tree.
1126+ // Note: the actual version number probably doesn’t matter that much,
1127+ // however its format does, so we probably don’t need to bump it
1128+ // every time we rebase on a newer chromium.
1129+ readonly property string _chromiumVersion: "35.0.1870.2"
1130+
1131+ readonly property string _more: (formFactor === "mobile") ? " Mobile" : ""
1132+
1133+ property string defaultUA: _template.arg(_ubuntuVersion).arg(_attributes).arg(_hardwareID).arg(_webkitVersion).arg(_chromiumVersion).arg(_more)
1134 }
1135
1136=== added file 'src/Ubuntu/Components/Extras/Browser/dummysingleton.qml'
1137--- src/Ubuntu/Components/Extras/Browser/dummysingleton.qml 1970-01-01 00:00:00 +0000
1138+++ src/Ubuntu/Components/Extras/Browser/dummysingleton.qml 2014-03-28 17:03:06 +0000
1139@@ -0,0 +1,27 @@
1140+/*
1141+ * Copyright 2014 Canonical Ltd.
1142+ *
1143+ * This file is part of webbrowser-app.
1144+ *
1145+ * webbrowser-app is free software; you can redistribute it and/or modify
1146+ * it under the terms of the GNU General Public License as published by
1147+ * the Free Software Foundation; version 3.
1148+ *
1149+ * webbrowser-app is distributed in the hope that it will be useful,
1150+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1151+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1152+ * GNU General Public License for more details.
1153+ *
1154+ * You should have received a copy of the GNU General Public License
1155+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1156+ */
1157+
1158+// This file is not really used, but without it importing version 0.1 of
1159+// Ubuntu.Components.Extras.Browser fails because the QML engine requests type
1160+// UbuntuWebContext, despite it being specific to version 0.2 of the module.
1161+
1162+pragma Singleton
1163+
1164+import QtQml 2.0
1165+
1166+QtObject {}
1167
1168=== modified file 'src/Ubuntu/Components/Extras/Browser/plugin.cpp'
1169--- src/Ubuntu/Components/Extras/Browser/plugin.cpp 2014-03-12 17:48:34 +0000
1170+++ src/Ubuntu/Components/Extras/Browser/plugin.cpp 2014-03-28 17:03:06 +0000
1171@@ -21,6 +21,8 @@
1172 // Qt
1173 #include <QtCore/QDir>
1174 #include <QtCore/QStandardPaths>
1175+#include <QtCore/QtGlobal>
1176+#include <QtGui/QGuiApplication>
1177 #include <QtQml>
1178
1179 static float getQtWebkitDpr()
1180@@ -31,6 +33,36 @@
1181 return ok ? value : 1.0;
1182 }
1183
1184+static QString getFormFactor()
1185+{
1186+ // This implementation only considers two possible form factors: desktop,
1187+ // and mobile (which includes phones and tablets).
1188+ // XXX: do we need to consider other form factors, such as tablet?
1189+ const char* DESKTOP = "desktop";
1190+ const char* MOBILE = "mobile";
1191+
1192+ // The "DESKTOP_MODE" environment variable can be used to force the form
1193+ // factor to desktop, when set to any valid value other than 0.
1194+ const char* DESKTOP_MODE_ENV_VAR = "DESKTOP_MODE";
1195+ if (qEnvironmentVariableIsSet(DESKTOP_MODE_ENV_VAR)) {
1196+ QByteArray stringValue = qgetenv(DESKTOP_MODE_ENV_VAR);
1197+ bool ok = false;
1198+ int value = stringValue.toInt(&ok);
1199+ if (ok) {
1200+ return (value == 0) ? MOBILE : DESKTOP;
1201+ }
1202+ }
1203+
1204+ // XXX: Assume that QtUbuntu means mobile, which is currently the case,
1205+ // but may not remain true forever.
1206+ QString platform = QGuiApplication::platformName();
1207+ if ((platform == "ubuntu") || (platform == "ubuntumirclient")) {
1208+ return MOBILE;
1209+ }
1210+
1211+ return DESKTOP;
1212+}
1213+
1214 void UbuntuBrowserPlugin::initializeEngine(QQmlEngine* engine, const char* uri)
1215 {
1216 Q_UNUSED(uri);
1217@@ -45,6 +77,8 @@
1218 // Set the desired pixel ratio (not needed once we use Qt’s way of
1219 // calculating the proper pixel ratio by device/screen).
1220 context->setContextProperty("QtWebKitDPR", getQtWebkitDpr());
1221+
1222+ context->setContextProperty("formFactor", getFormFactor());
1223 }
1224
1225 void UbuntuBrowserPlugin::registerTypes(const char* uri)
1226
1227=== modified file 'src/Ubuntu/Components/Extras/Browser/qmldir'
1228--- src/Ubuntu/Components/Extras/Browser/qmldir 2014-03-12 15:27:10 +0000
1229+++ src/Ubuntu/Components/Extras/Browser/qmldir 2014-03-28 17:03:06 +0000
1230@@ -1,3 +1,7 @@
1231 module Ubuntu.Components.Extras.Browser
1232 plugin ubuntu-ui-extras-browser-plugin
1233-UbuntuWebView 0.1 UbuntuWebView.qml
1234+UbuntuWebView 0.1 UbuntuWebView01.qml
1235+UbuntuWebView 0.2 UbuntuWebView02.qml
1236+# Without the following line, importing version 0.1 of the module fails
1237+singleton UbuntuWebContext 0.1 dummysingleton.qml
1238+singleton UbuntuWebContext 0.2 UbuntuWebContext.qml
1239
1240=== added file 'src/Ubuntu/Components/Extras/Browser/selection01.js'
1241--- src/Ubuntu/Components/Extras/Browser/selection01.js 1970-01-01 00:00:00 +0000
1242+++ src/Ubuntu/Components/Extras/Browser/selection01.js 2014-03-28 17:03:06 +0000
1243@@ -0,0 +1,193 @@
1244+/*
1245+ * Copyright 2013-2014 Canonical Ltd.
1246+ *
1247+ * This file is part of webbrowser-app.
1248+ *
1249+ * webbrowser-app is free software; you can redistribute it and/or modify
1250+ * it under the terms of the GNU General Public License as published by
1251+ * the Free Software Foundation; version 3.
1252+ *
1253+ * webbrowser-app is distributed in the hope that it will be useful,
1254+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1255+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1256+ * GNU General Public License for more details.
1257+ *
1258+ * You should have received a copy of the GNU General Public License
1259+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1260+ */
1261+
1262+// List of domains known to interfere with touch events listeners
1263+var blacklist = [
1264+ "m.8tracks.com", // http://pad.lv/1279903
1265+];
1266+if (blacklist.indexOf(document.domain) === -1) {
1267+
1268+ function elementContainedInBox(element, box) {
1269+ var rect = element.getBoundingClientRect();
1270+ return ((box.left <= rect.left) && (box.right >= rect.right) &&
1271+ (box.top <= rect.top) && (box.bottom >= rect.bottom));
1272+ }
1273+
1274+ function getImgFullUri(uri) {
1275+ if ((uri.slice(0, 7) === 'http://') ||
1276+ (uri.slice(0, 8) === 'https://') ||
1277+ (uri.slice(0, 7) === 'file://')) {
1278+ return uri;
1279+ } else if (uri.slice(0, 1) === '/') {
1280+ var docuri = document.documentURI;
1281+ var firstcolon = docuri.indexOf('://');
1282+ var protocol = 'http://';
1283+ if (firstcolon !== -1) {
1284+ protocol = docuri.slice(0, firstcolon + 3);
1285+ }
1286+ return protocol + document.domain + uri;
1287+ } else {
1288+ var base = document.baseURI;
1289+ var lastslash = base.lastIndexOf('/');
1290+ if (lastslash === -1) {
1291+ return base + '/' + uri;
1292+ } else {
1293+ return base.slice(0, lastslash + 1) + uri;
1294+ }
1295+ }
1296+ }
1297+
1298+ function getSelectedData(element) {
1299+ var node = element;
1300+ var data = new Object;
1301+
1302+ var nodeName = node.nodeName.toLowerCase();
1303+ if (nodeName === 'img') {
1304+ data.img = getImgFullUri(node.getAttribute('src'));
1305+ } else if (nodeName === 'a') {
1306+ data.href = node.href;
1307+ data.title = node.title;
1308+ }
1309+
1310+ // If the parent tag is a hyperlink, we want it too.
1311+ var parent = node.parentNode;
1312+ if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {
1313+ data.href = parent.href;
1314+ data.title = parent.title;
1315+ node = parent;
1316+ }
1317+
1318+ var boundingRect = node.getBoundingClientRect();
1319+ data.left = boundingRect.left;
1320+ data.top = boundingRect.top;
1321+ data.width = boundingRect.width;
1322+ data.height = boundingRect.height;
1323+
1324+ node = node.cloneNode(true);
1325+ // filter out script nodes
1326+ var scripts = node.getElementsByTagName('script');
1327+ while (scripts.length > 0) {
1328+ var scriptNode = scripts[0];
1329+ if (scriptNode.parentNode) {
1330+ scriptNode.parentNode.removeChild(scriptNode);
1331+ }
1332+ }
1333+ data.html = node.outerHTML;
1334+ data.nodeName = node.nodeName.toLowerCase();
1335+ // FIXME: extract the text and images in the order they appear in the block,
1336+ // so that this order is respected when the data is pushed to the clipboard.
1337+ data.text = node.textContent;
1338+ var images = [];
1339+ var imgs = node.getElementsByTagName('img');
1340+ for (var i = 0; i < imgs.length; i++) {
1341+ images.push(getImgFullUri(imgs[i].getAttribute('src')));
1342+ }
1343+ if (images.length > 0) {
1344+ data.images = images;
1345+ }
1346+
1347+ return data;
1348+ }
1349+
1350+ function adjustSelection(selection) {
1351+ // FIXME: allow selecting two consecutive blocks, instead of
1352+ // interpolating to the containing block.
1353+ var centerX = (selection.left + selection.right) / 2;
1354+ var centerY = (selection.top + selection.bottom) / 2;
1355+ var element = document.elementFromPoint(centerX, centerY);
1356+ var parent = element;
1357+ while (elementContainedInBox(parent, selection)) {
1358+ parent = parent.parentNode;
1359+ }
1360+ element = parent;
1361+ return getSelectedData(element);
1362+ }
1363+
1364+ function distance(touch1, touch2) {
1365+ return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +
1366+ Math.pow(touch2.clientY - touch1.clientY, 2));
1367+ }
1368+
1369+ navigator.qt.onmessage = function(message) {
1370+ var data = null;
1371+ try {
1372+ data = JSON.parse(message.data);
1373+ } catch (error) {
1374+ return;
1375+ }
1376+ if ('query' in data) {
1377+ if (data.query === 'adjustselection') {
1378+ var selection = adjustSelection(data);
1379+ selection.event = 'selectionadjusted';
1380+ navigator.qt.postMessage(JSON.stringify(selection));
1381+ }
1382+ }
1383+ }
1384+
1385+ var longpressObserver = -1;
1386+ var currentTouch = null;
1387+ var longpressDetected = false;
1388+
1389+ function longPressDetected(x, y) {
1390+ longpressDetected = true;
1391+ var element = document.elementFromPoint(x, y);
1392+ var data = getSelectedData(element);
1393+ data.event = 'longpress';
1394+ navigator.qt.postMessage(JSON.stringify(data));
1395+ }
1396+
1397+ function clearLongpressTimeout() {
1398+ clearTimeout(longpressObserver);
1399+ longpressObserver = -1;
1400+ currentTouch = null;
1401+ }
1402+
1403+ var doc = document.documentElement;
1404+
1405+ doc.addEventListener('touchstart', function(event) {
1406+ if (event.touches.length == 1) {
1407+ currentTouch = event.touches[0];
1408+ longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY);
1409+ }
1410+ });
1411+
1412+ doc.addEventListener('touchend', function(event) {
1413+ if (longpressDetected) {
1414+ longpressDetected = false;
1415+ event.preventDefault();
1416+ }
1417+ clearLongpressTimeout();
1418+ });
1419+
1420+ doc.addEventListener('touchmove', function(event) {
1421+ if (!currentTouch) {
1422+ return;
1423+ }
1424+ if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) {
1425+ clearLongpressTimeout();
1426+ }
1427+ });
1428+
1429+ doc.addEventListener('touchcancel', function(event) {
1430+ if (longpressDetected) {
1431+ longpressDetected = false;
1432+ }
1433+ clearLongpressTimeout();
1434+ });
1435+
1436+}
1437
1438=== renamed file 'src/Ubuntu/Components/Extras/Browser/selection.js' => 'src/Ubuntu/Components/Extras/Browser/selection02.js'
1439--- src/Ubuntu/Components/Extras/Browser/selection.js 2014-02-19 15:53:33 +0000
1440+++ src/Ubuntu/Components/Extras/Browser/selection02.js 2014-03-28 17:03:06 +0000
1441@@ -16,178 +16,132 @@
1442 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1443 */
1444
1445-// List of domains known to interfere with touch events listeners
1446-var blacklist = [
1447- "m.8tracks.com", // http://pad.lv/1279903
1448-];
1449-if (blacklist.indexOf(document.domain) === -1) {
1450-
1451- function elementContainedInBox(element, box) {
1452- var rect = element.getBoundingClientRect();
1453- return ((box.left <= rect.left) && (box.right >= rect.right) &&
1454- (box.top <= rect.top) && (box.bottom >= rect.bottom));
1455- }
1456-
1457- function getImgFullUri(uri) {
1458- if ((uri.slice(0, 7) === 'http://') ||
1459- (uri.slice(0, 8) === 'https://') ||
1460- (uri.slice(0, 7) === 'file://')) {
1461- return uri;
1462- } else if (uri.slice(0, 1) === '/') {
1463- var docuri = document.documentURI;
1464- var firstcolon = docuri.indexOf('://');
1465- var protocol = 'http://';
1466- if (firstcolon !== -1) {
1467- protocol = docuri.slice(0, firstcolon + 3);
1468- }
1469- return protocol + document.domain + uri;
1470+function elementContainedInBox(element, box) {
1471+ var rect = element.getBoundingClientRect();
1472+ return ((box.left <= rect.left) && (box.right >= rect.right) &&
1473+ (box.top <= rect.top) && (box.bottom >= rect.bottom));
1474+}
1475+
1476+function getImgFullUri(uri) {
1477+ if ((uri.slice(0, 7) === 'http://') ||
1478+ (uri.slice(0, 8) === 'https://') ||
1479+ (uri.slice(0, 7) === 'file://')) {
1480+ return uri;
1481+ } else if (uri.slice(0, 1) === '/') {
1482+ var docuri = document.documentURI;
1483+ var firstcolon = docuri.indexOf('://');
1484+ var protocol = 'http://';
1485+ if (firstcolon !== -1) {
1486+ protocol = docuri.slice(0, firstcolon + 3);
1487+ }
1488+ return protocol + document.domain + uri;
1489+ } else {
1490+ var base = document.baseURI;
1491+ var lastslash = base.lastIndexOf('/');
1492+ if (lastslash === -1) {
1493+ return base + '/' + uri;
1494 } else {
1495- var base = document.baseURI;
1496- var lastslash = base.lastIndexOf('/');
1497- if (lastslash === -1) {
1498- return base + '/' + uri;
1499- } else {
1500- return base.slice(0, lastslash + 1) + uri;
1501- }
1502- }
1503- }
1504-
1505- function getSelectedData(element) {
1506- var node = element;
1507- var data = new Object;
1508-
1509- var nodeName = node.nodeName.toLowerCase();
1510- if (nodeName === 'img') {
1511- data.img = getImgFullUri(node.getAttribute('src'));
1512- } else if (nodeName === 'a') {
1513- data.href = node.href;
1514- data.title = node.title;
1515- }
1516-
1517- // If the parent tag is a hyperlink, we want it too.
1518- var parent = node.parentNode;
1519- if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {
1520- data.href = parent.href;
1521- data.title = parent.title;
1522- node = parent;
1523- }
1524-
1525- var boundingRect = node.getBoundingClientRect();
1526- data.left = boundingRect.left;
1527- data.top = boundingRect.top;
1528- data.width = boundingRect.width;
1529- data.height = boundingRect.height;
1530-
1531- node = node.cloneNode(true);
1532- // filter out script nodes
1533- var scripts = node.getElementsByTagName('script');
1534- while (scripts.length > 0) {
1535- var scriptNode = scripts[0];
1536- if (scriptNode.parentNode) {
1537- scriptNode.parentNode.removeChild(scriptNode);
1538- }
1539- }
1540- data.html = node.outerHTML;
1541- data.nodeName = node.nodeName.toLowerCase();
1542- // FIXME: extract the text and images in the order they appear in the block,
1543- // so that this order is respected when the data is pushed to the clipboard.
1544- data.text = node.textContent;
1545- var images = [];
1546- var imgs = node.getElementsByTagName('img');
1547- for (var i = 0; i < imgs.length; i++) {
1548- images.push(getImgFullUri(imgs[i].getAttribute('src')));
1549- }
1550- if (images.length > 0) {
1551- data.images = images;
1552- }
1553-
1554- return data;
1555- }
1556-
1557- function adjustSelection(selection) {
1558- // FIXME: allow selecting two consecutive blocks, instead of
1559- // interpolating to the containing block.
1560- var centerX = (selection.left + selection.right) / 2;
1561- var centerY = (selection.top + selection.bottom) / 2;
1562- var element = document.elementFromPoint(centerX, centerY);
1563- var parent = element;
1564- while (elementContainedInBox(parent, selection)) {
1565- parent = parent.parentNode;
1566- }
1567- element = parent;
1568- return getSelectedData(element);
1569- }
1570-
1571- function distance(touch1, touch2) {
1572- return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +
1573- Math.pow(touch2.clientY - touch1.clientY, 2));
1574- }
1575-
1576- navigator.qt.onmessage = function(message) {
1577- var data = null;
1578- try {
1579- data = JSON.parse(message.data);
1580- } catch (error) {
1581- return;
1582- }
1583- if ('query' in data) {
1584- if (data.query === 'adjustselection') {
1585- var selection = adjustSelection(data);
1586- selection.event = 'selectionadjusted';
1587- navigator.qt.postMessage(JSON.stringify(selection));
1588- }
1589- }
1590- }
1591-
1592- var longpressObserver = -1;
1593- var currentTouch = null;
1594- var longpressDetected = false;
1595-
1596- function longPressDetected(x, y) {
1597- longpressDetected = true;
1598- var element = document.elementFromPoint(x, y);
1599- var data = getSelectedData(element);
1600- data.event = 'longpress';
1601- navigator.qt.postMessage(JSON.stringify(data));
1602- }
1603-
1604- function clearLongpressTimeout() {
1605- clearTimeout(longpressObserver);
1606- longpressObserver = -1;
1607- currentTouch = null;
1608- }
1609-
1610- var doc = document.documentElement;
1611-
1612- doc.addEventListener('touchstart', function(event) {
1613- if (event.touches.length == 1) {
1614- currentTouch = event.touches[0];
1615- longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY);
1616- }
1617- });
1618-
1619- doc.addEventListener('touchend', function(event) {
1620- if (longpressDetected) {
1621- longpressDetected = false;
1622- event.preventDefault();
1623- }
1624- clearLongpressTimeout();
1625- });
1626-
1627- doc.addEventListener('touchmove', function(event) {
1628- if (!currentTouch) {
1629- return;
1630- }
1631- if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) {
1632- clearLongpressTimeout();
1633- }
1634- });
1635-
1636- doc.addEventListener('touchcancel', function(event) {
1637- if (longpressDetected) {
1638- longpressDetected = false;
1639- }
1640- clearLongpressTimeout();
1641- });
1642-
1643-}
1644+ return base.slice(0, lastslash + 1) + uri;
1645+ }
1646+ }
1647+}
1648+
1649+function getSelectedData(element) {
1650+ var node = element;
1651+ var data = new Object;
1652+
1653+ var nodeName = node.nodeName.toLowerCase();
1654+ if (nodeName === 'img') {
1655+ data.img = getImgFullUri(node.getAttribute('src'));
1656+ } else if (nodeName === 'a') {
1657+ data.href = node.href;
1658+ data.title = node.title;
1659+ }
1660+
1661+ // If the parent tag is a hyperlink, we want it too.
1662+ var parent = node.parentNode;
1663+ if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {
1664+ data.href = parent.href;
1665+ data.title = parent.title;
1666+ node = parent;
1667+ }
1668+
1669+ var boundingRect = node.getBoundingClientRect();
1670+ data.left = boundingRect.left;
1671+ data.top = boundingRect.top;
1672+ data.width = boundingRect.width;
1673+ data.height = boundingRect.height;
1674+
1675+ node = node.cloneNode(true);
1676+ // filter out script nodes
1677+ var scripts = node.getElementsByTagName('script');
1678+ while (scripts.length > 0) {
1679+ var scriptNode = scripts[0];
1680+ if (scriptNode.parentNode) {
1681+ scriptNode.parentNode.removeChild(scriptNode);
1682+ }
1683+ }
1684+ data.html = node.outerHTML;
1685+ data.nodeName = node.nodeName.toLowerCase();
1686+ // FIXME: extract the text and images in the order they appear in the block,
1687+ // so that this order is respected when the data is pushed to the clipboard.
1688+ data.text = node.textContent;
1689+ var images = [];
1690+ var imgs = node.getElementsByTagName('img');
1691+ for (var i = 0; i < imgs.length; i++) {
1692+ images.push(getImgFullUri(imgs[i].getAttribute('src')));
1693+ }
1694+ if (images.length > 0) {
1695+ data.images = images;
1696+ }
1697+
1698+ return data;
1699+}
1700+
1701+function adjustSelection(selection) {
1702+ // FIXME: allow selecting two consecutive blocks, instead of
1703+ // interpolating to the containing block.
1704+ var centerX = (selection.left + selection.right) / 2;
1705+ var centerY = (selection.top + selection.bottom) / 2;
1706+ var element = document.elementFromPoint(centerX, centerY);
1707+ var parent = element;
1708+ while (elementContainedInBox(parent, selection)) {
1709+ parent = parent.parentNode;
1710+ }
1711+ element = parent;
1712+ return getSelectedData(element);
1713+}
1714+
1715+function distance(touch1, touch2) {
1716+ return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +
1717+ Math.pow(touch2.clientY - touch1.clientY, 2));
1718+}
1719+
1720+/*navigator.qt.onmessage = function(message) {
1721+ var data = null;
1722+ try {
1723+ data = JSON.parse(message.data);
1724+ } catch (error) {
1725+ return;
1726+ }
1727+ if ('query' in data) {
1728+ if (data.query === 'adjustselection') {
1729+ var selection = adjustSelection(data);
1730+ selection.event = 'selectionadjusted';
1731+ navigator.qt.postMessage(JSON.stringify(selection));
1732+ }
1733+ }
1734+}*/
1735+
1736+document.documentElement.addEventListener('contextmenu', function(event) {
1737+ var element = document.elementFromPoint(event.clientX, event.clientY);
1738+ var data = getSelectedData(element);
1739+ var w = document.defaultView;
1740+ data['scaleX'] = w.outerWidth / w.innerWidth * w.devicePixelRatio;
1741+ data['scaleY'] = w.outerHeight / w.innerHeight * w.devicePixelRatio;
1742+ oxide.sendMessage('contextmenu', data);
1743+});
1744+
1745+document.defaultView.addEventListener('scroll', function(event) {
1746+ oxide.sendMessage('scroll', {});
1747+});
1748
1749=== added file 'src/Ubuntu/Components/Extras/Browser/ua-override-worker.js'
1750--- src/Ubuntu/Components/Extras/Browser/ua-override-worker.js 1970-01-01 00:00:00 +0000
1751+++ src/Ubuntu/Components/Extras/Browser/ua-override-worker.js 2014-03-28 17:03:06 +0000
1752@@ -0,0 +1,46 @@
1753+/*
1754+ * Copyright 2014 Canonical Ltd.
1755+ *
1756+ * This file is part of webbrowser-app.
1757+ *
1758+ * webbrowser-app is free software; you can redistribute it and/or modify
1759+ * it under the terms of the GNU General Public License as published by
1760+ * the Free Software Foundation; version 3.
1761+ *
1762+ * webbrowser-app is distributed in the hope that it will be useful,
1763+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1764+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1765+ * GNU General Public License for more details.
1766+ *
1767+ * You should have received a copy of the GNU General Public License
1768+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1769+ */
1770+
1771+var overrides = [
1772+ [/^https?:\/\/mail.google.com\//, "Mozilla/5.0 (Linux; Ubuntu 14.04 like Android 4.4) AppleWebKit/537.36 Chromium/35.0.1870.2 Mobile Safari"]
1773+];
1774+
1775+function getUAoverride(url) {
1776+ for (var i = 0; i < overrides.length; i++) {
1777+ var override = overrides[i];
1778+ if (override[0].test(url)) {
1779+ return override[1];
1780+ }
1781+ }
1782+ return null;
1783+}
1784+
1785+exports.onBeforeSendHeaders = function(event) {
1786+ var override = getUAoverride(event.url);
1787+ if (override !== null) {
1788+ event.setHeader("User-Agent", override);
1789+ oxide.sendMessage({url: event.url, override: override});
1790+ }
1791+}
1792+
1793+exports.onGetUserAgentOverride = function(data) {
1794+ var override = getUAoverride(event.url);
1795+ if (override !== null) {
1796+ data.userAgentOverride = override;
1797+ }
1798+}
1799
1800=== modified file 'src/app/AlertDialog.qml'
1801--- src/app/AlertDialog.qml 2013-09-21 19:56:15 +0000
1802+++ src/app/AlertDialog.qml 2014-03-28 17:03:06 +0000
1803@@ -26,8 +26,8 @@
1804
1805 Button {
1806 text: i18n.tr("OK")
1807- onClicked: model.dismiss()
1808+ onClicked: model.accept()
1809 }
1810
1811 Component.onCompleted: show()
1812-}
1813\ No newline at end of file
1814+}
1815
1816=== added file 'src/app/BeforeUnloadDialog.qml'
1817--- src/app/BeforeUnloadDialog.qml 1970-01-01 00:00:00 +0000
1818+++ src/app/BeforeUnloadDialog.qml 2014-03-28 17:03:06 +0000
1819@@ -0,0 +1,38 @@
1820+/*
1821+ * Copyright 2014 Canonical Ltd.
1822+ *
1823+ * This file is part of webbrowser-app.
1824+ *
1825+ * webbrowser-app is free software; you can redistribute it and/or modify
1826+ * it under the terms of the GNU General Public License as published by
1827+ * the Free Software Foundation; version 3.
1828+ *
1829+ * webbrowser-app is distributed in the hope that it will be useful,
1830+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1831+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1832+ * GNU General Public License for more details.
1833+ *
1834+ * You should have received a copy of the GNU General Public License
1835+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1836+ */
1837+
1838+import QtQuick 2.0
1839+import Ubuntu.Components 0.1
1840+import Ubuntu.Components.Popups 0.1 as Popups
1841+
1842+Popups.Dialog {
1843+ title: i18n.tr("Confirm Navigation")
1844+ text: model.message
1845+
1846+ Button {
1847+ text: i18n.tr("Leave")
1848+ onClicked: model.accept()
1849+ }
1850+
1851+ Button {
1852+ text: i18n.tr("Stay")
1853+ onClicked: model.reject()
1854+ }
1855+
1856+ Component.onCompleted: show()
1857+}
1858
1859=== modified file 'src/app/CMakeLists.txt'
1860--- src/app/CMakeLists.txt 2014-03-13 07:33:10 +0000
1861+++ src/app/CMakeLists.txt 2014-03-28 17:03:06 +0000
1862@@ -16,6 +16,8 @@
1863
1864 qt5_use_modules(${COMMONLIB} Core Network Qml Quick Widgets)
1865
1866+include_directories(${Qt5Quick_PRIVATE_INCLUDE_DIRS})
1867+
1868 file(GLOB QML_FILES *.qml)
1869 install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app)
1870 install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app
1871
1872=== modified file 'src/app/PanelLoader.qml'
1873--- src/app/PanelLoader.qml 2013-11-15 17:04:27 +0000
1874+++ src/app/PanelLoader.qml 2014-03-28 17:03:06 +0000
1875@@ -75,7 +75,10 @@
1876
1877 url: currentWebview ? currentWebview.url : ""
1878
1879- loading: currentWebview ? currentWebview.loading || (currentWebview.loadProgress === 0) : false
1880+ loading: currentWebview ? currentWebview.loading
1881+ // workaround for https://bugs.launchpad.net/oxide/+bug/1290821
1882+ && !currentWebview.lastLoadStopped
1883+ : false
1884 loadProgress: currentWebview ? currentWebview.loadProgress : 0
1885
1886 canGoBack: currentWebview ? currentWebview.canGoBack : false
1887
1888=== modified file 'src/app/PromptDialog.qml'
1889--- src/app/PromptDialog.qml 2013-09-21 20:06:03 +0000
1890+++ src/app/PromptDialog.qml 2014-03-28 17:03:06 +0000
1891@@ -42,5 +42,11 @@
1892 onClicked: model.reject()
1893 }
1894
1895+ Binding {
1896+ target: model
1897+ property: "currentValue"
1898+ value: input.text
1899+ }
1900+
1901 Component.onCompleted: show()
1902-}
1903\ No newline at end of file
1904+}
1905
1906=== modified file 'src/app/WebViewImpl.qml'
1907--- src/app/WebViewImpl.qml 2014-03-13 10:16:20 +0000
1908+++ src/app/WebViewImpl.qml 2014-03-28 17:03:06 +0000
1909@@ -17,12 +17,10 @@
1910 */
1911
1912 import QtQuick 2.0
1913-import QtWebKit 3.1
1914-import QtWebKit.experimental 1.0
1915-import Ubuntu.Components 0.1
1916-import Ubuntu.Components.Extras.Browser 0.1
1917-import Ubuntu.Components.Popups 0.1
1918-import "actions" as Actions
1919+//import Ubuntu.Components 0.1
1920+import Ubuntu.Components.Extras.Browser 0.2
1921+//import Ubuntu.Components.Popups 0.1
1922+//import "actions" as Actions
1923
1924 UbuntuWebView {
1925 id: webview
1926@@ -30,20 +28,21 @@
1927 property var currentWebview: webview
1928 property var toolbar: null
1929
1930- experimental.certificateVerificationDialog: CertificateVerificationDialog {}
1931+ /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
1932 experimental.authenticationDialog: AuthenticationDialog {}
1933- experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}
1934- experimental.alertDialog: AlertDialog {}
1935- experimental.confirmDialog: ConfirmDialog {}
1936- experimental.promptDialog: PromptDialog {}
1937+ experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}*/
1938+ /*alertDialog: AlertDialog {}
1939+ confirmDialog: ConfirmDialog {}
1940+ promptDialog: PromptDialog {}
1941+ beforeUnloadDialog: BeforeUnloadDialog {}*/
1942
1943- selectionActions: ActionList {
1944+ /*selectionActions: ActionList {
1945 Actions.Copy {
1946 onTriggered: selection.copy()
1947 }
1948- }
1949+ }*/
1950
1951- experimental.onPermissionRequested: {
1952+ /*experimental.onPermissionRequested: {
1953 if (permission.type === PermissionRequest.Geolocation) {
1954 if (webview.toolbar) {
1955 webview.toolbar.close()
1956@@ -56,8 +55,5 @@
1957 // TODO: handle other types of permission requests
1958 // TODO: we might want to store the answer to avoid requesting
1959 // the permission everytime the user visits this site.
1960- }
1961-
1962- property int lastLoadRequestStatus: -1
1963- onLoadingChanged: lastLoadRequestStatus = loadRequest.status
1964+ }*/
1965 }
1966
1967=== modified file 'src/app/browserapplication.cpp'
1968--- src/app/browserapplication.cpp 2014-03-14 14:51:22 +0000
1969+++ src/app/browserapplication.cpp 2014-03-28 17:03:06 +0000
1970@@ -17,10 +17,13 @@
1971 */
1972
1973 // Qt
1974+#include <QtCore/QLibrary>
1975 #include <QtNetwork/QNetworkInterface>
1976+#include <QtGui/QOpenGLContext>
1977 #include <QtQml/QQmlComponent>
1978 #include <QtQml/QQmlContext>
1979 #include <QtQml/QQmlEngine>
1980+#include <QtQuick/private/qsgcontext_p.h>
1981 #include <QtQuick/QQuickWindow>
1982
1983 // local
1984@@ -29,7 +32,7 @@
1985 #include "webbrowser-window.h"
1986
1987 BrowserApplication::BrowserApplication(int& argc, char** argv)
1988- : QApplication(argc, argv)
1989+ : QGuiApplication(argc, argv)
1990 , m_engine(0)
1991 , m_window(0)
1992 , m_component(0)
1993@@ -37,6 +40,25 @@
1994 {
1995 m_arguments = arguments();
1996 m_arguments.removeFirst();
1997+
1998+ // The testability driver is only loaded by QApplication but not by
1999+ // QGuiApplication (see https://codereview.qt-project.org/#change,66513).
2000+ // Let’s load the testability driver on our own.
2001+ if (m_arguments.contains(QLatin1String("-testability")) ||
2002+ qgetenv("QT_LOAD_TESTABILITY") == "1") {
2003+ QLibrary testLib(QLatin1String("qttestability"));
2004+ if (testLib.load()) {
2005+ typedef void (*TasInitialize)(void);
2006+ TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
2007+ if (initFunction) {
2008+ initFunction();
2009+ } else {
2010+ qCritical("Library qttestability resolve failed!");
2011+ }
2012+ } else {
2013+ qCritical("Library qttestability load failed!");
2014+ }
2015+ }
2016 }
2017
2018 BrowserApplication::~BrowserApplication()
2019@@ -80,6 +102,11 @@
2020 QString appPkgName = qgetenv("APP_ID").split('_').first();
2021 QCoreApplication::setApplicationName(appPkgName);
2022
2023+ // Enable compositing in oxide
2024+ QOpenGLContext* glcontext = new QOpenGLContext(this);
2025+ glcontext->create();
2026+ QSGContext::setSharedOpenGLContext(glcontext);
2027+
2028 bool inspector = m_arguments.contains("--inspector");
2029 if (inspector) {
2030 QString host;
2031@@ -113,7 +140,7 @@
2032 m_webbrowserWindowProxy = new WebBrowserWindow();
2033 context->setContextProperty("webbrowserWindowProxy", m_webbrowserWindowProxy);
2034
2035- QObject* browser = m_component->create();
2036+ QObject* browser = m_component->beginCreate(context);
2037 m_window = qobject_cast<QQuickWindow*>(browser);
2038 m_webbrowserWindowProxy->setWindow(m_window);
2039
2040
2041=== modified file 'src/app/browserapplication.h'
2042--- src/app/browserapplication.h 2014-03-14 14:51:22 +0000
2043+++ src/app/browserapplication.h 2014-03-28 17:03:06 +0000
2044@@ -24,14 +24,14 @@
2045 #include <QtCore/QString>
2046 #include <QtCore/QStringList>
2047 #include <QtCore/QUrl>
2048-#include <QtWidgets/QApplication>
2049+#include <QtGui/QGuiApplication>
2050
2051 class QQmlComponent;
2052 class QQmlEngine;
2053 class QQuickWindow;
2054 class WebBrowserWindow;
2055
2056-class BrowserApplication : public QApplication
2057+class BrowserApplication : public QGuiApplication
2058 {
2059 Q_OBJECT
2060
2061@@ -49,11 +49,11 @@
2062 QStringList m_arguments;
2063 QQmlEngine* m_engine;
2064 QQuickWindow* m_window;
2065+ QQmlComponent* m_component;
2066
2067 private:
2068 QString appId() const;
2069
2070- QQmlComponent* m_component;
2071 WebBrowserWindow *m_webbrowserWindowProxy;
2072 };
2073
2074
2075=== modified file 'src/app/webbrowser/BookmarksView.qml'
2076--- src/app/webbrowser/BookmarksView.qml 2014-03-12 22:45:12 +0000
2077+++ src/app/webbrowser/BookmarksView.qml 2014-03-28 17:03:06 +0000
2078@@ -50,8 +50,8 @@
2079 url: model.url
2080 label: model.title ? model.title : model.url
2081
2082- property url thumbnailSource: "image://webthumbnail/" + model.url
2083- thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
2084+ //property url thumbnailSource: "image://webthumbnail/" + model.url
2085+ //thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
2086
2087 canBookmark: true
2088 bookmarksModel: bookmarksView.bookmarksModel
2089
2090=== modified file 'src/app/webbrowser/Browser.qml'
2091--- src/app/webbrowser/Browser.qml 2014-03-13 10:16:20 +0000
2092+++ src/app/webbrowser/Browser.qml 2014-03-28 17:03:06 +0000
2093@@ -17,8 +17,6 @@
2094 */
2095
2096 import QtQuick 2.0
2097-import QtWebKit 3.1
2098-import QtWebKit.experimental 1.0
2099 import Ubuntu.Components 0.1
2100 import webbrowserapp.private 0.1
2101 import "../actions" as Actions
2102@@ -48,7 +46,7 @@
2103 },
2104 Actions.Bookmark {
2105 enabled: currentWebview
2106- onTriggered: bookmarksModel.add(currentWebview.url, currentWebview.title, currentWebview.icon)
2107+ onTriggered: bookmarksModel.add(currentWebview.url, currentWebview.title, "")//currentWebview.icon)
2108 },
2109 Actions.NewTab {
2110 onTriggered: newTab("", true)
2111@@ -73,7 +71,7 @@
2112
2113 ErrorSheet {
2114 anchors.fill: webviewContainer
2115- visible: currentWebview ? (currentWebview.lastLoadRequestStatus === WebView.LoadFailedStatus) : false
2116+ visible: currentWebview ? currentWebview.lastLoadFailed : false
2117 url: currentWebview ? currentWebview.url : ""
2118 onRefreshClicked: currentWebview.reload()
2119 }
2120@@ -217,7 +215,7 @@
2121 enabled: stack.depth === 0
2122 visible: currentWebview === webview
2123
2124- experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
2125+ //experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
2126
2127 contextualActions: ActionList {
2128 Actions.OpenLinkInNewTab {
2129@@ -244,25 +242,9 @@
2130
2131 onNewTabRequested: newTab(url, true)
2132
2133- WebviewThumbnailer {
2134- id: thumbnailer
2135- webview: webview
2136- targetSize: Qt.size(units.gu(12), units.gu(12))
2137- property url thumbnailSource: "image://webthumbnail/" + webview.url
2138- onThumbnailRendered: {
2139- if (url == webview.url) {
2140- webview.thumbnail = thumbnailer.thumbnailSource
2141- }
2142- }
2143- }
2144- property url thumbnail: (url && thumbnailer.thumbnailExists()) ? thumbnailer.thumbnailSource : ""
2145-
2146 onLoadingChanged: {
2147- if (loadRequest.status === WebView.LoadSucceededStatus) {
2148+ if (lastLoadSucceeded) {
2149 _historyModel.add(webview.url, webview.title, webview.icon)
2150- if (!thumbnailer.thumbnailExists()) {
2151- thumbnailer.renderThumbnail()
2152- }
2153 }
2154 }
2155 }
2156
2157=== modified file 'src/app/webbrowser/CMakeLists.txt'
2158--- src/app/webbrowser/CMakeLists.txt 2014-03-13 07:30:35 +0000
2159+++ src/app/webbrowser/CMakeLists.txt 2014-03-28 17:03:06 +0000
2160@@ -19,25 +19,13 @@
2161 bookmarks-model.cpp
2162 settings.cpp
2163 webbrowser-app.cpp
2164- webthumbnail-provider.cpp
2165- webthumbnail-utils.cpp
2166- webview-thumbnailer.cpp
2167 )
2168
2169 add_executable(${WEBBROWSER_APP} ${WEBBROWSER_APP_SRC})
2170
2171 target_link_libraries(${WEBBROWSER_APP} ${COMMONLIB})
2172
2173-qt5_use_modules(${WEBBROWSER_APP} Core Gui Quick Sql WebKit)
2174-
2175-# work around the lack of a public cmake module for Qt5V8
2176-set(Qt5V8_PRIVATE_INCLUDE_DIRS
2177- "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}"
2178- "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}/QtV8")
2179-include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}
2180- ${Qt5V8_PRIVATE_INCLUDE_DIRS}
2181- ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
2182- ${Qt5WebKit_PRIVATE_INCLUDE_DIRS})
2183+qt5_use_modules(${WEBBROWSER_APP} Core Gui Quick Sql)
2184
2185 install(TARGETS ${WEBBROWSER_APP}
2186 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
2187
2188=== modified file 'src/app/webbrowser/TabsList.qml'
2189--- src/app/webbrowser/TabsList.qml 2014-03-12 22:45:12 +0000
2190+++ src/app/webbrowser/TabsList.qml 2014-03-28 17:03:06 +0000
2191@@ -82,7 +82,7 @@
2192
2193 url: model.url
2194 label: model.title ? model.title : model.url
2195- thumbnail: model.webview.thumbnail
2196+ //thumbnail: model.webview.thumbnail
2197 canClose: true
2198
2199 onStateChanged: listview.state = state
2200
2201=== modified file 'src/app/webbrowser/TimelineView.qml'
2202--- src/app/webbrowser/TimelineView.qml 2014-03-12 22:45:12 +0000
2203+++ src/app/webbrowser/TimelineView.qml 2014-03-28 17:03:06 +0000
2204@@ -18,7 +18,7 @@
2205
2206 import QtQuick 2.0
2207 import Ubuntu.Components 0.1
2208-import Ubuntu.Components.Extras.Browser 0.1
2209+//import Ubuntu.Components.Extras.Browser 0.1
2210 import Ubuntu.Components.ListItems 0.1 as ListItem
2211 import webbrowserapp.private 0.1
2212
2213@@ -173,8 +173,8 @@
2214 url: model.url
2215 label: model.title ? model.title : model.url
2216
2217- property url thumbnailSource: "image://webthumbnail/" + model.url
2218- thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
2219+ //property url thumbnailSource: "image://webthumbnail/" + model.url
2220+ //thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
2221
2222 canBookmark: true
2223 bookmarksModel: timelineView.bookmarksModel
2224@@ -282,8 +282,8 @@
2225 }
2226 }
2227
2228- property url thumbnailSource: "image://webthumbnail/" + model.domain
2229- thumbnail: WebThumbnailer.thumbnailExists(model.domain) ? thumbnailSource : ""
2230+ //property url thumbnailSource: "image://webthumbnail/" + model.domain
2231+ //thumbnail: WebThumbnailer.thumbnailExists(model.domain) ? thumbnailSource : ""
2232
2233 onClicked: {
2234 if ((timeline.currentIndex == timelineIndex) &&
2235
2236=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
2237--- src/app/webbrowser/webbrowser-app.cpp 2014-03-12 23:09:21 +0000
2238+++ src/app/webbrowser/webbrowser-app.cpp 2014-03-28 17:03:06 +0000
2239@@ -26,9 +26,6 @@
2240 #include "settings.h"
2241 #include "tabs-model.h"
2242 #include "webbrowser-app.h"
2243-#include "webthumbnail-provider.h"
2244-#include "webthumbnail-utils.h"
2245-#include "webview-thumbnailer.h"
2246
2247 // system
2248 #include <string.h>
2249@@ -41,23 +38,12 @@
2250 #include <QtCore/QMetaObject>
2251 #include <QtCore/QString>
2252 #include <QtCore/QTextStream>
2253-#include <QtCore/QThread>
2254 #include <QtQml/QtQml>
2255 #include <QtQuick/QQuickWindow>
2256
2257 WebbrowserApp::WebbrowserApp(int& argc, char** argv)
2258 : BrowserApplication(argc, argv)
2259- , m_thumbnailUtilsThread(0)
2260-{
2261-}
2262-
2263-WebbrowserApp::~WebbrowserApp()
2264-{
2265- if (m_thumbnailUtilsThread) {
2266- m_thumbnailUtilsThread->quit();
2267- m_thumbnailUtilsThread->wait();
2268- delete m_thumbnailUtilsThread;
2269- }
2270+{
2271 }
2272
2273 bool WebbrowserApp::initialize()
2274@@ -91,22 +77,9 @@
2275 qmlRegisterType<HistoryDomainListChronologicalModel>(uri, 0, 1, "HistoryDomainListChronologicalModel");
2276 qmlRegisterType<TabsModel>(uri, 0, 1, "TabsModel");
2277 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");
2278- qmlRegisterType<WebviewThumbnailer>(uri, 0, 1, "WebviewThumbnailer");
2279
2280 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
2281 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));
2282-
2283- // This singleton lives in its own thread to ensure that
2284- // disk I/O is not performed in the UI thread.
2285- WebThumbnailUtils& utils = WebThumbnailUtils::instance();
2286- m_thumbnailUtilsThread = new QThread;
2287- utils.moveToThread(m_thumbnailUtilsThread);
2288- m_thumbnailUtilsThread->start();
2289-
2290- WebThumbnailProvider* thumbnailer = new WebThumbnailProvider;
2291- m_engine->addImageProvider(QLatin1String("webthumbnail"), thumbnailer);
2292- m_engine->rootContext()->setContextProperty("WebThumbnailer", thumbnailer);
2293-
2294 QList<QUrl> urls = this->urls();
2295 if (urls.isEmpty()) {
2296 Settings settings;
2297@@ -116,6 +89,9 @@
2298 Q_FOREACH(const QUrl& url, urls) {
2299 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));
2300 }
2301+
2302+ m_component->completeCreate();
2303+
2304 return true;
2305 } else {
2306 return false;
2307
2308=== modified file 'src/app/webbrowser/webbrowser-app.h'
2309--- src/app/webbrowser/webbrowser-app.h 2014-03-12 23:09:21 +0000
2310+++ src/app/webbrowser/webbrowser-app.h 2014-03-28 17:03:06 +0000
2311@@ -21,22 +21,17 @@
2312
2313 #include "browserapplication.h"
2314
2315-class QThread;
2316-
2317 class WebbrowserApp : public BrowserApplication
2318 {
2319 Q_OBJECT
2320
2321 public:
2322 WebbrowserApp(int& argc, char** argv);
2323- ~WebbrowserApp();
2324
2325 bool initialize();
2326
2327 private:
2328 virtual void printUsage() const;
2329-
2330- QThread* m_thumbnailUtilsThread;
2331 };
2332
2333 #endif // __WEBBROWSER_APP_H__
2334
2335=== removed file 'src/app/webbrowser/webthumbnail-provider.cpp'
2336--- src/app/webbrowser/webthumbnail-provider.cpp 2014-03-12 23:09:21 +0000
2337+++ src/app/webbrowser/webthumbnail-provider.cpp 1970-01-01 00:00:00 +0000
2338@@ -1,53 +0,0 @@
2339-/*
2340- * Copyright 2013 Canonical Ltd.
2341- *
2342- * This file is part of webbrowser-app.
2343- *
2344- * webbrowser-app is free software; you can redistribute it and/or modify
2345- * it under the terms of the GNU General Public License as published by
2346- * the Free Software Foundation; version 3.
2347- *
2348- * webbrowser-app is distributed in the hope that it will be useful,
2349- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2350- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2351- * GNU General Public License for more details.
2352- *
2353- * You should have received a copy of the GNU General Public License
2354- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2355- */
2356-
2357-#include "webthumbnail-provider.h"
2358-#include "webthumbnail-utils.h"
2359-
2360-// Qt
2361-#include <QtCore/QDebug>
2362-#include <QtGui/QImageReader>
2363-
2364-WebThumbnailProvider::WebThumbnailProvider(QObject* parent)
2365- : QObject(parent)
2366- , QQuickImageProvider(QQuickImageProvider::Image)
2367-{
2368-}
2369-
2370-QImage WebThumbnailProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
2371-{
2372- QImage image;
2373- QFileInfo cached = WebThumbnailUtils::thumbnailFile(QUrl(id));
2374- if (cached.exists()) {
2375- QImageReader reader(cached.absoluteFilePath(), "PNG");
2376- if (requestedSize.isValid()) {
2377- reader.setScaledSize(requestedSize);
2378- }
2379- *size = reader.size();
2380- reader.read(&image);
2381- if (image.isNull()) {
2382- qWarning() << "Failed to load cached thumbnail:" << reader.errorString();
2383- }
2384- }
2385- return image;
2386-}
2387-
2388-bool WebThumbnailProvider::thumbnailExists(const QUrl& url) const
2389-{
2390- return WebThumbnailUtils::thumbnailFile(url).exists();
2391-}
2392
2393=== removed file 'src/app/webbrowser/webthumbnail-provider.h'
2394--- src/app/webbrowser/webthumbnail-provider.h 2014-03-12 23:09:21 +0000
2395+++ src/app/webbrowser/webthumbnail-provider.h 1970-01-01 00:00:00 +0000
2396@@ -1,39 +0,0 @@
2397-/*
2398- * Copyright 2013 Canonical Ltd.
2399- *
2400- * This file is part of webbrowser-app.
2401- *
2402- * webbrowser-app is free software; you can redistribute it and/or modify
2403- * it under the terms of the GNU General Public License as published by
2404- * the Free Software Foundation; version 3.
2405- *
2406- * webbrowser-app is distributed in the hope that it will be useful,
2407- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2408- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2409- * GNU General Public License for more details.
2410- *
2411- * You should have received a copy of the GNU General Public License
2412- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2413- */
2414-
2415-#ifndef __WEBTHUMBNAIL_PROVIDER_H__
2416-#define __WEBTHUMBNAIL_PROVIDER_H__
2417-
2418-// Qt
2419-#include <QtCore/QObject>
2420-#include <QtCore/QUrl>
2421-#include <QtQuick/QQuickImageProvider>
2422-
2423-class WebThumbnailProvider : public QObject, public QQuickImageProvider
2424-{
2425- Q_OBJECT
2426-
2427-public:
2428- WebThumbnailProvider(QObject* parent=0);
2429-
2430- virtual QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize);
2431-
2432- Q_INVOKABLE bool thumbnailExists(const QUrl& url) const;
2433-};
2434-
2435-#endif // __WEBTHUMBNAIL_PROVIDER_H__
2436
2437=== removed file 'src/app/webbrowser/webthumbnail-utils.cpp'
2438--- src/app/webbrowser/webthumbnail-utils.cpp 2014-03-12 23:09:21 +0000
2439+++ src/app/webbrowser/webthumbnail-utils.cpp 1970-01-01 00:00:00 +0000
2440@@ -1,108 +0,0 @@
2441-/*
2442- * Copyright 2013 Canonical Ltd.
2443- *
2444- * This file is part of webbrowser-app.
2445- *
2446- * webbrowser-app is free software; you can redistribute it and/or modify
2447- * it under the terms of the GNU General Public License as published by
2448- * the Free Software Foundation; version 3.
2449- *
2450- * webbrowser-app is distributed in the hope that it will be useful,
2451- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2452- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2453- * GNU General Public License for more details.
2454- *
2455- * You should have received a copy of the GNU General Public License
2456- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2457- */
2458-
2459-#include "domain-utils.h"
2460-#include "webthumbnail-utils.h"
2461-
2462-// Qt
2463-#include <QtCore/QCryptographicHash>
2464-#include <QtCore/QFile>
2465-#include <QtCore/QStandardPaths>
2466-#include <QtCore/QUrl>
2467-#include <QtGui/QImage>
2468-
2469-#define MAX_CACHE_SIZE_IN_BYTES 5 * 1024 * 1024 // 5MB
2470-
2471-WebThumbnailUtils::WebThumbnailUtils(QObject* parent)
2472- : QObject(parent)
2473-{
2474-}
2475-
2476-WebThumbnailUtils& WebThumbnailUtils::instance()
2477-{
2478- static WebThumbnailUtils utils;
2479- return utils;
2480-}
2481-
2482-WebThumbnailUtils::~WebThumbnailUtils()
2483-{
2484-}
2485-
2486-QDir WebThumbnailUtils::cacheLocation()
2487-{
2488- return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/thumbnails";
2489-}
2490-
2491-void WebThumbnailUtils::ensureCacheLocation()
2492-{
2493- QDir cache = cacheLocation();
2494- if (!cache.exists()) {
2495- QDir::root().mkpath(cache.absolutePath());
2496- }
2497-}
2498-
2499-QFileInfo WebThumbnailUtils::thumbnailFile(const QUrl& url)
2500-{
2501- QString hash(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex());
2502- return cacheLocation().absoluteFilePath(hash + ".png");
2503-}
2504-
2505-void WebThumbnailUtils::cacheThumbnail(const QUrl& url, const QImage& thumbnail) const
2506-{
2507- ensureCacheLocation();
2508- QFileInfo file = thumbnailFile(url);
2509- bool saved = thumbnail.save(file.absoluteFilePath());
2510-
2511- if (saved) {
2512- // Make a link to the thumbnail file for the corresponding domain’s thumbnail.
2513- QUrl domain(DomainUtils::extractTopLevelDomainName(url));
2514- QString domainThumbnail = WebThumbnailUtils::thumbnailFile(domain).absoluteFilePath();
2515- if (QFile::exists(domainThumbnail)) {
2516- QFile::remove(domainThumbnail);
2517- }
2518- QFile::link(file.fileName(), domainThumbnail);
2519- }
2520-
2521- expireCache();
2522-}
2523-
2524-void WebThumbnailUtils::expireCache() const
2525-{
2526- QDir cache = cacheLocation();
2527- if (!cache.exists()) {
2528- return;
2529- }
2530- QStringList nameFilters = QStringList() << "*.png";
2531- QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot;
2532- QDir::SortFlags sort = QDir::Time;
2533- QFileInfoList entries = cache.entryInfoList(nameFilters, filters, sort);
2534- qint64 currentSize = 0;
2535- Q_FOREACH(const QFileInfo& entry, entries) {
2536- currentSize += entry.size();
2537- }
2538- if (currentSize > MAX_CACHE_SIZE_IN_BYTES) {
2539- qint64 goal = MAX_CACHE_SIZE_IN_BYTES * 9 / 10;
2540- while (!entries.isEmpty() && (currentSize > goal)) {
2541- QFileInfo entry = entries.takeLast();
2542- qint64 size = entry.size();
2543- if (QFile::remove(entry.absoluteFilePath())) {
2544- currentSize -= size;
2545- }
2546- }
2547- }
2548-}
2549
2550=== removed file 'src/app/webbrowser/webthumbnail-utils.h'
2551--- src/app/webbrowser/webthumbnail-utils.h 2014-03-12 23:09:21 +0000
2552+++ src/app/webbrowser/webthumbnail-utils.h 1970-01-01 00:00:00 +0000
2553@@ -1,51 +0,0 @@
2554-/*
2555- * Copyright 2013 Canonical Ltd.
2556- *
2557- * This file is part of webbrowser-app.
2558- *
2559- * webbrowser-app is free software; you can redistribute it and/or modify
2560- * it under the terms of the GNU General Public License as published by
2561- * the Free Software Foundation; version 3.
2562- *
2563- * webbrowser-app is distributed in the hope that it will be useful,
2564- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2565- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2566- * GNU General Public License for more details.
2567- *
2568- * You should have received a copy of the GNU General Public License
2569- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2570- */
2571-
2572-#ifndef __WEBTHUMBNAIL_UTILS_H__
2573-#define __WEBTHUMBNAIL_UTILS_H__
2574-
2575-// Qt
2576-#include <QtCore/QDir>
2577-#include <QtCore/QFileInfo>
2578-#include <QtCore/QObject>
2579-
2580-class QImage;
2581-class QUrl;
2582-
2583-class WebThumbnailUtils : public QObject
2584-{
2585- Q_OBJECT
2586-
2587-public:
2588- static WebThumbnailUtils& instance();
2589- ~WebThumbnailUtils();
2590-
2591- static QDir cacheLocation();
2592- static void ensureCacheLocation();
2593- static QFileInfo thumbnailFile(const QUrl& url);
2594-
2595-public Q_SLOTS:
2596- void cacheThumbnail(const QUrl& url, const QImage& thumbnail) const;
2597-
2598-private:
2599- WebThumbnailUtils(QObject* parent=0);
2600-
2601- void expireCache() const;
2602-};
2603-
2604-#endif // __WEBTHUMBNAIL_UTILS_H__
2605
2606=== removed file 'src/app/webbrowser/webview-thumbnailer.cpp'
2607--- src/app/webbrowser/webview-thumbnailer.cpp 2014-03-19 08:25:39 +0000
2608+++ src/app/webbrowser/webview-thumbnailer.cpp 1970-01-01 00:00:00 +0000
2609@@ -1,162 +0,0 @@
2610-/*
2611- * Copyright 2013 Canonical Ltd.
2612- *
2613- * This file is part of webbrowser-app.
2614- *
2615- * webbrowser-app is free software; you can redistribute it and/or modify
2616- * it under the terms of the GNU General Public License as published by
2617- * the Free Software Foundation; version 3.
2618- *
2619- * webbrowser-app is distributed in the hope that it will be useful,
2620- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2621- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2622- * GNU General Public License for more details.
2623- *
2624- * You should have received a copy of the GNU General Public License
2625- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2626- */
2627-
2628-#include "webthumbnail-utils.h"
2629-#include "webview-thumbnailer.h"
2630-
2631-// Qt
2632-#include <QtCore/QtGlobal>
2633-#include <QtCore/QMetaObject>
2634-#include <QtCore/QTimer>
2635-#include <QtQuick/private/qsgrenderer_p.h>
2636-#include <QtWebKit/private/qquickwebpage_p.h>
2637-#include <QtWebKit/private/qquickwebview_p.h>
2638-
2639-class BindableFbo : public QSGBindable
2640-{
2641-public:
2642- BindableFbo(QOpenGLFramebufferObject* fbo) : m_fbo(fbo) {}
2643- virtual void bind() const { m_fbo->bind(); }
2644-
2645-private:
2646- QOpenGLFramebufferObject *m_fbo;
2647-};
2648-
2649-WebviewThumbnailer::WebviewThumbnailer(QQuickItem* parent)
2650- : QQuickItem(parent)
2651- , m_webview(0)
2652-{
2653-}
2654-
2655-QQuickWebView* WebviewThumbnailer::webview() const
2656-{
2657- return m_webview;
2658-}
2659-
2660-void WebviewThumbnailer::setWebview(QQuickWebView* webview)
2661-{
2662- if (webview != m_webview) {
2663- m_webview = webview;
2664- setFlag(QQuickItem::ItemHasContents, false);
2665- Q_EMIT webviewChanged();
2666- }
2667-}
2668-
2669-const QSize& WebviewThumbnailer::targetSize() const
2670-{
2671- return m_targetSize;
2672-}
2673-
2674-void WebviewThumbnailer::setTargetSize(const QSize& targetSize)
2675-{
2676- if (targetSize != m_targetSize) {
2677- m_targetSize = targetSize;
2678- Q_EMIT targetSizeChanged();
2679- }
2680-}
2681-
2682-bool WebviewThumbnailer::thumbnailExists() const
2683-{
2684- if (m_webview) {
2685- QUrl url = m_webview->url();
2686- if (url.isValid()) {
2687- return WebThumbnailUtils::thumbnailFile(url).exists();
2688- }
2689- }
2690- return false;
2691-}
2692-
2693-void WebviewThumbnailer::renderThumbnail()
2694-{
2695- // Delay the actual rendering to give all elements on the page
2696- // a chance to be fully rendered.
2697- QTimer::singleShot(1000, this, SLOT(doRenderThumbnail()));
2698-}
2699-
2700-void WebviewThumbnailer::doRenderThumbnail()
2701-{
2702- if (m_webview) {
2703- setFlag(QQuickItem::ItemHasContents);
2704- update();
2705- }
2706-}
2707-
2708-QSGNode* WebviewThumbnailer::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData)
2709-{
2710- Q_UNUSED(updatePaintNodeData);
2711-
2712- if (!(m_webview && (flags() & QQuickItem::ItemHasContents))) {
2713- return oldNode;
2714- }
2715- setFlag(QQuickItem::ItemHasContents, false);
2716-
2717- QQuickWebPage* page = m_webview->page();
2718- qreal min = qMin(page->width(), page->height());
2719- QSize size(min, min);
2720-
2721- QSGNode* node = QQuickItemPrivate::get(page)->itemNode();
2722- QSGNode* parent = node->QSGNode::parent();
2723- QSGNode* previousSibling = node->previousSibling();
2724- if (parent) {
2725- parent->removeChildNode(node);
2726- }
2727- QSGRootNode root;
2728- root.appendChildNode(node);
2729-
2730- QSGRenderer* renderer;
2731-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
2732- renderer = QQuickItemPrivate::get(this)->sceneGraphContext()->createRenderer();
2733-#else
2734- renderer = QQuickItemPrivate::get(this)->sceneGraphRenderContext()->createRenderer();
2735-#endif
2736- renderer->setRootNode(static_cast<QSGRootNode*>(&root));
2737-
2738- QOpenGLFramebufferObject fbo(size);
2739-
2740- renderer->setDeviceRect(size);
2741- renderer->setViewportRect(size);
2742- renderer->setProjectionMatrixToRect(QRectF(QPointF(), size));
2743- renderer->setClearColor(Qt::transparent);
2744-
2745- renderer->renderScene(BindableFbo(&fbo));
2746-
2747- fbo.release();
2748-
2749- const QUrl& url = m_webview->url();
2750- QImage image = fbo.toImage().scaled(m_targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
2751-
2752- // Invoke the method asynchronously.
2753- QMetaObject::invokeMethod(&WebThumbnailUtils::instance(), "cacheThumbnail",
2754- Qt::QueuedConnection, Q_ARG(QUrl, url), Q_ARG(QImage, image));
2755-
2756- root.removeChildNode(node);
2757- renderer->setRootNode(0);
2758- delete renderer;
2759-
2760- if (parent) {
2761- if (previousSibling) {
2762- parent->insertChildNodeAfter(node, previousSibling);
2763- } else {
2764- parent->prependChildNode(node);
2765- }
2766- }
2767-
2768- Q_EMIT thumbnailRendered(url);
2769-
2770- return oldNode;
2771-}
2772
2773=== removed file 'src/app/webbrowser/webview-thumbnailer.h'
2774--- src/app/webbrowser/webview-thumbnailer.h 2014-03-19 08:25:39 +0000
2775+++ src/app/webbrowser/webview-thumbnailer.h 1970-01-01 00:00:00 +0000
2776@@ -1,64 +0,0 @@
2777-/*
2778- * Copyright 2013 Canonical Ltd.
2779- *
2780- * This file is part of webbrowser-app.
2781- *
2782- * webbrowser-app is free software; you can redistribute it and/or modify
2783- * it under the terms of the GNU General Public License as published by
2784- * the Free Software Foundation; version 3.
2785- *
2786- * webbrowser-app is distributed in the hope that it will be useful,
2787- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2788- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2789- * GNU General Public License for more details.
2790- *
2791- * You should have received a copy of the GNU General Public License
2792- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2793- */
2794-
2795-#ifndef __WEBVIEW_THUMBNAILER_H__
2796-#define __WEBVIEW_THUMBNAILER_H__
2797-
2798-// Qt
2799-#include <QtCore/QSize>
2800-#include <QtCore/QUrl>
2801-#include <QtQuick/private/qquickitem_p.h>
2802-
2803-class QQuickWebView;
2804-
2805-class WebviewThumbnailer : public QQuickItem
2806-{
2807- Q_OBJECT
2808-
2809- Q_PROPERTY(QQuickWebView* webview READ webview WRITE setWebview NOTIFY webviewChanged)
2810- Q_PROPERTY(QSize targetSize READ targetSize WRITE setTargetSize NOTIFY targetSizeChanged)
2811-
2812-public:
2813- WebviewThumbnailer(QQuickItem* parent=0);
2814-
2815- QQuickWebView* webview() const;
2816- void setWebview(QQuickWebView* webview);
2817-
2818- const QSize& targetSize() const;
2819- void setTargetSize(const QSize& targetSize);
2820-
2821- Q_INVOKABLE bool thumbnailExists() const;
2822- Q_INVOKABLE void renderThumbnail();
2823-
2824-Q_SIGNALS:
2825- void webviewChanged() const;
2826- void targetSizeChanged() const;
2827- void thumbnailRendered(const QUrl& url) const;
2828-
2829-protected:
2830- virtual QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData);
2831-
2832-private Q_SLOTS:
2833- void doRenderThumbnail();
2834-
2835-private:
2836- QQuickWebView* m_webview;
2837- QSize m_targetSize;
2838-};
2839-
2840-#endif // __WEBVIEW_THUMBNAILER_H__
2841
2842=== modified file 'src/app/webcontainer/WebApp.qml'
2843--- src/app/webcontainer/WebApp.qml 2014-03-20 18:17:12 +0000
2844+++ src/app/webcontainer/WebApp.qml 2014-03-28 17:03:06 +0000
2845@@ -17,8 +17,6 @@
2846 */
2847
2848 import QtQuick 2.0
2849-import QtWebKit 3.1
2850-import QtWebKit.experimental 1.0
2851 import Ubuntu.Components 0.1
2852 import Ubuntu.Components.Popups 0.1
2853 import Ubuntu.Unity.Action 1.0 as UnityActions
2854@@ -29,20 +27,23 @@
2855 BrowserView {
2856 id: webapp
2857
2858- currentWebview: webview
2859+ currentWebview: webview.currentWebview
2860
2861 property alias url: webview.url
2862- property string webappName: ""
2863+
2864 property string webappModelSearchPath: ""
2865- property var webappUrlPatterns: null
2866+
2867+ property alias oxide: webview.withOxide
2868+ property alias webappName: webview.webappName
2869+ property alias webappUrlPatterns: webview.webappUrlPatterns
2870
2871 actions: [
2872 Actions.Back {
2873- enabled: backForwardButtonsVisible && currentWebview.canGoBack
2874+ enabled: backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoBack
2875 onTriggered: webview.goBack()
2876 },
2877 Actions.Forward {
2878- enabled: backForwardButtonsVisible && currentWebview.canGoForward
2879+ enabled: backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoForward
2880 onTriggered: webview.goForward()
2881 },
2882 Actions.Reload {
2883@@ -58,10 +59,8 @@
2884 // The UITK is trying too hard to be clever about the header and toolbar.
2885 flickable: null
2886
2887- WebViewImpl {
2888+ WebappContainerWebview {
2889 id: webview
2890-
2891- currentWebview: webview
2892 toolbar: panel.panel
2893
2894 anchors {
2895@@ -70,97 +69,17 @@
2896 top: parent.top
2897 }
2898 height: parent.height - osk.height
2899-
2900- experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
2901-
2902- contextualActions: ActionList {
2903- Actions.CopyLink {
2904- enabled: webview.contextualData.href.toString()
2905- onTriggered: Clipboard.push([webview.contextualData.href])
2906- }
2907- Actions.CopyImage {
2908- enabled: webview.contextualData.img.toString()
2909- onTriggered: Clipboard.push([webview.contextualData.img])
2910- }
2911- }
2912-
2913- function haveValidUrlPatterns() {
2914- return webappUrlPatterns && webappUrlPatterns.length !== 0
2915- }
2916-
2917- function navigationRequestedDelegate(request) {
2918- if (!request.isMainFrame) {
2919- request.action = WebView.AcceptRequest
2920- return
2921- }
2922-
2923- // Pass-through if we are not running as a named webapp (--webapp='Gmail')
2924- // or if we dont have a list of url patterns specified to filter the
2925- // browsing actions
2926- if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
2927- request.action = WebView.AcceptRequest
2928- return
2929- }
2930-
2931- var action = WebView.IgnoreRequest
2932- var url = request.url.toString()
2933-
2934- // The list of url patterns defined by the webapp takes precedence over command line
2935- if (isRunningAsANamedWebapp()) {
2936- if (unityWebapps.model.exists(unityWebapps.name) &&
2937- unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
2938- request.action = WebView.AcceptRequest
2939- return;
2940- }
2941- }
2942-
2943- // We still take the possible additional patterns specified in the command line
2944- // (the in the case of finer grained ones specifically for the container and not
2945- // as an 'install source' for the webapp).
2946- if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
2947- for (var i = 0; i < webappUrlPatterns.length; ++i) {
2948- var pattern = webappUrlPatterns[i]
2949- if (url.match(pattern)) {
2950- action = WebView.AcceptRequest
2951- break
2952- }
2953- }
2954- }
2955-
2956- request.action = action
2957- if (action === WebView.IgnoreRequest) {
2958- console.debug('Opening: ' + url + ' in the browser window.')
2959- Qt.openUrlExternally(url)
2960- }
2961- }
2962-
2963- onNewTabRequested: Qt.openUrlExternally(url)
2964-
2965- // Small shim needed when running as a webapp to wire-up connections
2966- // with the webview (message received, etc…).
2967- // This is being called (and expected) internally by the webapps
2968- // component as a way to bind to a webview lookalike without
2969- // reaching out directly to its internals (see it as an interface).
2970- function getUnityWebappsProxies() {
2971- var eventHandlers = {
2972- onAppRaised: function () {
2973- if (webbrowserWindow) {
2974- try {
2975- webbrowserWindow.raise();
2976- } catch (e) {
2977- console.debug('Error while raising: ' + e);
2978- }
2979- }
2980- }
2981- };
2982- return UnityWebAppsUtils.makeProxiesForQtWebViewBindee(webview, eventHandlers)
2983- }
2984+ developerExtrasEnabled: webapp.developerExtrasEnabled
2985 }
2986
2987 ErrorSheet {
2988 anchors.fill: webview
2989- visible: webview.lastLoadRequestStatus == WebView.LoadFailedStatus
2990- url: webview.url
2991+ visible: {
2992+ if (webview.lastLoadFailed !== undefined)
2993+ return webview.lastLoadFailed
2994+ return webview.currentWebview && webview.currentWebview.lastLoadFailed
2995+ }
2996+ url: webview.currentWebview.url
2997 onRefreshClicked: webview.reload()
2998 }
2999 }
3000@@ -168,7 +87,7 @@
3001 PanelLoader {
3002 id: panel
3003
3004- currentWebview: webview
3005+ currentWebview: webview.currentWebview
3006 chromeless: webapp.chromeless
3007
3008 backForwardButtonsVisible: webapp.backForwardButtonsVisible
3009@@ -185,12 +104,8 @@
3010 UnityWebApps.UnityWebApps {
3011 id: unityWebapps
3012 name: webappName
3013- bindee: webview
3014+ bindee: webview.currentWebview
3015 actionsContext: actionManager.globalContext
3016 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }
3017 }
3018-
3019- function isRunningAsANamedWebapp() {
3020- return webappName && typeof(webappName) === 'string' && webappName.length != 0
3021- }
3022 }
3023
3024=== added file 'src/app/webcontainer/WebViewImplWebkit.qml'
3025--- src/app/webcontainer/WebViewImplWebkit.qml 1970-01-01 00:00:00 +0000
3026+++ src/app/webcontainer/WebViewImplWebkit.qml 2014-03-28 17:03:06 +0000
3027@@ -0,0 +1,159 @@
3028+/*
3029+ * Copyright 2013 Canonical Ltd.
3030+ *
3031+ * This file is part of webbrowser-app.
3032+ *
3033+ * webbrowser-app is free software; you can redistribute it and/or modify
3034+ * it under the terms of the GNU General Public License as published by
3035+ * the Free Software Foundation; version 3.
3036+ *
3037+ * webbrowser-app is distributed in the hope that it will be useful,
3038+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3039+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3040+ * GNU General Public License for more details.
3041+ *
3042+ * You should have received a copy of the GNU General Public License
3043+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3044+ */
3045+
3046+import QtQuick 2.0
3047+import QtWebKit 3.1
3048+import QtWebKit.experimental 1.0
3049+import Ubuntu.Components 0.1
3050+import Ubuntu.Components.Extras.Browser 0.1
3051+import Ubuntu.UnityWebApps 0.1 as UnityWebApps
3052+import Ubuntu.Components.Popups 0.1
3053+import "../actions" as Actions
3054+import ".."
3055+
3056+UbuntuWebView {
3057+ id: webview
3058+
3059+ property bool developerExtrasEnabled: false
3060+ property var currentWebview: webview
3061+ property var toolbar: null
3062+ property string webappName: ""
3063+ property var webappUrlPatterns: null
3064+
3065+ experimental.certificateVerificationDialog: CertificateVerificationDialog {}
3066+ experimental.authenticationDialog: AuthenticationDialog {}
3067+ experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}
3068+ experimental.alertDialog: AlertDialog {}
3069+ experimental.confirmDialog: ConfirmDialog {}
3070+ experimental.promptDialog: PromptDialog {}
3071+
3072+ selectionActions: ActionList {
3073+ Actions.Copy {
3074+ onTriggered: selection.copy()
3075+ }
3076+ }
3077+
3078+ property bool lastLoadFailed: false
3079+ onLoadingChanged: {
3080+ lastLoadFailed = (loadRequest.status === WebView.LoadFailedStatus)
3081+ }
3082+
3083+ experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
3084+
3085+ experimental.onPermissionRequested: {
3086+ if (permission.type === PermissionRequest.Geolocation) {
3087+ if (webview.toolbar) {
3088+ webview.toolbar.close()
3089+ }
3090+ var text = i18n.tr("This page wants to know your device’s location.")
3091+ PopupUtils.open(Qt.resolvedUrl("PermissionRequest.qml"),
3092+ webview.currentWebview,
3093+ {"permission": permission, "text": text})
3094+ }
3095+ // TODO: handle other types of permission requests
3096+ // TODO: we might want to store the answer to avoid requesting
3097+ // the permission everytime the user visits this site.
3098+ }
3099+
3100+ contextualActions: ActionList {
3101+ Actions.CopyLink {
3102+ enabled: webview.contextualData.href.toString()
3103+ onTriggered: Clipboard.push([webview.contextualData.href])
3104+ }
3105+ Actions.CopyImage {
3106+ enabled: webview.contextualData.img.toString()
3107+ onTriggered: Clipboard.push([webview.contextualData.img])
3108+ }
3109+ }
3110+
3111+ function isRunningAsANamedWebapp() {
3112+ return webview.webappName && typeof(webview.webappName) === 'string' && webview.webappName.length != 0
3113+ }
3114+
3115+ function haveValidUrlPatterns() {
3116+ return webappUrlPatterns && webappUrlPatterns.length !== 0
3117+ }
3118+
3119+ function navigationRequestedDelegate(request) {
3120+ if (!request.isMainFrame) {
3121+ request.action = WebView.AcceptRequest
3122+ return
3123+ }
3124+
3125+ // Pass-through if we are not running as a named webapp (--webapp='Gmail')
3126+ // or if we dont have a list of url patterns specified to filter the
3127+ // browsing actions
3128+ if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
3129+ request.action = WebView.AcceptRequest
3130+ return
3131+ }
3132+
3133+ var action = WebView.IgnoreRequest
3134+ var url = request.url.toString()
3135+
3136+ // The list of url patterns defined by the webapp takes precedence over command line
3137+ if (isRunningAsANamedWebapp()) {
3138+ if (unityWebapps.model.exists(unityWebapps.name) &&
3139+ unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
3140+ request.action = WebView.AcceptRequest
3141+ return;
3142+ }
3143+ }
3144+
3145+ // We still take the possible additional patterns specified in the command line
3146+ // (the in the case of finer grained ones specifically for the container and not
3147+ // as an 'install source' for the webapp).
3148+ if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
3149+ for (var i = 0; i < webappUrlPatterns.length; ++i) {
3150+ var pattern = webappUrlPatterns[i]
3151+ if (url.match(pattern)) {
3152+ action = WebView.AcceptRequest
3153+ break
3154+ }
3155+ }
3156+ }
3157+
3158+ request.action = action
3159+ if (action === WebView.IgnoreRequest) {
3160+ console.debug('Opening: ' + url + ' in the browser window.')
3161+ Qt.openUrlExternally(url)
3162+ }
3163+ }
3164+
3165+ onNewTabRequested: Qt.openUrlExternally(url)
3166+
3167+ // Small shim needed when running as a webapp to wire-up connections
3168+ // with the webview (message received, etc…).
3169+ // This is being called (and expected) internally by the webapps
3170+ // component as a way to bind to a webview lookalike without
3171+ // reaching out directly to its internals (see it as an interface).
3172+ function getUnityWebappsProxies() {
3173+ var eventHandlers = {
3174+ onAppRaised: function () {
3175+ if (webbrowserWindow) {
3176+ try {
3177+ webbrowserWindow.raise();
3178+ } catch (e) {
3179+ console.debug('Error while raising: ' + e);
3180+ }
3181+ }
3182+ }
3183+ };
3184+ return UnityWebAppsUtils.makeProxiesForQtWebViewBindee(webview, eventHandlers)
3185+ }
3186+}
3187
3188=== added file 'src/app/webcontainer/WebappContainerWebview.qml'
3189--- src/app/webcontainer/WebappContainerWebview.qml 1970-01-01 00:00:00 +0000
3190+++ src/app/webcontainer/WebappContainerWebview.qml 2014-03-28 17:03:06 +0000
3191@@ -0,0 +1,151 @@
3192+/*
3193+ * Copyright 2014 Canonical Ltd.
3194+ *
3195+ * This file is part of webbrowser-app.
3196+ *
3197+ * webbrowser-app is free software; you can redistribute it and/or modify
3198+ * it under the terms of the GNU General Public License as published by
3199+ * the Free Software Foundation; version 3.
3200+ *
3201+ * webbrowser-app is distributed in the hope that it will be useful,
3202+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3203+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3204+ * GNU General Public License for more details.
3205+ *
3206+ * You should have received a copy of the GNU General Public License
3207+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3208+ */
3209+
3210+import QtQuick 2.0
3211+import Ubuntu.Components 0.1
3212+import Ubuntu.Unity.Action 1.0 as UnityActions
3213+import Ubuntu.UnityWebApps 0.1 as UnityWebApps
3214+import "../actions" as Actions
3215+import ".."
3216+
3217+Item {
3218+ id: containerWebview
3219+
3220+ property string url: ""
3221+ property bool withOxide: false
3222+ property bool developerExtrasEnabled: false
3223+ property string webappName: ""
3224+ property var currentWebview: webappContainerWebViewLoader.item
3225+ property var toolbar: null
3226+ property var webappUrlPatterns: null
3227+
3228+ Loader {
3229+ id: webappContainerWebViewLoader
3230+ anchors.fill: parent
3231+ sourceComponent: withOxide ? webappContainerWebViewOxide : webappContainerWebViewWebkit
3232+ }
3233+
3234+ Component {
3235+ id: webappContainerWebViewWebkit
3236+
3237+ WebViewImplWebkit {
3238+ toolbar: containerWebview.toolbar
3239+ url: containerWebview.url
3240+ webappName: containerWebview.webappName
3241+ webappUrlPatterns: containerWebview.webappUrlPatterns
3242+ developerExtrasEnabled: containerWebview.developerExtrasEnabled
3243+ }
3244+ }
3245+
3246+ Component {
3247+ id: webappContainerWebViewOxide
3248+
3249+ WebViewImpl {
3250+ id: webview
3251+
3252+ url: containerWebview.url
3253+ currentWebview: webview
3254+ toolbar: containerWebview.toolbar
3255+
3256+ contextualActions: ActionList {
3257+ Actions.CopyLink {
3258+ enabled: webview.contextualData.href.toString()
3259+ onTriggered: Clipboard.push([webview.contextualData.href])
3260+ }
3261+ Actions.CopyImage {
3262+ enabled: webview.contextualData.img.toString()
3263+ onTriggered: Clipboard.push([webview.contextualData.img])
3264+ }
3265+ }
3266+
3267+ function haveValidUrlPatterns() {
3268+ return webappUrlPatterns && webappUrlPatterns.length !== 0
3269+ }
3270+
3271+ /*function navigationRequestedDelegate(request) {
3272+ if (!request.isMainFrame) {
3273+ request.action = WebView.AcceptRequest
3274+ return
3275+ }
3276+
3277+ // Pass-through if we are not running as a named webapp (--webapp='Gmail')
3278+ // or if we dont have a list of url patterns specified to filter the
3279+ // browsing actions
3280+ if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
3281+ request.action = WebView.AcceptRequest
3282+ return
3283+ }
3284+
3285+ var action = WebView.IgnoreRequest
3286+ var url = request.url.toString()
3287+
3288+ // The list of url patterns defined by the webapp takes precedence over command line
3289+ if (isRunningAsANamedWebapp()) {
3290+ if (unityWebapps.model.exists(unityWebapps.name) &&
3291+ unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
3292+ request.action = WebView.AcceptRequest
3293+ return;
3294+ }
3295+ }
3296+
3297+ // We still take the possible additional patterns specified in the command line
3298+ // (the in the case of finer grained ones specifically for the container and not
3299+ // as an 'install source' for the webapp).
3300+ if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
3301+ for (var i = 0; i < webappUrlPatterns.length; ++i) {
3302+ var pattern = webappUrlPatterns[i]
3303+ if (url.match(pattern)) {
3304+ action = WebView.AcceptRequest
3305+ break
3306+ }
3307+ }
3308+ }
3309+
3310+ request.action = action
3311+ if (action === WebView.IgnoreRequest) {
3312+ console.debug('Opening: ' + url + ' in the browser window.')
3313+ Qt.openUrlExternally(url)
3314+ }
3315+ }*/
3316+
3317+ onNewTabRequested: Qt.openUrlExternally(url)
3318+
3319+ preferences.localStorageEnabled: true
3320+
3321+ // Small shim needed when running as a webapp to wire-up connections
3322+ // with the webview (message received, etc…).
3323+ // This is being called (and expected) internally by the webapps
3324+ // component as a way to bind to a webview lookalike without
3325+ // reaching out directly to its internals (see it as an interface).
3326+ function getUnityWebappsProxies() {
3327+ var eventHandlers = {
3328+ onAppRaised: function () {
3329+ if (webbrowserWindow) {
3330+ try {
3331+ webbrowserWindow.raise();
3332+ } catch (e) {
3333+ console.debug('Error while raising: ' + e);
3334+ }
3335+ }
3336+ }
3337+ };
3338+ return UnityWebAppsUtils.makeProxiesForWebViewBindee(webview, eventHandlers)
3339+ }
3340+ }
3341+ }
3342+}
3343
3344=== modified file 'src/app/webcontainer/webapp-container.cpp'
3345--- src/app/webcontainer/webapp-container.cpp 2014-03-20 18:17:12 +0000
3346+++ src/app/webcontainer/webapp-container.cpp 2014-03-28 17:03:06 +0000
3347@@ -24,10 +24,32 @@
3348 // Qt
3349 #include <QtCore/QCoreApplication>
3350 #include <QtCore/QDebug>
3351+#include <QtCore/QFile>
3352 #include <QtCore/QFileInfo>
3353+#include <QtCore/QtGlobal>
3354 #include <QtCore/QRegularExpression>
3355 #include <QtCore/QTextStream>
3356 #include <QtQuick/QQuickWindow>
3357+#include <QtQml/QQmlComponent>
3358+
3359+
3360+namespace
3361+{
3362+
3363+QString currentArchitecturePathName()
3364+{
3365+#if defined(Q_PROCESSOR_X86_32)
3366+ return QLatin1String("i386-linux-gnu");
3367+#elif defined(Q_PROCESSOR_X86_64)
3368+ return QLatin1String("x86_64-linux-gnu");
3369+#elif defined(Q_PROCESSOR_ARM)
3370+ return QLatin1String("arm-linux-gnueabihf");
3371+#else
3372+#error Unable to determine target architecture
3373+#endif
3374+}
3375+
3376+}
3377
3378 WebappContainer::WebappContainer(int& argc, char** argv)
3379 : BrowserApplication(argc, argv)
3380@@ -50,7 +72,13 @@
3381 m_window->setProperty("webappName", name);
3382 m_window->setProperty("backForwardButtonsVisible", m_arguments.contains("--enable-back-forward"));
3383 m_window->setProperty("addressBarVisible", m_arguments.contains("--enable-addressbar"));
3384+
3385+ bool oxide = withOxide();
3386+ qDebug() << "Using" << (oxide ? "Oxide" : "QtWebkit") << "as the web engine backend";
3387+ m_window->setProperty("oxide", oxide);
3388+
3389 m_window->setProperty("webappUrlPatterns", webappUrlPatterns());
3390+
3391 // When a webapp is being launched by name, the URL is pulled from its 'homepage'.
3392 if (name.isEmpty()) {
3393 QList<QUrl> urls = this->urls();
3394@@ -58,6 +86,9 @@
3395 m_window->setProperty("url", urls.first());
3396 }
3397 }
3398+
3399+ m_component->completeCreate();
3400+
3401 return true;
3402 } else {
3403 return false;
3404@@ -84,6 +115,31 @@
3405 out << " --enable-addressbar enable the display of the address bar" << endl;
3406 }
3407
3408+bool WebappContainer::withOxide() const
3409+{
3410+ Q_FOREACH(const QString& argument, m_arguments) {
3411+ if (argument == "--webkit") {
3412+ // force webkit
3413+ return false;
3414+ }
3415+ if (argument == "--oxide") {
3416+ // force oxide
3417+ return true;
3418+ }
3419+ }
3420+
3421+ // Use a runtime hint to transparently know if oxide
3422+ // can be used as a backend without the user/dev having
3423+ // to update its app or change something in the Exec args.
3424+ // Version 1.1 of ubuntu apparmor policy allows this file to
3425+ // be accessed whereas v1.0 only knows about qtwebkit.
3426+ QString oxideHintLocation =
3427+ QString("/usr/lib/%1/oxide-qt/oxide-renderer")
3428+ .arg(currentArchitecturePathName());
3429+
3430+ return QFile(oxideHintLocation).open(QIODevice::ReadOnly);
3431+}
3432+
3433 QString WebappContainer::webappModelSearchPath() const
3434 {
3435 Q_FOREACH(const QString& argument, m_arguments) {
3436
3437=== modified file 'src/app/webcontainer/webapp-container.h'
3438--- src/app/webcontainer/webapp-container.h 2014-03-14 14:51:22 +0000
3439+++ src/app/webcontainer/webapp-container.h 2014-03-28 17:03:06 +0000
3440@@ -39,6 +39,7 @@
3441 QString webappModelSearchPath() const;
3442 QString webappName() const;
3443 QStringList webappUrlPatterns() const;
3444+ bool withOxide() const;
3445 };
3446
3447 #endif // __WEBAPP_CONTAINER_H__
3448
3449=== modified file 'src/app/webcontainer/webapp-container.qml'
3450--- src/app/webcontainer/webapp-container.qml 2014-03-14 14:51:22 +0000
3451+++ src/app/webcontainer/webapp-container.qml 2014-03-28 17:03:06 +0000
3452@@ -30,6 +30,7 @@
3453 property alias webappName: browser.webappName
3454 property alias webappModelSearchPath: browser.webappModelSearchPath
3455 property alias webappUrlPatterns: browser.webappUrlPatterns
3456+ property alias oxide: browser.oxide
3457
3458 contentOrientation: browser.screenOrientation
3459
3460
3461=== modified file 'tests/autopilot/webbrowser_app/tests/test_tabs.py'
3462--- tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-02-06 04:31:01 +0000
3463+++ tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-03-28 17:03:06 +0000
3464@@ -17,6 +17,7 @@
3465 from __future__ import absolute_import
3466
3467 import time
3468+import unittest
3469 from testtools.matchers import Equals
3470 from autopilot.matchers import Eventually
3471
3472@@ -140,6 +141,8 @@
3473 address_bar = self.main_window.get_address_bar()
3474 self.assertThat(address_bar.activeFocus, Eventually(Equals(True)))
3475
3476+ # FIXME: re-enable when implemented in oxide
3477+ @unittest.skip("not implemented in oxide yet")
3478 def test_open_target_blank_in_new_tab(self):
3479 url = self.base_url + "/blanktargetlink"
3480 self.go_to_url(url)
3481@@ -149,6 +152,8 @@
3482 self.assertThat(self.main_window.currentIndex, Eventually(Equals(1)))
3483 self.assert_current_url(self.base_url + "/aleaiactaest")
3484
3485+ # FIXME: re-enable when implemented in oxide
3486+ @unittest.skip("not implemented in oxide yet")
3487 def test_open_iframe_target_blank_in_new_tab(self):
3488 url = self.base_url + "/fulliframewithblanktargetlink"
3489 self.go_to_url(url)
3490
3491=== modified file 'tests/unittests/qml/CMakeLists.txt'
3492--- tests/unittests/qml/CMakeLists.txt 2014-03-12 15:27:10 +0000
3493+++ tests/unittests/qml/CMakeLists.txt 2014-03-28 17:03:06 +0000
3494@@ -1,8 +1,15 @@
3495+set(XVFB_COMMAND)
3496+find_program(XVFBRUN xvfb-run)
3497+if(XVFBRUN)
3498+ set(XVFB_COMMAND ${XVFBRUN} -s "-screen 0 640x480x24" -a)
3499+else()
3500+ message(WARNING "Cannot find xvfb-run.")
3501+endif()
3502+
3503 set(TEST tst_QmlTests)
3504 add_executable(${TEST} tst_QmlTests.cpp)
3505 qt5_use_modules(${TEST} Core Qml Quick Test QuickTest)
3506-add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -import ${CMAKE_BINARY_DIR}/src)
3507-set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
3508+add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -import ${CMAKE_BINARY_DIR}/src)
3509
3510 # copy qml files under test to build dir
3511 set(out_qml_files)
3512@@ -13,7 +20,7 @@
3513 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${webbrowser-common_SOURCE_DIR}/${qmlFile} ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile})
3514 list(APPEND out_qml_files undertest/${qmlFile})
3515 endforeach(qmlFile)
3516-set(privateApiQmlFiles UserAgent.qml ua-overrides.js)
3517+set(privateApiQmlFiles UserAgent01.qml UserAgent02.qml ua-overrides.js)
3518 foreach(qmlFile ${privateApiQmlFiles})
3519 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile}
3520 DEPENDS ${webbrowser-plugin_SOURCE_DIR}/${qmlFile}
3521
3522=== added file 'tests/unittests/qml/tst_UbuntuWebView01.qml'
3523--- tests/unittests/qml/tst_UbuntuWebView01.qml 1970-01-01 00:00:00 +0000
3524+++ tests/unittests/qml/tst_UbuntuWebView01.qml 2014-03-28 17:03:06 +0000
3525@@ -0,0 +1,46 @@
3526+/*
3527+ * Copyright 2013 Canonical Ltd.
3528+ *
3529+ * This file is part of webbrowser-app.
3530+ *
3531+ * webbrowser-app is free software; you can redistribute it and/or modify
3532+ * it under the terms of the GNU General Public License as published by
3533+ * the Free Software Foundation; version 3.
3534+ *
3535+ * webbrowser-app is distributed in the hope that it will be useful,
3536+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3537+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3538+ * GNU General Public License for more details.
3539+ *
3540+ * You should have received a copy of the GNU General Public License
3541+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3542+ */
3543+
3544+import QtQuick 2.0
3545+import QtTest 1.0
3546+import Ubuntu.Components.Extras.Browser 0.1
3547+
3548+TestCase {
3549+ name: "UbuntuWebView"
3550+
3551+ function test_custom_UA_override() {
3552+ compare(webview1.getUAString(), undefined)
3553+ // passing a 'url' parameter to getUAString()
3554+ // (as was the API before) shouldn’t hurt:
3555+ compare(webview1.getUAString("http://example.com"), undefined)
3556+ verify(webview1.experimental.userAgent !== undefined)
3557+ compare(webview2.experimental.userAgent, "custom UA")
3558+ }
3559+
3560+ UbuntuWebView {
3561+ id: webview1
3562+ }
3563+
3564+ UbuntuWebView {
3565+ id: webview2
3566+
3567+ function getUAString(url) {
3568+ return "custom UA"
3569+ }
3570+ }
3571+}
3572
3573=== renamed file 'tests/unittests/qml/tst_UbuntuWebView.qml' => 'tests/unittests/qml/tst_UbuntuWebView02.qml'
3574--- tests/unittests/qml/tst_UbuntuWebView.qml 2014-03-14 17:26:10 +0000
3575+++ tests/unittests/qml/tst_UbuntuWebView02.qml 2014-03-28 17:03:06 +0000
3576@@ -18,18 +18,15 @@
3577
3578 import QtQuick 2.0
3579 import QtTest 1.0
3580-import Ubuntu.Components.Extras.Browser 0.1
3581+import Ubuntu.Components.Extras.Browser 0.2
3582
3583 TestCase {
3584 name: "UbuntuWebView"
3585
3586 function test_custom_UA_override() {
3587 compare(webview1.getUAString(), undefined)
3588- // passing a 'url' parameter to getUAString()
3589- // (as was the API before) shouldn’t hurt:
3590- compare(webview1.getUAString("http://example.com"), undefined)
3591- verify(webview1.experimental.userAgent !== undefined)
3592- compare(webview2.experimental.userAgent, "custom UA")
3593+ verify(webview1.context.userAgent !== undefined)
3594+ compare(webview2.context.userAgent, "custom UA")
3595 }
3596
3597 UbuntuWebView {
3598
3599=== removed file 'tests/unittests/qml/tst_UserAgent.qml'
3600--- tests/unittests/qml/tst_UserAgent.qml 2014-03-12 15:27:10 +0000
3601+++ tests/unittests/qml/tst_UserAgent.qml 1970-01-01 00:00:00 +0000
3602@@ -1,82 +0,0 @@
3603-/*
3604- * Copyright 2013 Canonical Ltd.
3605- *
3606- * This file is part of webbrowser-app.
3607- *
3608- * webbrowser-app is free software; you can redistribute it and/or modify
3609- * it under the terms of the GNU General Public License as published by
3610- * the Free Software Foundation; version 3.
3611- *
3612- * webbrowser-app is distributed in the hope that it will be useful,
3613- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3614- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3615- * GNU General Public License for more details.
3616- *
3617- * You should have received a copy of the GNU General Public License
3618- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3619- */
3620-
3621-import QtQuick 2.0
3622-import QtTest 1.0
3623-import "undertest"
3624-
3625-TestCase {
3626- name: "UserAgent"
3627-
3628- function test_get_domain_data() {
3629- return [
3630- {url: "http://ubuntu.com", domain: "ubuntu.com"},
3631- {url: "http://www.ubuntu.com", domain: "www.ubuntu.com"},
3632- {url: "http://ubuntu.com/", domain: "ubuntu.com"},
3633- {url: "http://www.ubuntu.com/", domain: "www.ubuntu.com"},
3634- {url: "ubuntu.com", domain: "ubuntu.com"},
3635- {url: "ubuntu.com/", domain: "ubuntu.com"},
3636- {url: "ubuntu.com/phone", domain: "ubuntu.com"},
3637- {url: "http://ubuntu.com/phone", domain: "ubuntu.com"},
3638- {url: "www.ubuntu.com/phone", domain: "www.ubuntu.com"},
3639- {url: "http://ubuntu.com/phone/index.html", domain: "ubuntu.com"},
3640- {url: "ubuntu.com/phone/index.html", domain: "ubuntu.com"},
3641- {url: "www.ubuntu.com/phone/index.html", domain: "www.ubuntu.com"},
3642- {url: "http://ubuntu.com/phone/index.html?foo=bar&baz=bleh", domain: "ubuntu.com"},
3643- ]
3644- }
3645- function test_get_domain(data) {
3646- compare(userAgent.getDomain(data.url), data.domain)
3647- }
3648-
3649- function test_get_domains_data() {
3650- return [
3651- {domain: "ubuntu.com", domains: ["ubuntu.com", "com"]},
3652- {domain: "test.example.org", domains: ["test.example.org", "example.org", "org"]},
3653- ]
3654- }
3655- function test_get_domains(data) {
3656- compare(userAgent.getDomains(data.domain), data.domains)
3657- }
3658-
3659- function test_get_ua_string_data() {
3660- return [
3661- {url: "http://ubuntu.com", ua: userAgent.defaultUA},
3662- {url: "http://example.org", ua: "full override"},
3663- {url: "http://example.com/test", ua: "Mozilla/5.0 (Ubuntu Edge; Mobile) WebKit/537.21"},
3664- {url: "http://www.google.com/", ua: "Mozilla/5.0 (Ubuntu; ble) WebKit/537.21"},
3665- {url: "https://mail.google.com/", ua: "Mozilla/5.0 (Ubuntu; Touch) WebKit/537.21"},
3666- ]
3667- }
3668- function test_get_ua_string(data) {
3669- compare(userAgent.getUAString(data.url), data.ua)
3670- }
3671-
3672- UserAgent {
3673- id: userAgent
3674-
3675- defaultUA: "Mozilla/5.0 (Ubuntu; Mobile) WebKit/537.21"
3676-
3677- overrides: {
3678- "example.org": "full override",
3679- "example.com": ["Ubuntu", "Ubuntu Edge"],
3680- "google.com": [/mobi/i, "b"],
3681- "mail.google.com": [/mobile/i, "Touch"],
3682- }
3683- }
3684-}
3685
3686=== added file 'tests/unittests/qml/tst_UserAgent01.qml'
3687--- tests/unittests/qml/tst_UserAgent01.qml 1970-01-01 00:00:00 +0000
3688+++ tests/unittests/qml/tst_UserAgent01.qml 2014-03-28 17:03:06 +0000
3689@@ -0,0 +1,82 @@
3690+/*
3691+ * Copyright 2013 Canonical Ltd.
3692+ *
3693+ * This file is part of webbrowser-app.
3694+ *
3695+ * webbrowser-app is free software; you can redistribute it and/or modify
3696+ * it under the terms of the GNU General Public License as published by
3697+ * the Free Software Foundation; version 3.
3698+ *
3699+ * webbrowser-app is distributed in the hope that it will be useful,
3700+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3701+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3702+ * GNU General Public License for more details.
3703+ *
3704+ * You should have received a copy of the GNU General Public License
3705+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3706+ */
3707+
3708+import QtQuick 2.0
3709+import QtTest 1.0
3710+import "undertest"
3711+
3712+TestCase {
3713+ name: "UserAgent"
3714+
3715+ function test_get_domain_data() {
3716+ return [
3717+ {url: "http://ubuntu.com", domain: "ubuntu.com"},
3718+ {url: "http://www.ubuntu.com", domain: "www.ubuntu.com"},
3719+ {url: "http://ubuntu.com/", domain: "ubuntu.com"},
3720+ {url: "http://www.ubuntu.com/", domain: "www.ubuntu.com"},
3721+ {url: "ubuntu.com", domain: "ubuntu.com"},
3722+ {url: "ubuntu.com/", domain: "ubuntu.com"},
3723+ {url: "ubuntu.com/phone", domain: "ubuntu.com"},
3724+ {url: "http://ubuntu.com/phone", domain: "ubuntu.com"},
3725+ {url: "www.ubuntu.com/phone", domain: "www.ubuntu.com"},
3726+ {url: "http://ubuntu.com/phone/index.html", domain: "ubuntu.com"},
3727+ {url: "ubuntu.com/phone/index.html", domain: "ubuntu.com"},
3728+ {url: "www.ubuntu.com/phone/index.html", domain: "www.ubuntu.com"},
3729+ {url: "http://ubuntu.com/phone/index.html?foo=bar&baz=bleh", domain: "ubuntu.com"},
3730+ ]
3731+ }
3732+ function test_get_domain(data) {
3733+ compare(userAgent.getDomain(data.url), data.domain)
3734+ }
3735+
3736+ function test_get_domains_data() {
3737+ return [
3738+ {domain: "ubuntu.com", domains: ["ubuntu.com", "com"]},
3739+ {domain: "test.example.org", domains: ["test.example.org", "example.org", "org"]},
3740+ ]
3741+ }
3742+ function test_get_domains(data) {
3743+ compare(userAgent.getDomains(data.domain), data.domains)
3744+ }
3745+
3746+ function test_get_ua_string_data() {
3747+ return [
3748+ {url: "http://ubuntu.com", ua: userAgent.defaultUA},
3749+ {url: "http://example.org", ua: "full override"},
3750+ {url: "http://example.com/test", ua: "Mozilla/5.0 (Ubuntu Edge; Mobile) WebKit/537.21"},
3751+ {url: "http://www.google.com/", ua: "Mozilla/5.0 (Ubuntu; ble) WebKit/537.21"},
3752+ {url: "https://mail.google.com/", ua: "Mozilla/5.0 (Ubuntu; Touch) WebKit/537.21"},
3753+ ]
3754+ }
3755+ function test_get_ua_string(data) {
3756+ compare(userAgent.getUAString(data.url), data.ua)
3757+ }
3758+
3759+ UserAgent01 {
3760+ id: userAgent
3761+
3762+ defaultUA: "Mozilla/5.0 (Ubuntu; Mobile) WebKit/537.21"
3763+
3764+ overrides: {
3765+ "example.org": "full override",
3766+ "example.com": ["Ubuntu", "Ubuntu Edge"],
3767+ "google.com": [/mobi/i, "b"],
3768+ "mail.google.com": [/mobile/i, "Touch"],
3769+ }
3770+ }
3771+}

Subscribers

People subscribed via source and target branches

to status/vote changes: