eric7/WebBrowser/Tools/Scripts.py

branch
eric7
changeset 8312
800c432b34c8
parent 8260
2161475d9639
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module containing function to generate JavaScript code.
8 """
9
10 #
11 # This code was ported from QupZilla.
12 # Copyright (C) David Rosca <nowrep@gmail.com>
13 #
14
15 from PyQt5.QtCore import QUrlQuery, QUrl
16
17 from .WebBrowserTools import getJavascript
18
19
20 def setupWebChannel(worldId):
21 """
22 Function generating a script to setup the web channel.
23
24 @param worldId world ID for which to setup the channel
25 @type int
26 @return script to setup the web channel
27 @rtype str
28 """
29 source = """
30 // ==UserScript==
31 {0}
32 // ==/UserScript==
33
34 (function() {{
35 {1}
36
37 function registerExternal(e) {{
38 window.external = e;
39 if (window.external) {{
40 var event = document.createEvent('Event');
41 event.initEvent('_eric_external_created', true, true);
42 window._eric_external = true;
43 document.dispatchEvent(event);
44 }}
45 }}
46
47 if (self !== top) {{
48 if (top._eric_external)
49 registerExternal(top.external);
50 else
51 top.document.addEventListener(
52 '_eric_external_created', function() {{
53 registerExternal(top.external);
54 }});
55 return;
56 }}
57
58 function registerWebChannel() {{
59 try {{
60 new QWebChannel(qt.webChannelTransport, function(channel) {{
61 var external = channel.objects.eric_object;
62 external.extra = {{}};
63 for (var key in channel.objects) {{
64 if (key != 'eric_object' && key.startsWith('eric_')) {{
65 external.extra[key.substr(5)] = channel.objects[key];
66 }}
67 }}
68 registerExternal(external);
69 }});
70 }} catch (e) {{
71 setTimeout(registerWebChannel, 100);
72 }}
73 }}
74 registerWebChannel();
75
76 }})()"""
77
78 from WebBrowser.WebBrowserPage import WebBrowserPage
79 match = (
80 "// @exclude eric:*"
81 if worldId == WebBrowserPage.SafeJsWorld else
82 "// @include eric:*"
83 )
84 return source.format(match, getJavascript("qwebchannel.js"))
85
86
87 def setupWindowObject():
88 """
89 Function generating a script to setup window.object add-ons.
90
91 @return generated script
92 @rtype str
93 """
94 source = """
95 (function() {
96 var external = {};
97 external.AddSearchProvider = function(url) {
98 window.location = 'eric:AddSearchProvider?url=' + url;
99 };
100 external.IsSearchProviderInstalled = function(url) {
101 console.warn('NOT IMPLEMENTED: IsSearchProviderInstalled()');
102 return false;
103 };
104 window.external = external;
105 window.print = function() {
106 window.location = 'eric:PrintPage';
107 };
108 })()"""
109
110 return source
111
112
113 def setStyleSheet(css):
114 """
115 Function generating a script to set a user style sheet.
116
117 @param css style sheet to be applied
118 @type str
119 @return script to set a user style sheet
120 @rtype str
121 """
122 source = """
123 (function() {{
124 var css = document.createElement('style');
125 css.setAttribute('type', 'text/css');
126 css.appendChild(document.createTextNode('{0}'));
127 document.getElementsByTagName('head')[0].appendChild(css);
128 }})()"""
129
130 style = css.replace("'", "\\'").replace("\n", "\\n")
131 return source.format(style)
132
133
134 def getFormData(pos):
135 """
136 Function generating a script to extract data for a form element.
137
138 @param pos position to extract data at
139 @type QPoint
140 @return script to extract form data
141 @rtype str
142 """
143 source = """
144 (function() {{
145 var e = document.elementFromPoint({0}, {1});
146 if (!e || e.tagName.toLowerCase() != 'input')
147 return;
148 var fe = e.parentElement;
149 while (fe) {{
150 if (fe.tagName.toLowerCase() != 'form')
151 break;
152 fe = fe.parentElement;
153 }}
154 if (!fe)
155 return;
156 var res = {{
157 method: fe.method.toLowerCase(),
158 action: fe.action,
159 inputName: e.name,
160 inputs: [],
161 }};
162 for (var i = 0; i < fe.length; ++i) {{
163 var input = fe.elements[i];
164 res.inputs.push([input.name, input.value]);
165 }}
166 return res;
167 }})()"""
168 return source.format(pos.x(), pos.y())
169
170
171 def getAllImages():
172 """
173 Function generating a script to extract all image tags of a web page.
174
175 @return script to extract image tags
176 @rtype str
177 """
178 source = """
179 (function() {
180 var out = [];
181 var imgs = document.getElementsByTagName('img');
182 for (var i = 0; i < imgs.length; ++i) {
183 var e = imgs[i];
184 out.push({
185 src: e.src,
186 alt: e.alt
187 });
188 }
189 return out;
190 })()"""
191 return source
192
193
194 def getAllMetaAttributes():
195 """
196 Function generating a script to extract all meta attributes of a web page.
197
198 @return script to extract meta attributes
199 @rtype str
200 """
201 source = """
202 (function() {
203 var out = [];
204 var meta = document.getElementsByTagName('meta');
205 for (var i = 0; i < meta.length; ++i) {
206 var e = meta[i];
207 out.push({
208 name: e.getAttribute('name'),
209 content: e.getAttribute('content'),
210 httpequiv: e.getAttribute('http-equiv'),
211 charset: e.getAttribute('charset')
212 });
213 }
214 return out;
215 })()"""
216 return source
217
218
219 def getOpenSearchLinks():
220 """
221 Function generating a script to extract all open search links.
222
223 @return script to extract all open serach links
224 @rtype str
225 """
226 source = """
227 (function() {
228 var out = [];
229 var links = document.getElementsByTagName('link');
230 for (var i = 0; i < links.length; ++i) {
231 var e = links[i];
232 if (e.type == 'application/opensearchdescription+xml') {
233 out.push({
234 url: e.getAttribute('href'),
235 title: e.getAttribute('title')
236 });
237 }
238 }
239 return out;
240 })()"""
241 return source
242
243
244 def sendPostData(url, data):
245 """
246 Function generating a script to send Post data.
247
248 @param url URL to send the data to
249 @type QUrl
250 @param data data to be sent
251 @type QByteArray
252 @return script to send Post data
253 @rtype str
254 """
255 source = """
256 (function() {{
257 var form = document.createElement('form');
258 form.setAttribute('method', 'POST');
259 form.setAttribute('action', '{0}');
260 var val;
261 {1}
262 form.submit();
263 }})()"""
264
265 valueSource = """
266 val = document.createElement('input');
267 val.setAttribute('type', 'hidden');
268 val.setAttribute('name', '{0}');
269 val.setAttribute('value', '{1}');
270 form.appendChild(val);"""
271
272 values = ""
273 query = QUrlQuery(data)
274 for name, value in query.queryItems(
275 QUrl.ComponentFormattingOption.FullyDecoded
276 ):
277 value = value.replace("'", "\\'")
278 name = name.replace("'", "\\'")
279 values += valueSource.format(name, value)
280
281 return source.format(url.toString(), values)
282
283
284 def setupFormObserver():
285 """
286 Function generating a script to monitor a web form for user entries.
287
288 @return script to monitor a web page
289 @rtype str
290 """
291 source = """
292 (function() {
293 function findUsername(inputs) {
294 var usernameNames = ['user', 'name', 'login'];
295 for (var i = 0; i < usernameNames.length; ++i) {
296 for (var j = 0; j < inputs.length; ++j)
297 if (inputs[j].type == 'text' &&
298 inputs[j].value.length &&
299 inputs[j].name.indexOf(usernameNames[i]) != -1)
300 return inputs[j].value;
301 }
302 for (var i = 0; i < inputs.length; ++i)
303 if (inputs[i].type == 'text' && inputs[i].value.length)
304 return inputs[i].value;
305 for (var i = 0; i < inputs.length; ++i)
306 if (inputs[i].type == 'email' && inputs[i].value.length)
307 return inputs[i].value;
308 return '';
309 }
310
311 function registerForm(form) {
312 form.addEventListener('submit', function() {
313 var form = this;
314 var data = '';
315 var password = '';
316 var inputs = form.getElementsByTagName('input');
317 for (var i = 0; i < inputs.length; ++i) {
318 var input = inputs[i];
319 var type = input.type.toLowerCase();
320 if (type != 'text' && type != 'password' &&
321 type != 'email')
322 continue;
323 if (!password && type == 'password')
324 password = input.value;
325 data += encodeURIComponent(input.name);
326 data += '=';
327 data += encodeURIComponent(input.value);
328 data += '&';
329 }
330 if (!password)
331 return;
332 data = data.substring(0, data.length - 1);
333 var url = window.location.href;
334 var username = findUsername(inputs);
335 external.passwordManager.formSubmitted(
336 url, username, password, data);
337 }, true);
338 }
339
340 for (var i = 0; i < document.forms.length; ++i)
341 registerForm(document.forms[i]);
342
343 var observer = new MutationObserver(function(mutations) {
344 for (var mutation of mutations)
345 for (var node of mutation.addedNodes)
346 if (node.tagName && node.tagName.toLowerCase() == 'form')
347 registerForm(node);
348 });
349 observer.observe(document.documentElement, {
350 childList: true, subtree: true
351 });
352
353 })()"""
354 return source
355
356
357 def completeFormData(data):
358 """
359 Function generating a script to fill in form data.
360
361 @param data data to be filled into the form
362 @type QByteArray
363 @return script to fill a form
364 @rtype str
365 """
366 source = """
367 (function() {{
368 var data = '{0}'.split('&');
369 var inputs = document.getElementsByTagName('input');
370
371 for (var i = 0; i < data.length; ++i) {{
372 var pair = data[i].split('=');
373 if (pair.length != 2)
374 continue;
375 var key = decodeURIComponent(pair[0]);
376 var val = decodeURIComponent(pair[1]);
377 for (var j = 0; j < inputs.length; ++j) {{
378 var input = inputs[j];
379 var type = input.type.toLowerCase();
380 if (type != 'text' && type != 'password' &&
381 type != 'email')
382 continue;
383 if (input.name == key) {{
384 input.value = val;
385 input.dispatchEvent(new Event('change'));
386 }}
387 }}
388 }}
389
390 }})()"""
391
392 data = bytes(data).decode("utf-8")
393 data = data.replace("'", "\\'")
394 return source.format(data)
395
396
397 def setCss(css):
398 """
399 Function generating a script to set a given CSS style sheet.
400
401 @param css style sheet
402 @type str
403 @return script to set the style sheet
404 @rtype str
405 """
406 source = """
407 (function() {{
408 var css = document.createElement('style');
409 css.setAttribute('type', 'text/css');
410 css.appendChild(document.createTextNode('{0}'));
411 document.getElementsByTagName('head')[0].appendChild(css);
412 }})()"""
413 style = css.replace("'", "\\'").replace("\n", "\\n")
414 return source.format(style)
415
416
417 def scrollToAnchor(anchor):
418 """
419 Function generating script to scroll to a given anchor.
420
421 @param anchor name of the anchor to scroll to
422 @type str
423 @return script to set the style sheet
424 @rtype str
425 """
426 source = """
427 (function() {{
428 var e = document.getElementById("{0}")
429 if (!e) {{
430 var els = document.querySelectorAll("[name='{0}']");
431 if (els.length)
432 e = els[0]
433 }}
434 if (e)
435 e.scrollIntoView()
436 }})()"""
437 return source.format(anchor)
438
439 ###########################################################################
440 ## scripts below are specific for eric
441 ###########################################################################
442
443
444 def getFeedLinks():
445 """
446 Function generating a script to extract all RSS and Atom feed links.
447
448 @return script to extract all RSS and Atom feed links
449 @rtype str
450 """
451 source = """
452 (function() {
453 var out = [];
454 var links = document.getElementsByTagName('link');
455 for (var i = 0; i < links.length; ++i) {
456 var e = links[i];
457 if ((e.rel == 'alternate') &&
458 ((e.type == 'application/atom+xml') ||
459 (e.type == 'application/rss+xml')
460 )
461 ) {
462 out.push({
463 url: e.getAttribute('href'),
464 title: e.getAttribute('title')
465 });
466 }
467 }
468 return out;
469 })()"""
470 return source

eric ide

mercurial