diff options
-rw-r--r-- | modules/organize/controllers/organize.php | 157 | ||||
-rw-r--r-- | modules/organize/helpers/organize_task.php | 71 | ||||
-rw-r--r-- | modules/organize/js/organize.js | 142 | ||||
-rw-r--r-- | modules/organize/views/organize.html.php | 5 | ||||
-rw-r--r-- | modules/organize/views/organize_button_pane.html.php | 11 |
5 files changed, 219 insertions, 167 deletions
diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 62a23444..a46b3a02 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -84,6 +84,35 @@ class Organize_Controller extends Controller { return $v->__toString(); } + function startTask($operation, $id) { + access::verify_csrf(); + $items = $this->input->post("item"); + + $item = ORM::factory("item", $id); + + $definition = $this->_getOperationDefinition($item, $operation); + + $task_def = Task_Definition::factory() + ->callback("organize_task::run") + ->description($definition["description"]) + ->name($definition["name"]); + $task = task::create($task_def, array("items" => $items, "position" => 0, "target" => $id, + "type" => $definition["type"], + "batch" => ceil(count($items) * .1))); + // @todo If there is only one item then call task_run($task->id); Maybe even change js so + // we can call finish as well. + batch::start(); + print json_encode(array("result" => "started", + "runningMsg" => $definition["runningMsg"], + "pauseMsg" => "<div class=\"gWarning\">{$definition['pauseMsg']}</div>", + "resumeMsg" => "<div class=\"gWarning\">{$definition['resumeMsg']}</div>", + "task" => array("id" => $task->id, + "percent_complete" => $task->percent_complete, + "type" => $task->get("type"), + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); + } function runTask($task_id) { access::verify_csrf(); @@ -91,12 +120,13 @@ class Organize_Controller extends Controller { $task = task::run($task_id); print json_encode(array("result" => $task->done ? $task->state : "in_progress", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); + "task" => array("id" => $task->id, + "percent_complete" => $task->percent_complete, + "type" => $task->get("type"), + "reload" => $task->get("refresh"), + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); } function finishTask($task_id) { @@ -107,9 +137,11 @@ class Organize_Controller extends Controller { if ($task->done) { $item = ORM::factory("item", (int)$task->get("target")); $type = $task->get("type"); - if ($type == "moveTo") { + switch ($type) { + case "move": $task->status = t("Move to '%album' completed", array("album" => $item->title)); - } else if ($type == "rearrange") { + break; + case "rearrange": try { $item->sort_column = "weight"; $item->save(); @@ -118,6 +150,11 @@ class Organize_Controller extends Controller { $task->state = "error"; $task->status = $e->getMessage(); } + break; + case "rotateCcw": + case "rotateCw": + $task->status = t("Rotation completed"); + break; } $task->save(); } @@ -141,10 +178,16 @@ class Organize_Controller extends Controller { $task->done = 1; $task->state = "cancelled"; $type = $task->get("type"); - if ($type == "moveTo") { + switch ($type) { + case "move": $task->status = t("Move to album was cancelled prior to completion"); - } else if ($type == "rearrange") { - $task->status = t("Rearrange album was cancelled prior to completion"); + break; + case "rearrange": + $task->status = t("Rearrange album was cancelled prior to completion"); + case "rotateCcw": + case "rotateCw": + $task->status = t("Rotation was cancelled prior to completion"); + break; } $task->save(); } @@ -159,51 +202,51 @@ class Organize_Controller extends Controller { "done" => $task->done))); } - function moveStart($id) { - access::verify_csrf(); - $items = $this->input->post("item"); - - $item = ORM::factory("item", $id); - - $task_def = Task_Definition::factory() - ->callback("organize_task::move") - ->description(t("Move albums and photos to '%name'", array("name" => $item->title))) - ->name(t("Move to '%name'", array("name" => $item->title))); - $task = task::create($task_def, array("items" => $items, "position" => 0, "target" => $id, - "type" => "moveTo", - "batch" => ceil(count($items) * .1))); - - batch::start(); - print json_encode(array("result" => "started", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); - } - - function rearrangeStart($id) { - access::verify_csrf(); - $items = $this->input->post("item"); - - $item = ORM::factory("item", $id); - - $task_def = Task_Definition::factory() - ->callback("organize_task::rearrange") - ->description(t("Rearrange the order of albums and photos")) - ->name(t("Rearrange: %name", array("name" => $item->title))); - $task = task::create($task_def, array("items" => $items, "position" => 0, "target" => $id, - "type" => "rearrange", - "batch" => ceil(count($items) * .1))); - - batch::start(); - print json_encode(array("result" => "started", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); + private function _getOperationDefinition($item, $operation) { + switch ($operation) { + case "move": + return array("description" => + t("Move albums and photos to '%name'", array("name" => $item->title)), + "name" => t("Move to '%name'", array("name" => $item->title)), + "type" => "move", + "runningMsg" => t("Move in progress"), + "pauseMsg" => t("The move operation was paused"), + "resumeMsg" => t("The move operation was resumed")); + break; + case "rearrange": + return array("description" => t("Rearrange the order of albums and photos"), + "name" => t("Rearrange: %name", array("name" => $item->title)), + "type" => "rearrange", + "runningMsg" => t("Rearrange in progress"), + "pauseMsg" => t("The rearrange operation was paused"), + "resumeMsg" => t("The rearrange operation was resumed")); + break; + case "rotateCcw": + return array("description" => t("Rotate the selected photos counter clockwise"), + "name" => t("Rotate images in %name", array("name" => $item->title)), + "type" => "rotateCcw", + "runningMsg" => t("Rotate Counter Clockwise in progress"), + "pauseMsg" => t("The rotate operation was paused"), + "resumeMsg" => t("The rotate operation was resumed")); + break; + case "rotateCw": + return array("description" => t("Rotate the selected photos clockwise"), + "name" => t("Rotate images in %name", array("name" => $item->title)), + "type" => "rotateCw", + "runningMsg" => t("Rotate Clockwise in progress"), + "pauseMsg" => t("The rotate operation was paused"), + "resumeMsg" => t("The rotate operation was resumed")); + break; + case "delete": + return array("description" => t("Delete selected photos and albums"), + "name" => t("`Delete images in %name", array("name" => $item->title)), + "type" => "delete", + "runningMsg" => t("Delete images in progress"), + "pauseMsg" => t("The delete operation was paused"), + "resumeMsg" => t("The delete operation was resumed")); + break; + default: + throw new Exception("Operation '$operation' is not implmented"); + } } }
\ No newline at end of file diff --git a/modules/organize/helpers/organize_task.php b/modules/organize/helpers/organize_task.php index bb6321fa..1344796a 100644 --- a/modules/organize/helpers/organize_task.php +++ b/modules/organize/helpers/organize_task.php @@ -23,17 +23,37 @@ class organize_task_Core { return array(); } - static function rearrange($task) { + static function run($task) { $context = unserialize($task->context); + $taskType = $context["type"]; try { + $target = ORM::factory("item", $context["target"]); $total = count($context["items"]); $stop = min($total - $context["position"], $context["batch"]); + $context["refresh"] = null; for ($offset = 0; $offset < $stop; $offset++) { $current_id = $context["position"] + $offset; $id = $context["items"][$current_id]; - Database::instance() - ->query("Update {items} set weight = {$context["position"]} where id=$id;"); + switch ($taskType) { + case "move": + $source = ORM::factory("item", $id); + core::move_item($source, $target); + break; + case "rearrange": + Database::instance() + ->query("Update {items} set weight = {$context["position"]} where id=$id;"); + break; + case "rotateCcw": + case "rotateCw": + $item = ORM::factory("item", $id); + if ($item->is_photo()) { + $context["refresh"] = self:: _do_rotation($item, $taskType == "rotateCcw" ? -90 : 90); + } + break; + default: + throw new Exception("Task '$taskType' is not implmented"); + } } $context["position"] += $stop; $task->state = "success"; @@ -49,29 +69,30 @@ class organize_task_Core { $task->done = $context["position"] == $total || $task->state == "error"; } - static function move($task) { - $context = unserialize($task->context); + private static function _do_rotation($item, $degrees) { + // This code is copied from Quick_Controller::rotate + graphics::rotate($item->file_path(), $item->file_path(), array("degrees" => $degrees)); - try { - $target = ORM::factory("item", $context["target"]); - $total = count($context["items"]); - $stop = min($total - $context["position"], $context["batch"]); - for ($offset = 0; $offset < $stop; $offset++) { - $current_id = $context["position"] + $offset; - $source = ORM::factory("item", $context["items"][$current_id]); - core::move_item($source, $target); - } - $context["position"] += $stop; - $task->state = "success"; - } catch(Exception $e) { - $task->status = $e->getMessage(); - $task->state = "error"; - $task->save(); - throw $e; + list($item->width, $item->height) = getimagesize($item->file_path()); + $item->resize_dirty= 1; + $item->thumb_dirty= 1; + $item->save(); + + graphics::generate($item); + + $parent = $item->parent(); + if ($parent->album_cover_item_id == $item->id) { + copy($item->thumb_path(), $parent->thumb_path()); + $parent->thumb_width = $item->thumb_width; + $parent->thumb_height = $item->thumb_height; + $parent->save(); } - $task->context = serialize($context); - $total = count($context["items"]); - $task->percent_complete = $context["position"] / (float)$total * 100; - $task->done = $context["position"] == $total || $task->state == "error"; + list ($height, $width) = $item->adjust_thumb_size(90); + $margin_top = (90 - $height) / 20; + + return array("src" => $item->thumb_url() . "?rnd=" . rand(), + "id" => $item->id, "marginTop" => "{$margin_top}em", + "width" => $width, "height" => $height); + } }
\ No newline at end of file diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 66ca0b33..e11c32c4 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -17,7 +17,6 @@ var draggable = { revert: true, zindex: 2000, helper: function(event, ui) { - console.dir(ui); $("#gMicroThumbPanel").append("<div id=\"gDragHelper\"><ul></ul></div>"); var beginTop = event.pageY; var beginLeft = event.pageX; @@ -95,9 +94,9 @@ var thumbDroppable = { $.ajax({ data: newOrder, dataType: "json", - success: startRearrangeCallback, + success: operationCallback, type: "POST", - url: get_url("organize/rearrangeStart", {item_id: item_id}) + url: get_url("organize/startTask/rearrange", {item_id: item_id}) }); } }; @@ -109,16 +108,15 @@ var treeDroppable = { hoverClass: "gBranchDroppable", drop: function(event, ui) { $("#gDragHelper").hide(); - var moveItems = ""; var targetItemId = $(this).attr("ref"); if ($(this).hasClass("gBranchSelected")) { $("#gOrganizeStatus").empty().append(INVALID_DROP_TARGET); ui.draggable.trigger("stop", event); return false; } + var postData = serializeItemIds("#gDragHelper li"); var okToMove = true; $("#gDragHelper li").each(function(i) { - moveItems += "&item[]=" + $(this).attr("ref"); okToMove &= targetItemId != $(this).attr("ref"); }); if (!okToMove) { @@ -130,35 +128,26 @@ var treeDroppable = { $("#thumb_" + $(this).attr("ref")).remove(); }); $.ajax({ - data: moveItems, + data: postData, dataType: "json", - success: startMoveCallback, + success: operationCallback, type: "POST", - url: get_url("organize/moveStart", {item_id: targetItemId}) + url: get_url("organize/startTask/move", {item_id: targetItemId}) }); } }; // Selectable var selectable = { - count: 0, filter: ".gMicroThumbContainer", selected: function(event, ui) { - /* - * Count the number of selected items if it is greater than 1, - * then click won't be called so we need to remove the gSelecting - * class in the stop event. - */ - var count = $("#gMicroThumbGrid").selectable("option", "count") + 1; - $("#gMicroThumbGrid").selectable("option", "count", count); $(ui.selected).addClass("gSelecting"); + setDrawerButtonState(); + }, + unselected: function(event, ui) { + setDrawerButtonState(); }, stop: function(event) { - var count = $("#gMicroThumbGrid").selectable("option", "count"); - if (count > 1) { - $(".gMicroThumbContainer.gSelecting").removeClass("gSelecting"); - } - $("#gMicroThumbGrid").selectable("option", "count", 0); } }; @@ -166,11 +155,12 @@ var selectable = { // Event Handlers // MicroThumbContainer click var onMicroThumbContainerClick = function(event) { - if ($(this).hasClass("gSelecting")) { - $(this).removeClass("gSelecting"); - } else { + if (!$(this).hasClass("gSelecting") && $(this).hasClass("ui-selected")) { $(this).removeClass("ui-selected"); } + $(this).removeClass("gSelecting"); + + setDrawerButtonState(); }; // MicroThumbContainer mousemove @@ -216,7 +206,15 @@ function drawerHandleButtonsClick(event) { $("#gDialog").dialog("close"); break; default: - console.log(operation); + var postData = serializeItemIds("#gMicroThumbPanel li.ui-selected"); + $.ajax({ + data: postData, + dataType: "json", + success: operationCallback, + type: "POST", + url: get_url("organize/startTask/" + operation, {item_id: item_id}) + }); + break; } } }; @@ -234,64 +232,29 @@ var getMicroThumbsCallback = function(json, textStatus) { } }; -// @todo see if we can combine the next two callbacks into an object -// as they are basically the same. -var startMoveCallback = function (data, textStatus) { - if (!paused) { - createProgressDialog(OPERATION_RUNNING); - task = data.task; - task.pauseMsg = MOVE_PAUSED; - task.resumeMSg = MOVE_RESUMED; - } - $(".gMicroThumbContainer").draggable("disable"); +var operationCallback = function (data, textStatus) { var done = false; - paused = false; - while (!done && !paused) { - $.ajax({async: false, - success: function(data, textStatus) { - $(".gProgressBar").progressbar("value", data.task.percent_complete); - done = data.task.done; - }, - error: function(XMLHttpRequest, textStatus, errorThrown) { - paused = true; - displayAjaxError(XMLHttpRequest.responseText); - }, - dataType: "json", - type: "POST", - url: get_url("organize/runTask", {task_id: task.id}) - }); - } - if (!paused) { - $("#gOrganizeProgressDialog").dialog("destroy").remove(); - $.ajax({async: false, - success: function(data, textStatus) { - task = null; - transitItems = []; - $("#gOrganizeStatus").empty().append("<div class='gSuccess'>" + data.task.status + "</div>"); - }, - dataType: "json", - type: "POST", - url: get_url("organize/finishTask", {task_id: task.id}) - }); - } - $(".gMicroThumbContainer").draggable("enable"); -}; - -var startRearrangeCallback = function (data, textStatus) { if (!paused) { - createProgressDialog(OPERATION_RUNNING); + createProgressDialog(data.runningMsg); task = data.task; - task.pauseMsg = REARRANGE_PAUSED; - task.resumeMsg = REARRANGE_RESUMED; + task.pauseMsg = data.pauseMsg; + task.resumeMsg = data.resumeMsg; + done = data.task.done; } $(".gMicroThumbContainer").draggable("disable"); - var done = false; paused = false; while (!done && !paused) { $.ajax({async: false, success: function(data, textStatus) { $(".gProgressBar").progressbar("value", data.task.percent_complete); - done = data.task.done; + done = data.task.done; + if (data.task.reload) { + var selector = "#gMicroThumb-" + data.task.reload.id + " img"; + $(selector).attr("height", data.task.reload.height); + $(selector).attr("width", data.task.reload.width); + $(selector).attr("src", data.task.reload.src); + $(selector).css("margin-top", data.task.reload.marginTop); + } }, error: function(XMLHttpRequest, textStatus, errorThrown) { paused = true; @@ -306,6 +269,7 @@ var startRearrangeCallback = function (data, textStatus) { $("#gOrganizeProgressDialog").dialog("destroy").remove(); $.ajax({async: false, success: function(data, textStatus) { + setDrawerButtonState(); task = null; $("#gOrganizeStatus").empty().append("<div class='gSuccess'>" + data.task.status + "</div>"); }, @@ -413,6 +377,35 @@ function get_url(uri, parms) { return url; } +/** + * Set the enabled/disabled state of the buttons. The album cover is only enabled if + * there is only 1 image selected + */ +function setDrawerButtonState() { + switch ($("#gMicroThumbGrid li.ui-selected").length) { + case 0: + $("#gOrganizeEditHandleButtonsLeft a").attr("disabled", true); + $("#gOrganizeEditHandleButtonsLeft a").addClass("ui-state-disabled"); + break; + case 1: + $("#gOrganizeEditHandleButtonsLeft a").removeAttr("disabled"); + $("#gOrganizeEditHandleButtonsLeft a").removeClass("ui-state-disabled"); + break; + default: + $("#gOrganizeEditHandleButtonsLeft a[ref='albumCover']").attr("disabled", true); + $("#gOrganizeEditHandleButtonsLeft a[ref='albumCover']").addClass("ui-state-disabled"); + } +} + +function serializeItemIds(selector) { + var postData = ""; + $(selector).each(function(i) { + postData += "&item[]=" + $(this).attr("ref"); + }); + + return postData; +} + function createProgressDialog(title) { $("body").append("<div id='gOrganizeProgressDialog'>" + "<div class='gProgressBar'></div>" + @@ -441,7 +434,8 @@ function createProgressDialog(title) { $("#gOrganizeTaskResume").hide(); $("#gOrganizeTaskCancel").hide(); $("#gOrganizeStatus").empty().append(task.resumeMsg); - startRearrangeCallback(); + operationCallback(); + //startRearrangeCallback(); }); $("#gOrganizeTaskCancel").click(function(event) { $("#gOrganizeTaskPause").show(); diff --git a/modules/organize/views/organize.html.php b/modules/organize/views/organize.html.php index c423f5a1..1b4a130a 100644 --- a/modules/organize/views/organize.html.php +++ b/modules/organize/views/organize.html.php @@ -5,12 +5,7 @@ var PAUSE_BUTTON = "<?= t("Pause") ?>"; var RESUME_BUTTON = "<?= t("Resume") ?>"; var CANCEL_BUTTON = "<?= t("Cancel") ?>"; - var OPERATION_RUNNING = "<?= t("Operation in Progress") ?>"; var INVALID_DROP_TARGET = "<div class=\"gError\"><?= t("Drop cancelled as it would result in a recursive move") ?></div>"; - var MOVE_PAUSED = "<div class=\"gWarning\"><?= t("The move operation was paused") ?></div>"; - var MOVE_RESUMED = "<div class=\"gWarning\"><?= t("The move operation was resumed") ?></div>"; - var REARRANGE_PAUSED = "<div class=\"gWarning\"><?= t("The rearrange operation was paused") ?></div>"; - var REARRANGE_RESUMED = "<div class=\"gWarning\"><?= t("The rearrange operation was resumed") ?></div>"; var item_id = <?= $item->id ?>; diff --git a/modules/organize/views/organize_button_pane.html.php b/modules/organize/views/organize_button_pane.html.php index a39c643c..9902eafb 100644 --- a/modules/organize/views/organize_button_pane.html.php +++ b/modules/organize/views/organize_button_pane.html.php @@ -1,7 +1,6 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> - -<a class="gButtonLink ui-corner-all ui-state-default" href="#" ref="edit" +<a class="gButtonLink ui-corner-all ui-state-default ui-state-disabled" href="#" ref="edit" disabled="1" title="<?= t("Edit Selection") ?>"> <span class="ui-icon ui-icon-pencil"> <?= t("Edit Selection") ?> @@ -9,14 +8,14 @@ </a> <? if (graphics::can("rotate")): ?> -<a class="gButtonLink ui-corner-all ui-state-default" href="#" ref="rotate_ccw" +<a class="gButtonLink ui-corner-all ui-state-default ui-state-disabled" href="#" ref="rotateCcw" disabled="1" title="<?= t("Rotate 90 degrees counter clockwise") ?>"> <span class="ui-icon ui-icon-rotate-ccw"> <?= t("Rotate 90 degrees counter clockwise") ?> </span> </a> -<a class="gButtonLink ui-corner-all ui-state-default" href="#" ref="rotate_cw" +<a class="gButtonLink ui-corner-all ui-state-default ui-state-disabled" href="#" ref="rotateCw" disabled="1" title="<?= t("Rotate 90 degrees clockwise") ?>"> <span class="ui-icon ui-icon-rotate-cw"> <?= t("Rotate 90 degrees clockwise") ?> @@ -24,14 +23,14 @@ </a> <? endif ?> -<a class="gButtonLink ui-corner-all ui-state-default" href="#" ref="album_cover" +<a class="gButtonLink ui-corner-all ui-state-default ui-state-disabled" href="#" ref="albumCover" disabled="1" title="<?= t("Choose this photo as the album cover") ?>"> <span class="ui-icon ui-icon-star"> <?= t("Choose this photo as the album cover") ?> </span> </a> -<a class="gButtonLink ui-corner-all ui-state-default" href="#" ref="delete" +<a class="gButtonLink ui-corner-all ui-state-default ui-state-disabled" href="#" ref="delete" disabled="1" title="<?= t("Delete selection") ?>"> <span class="ui-icon ui-icon-trash"> <?= t("Delete selection") ?> |