]> git.pld-linux.org Git - packages/eventum.git/blame - eventum-order.patch
Up to 3.10.12
[packages/eventum.git] / eventum-order.patch
CommitLineData
f4782eee
ER
1--- eventum-2.2/htdocs/ajax/order.php 1970-01-01 02:00:00.000000000 +0200
2+++ eventum-2.2-order/htdocs/ajax/order.php 2009-10-12 22:10:36.429185594 +0300
b738b023 3@@ -0,0 +1,69 @@
be762003 4+<?
b738b023 5+require_once dirname(__FILE__) . '/../../init.php';
be762003
ER
6+
7+// check login
8+if (!Auth::hasValidCookie(APP_COOKIE)) {
9+ exit;
10+}
11+
12+
be762003
ER
13+if (!isset($_POST['before']) || !isset($_POST['after'])) {
14+ exit;
15+}
16+
29e18d8b
ER
17+parse_str($_POST['before'], $before);
18+parse_str($_POST['after'], $after);
be762003
ER
19+
20+$before = $before['issue_list_table'];
21+$after = $after['issue_list_table'];
22+
23+
24+$before = array_slice($before, 2, count($before)-3);
25+$after = array_slice($after, 2, count($after)-3);
26+
27+if (count($before) != count($after) or count($before) < 1) {
28+ exit;
29+}
30+
31+$usr_id = Auth::getUserID();
32+
33+$order = Issue::getIssueOrderByUser($usr_id);
34+
35+if (!count($order)) {
36+ // no prev order list
37+ exit;
38+}
39+
40+$after_filterd = array();
41+$before_filterd = array();
42+
43+// remove issues that are not assigned to me
44+foreach ($after as $id) {
45+ if (isset($order[$id])) {
46+ $after_filterd[] = $id;
47+ }
48+}
49+foreach ($before as $id) {
50+ if (isset($order[$id])) {
51+ $before_filterd[] = $id;
52+ }
53+}
54+
55+foreach ($after_filterd as $key => $nID) {
56+ if ($nID != $before_filterd[$key]) {
57+ if ($nID) {
58+ $stmt = "UPDATE
59+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
60+ SET
61+ isu_order = " . $order[$before_filterd[$key]] . "
62+ WHERE
63+ isu_iss_id = $nID AND
64+ isu_usr_id = $usr_id";
c2e7ae63 65+ $res = DB_Helper::getInstance()->query($stmt);
be762003
ER
66+ if (PEAR::isError($res)) {
67+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
68+ die('update failed');
69+ }
70+ }
71+ }
72+}
858c6f2a
ER
73--- eventum-2.3.1/htdocs/css/style.css~ 2011-09-15 09:36:55.000000000 +0300
74+++ eventum-2.3.1/htdocs/css/style.css 2011-09-15 09:38:23.668223576 +0300
75@@ -177,6 +177,24 @@
098cbb72
ER
76 cursor: pointer;
77 }
858c6f2a 78
f4782eee
ER
79+.tDnD_whileDrag td {
80+ background-color: #ffffdd;
81+}
82+.tDnD_whileDrag td {
83+ border: 1px solid red;
84+}
85+.inline_date_pick {
86+ cursor: pointer;
87+}
88+.custom_field {
89+ cursor: pointer;
90+}
91+.showDragHandle {
92+ cursor: move;
93+ background-image: url(../images/updown2.gif);
94+ background-repeat: no-repeat;
95+ background-position: center center;
858c6f2a
ER
96+}
97
98 ul.excerpts {
99 list-style: none;
100@@ -187,4 +205,4 @@
101 ul.excerpts ul {
102 list-style-type: none;
103 padding-left: 1em;
104-}
105\ No newline at end of file
f4782eee 106+}
6b57f4ee
ER
107--- eventum-2.2/htdocs/js/jquery/jquery.tablednd.js 1970-01-01 02:00:00.000000000 +0200
108+++ eventum-2.2-order/htdocs/js/jquery/jquery.tablednd.js 2009-10-12 22:10:36.435851675 +0300
109@@ -0,0 +1,382 @@
110+/**
111+ * TableDnD plug-in for JQuery, allows you to drag and drop table rows
112+ * You can set up various options to control how the system will work
113+ * Copyright (c) Denis Howlett <denish@isocra.com>
114+ * Licensed like jQuery, see http://docs.jquery.com/License.
115+ *
116+ * Configuration options:
117+ *
118+ * onDragStyle
119+ * This is the style that is assigned to the row during drag. There are limitations to the styles that can be
120+ * associated with a row (such as you can't assign a border--well you can, but it won't be
121+ * displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as
122+ * a map (as used in the jQuery css(...) function).
123+ * onDropStyle
124+ * This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations
125+ * to what you can do. Also this replaces the original style, so again consider using onDragClass which
126+ * is simply added and then removed on drop.
127+ * onDragClass
128+ * This class is added for the duration of the drag and then removed when the row is dropped. It is more
129+ * flexible than using onDragStyle since it can be inherited by the row cells and other content. The default
130+ * is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your
131+ * stylesheet.
132+ * onDrop
133+ * Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table
134+ * and the row that was dropped. You can work out the new order of the rows by using
135+ * table.rows.
136+ * onDragStart
137+ * Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the
138+ * table and the row which the user has started to drag.
139+ * onAllowDrop
140+ * Pass a function that will be called as a row is over another row. If the function returns true, allow
141+ * dropping on that row, otherwise not. The function takes 2 parameters: the dragged row and the row under
142+ * the cursor. It returns a boolean: true allows the drop, false doesn't allow it.
143+ * scrollAmount
144+ * This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the
145+ * window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2,
146+ * FF3 beta
147+ * dragHandle
148+ * This is the name of a class that you assign to one or more cells in each row that is draggable. If you
149+ * specify this class, then you are responsible for setting cursor: move in the CSS and only these cells
150+ * will have the drag behaviour. If you do not specify a dragHandle, then you get the old behaviour where
151+ * the whole row is draggable.
152+ *
153+ * Other ways to control behaviour:
154+ *
155+ * Add class="nodrop" to any rows for which you don't want to allow dropping, and class="nodrag" to any rows
156+ * that you don't want to be draggable.
157+ *
158+ * Inside the onDrop method you can also call $.tableDnD.serialize() this returns a string of the form
159+ * <tableID>[]=<rowID1>&<tableID>[]=<rowID2> so that you can send this back to the server. The table must have
160+ * an ID as must all the rows.
161+ *
162+ * Other methods:
163+ *
164+ * $("...").tableDnDUpdate()
165+ * Will update all the matching tables, that is it will reapply the mousedown method to the rows (or handle cells).
166+ * This is useful if you have updated the table rows using Ajax and you want to make the table draggable again.
167+ * The table maintains the original configuration (so you don't have to specify it again).
168+ *
169+ * $("...").tableDnDSerialize()
170+ * Will serialize and return the serialized string as above, but for each of the matching tables--so it can be
171+ * called from anywhere and isn't dependent on the currentTable being set up correctly before calling
172+ *
173+ * Known problems:
174+ * - Auto-scoll has some problems with IE7 (it scrolls even when it shouldn't), work-around: set scrollAmount to 0
175+ *
176+ * Version 0.2: 2008-02-20 First public version
177+ * Version 0.3: 2008-02-07 Added onDragStart option
178+ * Made the scroll amount configurable (default is 5 as before)
179+ * Version 0.4: 2008-03-15 Changed the noDrag/noDrop attributes to nodrag/nodrop classes
180+ * Added onAllowDrop to control dropping
181+ * Fixed a bug which meant that you couldn't set the scroll amount in both directions
182+ * Added serialize method
183+ * Version 0.5: 2008-05-16 Changed so that if you specify a dragHandle class it doesn't make the whole row
184+ * draggable
185+ * Improved the serialize method to use a default (and settable) regular expression.
186+ * Added tableDnDupate() and tableDnDSerialize() to be called when you are outside the table
187+ */
188+jQuery.tableDnD = {
189+ /** Keep hold of the current table being dragged */
190+ currentTable : null,
191+ /** Keep hold of the current drag object if any */
192+ dragObject: null,
193+ /** The current mouse offset */
194+ mouseOffset: null,
195+ /** Remember the old value of Y so that we don't do too much processing */
196+ oldY: 0,
f4782eee 197+
6b57f4ee
ER
198+ /** Actually build the structure */
199+ build: function(options) {
200+ // Set up the defaults if any
f4782eee 201+
6b57f4ee
ER
202+ this.each(function() {
203+ // This is bound to each matching table, set up the defaults and override with user options
204+ this.tableDnDConfig = jQuery.extend({
205+ onDragStyle: null,
206+ onDropStyle: null,
207+ // Add in the default class for whileDragging
208+ onDragClass: "tDnD_whileDrag",
209+ onDrop: null,
210+ onDragStart: null,
211+ scrollAmount: 5,
212+ serializeRegexp: /[^\-]*$/, // The regular expression to use to trim row IDs
213+ serializeParamName: null, // If you want to specify another parameter name instead of the table ID
214+ dragHandle: null // If you give the name of a class here, then only Cells with this class will be draggable
215+ }, options || {});
216+ // Now make the rows draggable
217+ jQuery.tableDnD.makeDraggable(this);
218+ });
f4782eee 219+
6b57f4ee
ER
220+ // Now we need to capture the mouse up and mouse move event
221+ // We can use bind so that we don't interfere with other event handlers
222+ jQuery(document)
223+ .bind('mousemove', jQuery.tableDnD.mousemove)
224+ .bind('mouseup', jQuery.tableDnD.mouseup);
f4782eee 225+
6b57f4ee
ER
226+ // Don't break the chain
227+ return this;
228+ },
f4782eee 229+
6b57f4ee
ER
230+ /** This function makes all the rows on the table draggable apart from those marked as "NoDrag" */
231+ makeDraggable: function(table) {
232+ var config = table.tableDnDConfig;
233+ if (table.tableDnDConfig.dragHandle) {
234+ // We only need to add the event to the specified cells
235+ var cells = jQuery("td."+table.tableDnDConfig.dragHandle, table);
236+ cells.each(function() {
237+ // The cell is bound to "this"
238+ jQuery(this).mousedown(function(ev) {
239+ jQuery.tableDnD.dragObject = this.parentNode;
240+ jQuery.tableDnD.currentTable = table;
241+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
242+ if (config.onDragStart) {
243+ // Call the onDrop method if there is one
244+ config.onDragStart(table, this);
f4782eee 245+ }
6b57f4ee
ER
246+ return false;
247+ });
248+ })
249+ } else {
250+ // For backwards compatibility, we add the event to the whole row
251+ var rows = jQuery("tr", table); // get all the rows as a wrapped set
252+ rows.each(function() {
253+ // Iterate through each row, the row is bound to "this"
254+ var row = jQuery(this);
255+ if (! row.hasClass("nodrag")) {
256+ row.mousedown(function(ev) {
257+ if (ev.target.tagName == "TD") {
258+ jQuery.tableDnD.dragObject = this;
259+ jQuery.tableDnD.currentTable = table;
260+ jQuery.tableDnD.mouseOffset = jQuery.tableDnD.getMouseOffset(this, ev);
261+ if (config.onDragStart) {
262+ // Call the onDrop method if there is one
263+ config.onDragStart(table, this);
264+ }
265+ return false;
266+ }
267+ }).css("cursor", "move"); // Store the tableDnD object
268+ }
269+ });
270+ }
271+ },
f4782eee 272+
6b57f4ee
ER
273+ updateTables: function() {
274+ this.each(function() {
275+ // this is now bound to each matching table
276+ if (this.tableDnDConfig) {
277+ jQuery.tableDnD.makeDraggable(this);
278+ }
279+ })
280+ },
f4782eee 281+
6b57f4ee
ER
282+ /** Get the mouse coordinates from the event (allowing for browser differences) */
283+ mouseCoords: function(ev){
284+ if(ev.pageX || ev.pageY){
285+ return {x:ev.pageX, y:ev.pageY};
f4782eee 286+ }
6b57f4ee
ER
287+ return {
288+ x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
289+ y:ev.clientY + document.body.scrollTop - document.body.clientTop
290+ };
291+ },
f4782eee 292+
6b57f4ee
ER
293+ /** Given a target element and a mouse event, get the mouse offset from that element.
294+ To do this we need the element's position and the mouse position */
295+ getMouseOffset: function(target, ev) {
296+ ev = ev || window.event;
f4782eee 297+
6b57f4ee
ER
298+ var docPos = this.getPosition(target);
299+ var mousePos = this.mouseCoords(ev);
300+ return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
301+ },
f4782eee 302+
6b57f4ee
ER
303+ /** Get the position of an element by going up the DOM tree and adding up all the offsets */
304+ getPosition: function(e){
305+ var left = 0;
306+ var top = 0;
307+ /** Safari fix -- thanks to Luis Chato for this! */
308+ if (e.offsetHeight == 0) {
309+ /** Safari 2 doesn't correctly grab the offsetTop of a table row
310+ this is detailed here:
311+ http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
312+ the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
313+ note that firefox will return a text node as a first child, so designing a more thorough
314+ solution may need to take that into account, for now this seems to work in firefox, safari, ie */
315+ e = e.firstChild; // a table cell
f4782eee
ER
316+ }
317+
6b57f4ee
ER
318+ while (e.offsetParent){
319+ left += e.offsetLeft;
320+ top += e.offsetTop;
321+ e = e.offsetParent;
f4782eee 322+ }
f4782eee 323+
6b57f4ee
ER
324+ left += e.offsetLeft;
325+ top += e.offsetTop;
f4782eee 326+
6b57f4ee
ER
327+ return {x:left, y:top};
328+ },
329+
330+ mousemove: function(ev) {
331+ if (jQuery.tableDnD.dragObject == null) {
332+ return;
f4782eee 333+ }
f4782eee 334+
6b57f4ee
ER
335+ var dragObj = jQuery(jQuery.tableDnD.dragObject);
336+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
337+ var mousePos = jQuery.tableDnD.mouseCoords(ev);
338+ var y = mousePos.y - jQuery.tableDnD.mouseOffset.y;
339+ //auto scroll the window
340+ var yOffset = window.pageYOffset;
341+ if (document.all) {
342+ // Windows version
343+ //yOffset=document.body.scrollTop;
344+ if (typeof document.compatMode != 'undefined' &&
345+ document.compatMode != 'BackCompat') {
346+ yOffset = document.documentElement.scrollTop;
347+ }
348+ else if (typeof document.body != 'undefined') {
349+ yOffset=document.body.scrollTop;
350+ }
f4782eee 351+
6b57f4ee
ER
352+ }
353+
354+ if (mousePos.y-yOffset < config.scrollAmount) {
355+ window.scrollBy(0, -config.scrollAmount);
356+ } else {
357+ var windowHeight = window.innerHeight ? window.innerHeight
358+ : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
359+ if (windowHeight-(mousePos.y-yOffset) < config.scrollAmount) {
360+ window.scrollBy(0, config.scrollAmount);
361+ }
f4782eee 362+ }
f4782eee
ER
363+
364+
6b57f4ee
ER
365+ if (y != jQuery.tableDnD.oldY) {
366+ // work out if we're going up or down...
367+ var movingDown = y > jQuery.tableDnD.oldY;
368+ // update the old value
369+ jQuery.tableDnD.oldY = y;
370+ // update the style to show we're dragging
371+ if (config.onDragClass) {
372+ dragObj.addClass(config.onDragClass);
373+ } else {
374+ dragObj.css(config.onDragStyle);
375+ }
376+ // If we're over a row then move the dragged row to there so that the user sees the
377+ // effect dynamically
378+ var currentRow = jQuery.tableDnD.findDropTargetRow(dragObj, y);
379+ if (currentRow) {
380+ // TODO worry about what happens when there are multiple TBODIES
381+ if (movingDown && jQuery.tableDnD.dragObject != currentRow) {
382+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow.nextSibling);
383+ } else if (! movingDown && jQuery.tableDnD.dragObject != currentRow) {
384+ jQuery.tableDnD.dragObject.parentNode.insertBefore(jQuery.tableDnD.dragObject, currentRow);
385+ }
f4782eee 386+ }
f4782eee 387+ }
f4782eee 388+
6b57f4ee
ER
389+ return false;
390+ },
f4782eee 391+
6b57f4ee
ER
392+ /** We're only worried about the y position really, because we can only move rows up and down */
393+ findDropTargetRow: function(draggedRow, y) {
394+ var rows = jQuery.tableDnD.currentTable.rows;
395+ for (var i=0; i<rows.length; i++) {
396+ var row = rows[i];
397+ var rowY = this.getPosition(row).y;
398+ var rowHeight = parseInt(row.offsetHeight)/2;
399+ if (row.offsetHeight == 0) {
400+ rowY = this.getPosition(row.firstChild).y;
401+ rowHeight = parseInt(row.firstChild.offsetHeight)/2;
f4782eee 402+ }
6b57f4ee
ER
403+ // Because we always have to insert before, we need to offset the height a bit
404+ if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
405+ // that's the row we're over
406+ // If it's the same as the current row, ignore it
407+ if (row == draggedRow) {return null;}
408+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
409+ if (config.onAllowDrop) {
410+ if (config.onAllowDrop(draggedRow, row)) {
411+ return row;
412+ } else {
413+ return null;
414+ }
415+ } else {
416+ // If a row has nodrop class, then don't allow dropping (inspired by John Tarr and Famic)
417+ var nodrop = jQuery(row).hasClass("nodrop");
418+ if (! nodrop) {
419+ return row;
420+ } else {
421+ return null;
422+ }
f4782eee 423+ }
6b57f4ee 424+ return row;
f4782eee
ER
425+ }
426+ }
6b57f4ee
ER
427+ return null;
428+ },
f4782eee 429+
6b57f4ee
ER
430+ mouseup: function(e) {
431+ if (jQuery.tableDnD.currentTable && jQuery.tableDnD.dragObject) {
432+ var droppedRow = jQuery.tableDnD.dragObject;
433+ var config = jQuery.tableDnD.currentTable.tableDnDConfig;
434+ // If we have a dragObject, then we need to release it,
435+ // The row will already have been moved to the right place so we just reset stuff
436+ if (config.onDragClass) {
437+ jQuery(droppedRow).removeClass(config.onDragClass);
438+ } else {
439+ jQuery(droppedRow).css(config.onDropStyle);
440+ }
441+ jQuery.tableDnD.dragObject = null;
442+ if (config.onDrop) {
443+ // Call the onDrop method if there is one
444+ config.onDrop(jQuery.tableDnD.currentTable, droppedRow);
445+ }
446+ jQuery.tableDnD.currentTable = null; // let go of the table too
f4782eee 447+ }
6b57f4ee 448+ },
f4782eee 449+
6b57f4ee
ER
450+ serialize: function() {
451+ if (jQuery.tableDnD.currentTable) {
452+ return jQuery.tableDnD.serializeTable(jQuery.tableDnD.currentTable);
f4782eee 453+ } else {
6b57f4ee 454+ return "Error: No Table id set, you need to set an id on your table and every row";
f4782eee 455+ }
6b57f4ee 456+ },
f4782eee 457+
6b57f4ee
ER
458+ serializeTable: function(table) {
459+ var result = "";
460+ var tableId = table.id;
461+ var rows = table.rows;
462+ for (var i=0; i<rows.length; i++) {
463+ if (result.length > 0) result += "&";
464+ var rowId = rows[i].id;
465+ if (rowId && rowId && table.tableDnDConfig && table.tableDnDConfig.serializeRegexp) {
466+ rowId = rowId.match(table.tableDnDConfig.serializeRegexp)[0];
467+ }
f4782eee 468+
6b57f4ee 469+ result += tableId + '[]=' + rowId;
f4782eee 470+ }
6b57f4ee
ER
471+ return result;
472+ },
f4782eee 473+
6b57f4ee
ER
474+ serializeTables: function() {
475+ var result = "";
476+ this.each(function() {
477+ // this is now bound to each matching table
478+ result += jQuery.tableDnD.serializeTable(this);
479+ });
480+ return result;
f4782eee
ER
481+ }
482+
6b57f4ee
ER
483+}
484+
485+jQuery.fn.extend(
486+ {
487+ tableDnD : jQuery.tableDnD.build,
488+ tableDnDUpdate : jQuery.tableDnD.updateTables,
489+ tableDnDSerialize: jQuery.tableDnD.serializeTables
490+ }
491+);
492\ No newline at end of file
52eb5eb6
ER
493--- eventum-2.3.2/htdocs/list.php~ 2012-03-09 18:19:56.000000000 +0200
494+++ eventum-2.3.2/htdocs/list.php 2012-03-09 18:32:43.998284397 +0200
b4c9ce19
ER
495@@ -67,6 +67,11 @@
496 }
6b57f4ee
ER
497 }
498
499+@$reorder_usr_id = $_REQUEST["reorder_user"];
500+@$reorder_issue_id = $_REQUEST["reorder_source"];
501+@$reorder_neworder = $_REQUEST["reorder_neworder"];
502+Issue::reorderUserIssues($reorder_usr_id, $reorder_issue_id, $reorder_neworder);
503+
52eb5eb6
ER
504 if (!empty($_REQUEST['nosave'])) {
505 $options = Search::saveSearchParams(false);
506 } else {
b4c9ce19 507@@ -92,6 +97,24 @@
6b57f4ee
ER
508 }
509 $assign_options += $users;
510
1f9de427 511+// get the isu_order (assigned users) ordering user
6b57f4ee
ER
512+if (!empty($options["users"])) {
513+ if ($options["users"] == -2) {
514+ $isu_order_user = $usr_id;
515+ } else
516+ if ($options["users"] > 0) {
517+ $isu_order_user = $options["users"];
518+ } else {
519+ unset($isu_order_user);
520+ }
521+} else {
522+ unset($isu_order_user);
523+}
1f9de427
ER
524+
525+if (isset($isu_order_user)) {
526+ $tpl->assign("isu_order_user", $isu_order_user);
527+}
f4782eee 528+
b4c9ce19 529 $list = Search::getListing($prj_id, $options, $pagerRow, $rows);
6b57f4ee
ER
530 $tpl->assign("list", $list["list"]);
531 $tpl->assign("list_info", $list["info"]);
532--- eventum-2.2/lib/eventum/class.display_column.php 2009-09-14 18:07:55.000000000 +0300
533+++ eventum-2.2-order/lib/eventum/class.display_column.php 2009-10-12 22:10:36.429185594 +0300
534@@ -230,7 +230,10 @@
535 ),
536 "iss_expected_resolution_date" => array(
537 "title" => ev_gettext("Expected Resolution Date")
538- )
539+ ),
540+ "isu_order" => array(
541+ "title" => ev_gettext("Order")
542+ ),
543 )
544 );
545 return $columns[$page];
858c6f2a
ER
546--- eventum-2.3.1/lib/eventum/class.issue.php~ 2011-09-15 09:36:55.000000000 +0300
547+++ eventum-2.3.1/lib/eventum/class.issue.php 2011-09-15 09:42:02.844032474 +0300
548@@ -1374,6 +1374,7 @@
6b57f4ee 549 return -1;
858c6f2a
ER
550 }
551
552+ self::moveOrderForAllUsers($issue_id, 1000);
553 $prj_id = self::getProjectID($issue_id);
6b57f4ee 554
858c6f2a 555 // record the change
b738b023 556@@ -1800,16 +1801,33 @@
6b57f4ee
ER
557 {
558 $issue_id = Misc::escapeInteger($issue_id);
559 $assignee_usr_id = Misc::escapeInteger($assignee_usr_id);
560+ $order = 1;
561+ // move all orders down to free "order space" for this new association
858c6f2a 562+ $stmt = "UPDATE
6b57f4ee 563+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
f4782eee 564+ SET
6b57f4ee 565+ isu_order = isu_order + 1
f4782eee 566+ WHERE
6b57f4ee
ER
567+ isu_usr_id = $assignee_usr_id AND
568+ isu_order >= $order";
f4782eee
ER
569+ $res = DB_Helper::getInstance()->query($stmt);
570+ if (PEAR::isError($res)) {
571+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
572+ return -1;
573+ }
6b57f4ee
ER
574+ // insert the new association
575 $stmt = "INSERT INTO
576 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
577 (
578 isu_iss_id,
579 isu_usr_id,
580- isu_assigned_date
581+ isu_assigned_date,
582+ isu_order
583 ) VALUES (
584 $issue_id,
585 $assignee_usr_id,
586- '" . Date_Helper::getCurrentDateGMT() . "'
587+ '" . Date_Helper::getCurrentDateGMT() . "',
588+ $order
589 )";
590 $res = DB_Helper::getInstance()->query($stmt);
591 if (PEAR::isError($res)) {
b738b023 592@@ -1824,6 +1842,78 @@
6b57f4ee
ER
593 }
594 }
595
f4782eee 596+ /**
6b57f4ee
ER
597+ * Method used to get the order list to be rearranged
598+ *
599+ * @access private
600+ * @param string $issue_id The issue ID or a comma seperated list of IDs already prepared for giving to mysql
601+ * @param string $usr_id The user to remove. When not specified, all users are taken as to be removed for that issue
602+ * @return mixed delete order list to be rearranged. Used as a parameter to the method of rearranging the order.
f4782eee 603+ */
6b57f4ee 604+ function getDeleteUserAssociationOrderList($issue_id, $usr_id = "")
f4782eee 605+ {
6b57f4ee
ER
606+ // find all affected associantion orders
607+ $stmt = "SELECT isu_usr_id, isu_order FROM
608+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
609+ WHERE
610+ isu_iss_id IN ($issue_id)";
611+ if (!empty($usr_id)) {
612+ $stmt.= " AND isu_usr_id IN ($usr_id)";
f4782eee 613+ }
6b57f4ee
ER
614+ $stmt.= "ORDER BY isu_order";
615+ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC);
f4782eee
ER
616+ if (PEAR::isError($res)) {
617+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
6b57f4ee 618+ return -1;
f4782eee 619+ } else {
6b57f4ee
ER
620+ $deleted_orders = array();
621+ foreach ($res as $row) {
622+ if (empty($deleted_orders[$row['isu_usr_id']])) {
623+ $deleted_orders[$row['isu_usr_id']] = array();
624+ }
625+ $deleted_orders[$row['isu_usr_id']] [] = $row['isu_order'];
626+ }
627+ return $deleted_orders;
f4782eee 628+ }
f4782eee
ER
629+ }
630+
f4782eee 631+ /**
f4782eee 632+ *
6b57f4ee
ER
633+ * Method used to rearrange order list in the db according to known deleted records
634+ *
635+ * @access private
636+ * @param mixed deleteorder list
637+ * @return void
f4782eee 638+ */
6b57f4ee 639+ function rearrangeDeleteUserAssociationOrderList($delete_order_list)
f4782eee 640+ {
6b57f4ee
ER
641+ if (empty($delete_order_list) || (!is_array($delete_order_list))) {
642+ return -1;
f4782eee 643+ }
6b57f4ee
ER
644+ foreach ($delete_order_list as $isu_usr_id => $orders) {
645+ for ($i = 0; $i < count($orders); $i++) { // traverse all deleted orders
646+ // move the orders after them up to take the "order space" of the deleted records
647+ $stmt = "UPDATE
648+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
649+ SET
650+ isu_order = isu_order - " . ($i+1) . "
651+ WHERE
652+ isu_usr_id = $isu_usr_id AND
653+ isu_order > " . $orders[$i];
654+ if ($i < count($orders) - 1) {
655+ $stmt.= " AND
656+ isu_order < " . $orders[$i+1];
657+ }
658+ $res = DB_Helper::getInstance()->query($stmt);
659+ if (PEAR::isError($res)) {
660+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
661+ return -1;
662+ }
f4782eee 663+ }
f4782eee 664+ }
6b57f4ee 665+ return 1;
f4782eee 666+ }
6b57f4ee
ER
667+
668
669 /**
670 * Method used to delete all user assignments for a specific issue.
b738b023 671@@ -1839,6 +1929,7 @@
6b57f4ee
ER
672 if (is_array($issue_id)) {
673 $issue_id = implode(", ", $issue_id);
674 }
675+ $deleted_order_list = self::getDeleteUserAssociationOrderList($issue_id);
676 $stmt = "DELETE FROM
677 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
678 WHERE
b738b023 679@@ -1869,6 +1960,7 @@
6b57f4ee
ER
680 {
681 $issue_id = Misc::escapeInteger($issue_id);
682 $usr_id = Misc::escapeInteger($usr_id);
683+ $delete_order_list = self::getDeleteUserAssociationOrderList($issue_id, $usr_id);
684 $stmt = "DELETE FROM
685 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
686 WHERE
858c6f2a
ER
687@@ -2020,6 +2021,7 @@
688 History::add($issue_id, Auth::getUserID(), History::getTypeID('user_unassociated'),
689 User::getFullName($usr_id) . ' removed from issue by ' . User::getFullName(Auth::getUserID()));
6b57f4ee 690 }
858c6f2a
ER
691+ self::rearrangeDeleteUserAssociationOrderList($delete_order_list);
692 return 1;
6b57f4ee 693 }
858c6f2a 694
b738b023 695@@ -3253,6 +3352,8 @@
6b57f4ee
ER
696 $ids = implode(", ", $ids);
697 $stmt = "SELECT
698 isu_iss_id,
699+ isu_order,
700+ isu_usr_id,
701 usr_full_name
702 FROM
703 " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user,
b738b023 704@@ -3264,6 +3365,7 @@
6b57f4ee
ER
705 if (PEAR::isError($res)) {
706 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
707 } else {
708+ // gather names of the users assigned to each issue
709 $t = array();
710 for ($i = 0; $i < count($res); $i++) {
711 if (!empty($t[$res[$i]['isu_iss_id']])) {
b738b023 712@@ -3272,9 +3374,18 @@
6b57f4ee
ER
713 $t[$res[$i]['isu_iss_id']] = $res[$i]['usr_full_name'];
714 }
715 }
716+ // gather orders
717+ $o = array();
718+ for ($i = 0; $i < count($res); $i++) {
719+ if (empty($o[$res[$i]['isu_iss_id']])) {
720+ $o[$res[$i]['isu_iss_id']] = array();
721+ }
722+ $o[$res[$i]['isu_iss_id']][$res[$i]['isu_usr_id']] = $res[$i]['isu_order'];
723+ }
724 // now populate the $result variable again
725 for ($i = 0; $i < count($result); $i++) {
726 @$result[$i]['assigned_users'] = $t[$result[$i]['iss_id']];
727+ @$result[$i]['assigned_users_order'] = $o[$result[$i]['iss_id']];
728 }
729 }
730 }
b738b023 731@@ -4247,6 +4358,7 @@
6b57f4ee
ER
732 Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
733 return -1;
734 }
735+ self::moveOrderForAllUsers($issue_id, 1);
736 }
737
738
b738b023 739@@ -4346,4 +4458,120 @@
6b57f4ee
ER
740 History::add($issue_id, Auth::getUserID(), History::getTypeID('user_associated'),
741 "Issue assignment to changed (" . History::formatChanges(join(', ', $old_assignee_names), join(', ', $assignee_names)) . ") by " . User::getFullName(Auth::getUserID()));
742 }
f4782eee
ER
743+
744+ /**
745+ * Reorders user's issues as requested by user
746+ * @access public
747+ * @param $usr_id User to be reordered
748+ * @param $issue_id Issue or array of issues to be moved
749+ * @param $neworder The new order of the issues
750+ * @return void
751+ */
752+ function reorderUserIssues($usr_id, $issue_id, $neworder)
753+ {
754+ if (!isset($usr_id) || !isset($issue_id) || !isset($neworder)) {
755+ return false;
756+ }
757+ if (!is_numeric($usr_id) || !is_numeric($neworder)) {
758+ return false;
759+ }
760+ $usr_id = Misc::escapeInteger($usr_id);
761+ $issue_id = Misc::escapeInteger($issue_id);
762+ $neworder = Misc::escapeInteger($neworder);
763+ if (is_array($issue_id)) {
764+ $issue_count = count($issue_id);
765+ $issue_id_str = implode(", ", $issue_id);
766+ } else {
767+ $issue_count = 1;
768+ $issue_id_str = $issue_id;
769+ $issue_id = array($issue_id);
770+ }
771+ // do a nasty pretending to be deleting stuff so that reordering happens as if these elements were deleted
772+ $orderlist = self::getDeleteUserAssociationOrderList($issue_id_str, $usr_id);
773+ self::rearrangeDeleteUserAssociationOrderList($orderlist);
774+ // move down the orders to free the "order space" needed
775+ $stmt = "UPDATE
776+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
777+ SET
778+ isu_order = isu_order + $issue_count
779+ WHERE
780+ isu_usr_id = $usr_id AND
781+ isu_order >= $neworder";
782+ $res = DB_Helper::getInstance()->query($stmt);
783+ if (PEAR::isError($res)) {
784+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
785+ return -1;
786+ }
787+ //update the order for the issues being moved
788+ $i = 0;
789+ foreach ($issue_id as $iss_id) {
790+ $stmt = "UPDATE
791+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
792+ SET
793+ isu_order = " . ($neworder + $i) . "
794+ WHERE
795+ isu_usr_id = $usr_id AND
796+ isu_iss_id = $iss_id";
797+ $res = DB_Helper::getInstance()->query($stmt);
798+ if (PEAR::isError($res)) {
799+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
800+ return -1;
801+ }
802+ $i++;
803+ }
804+ }
805+
806+
807+ /**
808+ * Get users issue order list
809+ * @access public
810+ * @param $user_id User
811+ * @param $order_list Order of the issues
812+ * @return void
813+ */
814+ function getIssueOrderByUser($usr_id) {
815+
816+ if (!is_numeric($usr_id)) {
817+ return false;
818+ }
819+
820+ $stmt = "SELECT
821+ isu_iss_id, isu_order
822+ FROM
823+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
824+ WHERE
825+ isu_usr_id = " . $usr_id ;
826+
827+ $order_list = array();
828+
829+ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC);
830+
831+ if (PEAR::isError($res)) {
832+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
833+ return array();
834+ } else {
835+ foreach ($res as $row) {
836+ $order_list[$row["isu_iss_id"]] = $row["isu_order"];
837+ }
838+ }
839+ return $order_list;
840+ }
841+
842+ function moveOrderForAllUsers($issue_id, $neworder)
843+ {
844+ // Move the issue to the top priority for the ppl it's assigned to
845+ $stmt = "SELECT isu_usr_id FROM
846+ " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user
847+ WHERE
848+ isu_iss_id = " . Misc::escapeInteger($issue_id);
849+ $res = DB_Helper::getInstance()->getAll($stmt, DB_FETCHMODE_ASSOC);
850+ if (PEAR::isError($res)) {
851+ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__);
852+ return -1;
853+ }
854+ foreach ($res as $row) {
855+ self::reorderUserIssues($row["isu_usr_id"], $issue_id, $neworder);
856+ }
857+ }
858+
6b57f4ee 859 }
b4c9ce19
ER
860--- eventum-2.3.1/lib/eventum/class.search.php~ 2011-04-20 17:22:15.000000000 +0300
861+++ eventum-2.3.1/lib/eventum/class.search.php 2011-04-20 17:44:34.498519260 +0300
862@@ -63,6 +63,12 @@
863 {
864 $sort_by = self::getParam('sort_by');
865 $sort_order = self::getParam('sort_order');
866+ $users = self::getParam('users');
867+ if (empty($users) && $sort_by === 'isu_order') {
868+ // Sorting by isu_order is impossible when no user specified
869+ unset($sort_by);
870+ unset($sort_order);
871+ }
872 $rows = self::getParam('rows');
873 $hide_closed = self::getParam('hide_closed');
874 if ($hide_closed === '') {
875@@ -174,6 +174,7 @@
876 "iss_expected_resolution_date" => "desc",
877 "pre_title" => "asc",
878 "assigned" => "asc",
879+ "isu_order" => "desc",
880 );
881
882 foreach ($custom_fields as $fld_id => $fld_name) {
858c6f2a
ER
883--- eventum-2.3.1/templates/header.tpl.html~ 2011-09-15 09:36:55.000000000 +0300
884+++ eventum-2.3.1/templates/header.tpl.html 2011-09-15 09:43:49.318473817 +0300
1f9de427 885@@ -18,6 +18,7 @@
f4782eee
ER
886 <script type="text/javascript" src="{$rel_url}js/jquery/form.js?c=9984"></script>
887 <script type="text/javascript" src="{$rel_url}js/jquery/blockui.js?c=eb13"></script>
888 <script type="text/javascript" src="{$rel_url}js/jquery/ui.datepicker.js?c=a911"></script>
889+<script type="text/javascript" src="{$rel_url}js/jquery/jquery.tablednd.js"></script>
858c6f2a 890 <script type="text/javascript" src="{$rel_url}js/validation.js?c=ad33"></script>
1f9de427 891 <script type="text/javascript" src="{$rel_url}js/browserSniffer.js?c=c046"></script>
858c6f2a 892 <script type="text/javascript" src="{$rel_url}js/global.js?c=50d6"></script>
f4782eee
ER
893--- eventum-2.2/templates/list.tpl.html 2009-09-14 18:07:55.000000000 +0300
894+++ eventum-2.2-order/templates/list.tpl.html 2009-10-12 22:10:36.439185157 +0300
895@@ -92,6 +92,28 @@
896 f.target = '_popup';
897 f.submit();
898 }
899+function reorderBulk(order_user, neworder)
900+{
901+ url = page_url + "?";
902+ url += "reorder_user=" + order_user;
903+
904+ items = document.getElementsByName("item[]");
905+ checkedcount = 0;
906+ for (var i = 0; i < items.length; i++) {
907+ if (items[i].checked) {
908+ url += "&reorder_source[" + checkedcount + "]=" + items[i].value;
909+ checkedcount++;
910+ }
911+ }
912+ if (checkedcount == 0) {
913+ alert('{/literal}{t escape=js}Please choose which issues to move to the new place.{/t}{literal}');
914+ return false;
915+ }
916+
917+ url += "&reorder_neworder=" + neworder;
918+
919+ window.location.href = url;
920+}
921 function hideClosed(f)
922 {
923 if (f.hide_closed.checked) {
924@@ -153,6 +175,13 @@
925 f.go.disabled = true;
926 }
927 }
928+function updateCustomFields(issue_id)
929+{
930+ var features = 'width=560,height=460,top=30,left=30,resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no';
931+ var customWin = window.open('custom_fields.php?issue_id=' + issue_id, '_custom_fields', features);
932+ customWin.focus();
933+ return false;
934+}
935 //-->
936 </script>
937 {/literal}
938@@ -169,11 +198,11 @@
939 <input type="hidden" name="cat" value="bulk_update">
940 <tr>
941 <td>
942- <table bgcolor="#FFFFFF" width="100%" cellspacing="1" cellpadding="2" border="0">
943- <tr>
944+ <table bgcolor="#FFFFFF" width="100%" cellspacing="1" cellpadding="2" border="0" id="issue_list_table">
945+ <tr class="nodrag">
946 <td colspan="{$col_count}" class="default">
947 <table width="100%" cellspacing="0" cellpadding="0" border="0">
948- <tr>
949+ <tr class="nodrag">
950 <td class="default">
951 <b>{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})</b>
952 {include file="help_link.tpl.html" topic="list"}
953@@ -193,7 +222,7 @@
954 </table>
955 </td>
956 </tr>
957- <tr bgcolor="{$cell_color}">
958+ <tr bgcolor="{$cell_color}" class="nodrag">
959 {if $current_role > $roles.developer}
960 <td width="1%">
961 <input type="button" value="{t}All{/t}" class="shortcut" onClick="javascript:toggleSelectAll(this.form, 'item[]');toggleBulkUpdate();">
962@@ -208,7 +237,7 @@
963 {if $sorting.images[$fld_name_id] != ""}<a title="{t}sort by{/t} {$fld_title|escape:"html"}" href="{$sorting.links[$fld_name_id]}" class="white_link"><img border="0" src="{$sorting.images[$fld_name_id]}"></a>{/if}
964 </td>
965 {/foreach}
966- {else}
967+ {elseif $field_name != 'isu_order' || $isu_order_user}
968 <td align="{$column.align|default:'center'}" class="default_white" nowrap {if $column.width != ''}width="{$column.width}"{/if}>
969 {if $field_name == 'iss_summary'}
970 <table cellspacing="0" cellpadding="1" width="100%">
098cbb72 971@@ -268,8 +268,9 @@
f4782eee
ER
972 {/if}
973 {/foreach}
974 </tr>
975+ <tbody>
976 {section name="i" loop=$list}
977- <tr {if $current_role >= $roles.developer AND $list[i].iqu_status > 0}style="text-decoration: line-through;"{/if}>
978+ <tr {if $current_role >= $roles.developer AND $list[i].iqu_status > 0}style="text-decoration: line-through;"{/if} id="{$list[i].iss_id}" {if !$list[i].assigned_users_order[$current_user_id]}class="nodrag"{/if}>
979 {if $current_role > $roles.developer}
980 <td bgcolor="{$list[i].status_color}" width="1%" class="default" align="center"><input type="checkbox" name="item[]" value="{$list[i].iss_id}" onchange="toggleBulkUpdate();"></td>
981 {/if}
098cbb72
ER
982@@ -280,8 +281,8 @@
983 {$fld_value|formatCustomValue:$fld_id:$list[i].iss_id}
f4782eee
ER
984 </td>
985 {/foreach}
986- {else}
987- <td bgcolor="{$list[i].status_color}" align="{$column.align|default:'center'}" class="default">
988+ {elseif $field_name != 'isu_order' || $isu_order_user}
989+ <td bgcolor="{$list[i].status_color}" align="{$column.align|default:'center'}" class="default{if $field_name == 'isu_order'} dragHandle{/if}">
990 {if $field_name == 'iss_id'}
991 <a href="view.php?id={$list[i].iss_id}" class="link" title="{t}view issue details{/t}">{$list[i].iss_id}</a>
992 {elseif $field_name == 'pri_rank'}
f4782eee
ER
993@@ -288,6 +318,8 @@
994 {if $list[i].iss_private == 1}
995 <b>[Private]</b>
996 {/if}
997+ {elseif $field_name == 'isu_order'}
998+ {if $options.sort_by == "isu_order" and $current_user_id == $isu_order_user}&nbsp;{/if}
999 {/if}
1000 </td>
1001 {/if}
1002@@ -300,10 +332,11 @@
1003 </td>
1004 </tr>
1005 {/section}
1006- <tr bgcolor="{$cell_color}">
1007+ </tbody>
1008+ <tr bgcolor="{$cell_color}" class="nodrag">
1009 <td colspan="{$col_count}">
1010 <table width="100%" cellspacing="0" cellpadding="0">
1011- <tr>
1012+ <tr class="nodrag">
1013 <td width="30%" nowrap>
1014 {if $current_role > $roles.developer}
1015 <input type="button" value="{t}All{/t}" class="shortcut" onClick="javascript:toggleSelectAll(this.form, 'item[]');">
1016@@ -355,6 +388,35 @@
1017 </form>
1018 </table>
1019 <br />
1020-
1021+<script type="text/javascript">
1022+{*
1023+ * Order issues by drag and drop:
1024+ * only if sorted by order and viewing your own issues
1025+ *}
1026+{if $options.sort_by == "isu_order" and $current_user_id == $isu_order_user}
1027+{literal}
1028+var before = ''; // make it global variable
1029+$('#issue_list_table').tableDnD({
1030+ onDragClass: "tDnD_whileDrag",
1031+ onDragStart: function(table, row) {
1032+ before = $.tableDnD.serialize('id');
1033+ },
1034+ onDrop: function(table, row) {
1035+ $.post("/ajax/order.php", {before: before, after: $.tableDnD.serialize('id')}, function(data) {
1036+ if (data.length > 0) {
1037+ alert(data);
1038+ }
1039+ }, "text");
1040+ },
1041+ dragHandle: "dragHandle"
1042+});
1043+$("#issue_list_table tr").hover(function() {
1044+ $('#' + this.id + ' .dragHandle').addClass('showDragHandle');
1045+}, function() {
1046+ $('#' + this.id + ' .dragHandle').removeClass('showDragHandle');
1047+});
1048+{/literal}
1049+{/if}
1050+</script>
1051 {include file="app_info.tpl.html"}
1052 {include file="footer.tpl.html"}
This page took 0.361613 seconds and 4 git commands to generate.