Is there a way to optimise this? - javascript

I'm not very good with HTML and but I'm trying to make a website that will load Discord servers the user is in. I got the servers in map format, but loading them is very slow. Is there a way the time could be reduced? Any help is greatly appreciated!
My HTML
<!DOCTYPE html>
<head>
<title>NULL MUCH?</title>
<style>
.server {
width:200px;
height:200px;
object-fit:cover;
border-radius:50%;
}
.serverImgIn {
width:100px;
height:100px;
object-fit:cover;
border-radius:50%;
border-color: rgb(0, 89, 190);
}
.serverImgOut {
width:100px;
height:100px;
object-fit:cover;
border-radius:50%;
cursor: pointer;
filter: grayscale(100%);
}
.serverRow {
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
}
</style>
</head>
<body>
<div id="wrapper">
<!-- PLACEHOLDER TEXT HERE -->
</div>
<script>
window.onload = () => {
const guilds = {the guilds in JSON format}
var wrapper = document.getElementById('wrapper');
var row = document.createElement("servers_row");
row.innerHTML = ""; // clear images
row.classList.add('serverRow');
for (let i = 0; i < guilds.length; i++) {
//New row every 10 servers
if (i % 10 == 0) {
wrapper.appendChild(row);
row.innerHTML = "";
row.classList.add('serverRow');
}
var div = document.createElement("div");
var imagem = document.createElement("img");
var name = document.createElement("p");
name.innerText = guilds[i].name;
if (guilds[i].icon) {
imagem.src = `https://cdn.discordapp.com/icons/${guilds[i].id}/${guilds[i].icon}.png`;
} else {
imagem.src = 'http://purepng.com/public/uploads/large/purepng.com-white-cloudnaturestylenaturalbeautifulgreen-5415211264555x7ih.png';
}
if (guilds[i].inServer) {
//OPEN A NEW WINDOW FOR SERVER EDITING
imagem.onclick = function() {
imagem.classList.add('serverImgIn');
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:53134/getServer/', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
xhr.setRequestHeader('guilds', JSON.stringify(owned));
xhr.onloadend = (e) => { window.localStorage.setItem('serverInfo', (JSON.stringify(xhr.response))); window.location = 'http://localhost:53134/dashboard.html'; }
xhr.send(JSON.stringify(owned));
}
} else {
imagem.classList.add('serverImgOut');
imagem.onclick = function() {
window.open('DISCORD INVITE LINK HERE');
}//OPEN A NEW WINDOW WITH SERVER INVITE
}
div.appendChild(imagem);
div.appendChild(name);
div.classList.add('server');
row.appendChild(div);
}
wrapper.appendChild(row);
}
</script>
</body>
As a note I'm not sure if adding the onclick function in the loop increases the time, because It's not actually being called.
This is what it looks like on my end but to test it I think you'll have to pass in dummy data (I use the Discord API to get my data)

Related

Appending JS to the HTML

I am trying to append my variables 'showName' and 'showDescription' to the 'results' div object. I have tried to add them in using 'innerHTML' but I just get the description shown. I have tried making additional divs to put INSIDE the 'results' div but that didn't work either.
I want the 'showName' to appear above the 'showDescription in the div.
I am challenging myself to not use JQuery so that is not a viable option.
code:
document.querySelector('.search').addEventListener('keypress', function(e){//On button click of enter, get the value of the search bar and concatanate it to the end of the url
if(e.key==='Enter'){
var query = document.getElementById('main').value;
var url = fetch("http://api.tvmaze.com/search/shows?q="+query) //use fetch to get the data from the url, THEN convert it to json THEN console.log the data.
.then(response => response.json())
.then(data => {
console.log(data)
var domObject = document.createElement('div')
domObject.id="myDiv";
domObject.style.width="800px";
domObject.style.height="5000px";
domObject.style.display="flex";
domObject.style.flexDirection="column";
domObject.style.margin="auto";
domObject.style.borderRadius="30px";
domObject.style.background="";
document.body.appendChild(domObject);
for (var i = 0; i < data.length; i++) { //for all the items returned, loop through each one and show the name of the show and the dsescription of the show.
var showName = data[i].show.name;
//console.log(showName);
var showDescription = data[i].show.summary
//console.log(showDescription);
var results = document.createElement('div')
results.id="myResults";
results.style.width="600px"
results.style.height="400px";
results.style.background="white";
results.style.margin="auto";
results.style.borderRadius="30px";
results.style.fontFamily="Poppins"
results.style.display="flex";
results.style.flexDirection="column";
results.innerHTML=showName;
results.innerHTML=showDescription;
document.getElementById("myDiv").appendChild(results);
}
})
}
});
document.querySelector('.search').addEventListener('keydown', function(o){
if(o.key==='Backspace'){
location.reload();
}
});
result of searching in 'car'
results.innerHTML = showName;
results.innerHTML = showDescription;
With this you are overwriting showName with showDescription.
What you need to do is concatenate with +=.
Also, it will be much easier to replace this:
domObject.style.width = "800px";
domObject.style.height = "5000px";
domObject.style.display = "flex";
domObject.style.flexDirection = "column";
domObject.style.margin = "auto";
domObject.style.borderRadius = "30px";
domObject.style.background = "";
with domObject.classList.add('some-class');
and CSS will be:
.some-class {
width: 800px;
height: 500px;
// etc...
}
Moved your code to a working example.
Note: because of authors styles, it is only possible to run snippet in fullscreen. =)
const dosearch = () => {
var query = document.getElementById('main').value;
var url = fetch("https://api.tvmaze.com/search/shows?q=" + query)
.then(response => response.json())
.then(data => {
const myDiv = document.getElementById("myDiv");
myDiv.innerHTML = ''; // <---- this is for testing
for (var i = 0; i < data.length; i++) {
var showName = data[i].show.name;
var showDescription = data[i].show.summary
var results = document.createElement('div');
results.className = 'myResults';
var header = document.createElement('h2');
header.innerHTML = showName;
results.appendChild(header);
var desc = document.createElement('div');
desc.innerHTML = showDescription;
results.appendChild(desc);
myDiv.appendChild(results);
}
});
}
document.querySelector('.search').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
dosearch();
}
});
#myDiv {
width: 800px;
height: 5000px;
display: flex;
flex-direction: column;
margin: auto;
border-radius: 30px;
background: black;
}
.myResults {
width: 600px;
height: 400px;
background: white;
margin: auto;
border-radius: 30px;
font-family: Poppins;
display: flex;
flex-direction: column;
}
.myResults p, .myResults h2 {
margin: 1em;
}
<input type="text" id="main" class="search" style="margin-bottom: 4px" value="Car" /><button onclick="dosearch()">Go</button>
<div id="myDiv"></div>

How to display uploaded image in CSS background URL property using input file API - vanilla Javascript

The initial project had an array with file names stored in there and the image slider would display them.
I am trying to create the upload functionality where the user can upload an image and that image would then be pushed to the array.
I've tried utilizing the URL.createObjectURL method on the uploaded file and pushing it to the display but there's an error when the slide arrives at the array index.
The file comes out as 'blob:http etc...' and so i've tried removing 'blob' from the string and still receiving an error.
HTML:
<div id="container">
<button class="button" id="leftButton"><i class="fa fa-arrow-left"></i></button>
<button class="button" id="rightButton"><i class="fa fa-arrow-right"></i></button>
</div>
<div class="upload">
<p><input type='file' name='image' id="input"></p>
</div>
CSS:
#container {
margin: 100px auto;
height: 500px;
width: 900px;
border: 7px solid #3e92cc;
border-radius: 10px;
background: url('images/one.jpg');
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
Javascript:
let container = document.getElementById("container");
let rightButton = document.getElementById("rightButton");
let leftButton = document.getElementById("leftButton");
let images = ["one.jpg", "two.jpg", "three.jpg", "four.jpg", "five.jpg"];
let imagesIndex = 0;
const inputElement = document.getElementById("input");
let newURL;
//Add background to slider
function addBackground() {
if (!images[imagesIndex].includes('http')) {
container.style.background = `url('images/${images[imagesIndex]}')`;
} else {
container.style.background = `url('${images[imageIndex]}')`;
}
container.style.backgroundPosition = "center";
container.style.backgroundRepeat = "no-repeat";
container.style.backgroundSize = "cover";
}
// upload files
function handleFiles() {
const fileList = this.files; /* now you can work with the file list */
const objectURL = window.URL.createObjectURL(fileList[0]);
//remove 'blob:';
newURL = objectURL.replace('blob:', '');
console.log(newURL);
images.push(newURL);
}
// Event listeners
inputElement.addEventListener("change", handleFiles, false);
rightButton.addEventListener("click", function () {
imagesIndex++;
if (imagesIndex >= images.length) {
imagesIndex = 0;
}
console.log(imagesIndex);
addBackground();
})
leftButton.addEventListener("click", function () {
imagesIndex--;
if (imagesIndex < 0) {
imagesIndex = images.length - 1;
}
console.log(imagesIndex);
addBackground();
})
Don't remove blob: it's required in the URL scheme
// upload files
function handleFiles() {
const fileList = this.files; /* now you can work with the file list */
const objectURL = window.URL.createObjectURL(fileList[0]);
//remove 'blob:';
//newURL = objectURL.replace('blob:', '');
console.log(objectURL);
images.push(objectURL);
}
Corrected typo in imagesIndex
//Add background to slider
function addBackground() {
if (!images[imagesIndex].includes('http')) {
container.style.background = `url('images/${images[imagesIndex]}')`;
} else {
container.style.background = `url('${images[imagesIndex]}')`;
}
//.. other code
}

How transfer files (or folders) via Ajax by d'n'd?

I want to upload folder to server by d'n'd via AJAX. But already, I have troubles with upload files.
I use e.dataTransfer.items and webkitGetAsEntry() to check - is it file or folder?
If it's file, in function traverseFileTree I get file, but I can't append it to formData.
If I use e.dataTransfer.files, I don't know what is it. File or Folder because webkitGetAsEntry() get error.
What I do wrong?
How transfer files to global array $_FILES.
Source (upload.php):
echo "<pre>";
print_r ($_FILES);
echo "</pre>";
Source (index.html):
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<style>
body {
background: rgba(211,211,100, .5);
font: 20px Arial;
}
.dropzone {
width: 300px;
height: 300px;
border: 2px dashed #aaa;
color: #aaa;
line-height: 280px;
text-align: center;
position: absolute;
left: 50%;
margin-left: -150px;
top: 50%;
margin-top: -150px;
}
.dropzone.dragover {
color: green;
border: 2px dashed #000;
}
</style>
</head>
<body>
<p>Loaded files:</p>
<div id="uploads">
<ul>
</ul>
</div>
<div class="dropzone" id="dropzone">Drop files</div>
<script>
(function() {
var formData = new FormData();
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(e) {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
e.preventDefault();
upload(e.dataTransfer.items);
};
function traverseFileTree(item, path) {
path = path || "";
if (item.isFile) {
item.file(function(file) {
console.log(file); // show info
formData.append('file[]', file); // file exist, but don't append
});
} /*else if (item.isDirectory) {
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
for (var i=0; i<entries.length; i++) {
traverseFileTree(entries[i], path + item.name + "/");
}
});
}*/
}
var upload = function(items) {
var xhr = new XMLHttpRequest();
for(var i = 0; i < items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
traverseFileTree(item,'');
}
}
xhr.onload = function() {
console.log(this.responseText);
};
xhr.open('post', 'upload.php');
xhr.send(formData);
};
dropzone.ondragover = function() {
this.className = 'dropzone dragover';
this.innerHTML = 'Mouse up';
return false;
};
dropzone.ondragleave = function() {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
return false;
};
})();
</script>
Both file() and readEntries() return results asynchronously. Since it is impossible to know for certain how many files or directories, which themselves could contain additional directories containing still more files or folders, will be selected and dropped by user, the a single or recursive calls to traverseFileTree require some mechanism to determine when all asynchronous operations have completed. This can be achieved using one or more of several approaches.
The present approach increments a variable n, pushes each individual file to an array uploads. If n is 0, process the first file; increment n so that its value 1 greater than the array containing files .length until the array .length is equal to n - 1
uploads.length === n - 1 || n === 0
then copy uploads array using .slice(), set uploads.length and n to 0, pass array of files to function processFiles where files are appended to FormData() object, call to XMLHttpRequest() is made.
<!DOCTYPE html>
<html>
<head>
<title>Drag and Drop</title>
<style>
body {
background: rgba(211, 211, 100, .5);
font: 20px Arial;
}
.dropzone {
width: 300px;
height: 300px;
border: 2px dashed #aaa;
color: #aaa;
line-height: 280px;
text-align: center;
position: absolute;
left: 50%;
margin-left: -150px;
top: 50%;
margin-top: -150px;
}
.dropzone.dragover {
color: green;
border: 2px dashed #000;
}
</style>
</head>
<body>
<p>Loaded files:</p>
<div id="uploads">
<ul>
</ul>
</div>
<div class="dropzone" id="dropzone">Drop files</div>
<script>
(function() {
var n = 0, uploads = [];
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(e) {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
e.preventDefault();
upload(e.dataTransfer.items);
};
function processFiles(files) {
console.log("files:", files);
alert("processing " + files.length + " files");
var formData = new FormData();
// append files to `formData`
for (file of files) {
formData.append("file[]", file, file.name)
}
// check `formData` entries
var curr = 0;
for (data of formData.entries()) {
console.log("formData entry " + curr, data);
++curr;
}
delete curr;
// do ajax stuff here
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(this.responseText);
};
xhr.open("POST", "upload.php");
xhr.send(formData);
}
function traverseFileTree(item, path) {
var handleFiles = function handleFiles(item, path) {
path = path || "";
if (item.isFile) {
item.file(function(file) {
uploads.push(file);
console.log(file, n, uploads.length); // show info
if (uploads.length === n - 1 || n === 0) {
alert("traverseFiles complete, uploads length: "
+ uploads.length);
var files = uploads.slice(0);
n = uploads.length = 0;
processFiles(files)
}
});
} else if (item.isDirectory) {
var dirReader = item.createReader();
dirReader.readEntries(function(entries) {
// increment `n` here
n += entries.length;
for (var i = 0; i < entries.length; i++) {
handleFiles(entries[i], path + item.name + "/");
}
});
}
}
handleFiles(item, path);
}
var upload = function(items) {
if (n !== 0 && uploads.length !== 0) {
n = uploads.length = 0;
}
for (var i = 0; i < items.length; i++) {
var item = items[i].webkitGetAsEntry();
if (item) {
traverseFileTree(item, "");
}
}
};
dropzone.ondragover = function() {
this.className = 'dropzone dragover';
this.innerHTML = 'Mouse up';
return false;
};
dropzone.ondragleave = function() {
this.className = 'dropzone';
this.innerHTML = 'Drop files';
return false;
};
})();
</script>
</body>
</html>
plnkr http://plnkr.co/edit/OdFrwYH2gmbtvHfq3ZjH?p=preview
See also How can I filter out directories from upload handler in Firefox? , How to read files from folder

Dynamically create buttons based on input values from XML response

Alright, so I have been killing myself over this for a while now. I simply want to take an XML response containing names from my arduino and then dynamically create buttons. Each button needs to say the name and have the name as its id for the GetDrink function to use to send back to the arduino. If anyone can give me some help, maybe some code to work off of it would be appreciated.
I am able to have a button call the CreateButton function to create more buttons which all work. But I need to dynamically create the buttons off of the XML response. Also, this has to be done strictly using JavaScript and HTML.
<!DOCTYPE html>
<html>
<head>
<title>The AutoBar</title>
<script>
// Drinks
strDRINK1 = "";
function GetArduinoIO()
{
nocache = "&nocache=" + Math.random() * 1000000;
var request = new XMLHttpRequest();
request.onreadystatechange = function()
{
if (this.readyState == 4) {
if (this.status == 200) {
if (this.responseXML != null) {
var count;
var num_an = this.responseXML.getElementsByTagName('alcohol').length;
for (count = 0; count < num_an; count++) {
document.getElementsByClassName("AlcStatus")[count].innerHTML =
this.responseXML.getElementsByTagName('alcohol')[count].childNodes[0].nodeValue;
}
}
}
}
}
request.open("GET", "ajax_inputs" + strDRINK1 + nocache, true);
request.send(null);
setTimeout('GetArduinoIO()', 1000);**strong text**
strDRINK1 = "";
}
function GetDrink(clicked_id)
{
strDRINK1 = "&" + clicked_id;
document.getElementById("AlcStatus").innerHTML = "Your " + clicked_id + " is being made";
}
function CreateButton(Drink_Name)
{
myButton = document.createElement("input");
myButton.type = "button";
myButton.value = Drink_Name;
placeHolder = document.getElementById("button");
placeHolder.appendChild(myButton);
myButton.id = Drink_Name;
myButton.onclick = function()
{
strDRINK1 = "&" + myButton.id;
document.getElementById("AlcStatus").innerHTML = "Your " + myButton.id + " is being made";
}
}
</script>
<style>
.IO_box {
float: left;
margin: 0 20px 20px 0;
border: 1px solid blue;
padding: 0 5px 0 5px;
width: 320px;
}
h1 {
font-size: 320%;
color: blue;
margin: 0 0 10px 0;
}
h2 {
font-size: 200%;
color: #5734E6;
margin: 5px 0 5px 0;
}
p, form, button {
font-size: 180%;
color: #252525;
}
.small_text {
font-size: 70%;
color: #737373;
}
</style>
</head>
<body onload="GetArduinoIO()" BGCOLOR="#F5F6CE">
<p> <center><img src="pic.jpg" /></center><p>
<div class="IO_box">
<div id="button"></div>
</div>
<div class="IO_box">
<h2><span class="AlcStatus">...</span></h2>
</div>
<div>
<button onclick="location.href='Edit_Bar.htm'">Edit Bar Menu</button>
<div>
</body>
</html>
Something like this?
var xml = "<items><alcohol>Bourbon</alcohol><alcohol>Gin</alcohol><alcohol>Whiskey</alcohol></items>";
var parser = new DOMParser();
var dom = parser.parseFromString(xml, "text/xml");
var alcohol = dom.querySelectorAll('alcohol');
function getDrink(event) {
alert(event.target.value);
}
function makeButton(value) {
var b = document.createElement('button');
b.innerHTML = value;
b.value = value;
b.id = value;
b.addEventListener('click', getDrink);
return b;
}
var list = document.getElementById('buttons');
for(var i = 0; i < alcohol.length; i++ ) {
var b = makeButton(alcohol[i].firstChild.nodeValue);
var li = document.createElement('li');
li.appendChild(b);
list.appendChild(li);
}
<ul id="buttons"></ul>

Having to click Twice to get one response

I have made a dropdown that appears on click on a button. Pretty simple, except for how I have to click twice to get the js function to execute. After I click it the first, it appears and disappears like it should - taking only one click. I have no clue why it would require this and have searched for fixes, but none of them seem to work.
Here is my HTML:
<ul class="resources-menu">
<li>
<button onclick="res()" id="resbut" onblur="setTimeout('reshide()', 175)">Resources</button>
<ul id="resblock">
<li style="padding-bottom: 20px; text-align:center;padding-top:25px">
<button onclick="dirlnk()">Directory</button>
</li>
</ul>
</li>
</ul>
CSS:
.resources-menu {
width:88px;
float:left;
}
#resbut {
font-weight:700;
height:30px;
text-decoration:underline;
border-radius:3px;
border-color: black;
}
ul.resources-menu, ul.resources-menu ul {
list-style:none;
margin:0;
padding:0;
position: relative;
}
#resblock {
width: 90px;
background-color: lightblue;
display: none;
position: absolute;
border-bottom-left-radius: 15px;
border-bottom-right-radius:15px;
border-top-right-radius:10px;
border:solid;
border-color:black;
}
JavaScript
function res() {
if (document.getElementById('resblock').style.display == 'none') {
document.getElementById('resblock').style.display = 'block';
document.getElementById('resbut').style.background = "lightblue";
document.getElementById('resbut').style.borderBottomRightRadius = "0px";
document.getElementById('resbut').style.borderBottomLeftRadius = "0px";
document.getElementById('resbut').style.borderBottom = "none";
document.getElementById('resbut').style.textDecoration = "none";
} else {
document.getElementById('resblock').style.display = 'none';
document.getElementById('resbut').style.background = "";
document.getElementById('resbut').style.borderBottomRightRadius = "";
document.getElementById('resbut').style.borderBottomLeftRadius = "";
document.getElementById('resbut').style.borderBottom = "";
document.getElementById('resbut').style.textDecoration = "";
}
}
function reshide() {
document.getElementById('resblock').style.display = 'none';
document.getElementById('resbut').style.background = "";
document.getElementById('resbut').style.borderBottomRightRadius = "";
document.getElementById('resbut').style.borderBottomLeftRadius = "";
document.getElementById('resbut').style.borderBottom = "";
document.getElementById('resbut').style.textDecoration = "";
}
function dirlnk() {
window.location = "/Portal/directory";
}
You're looking at the style property when it's in the CSS files, not a style attribute. Use getComputedStyle instead:
function res() {
var resblock = document.getElementById('resblock');
var resblockStyle = resblock.style;
var resbutStyle = document.getElementById('resbut').style;
if (getComputedStyle(resblock).display === 'none') {
resblockStyle.display = 'block';
resblockStyle.background = "lightblue";
resbutStyle.borderBottomRightRadius = "0px";
resbutStyle.borderBottomLeftRadius = "0px";
resbutStyle.borderBottom = "none";
resbutStyle.textDecoration = "none";
} else {
reshide();
}
}
function reshide() {
var resblockStyle = document.getElementById('resblock').style;
var resbutStyle = document.getElementById('resbut').style;
resblockStyle.display = 'none';
resbutStyle.background = "";
resbutStyle.borderBottomRightRadius = "";
resbutStyle.borderBottomLeftRadius = "";
resbutStyle.borderBottom = "";
resbutStyle.textDecoration = "";
}
function dirlnk() {
window.location.href = "/Portal/directory";
}
It's also a good idea to cache your variables so you don't need to query the DOM for each style addition. Your reshide function does the same thing as the else in your res function -- you should avoid duplicating code where practicable.
Compatibility issues
As #garromark correctly notes, this solution won't work if you need to support older browsers (i.e. IE8 and below). Alternatively, you can add a class called .no-display and check whether that class is present or not:
.no-display {
display: none !important;
}
Then your JavaScript check:
if (/\bno\-display\b/.test(resblock.className)) {

Categories

Resources