I am trying to use some javascript with my django code but have a small issue calling functions from the second js file.
I am using code from here https://github.com/mattdiamond/Recorderjs
I took the html file Matt made and removed the header and created a django template and then put the javascript files with my other static files. Those files (twitter bootstrap) all work fine.
If I open the sheet it loads fine with the record and stop buttons available. If you press them they are recorded in the log but any function that should be called in the recorderWorker.js is ignored. So I can not save the file or see it.
As far as I can tell it never calls the second javascript file. If I put alert boxes in the recorderWorker.js nothing happens but they work in the Recorder.js.
var WORKER_PATH = 'recorderWorker.js';
var Recorder = function(source, cfg){
I know it is not a problem with the code since I tested it using another Python webserver (SimpleHTTPServer) and it works great.
I have made no changes to the js files and only create this template for the html.
{% load staticfiles %}
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Live input record and playback</title>
<style type='text/css'>
ul { list-style: none; }
#recordingslist audio { display: block; margin-bottom: 10px; }
</style>
</head>
And then the html file
{% extends "base_record.html" %}
{% block content %}
<h1>Recorder.js simple WAV export example</h1>
<p>Make sure you are using a recent version of Google Chrome, at the moment this only works with Google Chrome Canary.</p>
<p>Also before you enable microphone input either plug in headphones or turn the volume down if you want to avoid ear splitting feedback!</p>
<button onclick="startRecording(this);">record</button>
<button onclick="stopRecording(this);" disabled>stop</button>
<h2>Recordings</h2>
<ul id="recordingslist"></ul>
<h2>Log</h2>
<pre id="log"></pre>
<script>
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
var audio_context;
var recorder;
function startUserMedia(stream) {
var input = audio_context.createMediaStreamSource(stream);
__log('Media stream created.');
input.connect(audio_context.destination);
__log('Input connected to audio context destination.');
recorder = new Recorder(input);
__log('Recorder initialised.');
}
function startRecording(button) {
// alert("start recording")
recorder && recorder.record();
button.disabled = true;
button.nextElementSibling.disabled = false;
__log('Recording...');
}
function stopRecording(button) {
// alert("Stopped recording")
recorder && recorder.stop();
button.disabled = true;
button.previousElementSibling.disabled = false;
__log('Stopped recording.');
// create WAV download link using audio data blob
createDownloadLink();
recorder.clear();
}
function createDownloadLink() {
recorder && recorder.exportWAV(function(blob) {
alert("download link")
var url = URL.createObjectURL(blob);
var li = document.createElement('li');
var au = document.createElement('audio');
var hf = document.createElement('a');
au.controls = true;
au.src = url;
hf.href = url;
hf.download = new Date().toISOString() + '.wav';
hf.innerHTML = hf.download;
li.appendChild(au);
li.appendChild(hf);
recordingslist.appendChild(li);
});
}
window.onload = function init() {
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
window.URL = window.URL || window.webkitURL;
audio_context = new AudioContext;
__log('Audio context set up.');
__log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
} catch (e) {
alert('No web audio support in this browser!');
}
navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
__log('No live audio input: ' + e);
});
};
</script>
{% endblock %}
<body>
{% block content %}
{% endblock %}
<script type="text/javascript" src="{% static 'bootstrap/js/recorder.js' %}"></script>
</body>
</html>
Here is my settings.py
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static"
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/home/kevin/Programming/accent/static/',
)
I also faced similar issue where recorderWorker.js was not being accessed. However, the problem was solved when I did the following:
'static/filename/recorderWorker.js'
Note: Assuming that your JS file is located in the folder 'filename' which is in the static folder.
As far as Django is concerned, it looks for static files like JS files into the static folder, since you did not specify the path it did not load the file.
Related
This question is not duplicate of
Conditionally load JavaScript file
and nor this
How to include an external javascript file conditionally?
I have gone through them, they are kind of similar to what I want to do but not exactly same. Here is how, in the above question the user just wants to load the script file once based on a condition. But in my case I want to load different js files based on click events.
So here in my case I have an HTML document:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Experiment</title>
<link href="s.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navigation">
<nav>
<ul>
<li id="home_btn"> Home</li>
<li id="about_btn"> About </li>
</ul>
</nav>
</div>
<canvas id="myCanvas">
</canvas>
<div class="notePane">
<p> This is just a bunch of text not explanation</p>
</div>
</body>
<script src="./exp.js" type="text/javascript"></script>
</html>
and this h.html file is linked to an exp.js file. Now in the exp.js file :
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var js = document.createElement("script");
js.type="module";
h_btn.addEventListener("click", showHome );
a_btn.addEventListener("click", showAbout);
function showHome() {
js.src="./j1.js";
head.appendChild(js);
}
function showAbout() {
js.src="./j2.js";
head.appendChild(js);
}
So things work fine when I click the h_btn on the web page. It loads j1.js. But then when I click on the a_btn on the web page I expect to see j2.js linked but I don't see it. I have to refresh the page and then click on a_btn to see j2.js linked. How do I link j1.js and j2.js such that I don't have to refresh the page again and again to load the correct script.
Update: OP has updated the question requirements such that he wants to "unload" a JS file when another is clicked. There is no way to undo all the runtime logic once a JS file is loaded: the only way is to reload the page. Removing the <script> tag or changing the src attribute will not magically unbind event listeners or "undeclare" variables.
Therefore, if OP wants to "start anew", the only way is to check if a custom script has been loaded before: if it has, we force reload the page. There are of course many ways to "inform" the next page which source to load, if available: in the example below, we use query strings:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
var appendedScriptKey;
var scripts = {
'home': './j1.js',
'about': './j2.js'
}
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Check query string if a specific script is set
var params = (new URL(document.location)).searchParams;
var scriptKey = params.get('scriptKey');
if (scriptKey && scriptKey in scripts) {
appendScript(scriptKey);
}
function appendScript(key) {
if (hasAppendedScript) {
location.href = location.href + (location.search ? '?' : '&') + 'script=' + key;
location.reload();
}
var js = document.createElement("script");
js.type="module";
js.src = scripts[key];
head.appendChild(js);
appendedScript = key;
}
function showHome() {
appendedScriptKey('home');
}
function showAbout() {
appendScript('about');
}
This is because of how Node.appendChild() works. The first click works because you're creating a new element and inserting it into your document. However, the second click will not work as you've expected because the node already exists:
The Node.appendChild() method adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild() moves it from its current position to the new position
This means that the second click will only mutate the src attribute of the already-injected <script> element instead of creating a new one, and that also means that the second script src will not be loaded.
A solution will be to use a function that will create a script tag every single time:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
function insertScript(src) {
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
But this will also mean that multiple clicks on the same button will cause the script to be injected multiple times. This does not affect browser performance much since the browser has the loaded script cached somewhere, but to guard against this, it might be a good idea to implement some kind of unique identifier per script, and check against that before injection. There are many ways to do this, and this is just one way:
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var head = document.getElementsByTagName("head")[0];
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
// Store scripts that you've injected
var scripts = [];
function insertScript(src) {
// If we have previously attempted injection, then do nothing
if (scripts.indexOf(src) !== -1) {
return;
}
var js = document.createElement("script");
js.type = "module";
js.src = src;
head.appendChild(js);
// Push script to array
scripts.push(src);
}
function showHome() {
insertScript('./j1.js');
}
function showAbout() {
insertScript('./j2.js');
}
Alternative unique script injection strategies and ideas:
Use ES6 Map() to track unique script sources being injected
Perhaps only store src to array/dict/map when the script has successfully loaded
You have to create the element twice, as there can only be one element with 1 src.
var h_btn = document.getElementById("home_btn");
var a_btn = document.getElementById("about_btn");
var js1 = document.createElement("script");
var js2 = document.createElement("script");
h_btn.addEventListener("click", showHome);
a_btn.addEventListener("click", showAbout);
function showHome() {
js1.src = "j1.js";
document.body.appendChild(js1);
}
function showAbout() {
js2.src = "j2.js";
document.body.appendChild(js2);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Experiment</title>
<link href="s.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navigation">
<nav>
<ul>
<li id="home_btn"> Home</li>
<li id="about_btn"> About </li>
</ul>
</nav>
</div>
<canvas id="myCanvas">
</canvas>
<div class="notePane">
<p> This is just a bunch of text not explanation</p>
</div>
</body>
<script src="exp.js" type="text/javascript"></script>
</html>
So, I've been working on a page that uses only local files (server is not an option, unfortunately. Not even a localhost. The struggle is real.) and I've come to a situation where I need to grab text from a .csv file and populate it to the page. I have this bit of code that works, but I need to have a file set within the function when a button is pressed. Looking up the file manually isn't an option (to visualize what I'm doing, I'm making a mock database file in the most annoying way possible (because I have to, not because I want to)).
In the page I would have something like:
<button id="myButton" onclick="getText()"></button>
<script>
var myFile = "dataset.csv";
...
</script>
The following bit of code works (in regards to having it pull the data from the csv file), but, as I said, I need to pull the text from the file when a button is pressed and just have the file name set in the script, not pulling it up manually.
<!DOCTYPE html>
<html>
<body>
<input type="file" id="fileinput" />
<div id="outputdiv"></div>
<script type="text/javascript">
function readSingleFile(evt) {
var f = evt.target.files[0];
if (f) {
var r = new FileReader();
r.onload = function(e) {
var contents = e.target.result;
var splited = contents.split(/\r\n|\n|\r|,/g);
for (i=0; i<splited.length; i++){
document.getElementById("outputdiv").innerHTML = document.getElementById("outputdiv").innerHTML + splited[i] + "<br>";
}
}
r.readAsText(f);
} else {
alert("Failed to load file");
}
}
document.getElementById('fileinput').addEventListener('change', readSingleFile, false);
</script>
</body>
</html>
From what I can tell from the API, I would need to set the file attributes to a blob in order to pass it to FileReader. How I can do this without using an input box, I have no idea. There's also a 50% chance that I am completely wrong about this since I obviously don't know how to get this done.
If someone could show me how to achieve this with regards to what I'm looking for, it would be very much appreciated. I'm absolutely stumped.
Thank you.
Note: CORS restrictons will prevent this from working in most browsers. You can use FireFox Developer Edition, which disables CORS validation.
You can use an XMLHttpRequest to load a local file:
<!DOCTYPE html>
<html>
<body>
<button onclick="readSingleFile()">Click Me</button>
<div id="outputdiv"></div>
<script type="text/javascript">
function readSingleFile() {
let xhr = new XMLHttpRequest();
let url = "relative/path/to/file.txt;
if (!url) return;
xhr.onload = dataLoaded;
xhr.onerror = _ => "There was an error loading the file.";
xhr.overrideMimeType("text/plain");
xhr.open("GET",url);
xhr.send();
}
function dataLoaded(e){
var contents = e.target.responseText;
var splited = contents.split(/\r\n|\n|\r|,/g);
for (i=0; i<splited.length; i++){
document.getElementById("outputdiv").innerHTML = document.getElementById("outputdiv").innerHTML + splited[i] + "<br>";
}
</script>
</body>
</html>
I'm using Flask to create a little WebApp. In the file.py there is a
render_template('index.html', listaimmagini = listaimmagini)
where "listaimmagini" is a list of images name (According to Flask standard, the images are in static folder). Now in "index.html" i'm trying to show these images but seems that webapp doesn't found it in static folder (there is the usual broken icon for all my images)
Where is the error in my code?
Index.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
window.onload = function(){
var img = [];
{% for imagelego in listaimmagini %}
img.push("{{url_for('static', filename = imagelego)}}");
{% endfor %}
var parent = document.getElementsByClassName('scroll')[0];
if(img.length>0){
parent.style.overflowY = 'scroll';
for(i=0;i<img.length;i++){
image = document.createElement('IMG');
image.src = img[i][0];
image.alt = '';
image.setAttribute("class", "scegli");
parent.appendChild(image);
}
</script>
I found a script to write the contents of a textbox to a text file, and show the download link.
But now I need help with modifying this code to save the text files in a specific location in the server once the button is clicked.
Here is the code:
<html>
<head>
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
(function () {
var textFile = null,
makeTextFile = function (text) {
var data = new Blob([text], {type: 'text/plain'});
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(data);
return textFile;
};
var create = document.getElementById('create'),
textbox = document.getElementById('textbox');
create.addEventListener('click', function () {
var link = document.getElementById('downloadlink');
link.href = makeTextFile(textbox.value);
link.style.display = 'block';
}, false);
})();
}//]]>
</script>
</head>
<body>
<textarea id="textbox">Type something here</textarea>
<button id="create">Create file</button>
<a download="info.txt" id="downloadlink" style="display: none">Download</a>
<script>
// tell the embed parent frame the height of the content
if (window.parent && window.parent.parent){
window.parent.parent.postMessage(["resultsFrame", {
height: document.body.getBoundingClientRect().height,
slug: "qm5AG"
}], "*")
}
</script>
</body>
</html>
Please advise.
You will need to learn backend development for server side practices. A client cant make any modification to the server without a backend in place. (That would be a huge security hole!) I would suggest learning NodeJS here: https://www.w3schools.com/nodejs/
Once you become more familiar and think you are ready to pick up this project again send me a direct message and I will point you in the right direction.
I'm working on this project and ran into some complications using AWS S3 to host images. So I pivoted and decided to store the image as a Blob and let Javascript do the work of transforming the file into and out of the Blob, so I could then use AJAX and the API to store it in our DB. While this might be less than ideal, I'm still learning Javascript and hadn't worked with blobs a lot so I figured why not, time to learn.
My issue is that when I try to use a DataURI to show the image on the page it comes out as a string and not a DataURI, and therefore loads as a broken image. I haven't worked in ajax yet because I thought it better to take the image, turn it into an ascii string, put it in a blob, then get it back out before involving the API/server. Here is my html:
{% extends 'mp_app/base.html' %}
{% load staticfiles %}
{% block content %}
<div id="page-wrapper">
<pre id="fileDisplayArea"></pre>
<form id="picForm" method='post'>
{% csrf_token %}
<input type="file" id='imgFile' name="pic" accept="image/*">
<input type="submit" id='submitBtn'>
<input type="submit" id="showBtn">
</form>
<div id="imageDisplay"></div>
</div>
{% endblock %}
{% block javascript %}
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<script type="text/javascript" src="{% static 'js/blob.js' %}"></script>
{% endblock %}
and my Javascript
//js file to turn an image into a blob, then store the blob in our API.
// next: retrive the blob and put it on the page
function textToImg(text) {
//get ascii string into binary then into an array then into a blob.
//had some strange issues using ArrayBuffer()
var file = new
Array(atob(document.getElementById('fileDisplayArea').innerText));
file = new Blob(file, {type:'image/*'});
let displayArea = document.getElementById('imageDisplay')
//currently doesn't seem to be loading as a DataURL. It's type is string and
//shows up as a broken image.
var reader = new FileReader();
reader.onload = function(event) {
var content = event.target.result;
img = new Image();
img.src = content;
displayArea.append(img)
console.log(img);
}
reader.onerror = function(event) {
console.error('error, file could not be read: ' +
event.target.error.code);;
}
reader.readAsDataURL(file);
// TODO get data via ajax to our DB our restful API
}
//turns an image into a blob
function imgToText() {
// get file elem and get image
let file = document.getElementById('imgFile');
let img = document.getElementById('imgFile').files[0];
let displayArea = document.getElementById('fileDisplayArea');
//open a file reader and read in file, then turn it from binary to ascii
var reader = new FileReader();
reader.onload = function(event) {
let contents = event.target.result;
//turn to ascii string
let asciiContents = btoa(contents);
//add ascii string to form
let form = {
'file': asciiContents,
}
displayArea.append(form.file);
};
reader.onerror = function(event) {
console.error('error, file could not be read');
}
//read file as a bit string
reader.readAsBinaryString(img);
// TODO send data via ajax to our DB our restful API
};
//add click event so that image is processed upon submit
$('#submitBtn').click(function(event) {
event.preventDefault();
imgToText();
});
$('#showBtn').click(function(event) {
event.preventDefault();
textToImg();
})
The img src reads as the blob string makes me think the something is wrong with the DataURI, perhaps it isn't getting the file in the proper format. I couldn't post a screen shot because I need a better reputation. Sorry this is so verbose but I wanted to try and make a quality post. Thank you!
I solved the issue. Will post here for future learners who may need this option.
textToImg() already has the string it needs, so all you need to do is get the string, add it to the file input element, (I added it as a 'value' attr), then let image.src = 'data:image/*;base64, + value attr. And you're good to go.