I have the following HTML document
<!DOCTYPE HTML>
<html>
<head>
<link href="style.css" rel="stylesheet">
<script src="firstScript.js"></script>
<script src="secondScript.js"></script>
...
</head>
<body onload='function()' ..."></body>
</html>
This is great for development, but in the end I need to put all of those scripts and .css file directly into my html document rather than referencing them. To achieve this I wrote a little build script in python to replace each line containing a filename with the contents of that file wrapped in the appropriate html tags. Here's a little snippet to show what happens with javascript files.
FILES = [ "firstScript.js", "secondScript.js", ... ]
OUTPUT = "path/to/build.html"
for f in FILES:
scriptFile = open(f, "r")
scriptDAT = "<script>\n"+scriptFile.read()+"</script>"
scriptFile.close()
with fileinput.FileInput(OUTPUT, inplace=True) as file:
for line in file:
if line.find(f) >= 0: line = line.replace(line, scriptDAT)
print(line)
This mostly works, but sometimes the line.replace will write everything in scriptDAT except for the </script> tag at the end. For example, if firstScript.js contains
function helloWorld() {
console.log(helloWorld);
}
Then this script after replacing that first line might produce the html file
<!DOCTYPE HTML>
<html>
<head>
<link href="style.css" rel="stylesheet">
<script>
function helloWorld() {
console.log("Hello World!");
}
<script src="secondScript.js"></script>
...
</head>
<body onload='function()' ..."></body>
</html>
The line.replace(line, scripDAT) ignoring the closing tag at the end of the string. The really strange thing is that this behaviour only happens sometimes; when the python script replaces secondScript.js it might include the closing tag. Does anyone know why the replace method is behaving this way?
Related
I am making a Python program using PyQt5 GUI library.
I found out that using runJavaScript() method does not work for executing JavaScript code on my HTML document.
Here is my HTML document - a Mapbox GL JS component. It can also be found here: https://docs.mapbox.com/mapbox-gl-js/example/simple-map/ .
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display a map on a webpage</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.10.0/mapbox-gl.js"></script><script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoidmxhZGlra2lyIiwiYSI6ImNsNno2dnN3cjAxamYzbm4xeDhxa2xuY2oifQ.HhDTHZglHlDNte7XwGZ1Xg';
const map = new mapboxgl.Map({
container: 'map', // container ID
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v11', // style URL
center: [-74.5, 40], // starting position [lng, lat]
zoom: 9, // starting zoom
projection: 'globe' // display the map as a 3D globe
});
map.on('style.load', () => {
map.setFog({}); // Set the default atmosphere style
});
</script>
</body>
</html>
Here is a part of my Python code:
# Creating QWebEngineView widget called "mapView"
self.mapView = QtWebEngineWidgets.a
mapSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
mapSizePolicy.setHeightForWidth(self.mapView.sizePolicy().hasHeightForWidth())
self.mapView.setSizePolicy(mapSizePolicy)
self.mapView.setObjectName("mapView")
self.detstartpointMapLayout.addWidget(self.mapView)
# Opening an HTML document and passing the components to QWebEngineView widget
with open('mapboxjs.html', 'r') as file:
mapHTML = file.read()
self.mapView.setHtml(mapHTML)
# Running a JavaScript code (with no success).
self.mapView.page().runJavaScript("const marker1 = new mapboxgl.Marker().setLngLat([12.554729, 55.70651]).addTo(map);")
Here is an error that my program returned:
js: Uncaught ReferenceError: mapboxgl is not defined .
I suppose this happens because runJavaScript() or QWebEngineView do not notice libraries that I have imported before in HEAD section of the HTML document using tag. How to I bypass that?
The same JavaScript command works with no errors when I open the HTML code in Firefox and send JS code into the console.
My suggestion was right - it happened because the JS function in page.runJavaScript() was executed before the .js script in HEAD section of the HTML file has completed it's execution.
So, to solve the issue I delayed page().runJavascript() execution until the HTML file finishes loading completely (including .js file in the HEAD section) by replacing
self.widgetname.page().runJavaScript("someJavaScriptFunction")
with
self.widgetname.page().loadFinished.connect(lambda: self.widgetname.page().runJavaScript("someJavaScriptFunction"))
Don't forget to include lambda: before the self.widgetname.page().runJavaScript() .
Is it possible to have a upload box on a site where a user can drag in a folder of files but instead of the entire folder being uploaded you can just grab the file names and metadata?
Not complete, but probably a good start...
This would be possible with dropzone.js, by setting the autoProcessQueue option to false. Then you can drop files/folders via the GUI, without them actually uploading, but still access the file object in javascript to get the metadata.
See this answer for more information on how to add a manual button to eventually start processing this queue if you wish. Regardless of whether you process that queue or not, you can use the addedfile event to manually inspect the file objects.
A really basic example, with the scripts loaded from a CDN, would look like:
<html>
<head>
<title> Dropzone</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.css" integrity="sha256-0Z6mOrdLEtgqvj7tidYQnCYWG3G2GAIpatAWKhDx+VM=" crossorigin="anonymous" />
</head>
<body>
<div>
<form method='POST'
enctype="multipart/form-data"
class="dropzone"
id="my-awesome-dropzone"></form>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js" integrity="sha256-NLit4Z57jz8npRHkopjfr68hSZY1x/ruN0T8kf68xq4=" crossorigin="anonymous"></script>
<script type='text/javascript'>
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("form#my-awesome-dropzone",
{ url: "/upload",
autoProcessQueue: false,
});
myDropzone.on("addedfile", function(file) {
// runs for every file dropped
console.log(file.name, file.fullPath, file.lastModified, file.size);
});
</script>
</body>
</html>
Dropping a single file with the above code outputs something like:
views.py undefined 1567770276854 1604
You can drop an entire folder, and every file recursively will appear, including file.fullPath for each:
models.py stack/models.py 1566159281216 1974
serializers.py stack/serializers.py 1565978398499 309
...
You could instead console.log(file) to inspect that object further (in your browser's dev tools console) to see the other available metadata.
To get this data to the backend you could use the fetch API or a similar AJAX post function. You may wish to add all the info to an array, then post this to the backend at once using another event handler tied to an "Upload metadata!" button.
I was creating a simple website using web.py framework . But when i ran the website it gave template error.
My html file code
def with (greeting)
<html>
<head>
<title> "This is a web project"</title>
<body>
<H1>"Yoyo honey singh"</H1>
<H6>greeting<H6>
</body>
</head>
</html>
My python file code
import web
urls = ("/","Index")
app = web.application(urls,globals())
render = web.template.render("\templates")
class Index:
def GET(self):
greeting = "HELLO WORLD"
return render.index(greeting = greeting)
if __name__ == "__main__":
app.run()
I placed the index.html file in the template folder and the python script in the bin folder. The directory structure is like
D:\WEBSITE
WEBSITE
NAME
init.py
bin
app.py
tests
init.py
docs
templates
According to the documentation you should put a $ before each python statement in the template. Therefore the first file becames:
$def with (greeting)
<html>
<head>
<title> "This is a web project"</title>
<body>
<H1>"Yoyo honey singh"</H1>
<H6>$greeting<H6>
</body>
</head>
</html>
I have written a game in Python using the PyGame library that I am trying to embed into an HTML page to allow me to play in a web browser.
I am attempting to do this using the JavaScript library Skulpt. I have attached a test script below that successfully outputs the print statement below.
skulpt.html
<html>
<head>
<script src="assets/skulpt/skulpt.js" type="text/javascript"></script>
</head>
<body>
<textarea id="pythonCode">
print "I am python."
</textarea><br />
<pre id="output"></pre>
<script type="text/javascript">
function outf(text) {
var mypre = document.getElementById("output");
mypre.innerHTML = mypre.innerHTML + text;
}
var code = document.getElementById("pythonCode").value;
Sk.configure({output:outf});
eval(Sk.importMainWithBody("<stdin>",false,code));
</script>
</body>
</html>
Output of skulpt.html:
The issue that I am having is that when I use my game code instead of the simple print statement shown above it produces the error seen below;
I have included all relevant images to my web servers' directory at the correct path. I am unsure of why this error is being produced. Any help would be much appreciated, thanks!
Also, here is the attached Python game code (and a live demo of the error):
http://nicolasward.com/portfolio/skulpt.html
You have a lot of indentation on line 1 -> remember, in python, indentation always matters. Take away all those spaces/tabs on the first line and it should run.
How is to compress (minimize) HTML from python; I know I can use some regex to strip spaces and other things, but I want a real compiler using pure python(so it can be used on Google App Engine).
I did a test on a online html compressor and it saved 65% of the html size. I want that, but from python.
You can use htmlmin to minify your html:
import htmlmin
html = """
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap Case</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<h2>Well</h2>
<div class="well">Basic Well</div>
</div>
</body>
</html>
"""
minified = htmlmin.minify(html.decode("utf-8"), remove_empty_space=True)
print(minified)
htmlmin and html_slimmer are some simple html minifying tools for python. I have millions of html pages stored in my database and running htmlmin, I am able to reduce the page size between 5 and 50%. Neither of them do an optimal job at complete html minification (i.e. the font color #00000 can be reduced to #000), but it's a good start. I have a try/except block that runs htmlmin and then if that fails, html_slimmer because htmlmin seems to provide better compression, but it does not support non ascii characters.
Example Code:
import htmlmin
from slimmer import html_slimmer # or xhtml_slimmer, css_slimmer
try:
html=htmlmin.minify(html, remove_comments=True, remove_empty_space=True)
except:
html=html_slimmer( html.strip().replace('\n',' ').replace('\t',' ').replace('\r',' ') )
Good Luck!
I suppose that in GAE there is no really need for minify your html as GAE already gzip it Caching & GZip on GAE (Community Wiki)
I did not test but minified version of html will probably win only 1% of size as it only remove space once both version are compressed.
If you want to save storage, for example by memcached it, you have more interest to gzip it (even at low level of compression) than removing space as in python it will be probably smaller and faster as processed in C instead of pure python
import htmlmin
code='''<body>
Hello World
<div style='color:red;'>Hi</div>
</body>
'''
htmlmin.minify(code)
Last line output
<body> Hello World <div style=color:red;>Hi</div> </body>
You can use this code to delete spaces
htmlmin.minify(code,remove_empty_space=True)
I wrote a build script that duplicates my templates into another directory and then I use this trick to tell my application to select the correct template in development mode, or in production:
DEV = os.environ['SERVER_SOFTWARE'].startswith('Development') and not PRODUCTION_MODE
TEMPLATE_DIR = 'templates/2012/head/' if DEV else 'templates/2012/output/'
Whether it is gzipped by your webserver is not really the point, you should save every byte that you can for performance reasons.
If you look at some of the biggest sites out there, they often do things like writing invalid html to save bytes, for example, it is common to omit double quotes in id attributes in html tags, for example:
<!-- Invalid HTML -->
<div id=mydiv> ... </div>
<!-- Valid HTML -->
<div id="mydiv"> ... </div>
And there are several examples like this one, but that's beside the scope of the thread I guess.
Back to the question, I put together a little build script that minifies your HTML, CSS and JS. Caveat: It doesn't cover the case of the PRE tag.
import os
import re
import sys
from subprocess import call
HEAD_DIR = 'templates/2012/head/'
OUT_DIR = 'templates/2012/output/'
REMOVE_WS = re.compile(r"\s{2,}").sub
YUI_COMPRESSOR = 'java -jar tools/yuicompressor-2.4.7.jar '
CLOSURE_COMPILER = 'java -jar tools/compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS '
def ensure_dir(f):
d = os.path.dirname(f)
if not os.path.exists(d):
os.makedirs(d)
def getTarget(fn):
return fn.replace(HEAD_DIR, OUT_DIR)
def processHtml(fn, tg):
f = open(fn, 'r')
content = f.read()
content = REMOVE_WS(" ", content)
ensure_dir(tg)
d = open(tg, 'w+')
d.write(content)
content
def processCSS(fn, tg):
cmd = YUI_COMPRESSOR + fn + ' -o ' + tg
call(cmd, shell=True)
return
def processJS(fn, tg):
cmd = CLOSURE_COMPILER + fn + ' --js_output_file ' + tg
call(cmd, shell=True)
return
# Script starts here.
ensure_dir(OUT_DIR)
for root, dirs, files in os.walk(os.getcwd()):
for dir in dirs:
print "Processing", os.path.join(root, dir)
for file in files:
fn = os.path.join(root) + '/' + file
if fn.find(OUT_DIR) > 0:
continue
tg = getTarget(fn)
if file.endswith('.html'):
processHtml(fn, tg)
if file.endswith('.css'):
processCSS(fn, tg)
if file.endswith('.js'):
processJS(fn, tg)