createObjectURL unsupported in Opera - browser

Checking this adress: http://caniuse.com/#feat=bloburls you can see this is the only desktop browser with no support for this feature.
How can I find a workaround for this without to much change in my code?
var jpeg = NewBlob(imgData.array.buffer, "image/jpeg");
var url = DOMURL.createObjectURL(jpeg);

If your use case is to show a thumbnail of a picture the user selects, you can create a data uri for file she uploads. Tested under Opera 12.13 to work even with a couple meg image:
<script>
function handleFiles(files) {
var reader = new FileReader();
reader.onload = function(evt) {
document.getElementById("img1").src = evt.target.result;
}
reader.readAsDataURL(files[0]);
}
</script>
<img id="img1">
<form>
<input type="file" onchange="handleFiles(this.files)">
</form>

Related

How do I serve html,css and js as a post response while using CORS?

Trying to understand the best method to send html,css, js files back to the client via a Post request.
I'm running express,react.
What I have so far is a basic post route, that returns the compiled component with data (using handlebars) as a response. However the event handlers, css and js are absent. I'm not sure how to serve these along with the HTML as a response to an AJAX POST request on another domain.
I'm using webpack for SSR and figured this would work much the same but it doesn't.
Here is what i have so far...this just returns the html from my react component.
app.post("/", async (req, res) => {
const theHtml = `
<html>
<head><title>My First SSR</title>
<link href='http://localhost:8080/app.css'></link>
<script src="http://localhost:8080/app.js" charset="utf-8"></script>
<script src="http://localhost:8080/vendor.js" charset="utf-8"></script>
</head>
<body>
<h1>My First Server Side Render</h1>
<div id="reactele">{{{reactele}}}</div>
</body>
</html>
`;
const hbsTemplate = hbs.compile(theHtml);
const reactComp = renderToString(<App />);
const htmlToSend = hbsTemplate({ reactele: reactComp });
res.send(htmlToSend);
});
The above works and is returned just without js,css event handlers etc..
here is the App component
class App extends React.Component {
constructor() {
super();
this.handleButtonClick = this.handleButtonClick.bind(this);
this.handleTextChange = this.handleTextChange.bind(this);
this.handleReset = this.handleReset.bind(this);
this.state = {
name: "",
msg: ""
};
}
//Handlers
handleButtonClick = e => {
const nameLen = this.state.name.length;
if (nameLen > 0) {
this.setState({
msg: `You name has ${nameLen} characters including space`
});
}
};
handleTextChange = e => {
this.setState({ name: e.target.value });
};
handleReset = () => {
this.setState({ name: "", msg: "" });
};
//End Handlers
render() {
let msg;
if (this.state.msg !== "") {
msg = <p>{this.state.msg}</p>;
} else {
msg = "I have a state of none";
}
return (
//do something here where there is a button that will replace the text
<div>
<header className="App-header">
{/* <img src={logo} className="App-logo" alt="logo" /> */}
{/* <img src={logo} className="App-logo" alt="logo" /> */}
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<label>Your name </label>
<input
type="text"
id="txtName"
name="txtName"
value={this.state.name}
onChange={this.handleTextChange}
/>
<button id="btnSubmit" onClick={this.handleButtonClick}>
Calculate Name Length
</button>
<button id="btnReset" onClick={this.handleReset}>
Reset All
</button>
<hr />
{msg}
</div>
);
}
}
export default App;
On the client side i'm just appending the html to a blank page.
A few questions,
How do I maintain the eventhandlers on the requested html?
How do send the .css and .js along as well?
For some context, I'd like to avoid having to place and maintain 'client' code on my front-end server? My hope was something like webpack would handle this for me?
Thanks for any tips/suggestions.
EDIT:: To clarify this works if I access the route directly. I get the correlating js and css. Just not via a post request from another domain. I assume I'm missing some fundamental udnerstanding how the dom is maintained and scripts run.
You just need a static directory and a view renderer.
In your app.js or where ever you have initialized your express instance, add the following
var hbs = require('hbs');
var path = require('path');
var express = require('express');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
Now you can just put your html in a hbs file in a folder called 'views' and just return it like
app.post("/", (req, res) => {
res.render('index.hbs', {variable: 'value'});
});
For the static assets add the following lines
app.use(express.static(path.join(__dirname, 'public')));
and put your js and css or images or whatever static files you want in a folder named 'public' in your project root. These will be accessible at http://localhost:8080/app.js
So my issue was on client end (my second domain). It was how i was loading the html into the DOM, my old method was inneHTML on the body. Simple answer is this doesnt work.
I had to load it in another way, I chose to use jquery's .html(), this triggers the dom to evaluate the scripts etc.
#RohithBalaji your comment helped me find my issue.
Most AJAX APIs use the browser's .innerHTML to set the content. And
that will strip the and tags, but the scripts
will execute. But, since the head is stripped I am guessing they
aren't loading?

Download image from Express (Back-end) using React (Front-end)

I have an image stored in Express server. I have been trying to download the image using the following method in a React component.
<a href={my_image_url_from_state} download>Download Image</a>
But when i click on the 'Download Image' image is not downloaded. I see this error message:
I am able to display the same image in img tag, ie
<img src={my_image_url_from_state} />
that means nothing wrong with URL.
Do I need to make any changes in Express to download any files?
You need to write a function and invoke it on OnClick of the download button.
<button onClick={() => {download()}}>Download</button>
download function would be:
function download() {
var link = document.createElement('a');
link.href = 'images.jpg';
link.download = '<The URL of the image>';
document.body.appendChild(link);
link.click();
}
working code in reactJS class
class App extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<img onClick={() => { download(); }} src="<The URL of the image>" />
</div>
);
}
}
function download() {
var link = document.createElement('a');
link.href = 'images.jpg';
link.download = '<The URL of the image>';
document.body.appendChild(link);
link.click();
}
I ended up here because I was looking for a way to download an image in my React app from cloudinary and I found the snippet above as a useful starting point. I was getting the same error as Darshn. I speculate that perhaps the reason it wasn't working is that the backend origin url was different than the client app's origin.
I then researched and found that the download attribute of an anchor element only works for same-origin URLs. See The Anchor element
I then found an article on Soumitra Roy Sarkar's Roy Tutorials that I was able to incorporate into a solution.
I determined that since I was pulling from a different origin I would need to fetch the image, convert it to a Blob, create a URL for it, attach the url to the anchor tag.
Since I already was using the Cloudinary React SDK I was able to add the cloudinary-core to my dependencies.
yarn add cloudinary-core
Then I imported it into my module
import cloudinary from 'cloudinary-core';
const cloudinaryCore = new cloudinary.Cloudinary({cloud_name: '<My Cloudinary Cloud Name>'});
My download function looks like:
function download({publicKey, name}) {
const downloadUrl = `${cloudinaryCore.url(publicKey)}.jpg`;
fetch(downloadUrl)
.then((img) => img.blob())
.then((blob) => {
let url = window.URL.createObjectURL(blob);
let link = document.createElement('a');
link.href = url;
link.download = name;
link.click();
})
}
The function can be called by an html element like this:
<button onClick={() => {download({publicKey: '12345', name: 'image.jpg'})}}>Download</button>

What am i missing for the file upload using multipart form data ?

Hi for whatever reason i cannot use packages e.g. multer to upload file to node server. So i found example online, if just upload file in the form, it works fine.
Now i want to send another field "password" together with the file during submit, just cannot make it a work.
I do know there're plenty modules out there, for now just want to this example to work.
<form style="height: 100%;padding-bottom:63px;">
<p>
<input type="file" class="FirmwareFile"
name="myUpload" file-model="upload.newFwFile">
</p>
<p>
<input type="password" name="password" id="password"
placeholder="Password"
ng-model="upload.controllerPassword"
class="formInput">
</p>
</form>
httpSvc.uploadToUrl(myFile, myPd, myServerIPAddress, myRoute) {...}
factory.uploadToUrl = function (fwFile, pd, myServerIp, myRoute) {
var fd = new FormData();
//fd.append('passwd', pd); // cannot pass password to server side ?
fd.append('file', fwFile); // only this works
var deferred = $q.defer();
var completeUrl = ......
$http.post(completeUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (data) {
deferred.resolve(data);
}).error(function () {
deferred.reject();
});
return deferred.promise;
}
in server side, where to extract the password info please ?
var UploadImage = function(req, res, callback){
var destFile = fs.createWriteStream(uploadDest + "mytest");
var fileSize = req.headers['content-length'];
req.pipe(destFile); //why not sth. like req.body.file.pipe() ?
...
};
Your form does not have
<form enctype="multipart/form-data" action="..." method="...">
...
</form>
You will be better off using node-formidable. The example works straight out of the box. You might also want to look into angularJS specific form upload directives that have been made. No sense in reinventing the wheel.
Cheers

Nodejs/Express noob update page view no reload

I am using Node v.0.10.29 on Win XP SP3.
I am new to Node/Express.
I am trying to learn Node/Express by duplicating a existing PHP project.
http://stevenjsteele.com/database/
The PHP project allows the user to build a list of items
from either the materials, tools or equipment tables needed for a project,
without a page reload.
What I am having a hard time with (don't understand) is:
With the PHP project I can change tables using the select table
drop down without a page reload. This is done with a PHP echo and:
xmlHttp.open("POST","getpage.php?tablename="+str,true);
I initialize the app with:
var express = require('express'),
request = require('request'),
requirejs = require('requirejs'),
mysql = require('mysql'), // node-mysql module
path = require('path'),
bodyParser = require('body-parser'),
app = express();
var mh_connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password: ''
});
mh_connection.connect();
var materialhandler = router.route('/materialhandler');
materialhandler.get(function(req,res){
selecttools = 'tools';
selectelectrical = 'electrical';
selectequipment = 'equipment';
mh_connection.query('use materialhandler');
var strQuery = 'SELECT * FROM materialhandler.tools ORDER BY item_id';
mh_connection.query( strQuery, function(err, rows){
if(err) {
throw err;
}else{
tablename='Tools';
res.render('materialhandler',{title:"page title",data:rows});
res.end("");
}
});
});
In my node/express template (which is html) I use:
For the select option dropdown inside of a form,
I use: onchange="getData()"
<form id="theForm" action="/materialhandler">
<div class="tablepicker two-thirds column">
<select id="selectTable" onchange="getData()" class="selectpicker" name="selectpicker">
<optgroup>
<option name="" value="">Select Table</option>
<option name="tools" value="tools"><%=selecttools%></option>
<option name="electrical" value="electrical"><%=selectelectrical</option>
<option name="equipment" value="equipment"><%=selectequipment%</option>
</optgroup>
</select>
</div>
</form>
function getData() {
//console.log('begin');
var http = new XMLHttpRequest();
var selectedTable = selectTable.options[selectTable.selectedIndex].value;
http.open("POST", 'http://localhost:3000/materialhandler?selectpicker='+selectedTable, true);
http.setRequestHeader("Content-type", "application/x-www-form urlencoded");
http.onreadystatechange = function() {
console.log('onreadystatechange');
if (http.readyState == 4 && http.status == 200) {
//alert(http.responseText);
}
else {
console.log('readyState=' + http.readyState + ', status: ' + http.status);
}
}
//console.log('sending...')
http.send(selectedTable);
console.log(selectedTable)
//console.log('end');
$('#theForm').submit();
}
In terminal window console.log shows the selected table.
I am trying to change the tables without a page reload.
As I said at beginning I am just starting to learn this paradigm.
Any help or pointing in the right direction is appreciated.
Thanks.
The $('#theForm').submit(); is what's causing your page reload, but instead of doing it that way you can make your post request directly with javascript. jQuery would be a better alternative to XMLHttpRequest.
Instead of your getData() function, you can hook up some javascript to listen for select changes, and post them to your server like so:
$('#selectTable').on('change', function() {
$.post("materialhandler?selectpicker=" + $(this).val());
}

Using Nodejs (fs) to access files selected with input type=file

I am having trouble reading files in different locations (other than the Node project directory). I need to read a private key file (could be located anywhere on the file system) and transfer some yaml/yml files (also could be located anywhere) via sftp. These files are selected in a file input field which is accessed by a post method in my index.js (in Node). The problem is when I try to read the files I get an error that the file doesn't exist, specifically because the directory defaults to the Node project directory.
For example:
D:/path/to/Node/project
D:/this/is/where/the/keyis
It will try and read this file:
D:/path/to/Node/project/keyis
I'm not sure why I only get the filename. I know receiving the entire path is a security risk but I sort of need the path, even if it's not printed at any stage.
This is the code for the html form:
<form id="file-upload" name="uploadform" method="post" action="/upload" onsubmit="update()">
<input type='text' id='username' class="btn btn-lg btn-default" name='username' placeholder='Enter Username' style="color:#000"><br>
<h3>Select Key:</h3><input type='file' id='key-select' name='keySelect'><br>
<h3>Select Yaml:</h3><input type="file" id="file-select" name="yamlfiles[]" multiple accept=".yml, .yaml"/><br>
<button type="submit" class="btn btn-lg btn-default" id="upload">Upload Data</button>
</form>
and then in the index.js:
router.post('/upload', function(req,res) {
// Create a new connection
var fs = require('fs');
var Connection = require('ssh2');
var c = new Connection();
// Get the files to be uploaded
var files = req.body.yamlfiles;
var uname = req.body.username;
var key = req.body.keySelect;
...
...
c.connect(
{
host: 'some_host',
port: 22,
username: uname,
privateKey: fs.readFileSync(key)
}
);
Essentially readFileSync isn't working unless 'key' is in the project path. Is there something that I am missing? The same happens with 'files'.
Okay, I seem to have solved my own problem. For anyone that faces this problem in the future I will give a rough outline to my solution.
I needed to add: enctype="multipart/form-data" to my form. I had previously tried this, but I didn't understand what I needed to change on the server side. Using the nodejs module: https://github.com/andrewrk/node-multiparty I could parse the form data into a readable object. My server side code then became something like this:
router.post('/upload', function(req,res) {
// Create a new connection
var fs = require('fs');
var multiparty = require('multiparty');
var util = require('util');
var Connection = require('ssh2');
var c = new Connection();
// Get the files to be uploaded
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
// Each element of the object is an array
console.log("form parsed");
// yamlfiles is an array anyway
var yamlfiles = files.yamlfiles;
// username is just a text field, so the 0th element is username
var uname = fields.username[0];
// files is a single file, so the 0th element is my key
var key = files.keySelect[0];
...
...
// access key with key.path (will be a fakepath)
fs.readFileSync(key.path);
// access name with key.originalFilename
console.log(key.originalFilename);
After a bit of fiddling around It works perfectly. I hope this helps anyone else that faces this problem in the future and thank you very much to those who offered me assistance.

Resources