Cannot read property 'join' of undefined in Javascript file Electron JS - python

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);
});

Related

How to allow speech recogonition api in QWebEngineView

I have a small code
<!doctype html>
<head>
<title>JavaScript Speech to Text</title>
</head>
<body>
<h2>JavaScript Speech to Text</h2>
<p>Click on the below button and speak something...</p>
<p><button type="button" onclick="runSpeechRecognition()">Speech to Text</button> <span id="action"></span></p>
<div id="output" class="hide"></div>
<script>
/* JS comes here */
function runSpeechRecognition() {
// get output div reference
var output = document.getElementById("output");
// get action element reference
var action = document.getElementById("action");
// new speech recognition object
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
var recognition = new SpeechRecognition();
// This runs when the speech recognition service starts
recognition.onstart = function() {
action.innerHTML = "<small>listening, please speak...</small>";
};
recognition.onspeechend = function() {
action.innerHTML = "<small>stopped listening, hope you are done...</small>";
recognition.stop();
}
// This runs when the speech recognition service returns result
recognition.onresult = function(event) {
var transcript = event.results[0][0].transcript;
var confidence = event.results[0][0].confidence;
output.innerHTML = "<b>Text:</b> " + transcript + "<br/> <b>Confidence:</b> " + confidence*100+"%";
output.classList.remove("hide");
};
// start recognition
recognition.start();
}
</script>
</body>
It does not work on PyQtWebEngine
How to make it work.
I searched for it and found that only chromium based browser supports speech recogonition.
PyQtWebEngine is Chromium Based then How to make it work
Although this feature is available in chromium but it has been disabled by Qt as indicated in this report. Maybe in the following versions of Qt6 it will be enabled.

Simple AJAX example with Python not working

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.

Is it possible to configure Gulp Livereload for Django?

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']);

Responsive Web Design Detection for Crawler

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.

ASP.NET equivalent to Python's os.system([string])

I have an app made in Python, which accesses a Linux server's command prompt with os.system([string])
Now I'd like to transfer this away from Python, into some language like ASP.NET or something.
Is there a way to access the server's command prompt and run commands with ASP.NET or any technology found in Visual Studio?
This needs to run in a web app, where a user will click a button, and then a server-side command will run, so it's important that the technology suggested is compatible with all that.
Well it isn't ASP.net specific but in c#:
using System.Diagnostics;
Process.Start([string]);
Or With more access to the specific parts of running a program (like arguments, and output streams)
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c dir *.cs";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
here is how you could combine this with an ASPx Page:
First Process.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Process.aspx.cs" Inherits="com.gnld.web.promote.Process" %>
<!DOCTYPE html>
<html>
<head>
<title>Test Process</title>
<style>
textarea { width: 100%; height: 600px }
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="RunCommand" runat="server" Text="Run Dir" onclick="RunCommand_Click" />
<h1>Output</h1>
<asp:TextBox ID="CommandOutput" runat="server" ReadOnly="true" TextMode="MultiLine" />
</form>
</body>
</html>
Then the code behind:
using System;
namespace com.gnld.web.promote
{
public partial class Process : System.Web.UI.Page
{
protected void RunCommand_Click(object sender, EventArgs e)
{
using (var cmd = new System.Diagnostics.Process()
{
StartInfo = new System.Diagnostics.ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = "/c dir *.*",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true
}
})
{
cmd.Start();
CommandOutput.Text = cmd.StandardOutput.ReadToEnd();
};
}
}
}

Categories