diff --git a/controllers/AjaxController.php b/controllers/AjaxController.php new file mode 100644 index 0000000..a2d725e --- /dev/null +++ b/controllers/AjaxController.php @@ -0,0 +1,166 @@ +_helper->viewRenderer->setNoRender(true); + + $this->_helper->db->setDefaultModelName('SimplePagesPage'); + } + + /** + * Handle AJAX requests to update a simple page. + */ + public function updateAction() + { + if (!$this->_checkAjax('update')) { + return; + } + + // Handle action. + try { + $status = $this->_getParam('status'); + if (!in_array($status, array('public', 'private'))) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + + $id = (integer) $this->_getParam('id'); + $simplePage = $this->_helper->db->find($id); + if (!$simplePage) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + $simplePage->is_published = ($status == 'public'); + $simplePage->save(); + } catch (Exception $e) { + $this->getResponse()->setHttpResponseCode(500); + } + } + + /** + * Handle AJAX requests to delete a simple page. + */ + public function deleteAction() + { + if (!$this->_checkAjax('delete')) { + return; + } + + // Handle action. + try { + $id = (integer) $this->_getParam('id'); + $simplePage = $this->_helper->db->find($id); + if (!$simplePage) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + $simplePage->delete(); + } catch (Exception $e) { + $this->getResponse()->setHttpResponseCode(500); + } + } + + /** + * Handle AJAX requests to change a list of simple pages. + */ + public function changeAction() + { + if (!$this->_checkAjax('change')) { + return; + } + + // Handle action. + try { + $remove = $this->_getParam('remove'); + $remove = $remove ?: array(); + if (!is_array($remove)) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + + $order = $this->_getParam('order'); + if (!is_array($order) || empty($order)) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + + // Secure and normalize order. + $newOrder = array(); + // Remove root. + unset($order[0]); + foreach ($order as $input) { + $newOrder[(integer) $input['id']] = (integer) $input['parent_id']; + } + + // Delete pages to remove and update order array. + foreach ($remove as $id) { + $id = (integer) $id; + $simplePage = $this->_helper->db->find($id); + if (!$simplePage) { + $this->getResponse()->setHttpResponseCode(400); + return; + } + // Remove deleted pages from new order and attach children to + // new parent. + $newParentId = $newOrder[$id]; + unset($newOrder[$id]); + foreach ($newOrder as &$parentId) { + if ($parentId == $id) { + $parentId = $newParentId; + } + } + $simplePage->delete(); + } + + // Reorder pages if needed. + simple_pages_update_order($newOrder); + } catch (Exception $e) { + $this->getResponse()->setHttpResponseCode(500); + } + } + + /** + * Check AJAX requests. + * + * 400 Bad Request + * 403 Forbidden + * 500 Internal Server Error + * + * @param string $action + */ + protected function _checkAjax($action) + { + // Only allow AJAX requests. + $request = $this->getRequest(); + if (!$request->isXmlHttpRequest()) { + $this->getResponse()->setHttpResponseCode(403); + return false; + } + + // Allow only valid calls. + if ($request->getControllerName() != 'ajax' + || $request->getActionName() != $action + ) { + $this->getResponse()->setHttpResponseCode(400); + return false; + } + + // Allow only allowed users. + if (!is_allowed('SimplePages_Page', $action)) { + $this->getResponse()->setHttpResponseCode(403); + return false; + } + + return true; + } +} diff --git a/helpers/SimplePageFunctions.php b/helpers/SimplePageFunctions.php index b472e62..7a371fe 100644 --- a/helpers/SimplePageFunctions.php +++ b/helpers/SimplePageFunctions.php @@ -126,20 +126,42 @@ function simple_pages_display_breadcrumbs($pageId = null, $seperator=' > ', $inc return $html; } -function simple_pages_display_hierarchy($parentPageId = 0, $partialFilePath = 'index/browse-hierarchy-page.php') +/** + * Recursively list the pages under a page for editing. + * + * @param SimplePage $page A page to list. + * @return string + */ +function simple_pages_edit_page_list($page) { - $html = ''; - $childrenPages = get_db()->getTable('SimplePagesPage')->findChildrenPages($parentPageId); - if (count($childrenPages)) { + $html = '
-
- ()
- %1$s on %2$s',
- html_escape(metadata('simple_pages_page', 'modified_username')),
- html_escape(format_date(metadata('simple_pages_page', 'updated'), Zend_Date::DATETIME_SHORT))); ?>
-
-
-
| diff --git a/views/admin/index/browse.php b/views/admin/index/browse.php index 21a09c9..e0ac59d 100644 --- a/views/admin/index/browse.php +++ b/views/admin/index/browse.php @@ -1,27 +1,52 @@ 'simple-pages primary', - 'title' => html_escape(__('Simple Pages | Browse')), - 'content_class' => 'horizontal-nav'); +$currentView = isset($_GET['view']) && $_GET['view'] == 'hierarchy' ? 'hierarchy' : 'list'; + +queue_css_file('simple-pages', 'screen'); +queue_js_file(array('vendor/jquery.nestedSortable', 'simple-pages')); + +$head = array( + 'title' => html_escape(__('Simple Pages | Browse')), + 'bodyclass' => 'simple-pages primary', + 'content_class' => 'horizontal-nav', +); echo head($head); ?> + + + + - + - + partial('index/browse-hierarchy.php', array('simplePages' => $simple_pages_pages)); ?> partial('index/browse-list.php', array('simplePages' => $simple_pages_pages)); ?> - + + + + + + + diff --git a/views/admin/javascripts/simple-pages.js b/views/admin/javascripts/simple-pages.js new file mode 100644 index 0000000..cabcafe --- /dev/null +++ b/views/admin/javascripts/simple-pages.js @@ -0,0 +1,116 @@ +jQuery(document).ready(function() { + // Handle published / not published from any status. + jQuery('.simplepage.toggle-status').click(function(event) { + event.preventDefault(); + var id = jQuery(this).attr('id'); + var current = jQuery('#' + id); + id = id.substr(id.lastIndexOf('-') + 1); + var ajaxUrl = jQuery(this).attr('href') + '/simple-pages/ajax/update'; + jQuery(this).addClass('transmit'); + if (jQuery(this).hasClass('public')) { + jQuery.post(ajaxUrl, + { + status: 'private', + id: id + }, + function(data) { + current.addClass('private'); + current.removeClass('public'); + current.removeClass('transmit'); + if (current.text() != '') { + current.text(Omeka.messages.simplepages.private); + } + } + ); + } else { + jQuery.post(ajaxUrl, + { + status: 'public', + id: id + }, + function(data) { + current.addClass('public'); + current.removeClass('private'); + current.removeClass('transmit'); + if (current.text() != '') { + current.text(Omeka.messages.simplepages.public); + } + } + ); + } + }); + + // Handle deletion on list page. + jQuery('.simplepage.delete-confirm').click(function(event) { + event.preventDefault(); + if (!confirm(Omeka.messages.simplepages.confirmation)) { + return; + } + var id = jQuery(this).attr('id'); + var current = jQuery('#' + id); + id = id.substr(id.lastIndexOf('-') + 1); + var row = jQuery(this).closest('tr'); + var ajaxUrl = jQuery(this).attr('href') + '/simple-pages/ajax/delete'; + jQuery(this).addClass('transmit'); + jQuery.post(ajaxUrl, + { + id: id + }, + function(data) { + current.removeClass('transmit'); + row.remove(); + } + ); + }); + + // Enable drag and drop sorting for elements on hierarchy page. + jQuery('.sortable').nestedSortable({ + listType: 'ul', + items: 'li.page', + handle: '.sortable-item', + revert: 200, + forcePlaceholderSize: true, + forceHelperSize: true, + toleranceElement: '> div', + placeholder: 'ui-sortable-highlight', + containment: 'document', + maxLevels: 9 + }); + + // Handle deletion on hierarchy page. + jQuery('#page-list .delete-element').click(function(event) { + event.preventDefault(); + var header = jQuery(this).parent(); + if (jQuery(this).hasClass('delete-element')) { + jQuery(this).removeClass('delete-element').addClass('undo-delete'); + header.addClass('deleted'); + } else { + jQuery(this).removeClass('undo-delete').addClass('delete-element'); + header.removeClass('deleted'); + } + }); + + // Handle changes on hierarchy page. + jQuery('.update-pages').click(function(event) { + event.preventDefault(); + var sortable = jQuery('.sortable'); + sortable.nestedSortable({disabled: true}); + var remove = jQuery('#page-list .deleted').parent() + .map(function() {return parseInt(this.id.substr(this.id.lastIndexOf('_') + 1));}) + .get(); + var order = sortable.nestedSortable('toArray', {startDepthCount: 0}); + order = jQuery.map(order, function(value) {return {id: value.item_id, parent_id: value.parent_id};}); + var ajaxUrl = jQuery(this).attr('href') + '/simple-pages/ajax/change'; + jQuery('.update-pages').addClass('transmit red').removeClass('blue'); + jQuery.post(ajaxUrl, + { + remove: remove, + order: order + }, + function(data) { + // TODO Rebuild instead of reload (simply delete removeds). + location.reload(true); + } + ); + }); +}); diff --git a/views/shared/images/waiting-mini.gif b/views/shared/images/waiting-mini.gif new file mode 100644 index 0000000..6a00d4e Binary files /dev/null and b/views/shared/images/waiting-mini.gif differ |