Proper div placement difficulties on 2x2 grid - javascript

this is a school project. Making a 2x2 grid, pictures in 3 of them and the picture should be able to be moved from "box to box". Everything else is in order, except the lower 2 divs.
The top 2 are perfectly in line, but when trying to make the second one, they either come right next to the first ones (with a br so they're a bit lower), or then on top of each other under the first 2. I know it's not a big thing that i'm missing, but i just can't seem to figure it out.
#loota {
float: left;
width: 200px;
height: 283px;
border: 2px solid #aaaaaa;
}
#loota2 {
float: left;
width: 200px;
height: 283px;
border: 2px solid #aaaaaa;
}
<div id="loota" ondrop="tiputus(event)" ondragover="siirto(event)">
<img id="kuva1" src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder&w=200&h=283" draggable="true" ondragstart="veto(event)" width="200" height="283">
</div>
<div id="loota" ondrop="tiputus(event)" ondragover="siirto(event)">
<img id="kuva2" src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder&w=200&h=283" draggable="true" ondragstart="veto(event)" width="200" height="283">
</div>
<br>
<div id="loota2" ondrop="tiputus(event)" ondragover="siirto(event)">
<img id="kuva3" src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder&w=200&h=283" draggable="true" ondragstart="veto(event)" width="200" height="283">
</div>
<div id="loota" ondrop="tiputus(event)" ondragover="siirto(event)"></div>

The 2x2grid can be created using css nth operators.
The drag and drop can be done on individual images with a class and an operator function:
(function closedScopeForDragAndDropImages() {
var dragTarget = null;
window.addEventListener("dragover", function(event) {
// prevent default to allow drop
event.preventDefault();
}, false);
window.addEventListener("drag", function(event) {
if (event.target.className == "dropable-image") {
dragTarget = event.target;
}
// prevent default to allow drop
event.preventDefault();
}, false);
window.addEventListener("drop", function(event) {
// prevent default action (open as link for some elements)
event.preventDefault();
// move dragged elem to the selected drop target
if (event.target.className == "dropable-image") {
var src = dragTarget.getAttribute("src");
dragTarget.setAttribute("src", event.target.getAttribute("src"));
event.target.setAttribute("src", src)
}
}, false);
})();
.tile {
float: left;
width: 200px;
height: 283px;
border: 2px solid #aaaaaa;
}
.tile:nth-child(2n+3) {
clear: left;
}
<div class="tile">
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder1&w=200&h=283" class="dropable-image" draggable="true" />
</div>
<div class="tile">
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder2&w=200&h=283" class="dropable-image" draggable="true" />
</div>
<div class="tile">
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder3&w=200&h=283" class="dropable-image" draggable="true" />
</div>
<div class="tile">
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=Placeholder4&w=200&h=283" class="dropable-image" draggable="true" />
</div>

Related

How can one use HTML5 drag and drop API with JavaScript to display varying text, depending on which draggable element is dropped?

I am working on a webpage for a class assignment. We are to utilize the HTML5 API drag and drop, which has been successfully implemented. I wanted to go a step further with the drag and drop API by incorporating some JavaScript to change a line of text on the webpage. I anticipated this line of text to be able to change into different statements based on which draggable object was dropped. I was able to achieve a single change to the text, but I was unable to find a way to have the text change to a different message. I consulted with my professor about this and she recommended I ask the question in these forums to find out more information. Is there a way to achieve this effect with the HTML5 API?
The code I started with to get the initial change in text looks like this:
<body>
<main>
<h2 class="center">What are Specializations?</h2>
<p class="center">Specializations in Project Management are similar to certifications, but instead highlight expertise on specific management approaches, task oversight, and industries. </p>
<br>
<br>
<h2 class="center">What Specializations are available?</h2>
<p class="center" id="demo">(Drag and Drop the specializations into the box for more details)</p>
<br>
<br>
<div class="container" style="background-color: #fafad2;">
<div></div>
<div></div>
<div draggable="true" class="box" style="background-color: #AFFF7A; border-color: #000000; padding: 20%;"></div>
<div></div>
<div></div>
</div>
<br>
<div class="container">
<div draggable="true" class="box">PMI-RMP</div>
<div draggable="true" class="box">PMI-SP</div>
<div draggable="true" class="box">AHPP</div>
<div draggable="true" class="box">AM-MC</div>
<div draggable="true" class="box">CD-P</div>
<div draggable="true" class="box">CDBA</div>
<div draggable="true" class="box">BEPC</div>
<div draggable="true" class="box">BEPM</div>
<div draggable="true" class="box">BETI</div>
<div draggable="true" class="box">PMI-CP</div>
<div draggable="true" class="box">OTF</div>
<div draggable="true" class="box">OTI</div>
<div draggable="true" class="box">OTO</div>
</div>
<script>
/* Events fired on the drag target */
document.addEventListener("dragstart", function(event) {
// The dataTransfer.setData() method sets the data type and the value of the dragged data
event.dataTransfer.setData("Text", event.target.id);
});
// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function(event) {
document.getElementById("demo").innerHTML = "Finished dragging the p element.";
});
/* Events fired on the drop target */
// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function(event) {
event.preventDefault();
});
</script>
</main>
</body>
I would then approach the multi-message display by using a JavaScript event listener and if-else statements, seen in this code:
<body>
<main>
<h2 class="center">What are Specializations?</h2>
<p class="center">Specializations in Project Management are similar to certifications, but instead highlight expertise on specific management approaches, task oversight, and industries. </p>
<br>
<br>
<h2 class="center">What Specializations are available?</h2>
<p class="center" id="demo">(Drag and Drop the specializations into the box for more details)</p>
<br>
<br>
<div class="container" style="background-color: #fafad2;">
<div></div>
<div></div>
<div draggable="true" class="box" style="background-color: #AFFF7A; border-color: #000000; padding: 20%;"></div>
<div></div>
<div></div>
</div>
<br>
<div class="container">
<div draggable="true" class="box">PMI-RMP</div>
<div draggable="true" class="box">PMI-SP</div>
<div draggable="true" class="box">AHPP</div>
<div draggable="true" class="box">AM-MC</div>
<div draggable="true" class="box">CD-P</div>
<div draggable="true" class="box">CDBA</div>
<div draggable="true" class="box">BEPC</div>
<div draggable="true" class="box">BEPM</div>
<div draggable="true" class="box">BETI</div>
<div draggable="true" class="box">PMI-CP</div>
<div draggable="true" class="box">OTF</div>
<div draggable="true" class="box">OTI</div>
<div draggable="true" class="box">OTO</div>
</div>
<script>
/* Events fired on the drag target */
document.addEventListener("dragstart", function(event) {
// The dataTransfer.setData() method sets the data type and the value of the dragged data
event.dataTransfer.setData("Text", event.target.id);
});
// Output some text when finished dragging the p element and reset the opacity
document.addEventListener("dragend", function(event) {
document.getElementById("definition").innerHTML = "(Drag and Drop the specializations into the box for more details)";
var id='1';
if (id=='1') {
document.getElementById("definition").innerHTML = "This is definition 1";
}else if (id=='2'){
document.getElementById("definition").innerHTML = "This is definition 2";
}else if (id=='3'){
document.getElementById("definition").innerHTML = "This is definition 3";
}else (id=='4'){
document.getElementById("definition").innerHTML = "This is definition 4";
}
});
/* Events fired on the drop target */
// By default, data/elements cannot be dropped in other elements. To allow a drop, we must prevent the default handling of the element
document.addEventListener("dragover", function(event) {
event.preventDefault();
});
</script>
</main>
</body>
The CSS utilized:
body {
background-color:#fafad2;
margin: 3%;
}
h1 {
color:#4169E1;
font-family: "Trebuchet MS";
font-size: 300%;
opacity: 75%;
text-shadow: 1px -2px 1px #00008B;
}
h2 {
color:#4682B4;
font-family: "Trebuchet MS";
font-size: 200%;
}
h3 {
color:#B0C4DE;
font-family: "Trebuchet MS";
font-size: 150%;
font-style: italic;
}
main {
padding: 4%;
}
p {
font-family: Georgia;
}
.container {
background-color: #FFFF76;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 1%;
padding: 1%;
}
.box {
border: 3px solid #ddd;
background-color: #FFF5EE;
padding: 10%;
margin: 5%;
cursor: move;
text-align: center;
}
.box.over {
border: 4px dashed #666;
}

append the element before and after on drop it

I'm trying to make a website that use drag and drop functionality to build a website. But I'm facing the problem that the element is not being append before another element like the code I have shown. please help me so it can drop the elements before and after a specific element not just at the end of all the elements.
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">button1</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">button2</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">button3</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">button4</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)">
</div>
I'm using javascript.
That's actually quite tricky to achieve, you need to implement your own logic for inserting the element to the correct position in the list.
Here is an example where you can move items between divs and reorder items in the same div
(Note that I only implemented the logic for drag/drop items horizontally in a single line by using left offset, if you have multiple lines items list, you need to implement your own)
function allowDrop(ev) {
ev.preventDefault()
}
function drag(ev) {
ev.dataTransfer.setData('text', ev.target.id)
}
function drop(ev) {
ev.preventDefault()
var data = ev.dataTransfer.getData('text')
// ev.currentTarget is the div that the elements are dropped
const currentDragElementOffset = ev.clientX
const items = ev.currentTarget.children
//empty list, just append and return
if (items.length === 0) {
ev.currentTarget.appendChild(document.getElementById(data))
return
}
// non-empty list
for (let i = 0; i < items.length; i++) {
const item = items[i]
const {
left,
width
} = item.getBoundingClientRect()
// find the offset left from the center of the item
const currentElementLeftOffset = left + width / 2;
if (currentDragElementOffset < currentElementLeftOffset) {
ev.currentTarget.insertBefore(document.getElementById(data), item)
return
}
// found no insertion point, that means item was dragged to the end of the list
if (i === items.length - 1 && currentDragElementOffset > currentElementLeftOffset) {
ev.currentTarget.appendChild(document.getElementById(data))
}
}
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<!DOCTYPE html>
<html>
<body>
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">
button1
</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">
button2
</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">
button3
</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">
button4
</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
</body>
</html>
Simply use the CSS property order.
The drop zones must have display: flex or display: inline-flex (see .zone in Example - CSS)
Each item that is draggable should have style="order: number " (see Example - JS)
Also, to avoid an item appending to another item, use event.currentTarget instead of event.target in the drop() function (see drop() in Example - JS). In the example, the repetitive parts in HTML have been streamlined (see Figure I):
Figure I
Original Post
Example
Attributes on each element in HTML
Attributes assigned to each element by .forEach()
Inline events on each element in HTML
Onevent properties bound to each element by .forEach()
Example
Details are commented
/*
Collect all .btn into a NodeList
Iterate through NodeList with .forEach()
Bind dragstart event to current <button>
Add inline style "order" with the value of current index
Add "draggable" attribute with the value of true
*/
document.querySelectorAll('.btn').forEach((b, i) => {
b.ondragstart = drag;
b.style.order = i;
b.setAttribute('draggable', true);
});
/*
Collect all .zone into a NodeList
Iterate through NodeList with .forEach()
Bind drop event to current <div>
Bind dragover event to current <div>
*/
document.querySelectorAll('.zone').forEach(z => {
z.ondrop = drop;
z.ondragover = allowDrop;
});
function allowDrop(e) {
e.preventDefault();
}
function drag(e) {
e.dataTransfer.setData("text", e.target.id);
}
function drop(e) {
e.preventDefault();
let data = e.dataTransfer.getData("text");
/*
Change e.target to e.currentTarget to prevent any <button>
appending onto another <button>. e.currentTarget will always
point to .zone
*/
e.currentTarget.append(document.getElementById(data));
}
.zone {
display: flex;
align-items: center;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
.btn {
margin: 0 10px;
cursor: move;
}
<h2>Drag and Drop</h2>
<p>Drag the buttons back and forth between the two div elements.</p>
<div class="zone">
<button id='b1' class='btn'>button1</button>
<button id='b2' class='btn'>button2</button>
<button id='b3' class='btn'>button3</button>
<button id='b4' class='btn'>button4</button>
</div>
<div class="zone"></div>
You should use .prepend() method for inserting element before the other element.
Element.prepend() method inserts a set of Node objects or string objects before the first child of the Element. String objects are inserted as equivalent Text nodes.
Here's a Working Code :
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.prepend(document.getElementById(data));
}
#div1,
#div2 {
float: left;
width: 500px;
height: 35px;
margin: 10px;
padding: 10px;
border: 1px solid black;
}
<h2>Drag and Drop</h2>
<p>Drag the image back and forth between the two div elements.</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)">
<button draggable="true" ondragstart="drag(event)" id="drag1">button1</button>
<button draggable="true" ondragstart="drag(event)" id="drag2">button2</button>
<button draggable="true" ondragstart="drag(event)" id="drag3">button3</button>
<button draggable="true" ondragstart="drag(event)" id="drag4">button4</button>
</div>
<div id="div2" ondrop="drop(event)" ondragover="allowDrop(event)">
</div>

Changing the function of a button in a website

So below I have some code of what I'm working with. Right now, if you just launch the website, the #picture div has a background image, and if you press any of the buttons, that picture is replaced with something else.
So what I can't figure out is how the buttons would change what they do after pressing a button. Let's say you click on Button 1 and the background image is replaced. I want the buttons to recognize what background image is in that div and change functions accordingly, in my case, I want them to change what pictures they replace the current one with.
If the current background of #picture is X, you have ABC choices, if the background of #picture is Y, you have DEF choices, would be a TLDR explanation maybe.
<div id="adventure">
<div class="picture">
</div>
<div id="choice">
<button class="button1">Val 1</button>
<button class="button2">Val 2</button>
<button class="button3">Val 3</button>
</div>
</div>
$('.button1').click(function() {
$('.picture').css('background-image',
'url("image1")'
);
});
$('.button2').click(function() {
$('.picture').css('background-image',
'url("image2")'
);
});
$('.button3').click(function() {
$('.picture').css('background-image',
'url("image3")'
);
});
I've probably gone about doing this in a bad way but I'm really at a loss on how I would do this. I can only think up of one way of doing it and that is to have a bunch of if statements depending on what background is in the #picture div but I don't know how to implement that.
This demo relies on the class .active which determines which set of buttons (called .group) are visible, whilst the other .groups remain absent. The #switch button will toggle through each group.
You must name your images according to the id of the button it belongs to.
Example:
HTML of Button
<button id="image_of_sky.png">D</button>
URL to Image
http://domain.com/path/to/image_of_sky.png
jQuery img variable
var img = "http://domain.com/path/to/"+btn;
Snippet
$('.button').click(function() {
var btn = $(this).attr('id');
var img = "https://placehold.it/330x150?text=" + btn;
$('.picture').css('background-image',
'url(' + img + ')'
);
});
$('#switch').click(function() {
var act = $('.group.active');
var next = act.next();
act.removeClass('active');
next.addClass('active');
if (act.attr('id') == "choiceGHI") {
$('#choiceABC').addClass('active');
}
});
#adventure {
width: 395px;
}
.picture {
width: 330px;
height: 150px;
border: 1px outset grey;
}
.group {
width: 330px;
display: none;
padding: 0;
}
.button {
width: 32.5%;
margin: 0;
}
.active {
display: block;
}
#switch {
float: right;
margin: -20px 0 0 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="adventure">
<div class="picture"></div>
<div id="choiceABC" class="group active">
<button id="Image1" class="button">A</button>
<button id="Image2" class="button">B</button>
<button id="Image3" class="button">C</button>
</div>
<div id="choiceDEF" class="group">
<button id="Image4" class="button">D</button>
<button id="Image5" class="button">E</button>
<button id="Image6" class="button">F</button>
</div>
<div id="choiceGHI" class="group">
<button id="Image7" class="button">G</button>
<button id="Image8" class="button">H</button>
<button id="Image9" class="button">I</button>
</div>
<button id="switch">Switch</button>
</div>

How to hide div when it's already open?

I couldn't think of any better title, so I will try to explain my question here as clear as possible. I'm quite a newbie in JQuery so this is probably a very easy question.
I have some divs with a button on it. When you click the button, another div should pop-up.
My question is: How can I make the div, which is already open, close when clicking on another button?
I made a fiddle with some example code: http://jsfiddle.net/zuvjx775/1/
And the example code here:
HTML:
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="1" value='click!' />
</div>
<div class="show_1">
</div>
</div>
<br>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="2"value='click!' />
</div>
<div class="show_2">
</div>
</div>
JQuery:
$('.showDiv').on('click', function(){
var id = $(this).attr('id');
$('.show_'+id).show();
});
When show_1 for example is visible, and I click on the button in div2, I want show_2 to come up, which it does, but show_1 to dissapear.
Can someone point me in the right direction?
You can hide all divs that their class starts with 'show' before show the one you want. For example:
$('.showDiv').on('click', function() {
var id = $(this).attr('id');
$("div[class^='show']").hide();//find div class starts with 'show' and hide them
$('.show_' + id).show();
});
.test {
border: 1px solid black;
height: 100px;
width: 450px;
float: left;
}
.show_1 {
width: 50px;
height: 50px;
background-color: yellow;
float: left;
display: none;
}
.show_2 {
width: 50px;
height: 50px;
background-color: green;
float: left;
display: none;
}
.wrapper {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="1" value='click!' />
</div>
<div class="show_1">
</div>
</div>
<br>
<div class="wrapper">
<div class="test">
<input type='button' class='showDiv' id="2" value='click!' />
</div>
<div class="show_2">
</div>
</div>
Is the structure of the document fixed?
is so... I guess the easiest way of doing this is to just do the following:
$('.showDiv').on('click', function(){
var id = $(this).attr('id');
if(id == 1){
$('.show_1').show();
$('.show_2').hide();
}else{
$('.show_2').show();
$('.show_1').hide();
}
})

making a new div draggable, tried everything

Hello stackoverflow comunity.
I am working on some code that makes draggable resizeable divs. I have it working with the divs that are created originally, but the newly added divs arent becomming draggable.
Here is ALL my code:
<html>
<head>
<script>
var id = 4;
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
ev.target.appendChild(document.getElementById(ev.dataTransfer.getData("Text")));
}
function change(div)
{
var divw=parseInt(div.style.width);
var divh=parseInt(div.style.height);
var imgw=divw-10;
var imgh=divh-10;
div.children[0].style.width=imgw;
div.children[0].style.height=imgh;
div.style.border="dotted 3px grey";
}
function addimg()
{
var main = document.getElementById('main');
var div = document.createElement('div');
div.onmouseout = function() {this.style.border=0};
div.ondragstart = function() {drag(event)};
div.onmousemove = function() {change(this)};
div.setAttribute('draggable', true);
div.id = 'div'+id;
id+=1;
div.style.styleFloat = 'left';
div.style.cssFloat = 'left';
div.style.resize = 'both';
div.style.overflow = 'hidden';
div.style.height = '110px';
div.style.width = '110px';
div.innerHTML = '<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />';
main.appendChild(div);
}
</script>
</head>
<body>
<center>
<div ID="main" ondragover="event.preventDefault()" ondrop="drop(event)" style="width:900px; height:900px; border: dashed 1px lightgrey;" overflow="auto">
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML" style="resize:none; width: 100px; height: 100px"></textarea>
<p style="background-color: blue"></p>
</div>
<div style="clear:both"></div>
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
</div>
</center>
<button onclick="addimg()">add an image</button>
</body>
</html>
the issue is that the new divs aren't draggable.
P.S. if you use jquery, please explain it very detailed, i have no experience with it.
I m not sure what draggable function in this case is. Is it just dragging this newly added image to this element in top left ? After what that image disappear ?
If this is case, solution is very simple. In function addimage you have wrong line.Your line is:
div.ondragstart = function() {drag(event)};
And it should be
div.ondragstart = function(event) {drag(event)};
In this line you call function without setting event as argument, and you use it in function.
Hope it helps.
One solution is to use the same method used to create the <img> element, to create the <div>:
<html>
<head>
<script>
var id = 4;
function drag(ev) {
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev) {
ev.preventDefault();
document.getElementById('main')
.appendChild(document.getElementById(ev.dataTransfer.getData("Text")));
}
function change(div) {
var divw = parseInt(div.style.width);
var divh = parseInt(div.style.height);
var imgw = divw - 10;
var imgh = divh - 10;
div.children[0].style.width = imgw;
div.children[0].style.height = imgh;
div.style.border = "dotted 3px grey";
}
function addimg() {
var main = document.getElementById('main');
main.innerHTML += '<div id="div'+id+'" onmouseout="this.style.border=0" draggable="true" ' +
'ondragstart="drag(event)" onmousemove="change(this)" style="float:left; ' +
'resize:both; overflow:hidden; height: 110px; width:110px"></div>';
div = document.getElementById('div'+id);
div.innerHTML = '<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />';
id+=1;
}
</script>
</head>
<body>
<center>
<div ID="main" ondragover="event.preventDefault()" ondrop="drop(event)" style="width:900px; height:900px; border: dashed 1px lightgrey;" overflow="auto">
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML" style="resize:none; width: 100px; height: 100px"></textarea>
<p style="background-color: blue"></p>
</div>
<div style="clear:both"></div>
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
<div onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3" style="float:left; resize:both; overflow:hidden; height: 110px; width:110px">
<img draggable="false" style="width: 100px; height: 100px" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
</div>
</center>
<button onclick="addimg()">add an image</button>
</body>
</html>
This should ensure the browser renders the new <div> element in the same way as the existing ones. In addition ensuring that elements are appended back to the main <div> element when they are dropped, will prevent them from disappearing when dropped onto of other elements, as previously.
Using Jquery
On the tip of using jquery, if we include the jquery.min.js library at the top of the file:
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
The change() function can be rewritten as:
function change(div) {
var $div = $(div);
$div.css('border','dotted 3px grey')
.children( ':first' )
.width( $div.width() - 10 )
.height( $div.height() - 10 );
}
This is somewhat shorter than the original. The first line converts the div parameter into a jquery object and stores it in the $div variable. The $ at the beginning of the variable name is just a convention, as the variable contains a jquery object. Caching the jquery object in this variable is more efficient than using $(div) 3 times in the change() function.
Calls to$div.width() and $div.height() perform the same action as the parseInt() calls in the original function. Jquery allows function calls to be 'chained', thus the first call on $div sets the border style and returns the same $div object. The .children() call returns the first child of $div (the <img> element) which then has it's width and height set using the corresponding methods.
It should be noted that jquery is generally thought to be easier to use, and offer good cross browser compatibility (which can be a real headache) rather than more efficient.
Moving style out of elements
We can move the common style attribute out of the individual elements into a separate section in the <head> of the html:
<style>
#main {
width:900px;
height:900px;
border: dashed 1px lightgrey;
overflow: auto;
}
.dragDiv {
float: left;
resize: both;
overflow: hidden;
height: 110px;
width: 110px;
}
.dragDiv img {
width: 100px;
height: 100px
}
.dragDiv textarea {
resize: none;
width: 100px;
height: 100px;
}
</style>
By giving the drag-able <div> elements the class dragDiv we reduce the amount of style duplication:
<div id="main" ondragover="event.preventDefault()" ondrop="drop(event)">
<div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div1">
<textarea onblur="this.nextElementSibling.innerHTML=this.innerHTML"></textarea>
<p style="background-color: blue"></p>
</div>
<div style="clear:both"></div>
<div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div2">
<img draggable="false" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
<div class="dragDiv" onmouseout="this.style.border=0" draggable="true" ondragstart="drag(event)" onmousemove="change(this)" id="div3">
<img draggable="false" src="https://www.google.com/images/srpr/logo11w.png" />
</div>
</div>
Is this something like what you are looking for? I'm happy to suggest more alterations, if required.
Jquery offers draggables - which use absolute positioning; resizables; and sortables - which offer similar 'snap on drop' behaviour as the code above. Although I don't suggest you use these instead, they might be good guides as to how you wish your code to behave.

Categories