For my application I need to inject JS into the loaded url.
I am using the following snippet from here https://stackoverflow.com/a/10866495/1162305
import wx
import wx.html2
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = wx.html2.WebView.New(self)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.SetSizer(sizer)
self.SetSize((700, 700))
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.LoadURL("http://www.google.com")
dialog.Show()
dialog.browser.RunScript('alert("hello");')
app.MainLoop()
Here I am injecting javascript with RunScript but the problem is, this javascript loads before the webpage loads. How can I load this javascript after the webpage (given url) loaded completely.
I know in plain javascript I can use document.readyState === "complete", but here how can I do it?
According to documentation:
http://wxpython.org/Phoenix/docs/html/html2.WebView.html#phoenix-title-asynchronous-notifications
You should use EVT_WEBVIEW_LOADED event to check if asynchronous methods like LoadURL is completed.
self.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.browser)
Complete code could look something like (not tested):
import wx
import wx.html2
class MyBrowser(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
sizer = wx.BoxSizer(wx.VERTICAL)
self.browser = wx.html2.WebView.New(self)
sizer.Add(self.browser, 1, wx.EXPAND, 10)
self.Bind(wx.html2.EVT_WEBVIEW_LOADED, self.OnWebViewLoaded, self.browser)
self.SetSizer(sizer)
self.SetSize((700, 700))
def OnWebViewLoaded(self, evt):
# The full document has loaded
self.browser.RunScript('alert("hello");')
if __name__ == '__main__':
app = wx.App()
dialog = MyBrowser(None, -1)
dialog.browser.LoadURL("http://www.google.com")
dialog.Show()
app.MainLoop()
Related
The example of the code snippet is here:
from PySide2 import QtCore, QtGui, QtWidgets, QtWebChannel
from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
class AppWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.view = WebView(self)
self.setCentralWidget(self.view)
self.view.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True)
self.view.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True);
self.page = self.view.page()
self.page.setDevToolsPage(self.page)
#self.inspector = QWebInspector(self) # Crash is here!!!
#self.inspector.setPage(self.page)
#self.inspector.hide()
The three lines above were working perfectly in previous versions.
What is the alternative to QWebInspector in PySide2?
There is no equivalent QWebInspector class for QWebEngine, because the dev tools are provided by the underlying Chrome browser. An environment variable needs to be set to enable the tools, and you can then access them via a separate Chrome-based browser - see Qt WebEngine Developer Tools in the Qt5 docs for the full details.
Below is a simple demo based on your example code:
import sys, os
DEBUG_PORT = '5588'
DEBUG_URL = 'http://127.0.0.1:%s' % DEBUG_PORT
os.environ['QTWEBENGINE_REMOTE_DEBUGGING'] = DEBUG_PORT
from PySide2 import QtCore, QtGui, QtWidgets, QtWebChannel
from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
class AppWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.view = QWebEngineView(self)
self.setCentralWidget(self.view)
self.view.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True)
self.view.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True)
self.view.loadFinished.connect(self.handleLoaded)
self.view.load(QtCore.QUrl('https://google.com/'))
self.inspector = QWebEngineView()
self.inspector.setWindowTitle('Web Inspector')
self.inspector.load(QtCore.QUrl(DEBUG_URL))
def handleLoaded(self, ok):
if ok:
self.view.page().setDevToolsPage(self.inspector.page())
self.inspector.show()
app = QtWidgets.QApplication(sys.argv)
win = AppWindow()
win.setGeometry(600, 100, 600, 480)
win.show()
app.exec_()
I want to download a file and at the same time redirect to a new page. The user is shown a page with a link for the download. When they click it, I want to start the download then redirect to another page so they can't keep clicking it. However, I can only seem to get one or the other to work.
from flask import Flask, render_template, redirect, url_for, session, request, flash, send_file
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField
from pytube import YouTube
import os
import random, string
import re
app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'
session_id = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
class url_form(FlaskForm):
link = StringField('Enter link of YouTube video you would like to convert...')
audio = BooleanField('Audio Only')
submit = SubmitField('Convert')
def download_video(link, just_audio):
yt = YouTube(link)
download_path = 'conversions/'
#global myvar
if just_audio == True:
stream = yt.streams.filter(only_audio=True).first()
tag = 'video'
else:
stream = yt.streams.filter(adaptive=True).first()
tag = 'audio only'
download_video.name = yt.title
download_video.cleanString = re.sub('[^a-zA-Z0-9 \n\.]', '', download_video.name)
download_video.thumbnail = yt.thumbnail_url
download_video.path = stream.download(filename = download_video.cleanString, output_path = download_path)
return
#app.route('/', methods=['GET', 'POST'])
def index():
result = False
form = url_form()
if form.validate_on_submit():
session['link'] = form.link.data
if form.audio.data:
just_audio = True
else:
just_audio = False
session['just_audio'] = just_audio
link = session.get('link')
just_audio = session.get('just_audio')
download_video(link, just_audio)
#download_video(link, just_audio)
#return send_file(download_video.path, attachment_filename=download_video.cleanString + '.mp4', as_attachment=True)
return redirect(url_for('conversion_complete'))
return render_template('index.html', form=form, result=result)
#app.route('/conversion_complete', methods=['GET', 'POST'])
def conversion_complete():
return render_template('conversion_complete.html')
#app.route('/download/', methods=['GET'])
def download():
return send_file(download_video.path, attachment_filename=download_video.cleanString + '.mp4', as_attachment=True)
return render_template('result.html')
<html>
<body>
<h1>Conversion Complete</h1>
<a href='download' target='blank' type='button'><button class='btn btn-default'>Download!</button></a>
</body>
</html>
My urls is not matching with the hashtags. it says 404 url not found.
this is my base.html with hashtag:
$(document).ready(function() {
$("p").each(function(data) {
var strText = $(this).html();
console.log('1. strText=', strText);
var arrElems = strText.match(/#[a-zA-Z0-9]+/g);
console.log('arrElems=', arrElems);
$.each(arrElems, function(index, value){
strText = strText.toString().replace(value, ''+value+'');
});
console.log('2. strText=', strText);
$(this).html(strText);
});
});
my hshtag models.py:
from django.db import models
from blog.models import post
# Create your models here.
class HashTag(models.Model):
tag = models.CharField(max_length=120)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.tag
def get_postss(self):
return post.objects.filter(content__icontains="#" + self.tag)
this is my hashtag view:
from django.shortcuts import render
from django.views import View
from .models import HashTag
# Create your views here.
class HashTagView(View):
def get(self, request, hashtag, *args, **kwargs):
obj, created = HashTag.objects.get_or_create(tag=hashtag)
return render(request, 'hashtags/tag_view.html', {"obj": obj})
i put the url intothe primary url of my site:
from hashtags.views import HashTagView
from django.urls import path, re_path, include
urlpatterns = [
re_path(r'^tags/(?P<hashtag>.*)/$', HashTagView.as_view(), name='hashtag'),
]
There is one issue with your implementation.
1. Browser does not send # part to the server. So if your URL is like /tags/#tag then #tag won't be sent to the server. Further read: Why is the hash part of the URL not available on the server side?
Because of this behavior, your browser will hit /tags/ url. That is the reason of your 404 error.
You can check the example of twitter, If the hashtag is #DelhiElectionResults, then the url for that hashtag is https://twitter.com/hashtag/DelhiElectionResults.
Solution: Just remove # from the url and make it like: /tags/tag/. In your JS, you can use value.replace('#', '') to remove the # from the value.
$.each(arrElems, function(index, value){
strText = strText.toString().replace(value, ''+value+'');
});
So I have the following dilemma:
I am using Brython and everything is working ok. I have a small piece of code that executes ajax requests for me and I added that in the header to bind everything on the current elements in the page.
from browser import document, ajax
# URL Query String
qs = ''
# URL to work on
url = ''
def post_data(url, qs):
req = ajax.ajax()
# Bind the complete State to the on_post_complete function
req.bind('complete', on_post_complete)
# send a POST request to the url
req.open('POST', url, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
# send data as a dictionary
req.send(qs)
def get_data(url, qs):
req = ajax.ajax()
req.bind('complete', on_get_complete)
# Bind the complete State to the on_get_complete function
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def on_post_complete(req):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
else:
document["main_area"].html = "error " + req.text
def on_get_complete(req):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
else:
document["main_area"].html = "error " + req.text
def account_click(ev):
get_data("/account", qs)
def contact_link_click(ev):
get_data("/contact", qs)
def logo_link_click(ev):
get_data("/main_page", qs)
def products_link_click(ev):
get_data("/products_page", qs)
def register_link_click(ev):
get_data("/register", qs)
document['login_link'].bind('click', account_click)
document['contact_link'].bind('click', contact_link_click)
document['logo_link'].bind('click', logo_link_click)
document['register_link'].bind('click', register_link_click)
document['running_link'].bind('click', products_link_click)
document['fitness_link'].bind('click', products_link_click)
document['tennis_link'].bind('click', products_link_click)
document['football_link'].bind('click', products_link_click)
document['golf_link'].bind('click', products_link_click)
Ok now my bigger problem is the fact that register_link is not in the page from the beginning. To be more exact register_link will only be loaded into the DOM after the login_link link is clicked after which the register link does nothing because the event was unable to be bound on it from the get go.
Now I know that I could easily bypass this just by importing this again in that page but I would want to avoid redundant imports and i'm not really sure exactly how to go about doing this.
EDIT:
Or is there a way in brython to wait for the DOM to be loaded completely?
As you noticed, writing account_click like this :
def account_click(ev):
get_data("/account", qs)
document['register_link'].active = True
document['register_link'].bind('click', register_link_click)
doesn't work, because the program doesn't wait for get_data to complete before executing the next 2 lines.
A solution is to write a specific version of get_data and on_get_complete for this case (I have supposed that the "register_link" button is in the page, but initially disabled):
def complete_register(req):
"""Called when the Ajax request after "login_link" is complete."""
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
# enable "register link" button and add binding
document['register_link'].disabled = False
document['register_link'].bind('click', register_link_click)
else:
document["main_area"].html = "error " + req.text
def get_data_and_register(url, qs):
req = ajax.ajax()
req.bind('complete', complete_register)
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def account_click(ev):
get_data_and_register("/account", qs)
Another option would be to keep the generic functions get_data and on_get_complete, and add an optional parameter callback:
def get_data(url, qs, callback=None):
req = ajax.ajax()
req.bind('complete', lambda req:on_get_complete(req, callback))
# Bind the complete State to the on_get_complete function
req.open('GET', url+'?'+qs, True)
req.set_header('content-type', 'application/x-www-form-urlencoded')
req.send()
def on_get_complete(req, callback=None):
if req.status == 200 or req.status == 0:
# Take our response and inject it into the html div with id='main'
document["main_area"].html = req.text
if callback is not None:
callback(req)
else:
document["main_area"].html = "error " + req.text
This is nothing common sense can't work for you - and Brython in this respect does just the same as Javascript: any DOM element you want to change needs to exist before you try to modify/bind it.
For decades the "usual" way to do that in Javascript has been place the bindings in a function and just call it at the bottom of the page, or on the body tag onload event, after everything else is loaded. "Modern" Javascript code "solves" this by using jQuery or other framework and its ready() method.
You have to do the same there - the timer might work, but it is risky. And, of course, elements that just exist after one or more of the other functions are triggered should be dealt with inside the respective functions:
def account_click(ev):
get_data("/account", qs)
document['register_link'].bind('click', register_link_click)
I'm developing a web application where I'm stuck with a problem in one feature. You can check it out here http://qlimp.com You can also use this for username/password: dummy/dummy
After login, please click the link Go to cover settings You will see a palette where you can upload images, enter some text.
When you upload the image, I've written an ajax request in jQuery which uploads the image to the server and shows fullpage background preview of that image.
JQuery
$('#id_tmpbg').live('change', function()
{
$("#ajax-loader").show();
$("#uploadform").ajaxForm({success: showResponse}).submit();
});
function showResponse(responseText, statusText, xhr, $form) {
$.backstretch(responseText)
$("#ajax-loader").hide();
}
So the problem here is, when I upload the image, it shows
ValueError at /cover/
The view cover.views.backgroundview didn't return an HttpResponse object.
Request Method: POST Request URL: http://qlimp.com/cover/
I'm actually returning HttpResponse object in views.
Views.py:
#login_required
def backgroundview(request):
if request.is_ajax():
form = BackgroundModelForm(request.POST, request.FILES)
if form.is_valid():
try:
g = BackgroundModel.objects.get(user=request.user)
except BackgroundModel.DoesNotExist:
data = form.save(commit=False)
data.user = request.user
data.save()
else:
if g.tmpbg != '' and g.tmpbg != g.background:
image_path = os.path.join(settings.MEDIA_ROOT, str(g.tmpbg))
try:
os.unlink(image_path)
except:
pass
data = BackgroundModelForm(request.POST, request.FILES, instance=g).save()
return HttpResponse(data.tmpbg.url)
else:
form = BackgroundModelForm()
return render_to_response("cover.html", {'form': form}, context_instance=RequestContext(request))
Models.py:
class BackgroundModel(models.Model):
user = models.OneToOneField(User)
background = models.ImageField(upload_to='backgrounds', null=True, blank=True)
tmpbg = models.ImageField(upload_to='backgrounds', null=True, blank=True)
class BackgroundModelForm(ModelForm):
class Meta:
model = BackgroundModel
exclude = ('user','background')
But these things are working on my computer(save the image and shows the background preview) but not in the production server. Why is it so?
I've uploaded the same code to the server.
Could anyone help me? Thanks!
You are not returning a response if the form is valid.