$.fn.reverse = [].reverse; function getSides(jqObject) { var sides = {}; sides.n = Math.ceil(jqObject.offset().top); sides.w = Math.ceil(jqObject.offset().left); sides.s = Math.floor(sides.n + jqObject.outerHeight()); sides.e = Math.floor(sides.w + jqObject.outerWidth()); return sides; } function rectanglesIdentical(r1, r2) { var tolerance = 2; return ((Math.abs(r1.n - r2.n) < tolerance) && (Math.abs(r1.s - r2.s) < tolerance) && (Math.abs(r1.e - r2.e) < tolerance) && (Math.abs(r1.w - r2.w) < tolerance)); } function rectanglesOverlap(r1, r2) { if ( (( ((r1.w > r2.w) && (r1.w < r2.e)) || ((r1.e > r2.w) && (r1.e < r2.e)) ) && (r1.n < r2.s) && (r1.s > r2.n)) || (( ((r1.n > r2.n) && (r1.n < r2.s)) || ((r1.s > r2.n) && (r1.s < r2.s)) ) && (r1.w < r2.e) && (r1.e > r2.w)) ) { return true; } if ((r1.w >= r2.w) && (r1.n >= r2.n) && (r1.e <= r2.e) && (r1.s <= r2.s)) { return true; } if ((r2.w >= r1.w) && (r2.n >= r1.n) && (r2.e <= r1.e) && (r2.s <= r1.s)) { return true; } return false; } function overlapsBooked(rectangle, bookedMap) { for (var i=0; i tableData.x.data[tableData.x.data.length - 1].coord) || (p.y > tableData.y.data[tableData.y.data.length - 1].coord) ); } function snapToGrid(tableData, div, side, force) { var snapGap = (force) ? 100000: 20; var tolerance = 2; var isLR = (side=='left') || (side=='right'); var data = (isLR) ? tableData.x.data : tableData.y.data; var topLeft, bottomRight, divTop, divLeft, divWidth, divHeight, thisCoord, gap, gapTopLeft, gapBottomRight; for (var i=0; i<(data.length -1); i++) { topLeft = data[i].coord + 1; bottomRight = data[i+1].coord; divTop = div.offset().top; divLeft = div.offset().left; divWidth = div.outerWidth(); divHeight = div.outerHeight(); switch (side) { case 'top': thisCoord = divTop; break; case 'bottom': thisCoord = divTop + divHeight; break; case 'left': thisCoord = divLeft; break; case 'right': thisCoord = divLeft + divWidth; break; } gapTopLeft = thisCoord - topLeft; gapBottomRight = bottomRight - thisCoord; if (((gapTopLeft>0) && (gapBottomRight>0)) || ((i==0) && (gapTopLeft<0)) || ((i==(data.length-2)) && (gapBottomRight<0)) ) { gap = bottomRight - topLeft; if ((gapTopLeft <= gap/2) && (gapTopLeft < snapGap)) { switch (side) { case 'left': div.offset({top: divTop, left: topLeft}); div.width(divWidth + gapTopLeft); break; case 'right': if ((divWidth - gapTopLeft) < tolerance) { div.width(divWidth + gapBottomRight); } else { div.width(divWidth - gapTopLeft); } break; case 'top': div.offset({top: topLeft, left: divLeft}); div.height(divHeight + gapTopLeft); break; case 'bottom': div.height(divHeight - gapTopLeft); break; } return; } else if ((gapBottomRight <= gap/2) && (gapBottomRight < snapGap)) { switch (side) { case 'left': if ((divWidth - gapBottomRight) < tolerance) { div.offset({top: div.Top, left: topLeft}); div.width(divWidth + gapTopLeft); } else { div.offset({top: divTop, left: bottomRight}); div.width(divWidth - gapBottomRight); } break; case 'right': div.width(divWidth + gapBottomRight); break; case 'top': div.offset({top: bottomRight, left: divLeft}); div.height(divHeight - gapBottomRight); break; case 'bottom': div.height(divHeight + gapBottomRight); break; } return; } } } } function getBookingParams(table, tableData, div) { var rtl = (table.css('direction').toLowerCase() == 'rtl'); var params = {}; var data; var tolerance = 2; var cell = {x: {}, y: {}} cell.x.start = div.offset().left; cell.y.start = div.offset().top; cell.x.end = cell.x.start + div.outerWidth(); cell.y.end = cell.y.start + div.outerHeight(); for (var axis in cell) { data = tableData[axis].data; if (params[tableData[axis].key] === undefined) { params[tableData[axis].key] = []; } if (rtl && (axis=='x')) { for (var i = data.length - 1; i >= 0; i--) { if ((data[i].coord + tolerance) < cell[axis].start) { if ((tableData[axis].key == 'seconds') || (params[tableData[axis].key].length == 0)) { params[tableData[axis].key].push(data[i].value); } break; } if ((data[i].coord + tolerance) < cell[axis].end) { params[tableData[axis].key].push(data[i].value); } } } else { for (var i=0; i cell[axis].end) { if ((tableData[axis].key == 'seconds') || (params[tableData[axis].key].length == 0)) { params[tableData[axis].key].push(data[i].value); } break; } if ((data[i].coord + tolerance) > cell[axis].start) { params[tableData[axis].key].push(data[i].value); } } } } return params; } function getRowNumber(tableData, y) { for (var i=0; i= tableData.y.data[i].coord && y < tableData.y.data[i+1].coord) { return i; } } return null; } var highlightRowLabels = function (table, tableData, div) { if (highlightRowLabels.rows === undefined) { highlightRowLabels.rows = []; table.find('tbody tr').each(function() { highlightRowLabels.rows.push($(this).find('td.row_labels')); }); } var divStartRow = getRowNumber(tableData, div.offset().top); var divEndRow = getRowNumber(tableData, div.offset().top + div.outerHeight()); for (var i=0; i<\/div>'); var jqTarget = $(e.target); if (e.target.nodeName.toLowerCase() == "img") { jqTarget = jqTarget.parent(); } downHandler.origin = jqTarget.offset(); downHandler.firstPosition = {x: e.pageX, y: e.pageY}; downHandler.originalLink = jqTarget.find('a').andSelf('a').attr('href'); downHandler.box = $('
'); if (((args.page == 'week') && true) || ((args.page == 'day') && false)) { var slotWidth = jqTarget.outerWidth(); downHandler.maxWidth = true; downHandler.box.css('max-width', slotWidth + 'px'); downHandler.box.css('min-width', slotWidth + 'px'); } downHandler.box.offset(downHandler.origin); $(document.body).append(downHandler.box); }; var moveHandler = function(e) { var box = downHandler.box; var oldBoxOffset = box.offset(); var oldBoxWidth = box.outerWidth(); var oldBoxHeight = box.outerHeight(); if ((downHandler.maxWidth && (e.pageX < downHandler.origin.left)) || (downHandler.maxHeight && (e.pageY < downHandler.origin.top))) { return; } if (e.pageX < downHandler.origin.left) { if (e.pageY < downHandler.origin.top) { box.offset({top: e.pageY, left: e.pageX}) } else { box.offset({top: downHandler.origin.top, left: e.pageX}) } } else if (e.pageY < downHandler.origin.top) { box.offset({top: e.pageY, left: downHandler.origin.left}) } else { box.offset(downHandler.origin); } box.width(Math.abs(e.pageX - downHandler.origin.left)) box.height(Math.abs(e.pageY - downHandler.origin.top)); var boxSides = getSides(box); snapToGrid(tableData, box, 'top'); snapToGrid(tableData, box, 'bottom'); snapToGrid(tableData, box, 'right'); snapToGrid(tableData, box, 'left'); if (overlapsBooked(getSides(box), bookedMap)) { box.offset(oldBoxOffset) .width(oldBoxWidth) .height(oldBoxHeight); } if (outsideTable(tableData, {x: e.pageX, y: e.pageY})) { if (!moveHandler.outside) { box.addClass('outside'); moveHandler.outside = true; clearRowLabels(); } } else if (moveHandler.outside) { box.removeClass('outside'); moveHandler.outside = false; } if (!moveHandler.outside) { highlightRowLabels(table, tableData, box); } }; var upHandler = function(e) { e.preventDefault(); var tolerance = 2; var box = downHandler.box; var params = getBookingParams(table, tableData, box); $(document).unbind('mousemove',moveHandler); $(document).unbind('mouseup', upHandler); $('table.dwm_main').unwrap(); if (outsideTable(tableData, {x: e.pageX, y: e.pageY})) { box.remove(); return; } else if ((Math.abs(e.pageX - downHandler.firstPosition.x) <= tolerance) && (Math.abs(e.pageY - downHandler.firstPosition.y) <= tolerance)) { if (downHandler.originalLink !== undefined) { window.location = downHandler.originalLink; } else { box.remove(); } return; } var queryString = 'drag=1'; queryString += '&area=' + args.area; queryString += '&start_seconds=' + params.seconds[0]; queryString += '&end_seconds=' + params.seconds[params.seconds.length - 1]; if (args.page == 'day') { for (var i=0; i<\/div>'); divClone.css('max-width', 'none'); $('
<\/div>') .width(divClone.outerWidth() - 2) .height(divClone.outerHeight() - 2) .offset(divClone.offset()) .appendTo($('div.resizing')); table.find('td').not('td.new, td.row_labels').not(divBooking.closest('td')).each(function() { bookedMap.push(getSides($(this))); }); } var divResizeStop = function (event, ui) { bookedMap = []; if (divClone.resizable('option', 'disabled')) { divClone.resizable('enable') .offset(divBooking.offset()) .width(divBooking.outerWidth()) .height(divBooking.outerHeight()); } else { snapToGrid(tableData, divClone, 'left', true); snapToGrid(tableData, divClone, 'right', true); snapToGrid(tableData, divClone, 'top', true); snapToGrid(tableData, divClone, 'bottom', true); } $('div.outline').remove(); $('table.dwm_main').unwrap(); var r1 = getSides(divBooking); var r2 = getSides(divClone); if (!rectanglesIdentical(r1, r2)) { var data = {ajax: 1, commit: 1, day: args.day, month: args.month, year: args.year}; data.id = divClone.data('id'); var oldParams = getBookingParams(table, tableData, divBooking); var newParams = getBookingParams(table, tableData, divClone); if (newParams.seconds !== undefined) { if (newParams.seconds[0] != oldParams.seconds[0]) { data.start_seconds = newParams.seconds[0]; } if (newParams.seconds[newParams.seconds.length - 1] != oldParams.seconds[oldParams.seconds.length - 1]) { data.end_seconds = newParams.seconds[newParams.seconds.length - 1]; } } if (args.page == 'day') { data.page = 'day'; data.start_day = args.day; data.start_month = args.month; data.start_year = args.year; } else { data.page = 'week'; var startDate = newParams.date[0].split('-'); data.start_year = startDate[0]; data.start_month = startDate[1]; data.start_day = startDate[2]; } data.end_day = data.start_day; data.end_month = data.start_month; data.end_year = data.start_year; if (newParams.room !== undefined) { data.rooms = newParams.room; } $.post('edit_entry_handler.php', data, function(result) { if (result.valid_booking) { table.empty(); table.html(result.table_innerhtml); $(window).trigger('load'); $.each(result.new_details, function(i, value) { var cell = $('[data-id="' + value.id + '"]'); var cellAnchor = cell.find('a'); var oldHTML = cellAnchor.html(); var duration = 1000; cellAnchor.fadeOut(duration, function(){ cellAnchor.html('Changes saved').fadeIn(duration, function() { cellAnchor.fadeOut(duration, function() { cellAnchor.html(oldHTML).fadeIn(duration); }) }); }); }); } else { divClone.offset(divBooking.offset()) .width(divBooking.outerWidth()) .height(divBooking.outerHeight()); var alertMessage = ''; if (result.conflicts.length > 0) { alertMessage += 'The new booking will conflict with the following entries' + ": \n\n"; var conflictsList = getErrorList(result.conflicts); alertMessage += conflictsList.text; } if (result.rules_broken.length > 0) { if (result.conflicts.length > 0) { alertMessage += "\n\n"; } alertMessage += 'The new booking will conflict with the following policies' + ": \n\n"; var rulesList = getErrorList(result.rules_broken); alertMessage += rulesList.text; } alert(alertMessage); } }, 'json'); } } var directions = {times: {plus: true, minus: true}, other: {plus: true, minus: true}}; if ($(this).hasClass('series')) { directions.other = {plus: false, minus: false}; } if (((args.page == 'week') && true) || ((args.page == 'day') && false)) { directions.other = {plus: false, minus: false}; } if ($(this).hasClass('multiday_start')) { directions.times.minus = false; directions.other = {plus: false, minus: false}; } if ($(this).hasClass('multiday_end')) { directions.times.plus = false; directions.other = {plus: false, minus: false}; } var aHandles = []; if (directions.times.plus) { aHandles.push('s'); } if (directions.times.minus) { aHandles.push('n'); } if (directions.other.plus) { aHandles.push('e'); } if (directions.other.minus) { aHandles.push('w'); } var corners = ['nw', 'ne', 'se', 'sw']; for (var i=0; i= 0) && (aHandles.indexOf(corners[i][1]) >= 0)) { aHandles.push(corners[i]); } } var handles = aHandles.join(','); var divBooking = $(this).children('div'); var divClone = divBooking.clone(); divBooking.css('visibility', 'hidden'); divClone.css('z-index', '500') .css('position', 'absolute') .css('top', '0') .css('left', '0') .css('background-color', $(this).css('background-color')) .css('max-height', 'none') .css('min-height', '17px') .addClass('clone') .width(divBooking.outerWidth()) .height(divBooking.outerHeight()) if (handles) { divClone.resizable({handles: handles, resize: divResize, start: divResizeStart, stop: divResizeStop}); } divClone.appendTo($(this)); $(this).css('background-color', 'transparent') .wrapInner('
<\/div>'); }); $(window).resize(function(event) { if (event.target == this) { redrawClones(table); getTableData(table, tableData); } }); table.find('div.multiple_control') .click(function() { redrawClones(table); getTableData(table, tableData); }); } };