I am trying to upload a file to a cherrypy server, but without changing the displayed page.
A simple alert will be enough for my needs to tell the user that the upload is done.
I am trying this with a simple file input type and a button:
<div>
<label>Upload Sound:</label>
<input id="pathSound" style="width: 80%" type="file" accept=".mp3"/><br>
<button id="uploadSound">Upload</button>
</div>
and a script for the button click:
$("#uploadSound").click(function(e) {
if (document.getElementById("pathSound").value=='') {
alert("No file selected!");
e.preventDefault();
return;
}
var cardID = $('#tagID').html();
var file = document.getElementById("pathSound").files[0];
alert( "Tag: " + cardID + " File: " + file);
$.post("/uploadSound", {"cardID": cardID, "myFile": file})
.done(function(res) {
alert("File Saved!");
});
});
on the server side i have this function so far, but it is never called:
import os, os.path
import cherrypy
from cherrypy.process import plugins
class MagicBoxInterface(object):
#cherrypy.expose
def index(self):
return file('index.html')
#cherrypy.expose
def uploadSound(self, cardID='', myFile=None):
print 'uploadSound : ', cardID
print 'uploadSound : ', myFile
return ''
if __name__ == '__main__':
conf = {
'/': {
'tools.sessions.on': True,
'tools.staticdir.root': os.path.abspath(os.getcwd())
},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': './public'
}
}
interface = MagicBoxInterface()
cherrypy.quickstart(interface, '/', conf)
All the examples i find use normal post and show a result page after the upload, but this is not what i want to do! The displayed page must not change.
On a side note, i don't need to consider large files, because it will only handle files below 1-2 MB.
I have found some examples using frames, but i am not that familiar with html/javascript to fully understand how i can apply those to my needs.
And help on a simple solution is greatly appreciated.
Ok do this...
$("#uploadSound").click(function(e) {
if (document.getElementById("pathSound").value=='') {
alert("No file selected!");
e.preventDefault();
return;
}
var cardID = $('#tagID').html();
var file = document.getElementById("pathSound").files[0];
alert( "Tag: " + cardID + " File: " + file);
$.post("/MagicBoxInterface/uploadSound", {"cardID": cardID, "myFile": file})
.done(function(res) {
alert("File Saved!");
});
});
You just need to include the class in your post request path.
hope this helps!
Related
I have an application in Electron JS that is calling a python function to execute a python script.
When the script executes it should send the data back to the Electron JS GUI and display it.
The issue I am having is that it is saying that join is undefined:
weather.js:9 Uncaught TypeError: Cannot read property 'join' of
undefined
at get_weather (weather.js:9)
at HTMLButtonElement.onclick (weather.html:14)
here is my JavaScript file:
let {PythonShell} = require('python-shell')
var path = require("path")
function get_weather() {
var city = document.getElementById("city").value
var options = {
scriptPath : path.join(__dirname, '/../engine/'),
args : [city]
}
let pyshell = new PythonShell('weatherApp.py', options);
pyshell.on('message', function(message) {
swal(message);
})
document.getElementById("city").value = "";
}
The line "scriptPath : path.join(__dirname, '/../engine/')," seems to be the offending piece of code.
My gui.html file is as follows:
<html>
<head>
<title></title>
<meta charset="UTF-8">
</head>
<body>
<h1>Get your local weather ...</h1>
<br>
<br>
<label>Enter city name here: <label>
<input id="city" type = "text" placeholder="City">
<button type = "button" value="clickme" onclick="get_weather()">Get Weather</button>
<!--- <button class="btn btn-success" onclick="get_weather();">Go!</button> -->
<br>
<br>
<br>
<script src="/home/ironmantis7x/Documents/BSSLLC/projects/node_electron/electronDemoApps/guiApp/gui/linkers/weather.js"></script>
<p><button type="button">Back to Main Page</button>
</body>
</html>
What error(s) do I need to fix to get this working correctly?
Thank you.
The Problem
Since Electron 5 nodeIntegration is disabled by default in the window. Since normal browser API does not know require or join, you get errors when you try.
Reenabling nodeIntegration
You could enable nodeIntegration again, but it was disabled for a reason. Be sure you read and understand the electron security tutorial.
Using a preload script
Another way is to use a preload script. Let's have a look at the BrowserWindow documentation.
When creating a new BrowserWindow you can add several options. For this case we need the webPreferences.preload option:
Specifies a script that will be loaded before other scripts run in the page. This script will always have access to node APIs no matter whether node integration is turned on or off. The value should be the absolute file path to the script. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope.
Be aware that the preload script is run in the renderer process.
Example
Following is an example app, that opens a window with a button that uses the electron dialog to select files. This would not work with disabled nodeIntegration but thanks to our preload script, we reintroduced dialog.showOpenDialog() to our window.
main.js
const { app, BrowserWindow } = require("electron");
const { join } = require("path");
let win;
app.on("ready", () => {
win = new BrowserWindow({
webPreferences: {
//this is the default since electron 5
nodeIntegration: false,
//here you load your preload script
preload: join(__dirname, "preload.js")
}
});
win.loadURL(join(__dirname, "index.html"));
});
preload.js
const { dialog } = require("electron").remote;
window.mystuff = {
selectFile
};
async function selectFile() {
const files = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections"]
});
return files;
}
index.html
<html>
<body>
<main>
<button onclick="myFunction()">select file</button>
<ul id="foo"></ul>
</main>
<script>
async function myFunction() {
//the function provided by the preload script
const files = await window.mystuff.selectFile();
const list = document.getElementById("foo");
for (const file of files) {
const node = document.createElement("LI");
const textNode = document.createTextNode(file);
node.appendChild(textNode);
list.appendChild(node);
}
}
</script>
</body>
</html>
Sending events via IPC
If you are unsure your functionality should be exposed in the window, you can also send events via ipcRenderer.
preload.js
const { ipcRenderer } = require("electron");
window.mystuff = {
selectFile
};
function selectFile() {
return new Promise(resolve => {
ipcRenderer.on("selected-files", (e, files) => {
resolve(files);
});
ipcRenderer.send("select-files");
});
}
Additional part in main.js
ipcMain.on("select-files", async () => {
const files = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections"]
});
win.webContents.send("selected-files", files);
});
I am trying to implement a simple AJAX example, based on the demo shown on this page:
http://www.degraeve.com/reference/simple-ajax-example.php
I have copied the HTML portion and named it ajax_demo.html. For example:
<html>
<head>
<title>Simple Ajax Example</title>
<script language="Javascript">
function xmlhttpPost(strURL) {
var xmlHttpReq = false;
var self = this;
// Mozilla/Safari
if (window.XMLHttpRequest) {
self.xmlHttpReq = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
self.xmlHttpReq.open('POST', strURL, true);
self.xmlHttpReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
self.xmlHttpReq.onreadystatechange = function() {
if (self.xmlHttpReq.readyState == 4) {
updatepage(self.xmlHttpReq.responseText);
}
}
self.xmlHttpReq.send(getquerystring());
}
function getquerystring() {
var form = document.forms['f1'];
var word = form.word.value;
qstr = 'w=' + escape(word); // NOTE: no '?' before querystring
return qstr;
}
function updatepage(str){
document.getElementById("result").innerHTML = str;
}
</script>
</head>
<body>
<form name="f1">
<p>word: <input name="word" type="text">
<input value="Go" type="button" onclick='JavaScript:xmlhttpPost("/cgi-bin/simple-ajax-example.py")'></p>
<div id="result"></div>
</form>
</body>
</html>
Not shown above is the full real path to my simple-ajax-example.py here:
<input value="Go" type="button" onclick='JavaScript:xmlhttpPost("/cgi-bin/simple-ajax-example.py")'>
Both files are on my apache server. For example:
http://myserver.com/ajax_demo.html
http://myserver.com/cgi-bin/simple-ajax-example.py
My Python script does work when called directly and looks like this:
import cgi
form = cgi.FieldStorage()
secret_word = form.getvalue('word')
print "Content-type: text/html"
print ""
print "<p>The secret word is", secret_word, "<p>"
Problem is, this simply doesn't work. In the ajax_demo.html text box, when I enter text and click Go, nothing seems to happen.
What am I missing?
You probably need open a server to serve ../cgi-bin/ directory :)
try this commend,
python -m simpleHTTPServer 8100
-----EDIT-----
secret_word = form.getvalue('word')
qstr = 'word=' + escape(word)
Your querystring key is misspelled.
I would like to use gulp-liveReload with Django, is it possible? I have read that there is an alternative for Grunt, but I would prefer work with Gulp, it is easier for me.
Thanks,
I wrote up how to do it in a recent blog post here:
http://www.revsys.com/blog/2014/oct/21/ultimate-front-end-development-setup/
Basically you just need to write gulp tasks that watch what files you want to trigger livereloads, so for me that's templates:
/* Trigger a live reload on any Django template changes */
gulp.watch('**/templates/**').on('change', livereload.changed);
But you could also trigger it on models.py, views.py, or anything else you want really.
have you try this django-livereload ?
I also was struggling to find an answer howto to start a django server and get the browser live reloading working at the same time, however it turned out that it is easy to achieve (even when working cross platform on windows and linux):
//jshint node:true
'use strict';
var gulp = require('gulp'),
....
gutil = require('gulp-util');
var browserSync = require('browser-sync').create();
var serverUrl = 'localhost:8000';
var exec = require('child_process').exec;
var isProd = gutil.env.type === 'prod';
....
gulp.task('sass', function() {
return sass(sources.sass, {
compass: true,
sourcemap: true,
style: isProd ? 'compressed': 'expanded',
})
....
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(targets.css))
.pipe(browserSync.stream());
});
....
gulp.task('watch', function() {
gulp.watch(sources.sass, ['sass']);
gulp.watch(sources.pug, ['html'])
.on('change', browserSync.reload);
gulp.watch(sources.ts, ['typescript'])
.on('change', browserSync.reload);
// update browser on python change
gulp.watch('website/**/*.py')
.on('change', browserSync.reload);
});
// start django server
gulp.task('webserver', function() {
var isWin = /^win/.test(process.platform);
var cmd = '. venv/bin/activate && PYTHONUNBUFFERED=1 ';
if (isWin) { //for Windows
cmd = 'venv\\Scripts\\activate.bat && set PYTHONUNBUFFERED=1 && ';
}
var proc = exec(cmd + 'python manage.py runserver ' + serverUrl);
proc.stderr.on('data', function(data) {
process.stdout.write(data);
});
proc.stdout.on('data', function(data) {
process.stdout.write(data);
});
});
// start livereload
gulp.task('browser-sync', ['typescript', 'html', 'sass', 'webserver'], function() {
browserSync.init({
proxy: serverUrl,
port: 8080,
reloadDelay: 300,
reloadDebounce: 500
});
});
I assumed that you are talking about the static assets (stuff under static) in your django project.
The key step is to make the pages served by python manage.py runserver be aware of changes from the livereload server (usually implemented by tiny-lr)
A simple way to do so is to inject the following code to your base.html (assuming it as the parent template for the rest of html templates in django project)
# views.py
from django.conf import settings
# other imports ...
def index(request):
ctx = {'debug': settings.DEBUG, }
# other context setup...
return render(request, 'index.html', ctx)
# other views' definitions...
<!-- base.html -->
{% if debug %}
<!--
assuming your livereload server runs at localhost:35729
(default host:port for livereload )
-->
<script src="//localhost:35729/livereload.js"></script>
{% endif %}
// gulpfile.js
var gulp = require('gulp'),
gutil = require('gulp-util'),
coffee = require('gulp-coffee'),
livereload = require('gulp-livereload'),
debug = require('gulp-debug'),
watch = require('gulp-watch');
// other tasks definitions...
gulp.task('watch', function(){
livereload.listen(); // starts a tiny-lr server,
// default livereload server port is 35729
gulp.src('static/src/**/*.coffee')
.pipe(watch('static/src/**/*.coffee'))
.pipe(coffee())
.pipe(gulp.dest('static/dist'))
.pipe(livereload()); // send a signal to tiny-lr server
// to make the page with livereload.js
// to perform a reload action
})
I tried Frank Wile's answer, but I was having issues with it. The only way it worked for me with templates is if I saved a .py file and then made a change to a template.
I extended Frank's approach with a function that essentially touches a .py file before calling livereload.changed():
function touchPy() {
gulp.src(appName + '/__init__.py')
.pipe(gulp.dest(appName));
}
gulp.task('watch', function() {
livereload.listen();
// Changes to .css files works fine w/ Frank's approach
gulp.watch(paths.static).on('change', livereload.changed);
// Changes to .html files don't trigger a runserver refresh w/o touching a .py file
gulp.watch(paths.templates).on('change', function(file) {
touchPy();
livereload.changed(file);
});
});
You must include:
<script type="text/javascript" src="http://127.0.0.1:32700/livereload.js" />
to django main template. See http://argskwargs.io/blog/javascript/django-typescript-gulp-part-three/ . This is example for js and css files:
var gulp = require('gulp');
var watch = require('gulp-watch');
var livereload = require('gulp-livereload');
var gzip_options = {
threshold: '1kb',
gzipOptions: {
level: 9
}
};
gulp.task('css', function() {
return gulp.src('static/css/*.css')
.pipe(livereload());
});
gulp.task('js', function() {
return gulp.src('static/js/*.js')
.pipe(livereload());
});
/* Watch Files For Changes */
gulp.task('watch', function() {
livereload.listen(32700);
gulp.watch('static/css/*.css', ['css']);
gulp.watch('static/js/*.js', ['js']);
gulp.watch('static/css/*', 'static/js/*').on('change', livereload.changed);
});
gulp.task('default', ['css', 'js', 'watch']);
I'm writing a web crawler, but I only care about pages with responsive web design (RWD). Is there a tell-tale sign that the site is responsive? I am using the mechanize module in python.
The only thing I can think of is grepping the html for something like
href="css/bootstrap.min.css"
or
class="row-fluid"
or something that indicates percentages instead of pixels.
Any help would be appreciated.
My vote would be to search the page head for
<meta name="viewport" content="width=device-width, initial-scale=1.0" *** wildcard-selector-here *** >
I think it would be easier and more acurate than searching for the presence of CSS media queries.
Good luck!
I had a project where I needed to make the website responsive without touching any html markup and no programming code, the only thing I could modify was a stylesheet and a javascript file. I didn't even know which were all the pages of the website because it was a new project to me.
So the goal was to make it responsive so Google crawler won't penalize the site.
So I knew I could use https://www.google.com/webmasters/tools/mobile-friendly/ manually for the pages I wanted to test. But how could I test the whole site?
Well what I've done is to ask for a Webmaster Tools export of the most important links of the site, hundreds of them.
Then I've built a small "tool" that would do exactly what I think Google Responsive Test does, but this tool would accept a list of urls and would loop and test each of them if they fit on a 320px screen (iframe).
This is the HTML tool that you just open, type the urls in a text box, and hit Start! (responsiveChecker.html)
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>Responsive Checker</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="http://www.google.com/jsapi"></script>
<script>
var urls;
var delay=3000;
google.load("jquery", "1");
google.setOnLoadCallback(function() {
// Place init code here instead of $(document).ready()
console.log('jquery loaded');
$('#responsiveFrame').load(function(){
if (urls.length > 0) {
setTimeout(function(){ checkUrl(); }, delay);
}
});
});
function startChecking() {
var textUrls=$('#urls').val();
urls= textUrls.match(/[^\r\n]+/g);
checkUrl();
}
function checkUrl() {
var url;
if (urls.length > 0) {
url=urls[0];
console.log("checking: "+url);
$('#responsiveFrame').attr('src',url+'#rc=1');
urls.splice(0, 1);
} else {
console.log("no more urls");
}
}
</script>
</head>
<body>
<iframe id="responsiveFrame" width="320" height="480" src="about:blank" style="border: 1px solid red;" scrolling="no"></iframe>
<p>
<label for="urls">Enter URLs to check, one per line:</label><br />
<textarea id="urls" rows="30" cols="100"></textarea>
</p>
<p>
<input type="button" value="Start checking!" onclick="startChecking();">
</p>
</body>
</html>
This a script that must be loaded and run on the website you want to check:
var responsiveChecker = new function () {
this.width = 320;
this.hashParams={};
this.check = function () {
this.hashParams=this.parseHashBangArgs();
// this.log('responsiveChecker');
// this.log(this.hashParams);
if (!this.mustCheck()) {
return;
} else {
this.updateParams();
this.log('must check!');
var that = this;
var counter=0;
var visibleCounter=0;
jQuery("*").each(function() {
if (jQuery(this).width() > that.width) {
if ('SCRIPT' === this.tagName) {
// ignore script tags
} else {
that.log(this.tagName + "#" + this.id);
counter++;
if (jQuery(this).is(":visible")) {
visibleCounter++;
that.log(this.tagName + "#" + this.id);
}
}
}
});
var page=window.location.href;
if (visibleCounter > 0) {
this.log('[ERROR] page not responsive, there are elements bigger than screen size: '+page);
} else {
if (counter > 0) {
this.log('[WARNING] hey check the above list, there are some hidden elements with size bigger than the screen: '+page);
} else {
this.log('[SUCCESS] ¡todo bien! looks like all elements fit on the screen: '+page);
}
}
}
};
this.updateParams = function () {
if (typeof(this.hashParams.width) !== 'undefined') {
this.width=parseInt(this.hashParams.width);
}
};
this.mustCheck = function () {
if (typeof(this.hashParams.rc) !== 'undefined') {
return true;
}
return false;
};
// https://gist.github.com/miohtama/1570295
this.parseHashBangArgs = function() {
var aURL = window.location.href;
var vars = {};
var hashes = aURL.slice(aURL.indexOf('#') + 1).split('&');
for(var i = 0; i < hashes.length; i++) {
var hash = hashes[i].split('=');
if(hash.length > 1) {
vars[hash[0]] = hash[1];
} else {
vars[hash[0]] = null;
}
}
return vars;
};
this.log = function (msg) {
console.log(msg);
};
};
Place this at the end of a jquery ready:
responsiveChecker.check();
So finally how does it work:
You add the responsiveChecker javascripts on the website you want to check
You open the responsiveChecker.html file, add the urls of the site in the textarea and hit Start
It will start to load the urls in the iframe one by one, and on the Console tab of your browser it will log a "success", "warning" or "error", that means that either it is responsive, or maybe, or not responsive.
Let me know what you think!
By the way, does anybody think this could be useful if we clean it and build a real live tool/service that people could use to test their websites for responsiveness?
Oh btw: The actual checking is done with jQuery, by testing all the elements of the page that have a width smaller or equal to 320px. Indeed this is not 100% guarantee but I think Google's bot might be doing something like this but I'm sure it is more sophisticated.
I have very simple web page example read from html file using python. the html called led.html as in bellow:
<html>
<body>
<br>
<p>
<p>
<img src="images/on.png">
</body>
</html>
and the python code is:
import cherrypy
import os.path
import struct
class Server(object):
led_switch=1
def index(self, switch=''):
html = open('led.html','r').read()
if switch:
self.led_switch = int(switch)
print "Hellow world"
return html
index.exposed = True
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8080 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('images')
},
'/favicon.ico': { #favorite icon
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath("images/bulb.ico")
}
}
cherrypy.quickstart(Server(), config=conf)
The web page contain only one button called "on", when I click it I can see the text "Hello World " display on the terminal.
My question is how to make this text display on the web page over the "on" button after click on that button?
Thanks in advance.
You're going to want to use some kind of templating system. I use Jinja2 it's great!
Instead of...
html = open('led.html','r').read()
you would use...
import cherrypy
import os.path
import struct
from jinja2 import Template
class Server(object):
led_switch=1
def index(self, switch=''):
myText = ''
if switch:
self.led_switch = int(switch)
myText = "Please Wait"
html = Template("""
<html>
<body onload='setTimeout(function(){document.getElementById("UserMessage").innerHTML = "Ok! it's done"}, 5000)'>
<br>
<p id="UserMessage">{{ htmlText }}<p>
<img src="images/on.png">
</body>
</html>
""")
return html.render(htmlText=myText)
index.exposed = True
conf = {
'global' : {
'server.socket_host': '0.0.0.0', #0.0.0.0 or specific IP
'server.socket_port': 8080 #server port
},
'/images': { #images served as static files
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('images')
},
'/favicon.ico': { #favorite icon
'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath("images/bulb.ico")
}
}
cherrypy.quickstart(Server(), config=conf)
Hope this helps!
Andrew
If you do not want to use Jinja (to avoid extra dependencies) you could still use string formatting:
class Server(object):
led_switch=1
def index(self, switch=''):
myText = ''
if switch:
self.led_switch = int(switch)
myText = "Hellow world"
html = """
<html>
<body>
<br>
<p>{htmlText}
<p>
<img src="images/on.png">
</body>
</html>
"""
return html.format(htmlText=myText)