Falkon Develop
Cross-platform Qt-based web browser
scripts.cpp
Go to the documentation of this file.
1/* ============================================================
2* Falkon - Qt web browser
3* Copyright (C) 2015-2018 David Rosca <nowrep@gmail.com>
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program 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 "scripts.h"
20#include "qztools.h"
21#include "webpage.h"
22
23#include <QUrlQuery>
24#include <QtWebEngineWidgetsVersion>
25
27{
28 QString source = QL1S("(function() {"
29 "%1"
30 ""
31 "function registerExternal(e) {"
32 " window.external = e;"
33 " if (window.external) {"
34 " var event = document.createEvent('Event');"
35 " event.initEvent('_falkon_external_created', true, true);"
36 " window._falkon_external = true;"
37 " document.dispatchEvent(event);"
38 " }"
39 "}"
40 ""
41 "if (self !== top) {"
42 " if (top._falkon_external)"
43 " registerExternal(top.external);"
44 " else"
45 " top.document.addEventListener('_falkon_external_created', function() {"
46 " registerExternal(top.external);"
47 " });"
48 " return;"
49 "}"
50 ""
51 "function registerWebChannel() {"
52 " try {"
53 " new QWebChannel(qt.webChannelTransport, function(channel) {"
54 " var external = channel.objects.qz_object;"
55 " external.extra = {};"
56 " for (var key in channel.objects) {"
57 " if (key != 'qz_object' && key.startsWith('qz_')) {"
58 " external.extra[key.substr(3)] = channel.objects[key];"
59 " }"
60 " }"
61 " registerExternal(external);"
62 " });"
63 " } catch (e) {"
64 " setTimeout(registerWebChannel, 100);"
65 " }"
66 "}"
67 "registerWebChannel();"
68 ""
69 "})()");
70
71 return source.arg(QzTools::readAllFileContents(QSL(":/qtwebchannel/qwebchannel.js")));
72}
73
75{
76 QString source = QL1S("(function() {"
77 " let eFormsOld = [],"
78 " eFormsDone = [];"
79 ""
80 " function findUsername(inputs) {"
81 " let usernameNames = ['user', 'name', 'login'];"
82 ""
83 " for (let i = 0; i < usernameNames.length; ++i) {"
84 " for (let j = 0; j < inputs.length; ++j)"
85 " if (inputs[j].type == 'text' && inputs[j].value.length && inputs[j].name.indexOf(usernameNames[i]) != -1)"
86 " return inputs[j].value;"
87 " }"
88 ""
89 " for (let i = 0; i < inputs.length; ++i)"
90 " if (inputs[i].type == 'text' && inputs[i].value.length)"
91 " return inputs[i].value;"
92 ""
93 " for (let i = 0; i < inputs.length; ++i)"
94 " if (inputs[i].type == 'email' && inputs[i].value.length)"
95 " return inputs[i].value;"
96 ""
97 " return '';"
98 " }"
99 ""
100 " function processForm(eForm) {"
101 " let data = '';"
102 " let password = '';"
103 " let inputs = eForm.getElementsByTagName('input');"
104 ""
105 " for (let i = 0; i < inputs.length; ++i) {"
106 " let input = inputs[i];"
107 " let type = input.type.toLowerCase();"
108 " if (type != 'text' && type != 'password' && type != 'email')"
109 " continue;"
110 " if (!password && type == 'password')"
111 " password = input.value;"
112 " data += encodeURIComponent(input.name);"
113 " data += '=';"
114 " data += encodeURIComponent(input.value);"
115 " data += '&';"
116 " }"
117 ""
118 " if (!password)"
119 " return;"
120 ""
121 " if (eFormsDone.every(e => e != eForm)) {"
122 " eFormsDone.push(eForm);"
123 " } else {"
124 " return;"
125 " }"
126 ""
127 " data = data.substring(0, data.length - 1);"
128 " let url = window.location.href;"
129 " let username = findUsername(inputs);"
130 " external.autoFill.formSubmitted(url, username, password, data);"
131 " }"
132 ""
133 " function undoForm(eForm) {"
134 " let i = eFormsDone.indexOf(eForm);"
135 ""
136 " if (i >= 0) {"
137 " eFormsDone.splice(i, 1);"
138 " }"
139 " }"
140 ""
141 " function registerForm(eForm) {"
142 " let eInputs = eForm.getElementsByTagName('input');"
143 ""
144 " eForm.addEventListener('submit', () => processForm(eForm), true);"
145 ""
146 " for (let eInput of eInputs) {"
147 " let type = eInput.type.toLowerCase();"
148 " "
149 " if (type == 'password') {"
150 " eInput.addEventListener('blur', () => processForm(eForm), true);"
151 " eInput.addEventListener('input', () => undoForm(eForm), true);"
152 " eInput.addEventListener('keydown', () => event.keyCode === 13 && processForm(eForm), true);"
153 " }"
154 " }"
155 " }"
156 ""
157 " setInterval(() => {"
158 " try {"
159 " let eFormsNew = Array.from(document.forms);"
160 ""
161 " for (let eFormNew of eFormsNew) {"
162 " if (eFormsOld.every(e => e != eFormNew)) {"
163 " eFormsOld.push(eFormNew);"
164 " registerForm(eFormNew);"
165 " }"
166 " }"
167 ""
168 " } catch (e) {}"
169 " }, 100);"
170 "})()");
171
172 return source;
173}
174
176{
177 QString source = QL1S("(function() {"
178 "var external = {};"
179 "external.AddSearchProvider = function(url) {"
180 " window.location = 'falkon:AddSearchProvider?url=' + url;"
181 "};"
182 "external.IsSearchProviderInstalled = function(url) {"
183 " console.warn('NOT IMPLEMENTED: IsSearchProviderInstalled()');"
184 " return false;"
185 "};"
186 "window.external = external;");
187 source += QL1S("})()");
188
189 return source;
190}
191
193{
194 QString source = QzTools::readAllFileContents(QSL(":html/speeddial.user.js"));
195 source.replace(QL1S("%JQUERY%"), QzTools::readAllFileContents(QSL(":html/jquery.js")));
196 source.replace(QL1S("%JQUERY-UI%"), QzTools::readAllFileContents(QSL(":html/jquery-ui.js")));
197 return source;
198}
199
200QString Scripts::setCss(const QString &css)
201{
202 QString source = QL1S("(function() {"
203 "var head = document.getElementsByTagName('head')[0];"
204 "if (!head) return;"
205 "var css = document.createElement('style');"
206 "css.setAttribute('type', 'text/css');"
207 "css.appendChild(document.createTextNode('%1'));"
208 "head.appendChild(css);"
209 "})()");
210
211 QString style = css;
212 style.replace(QL1S("'"), QL1S("\\'"));
213 style.replace(QL1S("\n"), QL1S("\\n"));
214 return source.arg(style);
215}
216
217QString Scripts::sendPostData(const QUrl &url, const QByteArray &data)
218{
219 QString source = QL1S("(function() {"
220 "var form = document.createElement('form');"
221 "form.setAttribute('method', 'POST');"
222 "form.setAttribute('action', '%1');"
223 "var val;"
224 "%2"
225 "form.submit();"
226 "})()");
227
228 QString valueSource = QL1S("val = document.createElement('input');"
229 "val.setAttribute('type', 'hidden');"
230 "val.setAttribute('name', '%1');"
231 "val.setAttribute('value', '%2');"
232 "form.appendChild(val);");
233
234 QString values;
235 QUrlQuery query(QString::fromUtf8(data));
236
237 const auto &queryItems = query.queryItems(QUrl::FullyDecoded);
238 for (int i = 0; i < queryItems.size(); ++i) {
239 const auto &pair = queryItems[i];
240 QString value = pair.first;
241 QString key = pair.second;
242 value.replace(QL1S("'"), QL1S("\\'"));
243 key.replace(QL1S("'"), QL1S("\\'"));
244 values.append(valueSource.arg(value, key));
245 }
246
247 return source.arg(url.toString(), values);
248}
249
250QString Scripts::completeFormData(const QByteArray &data)
251{
252 QString source = QL1S("(function() {"
253 "var data = '%1'.split('&');"
254 "var inputs = document.getElementsByTagName('input');"
255 ""
256 "for (var i = 0; i < data.length; ++i) {"
257 " var pair = data[i].split('=');"
258 " if (pair.length != 2)"
259 " continue;"
260 " var key = decodeURIComponent(pair[0]);"
261 " var val = decodeURIComponent(pair[1]);"
262 " for (var j = 0; j < inputs.length; ++j) {"
263 " var input = inputs[j];"
264 " var type = input.type.toLowerCase();"
265 " if (type != 'text' && type != 'password' && type != 'email')"
266 " continue;"
267 " if (input.name == key && input.name != '') {"
268 " input.value = val;"
269 " input.dispatchEvent(new Event('change'));"
270 " }"
271 " }"
272 "}"
273 ""
274 "})()");
275
276 QString d = QString::fromUtf8(data);
277 d.replace(QL1S("'"), QL1S("\\'"));
278 return source.arg(d);
279}
280
282{
283 QString source = QL1S("(function() {"
284 "var out = [];"
285 "var links = document.getElementsByTagName('link');"
286 "for (var i = 0; i < links.length; ++i) {"
287 " var e = links[i];"
288 " if (e.type == 'application/opensearchdescription+xml') {"
289 " out.push({"
290 " url: e.href,"
291 " title: e.title"
292 " });"
293 " }"
294 "}"
295 "return out;"
296 "})()");
297
298 return source;
299}
300
302{
303 QString source = QL1S("(function() {"
304 "var out = [];"
305 "var imgs = document.getElementsByTagName('img');"
306 "for (var i = 0; i < imgs.length; ++i) {"
307 " var e = imgs[i];"
308 " out.push({"
309 " src: e.src,"
310 " alt: e.alt"
311 " });"
312 "}"
313 "return out;"
314 "})()");
315
316 return source;
317}
318
320{
321 QString source = QL1S("(function() {"
322 "var out = [];"
323 "var meta = document.getElementsByTagName('meta');"
324 "for (var i = 0; i < meta.length; ++i) {"
325 " var e = meta[i];"
326 " out.push({"
327 " name: e.getAttribute('name'),"
328 " content: e.getAttribute('content'),"
329 " httpequiv: e.getAttribute('http-equiv')"
330 " });"
331 "}"
332 "return out;"
333 "})()");
334
335 return source;
336}
337
338QString Scripts::getFormData(const QPointF &pos)
339{
340 QString source = QL1S("(function() {"
341 "var e = document.elementFromPoint(%1, %2);"
342 "if (!e || e.tagName.toLowerCase() != 'input')"
343 " return;"
344 "var fe = e.parentElement;"
345 "while (fe) {"
346 " if (fe.tagName.toLowerCase() == 'form')"
347 " break;"
348 " fe = fe.parentElement;"
349 "}"
350 "if (!fe)"
351 " return;"
352 "var res = {"
353 " method: fe.method.toLowerCase(),"
354 " action: fe.action,"
355 " inputName: e.name,"
356 " inputs: [],"
357 "};"
358 "for (var i = 0; i < fe.length; ++i) {"
359 " var input = fe.elements[i];"
360 " res.inputs.push([input.name, input.value]);"
361 "}"
362 "return res;"
363 "})()");
364
365 return source.arg(pos.x()).arg(pos.y());
366}
367
368QString Scripts::scrollToAnchor(const QString &anchor)
369{
370 QString source = QL1S("(function() {"
371 "var e = document.getElementById(\"%1\");"
372 "if (!e) {"
373 " var els = document.querySelectorAll(\"[name='%1']\");"
374 " if (els.length)"
375 " e = els[0];"
376 "}"
377 "if (e)"
378 " e.scrollIntoView();"
379 "})()");
380
381 return source.arg(anchor);
382}
static QString readAllFileContents(const QString &filename)
Definition: qztools.cpp:98
static QString completeFormData(const QByteArray &data)
Definition: scripts.cpp:250
static QString setupFormObserver()
Definition: scripts.cpp:74
static QString setCss(const QString &css)
Definition: scripts.cpp:200
static QString setupWindowObject()
Definition: scripts.cpp:175
static QString sendPostData(const QUrl &url, const QByteArray &data)
Definition: scripts.cpp:217
static QString scrollToAnchor(const QString &anchor)
Definition: scripts.cpp:368
static QString setupWebChannel()
Definition: scripts.cpp:26
static QString getFormData(const QPointF &pos)
Definition: scripts.cpp:338
static QString getAllMetaAttributes()
Definition: scripts.cpp:319
static QString getAllImages()
Definition: scripts.cpp:301
static QString getOpenSearchLinks()
Definition: scripts.cpp:281
static QString setupSpeedDial()
Definition: scripts.cpp:192
int value(const QColor &c)
Definition: colors.cpp:238
i
Definition: i18n.py:23
#define QL1S(x)
Definition: qzcommon.h:44
#define QSL(x)
Definition: qzcommon.h:40