X-Git-Url: http://git.pld-linux.org/?a=blobdiff_plain;f=eventum-order.patch;h=5764514ba18bbecb6b4ef71b611d190aebb24fb3;hb=371b276ab631c8d0f88f9387e6f31dffa7ad386a;hp=9194ceb0ef94d34261588806f60e0ec90ffea687;hpb=342dba9859cb7349a75e9333666b82f4ce2ce9f7;p=packages%2Feventum.git diff --git a/eventum-order.patch b/eventum-order.patch index 9194ceb..5764514 100644 --- a/eventum-order.patch +++ b/eventum-order.patch @@ -1,10 +1,8 @@ ---- eventum-new/ajax/order.php 2008-10-15 02:02:25.000000000 +0300 -+++ eventum-new/ajax/order.php 2008-10-15 02:02:25.000000000 +0300 -@@ -0,0 +1,72 @@ +--- eventum-2.2/htdocs/ajax/order.php 1970-01-01 02:00:00.000000000 +0200 ++++ eventum-2.2-order/htdocs/ajax/order.php 2009-10-12 22:10:36.429185594 +0300 +@@ -0,0 +1,69 @@ +dbh->query($stmt); ++ $res = DB_Helper::getInstance()->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + die('update failed'); @@ -73,254 +70,503 @@ + } + } +} ---- eventum/ajax/update.php 2008-10-15 01:46:20.000000000 +0300 -+++ eventum-new/ajax/update.php 2008-10-15 02:02:25.000000000 +0300 -@@ -0,0 +1,30 @@ -+ array( - "title" => ev_gettext("Expected Resolution Date") -- ) -+ ), -+ "isu_order" => array( -+ "title" => ev_gettext("Order") -+ ), - ) - ); - return $columns[$page]; ---- eventum/include/class.issue.php 2008-10-15 01:46:20.000000000 +0300 -+++ eventum-new/include/class.issue.php 2008-10-15 02:02:25.000000000 +0300 -@@ -1356,6 +1356,7 @@ - Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); - return -1; - } else { -+ Issue::moveOrderForAllUsers($issue_id, 1000); - $prj_id = Issue::getProjectID($issue_id); - - // record the change -@@ -1659,6 +1660,176 @@ - } - } -+ /** -+ * Method used to update the a single detail field of a specific issue. -+ * -+ * @param integer $issue_id -+ * @param string $field_name -+ * @param string $field_value -+ * @param string $field_type string or integer (for escape) -+ * @return integer 1 on success, -1 otherwise -+ */ -+ function updateField($issue_id, $field_name, $filed_value) { + ul.excerpts { + list-style: none; +@@ -187,4 +205,4 @@ + ul.excerpts ul { + list-style-type: none; + padding-left: 1em; +-} +\ No newline at end of file ++} +--- eventum-2.2/htdocs/js/jquery/jquery.tablednd.js 1970-01-01 02:00:00.000000000 +0200 ++++ eventum-2.2-order/htdocs/js/jquery/jquery.tablednd.js 2009-10-12 22:10:36.435851675 +0300 +@@ -0,0 +1,382 @@ ++/** ++ * TableDnD plug-in for JQuery, allows you to drag and drop table rows ++ * You can set up various options to control how the system will work ++ * Copyright (c) Denis Howlett ++ * Licensed like jQuery, see http://docs.jquery.com/License. ++ * ++ * Configuration options: ++ * ++ * onDragStyle ++ * This is the style that is assigned to the row during drag. There are limitations to the styles that can be ++ * associated with a row (such as you can't assign a border--well you can, but it won't be ++ * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as ++ * a map (as used in the jQuery css(...) function). ++ * onDropStyle ++ * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations ++ * to what you can do. Also this replaces the original style, so again consider using onDragClass which ++ * is simply added and then removed on drop. ++ * onDragClass ++ * This class is added for the duration of the drag and then removed when the row is dropped. It is more ++ * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default ++ * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your ++ * stylesheet. ++ * onDrop ++ * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table ++ * and the row that was dropped. You can work out the new order of the rows by using ++ * table.rows. ++ * onDragStart ++ * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the ++ * table and the row which the user has started to drag. ++ * onAllowDrop ++ * Pass a function that will be called as a row is over another row. If the function returns true, allow ++ * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under ++ * the cursor. It returns a boolean: true allows the drop, false doesn't allow it. ++ * scrollAmount ++ * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the ++ * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, ++ * FF3 beta ++ * dragHandle ++ * This is the name of a class that you assign to one or more cells in each row that is draggable. If you ++ * specify this class, then you are responsible for setting cursor: move in the CSS and only these cells ++ * will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where ++ * the whole row is draggable. ++ * ++ * Other ways to control behaviour: ++ * ++ * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows ++ * that you don't want to be draggable. ++ * ++ * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form ++ * []=&[]= so that you can send this back to the server. The table must have ++ * an ID as must all the rows. ++ * ++ * Other methods: ++ * ++ * $("...").tableDnDUpdate() ++ * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells). ++ * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again. ++ * The table maintains the original configuration (so you don't have to specify it again). ++ * ++ * $("...").tableDnDSerialize() ++ * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be ++ * called from anywhere and isn't dependent on the currentTable being set up correctly before calling ++ * ++ * Known problems: ++ * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 ++ * ++ * Version 0.2: 2008-02-20 First public version ++ * Version 0.3: 2008-02-07 Added onDragStart option ++ * Made the scroll amount configurable (default is 5 as before) ++ * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes ++ * Added onAllowDrop to control dropping ++ * Fixed a bug which meant that you couldn't set the scroll amount in both directions ++ * Added serialize method ++ * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row ++ * draggable ++ * Improved the serialize method to use a default (and settable) regular expression. ++ * Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table ++ */ ++jQuery.tableDnD = { ++ /** Keep hold of the current table being dragged */ ++ currentTable : null, ++ /** Keep hold of the current drag object if any */ ++ dragObject: null, ++ /** The current mouse offset */ ++ mouseOffset: null, ++ /** Remember the old value of Y so that we don't do too much processing */ ++ oldY: 0, + -+ $issue_id = Misc::escapeInteger($issue_id); ++ /** Actually build the structure */ ++ build: function(options) { ++ // Set up the defaults if any + -+ $usr_id = Auth::getUserID(); -+ $prj_id = Issue::getProjectID($issue_id); ++ this.each(function() { ++ // This is bound to each matching table, set up the defaults and override with user options ++ this.tableDnDConfig = jQuery.extend({ ++ onDragStyle: null, ++ onDropStyle: null, ++ // Add in the default class for whileDragging ++ onDragClass: "tDnD_whileDrag", ++ onDrop: null, ++ onDragStart: null, ++ scrollAmount: 5, ++ serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs ++ serializeParamName: null, // If you want to specify another parameter name instead of the table ID ++ dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable ++ }, options || {}); ++ // Now make the rows draggable ++ jQuery.tableDnD.makeDraggable(this); ++ }); + -+ // get all of the 'current' information of this issue -+ $current = Issue::getDetails($issue_id); ++ // Now we need to capture the mouse up and mouse move event ++ // We can use bind so that we don't interfere with other event handlers ++ jQuery(document) ++ .bind('mousemove', jQuery.tableDnD.mousemove) ++ .bind('mouseup', jQuery.tableDnD.mouseup); + -+ $stmt = "UPDATE -+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue -+ SET -+ iss_updated_date='" . Date_API::getCurrentDateGMT() . "', -+ iss_last_public_action_date='" . Date_API::getCurrentDateGMT() . "', -+ iss_last_public_action_type='updated'"; ++ // Don't break the chain ++ return this; ++ }, + -+ switch ($field_name) { -+ case 'category': -+ $stmt .= ", iss_prc_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'release': -+ $stmt .= ", iss_pre_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'expected_resolution_date': -+ $stmt .= ", iss_expected_resolution_date = '" . Misc::escapeString($filed_value) . "'"; -+ break; -+ case 'release': -+ $stmt .= ", iss_pre_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'priority': -+ $stmt .= ", iss_pri_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'status': -+ $stmt .= ", iss_sta_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'resolution': -+ $stmt .= ", iss_res_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'summary': -+ $stmt .= ", iss_summary = '" . Misc::escapeString($filed_value) . "'"; -+ break; -+ case 'description': -+ $stmt .= ", iss_description = '" . Misc::escapeString($filed_value) . "'"; -+ break; -+ case 'estimated_dev_time': -+ $stmt .= ", iss_dev_time = '" . Misc::escapeString($filed_value) . "'"; -+ break; -+ case 'percent_complete': -+ $stmt .= ", iss_percent_complete = '" . Misc::escapeString($filed_value) . "'"; -+ break; -+ case 'trigger_reminders': -+ $stmt .= ", iss_trigger_reminders = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'group': -+ $stmt .= ", iss_grp_id = " . Misc::escapeInteger($filed_value); -+ break; -+ case 'private': -+ $stmt .= ", iss_private = " . Misc::escapeInteger($filed_value); -+ break; -+ default: -+ Error_Handler::logError("Unknown field name $field_name", __FILE__, __LINE__); -+ return -1; -+ break; -+ } ++ /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ ++ makeDraggable: function(table) { ++ var config = table.tableDnDConfig; ++ if (table.tableDnDConfig.dragHandle) { ++ // We only need to add the event to the specified cells ++ var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table); ++ cells.each(function() { ++ // The cell is bound to "this" ++ jQuery(this).mousedown(function(ev) { ++ jQuery.tableDnD.dragObject = this.parentNode; ++ jQuery.tableDnD.currentTable = table; ++ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); ++ if (config.onDragStart) { ++ // Call the onDrop method if there is one ++ config.onDragStart(table, this); ++ } ++ return false; ++ }); ++ }) ++ } else { ++ // For backwards compatibility, we add the event to the whole row ++ var rows = jQuery("tr", table); // get all the rows as a wrapped set ++ rows.each(function() { ++ // Iterate through each row, the row is bound to "this" ++ var row = jQuery(this); ++ if (! row.hasClass("nodrag")) { ++ row.mousedown(function(ev) { ++ if (ev.target.tagName == "TD") { ++ jQuery.tableDnD.dragObject = this; ++ jQuery.tableDnD.currentTable = table; ++ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); ++ if (config.onDragStart) { ++ // Call the onDrop method if there is one ++ config.onDragStart(table, this); ++ } ++ return false; ++ } ++ }).css("cursor", "move"); // Store the tableDnD object ++ } ++ }); ++ } ++ }, + -+ $stmt .= " -+ WHERE -+ iss_id=$issue_id"; ++ updateTables: function() { ++ this.each(function() { ++ // this is now bound to each matching table ++ if (this.tableDnDConfig) { ++ jQuery.tableDnD.makeDraggable(this); ++ } ++ }) ++ }, + -+ $res = $GLOBALS["db_api"]->dbh->query($stmt); -+ if (PEAR::isError($res)) { -+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); -+ return -1; -+ } else { -+ $new = array( -+ 'category' => $current['iss_prc_id'], -+ 'release' => $current['iss_pre_id'], -+ 'expected_resolution_date' => $current['iss_expected_resolution_date'], -+ 'release' => $current['iss_pre_id'], -+ 'priority' => $current['iss_pri_id'], -+ 'status' => $current['iss_sta_id'], -+ 'resolution' => $current['iss_res_id'], -+ 'summary' => $current['iss_summary'], -+ 'description' => $current['iss_description'], -+ 'estimated_dev_time' => $current['iss_dev_time'], -+ 'percent_complete' => $current['iss_percent_complete'], -+ 'trigger_reminders' => $current['iss_trigger_reminders'], -+ 'group' => $current['iss_grp_id'], -+ 'iss_private' => $current['private'] -+ ); -+ $new[$field_name] = $filed_value; ++ /** Get the mouse coordinates from the event (allowing for browser differences) */ ++ mouseCoords: function(ev){ ++ if(ev.pageX || ev.pageY){ ++ return {x:ev.pageX, y:ev.pageY}; ++ } ++ return { ++ x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, ++ y:ev.clientY + document.body.scrollTop - document.body.clientTop ++ }; ++ }, + -+ // add change to the history (only for changes on specific fields?) -+ $updated_fields = array(); -+ if ($field_name == 'expected_resolution_date' && $current["iss_expected_resolution_date"] != $filed_value) { -+ $updated_fields["Expected Resolution Date"] = History::formatChanges($current["iss_expected_resolution_date"], $filed_value); -+ } -+ if ($field_name == 'category' && $current["iss_prc_id"] != $filed_value) { -+ $updated_fields["Category"] = History::formatChanges(Category::getTitle($current["iss_prc_id"]), Category::getTitle($filed_value)); -+ } -+ if ($field_name == 'release' && $current["iss_pre_id"] != $filed_value) { -+ $updated_fields["Release"] = History::formatChanges(Release::getTitle($current["iss_pre_id"]), Release::getTitle($filed_value)); -+ } -+ if ($field_name == 'priority' && $current["iss_pri_id"] != $filed_value) { -+ $updated_fields["Priority"] = History::formatChanges(Priority::getTitle($current["iss_pri_id"]), Priority::getTitle($filed_value)); -+ Workflow::handlePriorityChange($prj_id, $issue_id, $usr_id, $current, $new); -+ } -+ if ($field_name == 'status' && $current["iss_sta_id"] != $filed_value) { -+ // clear out the last-triggered-reminder flag when changing the status of an issue -+ Reminder_Action::clearLastTriggered($issue_id); ++ /** Given a target element and a mouse event, get the mouse offset from that element. ++ To do this we need the element's position and the mouse position */ ++ getMouseOffset: function(target, ev) { ++ ev = ev || window.event; + -+ // if old status was closed and new status is not, clear closed data from issue. -+ $old_status_details = Status::getDetails($current['iss_sta_id']); -+ if ($old_status_details['sta_is_closed'] == 1) { -+ $new_status_details = Status::getDetails($filed_value); -+ if ($new_status_details['sta_is_closed'] != 1) { -+ Issue::clearClosed($issue_id); -+ } -+ } -+ $updated_fields["Status"] = History::formatChanges(Status::getStatusTitle($current["iss_sta_id"]), Status::getStatusTitle($filed_value)); -+ } -+ if ($field_name == 'resolution' && $current["iss_res_id"] != $filed_value) { -+ $updated_fields["Resolution"] = History::formatChanges(Resolution::getTitle($current["iss_res_id"]), Resolution::getTitle($filed_value)); -+ } -+ if ($field_name == 'estimated_dev_time' && $current["iss_dev_time"] != $filed_value) { -+ $updated_fields["Estimated Dev. Time"] = History::formatChanges(Misc::getFormattedTime(($current["iss_dev_time"]*60)), Misc::getFormattedTime(($filed_value*60))); -+ } -+ if ($field_name == 'summary' && $current["iss_summary"] != $filed_value) { -+ $updated_fields["Summary"] = ''; -+ } -+ if ($field_name == 'description' && $current["iss_description"] != $filed_value) { -+ $updated_fields["Description"] = ''; -+ } -+ if ($field_name == 'private' && ($filed_value != $current['iss_private'])) { -+ $updated_fields["Private"] = History::formatChanges(Misc::getBooleanDisplayValue($current['iss_private']), Misc::getBooleanDisplayValue($filed_value)); -+ } -+ if (count($updated_fields) > 0) { -+ // log the changes -+ $changes = ''; -+ $i = 0; -+ foreach ($updated_fields as $key => $value) { -+ if ($i > 0) { -+ $changes .= "; "; -+ } -+ if (($key != "Summary") && ($key != "Description")) { -+ $changes .= "$key: $value"; -+ } else { -+ $changes .= "$key"; ++ var docPos = this.getPosition(target); ++ var mousePos = this.mouseCoords(ev); ++ return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; ++ }, ++ ++ /** Get the position of an element by going up the DOM tree and adding up all the offsets */ ++ getPosition: function(e){ ++ var left = 0; ++ var top = 0; ++ /** Safari fix -- thanks to Luis Chato for this! */ ++ if (e.offsetHeight == 0) { ++ /** Safari 2 doesn't correctly grab the offsetTop of a table row ++ this is detailed here: ++ http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ ++ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. ++ note that firefox will return a text node as a first child, so designing a more thorough ++ solution may need to take that into account, for now this seems to work in firefox, safari, ie */ ++ e = e.firstChild; // a table cell ++ } ++ ++ while (e.offsetParent){ ++ left += e.offsetLeft; ++ top += e.offsetTop; ++ e = e.offsetParent; ++ } ++ ++ left += e.offsetLeft; ++ top += e.offsetTop; ++ ++ return {x:left, y:top}; ++ }, ++ ++ mousemove: function(ev) { ++ if (jQuery.tableDnD.dragObject == null) { ++ return; ++ } ++ ++ var dragObj = jQuery(jQuery.tableDnD.dragObject); ++ var config = jQuery.tableDnD.currentTable.tableDnDConfig; ++ var mousePos = jQuery.tableDnD.mouseCoords(ev); ++ var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; ++ //auto scroll the window ++ var yOffset = window.pageYOffset; ++ if (document.all) { ++ // Windows version ++ //yOffset=document.body.scrollTop; ++ if (typeof document.compatMode != 'undefined' && ++ document.compatMode != 'BackCompat') { ++ yOffset = document.documentElement.scrollTop; ++ } ++ else if (typeof document.body != 'undefined') { ++ yOffset=document.body.scrollTop; ++ } ++ ++ } ++ ++ if (mousePos.y-yOffset < config.scrollAmount) { ++ window.scrollBy(0, -config.scrollAmount); ++ } else { ++ var windowHeight = window.innerHeight ? window.innerHeight ++ : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; ++ if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { ++ window.scrollBy(0, config.scrollAmount); ++ } ++ } ++ ++ ++ if (y != jQuery.tableDnD.oldY) { ++ // work out if we're going up or down... ++ var movingDown = y > jQuery.tableDnD.oldY; ++ // update the old value ++ jQuery.tableDnD.oldY = y; ++ // update the style to show we're dragging ++ if (config.onDragClass) { ++ dragObj.addClass(config.onDragClass); ++ } else { ++ dragObj.css(config.onDragStyle); ++ } ++ // If we're over a row then move the dragged row to there so that the user sees the ++ // effect dynamically ++ var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); ++ if (currentRow) { ++ // TODO worry about what happens when there are multiple TBODIES ++ if (movingDown && jQuery.tableDnD.dragObject != currentRow) { ++ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); ++ } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { ++ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); ++ } ++ } ++ } ++ ++ return false; ++ }, ++ ++ /** We're only worried about the y position really, because we can only move rows up and down */ ++ findDropTargetRow: function(draggedRow, y) { ++ var rows = jQuery.tableDnD.currentTable.rows; ++ for (var i=0; i rowY - rowHeight) && (y < (rowY + rowHeight))) { ++ // that's the row we're over ++ // If it's the same as the current row, ignore it ++ if (row == draggedRow) {return null;} ++ var config = jQuery.tableDnD.currentTable.tableDnDConfig; ++ if (config.onAllowDrop) { ++ if (config.onAllowDrop(draggedRow, row)) { ++ return row; ++ } else { ++ return null; ++ } ++ } else { ++ // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) ++ var nodrop = jQuery(row).hasClass("nodrop"); ++ if (! nodrop) { ++ return row; ++ } else { ++ return null; + } -+ $i++; + } ++ return row; ++ } ++ } ++ return null; ++ }, + -+ History::add($issue_id, $usr_id, History::getTypeID('issue_updated'), "Issue updated ($changes) by " . User::getFullName($usr_id)); -+ // send notifications for the issue being updated -+ Notification::notifyIssueUpdated($issue_id, $current, $new); ++ mouseup: function(e) { ++ if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { ++ var droppedRow = jQuery.tableDnD.dragObject; ++ var config = jQuery.tableDnD.currentTable.tableDnDConfig; ++ // If we have a dragObject, then we need to release it, ++ // The row will already have been moved to the right place so we just reset stuff ++ if (config.onDragClass) { ++ jQuery(droppedRow).removeClass(config.onDragClass); ++ } else { ++ jQuery(droppedRow).css(config.onDropStyle); ++ } ++ jQuery.tableDnD.dragObject = null; ++ if (config.onDrop) { ++ // Call the onDrop method if there is one ++ config.onDrop(jQuery.tableDnD.currentTable, droppedRow); + } ++ jQuery.tableDnD.currentTable = null; // let go of the table too + } -+ return 1; ++ }, ++ ++ serialize: function() { ++ if (jQuery.tableDnD.currentTable) { ++ return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable); ++ } else { ++ return "Error: No Table id set, you need to set an id on your table and every row"; ++ } ++ }, ++ ++ serializeTable: function(table) { ++ var result = ""; ++ var tableId = table.id; ++ var rows = table.rows; ++ for (var i=0; i 0) result += "&"; ++ var rowId = rows[i].id; ++ if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) { ++ rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0]; ++ } ++ ++ result += tableId + '[]=' + rowId; ++ } ++ return result; ++ }, ++ ++ serializeTables: function() { ++ var result = ""; ++ this.each(function() { ++ // this is now bound to each matching table ++ result += jQuery.tableDnD.serializeTable(this); ++ }); ++ return result; ++ } ++ ++} ++ ++jQuery.fn.extend( ++ { ++ tableDnD : jQuery.tableDnD.build, ++ tableDnDUpdate : jQuery.tableDnD.updateTables, ++ tableDnDSerialize: jQuery.tableDnD.serializeTables ++ } ++); +\ No newline at end of file +--- eventum-2.3.2/htdocs/list.php~ 2012-03-09 18:19:56.000000000 +0200 ++++ eventum-2.3.2/htdocs/list.php 2012-03-09 18:32:43.998284397 +0200 +@@ -67,6 +67,11 @@ + } + } + ++@$reorder_usr_id = $_REQUEST["reorder_user"]; ++@$reorder_issue_id = $_REQUEST["reorder_source"]; ++@$reorder_neworder = $_REQUEST["reorder_neworder"]; ++Issue::reorderUserIssues($reorder_usr_id, $reorder_issue_id, $reorder_neworder); ++ + if (!empty($_REQUEST['nosave'])) { + $options = Search::saveSearchParams(false); + } else { +@@ -92,6 +97,24 @@ + } + $assign_options += $users; + ++// get the isu_order (assigned users) ordering user ++if (!empty($options["users"])) { ++ if ($options["users"] == -2) { ++ $isu_order_user = $usr_id; ++ } else ++ if ($options["users"] > 0) { ++ $isu_order_user = $options["users"]; ++ } else { ++ unset($isu_order_user); + } ++} else { ++ unset($isu_order_user); ++} ++ ++if (isset($isu_order_user)) { ++ $tpl->assign("isu_order_user", $isu_order_user); ++} + + $list = Search::getListing($prj_id, $options, $pagerRow, $rows); + $tpl->assign("list", $list["list"]); + $tpl->assign("list_info", $list["info"]); +--- eventum-2.2/lib/eventum/class.display_column.php 2009-09-14 18:07:55.000000000 +0300 ++++ eventum-2.2-order/lib/eventum/class.display_column.php 2009-10-12 22:10:36.429185594 +0300 +@@ -230,7 +230,10 @@ + ), + "iss_expected_resolution_date" => array( + "title" => ev_gettext("Expected Resolution Date") +- ) ++ ), ++ "isu_order" => array( ++ "title" => ev_gettext("Order") ++ ), + ) + ); + return $columns[$page]; +--- eventum-2.3.1/lib/eventum/class.issue.php~ 2011-09-15 09:36:55.000000000 +0300 ++++ eventum-2.3.1/lib/eventum/class.issue.php 2011-09-15 09:42:02.844032474 +0300 +@@ -1374,6 +1374,7 @@ + return -1; + } - /** - * Move the issue to a new project -@@ -1820,16 +1991,33 @@ ++ self::moveOrderForAllUsers($issue_id, 1000); + $prj_id = self::getProjectID($issue_id); + + // record the change +@@ -1800,16 +1801,33 @@ { $issue_id = Misc::escapeInteger($issue_id); $assignee_usr_id = Misc::escapeInteger($assignee_usr_id); + $order = 1; + // move all orders down to free "order space" for this new association -+ $stmt = "UPDATE ++ $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + SET + isu_order = isu_order + 1 + WHERE + isu_usr_id = $assignee_usr_id AND + isu_order >= $order"; -+ $res = $GLOBALS["db_api"]->dbh->query($stmt); ++ $res = DB_Helper::getInstance()->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; @@ -337,13 +583,13 @@ ) VALUES ( $issue_id, $assignee_usr_id, -- '" . Date_API::getCurrentDateGMT() . "' -+ '" . Date_API::getCurrentDateGMT() . "', +- '" . Date_Helper::getCurrentDateGMT() . "' ++ '" . Date_Helper::getCurrentDateGMT() . "', + $order )"; - $res = $GLOBALS["db_api"]->dbh->query($stmt); + $res = DB_Helper::getInstance()->query($stmt); if (PEAR::isError($res)) { -@@ -1844,6 +2032,78 @@ +@@ -1824,6 +1842,78 @@ } } @@ -362,11 +608,11 @@ + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + WHERE + isu_iss_id IN ($issue_id)"; -+ if ($usr_id !== FALSE) { ++ if (!empty($usr_id)) { + $stmt.= " AND isu_usr_id IN ($usr_id)"; + } + $stmt.= "ORDER BY isu_order"; -+ $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); ++ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; @@ -409,7 +655,7 @@ + $stmt.= " AND + isu_order < " . $orders[$i+1]; + } -+ $res = $GLOBALS["db_api"]->dbh->query($stmt); ++ $res = DB_Helper::getInstance()->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; @@ -422,59 +668,31 @@ /** * Method used to delete all user assignments for a specific issue. -@@ -1859,6 +2119,7 @@ +@@ -1839,6 +1929,7 @@ if (is_array($issue_id)) { $issue_id = implode(", ", $issue_id); } -+ $deleted_order_list = Issue::getDeleteUserAssociationOrderList($issue_id); ++ $deleted_order_list = self::getDeleteUserAssociationOrderList($issue_id); $stmt = "DELETE FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user WHERE -@@ -1871,6 +2132,7 @@ - if ($usr_id) { - History::add($issue_id, $usr_id, History::getTypeID('user_all_unassociated'), 'Issue assignments removed by ' . User::getFullName($usr_id)); - } -+ Issue::rearrangeDeleteUserAsssociationOrderList($deleted_order_list); - return 1; - } - } -@@ -1889,6 +2151,7 @@ +@@ -1869,6 +1960,7 @@ { $issue_id = Misc::escapeInteger($issue_id); $usr_id = Misc::escapeInteger($usr_id); -+ $delete_order_list = Issue::getDeleteUserAssociationOrderList($issue_id, $usr_id); ++ $delete_order_list = self::getDeleteUserAssociationOrderList($issue_id, $usr_id); $stmt = "DELETE FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user WHERE -@@ -1903,6 +2166,7 @@ - History::add($issue_id, Auth::getUserID(), History::getTypeID('user_unassociated'), - User::getFullName($usr_id) . ' removed from issue by ' . User::getFullName(Auth::getUserID())); - } -+ Issue::rearrangeDeleteUserAssociationOrderList($delete_order_list); - return 1; +@@ -2020,6 +2021,7 @@ + History::add($issue_id, Auth::getUserID(), History::getTypeID('user_unassociated'), + User::getFullName($usr_id) . ' removed from issue by ' . User::getFullName(Auth::getUserID())); } ++ self::rearrangeDeleteUserAssociationOrderList($delete_order_list); + return 1; } -@@ -2379,6 +2643,11 @@ - { - $sort_by = Issue::getParam('sort_by'); - $sort_order = Issue::getParam('sort_order'); -+ $users = Issue::getParam('users'); -+ if (empty($users) && ($sort_by == 'isu_order')) { // Sorting by isu_order is impossible when no user specified -+ unset($sort_by); -+ unset($sort_order); -+ } - $rows = Issue::getParam('rows'); - $hide_closed = Issue::getParam('hide_closed'); - if ($hide_closed === '') { -@@ -2483,6 +2752,7 @@ - "last_action_date" => "desc", - "usr_full_name" => "asc", - "iss_expected_resolution_date" => "desc", -+ "isu_order" => "desc", - ); - foreach ($custom_fields as $fld_id => $fld_name) { -@@ -3275,6 +3545,8 @@ +@@ -3253,6 +3352,8 @@ $ids = implode(", ", $ids); $stmt = "SELECT isu_iss_id, @@ -483,7 +701,7 @@ usr_full_name FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user, -@@ -3286,6 +3558,7 @@ +@@ -3264,6 +3365,7 @@ if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); } else { @@ -491,7 +709,7 @@ $t = array(); for ($i = 0; $i < count($res); $i++) { if (!empty($t[$res[$i]['isu_iss_id']])) { -@@ -3294,9 +3567,18 @@ +@@ -3272,9 +3374,18 @@ $t[$res[$i]['isu_iss_id']] = $res[$i]['usr_full_name']; } } @@ -510,17 +728,17 @@ } } } -@@ -4264,6 +4546,7 @@ +@@ -4247,6 +4358,7 @@ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } -+ Issue::moveOrderForAllUsers($issue_id, 1); ++ self::moveOrderForAllUsers($issue_id, 1); } -@@ -4322,8 +4605,127 @@ - } - return $returns[$msg_id]; +@@ -4346,4 +4458,120 @@ + History::add($issue_id, Auth::getUserID(), History::getTypeID('user_associated'), + "Issue assignment to changed (" . History::formatChanges(join(', ', $old_assignee_names), join(', ', $assignee_names)) . ") by " . User::getFullName(Auth::getUserID())); } + + /** @@ -551,8 +769,8 @@ + $issue_id = array($issue_id); + } + // do a nasty pretending to be deleting stuff so that reordering happens as if these elements were deleted -+ $orderlist = Issue::getDeleteUserAssociationOrderList($issue_id_str, $usr_id); -+ Issue::rearrangeDeleteUserAssociationOrderList($orderlist); ++ $orderlist = self::getDeleteUserAssociationOrderList($issue_id_str, $usr_id); ++ self::rearrangeDeleteUserAssociationOrderList($orderlist); + // move down the orders to free the "order space" needed + $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user @@ -561,7 +779,7 @@ + WHERE + isu_usr_id = $usr_id AND + isu_order >= $neworder"; -+ $res = $GLOBALS["db_api"]->dbh->query($stmt); ++ $res = DB_Helper::getInstance()->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; @@ -576,7 +794,7 @@ + WHERE + isu_usr_id = $usr_id AND + isu_iss_id = $iss_id"; -+ $res = $GLOBALS["db_api"]->dbh->query($stmt); ++ $res = DB_Helper::getInstance()->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; @@ -608,7 +826,7 @@ + + $order_list = array(); + -+ $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); ++ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC); + + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); @@ -628,105 +846,53 @@ + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + WHERE + isu_iss_id = " . Misc::escapeInteger($issue_id); -+ $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); ++ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + foreach ($res as $row) { -+ Issue::reorderUserIssues($row["isu_usr_id"], $issue_id, $neworder); ++ self::reorderUserIssues($row["isu_usr_id"], $issue_id, $neworder); + } + } + } +--- eventum-2.3.1/lib/eventum/class.search.php~ 2011-04-20 17:22:15.000000000 +0300 ++++ eventum-2.3.1/lib/eventum/class.search.php 2011-04-20 17:44:34.498519260 +0300 +@@ -63,6 +63,12 @@ + { + $sort_by = self::getParam('sort_by'); + $sort_order = self::getParam('sort_order'); ++ $users = self::getParam('users'); ++ if (empty($users) && $sort_by === 'isu_order') { ++ // Sorting by isu_order is impossible when no user specified ++ unset($sort_by); ++ unset($sort_order); ++ } + $rows = self::getParam('rows'); + $hide_closed = self::getParam('hide_closed'); + if ($hide_closed === '') { +@@ -174,6 +174,7 @@ + "iss_expected_resolution_date" => "desc", + "pre_title" => "asc", + "assigned" => "asc", ++ "isu_order" => "desc", + ); -+ -+ -+ - // benchmarking the included file (aka setup time) - if (APP_BENCHMARK) { - $GLOBALS['bench']->setMarker('Included Issue Class'); ---- eventum-r3749/js/global.js~ 2008-10-15 02:03:48.000000000 +0300 -+++ eventum-r3749/js/global.js 2008-10-15 02:06:00.000000000 +0300 -@@ -799,4 +799,39 @@ - }); - }); - }); -+ -+$(document).ready(function() { -+ // dialog type calender isn't working in Konqueror beacuse it's not a supported browser for either jQuery or jQuery UI -+ // http://groups.google.com/group/jquery-ui/browse_thread/thread/ea61238c34cb5f33/046837b02fb90b5c -+ if (navigator.appName != 'Konqueror') { -+ $(".inline_date_pick").click(function() { -+ var masterObj = this; -+ var masterObjPos = $(masterObj).offset(); -+ // offset gives uses top and left but datepicker needs pageX and pageY -+ var masterObjPos = {pageX: masterObjPos.left, pageY: masterObjPos.top}; -+ $(this).datepicker( -+ // we use dialog type calender so we won't haveto have a hidden element on the page -+ 'dialog', -+ // selected date -+ masterObj.innerHTML, -+ // onclick handler -+ function (date, dteObj) { -+ fieldName = masterObj.id.substr(0,masterObj.id.indexOf('|')); -+ issueID = masterObj.id.substr(masterObj.id.indexOf('|')+1); -+ $.post("/ajax/update.php", {fieldName: fieldName, issueID: issueID, day: dteObj.selectedDay, month: (dteObj.selectedMonth+1), year: dteObj.selectedYear}, function(data) { -+ if (data.length > 0) { -+ masterObj.innerHTML = data; -+ } -+ }, "text"); -+ }, -+ // config -+ {dateFormat: 'dd M yy', duration: ""}, -+ // position of the datepicker calender - taken from div's offset -+ masterObjPos -+ ); -+ return false; -+ }); -+ } -+}); -+ - //--> ---- eventum/list.php 2008-10-15 01:46:20.000000000 +0300 -+++ eventum-new/list.php 2008-10-15 02:02:25.000000000 +0300 -@@ -67,6 +67,11 @@ - $profile['sort_by'] . "&sort_order=" . $profile['sort_order']); - } - -+@$reorder_usr_id = $_REQUEST["reorder_user"]; -+@$reorder_issue_id = $_REQUEST["reorder_source"]; -+@$reorder_neworder = $_REQUEST["reorder_neworder"]; -+Issue::reorderUserIssues($reorder_usr_id, $reorder_issue_id, $reorder_neworder); -+ - $options = Issue::saveSearchParams(); - $tpl->assign("options", $options); - $tpl->assign("sorting", Issue::getSortingInfo($options)); -@@ -90,6 +95,21 @@ - } - $assign_options += $users; - -+// get the isu_order (assignated users) ordering user -+if (!empty($options["users"])) { -+ if ($options["users"] == -2) { -+ $isu_order_user = $usr_id; -+ } else -+ if ($options["users"] > 0) { -+ $isu_order_user = $options["users"]; -+ } else { -+ unset($isu_order_user); -+ } -+} else { -+ unset($isu_order_user); -+} -+$tpl->assign("isu_order_user", $isu_order_user); -+ - $list = Issue::getListing($prj_id, $options, $pagerRow, $rows); - $tpl->assign("list", $list["list"]); - $tpl->assign("list_info", $list["info"]); ---- eventum/templates/list.tpl.html 2008-10-15 01:46:20.000000000 +0300 -+++ eventum-new/templates/list.tpl.html 2008-10-15 02:02:25.000000000 +0300 -@@ -89,6 +89,28 @@ + foreach ($custom_fields as $fld_id => $fld_name) { +--- eventum-2.3.1/templates/header.tpl.html~ 2011-09-15 09:36:55.000000000 +0300 ++++ eventum-2.3.1/templates/header.tpl.html 2011-09-15 09:43:49.318473817 +0300 +@@ -18,6 +18,7 @@ + + + ++ + + + +--- eventum-2.2/templates/list.tpl.html 2009-09-14 18:07:55.000000000 +0300 ++++ eventum-2.2-order/templates/list.tpl.html 2009-10-12 22:10:36.439185157 +0300 +@@ -92,6 +92,28 @@ f.target = '_popup'; f.submit(); } @@ -755,7 +921,7 @@ function hideClosed(f) { if (f.hide_closed.checked) { -@@ -150,6 +172,13 @@ +@@ -153,6 +175,13 @@ f.go.disabled = true; } } @@ -769,7 +935,7 @@ //--> {/literal} -@@ -166,11 +195,11 @@ +@@ -169,11 +198,11 @@ @@ -784,7 +950,7 @@ {t}Search Results{/t} ({$list_info.total_rows} {t}issues found{/t}{if $list_info.end_offset > 0}, {math equation="x + 1" x=$list_info.start_offset} - {$list_info.end_offset} {t}shown{/t}{/if}) {include file="help_link.tpl.html" topic="list"} -@@ -190,7 +219,7 @@ +@@ -193,7 +222,7 @@ @@ -793,7 +959,7 @@ {if $current_role > $roles.developer} -@@ -205,7 +234,7 @@ +@@ -208,7 +237,7 @@ {if $sorting.images[$fld_name_id] != ""}{/if} {/foreach} @@ -802,17 +968,7 @@ {if $field_name == 'iss_summary'} -@@ -221,6 +250,9 @@ -
- {elseif $sorting.links[$field_name] != ''} - {$column.title} -+ {if $field_name == 'isu_order'} -+
{$users[$isu_order_user]} -+ {/if} - {if $sorting.images[$field_name] != ""}{/if} - {else} - {$column.title} -@@ -229,19 +261,20 @@ +@@ -268,8 +268,9 @@ {/if} {/foreach} @@ -823,46 +979,32 @@ {if $current_role > $roles.developer} {/if} - {foreach from=$columns item=column key=field_name} - {if $field_name == 'custom_fields'} - {foreach from=$list[i].custom_field key=fld_id item=fld_value} -- -- {$fld_value|formatCustomValue:$fld_id:$list[i].iss_id} -+ -+ {$fld_value|formatCustomValue:$fld_id:$list[i].iss_id} +@@ -280,8 +281,8 @@ + {$fld_value|formatCustomValue:$fld_id:$list[i].iss_id} {/foreach} - {else} +- + {elseif $field_name != 'isu_order' || $isu_order_user} - ++ {if $field_name == 'iss_id'} {$list[i].iss_id} -@@ -276,7 +309,7 @@ - {elseif $field_name == 'iss_percent_complete'} - {$list[i].iss_percent_complete|escape:"html"}% - {elseif $field_name == 'iss_expected_resolution_date'} -- {$list[i].iss_expected_resolution_date|escape:"html"} -+
{$list[i].iss_expected_resolution_date|escape:"html"} 
- {elseif $field_name == 'iss_summary'} - {$list[i].iss_summary|escape:"html"} - {if $list[i].redeemed} -@@ -285,6 +318,10 @@ + {elseif $field_name == 'pri_rank'} +@@ -288,6 +318,8 @@ {if $list[i].iss_private == 1} [Private] {/if} + {elseif $field_name == 'isu_order'} -+ {if $list[i].assigned_users_order[$current_user_id]} -+ move -+ {/if} ++ {if $options.sort_by == "isu_order" and $current_user_id == $isu_order_user} {/if} {/if} {/if} -@@ -297,10 +334,11 @@ +@@ -300,10 +332,11 @@ {/section} - -+ ++ + @@ -871,7 +1013,7 @@
{if $current_role > $roles.developer} -@@ -352,6 +390,29 @@ +@@ -355,6 +388,35 @@

@@ -895,498 +1037,6 @@ + alert(data); + } + }, "text"); -+ } -+}); -+{/literal} -+{/if} -+ - {include file="app_info.tpl.html"} --{include file="footer.tpl.html"} -+{include file="footer.tpl.html"} -\ No newline at end of file ---- ./js/jquery/jquery.tablednd.js (revision 0) -+++ ./js/jquery/jquery.tablednd.js (revision 0) -@@ -0,0 +1,382 @@ -+/** -+ * TableDnD plug-in for JQuery, allows you to drag and drop table rows -+ * You can set up various options to control how the system will work -+ * Copyright (c) Denis Howlett -+ * Licensed like jQuery, see http://docs.jquery.com/License. -+ * -+ * Configuration options: -+ * -+ * onDragStyle -+ * This is the style that is assigned to the row during drag. There are limitations to the styles that can be -+ * associated with a row (such as you can't assign a border--well you can, but it won't be -+ * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as -+ * a map (as used in the jQuery css(...) function). -+ * onDropStyle -+ * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations -+ * to what you can do. Also this replaces the original style, so again consider using onDragClass which -+ * is simply added and then removed on drop. -+ * onDragClass -+ * This class is added for the duration of the drag and then removed when the row is dropped. It is more -+ * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default -+ * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your -+ * stylesheet. -+ * onDrop -+ * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table -+ * and the row that was dropped. You can work out the new order of the rows by using -+ * table.rows. -+ * onDragStart -+ * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the -+ * table and the row which the user has started to drag. -+ * onAllowDrop -+ * Pass a function that will be called as a row is over another row. If the function returns true, allow -+ * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under -+ * the cursor. It returns a boolean: true allows the drop, false doesn't allow it. -+ * scrollAmount -+ * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the -+ * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, -+ * FF3 beta -+ * dragHandle -+ * This is the name of a class that you assign to one or more cells in each row that is draggable. If you -+ * specify this class, then you are responsible for setting cursor: move in the CSS and only these cells -+ * will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where -+ * the whole row is draggable. -+ * -+ * Other ways to control behaviour: -+ * -+ * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows -+ * that you don't want to be draggable. -+ * -+ * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form -+ * []=&[]= so that you can send this back to the server. The table must have -+ * an ID as must all the rows. -+ * -+ * Other methods: -+ * -+ * $("...").tableDnDUpdate() -+ * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells). -+ * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again. -+ * The table maintains the original configuration (so you don't have to specify it again). -+ * -+ * $("...").tableDnDSerialize() -+ * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be -+ * called from anywhere and isn't dependent on the currentTable being set up correctly before calling -+ * -+ * Known problems: -+ * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0 -+ * -+ * Version 0.2: 2008-02-20 First public version -+ * Version 0.3: 2008-02-07 Added onDragStart option -+ * Made the scroll amount configurable (default is 5 as before) -+ * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes -+ * Added onAllowDrop to control dropping -+ * Fixed a bug which meant that you couldn't set the scroll amount in both directions -+ * Added serialize method -+ * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row -+ * draggable -+ * Improved the serialize method to use a default (and settable) regular expression. -+ * Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table -+ */ -+jQuery.tableDnD = { -+ /** Keep hold of the current table being dragged */ -+ currentTable : null, -+ /** Keep hold of the current drag object if any */ -+ dragObject: null, -+ /** The current mouse offset */ -+ mouseOffset: null, -+ /** Remember the old value of Y so that we don't do too much processing */ -+ oldY: 0, -+ -+ /** Actually build the structure */ -+ build: function(options) { -+ // Set up the defaults if any -+ -+ this.each(function() { -+ // This is bound to each matching table, set up the defaults and override with user options -+ this.tableDnDConfig = jQuery.extend({ -+ onDragStyle: null, -+ onDropStyle: null, -+ // Add in the default class for whileDragging -+ onDragClass: "tDnD_whileDrag", -+ onDrop: null, -+ onDragStart: null, -+ scrollAmount: 5, -+ serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs -+ serializeParamName: null, // If you want to specify another parameter name instead of the table ID -+ dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable -+ }, options || {}); -+ // Now make the rows draggable -+ jQuery.tableDnD.makeDraggable(this); -+ }); -+ -+ // Now we need to capture the mouse up and mouse move event -+ // We can use bind so that we don't interfere with other event handlers -+ jQuery(document) -+ .bind('mousemove', jQuery.tableDnD.mousemove) -+ .bind('mouseup', jQuery.tableDnD.mouseup); -+ -+ // Don't break the chain -+ return this; -+ }, -+ -+ /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */ -+ makeDraggable: function(table) { -+ var config = table.tableDnDConfig; -+ if (table.tableDnDConfig.dragHandle) { -+ // We only need to add the event to the specified cells -+ var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table); -+ cells.each(function() { -+ // The cell is bound to "this" -+ jQuery(this).mousedown(function(ev) { -+ jQuery.tableDnD.dragObject = this.parentNode; -+ jQuery.tableDnD.currentTable = table; -+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); -+ if (config.onDragStart) { -+ // Call the onDrop method if there is one -+ config.onDragStart(table, this); -+ } -+ return false; -+ }); -+ }) -+ } else { -+ // For backwards compatibility, we add the event to the whole row -+ var rows = jQuery("tr", table); // get all the rows as a wrapped set -+ rows.each(function() { -+ // Iterate through each row, the row is bound to "this" -+ var row = jQuery(this); -+ if (! row.hasClass("nodrag")) { -+ row.mousedown(function(ev) { -+ if (ev.target.tagName == "TD") { -+ jQuery.tableDnD.dragObject = this; -+ jQuery.tableDnD.currentTable = table; -+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev); -+ if (config.onDragStart) { -+ // Call the onDrop method if there is one -+ config.onDragStart(table, this); -+ } -+ return false; -+ } -+ }).css("cursor", "move"); // Store the tableDnD object -+ } -+ }); -+ } -+ }, -+ -+ updateTables: function() { -+ this.each(function() { -+ // this is now bound to each matching table -+ if (this.tableDnDConfig) { -+ jQuery.tableDnD.makeDraggable(this); -+ } -+ }) -+ }, -+ -+ /** Get the mouse coordinates from the event (allowing for browser differences) */ -+ mouseCoords: function(ev){ -+ if(ev.pageX || ev.pageY){ -+ return {x:ev.pageX, y:ev.pageY}; -+ } -+ return { -+ x:ev.clientX + document.body.scrollLeft - document.body.clientLeft, -+ y:ev.clientY + document.body.scrollTop - document.body.clientTop -+ }; -+ }, -+ -+ /** Given a target element and a mouse event, get the mouse offset from that element. -+ To do this we need the element's position and the mouse position */ -+ getMouseOffset: function(target, ev) { -+ ev = ev || window.event; -+ -+ var docPos = this.getPosition(target); -+ var mousePos = this.mouseCoords(ev); -+ return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y}; -+ }, -+ -+ /** Get the position of an element by going up the DOM tree and adding up all the offsets */ -+ getPosition: function(e){ -+ var left = 0; -+ var top = 0; -+ /** Safari fix -- thanks to Luis Chato for this! */ -+ if (e.offsetHeight == 0) { -+ /** Safari 2 doesn't correctly grab the offsetTop of a table row -+ this is detailed here: -+ http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/ -+ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild. -+ note that firefox will return a text node as a first child, so designing a more thorough -+ solution may need to take that into account, for now this seems to work in firefox, safari, ie */ -+ e = e.firstChild; // a table cell -+ } -+ -+ while (e.offsetParent){ -+ left += e.offsetLeft; -+ top += e.offsetTop; -+ e = e.offsetParent; -+ } -+ -+ left += e.offsetLeft; -+ top += e.offsetTop; -+ -+ return {x:left, y:top}; -+ }, -+ -+ mousemove: function(ev) { -+ if (jQuery.tableDnD.dragObject == null) { -+ return; -+ } -+ -+ var dragObj = jQuery(jQuery.tableDnD.dragObject); -+ var config = jQuery.tableDnD.currentTable.tableDnDConfig; -+ var mousePos = jQuery.tableDnD.mouseCoords(ev); -+ var y = mousePos.y - jQuery.tableDnD.mouseOffset.y; -+ //auto scroll the window -+ var yOffset = window.pageYOffset; -+ if (document.all) { -+ // Windows version -+ //yOffset=document.body.scrollTop; -+ if (typeof document.compatMode != 'undefined' && -+ document.compatMode != 'BackCompat') { -+ yOffset = document.documentElement.scrollTop; -+ } -+ else if (typeof document.body != 'undefined') { -+ yOffset=document.body.scrollTop; -+ } -+ -+ } -+ -+ if (mousePos.y-yOffset < config.scrollAmount) { -+ window.scrollBy(0, -config.scrollAmount); -+ } else { -+ var windowHeight = window.innerHeight ? window.innerHeight -+ : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight; -+ if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) { -+ window.scrollBy(0, config.scrollAmount); -+ } -+ } -+ -+ -+ if (y != jQuery.tableDnD.oldY) { -+ // work out if we're going up or down... -+ var movingDown = y > jQuery.tableDnD.oldY; -+ // update the old value -+ jQuery.tableDnD.oldY = y; -+ // update the style to show we're dragging -+ if (config.onDragClass) { -+ dragObj.addClass(config.onDragClass); -+ } else { -+ dragObj.css(config.onDragStyle); -+ } -+ // If we're over a row then move the dragged row to there so that the user sees the -+ // effect dynamically -+ var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y); -+ if (currentRow) { -+ // TODO worry about what happens when there are multiple TBODIES -+ if (movingDown && jQuery.tableDnD.dragObject != currentRow) { -+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling); -+ } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) { -+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow); -+ } -+ } -+ } -+ -+ return false; -+ }, -+ -+ /** We're only worried about the y position really, because we can only move rows up and down */ -+ findDropTargetRow: function(draggedRow, y) { -+ var rows = jQuery.tableDnD.currentTable.rows; -+ for (var i=0; i rowY - rowHeight) && (y < (rowY + rowHeight))) { -+ // that's the row we're over -+ // If it's the same as the current row, ignore it -+ if (row == draggedRow) {return null;} -+ var config = jQuery.tableDnD.currentTable.tableDnDConfig; -+ if (config.onAllowDrop) { -+ if (config.onAllowDrop(draggedRow, row)) { -+ return row; -+ } else { -+ return null; -+ } -+ } else { -+ // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic) -+ var nodrop = jQuery(row).hasClass("nodrop"); -+ if (! nodrop) { -+ return row; -+ } else { -+ return null; -+ } -+ } -+ return row; -+ } -+ } -+ return null; -+ }, -+ -+ mouseup: function(e) { -+ if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) { -+ var droppedRow = jQuery.tableDnD.dragObject; -+ var config = jQuery.tableDnD.currentTable.tableDnDConfig; -+ // If we have a dragObject, then we need to release it, -+ // The row will already have been moved to the right place so we just reset stuff -+ if (config.onDragClass) { -+ jQuery(droppedRow).removeClass(config.onDragClass); -+ } else { -+ jQuery(droppedRow).css(config.onDropStyle); -+ } -+ jQuery.tableDnD.dragObject = null; -+ if (config.onDrop) { -+ // Call the onDrop method if there is one -+ config.onDrop(jQuery.tableDnD.currentTable, droppedRow); -+ } -+ jQuery.tableDnD.currentTable = null; // let go of the table too -+ } -+ }, -+ -+ serialize: function() { -+ if (jQuery.tableDnD.currentTable) { -+ return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable); -+ } else { -+ return "Error: No Table id set, you need to set an id on your table and every row"; -+ } -+ }, -+ -+ serializeTable: function(table) { -+ var result = ""; -+ var tableId = table.id; -+ var rows = table.rows; -+ for (var i=0; i 0) result += "&"; -+ var rowId = rows[i].id; -+ if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) { -+ rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0]; -+ } -+ -+ result += tableId + '[]=' + rowId; -+ } -+ return result; -+ }, -+ -+ serializeTables: function() { -+ var result = ""; -+ this.each(function() { -+ // this is now bound to each matching table -+ result += jQuery.tableDnD.serializeTable(this); -+ }); -+ return result; -+ } -+ -+} -+ -+jQuery.fn.extend( -+ { -+ tableDnD : jQuery.tableDnD.build, -+ tableDnDUpdate : jQuery.tableDnD.updateTables, -+ tableDnDSerialize: jQuery.tableDnD.serializeTables -+ } -+); -\ No newline at end of file ---- eventum-r3765/templates/header.tpl.html~ 2008-10-28 20:23:04.000000000 +0200 -+++ eventum-r3765/templates/header.tpl.html 2008-10-28 22:39:10.604728264 +0200 -@@ -8,6 +8,7 @@ - - - -+ - - ++}); ++{/literal} ++{/if} ++ {include file="app_info.tpl.html"} --{include file="footer.tpl.html"} -\ No newline at end of file -+{include file="footer.tpl.html"} ---- eventum-r3776/misc/upgrade/update-database.php 2008-11-18 01:10:18.806283202 +0200 -+++ eventum/misc/upgrade/update-database.php 2008-11-18 01:15:20.703082655 +0200 -@@ -83,6 +83,7 @@ - 1 => '01_notes.php', - 2 => '02_usr_alias.php', - 3 => '03_prj_mail_aliases.php', -+ 4 => '04_isu_order.php', - ); - - // sanity check. check that the version table exists. ---- /dev/null 2008-11-04 20:33:38.146691408 +0200 -+++ eventum/misc/upgrade/patches/04_isu_order.php 2008-11-18 01:14:02.972104347 +0200 -@@ -0,0 +1,15 @@ -+ 0) { -- masterObj.innerHTML = data; -- } -+ masterObj.innerHTML = data; - }, "text"); - }, - // config ---- eventum-old2/include/class.issue.php 2008-10-15 18:30:31.590172372 +0300 -+++ ./include/class.issue.php 2008-11-19 15:04:43.710659328 +0200 -@@ -1694,7 +1694,11 @@ - $stmt .= ", iss_pre_id = " . Misc::escapeInteger($filed_value); - break; - case 'expected_resolution_date': -- $stmt .= ", iss_expected_resolution_date = '" . Misc::escapeString($filed_value) . "'"; -+ if (is_null($filed_value)) { -+ $stmt .= ", iss_expected_resolution_date = null"; -+ } else { -+ $stmt .= ", iss_expected_resolution_date = '" . Misc::escapeString($filed_value) . "'"; -+ } - break; - case 'release': - $stmt .= ", iss_pre_id = " . Misc::escapeInteger($filed_value); - ---- eventum/include/class.issue.php 2008-10-15 01:46:20.000000000 +0300 -+++ eventum-new/include/class.issue.php 2008-10-15 02:02:25.000000000 +0300 -@@ -2050,7 +2050,7 @@ - " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user - WHERE - isu_iss_id IN ($issue_id)"; -- if ($usr_id !== FALSE) { -+ if (!empty($usr_id)) { - $stmt.= " AND isu_usr_id IN ($usr_id)"; - } - $stmt.= "ORDER BY isu_order"; -@@ -2135,7 +2135,6 @@ - if ($usr_id) { - History::add($issue_id, $usr_id, History::getTypeID('user_all_unassociated'), 'Issue assignments removed by ' . User::getFullName($usr_id)); - } -- Issue::rearrangeDeleteUserAsssociationOrderList($deleted_order_list); - return 1; - } - } + {include file="footer.tpl.html"}