How can I iterate through all elements of local (server-side) folder? - javascript

Basically, I have a very simple website where the root directory looks like:
/images/
index.html
stuff.js
I want some way to recursively iterate through every file in the /images/ directory and display them in order in a section of my website. So for example, if /images/ contained:
images/a/a.png
images/b.png
images/c.jpg
....
then somewhere in index.html would contain:
<img src="images/a/a.png" />
<img src="images/b.png" />
<img src="images/c.jpg" />
....
My first idea was to do this using the document.write() function in stuff.js, but I couldn't find a good way to iterate through the local file directory in Javascript. I saw something about AJAX, but all of those examples involved editing an existing file, which I obviously don't want to do.
My current solution is just to manual create an array of strings containing all of the files in /images/, but doing this makes me think "There's got to be a better way!"
Let me know if I've been unclear.
Thanks!

Perhaps the best way to do this is to use a server-sided language to do it for you, and to use an asynchronous Javascript request to display the data.
This sample uses PHP to list all the files in a specified directory, and an xmlhttprequest to load this output and convert the results into image tags:
getimages.php:
<?php
//The directory (relative to this file) that holds the images
$dir = "Images";
//This array will hold all the image addresses
$result = array();
//Get all the files in the specified directory
$files = scandir($dir);
foreach($files as $file) {
switch(ltrim(strstr($file, '.'), '.')) {
//If the file is an image, add it to the array
case "jpg": case "jpeg":case "png":case "gif":
$result[] = $dir . "/" . $file;
}
}
//Convert the array into JSON
$resultJson = json_encode($result);
//Output the JSON object
//This is what the AJAX request will see
echo($resultJson);
?>
index.html (same directory as getimages.php):
<!DOCTYPE html>
<html>
<head>
<title>Image List Thing</title>
</head>
<body>
<div id="images"></div>
<input type="button" onclick="callForImages()" value="Load" />
<script>
//The div element that will contain the images
var imageContainer = document.getElementById("images");
//Makes an asynch request, loading the getimages.php file
function callForImages() {
//Create the request object
var httpReq = (window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");
//When it loads,
httpReq.onload = function() {
//Convert the result back into JSON
var result = JSON.parse(httpReq.responseText);
//Show the images
loadImages(result);
}
//Request the page
try {
httpReq.open("GET", "getimages.php", true);
httpReq.send(null);
} catch(e) {
console.log(e);
}
}
//Generates the images and sticks them in the container
function loadImages(images) {
//For each image,
for(var i = 0; i < images.length; i++) {
//Make a new image element, setting the source to the source in the array
var newImage = document.createElement("img");
newImage.setAttribute("src", images[i]);
//Add it to the container
imageContainer.appendChild(newImage);
}
}
</script>
</body>
</html>
Note that this is only an example. You'll probably want to make sure that the AJAX call is successful, and that the JSON conversion works both in the server code and on the client.

I stumbled on this article, as I was looking for the same thing, how to iterate through a list of files in a "Resources" folder, and display a webpage with clickable shortcuts to each of them.
Here's a clip of the webpage I ended up with:
Here's how I did it.
I added a very simple ASP.Net service, to iterate through the files in this folder...
List<OneResourceFile> listOfFilenames = new List<OneResourceFile>();
string Icon = "";
string localFolder = Server.MapPath("../Resources");
string[] fileEntries = Directory.GetFiles(localFolder);
foreach (string fileName in fileEntries)
{
string filename = System.IO.Path.GetFileName(fileName);
switch (Path.GetExtension(filename).ToLower())
{
case ".pptx":
case ".ppt":
Icon = "cssPowerPoint";
break;
case ".doc":
case ".docx":
Icon = "cssWord";
break;
case ".xlsx":
case ".xlsm":
case ".xls":
Icon = "cssExcel";
break;
default:
Icon = "cssUnknown";
break;
}
OneResourceFile oneFile = new OneResourceFile()
{
Filename = filename,
IconClass = Icon,
URL = "../Resources/" + filename
};
listOfFilenames.Add(oneFile);
}
string JSON = JsonConvert.SerializeObject(listOfFilenames);
return JSON;
..which built up a List of OneResouceFile records, each with a Filename, a CSS Class to apply to that shortcut (which would give it, say, an Excel icon, a PDF icon, etc) and a full URL of the item.
public class OneResourceFile
{
public string Filename { get; set; }
public string IconClass { get; set; }
public string URL { get; set; }
}
..and which returned a JSON set of results like this...
[
{
Filename: "Mikes Presentation.pptx",
IconClass: "cssPowerPoint",
URL: "~/Resources/Mikes Presentation.pptx"
},
{
Filename: "Mikes Accounts.xlsx",
IconClass: "cssExcel",
URL: "~/Resources/Mikes Accounts.xlsx""
}
]
Then, I just got some JQuery to call this web service, and create a a href for each item in the results:
<script type="text/javascript">
var URL = "/GetListOfResourceFiles.aspx"; // This is my web service
$.ajax({
url: URL,
type: 'GET',
cache: false,
dataType: "json",
success: function (JSON) {
// We've successfully loaded our JSON data
$.each(JSON.Results, function (inx) {
// Create one <a href> per JSON record, and append it to our list.
var thelink = $('<a>', {
text: this.Filename,
title: this.Filename,
href: this.URL,
class: this.IconClass
}).appendTo('#ListOfResources');
});
},
error: function (xhr, ajaxOptions, thrownError) {
alert("$.ajax error: " + xhr.status + " " + thrownError);
}
});
</script>
<p id="ListOfResources">
All you need then is to add some CSS styling for cssPowerPoint, cssExcel, etc, to give the a hrefs a relevant icon, for example:
.cssPowerpoint
{
vertical-align: top;
text-align: center;
background-repeat: no-repeat;
background-position: center 5px;
background-image: url(/Images/Icons/icnPowerPoint.png);
width: 100px;
height: 60px;
padding-top: 60px;
text-decoration: none;
display:inline-block;
color: #666;
margin-left: 20px;
}
And that's it. Cool, hey ?

Related

How set background img from MySQL database in javascript

I am using codelgniter, vanilla javascript , ajex, css, MySQL only
I want set background of image which store in mySQL database
The following code is working very well & not get error but problem is that how can I set background of image storage in database
Note the image is must be get using ajex ( xhr request respond )
The javascript create following css dynamically
.demo0::before {
Background: URL ("path");
}
.demo1::before {
Background: URL ("path");
}
.demo2::before {
Background: URL ("path");
}
And so on
I have following vanilla javascript
background_img=www.Demo.jpg; //temporary set
d_no=0;
Style0 = document.getElementByITagName("style")[0];
Style0.type="text/css";
Data=style0.innerHTML;
style0.innerHTML = data + "demo" d_no+"before { background: url("+ background_img +" );}";
d_no=d_no+1;
it is simple but tricky you need to make controller model of getting img src/url value in css or javascript or html url or src is may be path or image value
use following code
controller
<?php
class cover_img extends CI_Controller
{
public function index()
{
$getRequestData=stripslashes(file_get_contents("php://input"));
$datas=json_decode($getRequestData,true);
$this->load->model("cover_img_model","cim");
$this->cim->get_cover_img($datas["f_id"]);
}
}
?>
model
<?php
class cover_img_model extends CI_Model
{
function get_cover_img($username)
{
// echo $username;
$data=$this->db->query("select cover from user_detail where user_name='$username'");
foreach ($data->result_array() as $row)
{
echo "data:image/jpg;charset=utf8;base64,";
echo base64_encode($row['cover']);
}
}
}
?>
vanilla javascript
style0=document.getElementsByTagName("style")[0];
style0.type="text/css";
ccs_data=style0.innerHTML+"\n \n";
xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost/CI-social-media/index.php/cover_img", false);
obj = {"f_id":f_id}; // f_id is primary key field value for get the img using where condition in mysql change this f_id dynamically for getting different img
// alert(f_id);
data = JSON.stringify(obj);
xhr.onload = () => {
if (xhr.status == 200) {
if (xhr.response) {
style0.innerHTML = ccs_data +"\t "+ ".demo" + d_no + "::before{ \n\t\t background: url('"+xhr.responseText+"'); \n\t} ";
// alert(xhr.responseText);
}
else {
alert("something want wrong try agin later")
}
}
else {
alert("Something Want Wrong Try agin");
}
}
xhr.send(data);
document.getElementsByTagName('head')[0].appendChild(style0);
d_no=d_no+1;
If you get binary image from server:
<script>
fetch("/image") // url of binary image response
.then((response) => response.blob())
.then((myBlob) => {
const objectURL = URL.createObjectURL(myBlob);
document.querySelector('#body') // element selector, which has background
.style.backgroundImage = `url(${objectURL})`
});
</script>
If you have static image
<script>
fetch("/get-image.php") // url of php script, which returns url to static image
.then((response) => response.text())
.then((src) => {
document.querySelector('#body') // element selector, which has background
.style.backgroundImage = `url(${src})`
});
</script>

Loading Image Gallery taking too time in Razor View

I use a image gallery plugin called Unite Gallery plugin in an ASP.NET MVC project in order to display images stored in database. However, loading all of the images at the same time takes too long time (because each photo is in 1MB-4MB size and loading 500 photos at the same time on page load is not a good idea) and I think there must be a better approach i.e. asenkron loading or partial loading. Here is my Razor and Controller code. I have a look at many pages on the wweb and docs, but there is not an example in the documentation page. Do you have any idea?
<div id="gallery" style="display:none;">
#foreach (var item in Model)
{
if (item.FileData != null)
{
var base64 = Convert.ToBase64String(item.FileData);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img alt='Image'
src="#imgSrc"
data-image="#imgSrc"
data-description='Image'>
}
}
</div>
<script type="text/javascript">
jQuery(document).ready(function () {
var gallery = jQuery("#gallery").unitegallery({
gallery_theme: "default" //theme skin
});
gallery.on("item_change", function (num, data) {
if((num%15) == 0)
{
$.ajax({
url: '#Url.Action("List", "PhotoContest")',
data: { isAll: isAllChecked, page: num }, //??? I pass the page parameter???
success: function(data){
//call is successfully completed and we got result in data
//??? NO IDEA ???
},
error:function (xhr, ajaxOptions, thrownError){
//some errror, some show err msg to user and log the error
alert(xhr.responseText);
}
});
}
});
});
</script>
public ActionResult List(string query)
{
var model = db.Photo.Select(m => new PhotoViewModel
{
Id = m.Id,
Name = m.Name,
StatusId = m.StatusId,
SubmitDate = m.SubmitDate,
FileAttachments = m.FileAttachments,
SubmitNo = m.SubmitNo
})
.ToArray();
return View("List", model);
}
Update:
After trying to apply #Kris's perfect approach, I encountered the error shown below. There is not a fix or solution regarding to this specific problem on the web. Any idea?
The image after page load overloads div and gallery borders as shown below:
Load 30 images at a time
Load remaining in Itemchange event available in Unite gallery
Main Page
<div id="gallery" >
<input type="hidden" id="galleryPage" value="0"/>
#HTML.Action("GalleryImages") //first load 30 items as PageNo = 0
</div>
<script type="text/javascript">
var gallery;
jQuery(document).ready(function () {
gallery = jQuery("#gallery").unitegallery({
gallery_theme: "default" //theme skin
});
gallery.on("item_change", function (num, data) {
//when item loaded equals to 15 or 30 or multiples of 15 another 30 items get loaded
if((num%15) == 0)
{
$.ajax({
url: '#HTML.Action("GalleryImages")'+"?pageNo="+jQuery("galleryPage").val(),
data: { isAll: isAllChecked },
success: function(data){
jQuery("gallery").append(data);//partial view with new images
jQuery("galleryPage").val(gallery.getNumItems()/30); //page number total items/number of items per page
},
error:function (xhr, ajaxOptions, thrownError){
//some errror, some show err msg to user and log the error
alert(xhr.responseText);
}
});
}
});
});
</script>
Partial View (_galleryImages.cshtml)
#foreach (var item in Model)
{
if (item.FileData != null)
{
var base64 = Convert.ToBase64String(item.FileData);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img alt='Image'
src="#imgSrc"
data-image="#imgSrc"
data-description='Image'>
}
}
Controller
//Main View
public ActionResult List()
{
return View();
}
//Partial View
public Action GalleryImages(int PageNo)
{
int PageSize = 30;
var model = db.Photo.Select(m => new PhotoViewModel
{
Id = m.Id,
Name = m.Name,
StatusId = m.StatusId,
SubmitDate = m.SubmitDate,
FileAttachments = m.FileAttachments,
SubmitNo = m.SubmitNo
}).Skip(PageNo*PageSize).Take(PageSize).ToArray();
return PartialView("_galleryImages", model);
}
I don't think there's just one issue here. First, loading 100s of images all at once is going to be slow no matter what you do. For this point #Kris probably has the right idea. I'm unfamiliar with this particular library, but if it provides a way to progressively load in a handful of images at a time, you should definitely make use of that.
The second issue is that you're using base64-encoded data URIs. Images encoded in this way are roughly 150% as large as the actual image data itself. In other words, you're adding greater stress to an already stressed situation. Instead, you should have an action that returns the image data, something like:
public ActionResult GetImage(int id)
{
var image = db.Images.Find(id);
if (image == null)
{
return new HttpNotFoundResult();
}
return File(image.FileData, image.FileType);
}
You can get somewhat creative here by caching the database query result or even the entire response, but be advised that you'll need a significant amount of RAM, since you're going to be storing a lot of image data there.
Third, there's the issue of using a database to store image data in the first place. Just because databases provide a blob type, doesn't mean you need to use it. The most performant approach is always going to be serving directly from the filesystem, as IIS can serve static files directly, without involving all the ASP.NET machinery. Instead of storing the image data in your database, write the image to a filesystem location and then merely store the path to the image in the database. You could then optimize even further by actually offloading all the images to a CDN, ensuring super-fast delivery and taking virtually all load off your server.

How to upload base64 image resource with dropzone?

I'm trying to upload generated client side documents (images for the moment) with Dropzone.js.
// .../init.js
var myDropzone = new Dropzone("form.dropzone", {
autoProcessQueue: true
});
Once the client have finished his job, he just have to click a save button which call the save function :
// .../save.js
function save(myDocument) {
var file = {
name: 'Test',
src: myDocument,
};
console.log(myDocument);
myDropzone.addFile(file);
}
The console.log() correctly return me the content of my document
data:image/png;base64,iVBORw0KGgoAAAANS...
At this point, we can see the progress bar uploading the document in the drop zone but the upload failed.
Here is my (standart dropzone) HTML form :
<form action="/upload" enctype="multipart/form-data" method="post" class="dropzone">
<div class="dz-default dz-message"><span>Drop files here to upload</span></div>
<div class="fallback">
<input name="file" type="file" />
</div>
</form>
I got a Symfony2 controller who receive the post request.
// Get request
$request = $this->get('request');
// Get files
$files = $request->files;
// Upload
$do = $service->upload($files);
Uploading from the dropzone (by drag and drop or click) is working and the uploads are successfull but using the myDropzone.addFile() function return me an empty object in my controller :
var_dump($files);
return
object(Symfony\Component\HttpFoundation\FileBag)#11 (1) {
["parameters":protected]=>
array(0) {
}
}
I think i don't setup correctly my var file in the save function.
I tryied to create JS image (var img = new Image() ...) but without any success.
Thanks for your help !
Finally i found a working solution without creating canvas :
function dataURItoBlob(dataURI) {
'use strict'
var byteString,
mimestring
if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
byteString = atob(dataURI.split(',')[1])
} else {
byteString = decodeURI(dataURI.split(',')[1])
}
mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]
var content = new Array();
for (var i = 0; i < byteString.length; i++) {
content[i] = byteString.charCodeAt(i)
}
return new Blob([new Uint8Array(content)], {type: mimestring});
}
And the save function :
function save(dataURI) {
var blob = dataURItoBlob(dataURI);
myDropzone.addFile(blob);
}
The file appears correctly in dropzone and is successfully uploaded.
I still have to work on the filename (my document is named "blob").
The dataURItoBlob function have been found here : Convert Data URI to File then append to FormData
[EDIT] : I finally wrote the function in dropzone to do this job. You can check it here : https://github.com/CasperArGh/dropzone
And you can use it like this :
var dataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmAAAAKwCAYAAA...';
myDropzone.addBlob(dataURI, 'test.png');
I can't comment currently and wanted to send this to you.
I know you found your answer, but I had some trouble using your Git code and reshaped it a little for my needs, but I am about 100% positive this will work for EVERY possible need to add a file or a blob or anything and be able to apply a name to it.
Dropzone.prototype.addFileName = function(file, name) {
file.name = name;
file.upload = {
progress: 0,
total: file.size,
bytesSent: 0
};
this.files.push(file);
file.status = Dropzone.ADDED;
this.emit("addedfile", file);
this._enqueueThumbnail(file);
return this.accept(file, (function(_this) {
return function(error) {
if (error) {
file.accepted = false;
_this._errorProcessing([file], error);
} else {
file.accepted = true;
if (_this.options.autoQueue) {
_this.enqueueFile(file);
}
}
return _this._updateMaxFilesReachedClass();
};
})(this));
};
If this is added to dropzone.js (I did just below the line with Dropzone.prototype.addFile = function(file) { potentially line 1110.
Works like a charm and used just the same as any other. myDropzone.addFileName(file,name)!
Hopefully someone finds this useful and doesn't need to recreate it!
1) You say that: "Once the client have finished his job, he just have to click a save button which call the save function:"
This implies that you set autoProcessQueue: false and intercept the button click, to execute the saveFile() function.
$("#submitButton").click(function(e) {
// let the event not bubble up
e.preventDefault();
e.stopPropagation();
// process the uploads
myDropzone.processQueue();
});
2) check form action
Check that your form action="/upload" is routed correctly to your SF controller & action.
3) Example Code
You may find a full example over at the official Wiki
4) Ok, thanks to your comments, i understood the question better:
"How can i save my base64 image resource with dropzone?"
You need to embedd the image content as value
// base64 data
var dataURL = canvas.toDataURL();
// insert the data into the form
document.getElementById('image').value = canvas.toDataURL('image/png');
//or jQ: $('#img').val(canvas.toDataURL("image/png"));
// trigger submit of the form
document.forms["form1"].submit();
You might run into trouble doing this and might need to set the "origin-clean" flag to "true". see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#security-with-canvas-elements
how to save html5 canvas to server

How do you access other files stored on an website with JavaScript?

I am trying to write a webpage for a list of files to download. The files are stored with the webpage and I want the webpage to dynamically list all the files in the folder to download. That way when more are added I don't have to modify the webpage. I know how to use JavaScript to create links on the webpage but I need to use it to find the names of the files first.
I found a website that had code for navigating files like a file browser but it only uses a string to store the current location.
This is in the header:
<script type="text/javascript"><!--
var myloc = window.location.href;
var locarray = myloc.split("/");
delete locarray[(locarray.length-1)];
var fileref = locarray.join("/");
//--></script>
this is in the body:
<form>
<input type=button value="Show Files" onClick="window.location=fileref;">
</form>
However this doesn't really help since I am trying to create download links to files not have a file browser.
Edit:
When you host a traditional HTML page you upload the htmlfile and any images or content for the page to what ever server you use.
I want to use javascript to dynamically link to every file hosted with the webpage.
I am trying to combine this with hosting the files in a Dropbox public folder for a simple way to make the files available.
If you want a list of files on the server you will need to use a server-side script to gather their names:
JS--
//use AJAX to get the list of files from a server-side script
$.getJSON('path/to/server-side.php', { 'get_list' : 'true' }, function (serverResponse) {
//check the response to make sure it's a success
if (serverResponse.status == 'success') {
var len = serverResponse.output.length,
out = [];
//iterate through the serverResponse variable
for (var i = 0; i < len; i++) {
//add output to the `out` variable
out.push('<li>' + serverResponse.output[i] + '</li>');
}
//place new serverResponse output into DOM
$('#my-link-container').html('<ul>' + out.join('') + '</ul>');
} else {
alert('An Error Occured');
}
});
PHP--
<?php
//check to make sure the `get_list` GET variable exists
if (isset($_GET['get_list'])) {
//open the directory you want to use for your downloads
$handle = opendir('path/to/directory');
$output = array();
//iterate through the files in this directory
while ($file = readdir($handle)) {
//only add the file to the output if it is not in a black-list
if (!in_array($file, array('.', '..', 'error_log'))) {
$output[] = $file;
}
}
if (!empty($output)) {
//if there are files found then output them as JSON
echo json_encode(array('status' => 'success', 'output' => $output));
} else {
//if no files are found then output an error msg in JSON
echo json_encode(array('status' => 'error', 'output' => array()));
}
} else {
//if no `get_list` GET variable is found then output an error in JSON
echo json_encode(array('status' => 'error', 'output' => array()));
}
?>

Temporarily unzip a file to view contents within a browser

I want to unzip a file that contains an html page, css, and js directories. I want to unzip this temporarily and view the html in an iFrame, preferrably. I am using jszip which is working. I got the html to load, but how do I add the image, js, and css folders into the iFrame?
Here is what I have so far...
<div id="jszip_utils"></div>
<iframe id="iframe"></iframe>
<script type="text/javascript">
function showError(elt, err) {
elt.innerHTML = "<p class='alert alert-danger'>" + err + "</p>";
}
function showContent(elt, content) {
elt.innerHTML = "<p class='alert alert-success'>loaded !<br/>" +
"Content = " + content + "</p>";
}
var htmltext = JSZipUtils.getBinaryContent("/zip/myWebsite.zip", function (err, data) {
var elt = document.getElementById('jszip_utils');
if (err) {
showError(elt, err);
return;
}
try {
JSZip.loadAsync(data)
.then(function (zip) {
for(var name in zip.files) {
if (name.substring(name.lastIndexOf('.') + 1) === "html") {
return zip.file(name).async("string");
}
}
return zip.file("").async("string");
})
.then(function success(text) {
$('#iframe').contents().find('html').html(text);
showContent(elt, text);
}, function error(e) {
showError(elt, e);
});
} catch(e) {
showError(elt, e);
}
});
</script>
This gets the html, but the js css and image files are not showing up. I believe I need to do some sort of fake routing, but I'm not sure how I would be able to do that. Thanks for your help.
If the html/js in the zip is not too complicated, for instance an AngularJS app that has routes for partials, this is possible.
The trick is to replace css,js,img src/href urls that point to a file in the zip with either:
Object Url: URL.createObjectURL(Blob or File object);
Data Url: data:[<mediatype>][;base64],<data>
Or in the case of js and css inject the content directly into the appropriate element
After replacing the src/href references than just inject the new html into the iframe.
Step 1: Parse the html so you can manipulate it
//html from a call like zip.file("index.html").async("string")
let parser = new DOMParser;
let doc = parser.parseFromString(html,"text/html");
Step 2: Find all elements with a relative path (e.g. /imgs/img.jpg) as they are easier to deal with as you can then use that path for zip.file
//Simply finds all resource elements, then filters all that dont start with '/'
var elements = jQuery("link[href],script[src],img[src]",doc).filter(function(){
return /^\//.test(this.href || this.src);
});
Step 3: Replace src,href with object url, data url, or direct content
//assume element is the html element: <script src="/js/main.js"></script>
zip.file(element.src).async("string").then(jsText=>{
element.src = "data:text/javascript,"+encodeURIComponent(jsText);
});
Step 4: Get the new html text and inject it into the iframe
let newHTML = doc.documentElement.outerHTML;
var viewer = document.querySelector('#iframeID');
viewer = viewer.contentWindow || viewer.contentDocument.document || viewer.contentDocument;
viewer.document.open();
viewer.document.write(html);
viewer.document.close();
JSFiddle Demo - Demonstrates replacing the src/href urls
As a security note, if you are using zip files that you do not know the contents of, you should run the whole app in a protected iframe

Categories

Resources