Javascript report designer should allow to create copies of selected divs into same panel.
I tried to use
function DesignerClone() {
$(".ui-selected").each(function () {
var newDiv = $(this).prop('outerHTML'),
parentpanel = $(this).parent(".designer-panel-body");
parentpanel.prepend(newDiv);
});
}
but all divs are lost. and empty panel appears.
To reproduce, run code snippet and select some divs by mouse click.
After that press clone button.
How to clone boxes ?
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<style>
.designer-panel-body {
min-height: 1px;
overflow: hidden;
margin: 0;
padding: 0;
}
.panel-footer {
background-color: inherit;
}
.designer-panel,
.designer-resetmargins {
margin: 0;
padding: 0;
}
.designer-verticalline,
.designer-horizontalline,
.designer-rectangle {
font-size: 1pt;
border: 1px solid #000000;
}
.designer-field {
border: 1px solid lightgray;
white-space: pre;
overflow: hidden;
}
.ui-selecting {
background-color: lightskyblue;
color: white;
}
.ui-selected {
background-color: lightskyblue;
border-color: darkblue;
color: white;
}
.designer-label {
white-space: pre;
}
.designer-field,
.designer-label {
font-family: "Times New Roman";
font-size: 10pt;
z-index: 2;
}
.designer-verticalline,
.designer-horizontalline,
.designer-rectangle,
.designer-field,
.designer-image,
.designer-label {
position: absolute;
}
</style>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script>
function DesignerClone() {
$(".ui-selected").each(function () {
var newDiv = $(this).prop('outerHTML'),
parentpanel = $(this).parent(".designer-panel-body");
parentpanel.prepend(newDiv);
});
}
function getpos(e) {
return {
X: e.pageX,
Y: e.pageY
};
}
function Rect(start, stop) {
this.left = Math.min(start.X, stop.X);
this.top = Math.min(start.Y, stop.Y);
this.width = Math.abs(stop.X - start.X);
this.height = Math.abs(stop.Y - start.Y);
}
$(function () {
var startpos;
var selected = $([]),
offset = {
top: 0,
left: 0
};
$(".designer-verticalline, .designer-rectangle, .designer-field, .designer-image").resizable();
var $liigutatavad = $(".designer-verticalline, .designer-horizontalline, .designer-rectangle, .designer-field, .designer-image, .designer-label");
$liigutatavad.draggable({
start: function (event, ui) {
var $this = $(this);
if ($this.hasClass("ui-selected")) {
// if this is selected, attach current offset
// of each selected element to that element
selected = $(".ui-selected").each(function () {
var el = $(this);
el.data("offset", el.offset());
});
} else {
// if this is not selected, clear current selection
selected = $([]);
$liigutatavad.removeClass("ui-selected");
}
offset = $this.offset();
},
drag: function (event, ui) {
// drag all selected elements simultaneously
var dt = ui.position.top - offset.top,
dl = ui.position.left - offset.left;
selected.not(this).each(function () {
var $this = $(this);
var elOffset = $this.data("offset");
$this.css({
top: elOffset.top + dt,
left: elOffset.left + dl
});
});
}
});
// ...but manually implement selection to prevent interference from draggable()
$(".designer-panel-body").on("click", "div", function (e) {
if ( /*!e.metaKey &&*/ !e.shiftKey && !e.ctrlKey) {
// deselect other elements if meta/shift not held down
$(".designer-panel-body").removeClass("ui-selected");
$(this).addClass("ui-selected");
} else {
if ($(this).hasClass("ui-selected")) {
$(this).removeClass("ui-selected");
} else {
$(this).addClass("ui-selected");
}
}
});
$(".designer-panel-body").selectable({});
});
</script>
</head>
<body>
<button type="button" class="btn btn-default" onclick="javascript:false;DesignerClone()">
<span class="glyphicon glyphicon-paste"></span>
</button>
<div class='panel designer-panel'>
<div class='panel-body designer-panel-body panel-warning' style='height:4cm'>
<div class='designer-field' contenteditable='true' style='top:2.30cm;left:5.84cm;width:10.24cm;height:0.63cm;font-family:Arial;font-size:14pt;font-weight:bold;'>vnimi+' '+dok.tasudok</div>
<div class='designer-field' contenteditable='true' style='top:2.30cm;left:16.37cm;width:2.68cm;height:0.61cm;font-size:14pt;'>DOK.kuupaev</div>
<div class='rectangle' style='border-width: 1px;background-color:#FFFFFF;top:2.99cm;left:1.34cm;width:18.05cm;height:5.29cm'></div>
<div class='designer-field' contenteditable='true' style='top:3.01cm;left:1.53cm;width:9.71cm;height:0.55cm;font-size:12pt;'>m.FIRMA</div>
<div class='designer-field' contenteditable='true' style='top:3.01cm;left:12.13cm;width:3.13cm;height:0.53cm;font-size:12pt;'>ise.telefon</div>
</div>
<div class='bg-warning'>
<div class='panel-footer'><i class='glyphicon glyphicon-chevron-up'></i> GroupHeader 1: str(dokumnr)+str(koopia,2)</div>
</div>
</div>
</body>
</html>
.appendTo takes selected element and removes it from previous position in the DOM.
jQuery.clone() is what you might be looking for.
Related
I'm making a huge project which should be good regarding performance like every software. But I'm struggling about drag and drop objects.
Let me start with my code.
Here is my HTML:
<div class="drag-me"></div>
<div class="drop-on-me"></div>
Here is my JavaScript:
$('.drag-me').draggable();
$('.drop-on-me').hover(function(){
let el = $(this);
el.droppable({
drop: function(){
console.log("dropped!");
}
});
}, function(){
let el = $(this);
el.droppable('destroy');
});
Codepen Example
I need to trigger droppable event on hovering while dragging objects, because there are so many droppable objects in the page and it consumes much of RAM with the browser and the page crashes.
How can I trigger while I'm hovering with draggable object?
You will need to do a level of collision detection. The drag event can block out some other events, like hover from bubbling up. Consider the following code snippet.
$(function() {
function getBounds(el) {
var p = {
tl: $(el).position()
};
p['tr'] = {
top: p.tl.top,
left: p.tl.left + $(el).width()
};
p['bl'] = {
top: p.tl.top + $(el).height(),
left: p.tl.left
};
p['br'] = {
top: p.bl.top,
left: p.tr.left
};
return p;
}
function isOver(el, map) {
var myPos = getBounds(el);
var tObj = false;
$.each(map, function(k, v) {
if (myPos.tl.left > v.tl.left && myPos.tl.left < v.tr.left && myPos.tl.top > v.tl.top && myPos.tl.top < v.bl.top) {
console.log("Over", k);
tObj = $(".drop-on-me").eq(k);
}
});
return tObj;
}
function makeDrop(el) {
if (!$(el).hasClass("ui-droppable")) {
$(el).droppable({
addClasses: false,
drop: function() {
console.log("Item Dropped.");
},
out: function() {
$(this).droppable("destroy");
}
});
}
}
var dropPositions = [];
$(".drop-on-me:visible").each(function(i, el) {
dropPositions.push(getBounds(el));
});
console.log("Mapping complete.", dropPositions);
$('.drag-me').draggable({
start: function() {
console.log("Drag Start.");
},
stop: function() {
console.log("Drag Stop.");
},
drag: function(e, ui) {
var target = isOver(ui.helper, dropPositions);
if (target) {
console.log("Make Drop, Index: " + target.index());
makeDrop(target);
}
}
});
});
.drag-me {
width: 30px;
height: 30px;
background-color: rgba(255, 0, 0, 0.75);
border: 1px solid #000;
border-radius: 3px;
z-index: 300;
}
.drop-on-me {
width: 100px;
height: 100px;
background-color: rgba(0, 0, 255, 0.75);
border: 1px solid #000;
border-radius: 3px;
position: absolute;
}
.drop-on-me.top {
left: 80px;
top: 10px;
}
.drop-on-me.mid {
left: 40px;
top: 120px;
}
.drop-on-me.bot {
left: 240px;
top: 640px;
}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="drag-me"></div>
<div class="drop-on-me top"></div>
<div class="drop-on-me mid"></div>
<div class="drop-on-me bot"></div>
I create a clone function with jquery and included a deleted button inside it, when i click the delete button it will delete the particular box parent and hide the delete button when the delete button length < 2, i generate unique id for each box start from 1, it work when i delete the box with id in sequence start from 3,2,1 and 4 (from bottom to top box), but the delete button can't hide when i start delete start from 4,1,2,3 (from the top to the bottom), here my code below
$(document).ready(function(){
var counter = 1;
var total = 1;
var el = $('#clone');
var box = $('.box');
var container = '.container';
var deleteBtn = $('#delete');
$(document.body).on('click','#clone', function(){
counter ++;
total ++;
var startClone = box.clone(true);
startClone.appendTo(container);
box.attr('id','hallo' + counter);
$('.box').find('#delete').show();
deleteBtn.show();
})
$('#delete').on('click', function(){
total --;
$(this).closest('.box').remove();
console.log(total);
if(total < 2){
deleteBtn.hide();
}else {
deleteBtn.show();
}
})
})
.box {
background: red;
width: 100px;
height: 100px;
margin: 5px 0;
}
#clone {
display: block;
}
#delete {
display: none;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
<div class="container">
<div class="box" id="hallo1">
<button id="delete">Delete</button>
</div>
</div>
<button id='clone'>Clone this</button>
</body>
</html>
id should be unique. When you clode box element there would be multiple buttons with id delete and will create issues.
I used class .delete. Please check.
$(document).ready(function() {
var counter = 1;
var el = $('#clone');
var box = $('#hallo1');
var container = '.container';
box.hide(); //Hide the orginal box
var clone = function(){
counter++;
var startClone = box.clone(true);
startClone.append(counter - 1); //For test purposes. Please remove
startClone.appendTo(container);
startClone.attr('id', 'hallo' + counter);
startClone.show(); //Show the cloned box
startClone.find('.delete').show();
toggleDelete();
}
var toggleDelete = function(){
if ($(".delete").length < 2) {
$(".delete").hide();
} else {
$(".delete").show();
}
}
clone();//Clone initaly
$(document.body).on('click', '#clone', function() {
clone();
})
$('.delete').on('click', function() {
$(this).closest('.box').remove();
toggleDelete();
})
})
.box {
background: red;
width: 100px;
height: 100px;
margin: 5px 0;
}
#clone {
display: block;
}
.delete {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="box" id="hallo1">
<button class="delete">Delete</button>
</div>
</div>
<button id='clone'>Clone this</button>
Alternative cleaner Approach:
$(document).ready(function() {
$("#clone").click(function() {
clone();
toggleDelete();
});
$("body").on('click', '.delete', function() {
$(this).closest('.box').remove();
toggleDelete();
})
var toggleDelete = function() {
if ($(".delete").length < 2) {
$(".delete").hide();
} else {
$(".delete").show();
}
}
var clone = function() {
$("#container").append('<div class="container"><div class="box"><button class="delete">Delete</button></div></div>');
}
clone(); //Call init
});
.box {
background: red;
width: 100px;
height: 100px;
margin: 5px 0;
}
#clone {
display: block;
}
.delete {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container"></div>
<button id='clone'>Clone this</button>
Identifiers must be unique so assign a CSS then Class Selector can be used to target the element and You should use Event delegation to bind event with dynamic elements.
container.on('click', '.delete', function () {
$(this).closest('.box').remove();
if ($(".delete").length < 2) {
$(".delete").hide();
} else {
$(".delete").show();
}
});
$(document).ready(function() {
var el = $('#clone');
var box = $('.box');
var container = $('.container');
$(document.body).on('click', '#clone', function() {
var startClone = box.eq(0).clone();
startClone.appendTo(container);
$('.box').find('.delete').show();
})
container.on('click', '.delete', function() {
$(this).closest('.box').remove();
if ($(".delete").length < 2) {
$(".delete").hide();
} else {
$(".delete").show();
}
})
})
.box {
background: red;
width: 100px;
height: 100px;
margin: 5px 0;
}
#clone {
display: block;
}
.delete {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="box" id="hallo1">
<button class="delete">Delete</button>
</div>
</div>
<button id='clone'>Clone this</button>
I have a function which counts the number of line breaks in a div, depending on the width of the window. While the functions works fine when placed in the $(window).on('resize') function, it does not work when put in $(document).ready() function. I want it to work right on page load, and also window resize, how do I support both?
JSFiddle
Javascript/jQuery:
// functions called in both document.ready() and window.resize
$(document).ready(function(){
var lineCount = getLineCount();
postItems(lineCount);
$('.answer').text("Ready");
});
$(window).on('resize', function(){
var lineCount = getLineCount();
postItems(lineCount);
$('.answer').text("Number of lines: " + lineCount);
});
// calculates the amount of lines required to hold the items
function getLineCount() {
var lineWidth = $('.line').width();
var itemWidthSum = 0;
var lineCount=1;
$('.item').each(function(index, element) {
if((lineWidth - itemWidthSum) > ($(element).outerWidth())) {
itemWidthSum = itemWidthSum + $(element).outerWidth();
} else {
lineCount++;
itemWidthSum = $(element).outerWidth();
}
});
return lineCount;
}
// overlays rows for the amount of linebreaks
function postItems(lineCount){
var container = $('<div />');;
for(var i = 1; i <= lineCount; i++) {
container.append('<div class="line">' + i + '</div>');
}
$('.line-wrap').html(container);
}
You'll see at the start of the page, it incorrectly shows 17 lines, and then once you resize it will show the correct amount.
The issue lies in the first line of getLineCount(). Originally you had
var lineWidth = $('.line').width();
but no elements with the class "line" exist yet on your page (since they get added in your postItems() method. I changed it to
var lineWidth = $(".container").width();
instead, and now your code should be working. Snippet posted below:
$(document).ready(function(){
var lineCount = getLineCount();
postItems(lineCount);
$('.answer').text("Ready");
});
$(window).on('resize', function(){
var lineCount = getLineCount();
postItems(lineCount);
$('.answer').text("Number of lines: " + lineCount);
});
// calculates the amount of lines required to hold the items
function getLineCount() {
var lineWidth = $('.container').width();
var itemWidthSum = 0;
var lineCount=1;
$('.item').each(function(index, element) {
if((lineWidth - itemWidthSum) > ($(element).outerWidth())) {
itemWidthSum = itemWidthSum + $(element).outerWidth();
} else {
lineCount++;
itemWidthSum = $(element).outerWidth();
}
});
return lineCount;
}
// overlays rows for the amount of linebreaks
function postItems(lineCount){
var container = $('<div />');;
for(var i = 1; i <= lineCount; i++) {
container.append('<div class="line">' + i + '</div>');
}
$('.line-wrap').html(container);
}
body {
text-align:center;
}
.answer {
position: fixed;
left: 0;
bottom: 0;
}
.container {
position: relative;
width: 50%;
margin: 0 auto;
border: 1px solid #e8e8e8;
display: inline-block;
}
.item {
height: 50px;
padding:0 10px;
background-color: #aef2bd;
float: left;
opacity:0.2;
white-space: nowrap;
}
.line-wrap {
position: absolute;
border: 1px solid red;
width: 100%;
height: 100%;
top:0; left: 0;
}
.line {
height: 50px;
width: 100%;
background-color: blue;
opacity:0.5;
color: white;
transition: all 0.5s ease;
}
.line:hover {
background-color: yellow;
color: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="item-wrap">
<div class="item">Computer Science</div>
<div class="item">Language</div>
<div class="item">Marketing</div>
<div class="item">Biology</div>
<div class="item">Computer Science</div>
<div class="item">Language</div>
<div class="item">Marketing</div>
<div class="item">Biology</div>
<div class="item">Computer Science</div>
<div class="item">Language</div>
<div class="item">Marketing</div>
<div class="item">Biology</div>
<div class="item">Computer Science</div>
<div class="item">Language</div>
<div class="item">Marketing</div>
<div class="item">Biology</div>
</div>
<div class="line-wrap">
</div>
</div>
<h1 class="answer"></h1>
i want move my #timebase1 div into draghere div. now its move only the start of the div, i want to drop it in anywhere inside the dragehere div.
function funct(e) {
var id = e.id;
mouseXY(id);
}
function mouseXY(id) {
//alert(id);
var x = event.pageX,
y = event.pageY
$('#' + id).css({
top: y,
left: x + ''
});
}
.activelevel1 {
background-color: #EA623E;
}
.timescalebase {
margin-top: 13px;
height: 7px;
position: relative;
width:0px;
}
<div id="draghere"style="width:100%;margin-top:25px;">
<div id="timebase1"draggable="true"class="timescalebase activelevel1" ondrag=funct(this)>
</div>
You must allowdrop on your target div like this :
function funct(e) {
var id = e.id;
mouseXY(id);
}
function allowDrop(ev) {
ev.preventDefault();
}
function mouseXY(id) {
var x = event.pageX,
y = event.pageY
$('#' + id).css({
left: x
});
}
.activelevel1 {
background-color: red;
width: 10px;
height: 10px;
}
.timescalebase {
margin-top: 13px;
height: 7px;
position: relative;
}
#draghere {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="draghere" style="width:100%;margin-top:25px;" ondragover="allowDrop(event)">
<div id="timebase1" draggable="true" class="timescalebase activelevel1" ondrag="javascript:funct(this)">
</div>
</div>
EDIT
One example with jquery-ui :
https://jsfiddle.net/2gaq2r15/
$(document).ready(function(e) {
$("#timebase1").draggable({
containment: "#draghere",
axis: "x"
});
});
How do I change the placeholder like as the elements replace each other place.
Please see the example
https://jsfiddle.net/98h31o9v/11/
JavaScript
indexOfCell = 0;
add boxes to #div element
$('#add_box').on('click', function() {
var cell = $("<div></div>");
var elementObj = cell.get(0);
$('#div').append(elementObj);
cell.addClass('content-box').attr('id', 'box_' + indexOfCell);
cell.text(indexOfCell);
indexOfCell += 1;
console.log(elementObj);
$(cell).draggable({
helper: 'original',
zIndex: 10001,
start: function(event, ui) {
if ($(this).data('placeholder') === undefined) {
$(this).data('placeholder', createPlaceholder($(this)));
}
setPlaceHolder($(this).data('placeholder'), $(this));
$(this).after($(this).data('placeholder'));
},
stop: function(event, ui) {
$(this).css('left', $(this).data('placeholder').css('left'));
$(this).css('top', $(this).data('placeholder').css('top'));
$(this).data('placeholder').after($(this));
$(this).data('placeholder').detach();
}
});
$(cell).droppable({
tolerance: 'intersect',
greedy: true,
over: function(event, ui) {
replaceTwoItem(ui.draggable.data('placeholder'), $(this));
}
});
create placeholder
function createPlaceholder(that) {
var className = that.attr('class');
var placeholder = $(document.createElement(that.get(0).nodeName))
.addClass(className || className + " ui-sortable-placeholder")
.removeClass("ui-sortable-helper").css({
background: 'yellow',
border: '1px solid grey'
});
return placeholder;
}
set the placeholder to cell
function setPlaceHolder(placeholder, cell) {
placeholder.css('width', cell.width());
placeholder.css('height', cell.height());
placeholder.css("display", 'block');
placeholder.css('position', 'absolute');
placeholder.css('top', cell.css('top'));
placeholder.css('left', cell.css('left'));
}
replace two item when drag
function replaceTwoItem(itemFrom, itemTo) {
var itemToInsert;
var action;
if (itemFrom.index() === 0) {
itemToInsert = itemFrom.parent();
action = "prepend";
} else {
itemToInsert = itemFrom.prev();
action = "after";
}
itemTo.before(itemFrom);
if (itemTo.get(0) != itemToInsert.get(0)) {
if (action == 'prepend') {
itemToInsert.prepend(itemTo);
} else if (action == 'after') {
itemToInsert.after(itemTo);
}
}
}
});
HTML
<button id="add_box">AddBox</button>
<div id="div">
</div>
CSS
.content-box {
width: 100px;
height: 100px;
background: green;
margin: 5px;
float: left;
}
After the brief discussion in the comments about your requirements I think you can get rid of most of the code you're currently using. The example on the jquery
ui website can be tweaked slightly to get what you want.
Fiddle Example
HTML:
<button id="add_box">AddBox</button>
<div id="sortable" class="ui-sortable">
</div>
JQuery:
$('#add_box').on('click', function() {
//Determine the existing child count.
var boxCount = $('#sortable').children().length;
//Create a new "box" and add it to the end of the list.
var newBox = $('<div class="ui-state-default">' + boxCount + '</div>');
$('#sortable').append(newBox);
//Invoke the sortable function to ensure the appropriate events are bound.
$("#sortable").sortable({
placeholder: "ui-state-highlight"
});
});
CSS:
The below can be cleaned up somewhat.
#sortable {
margin: 0;
padding: 0;
}
.ui-state-highlight {
background: yellow;
margin: 0 5px 5px 5px;
color: black;
float: left;
width: 100px;
height: 100px;
}
.ui-state-default {
background: green;
margin: 0 5px 5px 5px;
color: black;
float: left;
width: 100px;
height: 100px;
}
Update .ui-state-default to change the initial colour and update .ui-state-highlight to change the placeholder colour.