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

Proposed by David Barth
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
Ubuntu Phablet Team 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.
Revision history for this message
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
492. By Alexandre Abreu

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

Clean up changelog.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2013-10-09 08:32:01 +0000
+++ CMakeLists.txt 2014-03-28 17:03:06 +0000
@@ -29,6 +29,7 @@
29endif()29endif()
3030
31find_package(Qt5Core REQUIRED)31find_package(Qt5Core REQUIRED)
32find_package(Qt5Gui REQUIRED)
32find_package(Qt5Sql REQUIRED)33find_package(Qt5Sql REQUIRED)
33find_package(Qt5Widgets REQUIRED)34find_package(Qt5Widgets REQUIRED)
34find_package(Qt5Quick REQUIRED)35find_package(Qt5Quick REQUIRED)
3536
=== modified file 'debian/control'
--- debian/control 2014-03-17 16:05:04 +0000
+++ debian/control 2014-03-28 17:03:06 +0000
@@ -8,8 +8,8 @@
8 hardening-wrapper,8 hardening-wrapper,
9 python,9 python,
10 libqt5sql5-sqlite,10 libqt5sql5-sqlite,
11 libqt5webkit5-dev,
12 libqt5webkit5-qmlwebkitplugin,11 libqt5webkit5-qmlwebkitplugin,
12 liboxideqt-qmlplugin,
13 qt5-default,13 qt5-default,
14 qt5-qmake,14 qt5-qmake,
15 qtbase5-dev,15 qtbase5-dev,
@@ -19,6 +19,7 @@
19 qtdeclarative5-qtquick2-plugin,19 qtdeclarative5-qtquick2-plugin,
20 qtdeclarative5-test-plugin,20 qtdeclarative5-test-plugin,
21 qtdeclarative5-ubuntu-ui-toolkit-plugin,21 qtdeclarative5-ubuntu-ui-toolkit-plugin,
22 xvfb,
22Standards-Version: 3.9.423Standards-Version: 3.9.4
23Homepage: https://launchpad.net/webbrowser-app24Homepage: https://launchpad.net/webbrowser-app
24# If you aren't a member of ~phablet-team but need to upload packaging changes,25# If you aren't a member of ~phablet-team but need to upload packaging changes,
@@ -30,7 +31,7 @@
30Multi-Arch: foreign31Multi-Arch: foreign
31Depends: ${misc:Depends},32Depends: ${misc:Depends},
32 ${shlibs:Depends},33 ${shlibs:Depends},
33 libqt5webkit5-qmlwebkitplugin,34 liboxideqt-qmlplugin,
34 qtdeclarative5-qtquick2-plugin,35 qtdeclarative5-qtquick2-plugin,
35 qtdeclarative5-ubuntu-ui-extras-browser-plugin (= ${binary:Version}),36 qtdeclarative5-ubuntu-ui-extras-browser-plugin (= ${binary:Version}),
36 qtdeclarative5-ubuntu-ui-toolkit-plugin,37 qtdeclarative5-ubuntu-ui-toolkit-plugin,
@@ -50,6 +51,7 @@
50Depends: ${misc:Depends},51Depends: ${misc:Depends},
51 ${shlibs:Depends},52 ${shlibs:Depends},
52 unity-webapps-qml,53 unity-webapps-qml,
54 libqt5webkit5-qmlwebkitplugin,
53 webbrowser-app (= ${binary:Version}),55 webbrowser-app (= ${binary:Version}),
54Description: Ubuntu web applications container56Description: Ubuntu web applications container
55 A lightweight webapps container tailored for Ubuntu, based on the Webkit57 A lightweight webapps container tailored for Ubuntu, based on the Webkit
@@ -62,6 +64,7 @@
62 ${shlibs:Depends},64 ${shlibs:Depends},
63 libqt5sql5-sqlite,65 libqt5sql5-sqlite,
64 libqt5webkit5-qmlwebkitplugin,66 libqt5webkit5-qmlwebkitplugin,
67 liboxideqt-qmlplugin,
65 qtdeclarative5-qtquick2-plugin,68 qtdeclarative5-qtquick2-plugin,
66 qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets (>= ${source:Version}),69 qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets (>= ${source:Version}),
67 qtdeclarative5-ubuntu-ui-toolkit-plugin,70 qtdeclarative5-ubuntu-ui-toolkit-plugin,
6871
=== modified file 'po/webbrowser-app.pot'
--- po/webbrowser-app.pot 2013-11-13 08:11:24 +0000
+++ po/webbrowser-app.pot 2014-03-28 17:03:06 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: webbrowser-app\n"9"Project-Id-Version: webbrowser-app\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2013-11-13 09:10+0100\n"11"POT-Creation-Date: 2014-03-26 10:59+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,14 +17,6 @@
17"Content-Type: text/plain; charset=UTF-8\n"17"Content-Type: text/plain; charset=UTF-8\n"
18"Content-Transfer-Encoding: 8bit\n"18"Content-Transfer-Encoding: 8bit\n"
1919
20#: src/app/ActivityView.qml:36 src/app/Chrome.qml:127
21msgid "Activity"
22msgstr ""
23
24#: src/app/ActivityView.qml:54
25msgid "Bookmarks"
26msgstr ""
27
28#: src/app/AlertDialog.qml:2420#: src/app/AlertDialog.qml:24
29msgid "JavaScript Alert"21msgid "JavaScript Alert"
30msgstr ""22msgstr ""
@@ -57,6 +49,18 @@
57msgid "Cancel"49msgid "Cancel"
58msgstr ""50msgstr ""
5951
52#: src/app/BeforeUnloadDialog.qml:24
53msgid "Confirm Navigation"
54msgstr ""
55
56#: src/app/BeforeUnloadDialog.qml:28
57msgid "Leave"
58msgstr ""
59
60#: src/app/BeforeUnloadDialog.qml:33
61msgid "Stay"
62msgstr ""
63
60#: src/app/CertificateVerificationDialog.qml:2464#: src/app/CertificateVerificationDialog.qml:24
61msgid "This connection is untrusted"65msgid "This connection is untrusted"
62msgstr ""66msgstr ""
@@ -85,6 +89,10 @@
85msgid "Forward"89msgid "Forward"
86msgstr ""90msgstr ""
8791
92#: src/app/Chrome.qml:127 src/app/webbrowser/ActivityView.qml:36
93msgid "Activity"
94msgstr ""
95
88#: src/app/ConfirmDialog.qml:2496#: src/app/ConfirmDialog.qml:24
89msgid "JavaScript Confirmation"97msgid "JavaScript Confirmation"
90msgstr ""98msgstr ""
@@ -134,52 +142,6 @@
134msgid "The website %1:%2 requires authentication."142msgid "The website %1:%2 requires authentication."
135msgstr ""143msgstr ""
136144
137#. TRANSLATORS: %1 refers to the number of open tabs
138#: src/app/TabsList.qml:37
139#, qt-format
140msgid "Currently viewing (%1)"
141msgstr ""
142
143#: src/app/TabsList.qml:68
144msgid "+"
145msgstr ""
146
147#: src/app/TimelineView.qml:83
148msgid "Today"
149msgstr ""
150
151#: src/app/TimelineView.qml:85
152msgid "Yesterday"
153msgstr ""
154
155#: src/app/TimelineView.qml:87
156msgid "Last 7 Days"
157msgstr ""
158
159#: src/app/TimelineView.qml:89
160msgid "This Month"
161msgstr ""
162
163#: src/app/TimelineView.qml:91
164msgid "This Year"
165msgstr ""
166
167#: src/app/TimelineView.qml:93
168msgid "Older"
169msgstr ""
170
171#: src/app/TimelineView.qml:276
172msgid "(local files)"
173msgstr ""
174
175#: src/app/TimelineView.qml:278
176msgid "(other)"
177msgstr ""
178
179#: src/app/WebViewImpl.qml:52
180msgid "This page wants to know your device’s location."
181msgstr ""
182
183#. TRANSLATORS: This is a free-form list of keywords associated to the 'Back' action.145#. TRANSLATORS: This is a free-form list of keywords associated to the 'Back' action.
184#. Keywords may actually be sentences, and must be separated by semi-colons.146#. Keywords may actually be sentences, and must be separated by semi-colons.
185#: src/app/actions/Back.qml:26147#: src/app/actions/Back.qml:26
@@ -266,24 +228,88 @@
266msgid "Leave Page"228msgid "Leave Page"
267msgstr ""229msgstr ""
268230
231#: src/app/webbrowser/ActivityView.qml:54
232msgid "Bookmarks"
233msgstr ""
234
235#. TRANSLATORS: %1 refers to the number of open tabs
236#: src/app/webbrowser/TabsList.qml:37
237#, qt-format
238msgid "Currently viewing (%1)"
239msgstr ""
240
241#: src/app/webbrowser/TabsList.qml:68
242msgid "+"
243msgstr ""
244
245#: src/app/webbrowser/TimelineView.qml:84
246msgid "Today"
247msgstr ""
248
249#: src/app/webbrowser/TimelineView.qml:86
250msgid "Yesterday"
251msgstr ""
252
253#: src/app/webbrowser/TimelineView.qml:88
254msgid "Last 7 Days"
255msgstr ""
256
257#: src/app/webbrowser/TimelineView.qml:90
258msgid "This Month"
259msgstr ""
260
261#: src/app/webbrowser/TimelineView.qml:92
262msgid "This Year"
263msgstr ""
264
265#: src/app/webbrowser/TimelineView.qml:94
266msgid "Older"
267msgstr ""
268
269#: src/app/webbrowser/TimelineView.qml:277
270msgid "(local files)"
271msgstr ""
272
273#: src/app/webbrowser/TimelineView.qml:279
274msgid "(other)"
275msgstr ""
276
277#: src/app/webbrowser/webbrowser-app.desktop.in:3
278msgid "Browser"
279msgstr ""
280
281#: src/app/webbrowser/webbrowser-app.desktop.in:4
282msgid "Web Browser"
283msgstr ""
284
285#: src/app/webbrowser/webbrowser-app.desktop.in:5
286msgid "Browse the World Wide Web"
287msgstr ""
288
269#. TRANSLATORS: %1 refers to the current page’s title289#. TRANSLATORS: %1 refers to the current page’s title
270#: src/app/webapp-container.qml:44 src/app/webbrowser-app.qml:35290#: src/app/webbrowser/webbrowser-app.qml:35
291#: src/app/webcontainer/webapp-container.qml:44
271#, qt-format292#, qt-format
272msgid "%1 - Ubuntu Web Browser"293msgid "%1 - Ubuntu Web Browser"
273msgstr ""294msgstr ""
274295
275#: src/app/webapp-container.qml:46 src/app/webbrowser-app.qml:37296#: src/app/webbrowser/webbrowser-app.qml:37
297#: src/app/webcontainer/webapp-container.qml:46
276msgid "Ubuntu Web Browser"298msgid "Ubuntu Web Browser"
277msgstr ""299msgstr ""
278300
279#: src/app/webbrowser-app.desktop.in:3301#: src/app/webcontainer/AccountsLoginPage.qml:70
280msgid "Browser"302msgid "No local account found for "
281msgstr ""303msgstr ""
282304
283#: src/app/webbrowser-app.desktop.in:4305#: src/app/webcontainer/AccountsLoginPage.qml:75
284msgid "Web Browser"306msgid "Skip account creation step"
285msgstr ""307msgstr ""
286308
287#: src/app/webbrowser-app.desktop.in:5309#: src/app/webcontainer/AccountsLoginPage.qml:124
288msgid "Browse the World Wide Web"310msgid "Add account"
311msgstr ""
312
313#: src/app/webcontainer/AccountsView.qml:38
314msgid "Select an account"
289msgstr ""315msgstr ""
290316
=== modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt'
--- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-03-13 07:33:10 +0000
+++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-03-28 17:03:06 +0000
@@ -13,7 +13,7 @@
1313
14add_library(${PLUGIN} MODULE ${PLUGIN_SRC})14add_library(${PLUGIN} MODULE ${PLUGIN_SRC})
1515
16qt5_use_modules(${PLUGIN} Core Qml)16qt5_use_modules(${PLUGIN} Core Gui Qml)
1717
18file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)18file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
19install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR})19install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR})
2020
=== added file 'src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml'
--- src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/ItemSelector01.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,63 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import Ubuntu.Components 0.1
21import Ubuntu.Components.ListItems 0.1 as ListItem
22import Ubuntu.Components.Popups 0.1
23
24Popover {
25 id: itemSelector
26
27 property QtObject selectorModel: model
28
29 caller: parent
30 contentWidth: Math.min(parent.width - units.gu(10), units.gu(40))
31 property real listContentHeight: 0 // intermediate property to avoid binding loop
32 contentHeight: Math.min(parent.height - units.gu(10), listContentHeight)
33
34 ListView {
35 clip: true
36 width: itemSelector.contentWidth
37 height: itemSelector.contentHeight
38
39 model: selectorModel.items
40
41 delegate: ListItem.Standard {
42 text: model.text
43 enabled: model.enabled
44 selected: model.selected
45 onClicked: selectorModel.accept(model.index)
46 }
47
48 section.property: "group"
49 section.delegate: ListItem.Header {
50 text: section
51 }
52
53 onContentHeightChanged: itemSelector.listContentHeight = contentHeight
54 }
55
56 Component.onCompleted: show()
57
58 onVisibleChanged: {
59 if (!visible) {
60 selectorModel.reject()
61 }
62 }
63}
064
=== renamed file 'src/Ubuntu/Components/Extras/Browser/ItemSelector.qml' => 'src/Ubuntu/Components/Extras/Browser/ItemSelector02.qml'
--- src/Ubuntu/Components/Extras/Browser/ItemSelector.qml 2013-03-21 16:44:04 +0000
+++ src/Ubuntu/Components/Extras/Browser/ItemSelector02.qml 2014-03-28 17:03:06 +0000
@@ -42,7 +42,10 @@
42 text: model.text42 text: model.text
43 enabled: model.enabled43 enabled: model.enabled
44 selected: model.selected44 selected: model.selected
45 onClicked: selectorModel.accept(model.index)45 onClicked: {
46 selectorModel.items.select(model.index)
47 selectorModel.accept()
48 }
46 }49 }
4750
48 section.property: "group"51 section.property: "group"
@@ -57,7 +60,7 @@
5760
58 onVisibleChanged: {61 onVisibleChanged: {
59 if (!visible) {62 if (!visible) {
60 selectorModel.reject()63 selectorModel.cancel()
61 }64 }
62 }65 }
63}66}
6467
=== added file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml'
--- src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebContext.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19pragma Singleton
20
21import QtQuick 2.0
22import com.canonical.Oxide 0.1
23
24Item {
25 property string customUA: userAgent.defaultUA
26
27 property QtObject sharedContext: WebContext {
28 dataPath: dataLocation
29 userAgent: customUA
30 networkRequestDelegate: uaOverrideWorker.item
31 userAgentOverrideDelegate: networkRequestDelegate
32 userScripts: [
33 UserScript {
34 context: "oxide://selection/"
35 url: Qt.resolvedUrl("selection02.js")
36 incognitoEnabled: true
37 matchAllFrames: true
38 }
39 ]
40 }
41
42 Component {
43 id: uaOverrideWorkerComponent
44
45 WebContextDelegateWorker {
46 source: Qt.resolvedUrl("ua-override-worker.js")
47 onMessage: console.log("Overriden UA for", message.url, ":", message.override)
48 }
49 }
50 Loader {
51 id: uaOverrideWorker
52 sourceComponent: (formFactor === "mobile") ? uaOverrideWorkerComponent : undefined
53 }
54
55 UserAgent02 {
56 id: userAgent
57 }
58}
059
=== added file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml'
--- src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebView01.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,272 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtWebKit 3.1
21import QtWebKit.experimental 1.0
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Extras.Browser 0.1
24import Ubuntu.Components.Popups 0.1
25
26/*!
27 \qmltype MainView
28 \inqmlmodule Ubuntu.Components.Extras.Browser 0.1
29 \obsolete
30 \brief Custom Ubuntu WebView extending QtWebKit’s WebView
31
32 This version of UbuntuWebView is deprecated and shouldn’t be used in new
33 code. Use version 0.2 or higher instead.
34*/
35WebView {
36 id: _webview
37
38 signal newTabRequested(url url)
39
40 QtObject {
41 property real devicePixelRatio: QtWebKitDPR
42 onDevicePixelRatioChanged: {
43 // Do not make this patch to QtWebKit a hard requirement.
44 if (_webview.experimental.hasOwnProperty('devicePixelRatio')) {
45 _webview.experimental.devicePixelRatio = devicePixelRatio
46 }
47 }
48 }
49
50 interactive: !selection.visible
51 maximumFlickVelocity: height * 5
52
53 /**
54 * Client overridable function called before the default treatment of a
55 * valid navigation request. This function can stop the navigation request
56 * if it sets the 'action' field of the request to IgnoreRequest.
57 *
58 */
59 function navigationRequestedDelegate(request) { }
60
61 UserAgent01 {
62 id: userAgent
63 }
64
65 /**
66 * This function can be overridden by client applications that embed an
67 * UbuntuWebView to provide a static overridden UA string.
68 * If not overridden, the default UA string and the default override
69 * mechanism will be used.
70 */
71 function getUAString() {
72 // Note that this function used to accept a 'url' parameter to allow
73 // embedders to implement a custom override mechanism. It was removed
74 // after observing that no application was using it, and to simplify
75 // the API. Embedders willing to provide a custom override mechanism
76 // can always override (at their own risk) the onNavigationRequested
77 // slot.
78 return undefined
79 }
80 experimental.userAgent: (_webview.getUAString() === undefined) ? userAgent.defaultUA : _webview.getUAString()
81 onNavigationRequested: {
82 request.action = WebView.AcceptRequest;
83
84 navigationRequestedDelegate (request);
85 if (request.action === WebView.IgnoreRequest)
86 return;
87
88 var staticUA = _webview.getUAString()
89 if (staticUA === undefined) {
90 _webview.experimental.userAgent = userAgent.getUAString(request.url)
91 } else {
92 _webview.experimental.userAgent = staticUA
93 }
94 }
95
96 experimental.preferences.navigatorQtObjectEnabled: true
97 experimental.userScripts: [Qt.resolvedUrl("hyperlinks.js"),
98 Qt.resolvedUrl("selection01.js")]
99 experimental.onMessageReceived: {
100 var data = null
101 try {
102 data = JSON.parse(message.data)
103 } catch (error) {
104 console.debug('DEBUG:', message.data)
105 return
106 }
107 if ('event' in data) {
108 if (data.event === 'longpress') {
109 if (('img' in data) || ('href' in data)) {
110 contextualData.clear()
111 if ('img' in data) {
112 contextualData.img = data.img
113 }
114 if ('href' in data) {
115 contextualData.href = data.href
116 contextualData.title = data.title
117 }
118 contextualRectangle.position(data)
119 PopupUtils.open(contextualPopover, contextualRectangle)
120 return
121 }
122 }
123 if ((data.event === 'longpress') || (data.event === 'selectionadjusted')) {
124 selection.clearData()
125 selection.createData()
126 if ('html' in data) {
127 selection.mimedata.html = data.html
128 }
129 // FIXME: push the text and image data in the order
130 // they appear in the selected block.
131 if ('text' in data) {
132 selection.mimedata.text = data.text
133 }
134 if ('images' in data) {
135 // TODO: download and cache the images locally
136 // (grab them from the webview’s cache, if possible),
137 // and forward local URLs.
138 selection.mimedata.urls = data.images
139 }
140 selection.show(data.left, data.top, data.width, data.height)
141 } else if (data.event === 'newtab') {
142 newTabRequested(data.url)
143 }
144 }
145 }
146
147 experimental.itemSelector: ItemSelector01 {}
148
149 property alias selection: selection
150 property ActionList selectionActions
151 Selection {
152 id: selection
153
154 anchors.fill: parent
155 visible: false
156
157 property Item __popover: null
158 property var mimedata: null
159
160 Component {
161 id: selectionPopover
162 ActionSelectionPopover {
163 grabDismissAreaEvents: false
164 actions: selectionActions
165 }
166 }
167
168 function createData() {
169 if (mimedata === null) {
170 mimedata = Clipboard.newData()
171 }
172 }
173
174 function clearData() {
175 if (mimedata !== null) {
176 delete mimedata
177 mimedata = null
178 }
179 }
180
181 function actionTriggered() {
182 selection.visible = false
183 }
184
185 function __showPopover() {
186 __popover = PopupUtils.open(selectionPopover, selection.rect)
187 var actions = __popover.actions.actions
188 for (var i in actions) {
189 actions[i].onTriggered.connect(actionTriggered)
190 }
191 }
192
193 function show(x, y, width, height) {
194 var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
195 rect.x = x * scale + _webview.contentX
196 rect.y = y * scale + _webview.contentY
197 rect.width = width * scale
198 rect.height = height * scale
199 visible = true
200 __showPopover()
201 }
202
203 onVisibleChanged: {
204 if (!visible && (__popover != null)) {
205 PopupUtils.close(__popover)
206 __popover = null
207 }
208 }
209
210 onResized: {
211 var message = new Object
212 message.query = 'adjustselection'
213 var rect = selection.rect
214 var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
215 message.left = (rect.x - _webview.contentX) / scale
216 message.right = (rect.x + rect.width - _webview.contentX) / scale
217 message.top = (rect.y - _webview.contentY) / scale
218 message.bottom = (rect.y + rect.height - _webview.contentY) / scale
219 _webview.experimental.postMessage(JSON.stringify(message))
220 }
221
222 function copy() {
223 Clipboard.push(mimedata)
224 clearData()
225 }
226 }
227
228 Item {
229 id: contextualRectangle
230
231 visible: false
232
233 function position(data) {
234 var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio
235 x = data.left * scale
236 y = data.top * scale
237 width = data.width * scale
238 height = data.height * scale
239 }
240 }
241 property QtObject contextualData: QtObject {
242 property url href
243 property string title
244 property url img
245
246 function clear() {
247 href = ''
248 title = ''
249 img = ''
250 }
251 }
252
253 property ActionList contextualActions
254 Component {
255 id: contextualPopover
256 ActionSelectionPopover {
257 actions: contextualActions
258 }
259 }
260
261 Scrollbar {
262 parent: _webview.parent
263 flickableItem: _webview
264 align: Qt.AlignTrailing
265 }
266
267 Scrollbar {
268 parent: _webview.parent
269 flickableItem: _webview
270 align: Qt.AlignBottom
271 }
272}
0273
=== renamed file 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml' => 'src/Ubuntu/Components/Extras/Browser/UbuntuWebView02.qml'
--- src/Ubuntu/Components/Extras/Browser/UbuntuWebView.qml 2014-03-14 17:33:23 +0000
+++ src/Ubuntu/Components/Extras/Browser/UbuntuWebView02.qml 2014-03-28 17:03:06 +0000
@@ -17,29 +17,18 @@
17 */17 */
1818
19import QtQuick 2.019import QtQuick 2.0
20import QtWebKit 3.120import QtQuick.Window 2.0
21import QtWebKit.experimental 1.021import com.canonical.Oxide 0.1
22import Ubuntu.Components 0.122import Ubuntu.Components 0.1
23import Ubuntu.Components.Extras.Browser 0.1
24import Ubuntu.Components.Popups 0.123import Ubuntu.Components.Popups 0.1
24import "."
2525
26WebView {26WebView {
27 id: _webview27 id: _webview
2828
29 signal newTabRequested(url url)29 signal newTabRequested(url url)
3030
31 QtObject {31 //interactive: !selection.visible
32 property real devicePixelRatio: QtWebKitDPR
33 onDevicePixelRatioChanged: {
34 // Do not make this patch to QtWebKit a hard requirement.
35 if (_webview.experimental.hasOwnProperty('devicePixelRatio')) {
36 _webview.experimental.devicePixelRatio = devicePixelRatio
37 }
38 }
39 }
40
41 interactive: !selection.visible
42 maximumFlickVelocity: height * 5
4332
44 /**33 /**
45 * Client overridable function called before the default treatment of a34 * Client overridable function called before the default treatment of a
@@ -49,27 +38,65 @@
49 */38 */
50 function navigationRequestedDelegate(request) { }39 function navigationRequestedDelegate(request) { }
5140
52 UserAgent {
53 id: userAgent
54 }
55
56 /**41 /**
57 * This function can be overridden by client applications that embed an42 * This function can be overridden by client applications that embed an
58 * UbuntuWebView to provide a static overridden UA string.43 * UbuntuWebView to provide a static overridden UA string.
59 * If not overridden, the default UA string and the default override44 * If not overridden, the default UA string and the default override
60 * mechanism will be used.45 * mechanism will be used.
46 *
47 * Note: as the UA string is a property of the shared context,
48 * an application that embeds several UbuntuWebViews that define different
49 * custom UA strings will result in the last view instantiated setting the
50 * UA for all the views.
61 */51 */
62 function getUAString() {52 function getUAString() {
63 // Note that this function used to accept a 'url' parameter to allow
64 // embedders to implement a custom override mechanism. It was removed
65 // after observing that no application was using it, and to simplify
66 // the API. Embedders willing to provide a custom override mechanism
67 // can always override (at their own risk) the onNavigationRequested
68 // slot.
69 return undefined53 return undefined
70 }54 }
71 experimental.userAgent: (_webview.getUAString() === undefined) ? userAgent.defaultUA : _webview.getUAString()55
72 onNavigationRequested: {56 context: UbuntuWebContext.sharedContext
57 Component.onCompleted: {
58 var customUA = getUAString()
59 if (customUA !== undefined) {
60 UbuntuWebContext.customUA = customUA
61 }
62 }
63
64 messageHandlers: [
65 ScriptMessageHandler {
66 msgId: "contextmenu"
67 contexts: ["oxide://selection/"]
68 callback: function(msg, frame) {
69 if (('img' in msg.args) || ('href' in msg.args)) {
70 if (internal.currentContextualMenu != null) {
71 PopupUtils.close(internal.currentContextualMenu)
72 }
73 contextualData.clear()
74 if ('img' in msg.args) {
75 contextualData.img = msg.args.img
76 }
77 if ('href' in msg.args) {
78 contextualData.href = msg.args.href
79 contextualData.title = msg.args.title
80 }
81 contextualRectangle.position(msg.args)
82 internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle)
83 } else if (internal.currentContextualMenu != null) {
84 PopupUtils.close(internal.currentContextualMenu)
85 }
86 }
87 },
88 ScriptMessageHandler {
89 msgId: "scroll"
90 contexts: ["oxide://selection/"]
91 callback: function(msg, frame) {
92 if (internal.currentContextualMenu != null) {
93 PopupUtils.close(internal.currentContextualMenu)
94 }
95 }
96 }
97 ]
98
99 /*onNavigationRequested: {
73 request.action = WebView.AcceptRequest;100 request.action = WebView.AcceptRequest;
74101
75 navigationRequestedDelegate (request);102 navigationRequestedDelegate (request);
@@ -82,9 +109,9 @@
82 } else {109 } else {
83 _webview.experimental.userAgent = staticUA110 _webview.experimental.userAgent = staticUA
84 }111 }
85 }112 }*/
86113
87 experimental.preferences.navigatorQtObjectEnabled: true114 /*experimental.preferences.navigatorQtObjectEnabled: true
88 experimental.userScripts: [Qt.resolvedUrl("hyperlinks.js"),115 experimental.userScripts: [Qt.resolvedUrl("hyperlinks.js"),
89 Qt.resolvedUrl("selection.js")]116 Qt.resolvedUrl("selection.js")]
90 experimental.onMessageReceived: {117 experimental.onMessageReceived: {
@@ -133,11 +160,11 @@
133 newTabRequested(data.url)160 newTabRequested(data.url)
134 }161 }
135 }162 }
136 }163 }*/
137164
138 experimental.itemSelector: ItemSelector {}165 popupMenu: ItemSelector02 {}
139166
140 property alias selection: selection167 /*property alias selection: selection
141 property ActionList selectionActions168 property ActionList selectionActions
142 Selection {169 Selection {
143 id: selection170 id: selection
@@ -214,7 +241,7 @@
214 Clipboard.push(mimedata)241 Clipboard.push(mimedata)
215 clearData()242 clearData()
216 }243 }
217 }244 }*/
218245
219 Item {246 Item {
220 id: contextualRectangle247 id: contextualRectangle
@@ -222,11 +249,10 @@
222 visible: false249 visible: false
223250
224 function position(data) {251 function position(data) {
225 var scale = _webview.experimental.test.contentsScale * _webview.experimental.test.devicePixelRatio252 x = data.left * data.scaleX
226 x = data.left * scale253 y = data.top * data.scaleY
227 y = data.top * scale254 width = data.width * data.scaleX
228 width = data.width * scale255 height = data.height * data.scaleY
229 height = data.height * scale
230 }256 }
231 }257 }
232 property QtObject contextualData: QtObject {258 property QtObject contextualData: QtObject {
@@ -249,15 +275,25 @@
249 }275 }
250 }276 }
251277
252 Scrollbar {278 QtObject {
253 parent: _webview.parent279 id: internal
254 flickableItem: _webview280 property int lastLoadRequestStatus: -1
255 align: Qt.AlignTrailing281 property Item currentContextualMenu: null
256 }282 }
257283
258 Scrollbar {284 readonly property bool lastLoadSucceeded: internal.lastLoadRequestStatus === LoadEvent.TypeSucceeded
259 parent: _webview.parent285 readonly property bool lastLoadStopped: internal.lastLoadRequestStatus === LoadEvent.TypeStopped
260 flickableItem: _webview286 readonly property bool lastLoadFailed: internal.lastLoadRequestStatus === LoadEvent.TypeFailed
261 align: Qt.AlignBottom287 onLoadingChanged: {
288 if (loadEvent.url.toString() !== "data:text/html,chromewebdata") {
289 internal.lastLoadRequestStatus = loadEvent.type
290 }
291 }
292
293 readonly property int screenOrientation: Screen.orientation
294 onScreenOrientationChanged: {
295 if (internal.currentContextualMenu != null) {
296 PopupUtils.close(internal.currentContextualMenu)
297 }
262 }298 }
263}299}
264300
=== added file 'src/Ubuntu/Components/Extras/Browser/UserAgent01.qml'
--- src/Ubuntu/Components/Extras/Browser/UserAgent01.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/UserAgent01.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,90 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtQuick.Window 2.0
21import Ubuntu.Components 0.1
22import "ua-overrides.js" as Overrides
23
24/*
25 * Useful documentation:
26 * http://en.wikipedia.org/wiki/User_agent#Format
27 * https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
28 * https://wiki.mozilla.org/B2G/User_Agent
29 * https://github.com/mozilla-b2g/gaia/blob/master/build/ua-override-prefs.js
30 * https://developers.google.com/chrome/mobile/docs/user-agent
31 */
32
33// This is an Item, not a QtObject, because it needs information about the Screen.
34Item {
35 // %1: form factor (Mobile, Tablet, Desktop)
36 // %2: WebKit version
37 readonly property string _template: "Mozilla/5.0 (Ubuntu; %1) WebKit/%2"
38
39 // See Source/WebCore/Configurations/Version.xcconfig in QtWebKit’s source tree
40 // TODO: determine this value at runtime
41 readonly property string _webkitVersion: "537.21"
42
43 // FIXME: this is a quick hack that will become increasingly unreliable
44 // as we support more devices, so we need a better solution for this
45 // FIXME: only handling phone and tablet for now, need to handle desktop too
46 readonly property string _formFactor: (Screen.width >= units.gu(60)) ? "Tablet" : "Mobile"
47
48 property string defaultUA: _template.arg(_formFactor).arg(_webkitVersion)
49
50 property var overrides: Overrides.overrides
51
52 function getDomain(url) {
53 var domain = url.toString()
54 var indexOfScheme = domain.indexOf("://")
55 if (indexOfScheme !== -1) {
56 domain = domain.slice(indexOfScheme + 3)
57 }
58 var indexOfPath = domain.indexOf("/")
59 if (indexOfPath !== -1) {
60 domain = domain.slice(0, indexOfPath)
61 }
62 return domain
63 }
64
65 function getDomains(domain) {
66 var components = domain.split(".")
67 var domains = []
68 for (var i = 0; i < components.length; i++) {
69 domains.push(components.slice(i).join("."))
70 }
71 return domains
72 }
73
74 function getUAString(url) {
75 var ua = defaultUA
76 var domains = getDomains(getDomain(url))
77 for (var i = 0; i < domains.length; i++) {
78 var domain = domains[i]
79 if (domain in overrides) {
80 var form = overrides[domain]
81 if (typeof form == "string") {
82 return form
83 } else if (typeof form == "object") {
84 return ua.replace(form[0], form[1])
85 }
86 }
87 }
88 return ua
89 }
90}
091
=== renamed file 'src/Ubuntu/Components/Extras/Browser/UserAgent.qml' => 'src/Ubuntu/Components/Extras/Browser/UserAgent02.qml'
--- src/Ubuntu/Components/Extras/Browser/UserAgent.qml 2013-09-25 16:38:06 +0000
+++ src/Ubuntu/Components/Extras/Browser/UserAgent02.qml 2014-03-28 17:03:06 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2014 Canonical Ltd.
3 *3 *
4 * This file is part of webbrowser-app.4 * This file is part of webbrowser-app.
5 *5 *
@@ -16,10 +16,7 @@
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */17 */
1818
19import QtQuick 2.019import QtQml 2.0
20import QtQuick.Window 2.0
21import Ubuntu.Components 0.1
22import "ua-overrides.js" as Overrides
2320
24/*21/*
25 * Useful documentation:22 * Useful documentation:
@@ -30,61 +27,36 @@
30 * https://developers.google.com/chrome/mobile/docs/user-agent27 * https://developers.google.com/chrome/mobile/docs/user-agent
31 */28 */
3229
33// This is an Item, not a QtObject, because it needs information about the Screen.30QtObject {
34Item {31 // %1: Ubuntu version, e.g. "14.04"
35 // %1: form factor (Mobile, Tablet, Desktop)32 // %2: optional token to specify further attributes of the platform (must start with a whitespace), e.g. "like Android"
36 // %2: WebKit version33 // %3: optional hardware ID token (must start with a semi-colon if present)
37 readonly property string _template: "Mozilla/5.0 (Ubuntu; %1) WebKit/%2"34 // %4: WebKit version, e.g. "537.36"
3835 // %5: Chromium version, e.g. "35.0.1870.2"
39 // See Source/WebCore/Configurations/Version.xcconfig in QtWebKit’s source tree36 // %6: optional token to provide additional free-form information (must start with a whitespace), e.g. "Mobile"
40 // TODO: determine this value at runtime37 // note #1: "Mozilla/5.0" is misinformation, but it is a legacy token that
41 readonly property string _webkitVersion: "537.21"38 // virtually every single UA out there has, it seems unwise to remove it
4239 // note #2: "AppleWebKit", as opposed to plain "WebKit", does make a
43 // FIXME: this is a quick hack that will become increasingly unreliable40 // difference in the content served by certain sites (e.g. gmail.com)
44 // as we support more devices, so we need a better solution for this41 readonly property string _template: "Mozilla/5.0 (Linux; Ubuntu %1%2%3) AppleWebKit/%4 Chromium/%5%6"
45 // FIXME: only handling phone and tablet for now, need to handle desktop too42
46 readonly property string _formFactor: (Screen.width >= units.gu(60)) ? "Tablet" : "Mobile"43 // FIXME: compute at build time (using lsb_release)
4744 readonly property string _ubuntuVersion: "14.04"
48 property string defaultUA: _template.arg(_formFactor).arg(_webkitVersion)45
4946 readonly property string _attributes: (formFactor === "mobile") ? " like Android 4.4" : ""
50 property var overrides: Overrides.overrides47
5148 readonly property string _hardwareID: ""
52 function getDomain(url) {49
53 var domain = url.toString()50 // See chromium/src/webkit/build/webkit_version.h.in in oxide’s source tree.
54 var indexOfScheme = domain.indexOf("://")51 readonly property string _webkitVersion: "537.36"
55 if (indexOfScheme !== -1) {52
56 domain = domain.slice(indexOfScheme + 3)53 // See chromium/src/chrome/VERSION in oxide’s source tree.
57 }54 // Note: the actual version number probably doesn’t matter that much,
58 var indexOfPath = domain.indexOf("/")55 // however its format does, so we probably don’t need to bump it
59 if (indexOfPath !== -1) {56 // every time we rebase on a newer chromium.
60 domain = domain.slice(0, indexOfPath)57 readonly property string _chromiumVersion: "35.0.1870.2"
61 }58
62 return domain59 readonly property string _more: (formFactor === "mobile") ? " Mobile" : ""
63 }60
6461 property string defaultUA: _template.arg(_ubuntuVersion).arg(_attributes).arg(_hardwareID).arg(_webkitVersion).arg(_chromiumVersion).arg(_more)
65 function getDomains(domain) {
66 var components = domain.split(".")
67 var domains = []
68 for (var i = 0; i < components.length; i++) {
69 domains.push(components.slice(i).join("."))
70 }
71 return domains
72 }
73
74 function getUAString(url) {
75 var ua = defaultUA
76 var domains = getDomains(getDomain(url))
77 for (var i = 0; i < domains.length; i++) {
78 var domain = domains[i]
79 if (domain in overrides) {
80 var form = overrides[domain]
81 if (typeof form == "string") {
82 return form
83 } else if (typeof form == "object") {
84 return ua.replace(form[0], form[1])
85 }
86 }
87 }
88 return ua
89 }
90}62}
9163
=== added file 'src/Ubuntu/Components/Extras/Browser/dummysingleton.qml'
--- src/Ubuntu/Components/Extras/Browser/dummysingleton.qml 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/dummysingleton.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,27 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19// This file is not really used, but without it importing version 0.1 of
20// Ubuntu.Components.Extras.Browser fails because the QML engine requests type
21// UbuntuWebContext, despite it being specific to version 0.2 of the module.
22
23pragma Singleton
24
25import QtQml 2.0
26
27QtObject {}
028
=== modified file 'src/Ubuntu/Components/Extras/Browser/plugin.cpp'
--- src/Ubuntu/Components/Extras/Browser/plugin.cpp 2014-03-12 17:48:34 +0000
+++ src/Ubuntu/Components/Extras/Browser/plugin.cpp 2014-03-28 17:03:06 +0000
@@ -21,6 +21,8 @@
21// Qt21// Qt
22#include <QtCore/QDir>22#include <QtCore/QDir>
23#include <QtCore/QStandardPaths>23#include <QtCore/QStandardPaths>
24#include <QtCore/QtGlobal>
25#include <QtGui/QGuiApplication>
24#include <QtQml>26#include <QtQml>
2527
26static float getQtWebkitDpr()28static float getQtWebkitDpr()
@@ -31,6 +33,36 @@
31 return ok ? value : 1.0;33 return ok ? value : 1.0;
32}34}
3335
36static QString getFormFactor()
37{
38 // This implementation only considers two possible form factors: desktop,
39 // and mobile (which includes phones and tablets).
40 // XXX: do we need to consider other form factors, such as tablet?
41 const char* DESKTOP = "desktop";
42 const char* MOBILE = "mobile";
43
44 // The "DESKTOP_MODE" environment variable can be used to force the form
45 // factor to desktop, when set to any valid value other than 0.
46 const char* DESKTOP_MODE_ENV_VAR = "DESKTOP_MODE";
47 if (qEnvironmentVariableIsSet(DESKTOP_MODE_ENV_VAR)) {
48 QByteArray stringValue = qgetenv(DESKTOP_MODE_ENV_VAR);
49 bool ok = false;
50 int value = stringValue.toInt(&ok);
51 if (ok) {
52 return (value == 0) ? MOBILE : DESKTOP;
53 }
54 }
55
56 // XXX: Assume that QtUbuntu means mobile, which is currently the case,
57 // but may not remain true forever.
58 QString platform = QGuiApplication::platformName();
59 if ((platform == "ubuntu") || (platform == "ubuntumirclient")) {
60 return MOBILE;
61 }
62
63 return DESKTOP;
64}
65
34void UbuntuBrowserPlugin::initializeEngine(QQmlEngine* engine, const char* uri)66void UbuntuBrowserPlugin::initializeEngine(QQmlEngine* engine, const char* uri)
35{67{
36 Q_UNUSED(uri);68 Q_UNUSED(uri);
@@ -45,6 +77,8 @@
45 // Set the desired pixel ratio (not needed once we use Qt’s way of77 // Set the desired pixel ratio (not needed once we use Qt’s way of
46 // calculating the proper pixel ratio by device/screen).78 // calculating the proper pixel ratio by device/screen).
47 context->setContextProperty("QtWebKitDPR", getQtWebkitDpr());79 context->setContextProperty("QtWebKitDPR", getQtWebkitDpr());
80
81 context->setContextProperty("formFactor", getFormFactor());
48}82}
4983
50void UbuntuBrowserPlugin::registerTypes(const char* uri)84void UbuntuBrowserPlugin::registerTypes(const char* uri)
5185
=== modified file 'src/Ubuntu/Components/Extras/Browser/qmldir'
--- src/Ubuntu/Components/Extras/Browser/qmldir 2014-03-12 15:27:10 +0000
+++ src/Ubuntu/Components/Extras/Browser/qmldir 2014-03-28 17:03:06 +0000
@@ -1,3 +1,7 @@
1module Ubuntu.Components.Extras.Browser1module Ubuntu.Components.Extras.Browser
2plugin ubuntu-ui-extras-browser-plugin2plugin ubuntu-ui-extras-browser-plugin
3UbuntuWebView 0.1 UbuntuWebView.qml3UbuntuWebView 0.1 UbuntuWebView01.qml
4UbuntuWebView 0.2 UbuntuWebView02.qml
5# Without the following line, importing version 0.1 of the module fails
6singleton UbuntuWebContext 0.1 dummysingleton.qml
7singleton UbuntuWebContext 0.2 UbuntuWebContext.qml
48
=== added file 'src/Ubuntu/Components/Extras/Browser/selection01.js'
--- src/Ubuntu/Components/Extras/Browser/selection01.js 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/selection01.js 2014-03-28 17:03:06 +0000
@@ -0,0 +1,193 @@
1/*
2 * Copyright 2013-2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19// List of domains known to interfere with touch events listeners
20var blacklist = [
21 "m.8tracks.com", // http://pad.lv/1279903
22];
23if (blacklist.indexOf(document.domain) === -1) {
24
25 function elementContainedInBox(element, box) {
26 var rect = element.getBoundingClientRect();
27 return ((box.left <= rect.left) && (box.right >= rect.right) &&
28 (box.top <= rect.top) && (box.bottom >= rect.bottom));
29 }
30
31 function getImgFullUri(uri) {
32 if ((uri.slice(0, 7) === 'http://') ||
33 (uri.slice(0, 8) === 'https://') ||
34 (uri.slice(0, 7) === 'file://')) {
35 return uri;
36 } else if (uri.slice(0, 1) === '/') {
37 var docuri = document.documentURI;
38 var firstcolon = docuri.indexOf('://');
39 var protocol = 'http://';
40 if (firstcolon !== -1) {
41 protocol = docuri.slice(0, firstcolon + 3);
42 }
43 return protocol + document.domain + uri;
44 } else {
45 var base = document.baseURI;
46 var lastslash = base.lastIndexOf('/');
47 if (lastslash === -1) {
48 return base + '/' + uri;
49 } else {
50 return base.slice(0, lastslash + 1) + uri;
51 }
52 }
53 }
54
55 function getSelectedData(element) {
56 var node = element;
57 var data = new Object;
58
59 var nodeName = node.nodeName.toLowerCase();
60 if (nodeName === 'img') {
61 data.img = getImgFullUri(node.getAttribute('src'));
62 } else if (nodeName === 'a') {
63 data.href = node.href;
64 data.title = node.title;
65 }
66
67 // If the parent tag is a hyperlink, we want it too.
68 var parent = node.parentNode;
69 if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {
70 data.href = parent.href;
71 data.title = parent.title;
72 node = parent;
73 }
74
75 var boundingRect = node.getBoundingClientRect();
76 data.left = boundingRect.left;
77 data.top = boundingRect.top;
78 data.width = boundingRect.width;
79 data.height = boundingRect.height;
80
81 node = node.cloneNode(true);
82 // filter out script nodes
83 var scripts = node.getElementsByTagName('script');
84 while (scripts.length > 0) {
85 var scriptNode = scripts[0];
86 if (scriptNode.parentNode) {
87 scriptNode.parentNode.removeChild(scriptNode);
88 }
89 }
90 data.html = node.outerHTML;
91 data.nodeName = node.nodeName.toLowerCase();
92 // FIXME: extract the text and images in the order they appear in the block,
93 // so that this order is respected when the data is pushed to the clipboard.
94 data.text = node.textContent;
95 var images = [];
96 var imgs = node.getElementsByTagName('img');
97 for (var i = 0; i < imgs.length; i++) {
98 images.push(getImgFullUri(imgs[i].getAttribute('src')));
99 }
100 if (images.length > 0) {
101 data.images = images;
102 }
103
104 return data;
105 }
106
107 function adjustSelection(selection) {
108 // FIXME: allow selecting two consecutive blocks, instead of
109 // interpolating to the containing block.
110 var centerX = (selection.left + selection.right) / 2;
111 var centerY = (selection.top + selection.bottom) / 2;
112 var element = document.elementFromPoint(centerX, centerY);
113 var parent = element;
114 while (elementContainedInBox(parent, selection)) {
115 parent = parent.parentNode;
116 }
117 element = parent;
118 return getSelectedData(element);
119 }
120
121 function distance(touch1, touch2) {
122 return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +
123 Math.pow(touch2.clientY - touch1.clientY, 2));
124 }
125
126 navigator.qt.onmessage = function(message) {
127 var data = null;
128 try {
129 data = JSON.parse(message.data);
130 } catch (error) {
131 return;
132 }
133 if ('query' in data) {
134 if (data.query === 'adjustselection') {
135 var selection = adjustSelection(data);
136 selection.event = 'selectionadjusted';
137 navigator.qt.postMessage(JSON.stringify(selection));
138 }
139 }
140 }
141
142 var longpressObserver = -1;
143 var currentTouch = null;
144 var longpressDetected = false;
145
146 function longPressDetected(x, y) {
147 longpressDetected = true;
148 var element = document.elementFromPoint(x, y);
149 var data = getSelectedData(element);
150 data.event = 'longpress';
151 navigator.qt.postMessage(JSON.stringify(data));
152 }
153
154 function clearLongpressTimeout() {
155 clearTimeout(longpressObserver);
156 longpressObserver = -1;
157 currentTouch = null;
158 }
159
160 var doc = document.documentElement;
161
162 doc.addEventListener('touchstart', function(event) {
163 if (event.touches.length == 1) {
164 currentTouch = event.touches[0];
165 longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY);
166 }
167 });
168
169 doc.addEventListener('touchend', function(event) {
170 if (longpressDetected) {
171 longpressDetected = false;
172 event.preventDefault();
173 }
174 clearLongpressTimeout();
175 });
176
177 doc.addEventListener('touchmove', function(event) {
178 if (!currentTouch) {
179 return;
180 }
181 if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) {
182 clearLongpressTimeout();
183 }
184 });
185
186 doc.addEventListener('touchcancel', function(event) {
187 if (longpressDetected) {
188 longpressDetected = false;
189 }
190 clearLongpressTimeout();
191 });
192
193}
0194
=== renamed file 'src/Ubuntu/Components/Extras/Browser/selection.js' => 'src/Ubuntu/Components/Extras/Browser/selection02.js'
--- src/Ubuntu/Components/Extras/Browser/selection.js 2014-02-19 15:53:33 +0000
+++ src/Ubuntu/Components/Extras/Browser/selection02.js 2014-03-28 17:03:06 +0000
@@ -16,178 +16,132 @@
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */17 */
1818
19// List of domains known to interfere with touch events listeners19function elementContainedInBox(element, box) {
20var blacklist = [20 var rect = element.getBoundingClientRect();
21 "m.8tracks.com", // http://pad.lv/127990321 return ((box.left <= rect.left) && (box.right >= rect.right) &&
22];22 (box.top <= rect.top) && (box.bottom >= rect.bottom));
23if (blacklist.indexOf(document.domain) === -1) {23}
2424
25 function elementContainedInBox(element, box) {25function getImgFullUri(uri) {
26 var rect = element.getBoundingClientRect();26 if ((uri.slice(0, 7) === 'http://') ||
27 return ((box.left <= rect.left) && (box.right >= rect.right) &&27 (uri.slice(0, 8) === 'https://') ||
28 (box.top <= rect.top) && (box.bottom >= rect.bottom));28 (uri.slice(0, 7) === 'file://')) {
29 }29 return uri;
3030 } else if (uri.slice(0, 1) === '/') {
31 function getImgFullUri(uri) {31 var docuri = document.documentURI;
32 if ((uri.slice(0, 7) === 'http://') ||32 var firstcolon = docuri.indexOf('://');
33 (uri.slice(0, 8) === 'https://') ||33 var protocol = 'http://';
34 (uri.slice(0, 7) === 'file://')) {34 if (firstcolon !== -1) {
35 return uri;35 protocol = docuri.slice(0, firstcolon + 3);
36 } else if (uri.slice(0, 1) === '/') {36 }
37 var docuri = document.documentURI;37 return protocol + document.domain + uri;
38 var firstcolon = docuri.indexOf('://');38 } else {
39 var protocol = 'http://';39 var base = document.baseURI;
40 if (firstcolon !== -1) {40 var lastslash = base.lastIndexOf('/');
41 protocol = docuri.slice(0, firstcolon + 3);41 if (lastslash === -1) {
42 }42 return base + '/' + uri;
43 return protocol + document.domain + uri;
44 } else {43 } else {
45 var base = document.baseURI;44 return base.slice(0, lastslash + 1) + uri;
46 var lastslash = base.lastIndexOf('/');45 }
47 if (lastslash === -1) {46 }
48 return base + '/' + uri;47}
49 } else {48
50 return base.slice(0, lastslash + 1) + uri;49function getSelectedData(element) {
51 }50 var node = element;
52 }51 var data = new Object;
53 }52
5453 var nodeName = node.nodeName.toLowerCase();
55 function getSelectedData(element) {54 if (nodeName === 'img') {
56 var node = element;55 data.img = getImgFullUri(node.getAttribute('src'));
57 var data = new Object;56 } else if (nodeName === 'a') {
5857 data.href = node.href;
59 var nodeName = node.nodeName.toLowerCase();58 data.title = node.title;
60 if (nodeName === 'img') {59 }
61 data.img = getImgFullUri(node.getAttribute('src'));60
62 } else if (nodeName === 'a') {61 // If the parent tag is a hyperlink, we want it too.
63 data.href = node.href;62 var parent = node.parentNode;
64 data.title = node.title;63 if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {
65 }64 data.href = parent.href;
6665 data.title = parent.title;
67 // If the parent tag is a hyperlink, we want it too.66 node = parent;
68 var parent = node.parentNode;67 }
69 if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) {68
70 data.href = parent.href;69 var boundingRect = node.getBoundingClientRect();
71 data.title = parent.title;70 data.left = boundingRect.left;
72 node = parent;71 data.top = boundingRect.top;
73 }72 data.width = boundingRect.width;
7473 data.height = boundingRect.height;
75 var boundingRect = node.getBoundingClientRect();74
76 data.left = boundingRect.left;75 node = node.cloneNode(true);
77 data.top = boundingRect.top;76 // filter out script nodes
78 data.width = boundingRect.width;77 var scripts = node.getElementsByTagName('script');
79 data.height = boundingRect.height;78 while (scripts.length > 0) {
8079 var scriptNode = scripts[0];
81 node = node.cloneNode(true);80 if (scriptNode.parentNode) {
82 // filter out script nodes81 scriptNode.parentNode.removeChild(scriptNode);
83 var scripts = node.getElementsByTagName('script');82 }
84 while (scripts.length > 0) {83 }
85 var scriptNode = scripts[0];84 data.html = node.outerHTML;
86 if (scriptNode.parentNode) {85 data.nodeName = node.nodeName.toLowerCase();
87 scriptNode.parentNode.removeChild(scriptNode);86 // FIXME: extract the text and images in the order they appear in the block,
88 }87 // so that this order is respected when the data is pushed to the clipboard.
89 }88 data.text = node.textContent;
90 data.html = node.outerHTML;89 var images = [];
91 data.nodeName = node.nodeName.toLowerCase();90 var imgs = node.getElementsByTagName('img');
92 // FIXME: extract the text and images in the order they appear in the block,91 for (var i = 0; i < imgs.length; i++) {
93 // so that this order is respected when the data is pushed to the clipboard.92 images.push(getImgFullUri(imgs[i].getAttribute('src')));
94 data.text = node.textContent;93 }
95 var images = [];94 if (images.length > 0) {
96 var imgs = node.getElementsByTagName('img');95 data.images = images;
97 for (var i = 0; i < imgs.length; i++) {96 }
98 images.push(getImgFullUri(imgs[i].getAttribute('src')));97
99 }98 return data;
100 if (images.length > 0) {99}
101 data.images = images;100
102 }101function adjustSelection(selection) {
103102 // FIXME: allow selecting two consecutive blocks, instead of
104 return data;103 // interpolating to the containing block.
105 }104 var centerX = (selection.left + selection.right) / 2;
106105 var centerY = (selection.top + selection.bottom) / 2;
107 function adjustSelection(selection) {106 var element = document.elementFromPoint(centerX, centerY);
108 // FIXME: allow selecting two consecutive blocks, instead of107 var parent = element;
109 // interpolating to the containing block.108 while (elementContainedInBox(parent, selection)) {
110 var centerX = (selection.left + selection.right) / 2;109 parent = parent.parentNode;
111 var centerY = (selection.top + selection.bottom) / 2;110 }
112 var element = document.elementFromPoint(centerX, centerY);111 element = parent;
113 var parent = element;112 return getSelectedData(element);
114 while (elementContainedInBox(parent, selection)) {113}
115 parent = parent.parentNode;114
116 }115function distance(touch1, touch2) {
117 element = parent;116 return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +
118 return getSelectedData(element);117 Math.pow(touch2.clientY - touch1.clientY, 2));
119 }118}
120119
121 function distance(touch1, touch2) {120/*navigator.qt.onmessage = function(message) {
122 return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) +121 var data = null;
123 Math.pow(touch2.clientY - touch1.clientY, 2));122 try {
124 }123 data = JSON.parse(message.data);
125124 } catch (error) {
126 navigator.qt.onmessage = function(message) {125 return;
127 var data = null;126 }
128 try {127 if ('query' in data) {
129 data = JSON.parse(message.data);128 if (data.query === 'adjustselection') {
130 } catch (error) {129 var selection = adjustSelection(data);
131 return;130 selection.event = 'selectionadjusted';
132 }131 navigator.qt.postMessage(JSON.stringify(selection));
133 if ('query' in data) {132 }
134 if (data.query === 'adjustselection') {133 }
135 var selection = adjustSelection(data);134}*/
136 selection.event = 'selectionadjusted';135
137 navigator.qt.postMessage(JSON.stringify(selection));136document.documentElement.addEventListener('contextmenu', function(event) {
138 }137 var element = document.elementFromPoint(event.clientX, event.clientY);
139 }138 var data = getSelectedData(element);
140 }139 var w = document.defaultView;
141140 data['scaleX'] = w.outerWidth / w.innerWidth * w.devicePixelRatio;
142 var longpressObserver = -1;141 data['scaleY'] = w.outerHeight / w.innerHeight * w.devicePixelRatio;
143 var currentTouch = null;142 oxide.sendMessage('contextmenu', data);
144 var longpressDetected = false;143});
145144
146 function longPressDetected(x, y) {145document.defaultView.addEventListener('scroll', function(event) {
147 longpressDetected = true;146 oxide.sendMessage('scroll', {});
148 var element = document.elementFromPoint(x, y);147});
149 var data = getSelectedData(element);
150 data.event = 'longpress';
151 navigator.qt.postMessage(JSON.stringify(data));
152 }
153
154 function clearLongpressTimeout() {
155 clearTimeout(longpressObserver);
156 longpressObserver = -1;
157 currentTouch = null;
158 }
159
160 var doc = document.documentElement;
161
162 doc.addEventListener('touchstart', function(event) {
163 if (event.touches.length == 1) {
164 currentTouch = event.touches[0];
165 longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY);
166 }
167 });
168
169 doc.addEventListener('touchend', function(event) {
170 if (longpressDetected) {
171 longpressDetected = false;
172 event.preventDefault();
173 }
174 clearLongpressTimeout();
175 });
176
177 doc.addEventListener('touchmove', function(event) {
178 if (!currentTouch) {
179 return;
180 }
181 if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) {
182 clearLongpressTimeout();
183 }
184 });
185
186 doc.addEventListener('touchcancel', function(event) {
187 if (longpressDetected) {
188 longpressDetected = false;
189 }
190 clearLongpressTimeout();
191 });
192
193}
194148
=== added file 'src/Ubuntu/Components/Extras/Browser/ua-override-worker.js'
--- src/Ubuntu/Components/Extras/Browser/ua-override-worker.js 1970-01-01 00:00:00 +0000
+++ src/Ubuntu/Components/Extras/Browser/ua-override-worker.js 2014-03-28 17:03:06 +0000
@@ -0,0 +1,46 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19var overrides = [
20 [/^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"]
21];
22
23function getUAoverride(url) {
24 for (var i = 0; i < overrides.length; i++) {
25 var override = overrides[i];
26 if (override[0].test(url)) {
27 return override[1];
28 }
29 }
30 return null;
31}
32
33exports.onBeforeSendHeaders = function(event) {
34 var override = getUAoverride(event.url);
35 if (override !== null) {
36 event.setHeader("User-Agent", override);
37 oxide.sendMessage({url: event.url, override: override});
38 }
39}
40
41exports.onGetUserAgentOverride = function(data) {
42 var override = getUAoverride(event.url);
43 if (override !== null) {
44 data.userAgentOverride = override;
45 }
46}
047
=== modified file 'src/app/AlertDialog.qml'
--- src/app/AlertDialog.qml 2013-09-21 19:56:15 +0000
+++ src/app/AlertDialog.qml 2014-03-28 17:03:06 +0000
@@ -26,8 +26,8 @@
2626
27 Button {27 Button {
28 text: i18n.tr("OK")28 text: i18n.tr("OK")
29 onClicked: model.dismiss()29 onClicked: model.accept()
30 }30 }
3131
32 Component.onCompleted: show()32 Component.onCompleted: show()
33}
34\ No newline at end of file33\ No newline at end of file
34}
3535
=== added file 'src/app/BeforeUnloadDialog.qml'
--- src/app/BeforeUnloadDialog.qml 1970-01-01 00:00:00 +0000
+++ src/app/BeforeUnloadDialog.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,38 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import Ubuntu.Components 0.1
21import Ubuntu.Components.Popups 0.1 as Popups
22
23Popups.Dialog {
24 title: i18n.tr("Confirm Navigation")
25 text: model.message
26
27 Button {
28 text: i18n.tr("Leave")
29 onClicked: model.accept()
30 }
31
32 Button {
33 text: i18n.tr("Stay")
34 onClicked: model.reject()
35 }
36
37 Component.onCompleted: show()
38}
039
=== modified file 'src/app/CMakeLists.txt'
--- src/app/CMakeLists.txt 2014-03-13 07:33:10 +0000
+++ src/app/CMakeLists.txt 2014-03-28 17:03:06 +0000
@@ -16,6 +16,8 @@
1616
17qt5_use_modules(${COMMONLIB} Core Network Qml Quick Widgets)17qt5_use_modules(${COMMONLIB} Core Network Qml Quick Widgets)
1818
19include_directories(${Qt5Quick_PRIVATE_INCLUDE_DIRS})
20
19file(GLOB QML_FILES *.qml)21file(GLOB QML_FILES *.qml)
20install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app)22install(FILES ${QML_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app)
21install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app23install(DIRECTORY actions DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app
2224
=== modified file 'src/app/PanelLoader.qml'
--- src/app/PanelLoader.qml 2013-11-15 17:04:27 +0000
+++ src/app/PanelLoader.qml 2014-03-28 17:03:06 +0000
@@ -75,7 +75,10 @@
7575
76 url: currentWebview ? currentWebview.url : ""76 url: currentWebview ? currentWebview.url : ""
7777
78 loading: currentWebview ? currentWebview.loading || (currentWebview.loadProgress === 0) : false78 loading: currentWebview ? currentWebview.loading
79 // workaround for https://bugs.launchpad.net/oxide/+bug/1290821
80 && !currentWebview.lastLoadStopped
81 : false
79 loadProgress: currentWebview ? currentWebview.loadProgress : 082 loadProgress: currentWebview ? currentWebview.loadProgress : 0
8083
81 canGoBack: currentWebview ? currentWebview.canGoBack : false84 canGoBack: currentWebview ? currentWebview.canGoBack : false
8285
=== modified file 'src/app/PromptDialog.qml'
--- src/app/PromptDialog.qml 2013-09-21 20:06:03 +0000
+++ src/app/PromptDialog.qml 2014-03-28 17:03:06 +0000
@@ -42,5 +42,11 @@
42 onClicked: model.reject()42 onClicked: model.reject()
43 }43 }
4444
45 Binding {
46 target: model
47 property: "currentValue"
48 value: input.text
49 }
50
45 Component.onCompleted: show()51 Component.onCompleted: show()
46}
47\ No newline at end of file52\ No newline at end of file
53}
4854
=== modified file 'src/app/WebViewImpl.qml'
--- src/app/WebViewImpl.qml 2014-03-13 10:16:20 +0000
+++ src/app/WebViewImpl.qml 2014-03-28 17:03:06 +0000
@@ -17,12 +17,10 @@
17 */17 */
1818
19import QtQuick 2.019import QtQuick 2.0
20import QtWebKit 3.120//import Ubuntu.Components 0.1
21import QtWebKit.experimental 1.021import Ubuntu.Components.Extras.Browser 0.2
22import Ubuntu.Components 0.122//import Ubuntu.Components.Popups 0.1
23import Ubuntu.Components.Extras.Browser 0.123//import "actions" as Actions
24import Ubuntu.Components.Popups 0.1
25import "actions" as Actions
2624
27UbuntuWebView {25UbuntuWebView {
28 id: webview26 id: webview
@@ -30,20 +28,21 @@
30 property var currentWebview: webview28 property var currentWebview: webview
31 property var toolbar: null29 property var toolbar: null
3230
33 experimental.certificateVerificationDialog: CertificateVerificationDialog {}31 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
34 experimental.authenticationDialog: AuthenticationDialog {}32 experimental.authenticationDialog: AuthenticationDialog {}
35 experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}33 experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}*/
36 experimental.alertDialog: AlertDialog {}34 /*alertDialog: AlertDialog {}
37 experimental.confirmDialog: ConfirmDialog {}35 confirmDialog: ConfirmDialog {}
38 experimental.promptDialog: PromptDialog {}36 promptDialog: PromptDialog {}
37 beforeUnloadDialog: BeforeUnloadDialog {}*/
3938
40 selectionActions: ActionList {39 /*selectionActions: ActionList {
41 Actions.Copy {40 Actions.Copy {
42 onTriggered: selection.copy()41 onTriggered: selection.copy()
43 }42 }
44 }43 }*/
4544
46 experimental.onPermissionRequested: {45 /*experimental.onPermissionRequested: {
47 if (permission.type === PermissionRequest.Geolocation) {46 if (permission.type === PermissionRequest.Geolocation) {
48 if (webview.toolbar) {47 if (webview.toolbar) {
49 webview.toolbar.close()48 webview.toolbar.close()
@@ -56,8 +55,5 @@
56 // TODO: handle other types of permission requests55 // TODO: handle other types of permission requests
57 // TODO: we might want to store the answer to avoid requesting56 // TODO: we might want to store the answer to avoid requesting
58 // the permission everytime the user visits this site.57 // the permission everytime the user visits this site.
59 }58 }*/
60
61 property int lastLoadRequestStatus: -1
62 onLoadingChanged: lastLoadRequestStatus = loadRequest.status
63}59}
6460
=== modified file 'src/app/browserapplication.cpp'
--- src/app/browserapplication.cpp 2014-03-14 14:51:22 +0000
+++ src/app/browserapplication.cpp 2014-03-28 17:03:06 +0000
@@ -17,10 +17,13 @@
17 */17 */
1818
19// Qt19// Qt
20#include <QtCore/QLibrary>
20#include <QtNetwork/QNetworkInterface>21#include <QtNetwork/QNetworkInterface>
22#include <QtGui/QOpenGLContext>
21#include <QtQml/QQmlComponent>23#include <QtQml/QQmlComponent>
22#include <QtQml/QQmlContext>24#include <QtQml/QQmlContext>
23#include <QtQml/QQmlEngine>25#include <QtQml/QQmlEngine>
26#include <QtQuick/private/qsgcontext_p.h>
24#include <QtQuick/QQuickWindow>27#include <QtQuick/QQuickWindow>
2528
26// local29// local
@@ -29,7 +32,7 @@
29#include "webbrowser-window.h"32#include "webbrowser-window.h"
3033
31BrowserApplication::BrowserApplication(int& argc, char** argv)34BrowserApplication::BrowserApplication(int& argc, char** argv)
32 : QApplication(argc, argv)35 : QGuiApplication(argc, argv)
33 , m_engine(0)36 , m_engine(0)
34 , m_window(0)37 , m_window(0)
35 , m_component(0)38 , m_component(0)
@@ -37,6 +40,25 @@
37{40{
38 m_arguments = arguments();41 m_arguments = arguments();
39 m_arguments.removeFirst();42 m_arguments.removeFirst();
43
44 // The testability driver is only loaded by QApplication but not by
45 // QGuiApplication (see https://codereview.qt-project.org/#change,66513).
46 // Let’s load the testability driver on our own.
47 if (m_arguments.contains(QLatin1String("-testability")) ||
48 qgetenv("QT_LOAD_TESTABILITY") == "1") {
49 QLibrary testLib(QLatin1String("qttestability"));
50 if (testLib.load()) {
51 typedef void (*TasInitialize)(void);
52 TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
53 if (initFunction) {
54 initFunction();
55 } else {
56 qCritical("Library qttestability resolve failed!");
57 }
58 } else {
59 qCritical("Library qttestability load failed!");
60 }
61 }
40}62}
4163
42BrowserApplication::~BrowserApplication()64BrowserApplication::~BrowserApplication()
@@ -80,6 +102,11 @@
80 QString appPkgName = qgetenv("APP_ID").split('_').first();102 QString appPkgName = qgetenv("APP_ID").split('_').first();
81 QCoreApplication::setApplicationName(appPkgName);103 QCoreApplication::setApplicationName(appPkgName);
82104
105 // Enable compositing in oxide
106 QOpenGLContext* glcontext = new QOpenGLContext(this);
107 glcontext->create();
108 QSGContext::setSharedOpenGLContext(glcontext);
109
83 bool inspector = m_arguments.contains("--inspector");110 bool inspector = m_arguments.contains("--inspector");
84 if (inspector) {111 if (inspector) {
85 QString host;112 QString host;
@@ -113,7 +140,7 @@
113 m_webbrowserWindowProxy = new WebBrowserWindow();140 m_webbrowserWindowProxy = new WebBrowserWindow();
114 context->setContextProperty("webbrowserWindowProxy", m_webbrowserWindowProxy);141 context->setContextProperty("webbrowserWindowProxy", m_webbrowserWindowProxy);
115142
116 QObject* browser = m_component->create();143 QObject* browser = m_component->beginCreate(context);
117 m_window = qobject_cast<QQuickWindow*>(browser);144 m_window = qobject_cast<QQuickWindow*>(browser);
118 m_webbrowserWindowProxy->setWindow(m_window);145 m_webbrowserWindowProxy->setWindow(m_window);
119146
120147
=== modified file 'src/app/browserapplication.h'
--- src/app/browserapplication.h 2014-03-14 14:51:22 +0000
+++ src/app/browserapplication.h 2014-03-28 17:03:06 +0000
@@ -24,14 +24,14 @@
24#include <QtCore/QString>24#include <QtCore/QString>
25#include <QtCore/QStringList>25#include <QtCore/QStringList>
26#include <QtCore/QUrl>26#include <QtCore/QUrl>
27#include <QtWidgets/QApplication>27#include <QtGui/QGuiApplication>
2828
29class QQmlComponent;29class QQmlComponent;
30class QQmlEngine;30class QQmlEngine;
31class QQuickWindow;31class QQuickWindow;
32class WebBrowserWindow;32class WebBrowserWindow;
3333
34class BrowserApplication : public QApplication34class BrowserApplication : public QGuiApplication
35{35{
36 Q_OBJECT36 Q_OBJECT
3737
@@ -49,11 +49,11 @@
49 QStringList m_arguments;49 QStringList m_arguments;
50 QQmlEngine* m_engine;50 QQmlEngine* m_engine;
51 QQuickWindow* m_window;51 QQuickWindow* m_window;
52 QQmlComponent* m_component;
5253
53private:54private:
54 QString appId() const;55 QString appId() const;
5556
56 QQmlComponent* m_component;
57 WebBrowserWindow *m_webbrowserWindowProxy;57 WebBrowserWindow *m_webbrowserWindowProxy;
58};58};
5959
6060
=== modified file 'src/app/webbrowser/BookmarksView.qml'
--- src/app/webbrowser/BookmarksView.qml 2014-03-12 22:45:12 +0000
+++ src/app/webbrowser/BookmarksView.qml 2014-03-28 17:03:06 +0000
@@ -50,8 +50,8 @@
50 url: model.url50 url: model.url
51 label: model.title ? model.title : model.url51 label: model.title ? model.title : model.url
5252
53 property url thumbnailSource: "image://webthumbnail/" + model.url53 //property url thumbnailSource: "image://webthumbnail/" + model.url
54 thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""54 //thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
5555
56 canBookmark: true56 canBookmark: true
57 bookmarksModel: bookmarksView.bookmarksModel57 bookmarksModel: bookmarksView.bookmarksModel
5858
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2014-03-13 10:16:20 +0000
+++ src/app/webbrowser/Browser.qml 2014-03-28 17:03:06 +0000
@@ -17,8 +17,6 @@
17 */17 */
1818
19import QtQuick 2.019import QtQuick 2.0
20import QtWebKit 3.1
21import QtWebKit.experimental 1.0
22import Ubuntu.Components 0.120import Ubuntu.Components 0.1
23import webbrowserapp.private 0.121import webbrowserapp.private 0.1
24import "../actions" as Actions22import "../actions" as Actions
@@ -48,7 +46,7 @@
48 },46 },
49 Actions.Bookmark {47 Actions.Bookmark {
50 enabled: currentWebview48 enabled: currentWebview
51 onTriggered: bookmarksModel.add(currentWebview.url, currentWebview.title, currentWebview.icon)49 onTriggered: bookmarksModel.add(currentWebview.url, currentWebview.title, "")//currentWebview.icon)
52 },50 },
53 Actions.NewTab {51 Actions.NewTab {
54 onTriggered: newTab("", true)52 onTriggered: newTab("", true)
@@ -73,7 +71,7 @@
7371
74 ErrorSheet {72 ErrorSheet {
75 anchors.fill: webviewContainer73 anchors.fill: webviewContainer
76 visible: currentWebview ? (currentWebview.lastLoadRequestStatus === WebView.LoadFailedStatus) : false74 visible: currentWebview ? currentWebview.lastLoadFailed : false
77 url: currentWebview ? currentWebview.url : ""75 url: currentWebview ? currentWebview.url : ""
78 onRefreshClicked: currentWebview.reload()76 onRefreshClicked: currentWebview.reload()
79 }77 }
@@ -217,7 +215,7 @@
217 enabled: stack.depth === 0215 enabled: stack.depth === 0
218 visible: currentWebview === webview216 visible: currentWebview === webview
219217
220 experimental.preferences.developerExtrasEnabled: developerExtrasEnabled218 //experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
221219
222 contextualActions: ActionList {220 contextualActions: ActionList {
223 Actions.OpenLinkInNewTab {221 Actions.OpenLinkInNewTab {
@@ -244,25 +242,9 @@
244242
245 onNewTabRequested: newTab(url, true)243 onNewTabRequested: newTab(url, true)
246244
247 WebviewThumbnailer {
248 id: thumbnailer
249 webview: webview
250 targetSize: Qt.size(units.gu(12), units.gu(12))
251 property url thumbnailSource: "image://webthumbnail/" + webview.url
252 onThumbnailRendered: {
253 if (url == webview.url) {
254 webview.thumbnail = thumbnailer.thumbnailSource
255 }
256 }
257 }
258 property url thumbnail: (url && thumbnailer.thumbnailExists()) ? thumbnailer.thumbnailSource : ""
259
260 onLoadingChanged: {245 onLoadingChanged: {
261 if (loadRequest.status === WebView.LoadSucceededStatus) {246 if (lastLoadSucceeded) {
262 _historyModel.add(webview.url, webview.title, webview.icon)247 _historyModel.add(webview.url, webview.title, webview.icon)
263 if (!thumbnailer.thumbnailExists()) {
264 thumbnailer.renderThumbnail()
265 }
266 }248 }
267 }249 }
268 }250 }
269251
=== modified file 'src/app/webbrowser/CMakeLists.txt'
--- src/app/webbrowser/CMakeLists.txt 2014-03-13 07:30:35 +0000
+++ src/app/webbrowser/CMakeLists.txt 2014-03-28 17:03:06 +0000
@@ -19,25 +19,13 @@
19 bookmarks-model.cpp19 bookmarks-model.cpp
20 settings.cpp20 settings.cpp
21 webbrowser-app.cpp21 webbrowser-app.cpp
22 webthumbnail-provider.cpp
23 webthumbnail-utils.cpp
24 webview-thumbnailer.cpp
25)22)
2623
27add_executable(${WEBBROWSER_APP} ${WEBBROWSER_APP_SRC})24add_executable(${WEBBROWSER_APP} ${WEBBROWSER_APP_SRC})
2825
29target_link_libraries(${WEBBROWSER_APP} ${COMMONLIB})26target_link_libraries(${WEBBROWSER_APP} ${COMMONLIB})
3027
31qt5_use_modules(${WEBBROWSER_APP} Core Gui Quick Sql WebKit)28qt5_use_modules(${WEBBROWSER_APP} Core Gui Quick Sql)
32
33# work around the lack of a public cmake module for Qt5V8
34set(Qt5V8_PRIVATE_INCLUDE_DIRS
35 "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}"
36 "/usr/include/qt5/QtV8/${Qt5Qml_VERSION_STRING}/QtV8")
37include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}
38 ${Qt5V8_PRIVATE_INCLUDE_DIRS}
39 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
40 ${Qt5WebKit_PRIVATE_INCLUDE_DIRS})
4129
42install(TARGETS ${WEBBROWSER_APP}30install(TARGETS ${WEBBROWSER_APP}
43 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})31 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
4432
=== modified file 'src/app/webbrowser/TabsList.qml'
--- src/app/webbrowser/TabsList.qml 2014-03-12 22:45:12 +0000
+++ src/app/webbrowser/TabsList.qml 2014-03-28 17:03:06 +0000
@@ -82,7 +82,7 @@
8282
83 url: model.url83 url: model.url
84 label: model.title ? model.title : model.url84 label: model.title ? model.title : model.url
85 thumbnail: model.webview.thumbnail85 //thumbnail: model.webview.thumbnail
86 canClose: true86 canClose: true
8787
88 onStateChanged: listview.state = state88 onStateChanged: listview.state = state
8989
=== modified file 'src/app/webbrowser/TimelineView.qml'
--- src/app/webbrowser/TimelineView.qml 2014-03-12 22:45:12 +0000
+++ src/app/webbrowser/TimelineView.qml 2014-03-28 17:03:06 +0000
@@ -18,7 +18,7 @@
1818
19import QtQuick 2.019import QtQuick 2.0
20import Ubuntu.Components 0.120import Ubuntu.Components 0.1
21import Ubuntu.Components.Extras.Browser 0.121//import Ubuntu.Components.Extras.Browser 0.1
22import Ubuntu.Components.ListItems 0.1 as ListItem22import Ubuntu.Components.ListItems 0.1 as ListItem
23import webbrowserapp.private 0.123import webbrowserapp.private 0.1
2424
@@ -173,8 +173,8 @@
173 url: model.url173 url: model.url
174 label: model.title ? model.title : model.url174 label: model.title ? model.title : model.url
175175
176 property url thumbnailSource: "image://webthumbnail/" + model.url176 //property url thumbnailSource: "image://webthumbnail/" + model.url
177 thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""177 //thumbnail: WebThumbnailer.thumbnailExists(model.url) ? thumbnailSource : ""
178178
179 canBookmark: true179 canBookmark: true
180 bookmarksModel: timelineView.bookmarksModel180 bookmarksModel: timelineView.bookmarksModel
@@ -282,8 +282,8 @@
282 }282 }
283 }283 }
284284
285 property url thumbnailSource: "image://webthumbnail/" + model.domain285 //property url thumbnailSource: "image://webthumbnail/" + model.domain
286 thumbnail: WebThumbnailer.thumbnailExists(model.domain) ? thumbnailSource : ""286 //thumbnail: WebThumbnailer.thumbnailExists(model.domain) ? thumbnailSource : ""
287287
288 onClicked: {288 onClicked: {
289 if ((timeline.currentIndex == timelineIndex) &&289 if ((timeline.currentIndex == timelineIndex) &&
290290
=== modified file 'src/app/webbrowser/webbrowser-app.cpp'
--- src/app/webbrowser/webbrowser-app.cpp 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webbrowser-app.cpp 2014-03-28 17:03:06 +0000
@@ -26,9 +26,6 @@
26#include "settings.h"26#include "settings.h"
27#include "tabs-model.h"27#include "tabs-model.h"
28#include "webbrowser-app.h"28#include "webbrowser-app.h"
29#include "webthumbnail-provider.h"
30#include "webthumbnail-utils.h"
31#include "webview-thumbnailer.h"
3229
33// system30// system
34#include <string.h>31#include <string.h>
@@ -41,23 +38,12 @@
41#include <QtCore/QMetaObject>38#include <QtCore/QMetaObject>
42#include <QtCore/QString>39#include <QtCore/QString>
43#include <QtCore/QTextStream>40#include <QtCore/QTextStream>
44#include <QtCore/QThread>
45#include <QtQml/QtQml>41#include <QtQml/QtQml>
46#include <QtQuick/QQuickWindow>42#include <QtQuick/QQuickWindow>
4743
48WebbrowserApp::WebbrowserApp(int& argc, char** argv)44WebbrowserApp::WebbrowserApp(int& argc, char** argv)
49 : BrowserApplication(argc, argv)45 : BrowserApplication(argc, argv)
50 , m_thumbnailUtilsThread(0)46{
51{
52}
53
54WebbrowserApp::~WebbrowserApp()
55{
56 if (m_thumbnailUtilsThread) {
57 m_thumbnailUtilsThread->quit();
58 m_thumbnailUtilsThread->wait();
59 delete m_thumbnailUtilsThread;
60 }
61}47}
6248
63bool WebbrowserApp::initialize()49bool WebbrowserApp::initialize()
@@ -91,22 +77,9 @@
91 qmlRegisterType<HistoryDomainListChronologicalModel>(uri, 0, 1, "HistoryDomainListChronologicalModel");77 qmlRegisterType<HistoryDomainListChronologicalModel>(uri, 0, 1, "HistoryDomainListChronologicalModel");
92 qmlRegisterType<TabsModel>(uri, 0, 1, "TabsModel");78 qmlRegisterType<TabsModel>(uri, 0, 1, "TabsModel");
93 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");79 qmlRegisterType<BookmarksModel>(uri, 0, 1, "BookmarksModel");
94 qmlRegisterType<WebviewThumbnailer>(uri, 0, 1, "WebviewThumbnailer");
9580
96 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {81 if (BrowserApplication::initialize("webbrowser/webbrowser-app.qml")) {
97 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));82 m_window->setProperty("chromeless", m_arguments.contains("--chromeless"));
98
99 // This singleton lives in its own thread to ensure that
100 // disk I/O is not performed in the UI thread.
101 WebThumbnailUtils& utils = WebThumbnailUtils::instance();
102 m_thumbnailUtilsThread = new QThread;
103 utils.moveToThread(m_thumbnailUtilsThread);
104 m_thumbnailUtilsThread->start();
105
106 WebThumbnailProvider* thumbnailer = new WebThumbnailProvider;
107 m_engine->addImageProvider(QLatin1String("webthumbnail"), thumbnailer);
108 m_engine->rootContext()->setContextProperty("WebThumbnailer", thumbnailer);
109
110 QList<QUrl> urls = this->urls();83 QList<QUrl> urls = this->urls();
111 if (urls.isEmpty()) {84 if (urls.isEmpty()) {
112 Settings settings;85 Settings settings;
@@ -116,6 +89,9 @@
116 Q_FOREACH(const QUrl& url, urls) {89 Q_FOREACH(const QUrl& url, urls) {
117 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));90 QMetaObject::invokeMethod(browser, "newTab", Q_ARG(QVariant, url), Q_ARG(QVariant, true));
118 }91 }
92
93 m_component->completeCreate();
94
119 return true;95 return true;
120 } else {96 } else {
121 return false;97 return false;
12298
=== modified file 'src/app/webbrowser/webbrowser-app.h'
--- src/app/webbrowser/webbrowser-app.h 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webbrowser-app.h 2014-03-28 17:03:06 +0000
@@ -21,22 +21,17 @@
2121
22#include "browserapplication.h"22#include "browserapplication.h"
2323
24class QThread;
25
26class WebbrowserApp : public BrowserApplication24class WebbrowserApp : public BrowserApplication
27{25{
28 Q_OBJECT26 Q_OBJECT
2927
30public:28public:
31 WebbrowserApp(int& argc, char** argv);29 WebbrowserApp(int& argc, char** argv);
32 ~WebbrowserApp();
3330
34 bool initialize();31 bool initialize();
3532
36private:33private:
37 virtual void printUsage() const;34 virtual void printUsage() const;
38
39 QThread* m_thumbnailUtilsThread;
40};35};
4136
42#endif // __WEBBROWSER_APP_H__37#endif // __WEBBROWSER_APP_H__
4338
=== removed file 'src/app/webbrowser/webthumbnail-provider.cpp'
--- src/app/webbrowser/webthumbnail-provider.cpp 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webthumbnail-provider.cpp 1970-01-01 00:00:00 +0000
@@ -1,53 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "webthumbnail-provider.h"
20#include "webthumbnail-utils.h"
21
22// Qt
23#include <QtCore/QDebug>
24#include <QtGui/QImageReader>
25
26WebThumbnailProvider::WebThumbnailProvider(QObject* parent)
27 : QObject(parent)
28 , QQuickImageProvider(QQuickImageProvider::Image)
29{
30}
31
32QImage WebThumbnailProvider::requestImage(const QString& id, QSize* size, const QSize& requestedSize)
33{
34 QImage image;
35 QFileInfo cached = WebThumbnailUtils::thumbnailFile(QUrl(id));
36 if (cached.exists()) {
37 QImageReader reader(cached.absoluteFilePath(), "PNG");
38 if (requestedSize.isValid()) {
39 reader.setScaledSize(requestedSize);
40 }
41 *size = reader.size();
42 reader.read(&image);
43 if (image.isNull()) {
44 qWarning() << "Failed to load cached thumbnail:" << reader.errorString();
45 }
46 }
47 return image;
48}
49
50bool WebThumbnailProvider::thumbnailExists(const QUrl& url) const
51{
52 return WebThumbnailUtils::thumbnailFile(url).exists();
53}
540
=== removed file 'src/app/webbrowser/webthumbnail-provider.h'
--- src/app/webbrowser/webthumbnail-provider.h 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webthumbnail-provider.h 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __WEBTHUMBNAIL_PROVIDER_H__
20#define __WEBTHUMBNAIL_PROVIDER_H__
21
22// Qt
23#include <QtCore/QObject>
24#include <QtCore/QUrl>
25#include <QtQuick/QQuickImageProvider>
26
27class WebThumbnailProvider : public QObject, public QQuickImageProvider
28{
29 Q_OBJECT
30
31public:
32 WebThumbnailProvider(QObject* parent=0);
33
34 virtual QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize);
35
36 Q_INVOKABLE bool thumbnailExists(const QUrl& url) const;
37};
38
39#endif // __WEBTHUMBNAIL_PROVIDER_H__
400
=== removed file 'src/app/webbrowser/webthumbnail-utils.cpp'
--- src/app/webbrowser/webthumbnail-utils.cpp 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webthumbnail-utils.cpp 1970-01-01 00:00:00 +0000
@@ -1,108 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "domain-utils.h"
20#include "webthumbnail-utils.h"
21
22// Qt
23#include <QtCore/QCryptographicHash>
24#include <QtCore/QFile>
25#include <QtCore/QStandardPaths>
26#include <QtCore/QUrl>
27#include <QtGui/QImage>
28
29#define MAX_CACHE_SIZE_IN_BYTES 5 * 1024 * 1024 // 5MB
30
31WebThumbnailUtils::WebThumbnailUtils(QObject* parent)
32 : QObject(parent)
33{
34}
35
36WebThumbnailUtils& WebThumbnailUtils::instance()
37{
38 static WebThumbnailUtils utils;
39 return utils;
40}
41
42WebThumbnailUtils::~WebThumbnailUtils()
43{
44}
45
46QDir WebThumbnailUtils::cacheLocation()
47{
48 return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/thumbnails";
49}
50
51void WebThumbnailUtils::ensureCacheLocation()
52{
53 QDir cache = cacheLocation();
54 if (!cache.exists()) {
55 QDir::root().mkpath(cache.absolutePath());
56 }
57}
58
59QFileInfo WebThumbnailUtils::thumbnailFile(const QUrl& url)
60{
61 QString hash(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Md5).toHex());
62 return cacheLocation().absoluteFilePath(hash + ".png");
63}
64
65void WebThumbnailUtils::cacheThumbnail(const QUrl& url, const QImage& thumbnail) const
66{
67 ensureCacheLocation();
68 QFileInfo file = thumbnailFile(url);
69 bool saved = thumbnail.save(file.absoluteFilePath());
70
71 if (saved) {
72 // Make a link to the thumbnail file for the corresponding domain’s thumbnail.
73 QUrl domain(DomainUtils::extractTopLevelDomainName(url));
74 QString domainThumbnail = WebThumbnailUtils::thumbnailFile(domain).absoluteFilePath();
75 if (QFile::exists(domainThumbnail)) {
76 QFile::remove(domainThumbnail);
77 }
78 QFile::link(file.fileName(), domainThumbnail);
79 }
80
81 expireCache();
82}
83
84void WebThumbnailUtils::expireCache() const
85{
86 QDir cache = cacheLocation();
87 if (!cache.exists()) {
88 return;
89 }
90 QStringList nameFilters = QStringList() << "*.png";
91 QDir::Filters filters = QDir::Files | QDir::NoDotAndDotDot;
92 QDir::SortFlags sort = QDir::Time;
93 QFileInfoList entries = cache.entryInfoList(nameFilters, filters, sort);
94 qint64 currentSize = 0;
95 Q_FOREACH(const QFileInfo& entry, entries) {
96 currentSize += entry.size();
97 }
98 if (currentSize > MAX_CACHE_SIZE_IN_BYTES) {
99 qint64 goal = MAX_CACHE_SIZE_IN_BYTES * 9 / 10;
100 while (!entries.isEmpty() && (currentSize > goal)) {
101 QFileInfo entry = entries.takeLast();
102 qint64 size = entry.size();
103 if (QFile::remove(entry.absoluteFilePath())) {
104 currentSize -= size;
105 }
106 }
107 }
108}
1090
=== removed file 'src/app/webbrowser/webthumbnail-utils.h'
--- src/app/webbrowser/webthumbnail-utils.h 2014-03-12 23:09:21 +0000
+++ src/app/webbrowser/webthumbnail-utils.h 1970-01-01 00:00:00 +0000
@@ -1,51 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __WEBTHUMBNAIL_UTILS_H__
20#define __WEBTHUMBNAIL_UTILS_H__
21
22// Qt
23#include <QtCore/QDir>
24#include <QtCore/QFileInfo>
25#include <QtCore/QObject>
26
27class QImage;
28class QUrl;
29
30class WebThumbnailUtils : public QObject
31{
32 Q_OBJECT
33
34public:
35 static WebThumbnailUtils& instance();
36 ~WebThumbnailUtils();
37
38 static QDir cacheLocation();
39 static void ensureCacheLocation();
40 static QFileInfo thumbnailFile(const QUrl& url);
41
42public Q_SLOTS:
43 void cacheThumbnail(const QUrl& url, const QImage& thumbnail) const;
44
45private:
46 WebThumbnailUtils(QObject* parent=0);
47
48 void expireCache() const;
49};
50
51#endif // __WEBTHUMBNAIL_UTILS_H__
520
=== removed file 'src/app/webbrowser/webview-thumbnailer.cpp'
--- src/app/webbrowser/webview-thumbnailer.cpp 2014-03-19 08:25:39 +0000
+++ src/app/webbrowser/webview-thumbnailer.cpp 1970-01-01 00:00:00 +0000
@@ -1,162 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "webthumbnail-utils.h"
20#include "webview-thumbnailer.h"
21
22// Qt
23#include <QtCore/QtGlobal>
24#include <QtCore/QMetaObject>
25#include <QtCore/QTimer>
26#include <QtQuick/private/qsgrenderer_p.h>
27#include <QtWebKit/private/qquickwebpage_p.h>
28#include <QtWebKit/private/qquickwebview_p.h>
29
30class BindableFbo : public QSGBindable
31{
32public:
33 BindableFbo(QOpenGLFramebufferObject* fbo) : m_fbo(fbo) {}
34 virtual void bind() const { m_fbo->bind(); }
35
36private:
37 QOpenGLFramebufferObject *m_fbo;
38};
39
40WebviewThumbnailer::WebviewThumbnailer(QQuickItem* parent)
41 : QQuickItem(parent)
42 , m_webview(0)
43{
44}
45
46QQuickWebView* WebviewThumbnailer::webview() const
47{
48 return m_webview;
49}
50
51void WebviewThumbnailer::setWebview(QQuickWebView* webview)
52{
53 if (webview != m_webview) {
54 m_webview = webview;
55 setFlag(QQuickItem::ItemHasContents, false);
56 Q_EMIT webviewChanged();
57 }
58}
59
60const QSize& WebviewThumbnailer::targetSize() const
61{
62 return m_targetSize;
63}
64
65void WebviewThumbnailer::setTargetSize(const QSize& targetSize)
66{
67 if (targetSize != m_targetSize) {
68 m_targetSize = targetSize;
69 Q_EMIT targetSizeChanged();
70 }
71}
72
73bool WebviewThumbnailer::thumbnailExists() const
74{
75 if (m_webview) {
76 QUrl url = m_webview->url();
77 if (url.isValid()) {
78 return WebThumbnailUtils::thumbnailFile(url).exists();
79 }
80 }
81 return false;
82}
83
84void WebviewThumbnailer::renderThumbnail()
85{
86 // Delay the actual rendering to give all elements on the page
87 // a chance to be fully rendered.
88 QTimer::singleShot(1000, this, SLOT(doRenderThumbnail()));
89}
90
91void WebviewThumbnailer::doRenderThumbnail()
92{
93 if (m_webview) {
94 setFlag(QQuickItem::ItemHasContents);
95 update();
96 }
97}
98
99QSGNode* WebviewThumbnailer::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData)
100{
101 Q_UNUSED(updatePaintNodeData);
102
103 if (!(m_webview && (flags() & QQuickItem::ItemHasContents))) {
104 return oldNode;
105 }
106 setFlag(QQuickItem::ItemHasContents, false);
107
108 QQuickWebPage* page = m_webview->page();
109 qreal min = qMin(page->width(), page->height());
110 QSize size(min, min);
111
112 QSGNode* node = QQuickItemPrivate::get(page)->itemNode();
113 QSGNode* parent = node->QSGNode::parent();
114 QSGNode* previousSibling = node->previousSibling();
115 if (parent) {
116 parent->removeChildNode(node);
117 }
118 QSGRootNode root;
119 root.appendChildNode(node);
120
121 QSGRenderer* renderer;
122#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
123 renderer = QQuickItemPrivate::get(this)->sceneGraphContext()->createRenderer();
124#else
125 renderer = QQuickItemPrivate::get(this)->sceneGraphRenderContext()->createRenderer();
126#endif
127 renderer->setRootNode(static_cast<QSGRootNode*>(&root));
128
129 QOpenGLFramebufferObject fbo(size);
130
131 renderer->setDeviceRect(size);
132 renderer->setViewportRect(size);
133 renderer->setProjectionMatrixToRect(QRectF(QPointF(), size));
134 renderer->setClearColor(Qt::transparent);
135
136 renderer->renderScene(BindableFbo(&fbo));
137
138 fbo.release();
139
140 const QUrl& url = m_webview->url();
141 QImage image = fbo.toImage().scaled(m_targetSize, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
142
143 // Invoke the method asynchronously.
144 QMetaObject::invokeMethod(&WebThumbnailUtils::instance(), "cacheThumbnail",
145 Qt::QueuedConnection, Q_ARG(QUrl, url), Q_ARG(QImage, image));
146
147 root.removeChildNode(node);
148 renderer->setRootNode(0);
149 delete renderer;
150
151 if (parent) {
152 if (previousSibling) {
153 parent->insertChildNodeAfter(node, previousSibling);
154 } else {
155 parent->prependChildNode(node);
156 }
157 }
158
159 Q_EMIT thumbnailRendered(url);
160
161 return oldNode;
162}
1630
=== removed file 'src/app/webbrowser/webview-thumbnailer.h'
--- src/app/webbrowser/webview-thumbnailer.h 2014-03-19 08:25:39 +0000
+++ src/app/webbrowser/webview-thumbnailer.h 1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef __WEBVIEW_THUMBNAILER_H__
20#define __WEBVIEW_THUMBNAILER_H__
21
22// Qt
23#include <QtCore/QSize>
24#include <QtCore/QUrl>
25#include <QtQuick/private/qquickitem_p.h>
26
27class QQuickWebView;
28
29class WebviewThumbnailer : public QQuickItem
30{
31 Q_OBJECT
32
33 Q_PROPERTY(QQuickWebView* webview READ webview WRITE setWebview NOTIFY webviewChanged)
34 Q_PROPERTY(QSize targetSize READ targetSize WRITE setTargetSize NOTIFY targetSizeChanged)
35
36public:
37 WebviewThumbnailer(QQuickItem* parent=0);
38
39 QQuickWebView* webview() const;
40 void setWebview(QQuickWebView* webview);
41
42 const QSize& targetSize() const;
43 void setTargetSize(const QSize& targetSize);
44
45 Q_INVOKABLE bool thumbnailExists() const;
46 Q_INVOKABLE void renderThumbnail();
47
48Q_SIGNALS:
49 void webviewChanged() const;
50 void targetSizeChanged() const;
51 void thumbnailRendered(const QUrl& url) const;
52
53protected:
54 virtual QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData);
55
56private Q_SLOTS:
57 void doRenderThumbnail();
58
59private:
60 QQuickWebView* m_webview;
61 QSize m_targetSize;
62};
63
64#endif // __WEBVIEW_THUMBNAILER_H__
650
=== modified file 'src/app/webcontainer/WebApp.qml'
--- src/app/webcontainer/WebApp.qml 2014-03-20 18:17:12 +0000
+++ src/app/webcontainer/WebApp.qml 2014-03-28 17:03:06 +0000
@@ -17,8 +17,6 @@
17 */17 */
1818
19import QtQuick 2.019import QtQuick 2.0
20import QtWebKit 3.1
21import QtWebKit.experimental 1.0
22import Ubuntu.Components 0.120import Ubuntu.Components 0.1
23import Ubuntu.Components.Popups 0.121import Ubuntu.Components.Popups 0.1
24import Ubuntu.Unity.Action 1.0 as UnityActions22import Ubuntu.Unity.Action 1.0 as UnityActions
@@ -29,20 +27,23 @@
29BrowserView {27BrowserView {
30 id: webapp28 id: webapp
3129
32 currentWebview: webview30 currentWebview: webview.currentWebview
3331
34 property alias url: webview.url32 property alias url: webview.url
35 property string webappName: ""33
36 property string webappModelSearchPath: ""34 property string webappModelSearchPath: ""
37 property var webappUrlPatterns: null35
36 property alias oxide: webview.withOxide
37 property alias webappName: webview.webappName
38 property alias webappUrlPatterns: webview.webappUrlPatterns
3839
39 actions: [40 actions: [
40 Actions.Back {41 Actions.Back {
41 enabled: backForwardButtonsVisible && currentWebview.canGoBack42 enabled: backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoBack
42 onTriggered: webview.goBack()43 onTriggered: webview.goBack()
43 },44 },
44 Actions.Forward {45 Actions.Forward {
45 enabled: backForwardButtonsVisible && currentWebview.canGoForward46 enabled: backForwardButtonsVisible && webview.currentWebview && webview.currentWebview.canGoForward
46 onTriggered: webview.goForward()47 onTriggered: webview.goForward()
47 },48 },
48 Actions.Reload {49 Actions.Reload {
@@ -58,10 +59,8 @@
58 // The UITK is trying too hard to be clever about the header and toolbar.59 // The UITK is trying too hard to be clever about the header and toolbar.
59 flickable: null60 flickable: null
6061
61 WebViewImpl {62 WebappContainerWebview {
62 id: webview63 id: webview
63
64 currentWebview: webview
65 toolbar: panel.panel64 toolbar: panel.panel
6665
67 anchors {66 anchors {
@@ -70,97 +69,17 @@
70 top: parent.top69 top: parent.top
71 }70 }
72 height: parent.height - osk.height71 height: parent.height - osk.height
7372 developerExtrasEnabled: webapp.developerExtrasEnabled
74 experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
75
76 contextualActions: ActionList {
77 Actions.CopyLink {
78 enabled: webview.contextualData.href.toString()
79 onTriggered: Clipboard.push([webview.contextualData.href])
80 }
81 Actions.CopyImage {
82 enabled: webview.contextualData.img.toString()
83 onTriggered: Clipboard.push([webview.contextualData.img])
84 }
85 }
86
87 function haveValidUrlPatterns() {
88 return webappUrlPatterns && webappUrlPatterns.length !== 0
89 }
90
91 function navigationRequestedDelegate(request) {
92 if (!request.isMainFrame) {
93 request.action = WebView.AcceptRequest
94 return
95 }
96
97 // Pass-through if we are not running as a named webapp (--webapp='Gmail')
98 // or if we dont have a list of url patterns specified to filter the
99 // browsing actions
100 if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
101 request.action = WebView.AcceptRequest
102 return
103 }
104
105 var action = WebView.IgnoreRequest
106 var url = request.url.toString()
107
108 // The list of url patterns defined by the webapp takes precedence over command line
109 if (isRunningAsANamedWebapp()) {
110 if (unityWebapps.model.exists(unityWebapps.name) &&
111 unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
112 request.action = WebView.AcceptRequest
113 return;
114 }
115 }
116
117 // We still take the possible additional patterns specified in the command line
118 // (the in the case of finer grained ones specifically for the container and not
119 // as an 'install source' for the webapp).
120 if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
121 for (var i = 0; i < webappUrlPatterns.length; ++i) {
122 var pattern = webappUrlPatterns[i]
123 if (url.match(pattern)) {
124 action = WebView.AcceptRequest
125 break
126 }
127 }
128 }
129
130 request.action = action
131 if (action === WebView.IgnoreRequest) {
132 console.debug('Opening: ' + url + ' in the browser window.')
133 Qt.openUrlExternally(url)
134 }
135 }
136
137 onNewTabRequested: Qt.openUrlExternally(url)
138
139 // Small shim needed when running as a webapp to wire-up connections
140 // with the webview (message received, etc…).
141 // This is being called (and expected) internally by the webapps
142 // component as a way to bind to a webview lookalike without
143 // reaching out directly to its internals (see it as an interface).
144 function getUnityWebappsProxies() {
145 var eventHandlers = {
146 onAppRaised: function () {
147 if (webbrowserWindow) {
148 try {
149 webbrowserWindow.raise();
150 } catch (e) {
151 console.debug('Error while raising: ' + e);
152 }
153 }
154 }
155 };
156 return UnityWebAppsUtils.makeProxiesForQtWebViewBindee(webview, eventHandlers)
157 }
158 }73 }
15974
160 ErrorSheet {75 ErrorSheet {
161 anchors.fill: webview76 anchors.fill: webview
162 visible: webview.lastLoadRequestStatus == WebView.LoadFailedStatus77 visible: {
163 url: webview.url78 if (webview.lastLoadFailed !== undefined)
79 return webview.lastLoadFailed
80 return webview.currentWebview && webview.currentWebview.lastLoadFailed
81 }
82 url: webview.currentWebview.url
164 onRefreshClicked: webview.reload()83 onRefreshClicked: webview.reload()
165 }84 }
166 }85 }
@@ -168,7 +87,7 @@
168 PanelLoader {87 PanelLoader {
169 id: panel88 id: panel
17089
171 currentWebview: webview90 currentWebview: webview.currentWebview
172 chromeless: webapp.chromeless91 chromeless: webapp.chromeless
17392
174 backForwardButtonsVisible: webapp.backForwardButtonsVisible93 backForwardButtonsVisible: webapp.backForwardButtonsVisible
@@ -185,12 +104,8 @@
185 UnityWebApps.UnityWebApps {104 UnityWebApps.UnityWebApps {
186 id: unityWebapps105 id: unityWebapps
187 name: webappName106 name: webappName
188 bindee: webview107 bindee: webview.currentWebview
189 actionsContext: actionManager.globalContext108 actionsContext: actionManager.globalContext
190 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }109 model: UnityWebApps.UnityWebappsAppModel { searchPath: webappModelSearchPath }
191 }110 }
192
193 function isRunningAsANamedWebapp() {
194 return webappName && typeof(webappName) === 'string' && webappName.length != 0
195 }
196}111}
197112
=== added file 'src/app/webcontainer/WebViewImplWebkit.qml'
--- src/app/webcontainer/WebViewImplWebkit.qml 1970-01-01 00:00:00 +0000
+++ src/app/webcontainer/WebViewImplWebkit.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,159 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtWebKit 3.1
21import QtWebKit.experimental 1.0
22import Ubuntu.Components 0.1
23import Ubuntu.Components.Extras.Browser 0.1
24import Ubuntu.UnityWebApps 0.1 as UnityWebApps
25import Ubuntu.Components.Popups 0.1
26import "../actions" as Actions
27import ".."
28
29UbuntuWebView {
30 id: webview
31
32 property bool developerExtrasEnabled: false
33 property var currentWebview: webview
34 property var toolbar: null
35 property string webappName: ""
36 property var webappUrlPatterns: null
37
38 experimental.certificateVerificationDialog: CertificateVerificationDialog {}
39 experimental.authenticationDialog: AuthenticationDialog {}
40 experimental.proxyAuthenticationDialog: ProxyAuthenticationDialog {}
41 experimental.alertDialog: AlertDialog {}
42 experimental.confirmDialog: ConfirmDialog {}
43 experimental.promptDialog: PromptDialog {}
44
45 selectionActions: ActionList {
46 Actions.Copy {
47 onTriggered: selection.copy()
48 }
49 }
50
51 property bool lastLoadFailed: false
52 onLoadingChanged: {
53 lastLoadFailed = (loadRequest.status === WebView.LoadFailedStatus)
54 }
55
56 experimental.preferences.developerExtrasEnabled: developerExtrasEnabled
57
58 experimental.onPermissionRequested: {
59 if (permission.type === PermissionRequest.Geolocation) {
60 if (webview.toolbar) {
61 webview.toolbar.close()
62 }
63 var text = i18n.tr("This page wants to know your device’s location.")
64 PopupUtils.open(Qt.resolvedUrl("PermissionRequest.qml"),
65 webview.currentWebview,
66 {"permission": permission, "text": text})
67 }
68 // TODO: handle other types of permission requests
69 // TODO: we might want to store the answer to avoid requesting
70 // the permission everytime the user visits this site.
71 }
72
73 contextualActions: ActionList {
74 Actions.CopyLink {
75 enabled: webview.contextualData.href.toString()
76 onTriggered: Clipboard.push([webview.contextualData.href])
77 }
78 Actions.CopyImage {
79 enabled: webview.contextualData.img.toString()
80 onTriggered: Clipboard.push([webview.contextualData.img])
81 }
82 }
83
84 function isRunningAsANamedWebapp() {
85 return webview.webappName && typeof(webview.webappName) === 'string' && webview.webappName.length != 0
86 }
87
88 function haveValidUrlPatterns() {
89 return webappUrlPatterns && webappUrlPatterns.length !== 0
90 }
91
92 function navigationRequestedDelegate(request) {
93 if (!request.isMainFrame) {
94 request.action = WebView.AcceptRequest
95 return
96 }
97
98 // Pass-through if we are not running as a named webapp (--webapp='Gmail')
99 // or if we dont have a list of url patterns specified to filter the
100 // browsing actions
101 if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
102 request.action = WebView.AcceptRequest
103 return
104 }
105
106 var action = WebView.IgnoreRequest
107 var url = request.url.toString()
108
109 // The list of url patterns defined by the webapp takes precedence over command line
110 if (isRunningAsANamedWebapp()) {
111 if (unityWebapps.model.exists(unityWebapps.name) &&
112 unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
113 request.action = WebView.AcceptRequest
114 return;
115 }
116 }
117
118 // We still take the possible additional patterns specified in the command line
119 // (the in the case of finer grained ones specifically for the container and not
120 // as an 'install source' for the webapp).
121 if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
122 for (var i = 0; i < webappUrlPatterns.length; ++i) {
123 var pattern = webappUrlPatterns[i]
124 if (url.match(pattern)) {
125 action = WebView.AcceptRequest
126 break
127 }
128 }
129 }
130
131 request.action = action
132 if (action === WebView.IgnoreRequest) {
133 console.debug('Opening: ' + url + ' in the browser window.')
134 Qt.openUrlExternally(url)
135 }
136 }
137
138 onNewTabRequested: Qt.openUrlExternally(url)
139
140 // Small shim needed when running as a webapp to wire-up connections
141 // with the webview (message received, etc…).
142 // This is being called (and expected) internally by the webapps
143 // component as a way to bind to a webview lookalike without
144 // reaching out directly to its internals (see it as an interface).
145 function getUnityWebappsProxies() {
146 var eventHandlers = {
147 onAppRaised: function () {
148 if (webbrowserWindow) {
149 try {
150 webbrowserWindow.raise();
151 } catch (e) {
152 console.debug('Error while raising: ' + e);
153 }
154 }
155 }
156 };
157 return UnityWebAppsUtils.makeProxiesForQtWebViewBindee(webview, eventHandlers)
158 }
159}
0160
=== added file 'src/app/webcontainer/WebappContainerWebview.qml'
--- src/app/webcontainer/WebappContainerWebview.qml 1970-01-01 00:00:00 +0000
+++ src/app/webcontainer/WebappContainerWebview.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,151 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import Ubuntu.Components 0.1
21import Ubuntu.Unity.Action 1.0 as UnityActions
22import Ubuntu.UnityWebApps 0.1 as UnityWebApps
23import "../actions" as Actions
24import ".."
25
26Item {
27 id: containerWebview
28
29 property string url: ""
30 property bool withOxide: false
31 property bool developerExtrasEnabled: false
32 property string webappName: ""
33 property var currentWebview: webappContainerWebViewLoader.item
34 property var toolbar: null
35 property var webappUrlPatterns: null
36
37 Loader {
38 id: webappContainerWebViewLoader
39 anchors.fill: parent
40 sourceComponent: withOxide ? webappContainerWebViewOxide : webappContainerWebViewWebkit
41 }
42
43 Component {
44 id: webappContainerWebViewWebkit
45
46 WebViewImplWebkit {
47 toolbar: containerWebview.toolbar
48 url: containerWebview.url
49 webappName: containerWebview.webappName
50 webappUrlPatterns: containerWebview.webappUrlPatterns
51 developerExtrasEnabled: containerWebview.developerExtrasEnabled
52 }
53 }
54
55 Component {
56 id: webappContainerWebViewOxide
57
58 WebViewImpl {
59 id: webview
60
61 url: containerWebview.url
62 currentWebview: webview
63 toolbar: containerWebview.toolbar
64
65 contextualActions: ActionList {
66 Actions.CopyLink {
67 enabled: webview.contextualData.href.toString()
68 onTriggered: Clipboard.push([webview.contextualData.href])
69 }
70 Actions.CopyImage {
71 enabled: webview.contextualData.img.toString()
72 onTriggered: Clipboard.push([webview.contextualData.img])
73 }
74 }
75
76 function haveValidUrlPatterns() {
77 return webappUrlPatterns && webappUrlPatterns.length !== 0
78 }
79
80 /*function navigationRequestedDelegate(request) {
81 if (!request.isMainFrame) {
82 request.action = WebView.AcceptRequest
83 return
84 }
85
86 // Pass-through if we are not running as a named webapp (--webapp='Gmail')
87 // or if we dont have a list of url patterns specified to filter the
88 // browsing actions
89 if ( ! haveValidUrlPatterns() && ! isRunningAsANamedWebapp()) {
90 request.action = WebView.AcceptRequest
91 return
92 }
93
94 var action = WebView.IgnoreRequest
95 var url = request.url.toString()
96
97 // The list of url patterns defined by the webapp takes precedence over command line
98 if (isRunningAsANamedWebapp()) {
99 if (unityWebapps.model.exists(unityWebapps.name) &&
100 unityWebapps.model.doesUrlMatchesWebapp(unityWebapps.name, url)) {
101 request.action = WebView.AcceptRequest
102 return;
103 }
104 }
105
106 // We still take the possible additional patterns specified in the command line
107 // (the in the case of finer grained ones specifically for the container and not
108 // as an 'install source' for the webapp).
109 if (webappUrlPatterns && webappUrlPatterns.length !== 0) {
110 for (var i = 0; i < webappUrlPatterns.length; ++i) {
111 var pattern = webappUrlPatterns[i]
112 if (url.match(pattern)) {
113 action = WebView.AcceptRequest
114 break
115 }
116 }
117 }
118
119 request.action = action
120 if (action === WebView.IgnoreRequest) {
121 console.debug('Opening: ' + url + ' in the browser window.')
122 Qt.openUrlExternally(url)
123 }
124 }*/
125
126 onNewTabRequested: Qt.openUrlExternally(url)
127
128 preferences.localStorageEnabled: true
129
130 // Small shim needed when running as a webapp to wire-up connections
131 // with the webview (message received, etc…).
132 // This is being called (and expected) internally by the webapps
133 // component as a way to bind to a webview lookalike without
134 // reaching out directly to its internals (see it as an interface).
135 function getUnityWebappsProxies() {
136 var eventHandlers = {
137 onAppRaised: function () {
138 if (webbrowserWindow) {
139 try {
140 webbrowserWindow.raise();
141 } catch (e) {
142 console.debug('Error while raising: ' + e);
143 }
144 }
145 }
146 };
147 return UnityWebAppsUtils.makeProxiesForWebViewBindee(webview, eventHandlers)
148 }
149 }
150 }
151}
0152
=== modified file 'src/app/webcontainer/webapp-container.cpp'
--- src/app/webcontainer/webapp-container.cpp 2014-03-20 18:17:12 +0000
+++ src/app/webcontainer/webapp-container.cpp 2014-03-28 17:03:06 +0000
@@ -24,10 +24,32 @@
24// Qt24// Qt
25#include <QtCore/QCoreApplication>25#include <QtCore/QCoreApplication>
26#include <QtCore/QDebug>26#include <QtCore/QDebug>
27#include <QtCore/QFile>
27#include <QtCore/QFileInfo>28#include <QtCore/QFileInfo>
29#include <QtCore/QtGlobal>
28#include <QtCore/QRegularExpression>30#include <QtCore/QRegularExpression>
29#include <QtCore/QTextStream>31#include <QtCore/QTextStream>
30#include <QtQuick/QQuickWindow>32#include <QtQuick/QQuickWindow>
33#include <QtQml/QQmlComponent>
34
35
36namespace
37{
38
39QString currentArchitecturePathName()
40{
41#if defined(Q_PROCESSOR_X86_32)
42 return QLatin1String("i386-linux-gnu");
43#elif defined(Q_PROCESSOR_X86_64)
44 return QLatin1String("x86_64-linux-gnu");
45#elif defined(Q_PROCESSOR_ARM)
46 return QLatin1String("arm-linux-gnueabihf");
47#else
48#error Unable to determine target architecture
49#endif
50}
51
52}
3153
32WebappContainer::WebappContainer(int& argc, char** argv)54WebappContainer::WebappContainer(int& argc, char** argv)
33 : BrowserApplication(argc, argv)55 : BrowserApplication(argc, argv)
@@ -50,7 +72,13 @@
50 m_window->setProperty("webappName", name);72 m_window->setProperty("webappName", name);
51 m_window->setProperty("backForwardButtonsVisible", m_arguments.contains("--enable-back-forward"));73 m_window->setProperty("backForwardButtonsVisible", m_arguments.contains("--enable-back-forward"));
52 m_window->setProperty("addressBarVisible", m_arguments.contains("--enable-addressbar"));74 m_window->setProperty("addressBarVisible", m_arguments.contains("--enable-addressbar"));
75
76 bool oxide = withOxide();
77 qDebug() << "Using" << (oxide ? "Oxide" : "QtWebkit") << "as the web engine backend";
78 m_window->setProperty("oxide", oxide);
79
53 m_window->setProperty("webappUrlPatterns", webappUrlPatterns());80 m_window->setProperty("webappUrlPatterns", webappUrlPatterns());
81
54 // When a webapp is being launched by name, the URL is pulled from its 'homepage'.82 // When a webapp is being launched by name, the URL is pulled from its 'homepage'.
55 if (name.isEmpty()) {83 if (name.isEmpty()) {
56 QList<QUrl> urls = this->urls();84 QList<QUrl> urls = this->urls();
@@ -58,6 +86,9 @@
58 m_window->setProperty("url", urls.first());86 m_window->setProperty("url", urls.first());
59 }87 }
60 }88 }
89
90 m_component->completeCreate();
91
61 return true;92 return true;
62 } else {93 } else {
63 return false;94 return false;
@@ -84,6 +115,31 @@
84 out << " --enable-addressbar enable the display of the address bar" << endl;115 out << " --enable-addressbar enable the display of the address bar" << endl;
85}116}
86117
118bool WebappContainer::withOxide() const
119{
120 Q_FOREACH(const QString& argument, m_arguments) {
121 if (argument == "--webkit") {
122 // force webkit
123 return false;
124 }
125 if (argument == "--oxide") {
126 // force oxide
127 return true;
128 }
129 }
130
131 // Use a runtime hint to transparently know if oxide
132 // can be used as a backend without the user/dev having
133 // to update its app or change something in the Exec args.
134 // Version 1.1 of ubuntu apparmor policy allows this file to
135 // be accessed whereas v1.0 only knows about qtwebkit.
136 QString oxideHintLocation =
137 QString("/usr/lib/%1/oxide-qt/oxide-renderer")
138 .arg(currentArchitecturePathName());
139
140 return QFile(oxideHintLocation).open(QIODevice::ReadOnly);
141}
142
87QString WebappContainer::webappModelSearchPath() const143QString WebappContainer::webappModelSearchPath() const
88{144{
89 Q_FOREACH(const QString& argument, m_arguments) {145 Q_FOREACH(const QString& argument, m_arguments) {
90146
=== modified file 'src/app/webcontainer/webapp-container.h'
--- src/app/webcontainer/webapp-container.h 2014-03-14 14:51:22 +0000
+++ src/app/webcontainer/webapp-container.h 2014-03-28 17:03:06 +0000
@@ -39,6 +39,7 @@
39 QString webappModelSearchPath() const;39 QString webappModelSearchPath() const;
40 QString webappName() const;40 QString webappName() const;
41 QStringList webappUrlPatterns() const;41 QStringList webappUrlPatterns() const;
42 bool withOxide() const;
42};43};
4344
44#endif // __WEBAPP_CONTAINER_H__45#endif // __WEBAPP_CONTAINER_H__
4546
=== modified file 'src/app/webcontainer/webapp-container.qml'
--- src/app/webcontainer/webapp-container.qml 2014-03-14 14:51:22 +0000
+++ src/app/webcontainer/webapp-container.qml 2014-03-28 17:03:06 +0000
@@ -30,6 +30,7 @@
30 property alias webappName: browser.webappName30 property alias webappName: browser.webappName
31 property alias webappModelSearchPath: browser.webappModelSearchPath31 property alias webappModelSearchPath: browser.webappModelSearchPath
32 property alias webappUrlPatterns: browser.webappUrlPatterns32 property alias webappUrlPatterns: browser.webappUrlPatterns
33 property alias oxide: browser.oxide
3334
34 contentOrientation: browser.screenOrientation35 contentOrientation: browser.screenOrientation
3536
3637
=== modified file 'tests/autopilot/webbrowser_app/tests/test_tabs.py'
--- tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-02-06 04:31:01 +0000
+++ tests/autopilot/webbrowser_app/tests/test_tabs.py 2014-03-28 17:03:06 +0000
@@ -17,6 +17,7 @@
17from __future__ import absolute_import17from __future__ import absolute_import
1818
19import time19import time
20import unittest
20from testtools.matchers import Equals21from testtools.matchers import Equals
21from autopilot.matchers import Eventually22from autopilot.matchers import Eventually
2223
@@ -140,6 +141,8 @@
140 address_bar = self.main_window.get_address_bar()141 address_bar = self.main_window.get_address_bar()
141 self.assertThat(address_bar.activeFocus, Eventually(Equals(True)))142 self.assertThat(address_bar.activeFocus, Eventually(Equals(True)))
142143
144 # FIXME: re-enable when implemented in oxide
145 @unittest.skip("not implemented in oxide yet")
143 def test_open_target_blank_in_new_tab(self):146 def test_open_target_blank_in_new_tab(self):
144 url = self.base_url + "/blanktargetlink"147 url = self.base_url + "/blanktargetlink"
145 self.go_to_url(url)148 self.go_to_url(url)
@@ -149,6 +152,8 @@
149 self.assertThat(self.main_window.currentIndex, Eventually(Equals(1)))152 self.assertThat(self.main_window.currentIndex, Eventually(Equals(1)))
150 self.assert_current_url(self.base_url + "/aleaiactaest")153 self.assert_current_url(self.base_url + "/aleaiactaest")
151154
155 # FIXME: re-enable when implemented in oxide
156 @unittest.skip("not implemented in oxide yet")
152 def test_open_iframe_target_blank_in_new_tab(self):157 def test_open_iframe_target_blank_in_new_tab(self):
153 url = self.base_url + "/fulliframewithblanktargetlink"158 url = self.base_url + "/fulliframewithblanktargetlink"
154 self.go_to_url(url)159 self.go_to_url(url)
155160
=== modified file 'tests/unittests/qml/CMakeLists.txt'
--- tests/unittests/qml/CMakeLists.txt 2014-03-12 15:27:10 +0000
+++ tests/unittests/qml/CMakeLists.txt 2014-03-28 17:03:06 +0000
@@ -1,8 +1,15 @@
1set(XVFB_COMMAND)
2find_program(XVFBRUN xvfb-run)
3if(XVFBRUN)
4 set(XVFB_COMMAND ${XVFBRUN} -s "-screen 0 640x480x24" -a)
5else()
6 message(WARNING "Cannot find xvfb-run.")
7endif()
8
1set(TEST tst_QmlTests)9set(TEST tst_QmlTests)
2add_executable(${TEST} tst_QmlTests.cpp)10add_executable(${TEST} tst_QmlTests.cpp)
3qt5_use_modules(${TEST} Core Qml Quick Test QuickTest)11qt5_use_modules(${TEST} Core Qml Quick Test QuickTest)
4add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -import ${CMAKE_BINARY_DIR}/src)12add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -import ${CMAKE_BINARY_DIR}/src)
5set_tests_properties(${TEST} PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
613
7# copy qml files under test to build dir14# copy qml files under test to build dir
8set(out_qml_files)15set(out_qml_files)
@@ -13,7 +20,7 @@
13 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${webbrowser-common_SOURCE_DIR}/${qmlFile} ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile})20 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${webbrowser-common_SOURCE_DIR}/${qmlFile} ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile})
14 list(APPEND out_qml_files undertest/${qmlFile})21 list(APPEND out_qml_files undertest/${qmlFile})
15endforeach(qmlFile)22endforeach(qmlFile)
16set(privateApiQmlFiles UserAgent.qml ua-overrides.js)23set(privateApiQmlFiles UserAgent01.qml UserAgent02.qml ua-overrides.js)
17foreach(qmlFile ${privateApiQmlFiles})24foreach(qmlFile ${privateApiQmlFiles})
18 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile}25 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/undertest/${qmlFile}
19 DEPENDS ${webbrowser-plugin_SOURCE_DIR}/${qmlFile}26 DEPENDS ${webbrowser-plugin_SOURCE_DIR}/${qmlFile}
2027
=== added file 'tests/unittests/qml/tst_UbuntuWebView01.qml'
--- tests/unittests/qml/tst_UbuntuWebView01.qml 1970-01-01 00:00:00 +0000
+++ tests/unittests/qml/tst_UbuntuWebView01.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,46 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtTest 1.0
21import Ubuntu.Components.Extras.Browser 0.1
22
23TestCase {
24 name: "UbuntuWebView"
25
26 function test_custom_UA_override() {
27 compare(webview1.getUAString(), undefined)
28 // passing a 'url' parameter to getUAString()
29 // (as was the API before) shouldn’t hurt:
30 compare(webview1.getUAString("http://example.com"), undefined)
31 verify(webview1.experimental.userAgent !== undefined)
32 compare(webview2.experimental.userAgent, "custom UA")
33 }
34
35 UbuntuWebView {
36 id: webview1
37 }
38
39 UbuntuWebView {
40 id: webview2
41
42 function getUAString(url) {
43 return "custom UA"
44 }
45 }
46}
047
=== renamed file 'tests/unittests/qml/tst_UbuntuWebView.qml' => 'tests/unittests/qml/tst_UbuntuWebView02.qml'
--- tests/unittests/qml/tst_UbuntuWebView.qml 2014-03-14 17:26:10 +0000
+++ tests/unittests/qml/tst_UbuntuWebView02.qml 2014-03-28 17:03:06 +0000
@@ -18,18 +18,15 @@
1818
19import QtQuick 2.019import QtQuick 2.0
20import QtTest 1.020import QtTest 1.0
21import Ubuntu.Components.Extras.Browser 0.121import Ubuntu.Components.Extras.Browser 0.2
2222
23TestCase {23TestCase {
24 name: "UbuntuWebView"24 name: "UbuntuWebView"
2525
26 function test_custom_UA_override() {26 function test_custom_UA_override() {
27 compare(webview1.getUAString(), undefined)27 compare(webview1.getUAString(), undefined)
28 // passing a 'url' parameter to getUAString()28 verify(webview1.context.userAgent !== undefined)
29 // (as was the API before) shouldn’t hurt:29 compare(webview2.context.userAgent, "custom UA")
30 compare(webview1.getUAString("http://example.com"), undefined)
31 verify(webview1.experimental.userAgent !== undefined)
32 compare(webview2.experimental.userAgent, "custom UA")
33 }30 }
3431
35 UbuntuWebView {32 UbuntuWebView {
3633
=== removed file 'tests/unittests/qml/tst_UserAgent.qml'
--- tests/unittests/qml/tst_UserAgent.qml 2014-03-12 15:27:10 +0000
+++ tests/unittests/qml/tst_UserAgent.qml 1970-01-01 00:00:00 +0000
@@ -1,82 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtTest 1.0
21import "undertest"
22
23TestCase {
24 name: "UserAgent"
25
26 function test_get_domain_data() {
27 return [
28 {url: "http://ubuntu.com", domain: "ubuntu.com"},
29 {url: "http://www.ubuntu.com", domain: "www.ubuntu.com"},
30 {url: "http://ubuntu.com/", domain: "ubuntu.com"},
31 {url: "http://www.ubuntu.com/", domain: "www.ubuntu.com"},
32 {url: "ubuntu.com", domain: "ubuntu.com"},
33 {url: "ubuntu.com/", domain: "ubuntu.com"},
34 {url: "ubuntu.com/phone", domain: "ubuntu.com"},
35 {url: "http://ubuntu.com/phone", domain: "ubuntu.com"},
36 {url: "www.ubuntu.com/phone", domain: "www.ubuntu.com"},
37 {url: "http://ubuntu.com/phone/index.html", domain: "ubuntu.com"},
38 {url: "ubuntu.com/phone/index.html", domain: "ubuntu.com"},
39 {url: "www.ubuntu.com/phone/index.html", domain: "www.ubuntu.com"},
40 {url: "http://ubuntu.com/phone/index.html?foo=bar&baz=bleh", domain: "ubuntu.com"},
41 ]
42 }
43 function test_get_domain(data) {
44 compare(userAgent.getDomain(data.url), data.domain)
45 }
46
47 function test_get_domains_data() {
48 return [
49 {domain: "ubuntu.com", domains: ["ubuntu.com", "com"]},
50 {domain: "test.example.org", domains: ["test.example.org", "example.org", "org"]},
51 ]
52 }
53 function test_get_domains(data) {
54 compare(userAgent.getDomains(data.domain), data.domains)
55 }
56
57 function test_get_ua_string_data() {
58 return [
59 {url: "http://ubuntu.com", ua: userAgent.defaultUA},
60 {url: "http://example.org", ua: "full override"},
61 {url: "http://example.com/test", ua: "Mozilla/5.0 (Ubuntu Edge; Mobile) WebKit/537.21"},
62 {url: "http://www.google.com/", ua: "Mozilla/5.0 (Ubuntu; ble) WebKit/537.21"},
63 {url: "https://mail.google.com/", ua: "Mozilla/5.0 (Ubuntu; Touch) WebKit/537.21"},
64 ]
65 }
66 function test_get_ua_string(data) {
67 compare(userAgent.getUAString(data.url), data.ua)
68 }
69
70 UserAgent {
71 id: userAgent
72
73 defaultUA: "Mozilla/5.0 (Ubuntu; Mobile) WebKit/537.21"
74
75 overrides: {
76 "example.org": "full override",
77 "example.com": ["Ubuntu", "Ubuntu Edge"],
78 "google.com": [/mobi/i, "b"],
79 "mail.google.com": [/mobile/i, "Touch"],
80 }
81 }
82}
830
=== added file 'tests/unittests/qml/tst_UserAgent01.qml'
--- tests/unittests/qml/tst_UserAgent01.qml 1970-01-01 00:00:00 +0000
+++ tests/unittests/qml/tst_UserAgent01.qml 2014-03-28 17:03:06 +0000
@@ -0,0 +1,82 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtQuick 2.0
20import QtTest 1.0
21import "undertest"
22
23TestCase {
24 name: "UserAgent"
25
26 function test_get_domain_data() {
27 return [
28 {url: "http://ubuntu.com", domain: "ubuntu.com"},
29 {url: "http://www.ubuntu.com", domain: "www.ubuntu.com"},
30 {url: "http://ubuntu.com/", domain: "ubuntu.com"},
31 {url: "http://www.ubuntu.com/", domain: "www.ubuntu.com"},
32 {url: "ubuntu.com", domain: "ubuntu.com"},
33 {url: "ubuntu.com/", domain: "ubuntu.com"},
34 {url: "ubuntu.com/phone", domain: "ubuntu.com"},
35 {url: "http://ubuntu.com/phone", domain: "ubuntu.com"},
36 {url: "www.ubuntu.com/phone", domain: "www.ubuntu.com"},
37 {url: "http://ubuntu.com/phone/index.html", domain: "ubuntu.com"},
38 {url: "ubuntu.com/phone/index.html", domain: "ubuntu.com"},
39 {url: "www.ubuntu.com/phone/index.html", domain: "www.ubuntu.com"},
40 {url: "http://ubuntu.com/phone/index.html?foo=bar&baz=bleh", domain: "ubuntu.com"},
41 ]
42 }
43 function test_get_domain(data) {
44 compare(userAgent.getDomain(data.url), data.domain)
45 }
46
47 function test_get_domains_data() {
48 return [
49 {domain: "ubuntu.com", domains: ["ubuntu.com", "com"]},
50 {domain: "test.example.org", domains: ["test.example.org", "example.org", "org"]},
51 ]
52 }
53 function test_get_domains(data) {
54 compare(userAgent.getDomains(data.domain), data.domains)
55 }
56
57 function test_get_ua_string_data() {
58 return [
59 {url: "http://ubuntu.com", ua: userAgent.defaultUA},
60 {url: "http://example.org", ua: "full override"},
61 {url: "http://example.com/test", ua: "Mozilla/5.0 (Ubuntu Edge; Mobile) WebKit/537.21"},
62 {url: "http://www.google.com/", ua: "Mozilla/5.0 (Ubuntu; ble) WebKit/537.21"},
63 {url: "https://mail.google.com/", ua: "Mozilla/5.0 (Ubuntu; Touch) WebKit/537.21"},
64 ]
65 }
66 function test_get_ua_string(data) {
67 compare(userAgent.getUAString(data.url), data.ua)
68 }
69
70 UserAgent01 {
71 id: userAgent
72
73 defaultUA: "Mozilla/5.0 (Ubuntu; Mobile) WebKit/537.21"
74
75 overrides: {
76 "example.org": "full override",
77 "example.com": ["Ubuntu", "Ubuntu Edge"],
78 "google.com": [/mobi/i, "b"],
79 "mail.google.com": [/mobile/i, "Touch"],
80 }
81 }
82}

Subscribers

People subscribed via source and target branches

to status/vote changes: