|
$(function() { |
|
// maximum number of columns that can be within a row, |
|
// for instance: 3 would be 3 col-sm-4 columns across a row. |
|
|
|
// var dyCol = 6; |
|
var colors = [ |
|
{col: '#50cc79'}, |
|
{col: '#406fff'}, |
|
{col: '#4c4fe0'}, |
|
{col: '#e04c8a'}, |
|
{col: '#fae34b'}, |
|
{col: '#fa9d4b'} |
|
]; |
|
var zone_array = [ |
|
{ |
|
id: 'zone_1', |
|
innerId: 'inner_1', |
|
col: '', |
|
offset: '', |
|
height: '540px', |
|
width: '500px', |
|
css: 'position: absolute; top: 50%; left: 50%; transform: translate(-50%,0%);', |
|
rowCount: '3', |
|
} |
|
]; |
|
$.fn.stack = function() { |
|
var o = $(this).closest('.absolute').siblings('.absolute').find('.widget'); |
|
var group = $(o).sort(function(a,b) { |
|
return (parseInt($(a).css("z-index"),10) || 1) - (parseInt($(b).css("z-index"),10) || 1); |
|
}); |
|
if (!group.length) { return; } |
|
|
|
var min = parseInt($(group[0]).css('z-index')) || 1; |
|
$(group).each(function(i) { |
|
console.log(i); |
|
$(this).css('z-index', min + i); |
|
}); |
|
|
|
$(this[0]).css('z-index', min + group.length); |
|
} |
|
// function loadDoc() { |
|
// $.getScript( "https://codepen.io/Souleste/pen/poogjWr.js", function( data, textStatus, jqxhr ) { |
|
|
|
var zoneCount = 0; |
|
$(document).on('click', '.add-row', function() { |
|
var zoneInner = $(this).closest('.zone').find('.zone-inner'); |
|
addCols(); |
|
enableSortable(); |
|
}); |
|
|
|
$(document).on('click', '.remove-row', function() { |
|
var zone = $(this).closest('.zone'); |
|
var zoneInner = zone.find('.zone-inner'); |
|
var zH = zoneInner.height(); |
|
var zW = zoneInner.width(); |
|
var zoneCol = zoneInner.find('.absolute'); |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var c = Math.floor( zW / 12 ); |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( c * colsPerWig ); |
|
var c3 = Math.floor( c * colsPerWig ); |
|
var rowCount = zoneInner.find('.absolute').last().attr('data-row'); |
|
|
|
if (zoneCol.length > (12 - colsPerWig) + 1) { |
|
var el = zoneCol.slice( ((12 - colsPerWig) + 1) * -1 ); |
|
var nested = el.find('.nested-widget').not('.cloner'); |
|
if (nested.length > 0) { |
|
nested.css({'height':'100px', 'width':'100px', 'min-height': '100px'}); |
|
$('.nest-contain').append(nested); |
|
} |
|
el.remove(); |
|
zoneInner.height(zH - c3); |
|
zone.height(zoneInner.height() + 50); |
|
zoneInner.find('.fake-col[data-row="'+rowCount+'"]').remove(); |
|
} |
|
|
|
for (i = 0; i < zoneCol.length; i++) { |
|
var self = zoneCol.eq(i); |
|
var el = self; |
|
var widget = self.find('.widget'); |
|
var wH = widget.height(); |
|
var r = Math.floor( zH / c3 ); |
|
var zH = zoneInner[0].offsetHeight; |
|
var zB = zoneInner[0].offsetTop + zH; |
|
var cH = el[0].offsetHeight; |
|
var cB = el[0].offsetTop + cH; |
|
|
|
if ( cB > zH ) { |
|
widget.css('height', wH - c3 ); |
|
widget.height( wH - c3 ); |
|
// console.log(wH); |
|
// console.log(wH - c3); |
|
} |
|
} |
|
|
|
}); |
|
|
|
$(document).on('click', '#add_zone', function() { |
|
var addZone = $(this); |
|
var rando = Math.floor(Math.random() * colors.length); |
|
var zoneInner = $(this).closest('.zone').find('.zone-inner'); |
|
var cols = zoneInner.find('.absolute'); |
|
var zoneHeight = zoneInner.height(); |
|
var zoneWidth = zoneInner.width(); |
|
var cols = Math.floor(zoneWidth / 12); |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var colsm = 12 / dyCol; |
|
var colsNum = Math.floor( cols * colsm ); |
|
zoneCount = 0; |
|
zoneInner.find('.widget').each(function() { |
|
var self = $(this); |
|
var txt = self.find('.zone-txt'); |
|
self.attr('id','wig_' + (zoneCount + 1) ); |
|
txt.html(zoneCount + 1); |
|
zoneCount = zoneCount + 1; |
|
}); |
|
zoneCount = zoneCount; |
|
if ( $('.zone-col').length < 1 ) { |
|
addCols(); |
|
enableSortable(); |
|
} |
|
$('.absolute').each(function() { |
|
if ( !$(this).hasClass('disabled') && $(this).children().length == 0 ) { |
|
zoneCount++; |
|
var widget = $('<div class="widget" id="wig_'+zoneCount+'" style="width: '+colsNum+'px; height: '+colsNum+'px;"><i class="fa fa-chevron-right resize-icon" aria-hidden="true"></i><i class="fa fa-times remove-widget" title="remove this widget"></i><div class="widget-inner" style="background: '+colors[rando]["col"]+';"><div class="nested-col nested-absolute"></div><div class="zone-txt text-center">'+zoneCount+'</div><div class="widget-title"></div></div></div>'); |
|
$(this).append(widget); |
|
widget.css({'min-width':colsNum, 'min-height':colsNum }); |
|
setData(widget, $(this)); |
|
disableCol($(this)); |
|
var sibs = $(this).siblings('.absolute'); |
|
// overlap(sibs, $(this)); |
|
|
|
var ani = $(this).find('.widget-inner'); |
|
animateWidget(ani); |
|
|
|
var uiItem = $('.widget'); |
|
var containTo = $(this).closest('.zone-inner'); |
|
|
|
resize(uiItem, containTo, cols, colsNum, colsm); |
|
enableSortable(); |
|
|
|
// var howMany = parseInt($(this).find('.widget').attr('data-height')); |
|
// // for (n = 0; n < howMany; n++) { |
|
// createNestedCols($(this).find('.widget').find('.widget-inner')); |
|
// // } |
|
|
|
return false; |
|
} |
|
}); |
|
}); |
|
|
|
// CREATE ZONES FROM ARRAY |
|
function createZones() { |
|
// count the number of zones in zone_array |
|
var count = zone_array.length; |
|
for (var i = 0; i < count; i++) { |
|
$('#zone_div').append('<div id="'+zone_array[i]["id"]+'" class="zone" style="height:'+zone_array[i]["height"]+'; width:'+zone_array[i]["width"]+'; '+zone_array[i]["css"]+'" data-rows="'+zone_array[i]["rowCount"]+'"><div class="zone-helper"><div class="add-row" title="add a row."></div><div class="remove-row" title="remove a row."></div><button class="btn btn-sm clear-zone" title="remove all widgets from this zone.">clear zone</button><button id="add_zone" class="btn btn-sm">add zone</button></div><div id="'+zone_array[i]["innerId"]+'" class="zone-inner"></div></div>'); |
|
} |
|
// console.log( JSON.stringify(zone_array, null, "\t") ); |
|
} createZones(); |
|
// CREATE ZONE-COLS |
|
function createZoneCols() { |
|
$('.zone-inner').each(function(e) { |
|
var self = $(this); |
|
var win = $(this).width(); |
|
switch(true) { |
|
case ( 0 < win && win <= 400 ): self.attr('data-cols', '3'); break; |
|
case ( 400 < win && win <= 500 ): self.attr('data-cols', '4'); break; |
|
case ( 500 < win ): self.attr('data-cols', '6'); break; |
|
} |
|
// get the zones width, divide by 12 to make 12 'columns' |
|
var zoneHeight = self.height(); |
|
var zoneWidth = parseFloat( self.width() ); |
|
var cols = Math.floor( zoneWidth / 12 ); // make 12 columns |
|
var perc = (cols / zoneWidth) * 100; // one column percent of zone-inner |
|
var dyCol = self.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
|
|
// var rows = Math.floor( zoneHeight / colsNum ); |
|
var rows = parseInt(self.closest('.zone').attr('data-rows')); |
|
var rows = 3; // make a square |
|
var colAmount = 13 - colsPerWig; |
|
for (var x = 0; x < rows; x++) { |
|
for (var y = 0; y < colAmount; y++) { |
|
// self.append('<div class="zone-col absolute" data-row="'+x+'" style="min-width: '+ (cols) +'px; min-height: '+ colsNum +'px; top:'+ (colsNum * x) +'px; left: '+ (cols * y) +'px; "></div>'); |
|
self.append('<div class="zone-col absolute" data-eq="'+y+'" data-row="'+x+'" style="min-width: '+perc+'%; min-height: '+ colsNum +'px; top:'+(colsNum * x)+'px; left: '+(cols * y)+'px; "></div>'); |
|
var appended = self.find('.absolute[data-row="'+x+'"][data-eq="'+y+'"]'); |
|
var i = self.find('.absolute').index(appended); |
|
appended.attr('data-index', i); |
|
} |
|
for (var f = 0; f < (12 - colAmount); f++) { |
|
var lastFake = self.find('.fake-col[data-row="'+x+'"]').last(); |
|
var left = lastFake.length > 0 ? lastFake.position().left + cols : colAmount * cols; |
|
self.append('<div class="fake-col" data-row="'+x+'" style="min-width: '+perc+'%; min-height: '+ colsNum +'px; top:'+(colsNum * x)+'px; left: '+ left +'px; "></div>'); |
|
} |
|
} |
|
|
|
var lastCol = self.find('.absolute').last(); |
|
var rowCount = parseInt(lastCol.attr('data-row')); |
|
self.css({ |
|
'height': (rowCount + 1) * colsNum, |
|
'width': (cols * 12) |
|
}); |
|
self.closest('.zone').css({ |
|
'height': (rowCount + 1) * colsNum + 50, |
|
'width': (cols * 12) + 15 |
|
}); |
|
enableSortable(); |
|
|
|
}); |
|
} createZoneCols(); |
|
|
|
|
|
function buildZones() { |
|
for (z = 0; z < zone_array.length; z++) { |
|
// console.log('zone: ' + JSON.stringify(zone_array[z], null, "\t")); |
|
var zone = zone_array[z]; |
|
|
|
// get the zones width, divide by 12 to make 12 'columns' |
|
var zone_inner = $('.zone-inner'); |
|
var zoneWidth = parseFloat(zone_inner.width()); |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var colP = ( (cols / zoneWidth) * 100 ); // one column percent of zone-inner |
|
var dyCol = zone_inner.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
|
|
// go through each widget and append to corresponding zone. |
|
var wig_array = zone['children']; |
|
|
|
for (w = 0; w < wig_array.length; w++) { |
|
var current = wig_array[w]; |
|
var data_width = parseInt(current["data_width"]) * cols; |
|
var data_height = parseInt(current["data_height"]) * colsNum; |
|
|
|
var wig = $('<div class="widget" id="'+current["id"]+'" style="width: '+data_width+'px; height: '+data_height+'px; min-width: '+colsNum+'px; min-height: '+colsNum+'px;" data-x="'+current["data_x"]+'" data-y="'+current["data_y"]+'"><i class="fa fa-chevron-right resize-icon" aria-hidden="true"></i><i class="fa fa-times remove-widget" title="remove this widget"></i><div class="widget-inner" style="background:'+current["bg"]+';"><div class="nested-col nested-absolute"></div><div class="zone-txt text-center">blah</div><div class="widget-title"></div></div></div>'); |
|
var goHere; |
|
var og = zone_inner.find('.absolute[data-row="'+current['data_y']+'"]').eq(current['data_x']); |
|
|
|
// if the position from the array is not open, find the next open '.zone-col', and add more rows when needed. |
|
// this could happen when the width of the zone changes. |
|
if (og.length == 0) { |
|
// need to find the last .absolute that has .widget child |
|
goHere = zone_inner.find('.absolute:has(".widget")').last().nextAll('.zone-col').first(); |
|
if (goHere.length == 0) { |
|
addCols(); |
|
} |
|
goHere = zone_inner.find('.absolute:has(".widget")').last().nextAll('.zone-col').first(); |
|
} else if (og.hasClass('disabled')) { |
|
goHere = zone_inner.find('.absolute:has(".widget")').last().nextAll('.zone-col').first(); |
|
if (goHere.length == 0) { |
|
addCols(); |
|
} |
|
goHere = zone_inner.find('.absolute:has(".widget")').last().nextAll('.zone-col').first(); |
|
} else { |
|
goHere = og; |
|
} |
|
|
|
function moreHeight() { |
|
// when there are not enough rows for a widget's height... |
|
var row_and_height = parseInt(goHere.attr('data-row')) + parseInt(current["data_height"]); |
|
var last_row_num = parseInt(zone_inner.find('.absolute').last().attr('data-row')); |
|
if (row_and_height != last_row_num) { |
|
var amountNeeded = (row_and_height - last_row_num) - 1; |
|
for (n = 0; n < amountNeeded; n++) { |
|
addCols(); |
|
} |
|
} |
|
} moreHeight(); |
|
|
|
goHere.append(wig); |
|
|
|
// check if widget is overflowing the zone, if so, find the next open zone-col |
|
var zH = zone_inner[0].offsetHeight; |
|
var zW = zone_inner[0].offsetWidth; |
|
|
|
var zR = zone_inner[0].offsetLeft + zW; |
|
var zB = zone_inner[0].offsetTop + zH; |
|
|
|
var cH = goHere[0].offsetHeight; |
|
var cW = goHere[0].offsetWidth; |
|
var cR = goHere[0].offsetLeft + cW; |
|
var cB = goHere[0].offsetTop + cH; |
|
|
|
while (cR > zR) { |
|
var de = goHere.find('.widget').detach(); |
|
goHere = goHere.nextAll('.zone-col').first(); |
|
goHere.append(de); |
|
|
|
cW = goHere[0].offsetWidth; |
|
cR = goHere[0].offsetLeft + cW; |
|
|
|
if (cR < zR) { |
|
break; |
|
} |
|
} |
|
// if there are no open zone-cols, append a new row until the widget fits. |
|
moreHeight(); |
|
|
|
// enable all the sortables |
|
enableSortable(); |
|
|
|
// zoneOverflow(zone_inner, goHere); |
|
|
|
for (i = 0; i < goHere.siblings('.absolute').length; i++) { |
|
var colSib = goHere.siblings('.absolute').eq(i); |
|
if (colSib.children('.widget').length > 0) { |
|
dropCollision(colSib, goHere); |
|
} |
|
overlap(colSib, goHere); |
|
} |
|
disableCol(goHere); |
|
|
|
setData(wig, goHere); |
|
// disableCol(goHere); |
|
|
|
// var howMany = parseInt(goHere.find('.widget').attr('data-height')); |
|
// // for (n = 0; n < howMany; n++) { |
|
// createNestedCols(goHere.find('.widget').find('.widget-inner')); |
|
// // } |
|
|
|
var containTo = zone_inner; |
|
resize(wig, containTo, cols, colsNum, colsPerWig); |
|
} |
|
} |
|
} |
|
// buildZones(); |
|
|
|
|
|
// function createNestedCols(el) { |
|
// var zoneInner = el.closest('.zone-inner'); |
|
// var dyCol = zoneInner.attr('data-cols'); |
|
// var zoneWidth = parseFloat( zoneInner.width() ); |
|
// var cols = Math.floor( zoneWidth / 12 ); // make 12 columns |
|
// var perc = (cols / zoneWidth) * 100; // one column percent of zone-inner |
|
// var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
// var colsNum = Math.floor( cols * colsPerWig ); |
|
|
|
// var newCol = $('<div class="nested-col nested-absolute"></div>'); |
|
// el.append(newCol); |
|
// } |
|
|
|
// function removeWhitespace() { |
|
// var zoneInner = $('.zone-inner'); |
|
// var zH = $('.zone-inner').height(); |
|
// var zW = $('.zone-inner').width(); |
|
// var dyCol = $('.zone-inner').attr('data-cols'); |
|
// var c = Math.floor( zW / 12 ); |
|
// var colsm = 12 / dyCol; |
|
// var c3 = Math.floor( c * colsm ); |
|
|
|
// var last = $('.absolute').last(); |
|
// var x = $('.absolute').index(last); |
|
|
|
// if ($('.absolute').length > ((dyCol * 2) - 1) * 3) { |
|
// for (i = x; i > x - ((dyCol * 2) - 1); i--) { |
|
// console.log(i); |
|
// var change = $('.absolute').eq(i); |
|
// console.log(change); |
|
// change.css('background','blue'); |
|
// change.addClass('remove-this'); |
|
// } |
|
// if ($('.remove-this').children().length < 1) { |
|
// $('.remove-this').remove(); |
|
// $('.zone-inner').height(zH - c3); |
|
// $('.zone').height($('.zone').height() - c3); |
|
// } |
|
// } |
|
// } |
|
|
|
function enableSortable() { |
|
var thisWig; |
|
$('.zone-col').sortable({ |
|
items: '.widget', |
|
connectWith: '.zone-col', |
|
handle: ".widget-inner", |
|
placeholder: "widget-placeholder ui-corner-all", |
|
// tolerance: 'pointer', |
|
// cursorAt: { left: 20, top: 20 }, |
|
start: function(event, ui) { |
|
console.log($(event.target)); |
|
|
|
var thisCol = $(this); |
|
thisCol.find('.widget').css('position', 'absolute !important'); |
|
var zone = $(this).closest('.zone-inner'); |
|
var zoneWidth = thisCol.parent('.zone-inner').width(); |
|
var cols = parseFloat( zoneWidth / 12 ); |
|
var dyCol = thisCol.parent('.zone-inner').attr('data-cols'); |
|
var colsm = 12 / dyCol; |
|
var colsNum = Math.floor( cols * colsm ); |
|
var allCols = zone.find('.absolute'); |
|
var sibs = $(this).siblings('.absolute'); |
|
|
|
// enable all cols so that we can drop to any cols that we were previously overlapping. |
|
enableAll(allCols); |
|
|
|
// loop through the siblings of the currently dragged widget, |
|
// if that sibling has a child, call disableCol() on it. |
|
// then loop through the siblings of that sibling to call overlap() in case it is overlapping other cols. |
|
for (i = 0; i < sibs.length; i++) { |
|
var el = sibs.eq(i); |
|
if ( el.find('.widget').length > 0) { |
|
var elSibs = el.siblings('.absolute'); |
|
for (a = 0; a < elSibs.length; a++) { |
|
var colSib = elSibs.eq(a); |
|
overlap(colSib, el); |
|
} |
|
disableCol(el); |
|
} |
|
} |
|
|
|
var wig = thisCol.find('.widget-inner'); |
|
$('.widget-inner').not(wig).toggleClass('not-dragging'); |
|
|
|
// set the placeholder's height and width equal to this widget. |
|
var wigW = wig[0].offsetWidth; |
|
var wigH = wig[0].offsetHeight; |
|
zone.find('.widget-placeholder').css({ |
|
'width': wigW, |
|
'height': wigH |
|
}); |
|
|
|
// set the 'ogIndex' so that we can see if it changes on stop. |
|
ui.item.data({ |
|
'ogIndex': ui.item.closest('.absolute').index(thisCol) |
|
}); |
|
}, |
|
over: function(event, ui) { |
|
// refresh sortable columns only when we are dragging over them |
|
// previously called in sortable start and that caused a lot of lag with multiple widgets... |
|
$(this).sortable('refresh'); |
|
}, |
|
sort: function(event, ui) { |
|
var x = event.pageX; |
|
var y = event.pageY; |
|
var parentOffset = ui.item.offset(); |
|
var relX = x - parentOffset.left; |
|
var relY = y - parentOffset.top; |
|
|
|
ui.item.offset({ |
|
left: Math.floor(x - relX), |
|
top: Math.floor(y - relY) |
|
}); |
|
}, |
|
receive: function(event, ui) { |
|
var zoneInner = $(this).closest('.zone-inner'); |
|
var zH = zoneInner.height(); |
|
var zW = zoneInner.width(); |
|
var cols = Math.floor( zW / 12 ); |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var colsm = 12 / dyCol; |
|
var colsNum = Math.floor( cols * colsm ); |
|
var thisCol = $(this); |
|
|
|
// DETECT ZONE OVERFLOW |
|
// zoneOverflow(zoneInner, thisCol); |
|
function moreHeight() { |
|
// when there are not enough rows for a widget's height... |
|
var row_and_height = parseInt(thisCol.attr('data-row')) + parseInt(ui.item.attr('data-height')); |
|
var last_row_num = parseInt(zoneInner.find('.absolute').last().attr('data-row')); |
|
if (row_and_height != last_row_num) { |
|
var amountNeeded = (row_and_height - last_row_num) - 1; |
|
for (n = 0; n < amountNeeded; n++) { |
|
addCols(); |
|
} |
|
} |
|
} moreHeight(); |
|
|
|
var el = $(this); |
|
var elSibs = $(this).siblings('.absolute'); |
|
for (i = 0; i < elSibs.length; i++) { |
|
var colSib = elSibs.eq(i); |
|
if (colSib.find('.widget').length > 0) { |
|
dropCollision(colSib, el); |
|
} |
|
overlap(colSib, el); |
|
} |
|
disableCol(thisCol); |
|
|
|
var ani = el.find('.widget-inner'); |
|
animateWidget(ani); |
|
|
|
if ( ui.item.find(".remove-widget").length == 0 ) { |
|
ui.item.append('<i class="fa fa-chevron-right resize-icon" aria-hidden="true"></i><i class="fa fa-times remove-widget" title="remove this widget"></i>'); |
|
ui.item.outerWidth(colsNum); |
|
ui.item.outerHeight(colsNum); |
|
ui.item.css({'min-width':colsNum, 'min-height':colsNum }); |
|
var el; |
|
var elSibs; |
|
var uiItem; |
|
} |
|
|
|
var uiItem = ui.item; |
|
var containTo = $(this).closest('.zone-inner'); |
|
|
|
resize(uiItem, containTo, cols, colsNum, colsm); |
|
|
|
var widget = $(this).find('.widget'); |
|
var zoneCol = $(this); |
|
setData(widget, zoneCol); |
|
|
|
var wig = ui.item.find('.widget-inner'); |
|
var func = 'zonesortreceive'; |
|
var nested = ui.item.find('.nested-widget'); |
|
for(b = 0; b < nested.length; b++) { |
|
var self = nested.eq(b); |
|
outOfNest(func, wig, self); |
|
} |
|
}, |
|
stop: function(event, ui) { |
|
$('.widget-inner').not(thisWig).toggleClass('not-dragging'); |
|
var thisCol = $(this); |
|
var zoneInner = thisCol.closest('.zone-inner'); |
|
var el = $(this); |
|
var elSibs = $(this).siblings('.absolute'); |
|
|
|
// DETECT ZONE OVERFLOW |
|
zoneOverflow(zoneInner, thisCol); |
|
|
|
for (i = 0; i < elSibs.length; i++) { |
|
var colSib = elSibs.eq(i); |
|
if (colSib.find('.widget').length > 0) { |
|
dropCollision(colSib, el); |
|
} |
|
overlap(colSib, el); |
|
} |
|
if ($(this).children().length > 0) { |
|
disableCol(thisCol); |
|
} |
|
|
|
var ani = el.find('.widget-inner'); |
|
animateWidget(ani); |
|
|
|
var widget = $(this).find('.widget'); |
|
var zoneCol = $(this); |
|
setData(widget, zoneCol); |
|
|
|
var wig = ui.item.find('.widget-inner'); |
|
var func = 'zonesortstop'; |
|
var nested = ui.item.find('.nested-widget'); |
|
for(b = 0; b < nested.length; b++) { |
|
var self = nested.eq(b); |
|
outOfNest(func, wig, self); |
|
} |
|
|
|
// detect if the item position has changed so that - |
|
// we can remind the user to save... |
|
if (ui.item.closest('.absolute').index(thisCol) != ui.item.data('ogIndex')) { |
|
console.log('position has changed'); |
|
} |
|
} |
|
}); |
|
|
|
$('.nest-contain').sortable({ |
|
connectWith: '.nested-col', |
|
items: '.nested-widget', |
|
placeholder: 'nested-placeholder', |
|
handle: '.nested-widget-inner', |
|
zIndex: 9999, |
|
start: function(event, ui) { |
|
if ( ui.item.hasClass('cloner') ) { |
|
clone = ui.item.clone(); |
|
return clone; |
|
} |
|
}, |
|
stop: function(event,ui) { |
|
if ( ui.item.parent().hasClass('nest-contain') ) { |
|
ui.item.css({'width':'100px', 'height':'100px', 'min-width':'100px', 'min-height':'100px', 'position':'relative !important'}); |
|
} |
|
if (ui.item.hasClass('cloner') && ! ui.item.parent('.nest-contain').length ) { |
|
clone.appendTo('.nest-contain'); |
|
} |
|
} |
|
}); |
|
|
|
$('.nested-col').sortable({ |
|
items: '.nested-widget', |
|
placeholder: 'nested-placeholder', |
|
forcePlaceholderSize: true, |
|
handle: '.nested-widget-inner', |
|
connectWith:['.nested-col', '.nest-contain'], |
|
zIndex: 9999, |
|
start: function(event, ui) { |
|
var wig = ui.item.closest('.widget'); |
|
wig.stack(); |
|
var ab = wig.closest('.absolute'); |
|
ui.placeholder.css({ |
|
'height': ui.placeholder.height() - 30, |
|
'margin-top': '12px' |
|
}); |
|
|
|
ui.item.data({ |
|
'ogParent': ui.item.closest('.widget').attr('id'), |
|
'ogHeight': ui.item.height() |
|
}); |
|
|
|
$('.nested-col').sortable("option", "stack", ui.item.closest('.widget')); |
|
|
|
}, |
|
receive: function(event, ui) { |
|
console.log('received'); |
|
var zoneInner = $(this).closest('.zone-inner'); |
|
var zoneWidth = parseFloat(zoneInner.width()); |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var dyCol = zoneInner.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
console.log(ui.item.closest('.widget-inner').height()); |
|
var minHeight = $(this).height() / ui.item.closest('.widget').attr('data-height'); |
|
ui.item.css({ |
|
'width': '100%', |
|
'min-height': colsNum - 10, |
|
'height': colsNum - 10 |
|
}); |
|
|
|
var widget = ui.item.closest('.widget'); |
|
var zoneCol = widget.closest('.absolute'); |
|
var sibs = zoneCol.siblings('.absolute'); |
|
var widgetOff = parseInt(widget.attr('data-y')) + parseInt(widget.attr('data-height')); |
|
|
|
var csHeight = ui.item.attr('data-cs-height'); |
|
if (csHeight != undefined) { |
|
if (csHeight.length) { |
|
while (ui.item.height() < csHeight) { |
|
ui.item.height(ui.item.height() + colsNum); |
|
console.log('something happened'); |
|
if (ui.item.height() >= csHeight) { |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
var y1 = widget.offset().top; |
|
var b1 = y1 + widget.height(); |
|
var y2 = ui.item.offset().top; |
|
var b2 = y2 + ui.item.height(); |
|
|
|
// var firstNested = widget.find('.nested-widget').first(); |
|
var newHeight = 0; |
|
var nested = widget.find('.nested-widget'); |
|
for(var n = 0; n < nested.length; n++) { |
|
var self = nested.eq(n); |
|
console.log('height: ' + self.outerHeight()); |
|
newHeight += self.outerHeight(); |
|
} |
|
console.log(newHeight); |
|
// if (newHeight > (widget.height() + widget.offset().top)) { |
|
widget.height( Math.round( (newHeight + 10) / colsNum) * colsNum ); |
|
// } |
|
|
|
setData(widget, zoneCol); // set data attributes |
|
|
|
var group = []; |
|
var group2 = []; |
|
var isPushy = ''; |
|
for (a = 0; a < sibs.length; a++) { |
|
var sib = sibs.eq(a); |
|
if (sib.find('.widget').length > 0) { |
|
var sibWig = sib.find('.widget'); |
|
var pushem = pushy(sib, zoneCol); |
|
if (pushem == true) { |
|
group.push(sibWig[0]); |
|
sibWig[0].remove(); |
|
isPushy = true; |
|
} else if (pushem == false) { |
|
console.log('blah'); |
|
} else { |
|
console.log(pushem); |
|
var sibWig = pushem.obj.find('.widget'); |
|
group2.push(sibWig[0]); |
|
sibWig[0].remove(); |
|
// isPushy = true; |
|
} |
|
} |
|
} |
|
|
|
if (isPushy == true) { |
|
var groupLength = group.length - 1; |
|
var firstWig = group[0]; |
|
var lastWig = group[groupLength]; |
|
var wigEnd = (parseInt(widget.attr('data-y')) + parseInt(widget.attr('data-height'))); |
|
var goHere = zoneInner.find('.absolute[data-row="'+ (wigEnd - 1) +'"]').last(); |
|
if (goHere.length == 0) { |
|
addCols(); |
|
} |
|
goHere = zoneInner.find('.absolute[data-row="'+ (wigEnd - 1) +'"]').last(); |
|
|
|
var rowsNeeded = (wigEnd - widgetOff); |
|
addColsAfter(goHere, rowsNeeded); |
|
|
|
for (b = 0; b < sibs.length; b++) { |
|
var sib = sibs.eq(b); |
|
var colY = zoneCol.offset().top; |
|
var colB = zoneCol.height() + colY; |
|
|
|
var sibY = sib.offset().top; |
|
var sibB = sib.height() + sibY; |
|
|
|
var row = parseInt(sib.attr('data-row')); |
|
if ( sibB > colB && sibY >= colB) { |
|
var de = sib.detach(); |
|
zoneInner.append(de); |
|
de.css('top', sib.position().top + (colsNum * rowsNeeded)); |
|
de.attr('data-row', row + rowsNeeded); |
|
} |
|
} |
|
|
|
var lastCol = zoneInner.find('.absolute').last(); |
|
var rowCount = parseInt(lastCol.attr('data-row')); |
|
zoneInner.height((rowCount + 1) * colsNum); |
|
zoneInner.closest('.zone').height( $('.zone-inner').height() + 50 ); |
|
|
|
// for each element that is being overlapped, find its new column after we have appended rows. |
|
for (var g = 0; g < group.length; g++) { |
|
var self = group[g]; |
|
var x = $(self).attr('data-x'); |
|
var y = parseInt($(self).attr('data-y')) + rowsNeeded; // our new y position is the original y + the amount of rows we appended. |
|
var putWidgetHere = zoneInner.find('.absolute[data-eq="'+x+'"][data-row="'+y+'"]'); |
|
putWidgetHere.append($(self)); |
|
setData($(self), putWidgetHere); // set data attributes |
|
} |
|
|
|
} |
|
|
|
// for each element that is not under the overlapped elements, append to its original position. |
|
for (var g2 = 0; g2 < group2.length; g2++) { |
|
var self = group2[g2]; |
|
var x = $(self).attr('data-x'); |
|
var y = $(self).attr('data-y'); |
|
var putWidgetHere = zoneInner.find('.absolute[data-eq="'+x+'"][data-row="'+y+'"]'); |
|
putWidgetHere.append($(self)); |
|
setData($(self), putWidgetHere); // set data attributes |
|
} |
|
|
|
|
|
|
|
// var wig = ui.item.closest('.widget-inner'); |
|
// var func = event.type; |
|
// outOfNest(func, wig, ui.item); |
|
|
|
// var nestSibs = ui.item.siblings('.nested-widget'); |
|
// for (i = 0; i < nestSibs.length; i++) { |
|
// var self = nestSibs.eq(i); |
|
// outOfNest(func, wig, self); |
|
// } |
|
|
|
function moreHeight() { |
|
// when there are not enough rows for a widget's height... |
|
var row_and_height = parseInt(zoneCol.attr('data-row')) + parseInt(widget.attr('data-height')); |
|
var last_row_num = parseInt(zoneInner.find('.absolute').last().attr('data-row')); |
|
if (row_and_height != last_row_num) { |
|
var amountNeeded = (row_and_height - last_row_num) - 1; |
|
for (n = 0; n < amountNeeded; n++) { |
|
addCols(); |
|
} |
|
} |
|
} moreHeight(); |
|
|
|
|
|
enableAll(zoneInner.find('.absolute')); |
|
for (bl = 0; bl < sibs.length; bl++) { |
|
var el = sibs.eq(bl); |
|
if ( el.find('.widget').length > 0) { |
|
var elSibs = el.siblings('.absolute'); |
|
for (a = 0; a < elSibs.length; a++) { |
|
var colSib = elSibs.eq(a); |
|
// if (colSib.find('.widget').length > 0) { |
|
// disableCol(colSib); |
|
// } |
|
var sibSibs = colSib.siblings('.absolute'); |
|
for (ss = 0; ss < sibSibs.length; ss++) { |
|
var sibSib = sibSibs.eq(ss); |
|
overlap(sibSib, colSib); |
|
} |
|
overlap(colSib, el); |
|
} |
|
disableCol(el); |
|
} |
|
overlap(el, zoneCol); |
|
setData(el.find('.widget'), el); // set data attributes |
|
} |
|
|
|
|
|
disableCol(zoneCol); |
|
setData(widget, zoneCol); // set data attributes |
|
|
|
nestedResize(ui.item, colsNum, ui.item.closest('.nested-col')); |
|
}, |
|
stop: function(event, ui) { |
|
var zoneInner = $(this).closest('.zone-inner'); |
|
var zoneWidth = parseFloat(zoneInner.width()); |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var dyCol = zoneInner.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
|
|
var wig = ui.item.closest('.widget-inner'); |
|
var func = event.type; |
|
outOfNest(func, wig, ui.item); |
|
|
|
var sibs = ui.item.siblings('.nested-widget'); |
|
for (i = 0; i < sibs.length; i++) { |
|
var self = sibs.eq(i); |
|
outOfNest(func, wig, self); |
|
} |
|
|
|
nestedResize(ui.item, colsNum, ui.item.closest('.nested-col')); |
|
}, |
|
over: function(event, ui) { |
|
var zoneInner = $(this).closest('.zone-inner'); |
|
var zoneWidth = parseFloat(zoneInner.width()); |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var dyCol = zoneInner.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
var minHeight = colsNum - 10; |
|
|
|
console.log('yeeeee'); |
|
ui.item.css({ |
|
'width': $(this).width() |
|
}); |
|
|
|
if(ui.item.data('ogParent') != ui.placeholder.closest('.widget').attr('id')) { |
|
ui.placeholder.height(minHeight - 30); |
|
ui.item.height(minHeight); |
|
console.log(ui.placeholder.closest('.widget').attr('id')); |
|
} else { |
|
ui.item.height(ui.item.data('ogHeight')); |
|
ui.placeholder.height(ui.item.data('ogHeight') - 30); |
|
} |
|
} |
|
}); |
|
} enableSortable(); |
|
|
|
function nestedResize(uiItem, colsNum, containTo) { |
|
console.log(containTo); |
|
uiItem.resizable({ |
|
containment: containTo, |
|
handles: 's', |
|
grid: [null, colsNum], |
|
start: function(event, ui) { |
|
}, |
|
resize: function(event, ui) { |
|
var wig = $(this).closest('.widget-inner'); |
|
var func = event.type; |
|
var sibs = $(this).siblings('.nested-widget'); |
|
for (i = 0; i < sibs.length; i++) { |
|
var self = sibs.eq(i); |
|
outOfNest(func, wig, self); |
|
} |
|
}, |
|
stop: function(event, ui) { |
|
var wig = $(this).closest('.widget-inner'); |
|
var func = event.type; |
|
var sibs = $(this).siblings('.nested-widget'); |
|
for (i = 0; i < sibs.length; i++) { |
|
var self = sibs.eq(i); |
|
outOfNest(func, wig, self); |
|
} |
|
} |
|
}); |
|
} |
|
|
|
$(document).on('mousemove', function(e) { |
|
var el = $('.nested-widget.ui-resizable-resizing'); |
|
if (el.length > 0) { |
|
var wig = el.closest('.widget-inner'); |
|
var i = wig.find('.nested-widget').index(el); |
|
if (i > 0) { |
|
var y1 = el.offset().top; |
|
var b1 = y1 + el.height(); |
|
var y2 = wig.offset().top; |
|
var b2 = y2 + wig.height(); |
|
|
|
if (b1 > b2) { |
|
el.css({ 'max-height': el.height() }); |
|
} else { |
|
el.css({ 'max-height': 'unset' }); |
|
} |
|
} |
|
} |
|
}); |
|
|
|
function outOfNest(func, wig, item) { |
|
var zoneInner = item.closest('.zone-inner'); |
|
var zoneWidth = parseFloat(zoneInner.width()); |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var dyCol = zoneInner.attr('data-cols'); // how many widgets are allowed to fit in a row |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
var x1 = item[0].offsetLeft; |
|
var y1 = item[0].offsetTop; |
|
var r1 = item[0].offsetWidth + x1; |
|
var b1 = item[0].offsetHeight + y1; |
|
var x2 = wig[0].offsetLeft; |
|
var y2 = wig[0].offsetTop; |
|
var r2 = wig[0].offsetWidth + x2; |
|
var b2 = wig[0].offsetHeight + y2; |
|
|
|
console.log(b1, b2); |
|
|
|
switch(func) { |
|
// case 'resizestop': |
|
// if (b1 > b2) { |
|
// var inner = item.find('.nested-widget-inner').html(); |
|
// var re = $('<div class="nested-widget"><div class="nested-widget-inner">'+inner+'</div></div>'); |
|
// item.remove(); |
|
// if (!item.hasClass('cloner')) { |
|
// $('.nest-contain').append(re); |
|
// } |
|
// } |
|
// break; |
|
case 'resize': |
|
if (b1 > b2) { |
|
item.find('.nested-widget-inner').css({ |
|
'background' : 'rgba(245, 75, 66, 0.5)' |
|
}); |
|
} else { |
|
item.find('.nested-widget-inner').css({ |
|
'background' : '#333' |
|
}); |
|
} |
|
break; |
|
case 'sortstop': case 'sortreceive': |
|
if (b1 > b2) { |
|
var inner = item.find('.nested-widget-inner').html(); |
|
var re = $('<div class="nested-widget"><div class="nested-widget-inner">'+inner+'</div></div>'); |
|
item.remove(); |
|
if (!item.hasClass('cloner')) { |
|
$('.nest-contain').append(re); |
|
} |
|
} |
|
break; |
|
case 'zonesortstop': case 'zonesortreceive': case 'resizestop': |
|
if (b1 > b2) { |
|
if (wig.find('.nested-widget').index(item) + 1 == wig.find('.nested-widget').length && y1 < b2) { |
|
console.log('yeeessSDsdee'); |
|
item.css({'height': (b1 - b2) - 10}); |
|
item.find('.nested-widget-inner').css({ |
|
'background' : '#333' |
|
}); |
|
} else { |
|
var inner = item.find('.nested-widget-inner').html(); |
|
var re = $('<div class="nested-widget"><div class="nested-widget-inner">'+inner+'</div></div>'); |
|
item.remove(); |
|
if (!item.hasClass('cloner')) { |
|
$('.nest-contain').append(re); |
|
} |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
|
|
function addCols() { |
|
var zoneHeight = $('.zone-inner').height(); |
|
var zoneWidth = $('.zone-inner').width(); |
|
var cols = Math.floor( zoneWidth / 12 ); // make 12 columns |
|
var perc = (cols / zoneWidth) * 100; |
|
var dyCol = $('.zone-inner').attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
$('.zone-inner').closest('.zone').height( (zoneHeight + colsNum)); |
|
var lastCol = $('.zone-inner').find('.absolute').last(); |
|
var appendHere = lastCol[0].offsetTop + colsNum; |
|
|
|
var rowCount = parseInt(lastCol.attr('data-row')); |
|
|
|
var colAmount = (12 - colsPerWig) + 1; |
|
for (var i = 0; i < colAmount; i++) { |
|
$('.zone-inner').append('<div class="zone-col absolute ui-sortable" data-eq="'+i+'" data-row="'+(rowCount + 1)+'" style="min-width: '+perc+'%; min-height: '+colsNum+'px; top:'+appendHere+'px; left: '+(cols * i)+'px; "></div>'); |
|
var blah = $('.zone-inner').find('.absolute[data-row="'+(rowCount + 1)+'"][data-eq="'+i+'"]'); |
|
var n = $('.zone-inner').find('.absolute').index(blah); |
|
blah.attr('data-index', n); |
|
} |
|
// for (var f = 0; f < (12 - colAmount); f++) { |
|
// var lastFake = $('.zone-inner').find('.fake-col[data-row="'+(rowCount + 1)+'"]').last(); |
|
// var left = lastFake.length > 0 ? lastFake.position().left + cols : colAmount * cols; |
|
// $('.zone-inner').append('<div class="fake-col" data-row="'+(rowCount + 1)+'" style="min-width: '+perc+'%; min-height: '+ colsNum +'px; top:'+(colsNum * (rowCount + 1))+'px; left: '+ left +'px; "></div>'); |
|
// } |
|
lastCol = $('.zone-inner').find('.absolute').last(); |
|
rowCount = parseInt(lastCol.attr('data-row')); |
|
$('.zone-inner').height((rowCount + 1) * colsNum); |
|
$('.zone-inner').closest('.zone').height( $('.zone-inner').height() + 50 ); |
|
enableSortable(); |
|
} |
|
|
|
function addColsAfter(el, rowsNeeded) { |
|
var zoneInner = el.closest('.zone-inner'); |
|
var zoneHeight = zoneInner.height(); |
|
var zoneWidth = zoneInner.width(); |
|
var cols = Math.floor( zoneWidth / 12 ); // make 12 columns |
|
var perc = (cols / zoneWidth) * 100; |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
zoneInner.closest('.zone').height( (zoneHeight + colsNum)); |
|
var appendHere = el[0].offsetTop + colsNum; |
|
|
|
var rowCount = parseInt(el.attr('data-row')) + 1; |
|
|
|
var colAmount = (12 - colsPerWig) + 1; |
|
for (la = 0; la < rowsNeeded; la++) { |
|
for (var i = 0; i < colAmount; i++) { |
|
zoneInner.append('<div class="zone-col absolute ui-sortable" data-eq="'+i+'" data-row="'+rowCount+'" style="min-width: '+perc+'%; min-height: '+colsNum+'px; top:'+appendHere+'px; left: '+(cols * i)+'px;"></div>'); |
|
var blah = $('.zone-inner').find('.absolute[data-row="'+(rowCount + 1)+'"][data-eq="'+i+'"]'); |
|
var n = $('.zone-inner').find('.absolute').index(blah); |
|
blah.attr('data-index', n); |
|
} |
|
console.log(la); |
|
appendHere = el[0].offsetTop + (colsNum * (la + 2)); |
|
rowCount = rowCount + 1; |
|
} |
|
enableSortable(); |
|
} |
|
|
|
// REMOVE WIDGET |
|
$(document).on('click', '.remove-widget', function() { |
|
var widget = $(this).closest('.widget'); |
|
var zone = widget.closest('.zone-inner'); |
|
var zoneCol = widget.closest('.absolute'); |
|
var zoneWidth = zone.width(); |
|
var widgetID = widget.attr('id'); |
|
var widgetTxt = widget.find('.zone-txt').html(); |
|
var allCols = zone.find('.absolute'); |
|
var sibs = $(this).closest('.absolute').siblings('.absolute'); |
|
enableAll(allCols); |
|
widget.remove(); |
|
|
|
// again looping through all sortable columns to find overlap. |
|
for (i = 0; i < sibs.length; i++) { |
|
var el = sibs.eq(i); |
|
if ( el.find('.widget').length > 0 ) { |
|
disableCol(el); |
|
var elSibs = el.siblings('.absolute'); |
|
for (a = 0; a < elSibs.length; a++) { |
|
var colSib = elSibs.eq(a); |
|
overlap(colSib, el); |
|
} |
|
} |
|
} |
|
|
|
var nested = widget.find('.nested-widget').not('.cloner'); |
|
nested.css({'height':'100px', 'width':'100px', 'min-height':'100px'}); |
|
$('.nest-contain').append(nested); |
|
|
|
// refresh sortable columns, causes lag but is needed. |
|
allCols.sortable('refresh'); |
|
zoneCount = 0; |
|
for (x = 0; x < zone.find('.widget').length; x++) { |
|
var wig = zone.find('.widget').eq(x); |
|
var txt = wig.find('.zone-txt'); |
|
var reCount = zoneCount + 1; |
|
wig.attr('id','wig_' + reCount); |
|
txt.html(zoneCount = reCount); |
|
} |
|
}); |
|
|
|
// CLEAR CHOSEN ZONE |
|
$(document).on('click', '.clear-zone', function() { |
|
var zoneInner = $(this).closest('.zone').find('.zone-inner'); |
|
var nested = zoneInner.find('.nested-widget').not('.cloner'); |
|
zoneInner.empty(); |
|
nested.css({'height':'100px', 'width':'100px', 'min-height': '100px'}); |
|
$('.nest-contain').append(nested); |
|
createZoneCols(); |
|
zoneCount = 0; |
|
}); |
|
|
|
|
|
$(document).on('click', '.remove-nested-widget', function() { |
|
var self = $(this).closest('.nested-widget'); |
|
var inner = self.find('.nested-widget-inner').html(); |
|
var re = $('<div class="nested-widget"><div class="nested-widget-inner">'+inner+'</div></div>'); |
|
self.remove(); |
|
|
|
$('.nest-contain').append(re); |
|
}); |
|
|
|
// cursor grabbing |
|
// will not work properly when developer tools are open |
|
// function mouseDrag() { |
|
// var ismousedown = false; |
|
// $(document).on({ |
|
// mouseover: function() { ismousedown = false; $(this).addClass('grab'); }, |
|
// mousedown: function() { ismousedown = true; $(this).addClass('grabbing').removeClass('grab').css('cursor','grabbing !important'); }, |
|
// mouseup: function() { ismousedown = false; $(this).removeClass('grabbing').addClass('grab').css('cursor','grab !important');}, |
|
// mousemove: function() { |
|
// if (ismousedown == true) { |
|
// $(this).addClass('grabbing').removeClass('grab').css('cursor','grabbing !important'); |
|
// } |
|
// }, |
|
// mouseout: function() { $(this).removeClass('grab grabbing'); } |
|
// }, '.widget-inner'); |
|
// } mouseDrag(); |
|
|
|
// SERIALIZATION |
|
$('#save_coord').on('click', function(e) { |
|
e.preventDefault(); |
|
var coords = []; |
|
$.each($('.zone-inner'), function() { |
|
var self = this; |
|
var widgets = $(self).find('.widget'); |
|
var coord = $(self).position(); |
|
var coord_width = $(self).outerWidth(); |
|
var coord_height = $(self).outerHeight(); |
|
var children = []; |
|
var item = { id: $(self).parent().attr('id'), x: coord.left, y: coord.top, width: coord_width, height: coord_height, data_cols: $(self).attr('data-cols'), children: children}; |
|
coords.push(item); |
|
|
|
var count = coords.length - 1; |
|
$(widgets).each(function() { |
|
var widgetSelf = $(this); |
|
var el = widgetSelf.parent('.absolute'); |
|
var widgetWidth = $(el).outerWidth(true); |
|
var zoneWidth = $(el).parent('.zone-inner').width(); |
|
var data_sm = $(widgetSelf).attr('data-width'); |
|
var sibs = $(el).siblings('.absolute'); |
|
var x1 = $(el).position().left; |
|
var y1 = $(el).position().top; |
|
var r1 = x1 + $(el).width(); |
|
var b1 = y1 + $(el).height(); |
|
var offPerc = parseFloat( (x1 / zoneWidth) * 100 ); |
|
// var offset = $(widgetSelf).attr('data-x'); |
|
// sibs.each(function() { |
|
// var self = this; |
|
// var x2 = $(self).position().left; |
|
// var y2 = $(self).position().top; |
|
// var r2 = x2 + $(self).width(); |
|
// var b2 = y2 + $(self).height(); |
|
// if ( $(self).children('.widget').length > 0 ) { |
|
// var widget = $(self).find('.widget'); |
|
// if ( y1==y2 && x1>x2) { |
|
// offset = offset - widget.attr('data-width'); |
|
// } |
|
// if ( x1==r2 && y1==y2 && b1==b2 || x1==r2 && y1>=y2 && b1<=b2 || x1==r2 && y1<=y2 && b1>=b2 ) { |
|
// offset = 0; |
|
// } |
|
// } |
|
// }); |
|
var elCoord = el.position(); |
|
var elCoord_width = el.outerWidth(); |
|
var elCoord_height = el.outerHeight(); |
|
var elItem = { id: el.children().attr('id'), x: elCoord.left, y: elCoord.top, data_x: widgetSelf.attr('data-x'), data_y: widgetSelf.attr('data-y'), data: elCoord_width, height: elCoord_height, data_width: widgetSelf.attr('data-width'), data_height: widgetSelf.attr('data-height'), col: data_sm, bg: widgetSelf.find('.widget-inner').css('background') }; |
|
coords[count]['children'].push(elItem); |
|
}); |
|
}); |
|
console.log( JSON.stringify(coords, null, "\t") ); |
|
console.log(coords); |
|
}); |
|
|
|
// Resize function |
|
function resize(uiItem, containTo, cols, colsNum, colsm) { |
|
uiItem.resizable({ |
|
//(Math.floor( cols * colsm ) / 2) |
|
grid: [cols, colsNum], |
|
handles: 'se', |
|
containment: containTo, |
|
start: function(event, ui) { |
|
// DETECT COLLISION |
|
var el = ui.element.closest('.absolute'); |
|
var elSibs = ui.element.closest('.absolute').siblings('.absolute'); |
|
// so that we can continue resizine once there is no collision |
|
ui.element.resizable( "option", "maxHeight", null ); |
|
ui.element.resizable( "option", "maxWidth", null ); |
|
for (i = 0; i < elSibs.length; i++) { |
|
var colSib = elSibs.eq(i); |
|
var child = colSib.children().length; |
|
if (child > 0) { |
|
for (x = 0; x < colSib.length; x++) { |
|
var self = colSib.eq(x); |
|
resizeCollision(self, el); |
|
} |
|
} |
|
} |
|
var thisWig = ui.element.find('.widget-inner'); |
|
$('.widget-inner').not(thisWig).toggleClass('not-dragging'); |
|
|
|
// don't let the widget resize up past the last nested-widget |
|
var nested = $(this).find('.nested-widget').last(); |
|
if (nested.length > 0) { |
|
var nestY = nested.offset().top; |
|
var nestB = nestY + nested.height(); |
|
|
|
var elY = $(this).offset().top; |
|
var elB = elY + $(this).height(); |
|
|
|
if ( (nestB - 8) == elB ) { |
|
$(this, '.ui-resizable-resizing').resizable( "option", "minHeight", $(this).outerHeight()); |
|
} |
|
} |
|
|
|
// find the original size of item so we can later detect if it has changed. |
|
ui.element.data('ogSize', { width: ui.element[0].offsetWidth, height: ui.element[0].offsetHeight }); |
|
}, |
|
resize: function(event, ui) { |
|
// DETECT COLLISION |
|
var el = ui.element.parent(); |
|
var elSibs = ui.element.parent().siblings('.absolute'); |
|
// so that we can continue to resize once there is no collision |
|
ui.element.resizable( "option", "maxHeight", null ); |
|
ui.element.resizable( "option", "maxWidth", null ); |
|
|
|
// don't let the widget resize up past the last nested-widget |
|
var nested = $(this).find('.nested-widget').last(); |
|
if (nested.length > 0) { |
|
var nestY = nested.offset().top; |
|
var nestB = nestY + nested.height(); |
|
|
|
var elY = $(this).offset().top; |
|
var elB = elY + $(this).height(); |
|
|
|
if ( (nestB-8) == elB ) { |
|
$(this, '.ui-resizable-resizing').resizable( "option", "minHeight", $(this).outerHeight()); |
|
} |
|
} |
|
|
|
for (i = 0; i < elSibs.length; i++) { |
|
var colSib = elSibs.eq(i); |
|
var child = colSib.children('.widget').length; |
|
if (child > 0) { |
|
for (x = 0; x < colSib.length; x++) { |
|
var self = colSib.eq(x); |
|
resizeCollision(self, el); |
|
} |
|
} |
|
colSib.addClass('zone-col').removeClass('disabled'); |
|
overlap(colSib, el); |
|
disableCol(el); |
|
} |
|
}, |
|
stop: function(event, ui) { |
|
var wig = ui.element; |
|
var thisWig = wig.find('.widget-inner'); |
|
var el = wig.parent(); |
|
var elSibs = el.siblings('.absolute'); |
|
for (i = 0; i < elSibs.length; i++) { |
|
var colSib = elSibs.eq(i); |
|
var sibs = colSib.siblings('.absolute'); |
|
if (colSib.children('.widget').length > 0) { |
|
// overlap(colSib, el); |
|
resizeCollision(colSib, el); |
|
for (x = 0; x < sibs.length; x++) { |
|
var thisSib = sibs.eq(x); |
|
overlap(thisSib, colSib); |
|
} |
|
dropCollision(colSib, el); |
|
disableCol(colSib); |
|
} |
|
} |
|
// drop/stop animation |
|
var ani = thisWig; |
|
animateWidget(ani); |
|
// not working in "else" conditions, making other "if" conditions obsolete |
|
wig.resizable("option", "maxHeight", null); |
|
wig.resizable("option", "maxWidth", null); |
|
$('.widget-inner').not(thisWig).toggleClass('not-dragging'); |
|
|
|
// set data attributes |
|
setData(wig, el); |
|
|
|
// detect if the item size has changed so that |
|
// we can remind the user to save... |
|
if (ui.element[0].offsetWidth != ui.element.data('ogSize').width || ui.element[0].offsetHeight != ui.element.data('ogSize').height) { |
|
console.log('Size has changed.'); |
|
} |
|
|
|
|
|
var zoneInner = ui.element.closest('.zone-inner'); |
|
var zoneWidth = zoneInner.width(); |
|
var cols = Math.floor( zoneWidth / 12 ); // make 12 columns |
|
var perc = (cols / zoneWidth) * 100; |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( cols * colsPerWig ); |
|
|
|
$(this, '.ui-resizable-resizing').resizable( "option", "minHeight", null); |
|
|
|
} |
|
}); |
|
} |
|
|
|
// COLLISION DETECTION FUNCTION |
|
function resizeCollision(colSib, el) { |
|
var zone = el.closest('.zone-inner'); |
|
var zoneHeight = zone[0].offsetHeight; |
|
var zoneWidth = zone[0].offsetWidth; |
|
var x1 = el[0].offsetLeft; // ui.element left position |
|
var y1 = el[0].offsetTop; // ui.element top position |
|
var b1 = y1 + el[0].offsetHeight; // ui.element "bottom" position |
|
var r1 = x1 + el[0].offsetWidth; // ui.element "right" position |
|
|
|
var x2 = colSib[0].offsetLeft; // collided sibling left position |
|
var y2 = colSib[0].offsetTop; // collided sibling top position |
|
var b2 = y2 + colSib[0].offsetHeight; // collided sibling "bottom" position |
|
var r2 = x2 + colSib[0].offsetWidth; // collided sibling "right" position |
|
// X-AXIS |
|
if ( (r1 == x2 && y1 == y2 || r1 == x2 && b1 == b2) |
|
|| (y2 < y1 && b2 > b1 && r2 > r1) |
|
|| (y1 < y2 && b1 > b2 && r2 > r1) |
|
|| (y2 < b1 && b2 > b1 && r1 == x2) ) |
|
{ |
|
$('.ui-resizable-resizing').resizable( "option", "maxWidth", (x2 - x1) ); |
|
} |
|
// Y-AXIS |
|
if ( (b1 == y2 && x1 == x2 || b1 == y2 && r1 == r2) |
|
|| (x1 < x2 && r1 > r2 && b1 == y2) |
|
|| (x2 < x1 && r2 > r1 && b1 == y2) |
|
|| (r2 > r1 && x2 < r1 && b1 == y2) ) |
|
{ |
|
$('.ui-resizable-resizing').resizable( "option", "maxHeight", (y2 - y1) ); |
|
} |
|
} |
|
|
|
function disableCol(thisCol) { |
|
var zone = thisCol.closest('.zone-inner'); |
|
var zoneWidth = zone ? zone[0].offsetWidth : ''; |
|
var cols = Math.floor( zoneWidth / 12 ); |
|
var dyCol = thisCol.closest('.zone-inner').attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; |
|
var colAmount = (12 - colsPerWig) + 1; |
|
var disable = 12 - colAmount; |
|
var cols8 = cols * (colAmount - 1); |
|
var i = zone.find('.absolute').index(thisCol); |
|
|
|
// if (dyCol == 7 || dyCol == 9 || dyCol == 10) { |
|
// var cols8 = (dyCol - colsPerWig) * (cols * colsPerWig); |
|
// } else { |
|
// var cols8 = (dyCol - 1) * (cols * colsPerWig); |
|
// } |
|
// if (thisCol[0].offsetLeft <= 0) { |
|
// thisCol.removeClass('zone-col').addClass('disabled'); |
|
// for (a = i; a <= i + disable; a++) { |
|
// var toDisable = zone.find('.absolute').eq(a); |
|
// if (toDisable[0].offsetTop == thisCol[0].offsetTop) { |
|
// zone.find('.absolute').eq(a).removeClass('zone-col').addClass('disabled'); |
|
// } |
|
// } |
|
// } else if (thisCol[0].offsetLeft >= cols8 ) { |
|
// thisCol.removeClass('zone-col').addClass('disabled'); |
|
// for (b = i; b >= i - disable; b--) { |
|
// var toDisable = zone.find('.absolute').eq(b); |
|
// if (toDisable[0].offsetTop == thisCol[0].offsetTop) { |
|
// toDisable.removeClass('zone-col').addClass('disabled'); |
|
// } |
|
// } |
|
// } else { |
|
thisCol.removeClass('zone-col').addClass('disabled'); |
|
for (a = i; a <= i + disable; a++) { |
|
var toDisable = zone.find('.absolute').eq(a); |
|
if (toDisable.length > 0) { |
|
if (toDisable[0].offsetTop == thisCol[0].offsetTop) { |
|
zone.find('.absolute').eq(a).removeClass('zone-col').addClass('disabled'); |
|
} |
|
} |
|
} |
|
for (b = i; b >= i - disable; b--) { |
|
var toDisable = zone.find('.absolute').eq(b); |
|
if (toDisable[0].offsetTop == thisCol[0].offsetTop) { |
|
toDisable.removeClass('zone-col').addClass('disabled'); |
|
} |
|
} |
|
// } |
|
} |
|
|
|
function enableCol(thisCol) { |
|
thisCol.addClass('zone-col').removeClass('disabled'); |
|
thisCol.prev().addClass('zone-col').removeClass('disabled'); |
|
thisCol.next().addClass('zone-col').removeClass('disabled'); |
|
} |
|
function enableAll(allCols) { |
|
allCols.addClass('zone-col').removeClass('disabled'); |
|
} |
|
|
|
// check if a zone-col is overlapping any other zone-cols, |
|
// if so, disabled those zone-cols. |
|
function overlap(colSib, el) { |
|
var zone = el.closest('.zone-inner'); |
|
var zoneHeight = zone[0].offsetHeight; |
|
var zoneWidth = zone[0].offsetWidth; |
|
var x1 = el[0].offsetLeft; // ui.element left position |
|
var y1 = el[0].offsetTop; // ui.element top position |
|
var b1 = y1 + el[0].offsetHeight; // ui.element "bottom" position |
|
var r1 = x1 + el[0].offsetWidth; // ui.element "right" position |
|
var x2 = colSib[0].offsetLeft; // collided sibling left position |
|
var y2 = colSib[0].offsetTop; // collided sibling top position |
|
var b2 = y2 + colSib[0].offsetHeight; // collided sibling "bottom" position |
|
var r2 = x2 + colSib[0].offsetWidth; // collided sibling "right" position |
|
|
|
// causing slow down? |
|
// var i = zone.find('.absolute').index(colSib); // at 64 widgets: ~604ms |
|
var i = colSib.attr('data-index'); // at 64 widgets: ~168ms |
|
|
|
var cols = Math.floor( zoneWidth / 12 ); |
|
var dyCol = zone.attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; |
|
var colAmount = (12 - colsPerWig) + 1; |
|
if ( r1 > x2 && x1 < r2 && y1 <= y2 && b1 >= b2 ) { |
|
colSib.addClass('disabled').removeClass('zone-col'); |
|
for (b = i; b >= i - (12 - colAmount); b--) { |
|
var toDisable = zone.find('.absolute').eq(b); |
|
if (toDisable[0].offsetTop == y2) { |
|
toDisable.removeClass('zone-col').addClass('disabled'); |
|
} |
|
} |
|
} |
|
} |
|
|
|
function pushy(sib, el) { // when a nested widget overflows the parent widget, we need to push down any widgets below said widget. |
|
var zone = el.closest('.zone-inner'); |
|
var zoneHeight = zone[0].offsetHeight; |
|
var zoneWidth = zone[0].offsetWidth; |
|
var x1 = el[0].offsetLeft; |
|
var y1 = el[0].offsetTop; |
|
var b1 = y1 + el[0].offsetHeight; |
|
var r1 = x1 + el[0].offsetWidth; |
|
var x2 = sib[0].offsetLeft; |
|
var y2 = sib[0].offsetTop; |
|
var b2 = y2 + sib[0].offsetHeight; |
|
var r2 = x2 + sib[0].offsetWidth; |
|
|
|
var theSib = sib; |
|
var res = false; |
|
if ( (b1>y2 && y1<y2 && (x1==x2 || r1==r2)) |
|
|| (r1<r2 && x1>x2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (x1<x2 && r1>r2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (x1>x2 && r1<r2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (r1>x2 && r1<r2 && y2<b1 && y2>y1) |
|
|| (x1>x2 && x1<r2 && y2<b1 && y2>y1) ) |
|
{ |
|
sib.find('.widget').css('background', 'green'); |
|
res = true; |
|
} else if (x2 >= r1 || r2 <= x1) { |
|
res = {push: 'no', obj: theSib}; |
|
// res = 'nopush'; |
|
} |
|
return res; |
|
} |
|
|
|
// check for collision when dropping a widget, if it overlaps another widget. |
|
function dropCollision(colSib, el) { |
|
console.log('yooooooohoooooooooo'); |
|
var zone = el.closest('.zone-inner'); |
|
var zoneHeight = zone[0].offsetHeight; |
|
var zoneWidth = zone[0].offsetWidth; |
|
var x1 = el[0].offsetLeft; // ui.element left position |
|
var y1 = el[0].offsetTop; // ui.element top position |
|
var b1 = y1 + el[0].offsetHeight; // ui.element "bottom" position |
|
var r1 = x1 + el[0].offsetWidth; // ui.element "right" position |
|
var x2 = colSib[0].offsetLeft; // collided sibling left position |
|
var y2 = colSib[0].offsetTop; // collided sibling top position |
|
var b2 = y2 + colSib[0].offsetHeight; // collided sibling "bottom" position |
|
var r2 = x2 + colSib[0].offsetWidth; // collided sibling "right" position |
|
|
|
//X-AXIS |
|
if ( (r1 > x2 && x1 < x2 && (y1 == y2 || b1 == b2 )) || (y1 > y2 && b1 < b2 && (x1 == x2 || r1 == r2)) || (y1 < b2 && b1 >= b2 && y1 >= y2 && r1 >= x2 && x1 < x2) ) |
|
{ |
|
el.find('.widget').css('width', (x2 - x1) ); |
|
} |
|
//Y-AXIS |
|
if ( (b1>y2 && y1<y2 && (x1==x2 || r1==r2)) |
|
|| (r1<r2 && x1>x2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (x1<x2 && r1>r2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (x1>x2 && r1<r2 && (y1==y2 || (b1==b2 || (b1>b2 && (y1<y2 || y1==y2)))) ) |
|
|| (r1>x2 && r1<r2 && y2<b1 && y2>y1) |
|
|| (x1>x2 && x1<r2 && y2<b1 && y2>y1) ) |
|
{ |
|
el.find('.widget').css('height', (y2 - y1) ); |
|
} |
|
} |
|
|
|
function zoneOverflow(zoneInner, el) { |
|
var col = parseFloat(zoneInner.width() / 12); |
|
var dyCol = zoneInner.attr('data-cols'); |
|
var colsPerWig = 12 / dyCol; // gives us the 'col-sm' in bootstrap terms for each widget |
|
var colsNum = Math.floor( col * colsPerWig ); |
|
|
|
var zH = zoneInner[0].offsetHeight; |
|
var zW = zoneInner[0].offsetWidth; |
|
|
|
var cols = Math.floor(zW / colsNum); |
|
var rows = Math.floor(zH / colsNum); |
|
|
|
var zR = zoneInner[0].offsetLeft + zW; |
|
var zB = zoneInner[0].offsetTop + zH; |
|
|
|
var cH = el[0].offsetHeight; |
|
var cW = el[0].offsetWidth; |
|
var cR = el[0].offsetLeft + cW; |
|
var cB = el[0].offsetTop + cH; |
|
if ( cR > zR ) { |
|
el.find('.widget').css('width', ((cols * colsNum) - el[0].offsetLeft)); |
|
} |
|
if ( cB > zB ) { |
|
el.find('.widget').css('height', ((rows * colsNum) - el[0].offsetTop)); |
|
} |
|
} |
|
|
|
// set data attributes like: 'data_width', 'data_height', 'data_x', and 'data_y' |
|
// these attributes will be used when loading in widgets. |
|
function setData(widget, zoneCol) { |
|
if (widget[0] != undefined && zoneCol[0] != undefined) { |
|
var widgetWidth = Math.floor(widget[0].offsetWidth); |
|
var widgetHeight = Math.floor(widget[0].offsetHeight); |
|
var zoneWidth = widget.closest('.zone-inner')[0].offsetWidth; |
|
var zoneHeight = widget.closest('.zone-inner')[0].offsetHeight; |
|
var cols = Math.floor( (zoneWidth / 12) ); // make 12 columns |
|
var dyCol = widget.closest('.zone-inner').attr('data-cols'); |
|
var colsm = 12 / dyCol; |
|
var colsNum = Math.floor( cols * colsm ); |
|
var rows = Math.floor(zoneHeight / colsNum); |
|
var colPerc = parseFloat( (widgetWidth / zoneWidth) * 100 ); |
|
var data_width; |
|
switch(true) { |
|
case ( 92 < colPerc && colPerc <= 100 ): data_width = 12; break; |
|
case ( 84 < colPerc && colPerc < 92 ): data_width = 11; break; |
|
case ( 76 < colPerc && colPerc < 84 ): data_width = 10; break; |
|
case ( 67 < colPerc && colPerc < 76 ): data_width = 9; break; |
|
case ( 59 < colPerc && colPerc < 67 ): data_width = 8; break; |
|
case ( 51 < colPerc && colPerc < 59 ): data_width = 7; break; |
|
case ( 42 < colPerc && colPerc < 51 ): data_width = 6; break; |
|
case ( 34 < colPerc && colPerc < 42 ): data_width = 5; break; |
|
case ( 26 < colPerc && colPerc < 34 ): data_width = 4; break; |
|
case ( 17 < colPerc && colPerc < 26 ): data_width = 3; break; |
|
case ( 9 < colPerc && colPerc < 17 ): data_width = 2; break; |
|
case ( 0 < colPerc && colPerc < 9 ): data_width = 1; break; |
|
} |
|
var data_height = parseFloat(widgetHeight / colsNum); |
|
var data_y = zoneCol.attr('data-row'); |
|
var data_x = $('.absolute[data-row="'+data_y+'"]').index(widget.closest('.absolute[data-row="'+data_y+'"]')); |
|
widget.attr({ |
|
'data-width': data_width, |
|
'data-height': data_height, |
|
'data-x': data_x, |
|
'data-y': data_y |
|
}); |
|
} |
|
} |
|
|
|
function animateWidget(el) { |
|
el.queue('fx', function(next) { |
|
$(this).addClass('animate'); |
|
next(); |
|
}); |
|
el.delay(400).queue('fx', function(next) { |
|
$(this).removeClass('animate'); |
|
next(); |
|
}); |
|
} |
|
|
|
// }); |
|
// } loadDoc(); |
|
|
|
}); |