From 65c850c393ce6159289e3fd05056c33e7d62e961 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 10:26:11 -0700 Subject: Revert "Revert "Checkpoint the organize module rewrite. At this point, it doesn't really do"" This reverts commit 397468c47b8fc3fefeb54ff19a73980ed1dd8c20. --- modules/organize/controllers/organize.php | 507 ++---------------------------- 1 file changed, 30 insertions(+), 477 deletions(-) (limited to 'modules/organize/controllers') diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 898be509..d7854c53 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -19,54 +19,48 @@ */ class Organize_Controller extends Controller { private static $_MICRO_THUMB_SIZE = 90; - private static $_MICRO_THUMB_PADDING = 5; + private static $_MICRO_THUMB_PADDING = 10; - function index($item_id=1) { + function index($item_id) { $item = ORM::factory("item", $item_id); $root = ($item->id == 1) ? $item : ORM::factory("item", 1); access::required("view", $item); access::required("edit", $item); - $v = new View("organize.html"); + $v = new View("organize_dialog.html"); $v->root = $root; $v->item = $item; - $v->album_tree = $this->tree($item, $root); + $v->album_tree = $this->_tree($item, $root); + $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item); $v->button_pane = new View("organize_button_pane.html"); + $buttons = (object)array("left" => array(), "middle" =>array(), "right" => array(), + "item" => $item); + module::event("organize_format_button_pane", $buttons); + + $v->button_pane->buttons = $buttons; print $v; } - function content($item_id) { + function content($item_id, $offset=0) { $item = ORM::factory("item", $item_id); access::required("view", $item); access::required("edit", $item); - $width = $this->input->get("width"); - $height = $this->input->get("height"); - $offset = $this->input->get("offset", 0); - $thumbsize = self::$_MICRO_THUMB_SIZE + 2 * self::$_MICRO_THUMB_PADDING; - $page_size = ceil($width / $thumbsize) * ceil($height / $thumbsize); + $v = $this->_get_micro_thumb_grid($item, $offset); + print $v->__toString(); + } + private function _get_micro_thumb_grid($item, $offset=0) { $v = new View("organize_thumb_grid.html"); - $v->children = $item->children($page_size, $offset); + $v->item_id = $item->id; + $v->children = $item->children(25, $offset); $v->thumbsize = self::$_MICRO_THUMB_SIZE; - $v->padding = self::$_MICRO_THUMB_PADDING; - $v->offset = $offset; - - print json_encode(array("count" => $v->children->count(), - "data" => $v->__toString())); - } - - function header($item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - access::required("edit", $item); + $v->offset = $offset + 25; - print json_encode( - array("title" => p::purify($item->title), - "description" => empty($item->description) ? "" : p::purify($item->description))); + return $v; } - function tree($item, $parent) { + private function _tree($item, $parent, $selected=false) { access::required("view", $item); access::required("edit", $item); @@ -75,466 +69,25 @@ class Organize_Controller extends Controller { ->orderby(array("title" => "ASC")) ->find_all(); - $v = new View("organize_album.html"); + $v = new View("organize_tree.html"); $v->album = $parent; - $v->selected = $parent->id == $item->id; - - if ($albums->count()) { - $v->album_icon = $parent->id == 1 || $v->selected ? "ui-icon-minus" : "ui-icon-plus"; - } else { - $v->album_icon = ""; - } + $v->selected = false; $v->children = ""; - foreach ($albums as $album) { - $v->children .= $this->tree($item, $album); - } - return $v->__toString(); - } - - function startTask($operation, $id) { - access::verify_csrf(); - $items = $this->input->post("item"); - - $item = ORM::factory("item", $id); - access::required("view", $item); - access::required("edit", $item); - - $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" => "
{$definition['pauseMsg']}
", - "resumeMsg" => "
{$definition['resumeMsg']}
", - "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(); - - $task = task::run($task_id); - if (!$task->loaded || $task->owner_id != user::active()->id) { - access::forbidden(); - } - - print json_encode(array("result" => $task->done ? $task->state : "in_progress", - "task" => array("id" => $task->id, - "percent_complete" => $task->percent_complete, - "type" => $task->get("type"), - "post_process" => $task->get("post_process"), - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); - } - - function finishTask($task_id) { - access::verify_csrf(); - - $task = ORM::factory("task", $task_id); - if (!$task->loaded || $task->owner_id != user::active()->id) { - access::forbidden(); - } - - if ($task->done) { - $item = ORM::factory("item", (int)$task->get("target")); - $type = $task->get("type"); - switch ($type) { - case "albumCover": - $task->status = t("Album cover set for '%album'", array("album" => $item->title)); - break; - case "delete": - $task->status = t("Selection deleted"); - break; - case "move": - $task->status = t("Move to '%album' completed", array("album" => $item->title)); - break; - case "rearrange": - try { - $item->sort_column = "weight"; - $item->save(); - $task->status = t("Rearrange for '%album' completed", array("album" => $item->title)); - } catch (Exception $e) { - $task->state = "error"; - $task->status = $e->getMessage(); - } - break; - case "rotateCcw": - case "rotateCw": - $task->status = t("Rotation completed"); - break; - } - $task->save(); - } - - batch::stop(); - print json_encode(array("result" => "success", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); - } - - function cancelTask($task_id) { - access::verify_csrf(); - - $task = ORM::factory("task", $task_id); - if (!$task->loaded || $task->owner_id != user::active()->id) { - access::forbidden(); - } - - if (!$task->done) { - $task->done = 1; - $task->state = "cancelled"; - $type = $task->get("type"); - switch ($type) { - case "move": - $task->status = t("Move to 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(); - } - - batch::stop(); - print json_encode(array("result" => "success", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); - } - - function editForm() { - $event_parms = new stdClass(); - $event_parms->panes = array(); - $event_parms->itemids = $this->input->get("item"); - - // The following code should be done more dynamically i.e. use the event mechanism - if (count($event_parms->itemids) == 1) { - $item = ORM::factory("item") - ->in("id", $event_parms->itemids[0]) - ->find(); - - access::required("view", $item); - access::required("edit", $item); - - $event_parms->panes[] = array( - "label" => $item->is_album() ? t("Edit Album") : t("Edit Photo"), - "content" => organize::get_general_edit_form($item)); - - if ($item->is_album()) { - $event_parms->panes[] = array("label" => t("Sort Order"), - "content" => organize::get_sort_edit_form($item)); - } - } - - $event_parms->panes[] = array("label" => t("Manage Tags"), - "content" => organize::get_tag_form($event_parms->itemids)); - - $v = new View("organize_edit.html"); - $v->panes = $event_parms->panes; - print $v->render(); - } - - // Handlers for the album/photo edit. Probably should be in modules/gallery - public function general() { - access::verify_csrf(); - - $itemids = $this->input->post("item"); - $item = ORM::factory("item") - ->in("id", $itemids[0]) - ->find(); - access::required("view", $item); - access::required("edit", $item); - - $form = organize::get_general_edit_form($item); - if ($form->validate()) { - $orig = clone $item; - $item->title = $form->title->value; - $item->description = $form->description->value; - $item->rename($form->dirname->value); - $item->save(); + $v->album_icon = "ui-icon-plus"; + if (!$selected) { + $v->selected = $parent->id == $item->id; - if ($item->is_album()) { - log::success("content", "Updated album", "id\">view"); - $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); - } else { - log::success("content", "Updated photo", "id\">view"); - $message = t("Saved photo %photo_title", array("photo_title" => p::purify($item->title))); + if ($albums->count() && ($parent->id == 1 || $v->selected) ) { + $v->album_icon = "ui-icon-minus"; } - print json_encode(array("form" => $form->__toString(), "message" => $message)); - } else { - print json_encode(array("form" => $form->__toString())); - } - } - - public function reset_general() { - $itemids = Input::instance()->get("item"); - $item = ORM::factory("item") - ->in("id", $itemids[0]) - ->find(); - access::required("view", $item); - access::required("edit", $item); - - print organize::get_general_edit_form($item); - } - - public function sort() { - access::verify_csrf(); - - $itemids = $this->input->post("item"); - $item = ORM::factory("item") - ->in("id", $itemids[0]) - ->find(); - access::required("view", $item); - access::required("edit", $item); - - $form = organize::get_sort_edit_form($item); - if ($form->validate()) { - $orig = clone $item; - $item->sort_column = $form->column->value; - $item->sort_order = $form->direction->value; - $item->save(); - - log::success("content", "Updated album", "id\">view"); - $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); - print json_encode(array("form" => $form->__toString(), "message" => $message)); - } else { - print json_encode(array("form" => $form->__toString())); - } - } - - public function reset_sort() { - $itemids = Input::instance()->get("item"); - $item = ORM::factory("item") - ->in("id", $itemids[0]) - ->find(); - access::required("view", $item); - access::required("edit", $item); - - print organize::get_sort_edit_form($item); - } - - public function edit_tags() { - access::verify_csrf(); - $itemids = explode("|", $this->input->post("item")); - $form = organize::get_tag_form($itemids); - $old_tags = $form->tags->value; - if ($form->validate()) { - - $old_tags = preg_split("/[;,\s]+/", $old_tags); - sort($old_tags); - $new_tags = preg_split("/[;,\s]+/", $form->tags->value); - sort($new_tags); - - $HIGH_VALUE_STRING = "\256"; - for ($old_index = $new_index = 0;;) { - $old_tag = $old_index >= count($old_tags) ? $HIGH_VALUE_STRING : $old_tags[$old_index]; - $new_tag = $new_index >= count($new_tags) ? $HIGH_VALUE_STRING : $new_tags[$new_index]; - if ($old_tag == $HIGH_VALUE_STRING && $new_tag == $HIGH_VALUE_STRING) { - break; - } - $matches = array(); - $old_star = false; - if (preg_match("/(.*)(\*)$/", $old_tag, $matches)) { - $old_star = true; - $old_tag = $matches[1]; - } - $new_star = false; - if (preg_match("/(.*)(\*)$/", $new_tag, $matches)) { - $new_star = true; - $new_tag = $matches[1]; - } - if ($old_tag > $new_tag) { - // Its missing in the old list so add it - $this->_add_tag($new_tag, $itemids); - $new_index++; - } else if ($old_tag < $new_tag) { - // Its missing in the new list so its been removed - $this->_delete_tag($old_tag, $itemids); - $old_index++; - } else { - if ($old_star && !$new_star) { - // User wants tag to apply to all items, originally only on some of selected - $this->_update_tag($old_tag, $itemids); - } // Not changed ignore - $old_index++; - $new_index++; - } + foreach ($albums as $album) { + $v->children .= $this->_tree($item, $album, $v->selected); } } - print json_encode(array("form" => $form->__toString(), "message" => t("Tags updated"))); - } - - public function reset_edit_tags() { - $itemids = $this->input->get("item"); - - print organize::get_tag_form($itemids); - } - - private function _add_tag($new_tag, $itemids) { - // Super lame security stopgap. This code is going to get rewritten anyway. - foreach ($itemids as $item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - access::required("edit", $item); - } - - $tag = ORM::factory("tag") - ->where("name", $new_tag) - ->find(); - if ($tag->loaded) { - $tag->count += count($itemids); - } else { - $tag->name = $new_tag; - $tag->count = count($itemids); - } - $tag->save(); - - $db = Database::instance(); - foreach ($itemids as $item_id) { - $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); - } - } - - private function _delete_tag($new_tag, $itemids) { - // Super lame security stopgap. This code is going to get rewritten anyway. - foreach ($itemids as $item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - access::required("edit", $item); - } - - $tag = ORM::factory("tag") - ->where("name", $new_tag) - ->find(); - $tag->count -= count($itemids); - if ($tag->count > 0) { - $tag->save(); - } else { - $tag->delete(); - } - - $ids = implode(", ", $itemids); - Database::instance()->query( - "DELETE FROM {items_tags} WHERE tag_id = {$tag->id} AND item_id IN ($ids);"); - } - - private function _update_tag($new_tag, $itemids) { - // Super lame security stopgap. This code is going to get rewritten anyway. - foreach ($itemids as $item_id) { - $item = ORM::factory("item", $item_id); - access::required("view", $item); - access::required("edit", $item); - } - - $tag = ORM::factory("tag") - ->where("name", $new_tag) - ->find(); - - $db = Database::instance(); - $ids = implode(", ", $itemids); - $result = $db->query( - "SELECT item_id FROM {items_tags} - WHERE tag_id = {$tag->id} - AND item_id IN ($ids)"); - - $add_items = array_fill_keys($itemids, 1); - foreach($result as $row) { - unset($add_items[$row->item_id]); - } - $add_items = array_keys($add_items); - $tag->count += count($add_items); - $tag->save(); - foreach ($add_items as $item_id) { - $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); - } + return $v->__toString(); } - 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 / 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; - - case "albumCover": - return array("description" => t("Reset Album Cover"), - "name" => t("Reset Album cover for %name", array("name" => $item->title)), - "type" => "albumCover", - "runningMsg" => t("Reset Album Cover in progress"), - "pauseMsg" => t("Reset album cover was paused"), - "resumeMsg" => t("Reset album cover was resumed")); - break; - - default: - throw new Exception("Operation '$operation' is not implmented"); - } - } } -- cgit v1.2.3 From 63f3efef37839ffba8cd75b9098d56cd03b06376 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 5 Aug 2009 10:26:49 -0700 Subject: Revert "Revert "Enable the expand/collapse of branches by clicking on the plus/minus"" This reverts commit e37526f94df74a52a9cf36f0a5a5e641958ebbb3. --- modules/organize/controllers/organize.php | 59 ++++++++++++++++--------- modules/organize/css/organize.css | 8 ++++ modules/organize/js/organize.js | 28 +++++++++++- modules/organize/views/organize_dialog.html.php | 2 +- modules/organize/views/organize_tree.html.php | 10 +++-- 5 files changed, 80 insertions(+), 27 deletions(-) (limited to 'modules/organize/controllers') diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index d7854c53..e10e33b5 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -50,6 +50,27 @@ class Organize_Controller extends Controller { print $v->__toString(); } + function children($item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + + $albums = $item->children(null, 0, "album", array("title" => "ASC")); + + $children = ""; + foreach ($albums as $album) { + $v = new View("organize_tree.html"); + $v->album = $album; + $v->selected = false; + $v->children = array(); + $v->album_icon = $album->children_count("album") ? "ui-icon-plus" : "gBranchEmpty"; + + $children .= $v->__toString(); + } + + print $children; + } + private function _get_micro_thumb_grid($item, $offset=0) { $v = new View("organize_thumb_grid.html"); $v->item_id = $item->id; @@ -60,34 +81,30 @@ class Organize_Controller extends Controller { return $v; } - private function _tree($item, $parent, $selected=false) { - access::required("view", $item); - access::required("edit", $item); - - $albums = ORM::factory("item") - ->where(array("parent_id" => $parent->id, "type" => "album")) - ->orderby(array("title" => "ASC")) - ->find_all(); + private function _tree($item, $parent, $depth=0) { + $albums = $parent->children(null, 0, "album", array("title" => "ASC")); $v = new View("organize_tree.html"); $v->album = $parent; - $v->selected = false; - $v->children = ""; - $v->album_icon = "ui-icon-plus"; - if (!$selected) { - $v->selected = $parent->id == $item->id; + if ($parent->id == $item->id) { + $v->selected = true; + $depth = 1; + } else { + $v->selected = false; + } + $v->children = array(); + $v->album_icon = "gBranchEmpty"; + if ($albums->count()) { + $v->album_icon = "ui-icon-plus"; - if ($albums->count() && ($parent->id == 1 || $v->selected) ) { + if ($depth <= 1) { $v->album_icon = "ui-icon-minus"; - } - - foreach ($albums as $album) { - $v->children .= $this->_tree($item, $album, $v->selected); + foreach ($albums as $album) { + $v->children[] = $this->_tree($item, $album, ++$depth); + } } } - return $v->__toString(); + return $v; } - - } diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index 4568a707..7c2d9c5b 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -41,6 +41,14 @@ padding-left: 1.2em; } +.gBranchText:hover { + border: 1px dashed #999; +} + +.gBranchEmpty { + visibility: hidden; +} + .gBranchSelected { background-color: #cfdeff !important; border-bottom: 1px solid #999 !important; diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index e84afd03..74b02569 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -37,7 +37,6 @@ * Dynamically initialize the organize dialog when it is displayed */ function _init(data) { - // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 $(".sf-menu li.sfHover ul").css("z-index", 70); @@ -64,6 +63,8 @@ $.gallery_reload(); }); + $(".gBranchText span").click(_collapse_or_expanded_tree); + //$(".gOrganizeBranch .ui-icon").click(organizeToggleChildren); //$(".gBranchText").droppable(treeDroppable); //$(".gBranchText").click(organizeOpenFolder); @@ -109,6 +110,31 @@ $("#gOrganizeDialog").dialog("close"); }; + /** + * Open or close a branch. If the children is a div placeholder, replace with - -- cgit v1.2.3 From 3823f65dfb4114caf9bd9cfbf730638927f6c970 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 12 Aug 2009 21:55:25 -0700 Subject: Implement the first part of drag functionality. Having trouble getting visual feedback of the drop position between thumbnails, so this commit provides a checkpoint for trying various options --- modules/organize/controllers/organize.php | 9 +-- modules/organize/css/organize.css | 9 ++- modules/organize/helpers/organize_theme.php | 28 +++++++++ modules/organize/js/organize.js | 73 +++++++++++++++++++++- modules/organize/views/organize_dialog.html.php | 4 +- .../organize/views/organize_thumb_grid.html.php | 2 +- modules/organize/views/organize_tree.html.php | 4 +- 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 modules/organize/helpers/organize_theme.php (limited to 'modules/organize/controllers') diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 3a81ef4f..6f83f940 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -60,13 +60,14 @@ class Organize_Controller extends Controller { $v->album_icon = "gBranchEmpty"; $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); - if ($albums->count()) { - $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus"; - - foreach ($albums as $album) { + foreach ($albums as $album) { + if (access::can("view", $album)) { $v->children[] = $this->_tree($album, $parents); } } + if (count($v->children)) { + $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus"; + } return $v; } } diff --git a/modules/organize/css/organize.css b/modules/organize/css/organize.css index a4b5fdbd..1cc7c92c 100644 --- a/modules/organize/css/organize.css +++ b/modules/organize/css/organize.css @@ -1,3 +1,4 @@ + /******************************************************************* * Dialog wide stylings */ @@ -92,7 +93,7 @@ } #gMicroThumbGrid { - padding: .5em; + padding: 1em; } .gMicroThumb { @@ -107,10 +108,14 @@ width: 9em; } -.gMicroThumb.ui-selected { +.gMicroThumb.ui-state-selected { opacity: 1; } +.ui-selectable-lasso { + z-index: 2000 !important; + border: 1px dashed #13A; +} .gThumbnail { padding: .5em; diff --git a/modules/organize/helpers/organize_theme.php b/modules/organize/helpers/organize_theme.php new file mode 100644 index 00000000..de812261 --- /dev/null +++ b/modules/organize/helpers/organize_theme.php @@ -0,0 +1,28 @@ +item(); + if ($item && access::can("edit", $item) && $item->is_album()) { + $theme->script("organize.js"); + $theme->css("organize.css"); + } + } +} diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 05693200..c9408673 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,15 +1,83 @@ (function($) { $.organize = { + micro_thumb_draggable: { + distance: 10, + cursorAt: { left: -10, top: -10}, + appendTo: "#gOrganizeContentPane", + helper: function(event, ui) { + var selected = $("li.ui-state-selected img"), + set = $('
').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), + offset = $(this).offset(), + click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + + selected.each(function(i) { + var row = parseInt(i / 5); + var j = i - (row * 5); + + var o = $(this).offset(); + + var copy = $(this).clone() + .css({ + width: $(this).width(), height: $(this).height(), display: "block", + margin: 0, position: 'absolute', outline: '5px solid #fff', + left: o.left - event.pageX, top: o.top - event.pageY + }) + .appendTo(set) + .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + }); + return set; + }, + start: function(event, ui) { + $("#gMicroThumbPanel").prepend("
"); + + $("#gMicroThumbPanel li.ui-state-selected").hide(); + }, + drag: function(event, ui) { + var container = $("#gMicroThumbPanel").get(0); + var scrollTop = container.scrollTop; + var height = $(container).height(); + if (event.pageY > height + scrollTop) { + container.scrollTop += height; + } else if (event.pageY < scrollTop) { + container.scrollTop -= height; + } + }, + stop: function(event, ui) { + $("li.ui-state-selected").show(); + } + }, + + droppable: { + accept: "*", + tolerance: "pointer", + greedy: true, + drop: function(event, ui) { + // @todo do a ajax call to send the rearrange request to the zerver + // organize/move/target_id/ + // post parameters + // before=id|after=id + // source=[id1, id2, ...] + // before or after not supplied then append to end + // return: json { + // result: success | msg, + // tree: null | new tree, + // content: new thumbgrid + // } + } + }, + /** * Dynamically initialize the organize dialog when it is displayed */ init: function(data) { + var self = this; // Deal with ui.jquery bug: http://dev.jqueryui.com/ticket/4475 (target 1.8?) $(".sf-menu li.sfHover ul").css("z-index", 68); $("#gDialog").dialog("option", "zIndex", 70); $("#gDialog").bind("dialogopen", function(event, ui) { $("#gOrganize").height($("#gDialog").innerHeight() - 20); $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); + $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 59); }); $("#gDialog").bind("dialogclose", function(event, ui) { @@ -23,7 +91,10 @@ $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); - $("#gMicroThumbGrid").selectable({filter: ".gMicroThumb"}); + $("#gMicroThumbPanel").selectable({filter: "li"}); + $("#gMicroThumbPanel img").draggable($.organize.micro_thumb_draggable); + $(".gOrganizeBranch").droppable($.organize.droppable); + $("#gMicroThumbPanel").droppable($.organize.droppable); }, /** diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index b946d82b..f8d6d792 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,5 +1,4 @@ -" />

p::purify($title))) ?>

@@ -11,7 +10,7 @@
-
+
    @@ -39,7 +38,6 @@
- diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 0d54c5c8..b6e3aa11 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -3,7 +3,7 @@
  • " ref="id ?>"> - thumb_img(array("class" => "gThumbnail"), 90, true) ?> + thumb_img(array("class" => "gThumbnail", "ref" => $child->id), 90, true) ?>
  • diff --git a/modules/organize/views/organize_tree.html.php b/modules/organize/views/organize_tree.html.php index 99b0dc1a..d2ef287a 100644 --- a/modules/organize/views/organize_tree.html.php +++ b/modules/organize/views/organize_tree.html.php @@ -1,11 +1,11 @@
  • gBranchText"> + class=""> - title) ?> + title) ?>
      "> -- cgit v1.2.3 From 76f320ab3d6b1f67055dd913eb5811d0d113682a Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sun, 16 Aug 2009 12:36:14 -0700 Subject: In this patch, drag now works to the album tree, but the progress bar is not showing. As well fixed a problem where selectable single clink no longer worked when the album was reloaded. --- modules/gallery/controllers/combined.php | 9 +- modules/organize/controllers/organize.php | 121 +++++++++++++++++++-- modules/organize/js/organize.js | 138 ++++++++++++++---------- modules/organize/views/organize_dialog.html.php | 7 +- 4 files changed, 208 insertions(+), 67 deletions(-) (limited to 'modules/organize/controllers') diff --git a/modules/gallery/controllers/combined.php b/modules/gallery/controllers/combined.php index 9a790fdf..c1f42bfe 100644 --- a/modules/gallery/controllers/combined.php +++ b/modules/gallery/controllers/combined.php @@ -42,22 +42,23 @@ class Combined_Controller extends Controller { private function _emit($type, $key) { $input = Input::instance(); + // We don't need to save the session for this request + Session::abort_save(); + // Our data is immutable, so if they already have a copy then it needs no updating. if ($input->server("HTTP_IF_MODIFIED_SINCE")) { header('HTTP/1.0 304 Not Modified'); header("Expires: Tue, 19 Jan 2038 00:00:00 GMT"); header("Cache-Control: max-age=2678400"); header('Pragma: public'); - return; + Kohana::close_buffers(false); + return ""; } if (empty($key)) { Kohana::show_404(); } - // We don't need to save the session for this request - Session::abort_save(); - $cache = Cache::instance(); $use_gzip = function_exists("gzencode") && stripos($input->server("HTTP_ACCEPT_ENCODING"), "gzip") !== false && diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 6f83f940..1c4a3a69 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -32,8 +32,8 @@ class Organize_Controller extends Controller { } $parents[$item->id] = 1; - $v->album_tree = $this->_tree($root, $parents); - $v->micro_thumb_grid = $this->_get_micro_thumb_grid($item, 0); + $v->album_tree = self::_tree($root, $parents); + $v->micro_thumb_grid = self::_get_micro_thumb_grid($item, 0); print $v; } @@ -41,17 +41,77 @@ class Organize_Controller extends Controller { $item = ORM::factory("item", $item_id); access::required("view", $item); access::required("edit", $item); - print $this->_get_micro_thumb_grid($item, $offset); + print self::_get_micro_thumb_grid($item, $offset); } - private function _get_micro_thumb_grid($item, $offset) { + function move($target_id) { + access::verify_csrf(); + + $task_def = Task_Definition::factory() + ->callback("Organize_Controller::move_task_handler") + ->description(t("Move images")) + ->name(t("Move Images")); + $task = task::create($task_def, array("target_id" => $target_id, + "source_ids" => $this->input->post("source_ids"))); + + print json_encode( + array("result" => "started", + "status" => $task->status, + "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); + } + + function rearrange($target_id, $before) { + access::verify_csrf(); + $target = ORM::factory("item", $target_id); + $parent = $target->parent(); + access::required("view", $parent); + access::required("edit", $parent); + + $task_def = Task_Definition::factory() + ->callback("Organize_Controller::rearrange_task_handler") + ->description(t("Rearrange Image")) + ->name(t("Rearrange Images")); + $task = task::create($task_def, array("target_id" => $target_id, "before" => $before, + "current" => 0, + "source_ids" => $this->input->post("source_ids"))); + + print json_encode( + array("result" => "started", + "status" => $task->status, + "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token()))); + } + + private static function _get_micro_thumb_grid($item, $offset) { $v = new View("organize_thumb_grid.html"); $v->item = $item; $v->offset = $offset; return $v; } - private function _tree($item, $parents) { + /** + * Run the task + */ + function run($task_id) { + access::verify_csrf(); + + $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } + + $task = task::run($task_id); + $results = array("done" => $task->done, "status" => $task->status, + "percent_complete" => $task->percent_complete); + foreach (array("tree", "content") as $data) { + $value = $task->get($data, false); + if ($value !== false) { + $results[$data] = $value; + } + } + print json_encode($results); + } + + private static function _tree($item, $parents) { $v = new View("organize_tree.html"); $v->album = $item; $keys = array_keys($parents); @@ -62,7 +122,7 @@ class Organize_Controller extends Controller { $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); foreach ($albums as $album) { if (access::can("view", $album)) { - $v->children[] = $this->_tree($album, $parents); + $v->children[] = self::_tree($album, $parents); } } if (count($v->children)) { @@ -70,4 +130,53 @@ class Organize_Controller extends Controller { } return $v; } + + static function move_task_handler($task) { + $start = microtime(true); + if ($task->percent_complete == 0) { + batch::start(); + } + + $target = ORM::factory("item", $task->get("target_id")); + $source_ids = $task->get("source_ids", array()); + $idx = $task->get("current", 0); + $count = 0; + for (; $idx < count($source_ids) && microtime(true) - $start < 0.5; $idx++) { + item::move(ORM::factory("item", $source_ids[$idx]), $target); + $count++; + } + $task->set("current", $idx); + $task->percent_complete = ceil($idx / count($source_ids) * 100); + $task->status = t2("Moved one file", "Moved %count files", $count); + if ($task->percent_complete == 100) { + batch::stop(); + $task->done = true; + $task->state = "success"; + $parents = array(); + foreach ($target->parents() as $parent) { + $parents[$parent->id] = 1; + } + $parents[$target->id] = 1; + // @TODO do we want to set a flag and then generate them in the run method so we don't + // potentially store large data items in the task? + $task->set("tree", self::_tree(ORM::factory("item", 1), $parents)->__toString()); + $task->set("content", self::_get_micro_thumb_grid($target, 0)->__toString()); + } + } + + static function rearrange_task_handler($task) { + // @todo need to + // 1) reset the weights based on the current sort order + // 2) when they are all copied, change the sort order of the parent to "weight" + $task->percent_complete = 100; + //$start = microtime(true); + //$mode = $task->get("mode", "init"); + //$start = microtime(true); + // if (microtime(true) - $start > 0.5) { + // break; + $task->done = true; + $task->state = "success"; + $target = ORM::factory("item", $task->get("target_id")); + $task->set("content", self::_get_micro_thumb_grid($target, 0)->__toString()); + } } diff --git a/modules/organize/js/organize.js b/modules/organize/js/organize.js index 07c07286..2d7c99fc 100644 --- a/modules/organize/js/organize.js +++ b/modules/organize/js/organize.js @@ -1,32 +1,37 @@ (function($) { $.organize = { micro_thumb_draggable: { + handle: ".ui-state-selected", distance: 10, cursorAt: { left: -10, top: -10}, appendTo: "#gMicroThumbPanel", helper: function(event, ui) { - var selected = $(".ui-draggable.ui-state-selected img"), - set = $('
      ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), - offset = $(this).offset(), - click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; - - selected.each(function(i) { - var row = parseInt(i / 5); - var j = i - (row * 5); - - var o = $(this).offset(); - - var copy = $(this).clone() - .css({ - width: $(this).width(), height: $(this).height(), display: "block", - margin: 0, position: 'absolute', outline: '5px solid #fff', - left: o.left - event.pageX, top: o.top - event.pageY - }) - .appendTo(set) - .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); - }); - return set; + var selected = $(".ui-draggable.ui-state-selected img"); + if (selected.length) { + var set = $('
      ').css({zIndex: 2000, width: 80, height: Math.ceil(selected.length / 5) * 16 }), + offset = $(this).offset(), + click = { left: event.pageX - offset.left, top: event.pageY - offset.top }; + + selected.each(function(i) { + var row = parseInt(i / 5); + var j = i - (row * 5); + + var o = $(this).offset(); + + var copy = $(this).clone() + .css({ + width: $(this).width(), height: $(this).height(), display: "block", + margin: 0, position: 'absolute', outline: '5px solid #fff', + left: o.left - event.pageX, top: o.top - event.pageY + }) + .appendTo(set) + .animate({width: 10, height: 10, outlineWidth: 1, margin: 1, left: (20 * j), top: (row * 20)}, 500); + }); + return set; + } + return null; }, + start: function(event, ui) { $("#gMicroThumbPanel .ui-state-selected").hide(); }, @@ -52,9 +57,8 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - parent_id: $(".gBranchSelected").attr("ref"), - target_id: $(".currentDropTarget").attr("ref"), - position: $(".currentDropTarget").css("borderLeftStyle") == "solid" ? "before" : "after", + url: rearrange_url.replace("__TARGET_ID__", $(".currentDropTarget").attr("ref")) + .replace("__BEFORE__", $(".currentDropTarget").css("borderLeftStyle") == "solid"), source: $(ui.helper).children("img") }); } @@ -66,40 +70,61 @@ greedy: true, drop: function(event, ui) { $.organize.do_drop({ - parent_id: $(event.target).attr("ref"), - target_id: -1, - position: "after", + url: move_url.replace("__TARGET_ID__", $(event.target).attr("ref")), source: $(ui.helper).children("img") }); } }, - do_drop:function(drop_parms) { - var source_ids = ""; - $(drop_parms.source).each(function(i) { - source_ids += (source_ids.length ? "&" : "") + "source_id[" + i + "]=" + $(this).attr("ref"); + do_drop:function(options) { + var source_ids = []; + $(options.source).each(function(i) { + source_ids.push($(this).attr("ref")); }); - var url = drop_url.replace("__PARENT_ID__", drop_parms.parent_id) - .replace("__POSITION__", drop_parms.position) - .replace("__TARGET_ID__", drop_parms.target_id); - - console.group("do_drop"); - console.log("Generated url: " + url); - console.log("Post data(ids to move): " + source_ids); - console.groupEnd(); - // @todo do a ajax call to send the rearrange request to the server - // organize/move/parent_id/before|after/-1|target_id - // post parameters - // source=[id1, id2, ...] - // before or after not supplied then append to end - // return: json { - // result: success | msg, - // tree: null | new tree, - // content: new thumbgrid - // } - // do forget to reset all the stuff in init when updating the content + + if (source_ids.length) { + $("#gOrganize .gProgressBar").progressbar().progressbar("value", 0); + $("#gOrganizeProgress").slideDown("fast", function() { + $.ajax({ + url: options.url, + type: "POST", + async: false, + data: { "source_ids[]": source_ids }, + dataType: "json", + success: function(data, textStatus) { + $("#gStatus").html(data.status); + $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); + setTimeout(function() { $.organize._run_task(data.url); }, 0); + } + }); + }); + } }, + _run_task: function(url) { + $.ajax({ + url: url, + async: false, + dataType: "json", + success: function(data, textStatus) { + $("#gStatus").html(data.status); + $("#gOrganize .gProgressBar").progressbar("value", data.percent_complete); + if (data.done) { + $("#gProgress").slideUp(); + // Don't forget to refresh the content pane and tree + if (data.tree) { + $("#gOrganizeAlbumTree").html(data.tree); + } + if (data.content) { + $("#gMicroThumbGrid").html(data.content); + } + $.organize.set_handlers(); + } else { + setTimeout(function() { $.organize._run_task(url); }, 0); + } + } + }); + }, mouse_move_handler: function(event) { if ($(".gDragHelper").length) { $(".gMicroThumbGridCell").css("borderStyle", "hidden"); @@ -121,8 +146,8 @@ $("#gDialog").dialog("option", "zIndex", 70); $("#gDialog").bind("dialogopen", function(event, ui) { $("#gOrganize").height($("#gDialog").innerHeight() - 20); - $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 90); - $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 59); + $("#gMicroThumbPanel").height($("#gDialog").innerHeight() - 120); + $("#gOrganizeAlbumTree").height($("#gDialog").innerHeight() - 89); }); $("#gDialog").bind("dialogclose", function(event, ui) { @@ -133,18 +158,18 @@ $("#gDialog").dialog("close"); }); - $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); - $("#gMicroThumbPanel").droppable($.organize.content_droppable); - $.organize.set_handlers(); }, set_handlers: function() { + $("#gMicroThumbPanel").selectable({filter: ".gMicroThumbGridCell"}); + $("#gMicroThumbPanel").droppable($.organize.content_droppable); + $(".gMicroThumbGridCell").draggable($.organize.micro_thumb_draggable); $(".gMicroThumbGridCell").mousemove($.organize.mouse_move_handler); $(".gOrganizeBranch").droppable($.organize.branch_droppable); - $(".gBranchText span").click($.organize.collapse_or_expand_tree); $(".gBranchText").click($.organize.show_album); + $(".gOrganizeBranch .ui-icon").click($.organize.collapse_or_expand_tree); }, /** @@ -164,6 +189,7 @@ if ($(event.currentTarget).hasClass("gBranchSelected")) { return; } + $("#gMicroThumbPanel").selectable("destroy"); var id = $(event.currentTarget).attr("ref"); $(".gBranchSelected").removeClass("gBranchSelected"); $("#gOrganizeBranch-" + id).addClass("gBranchSelected"); diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index 982eba9e..46f9ad9b 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,6 +1,7 @@

      p::purify($title))) ?>

      @@ -39,6 +40,10 @@
  • +