Re #394 update slug, route and raw route with appended number when doing a copy of the page (#537)

Does not change the page title, just the page route property if set in the header, to avoid two pages with the same slug / route / raw route. Handles ordering too, and pages with custom slug. Independently updates the slug and the folder name.
This commit is contained in:
Flavio Copes
2016-06-07 23:10:34 +02:00
parent 235c2c9e73
commit 1ad76c04f9
2 changed files with 111 additions and 33 deletions

View File

@@ -1419,27 +1419,13 @@ class AdminController
return $found;
}
/**
* Handles creating an empty page folder (without markdown file)
* Get the next available ordering number in a folder
*
* @return bool True if the action was performed.
* @return string the correct order string to prepend
*/
public function taskSaveNewFolder()
private function getNextOrderInFolder($path)
{
if (!$this->authorizeTask('save', $this->dataPermissions())) {
return false;
}
$data = (array) $this->data;
if ($data['route'] == '/') {
$path = $this->grav['locator']->findResource('page://');
} else {
$path = $page = $this->grav['page']->find($data['route'])->path();
}
$files = Folder::all($path, ['recursive' => false]);
$highestOrder = 0;
@@ -1463,6 +1449,30 @@ class AdminController
$orderOfNewFolder = '0' . $orderOfNewFolder;
}
return $orderOfNewFolder;
}
/**
* Handles creating an empty page folder (without markdown file)
*
* @return bool True if the action was performed.
*/
public function taskSaveNewFolder()
{
if (!$this->authorizeTask('save', $this->dataPermissions())) {
return false;
}
$data = (array) $this->data;
if ($data['route'] == '/') {
$path = $this->grav['locator']->findResource('page://');
} else {
$path = $this->grav['page']->find($data['route'])->path();
}
$orderOfNewFolder = $this->getNextOrderInFolder($path);
Folder::mkdir($path . '/' . $orderOfNewFolder . '.' . $data['folder']);
Cache::clearCache('standard');
@@ -1526,8 +1536,6 @@ class AdminController
/** @var Page $obj */
$obj = $this->admin->page(true);
// Ensure route is prefixed with a forward slash.
$route = '/' . ltrim($route, '/');
@@ -1705,6 +1713,60 @@ class AdminController
return true;
}
/**
* Find the first available $item ('slug' | 'folder') for a page
* Used when copying a page, to determine the first available slot
*
* @param string $item
* @param Page $page
*
* @return string The first available slot
*/
protected function findFirstAvailable($item, $page)
{
if (!$page->parent()->children()) {
return $page->$item();
}
$withoutPrefix = function ($string) {
$match = preg_split('/^[0-9]+\./u', $string, 2, PREG_SPLIT_DELIM_CAPTURE);
return isset($match[1]) ? $match[1] : $match[0];
};
$withoutPostfix = function ($string) {
$match = preg_split('/-(\d+)$/', $string, 2, PREG_SPLIT_DELIM_CAPTURE);
return $match[0];
};
$appendedNumber = function ($string) {
$match = preg_split('/-(\d+)$/', $string, 2, PREG_SPLIT_DELIM_CAPTURE);
$append = (isset($match[1]) ? (int)$match[1] + 1 : 2);
return $append;
};
$highest = 1;
$siblings = $page->parent()->children();
$findCorrectAppendedNumber = function ($item, $page_item, $highest) use ($siblings, &$findCorrectAppendedNumber, &$withoutPrefix) {
foreach ($siblings as $sibling) {
if ($withoutPrefix($sibling->$item()) == ($highest === 1 ? $page_item : $page_item . '-' . $highest)) {
$highest = $findCorrectAppendedNumber($item, $page_item, $highest + 1);
return $highest;
}
}
return $highest;
};
$base = $withoutPrefix($withoutPostfix($page->$item()));
$return = $base;
$highest = $findCorrectAppendedNumber($item, $base, $highest);
if ($highest > 1) {
$return .= '-' . $highest;
}
return $return;
}
/**
* Save page as a new copy.
*
@@ -1726,35 +1788,49 @@ class AdminController
/** @var Pages $pages */
$pages = $this->grav['pages'];
// And then get the current page.
// Get the current page.
$page = $this->admin->page(true);
// Find new parent page in order to build the path.
$parent = $page->parent() ?: $pages->root();
// Make a copy of the current page and fill the updated information into it.
$page = $page->copy($parent);
if ($page->order()) {
$order = $this->getNextOrderInFolder($page->parent()->path());
}
$this->preparePage($page);
// Make sure the header is loaded in case content was set through raw() (expert mode)
$page->header();
// Deal with folder naming conflicts, but limit number of searches to 99.
$break = 99;
while ($break > 0 && file_exists($page->filePath())) {
$break--;
$match = preg_split('/-(\d+)$/', $page->path(), 2, PREG_SPLIT_DELIM_CAPTURE);
$page->path($match[0] . '-' . (isset($match[1]) ? (int)$match[1] + 1 : 2));
// Reset slug and route. For now we do not support slug twig variable on save.
$page->slug('');
if ($page->order()) {
$page->order($order);
}
$page->save();
$folder = $this->findFirstAvailable('folder', $page);
$slug = $this->findFirstAvailable('slug', $page);
$page->path($page->parent()->path() . DS . $page->order() . $folder);
$page->route($page->parent()->route() . '/' . $slug);
$page->rawRoute($page->parent()->rawRoute() . '/' . $slug);
$page->save(false);
$redirect = $this->view . $page->rawRoute();
$header = $page->header();
if (isset($header->slug)) {
$match = preg_split('/-(\d+)$/', $header->slug, 2, PREG_SPLIT_DELIM_CAPTURE);
$header->slug = $match[0] . '-' . (isset($match[1]) ? (int)$match[1] + 1 : 2);
}
$page->header($header);
$page->save();
// Enqueue message and redirect to new location.
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.SUCCESSFULLY_COPIED'), 'info');
$parent_route = $parent->route() ? '/' . ltrim($parent->route(), '/') : '';
$this->setRedirect($this->view . $parent_route . '/' . $page->slug());
$this->setRedirect($redirect);
} catch (\Exception $e) {
throw new \RuntimeException('Copying page failed on error: ' . $e->getMessage());