mirror of
https://github.com/typemill/typemill.git
synced 2025-07-30 19:00:32 +02:00
Version 1.4.9: Rewrite slug and recreate cache
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
meta:
|
||||
title: 'Setup Your Website'
|
||||
description: 'Typemill provides detailed settings, and you have access to nearly all settings in the author panel. Learn the basics in this short video:'
|
||||
heroimage: media/live/jack-ward-wbs1qewclne-unsplash.jpeg
|
||||
heroimage: ''
|
||||
heroimagealt: null
|
||||
owner: trendschau
|
||||
author: 'Sebastian Schürmanns'
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
Typemill has a build-in system to restrict access to pages or to the whole websites. You can activate both features in the system settings under the section "access rights". If you activate one of the features, then Typemill will use session cookies on all frontend pages. Learn all the details in the following video tutorial:
|
||||
|
||||
```pagebreak
|
||||
```
|
||||
|
||||
{#UW_m-4g1kAA .youtube}
|
||||
|
||||
## Restrict Access for the Website
|
||||
|
@@ -8,6 +8,7 @@ use Typemill\Models\Folder;
|
||||
use Typemill\Models\Write;
|
||||
use Typemill\Models\WriteYaml;
|
||||
use Typemill\Models\WriteMeta;
|
||||
use Typemill\Models\WriteCache;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
use Typemill\Events\OnPagePublished;
|
||||
use Typemill\Events\OnPageUnpublished;
|
||||
@@ -407,6 +408,78 @@ class ArticleApiController extends ContentController
|
||||
return $response->withJson(['errors' => ['message' => 'Could not write to file. Please check if the file is writable']], 404);
|
||||
}
|
||||
}
|
||||
|
||||
public function renameArticle(Request $request, Response $response, $args)
|
||||
{
|
||||
# get params from call
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
$dir = $this->settings['basePath'] . 'cache';
|
||||
$pathToContent = $this->settings['rootPath'] . $this->settings['contentFolder'];
|
||||
|
||||
# minimum permission is that user is allowed to update his own content
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'mycontent', 'update'))
|
||||
{
|
||||
return $response->withJson(array('data' => false, 'errors' => 'You are not allowed to update content.'), 403);
|
||||
}
|
||||
|
||||
# validate input
|
||||
if(!preg_match("/^[a-z0-9\-]*$/", $this->params['slug']))
|
||||
{
|
||||
return $response->withJson(['errors' => ['message' => 'the slug contains invalid characters.' ]],422);
|
||||
}
|
||||
|
||||
# set structure
|
||||
if(!$this->setStructure($draft = true)){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# set information for homepage
|
||||
$this->setHomepage($args = false);
|
||||
|
||||
# set item
|
||||
if(!$this->setItem()){ return $response->withJson($this->errors, 404); }
|
||||
|
||||
# validate input part 2
|
||||
if($this->params['slug'] == $this->item->slug OR $this->params['slug'] == '')
|
||||
{
|
||||
return $response->withJson(['errors' => ['message' => 'the slug is empty or the same as the old one.' ]],422);
|
||||
}
|
||||
|
||||
# if user has no right to update content from others (eg admin or editor)
|
||||
if(!$this->c->acl->isAllowed($_SESSION['role'], 'content', 'update'))
|
||||
{
|
||||
# check ownership. This code should nearly never run, because there is no button/interface to trigger it.
|
||||
if(!$this->checkContentOwnership())
|
||||
{
|
||||
return $response->withJson(array('data' => $this->structure, 'errors' => 'You are not allowed to move that content.'), 403);
|
||||
}
|
||||
}
|
||||
|
||||
# get the folder where file lives in
|
||||
$pathWithoutFile = str_replace($this->item->originalName, '', $this->item->path);
|
||||
|
||||
# create the new file name with the updated slug
|
||||
$newPathWithoutType = $pathWithoutFile . $this->item->order . '-' . $this->params['slug'];
|
||||
|
||||
# rename the file
|
||||
$write = new WriteCache();
|
||||
$write->renamePost($this->item->pathWithoutType, $newPathWithoutType);
|
||||
|
||||
# delete the cache
|
||||
$error = $write->deleteCacheFiles($dir);
|
||||
if($error)
|
||||
{
|
||||
return $response->withJson(['errors' => $error], 500);
|
||||
}
|
||||
|
||||
# recreates the cache for structure, structure-extended and navigation
|
||||
$write->getFreshStructure($pathToContent, $this->uri);
|
||||
|
||||
$newUrlRel = str_replace($this->item->slug, $this->params['slug'], $this->item->urlRelWoF);
|
||||
|
||||
$url = $this->uri->getBaseUrl() . '/tm/content/' . $this->settings['editor'] . $newUrlRel;
|
||||
|
||||
return $response->withJson(array('data' => false, 'errors' => false, 'url' => $url));
|
||||
}
|
||||
|
||||
public function sortArticle(Request $request, Response $response, $args)
|
||||
{
|
||||
|
@@ -46,7 +46,7 @@ class PageController extends Controller
|
||||
# if the cached structure is still valid, use it
|
||||
if($cache->validate('cache', 'lastCache.txt', 600))
|
||||
{
|
||||
$structure = $this->getCachedStructure($cache);
|
||||
$structure = $cache->getCachedStructure();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -57,7 +57,7 @@ class PageController extends Controller
|
||||
if(!isset($structure) OR !$structure)
|
||||
{
|
||||
# if not, get a fresh structure of the content folder
|
||||
$structure = $this->getFreshStructure($pathToContent, $cache, $uri);
|
||||
$structure = $cache->getFreshStructure($pathToContent, $uri);
|
||||
|
||||
# if there is no structure at all, the content folder is probably empty
|
||||
if(!$structure)
|
||||
@@ -356,145 +356,7 @@ class PageController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCachedStructure($cache)
|
||||
{
|
||||
return $cache->getCache('cache', 'structure.txt');
|
||||
}
|
||||
|
||||
protected function getFreshStructure($pathToContent, $cache, $uri)
|
||||
{
|
||||
/* scan the content of the folder */
|
||||
$pagetree = Folder::scanFolder($pathToContent);
|
||||
|
||||
/* if there is no content, render an empty page */
|
||||
if(count($pagetree) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $yaml->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
# create an array of object with the whole content of the folder
|
||||
$structure = Folder::getFolderContentDetails($pagetree, $extended, $uri->getBaseUrl(), $uri->getBasePath());
|
||||
|
||||
# now update the extended structure
|
||||
if(!$extended)
|
||||
{
|
||||
$extended = $this->createExtended($this->pathToContent, $yaml, $structure);
|
||||
|
||||
if(!empty($extended))
|
||||
{
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
|
||||
# we have to update the structure with extended again
|
||||
$structure = Folder::getFolderContentDetails($pagetree, $extended, $uri->getBaseUrl(), $uri->getBasePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
$extended = false;
|
||||
}
|
||||
}
|
||||
|
||||
# cache structure
|
||||
$cache->updateCache('cache', 'structure.txt', 'lastCache.txt', $structure);
|
||||
|
||||
if($extended && $this->containsHiddenPages($extended))
|
||||
{
|
||||
# generate the navigation (delete empty pages)
|
||||
$navigation = $this->createNavigationFromStructure($structure);
|
||||
|
||||
# cache navigation
|
||||
$cache->updateCache('cache', 'navigation.txt', false, $navigation);
|
||||
}
|
||||
else
|
||||
{
|
||||
# make sure no separate navigation file is set
|
||||
$cache->deleteFileWithPath('cache' . DIRECTORY_SEPARATOR . 'navigation.txt');
|
||||
}
|
||||
|
||||
# load and return the cached structure, because might be manipulated with navigation....
|
||||
$structure = $this->getCachedStructure($cache);
|
||||
|
||||
return $structure;
|
||||
}
|
||||
|
||||
# creates a file that holds all hide flags and navigation titles
|
||||
# reads all meta-files and creates an array with url => ['hide' => bool, 'navtitle' => 'bla']
|
||||
protected function createExtended($contentPath, $yaml, $structure, $extended = NULL)
|
||||
{
|
||||
if(!$extended)
|
||||
{
|
||||
$extended = [];
|
||||
}
|
||||
|
||||
foreach ($structure as $key => $item)
|
||||
{
|
||||
# $filename = ($item->elementType == 'folder') ? DIRECTORY_SEPARATOR . 'index.yaml' : $item->pathWithoutType . '.yaml';
|
||||
$filename = $item->pathWithoutType . '.yaml';
|
||||
|
||||
if(file_exists($contentPath . $filename))
|
||||
{
|
||||
# read file
|
||||
$meta = $yaml->getYaml('content', $filename);
|
||||
|
||||
$extended[$item->urlRelWoF]['hide'] = isset($meta['meta']['hide']) ? $meta['meta']['hide'] : false;
|
||||
$extended[$item->urlRelWoF]['navtitle'] = isset($meta['meta']['navtitle']) ? $meta['meta']['navtitle'] : '';
|
||||
}
|
||||
|
||||
if ($item->elementType == 'folder')
|
||||
{
|
||||
$extended = $this->createExtended($contentPath, $yaml, $item->folderContent, $extended);
|
||||
}
|
||||
}
|
||||
return $extended;
|
||||
}
|
||||
|
||||
# checks if there is a hidden page, returns true on first find
|
||||
protected function containsHiddenPages($extended)
|
||||
{
|
||||
foreach($extended as $element)
|
||||
{
|
||||
if(isset($element['hide']) && $element['hide'] === true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createNavigationFromStructure($navigation)
|
||||
{
|
||||
foreach ($navigation as $key => $element)
|
||||
{
|
||||
if($element->hide === true)
|
||||
{
|
||||
unset($navigation[$key]);
|
||||
}
|
||||
elseif(isset($element->folderContent))
|
||||
{
|
||||
$navigation[$key]->folderContent = $this->createNavigationFromStructure($element->folderContent);
|
||||
}
|
||||
}
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
# not in use, stored the latest version in user settings, but that does not make sense because checkd on the fly with api in admin
|
||||
protected function updateVersion($baseUrl)
|
||||
{
|
||||
/* check the latest public typemill version */
|
||||
$version = new VersionCheck();
|
||||
$latestVersion = $version->checkVersion($baseUrl);
|
||||
|
||||
if($latestVersion)
|
||||
{
|
||||
/* store latest version */
|
||||
\Typemill\Settings::updateSettings(array('latestVersion' => $latestVersion));
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFirstImage(array $contentBlocks)
|
||||
{
|
||||
foreach($contentBlocks as $block)
|
||||
|
@@ -4,6 +4,7 @@ namespace Typemill\Controllers;
|
||||
|
||||
use \Symfony\Component\Yaml\Yaml;
|
||||
use Typemill\Models\Write;
|
||||
use Typemill\Models\WriteCache;
|
||||
use Typemill\Models\Fields;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\User;
|
||||
@@ -971,38 +972,24 @@ class SettingsController extends Controller
|
||||
|
||||
public function clearCache($request, $response, $args)
|
||||
{
|
||||
$settings = $this->c->get('settings');
|
||||
$dir = $settings['basePath'] . 'cache';
|
||||
$iterator = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$files = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
$settings = $this->c->get('settings');
|
||||
$dir = $settings['basePath'] . 'cache';
|
||||
$uri = $request->getUri()->withUserInfo('');
|
||||
$pathToContent = $settings['rootPath'] . $settings['contentFolder'];
|
||||
|
||||
$error = false;
|
||||
$writeCache = new writeCache();
|
||||
|
||||
foreach($files as $file)
|
||||
{
|
||||
if ($file->isDir())
|
||||
{
|
||||
if(!rmdir($file->getRealPath()))
|
||||
{
|
||||
$error = 'Could not delete some folders.';
|
||||
}
|
||||
}
|
||||
elseif($file->getExtension() !== 'css')
|
||||
{
|
||||
if(!unlink($file->getRealPath()) )
|
||||
{
|
||||
$error = 'Could not delete some files.';
|
||||
}
|
||||
}
|
||||
}
|
||||
$error = $writeCache->deleteCacheFiles($dir);
|
||||
|
||||
if($error)
|
||||
{
|
||||
return $response->withJson(['errors' => $error], 500);
|
||||
}
|
||||
|
||||
return $response->withJson(array('errors' => false));
|
||||
# this recreates the cache for structure, structure-extended and navigation
|
||||
$writeCache->getFreshStructure($pathToContent, $uri);
|
||||
|
||||
return $response->withJson(array('errors' => false));
|
||||
}
|
||||
|
||||
private function getUserFields($role)
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
use Typemill\Models\WriteYaml;
|
||||
|
||||
class WriteCache extends Write
|
||||
{
|
||||
/**
|
||||
@@ -73,17 +75,159 @@ class WriteCache extends Write
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Create a function to clear a specific cache file
|
||||
*/
|
||||
public function clearCache($name)
|
||||
public function getCachedStructure()
|
||||
{
|
||||
return $this->getCache('cache', 'structure.txt');
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Create a function to clear all cache files
|
||||
*/
|
||||
public function clearAllCacheFiles()
|
||||
public function deleteCacheFiles($dir)
|
||||
{
|
||||
$iterator = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
|
||||
$files = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
|
||||
|
||||
$error = false;
|
||||
|
||||
foreach($files as $file)
|
||||
{
|
||||
if ($file->isDir())
|
||||
{
|
||||
if(!rmdir($file->getRealPath()))
|
||||
{
|
||||
$error = 'Could not delete some folders.';
|
||||
}
|
||||
}
|
||||
elseif($file->getExtension() !== 'css')
|
||||
{
|
||||
if(!unlink($file->getRealPath()) )
|
||||
{
|
||||
$error = 'Could not delete some files.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
public function getFreshStructure($contentPath, $uri)
|
||||
{
|
||||
# scan the content of the folder
|
||||
$pagetree = Folder::scanFolder('content');
|
||||
|
||||
# if there is no content, render an empty page
|
||||
if(count($pagetree) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# get the extended structure files with changes like navigation title or hidden pages
|
||||
$yaml = new writeYaml();
|
||||
$extended = $yaml->getYaml('cache', 'structure-extended.yaml');
|
||||
|
||||
# create an array of object with the whole content of the folder
|
||||
$structure = Folder::getFolderContentDetails($pagetree, $extended, $uri->getBaseUrl(), $uri->getBasePath());
|
||||
|
||||
# now update the extended structure
|
||||
if(!$extended)
|
||||
{
|
||||
$extended = $this->createExtended($contentPath, $yaml, $structure);
|
||||
|
||||
if(!empty($extended))
|
||||
{
|
||||
$yaml->updateYaml('cache', 'structure-extended.yaml', $extended);
|
||||
|
||||
# we have to update the structure with extended again
|
||||
$structure = Folder::getFolderContentDetails($pagetree, $extended, $uri->getBaseUrl(), $uri->getBasePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
$extended = false;
|
||||
}
|
||||
}
|
||||
|
||||
# cache structure
|
||||
$this->updateCache('cache', 'structure.txt', 'lastCache.txt', $structure);
|
||||
|
||||
if($extended && $this->containsHiddenPages($extended))
|
||||
{
|
||||
# generate the navigation (delete empty pages)
|
||||
$navigation = $this->createNavigationFromStructure($structure);
|
||||
|
||||
# cache navigation
|
||||
$this->updateCache('cache', 'navigation.txt', false, $navigation);
|
||||
}
|
||||
else
|
||||
{
|
||||
# make sure no separate navigation file is set
|
||||
$this->deleteFileWithPath('cache' . DIRECTORY_SEPARATOR . 'navigation.txt');
|
||||
}
|
||||
|
||||
# load and return the cached structure, because might be manipulated with navigation....
|
||||
$structure = $this->getCachedStructure();
|
||||
|
||||
return $structure;
|
||||
}
|
||||
|
||||
# creates a file that holds all hide flags and navigation titles
|
||||
# reads all meta-files and creates an array with url => ['hide' => bool, 'navtitle' => 'bla']
|
||||
public function createExtended($contentPath, $yaml, $structure, $extended = NULL)
|
||||
{
|
||||
if(!$extended)
|
||||
{
|
||||
$extended = [];
|
||||
}
|
||||
|
||||
foreach ($structure as $key => $item)
|
||||
{
|
||||
# $filename = ($item->elementType == 'folder') ? DIRECTORY_SEPARATOR . 'index.yaml' : $item->pathWithoutType . '.yaml';
|
||||
$filename = $item->pathWithoutType . '.yaml';
|
||||
|
||||
if(file_exists($contentPath . $filename))
|
||||
{
|
||||
# read file
|
||||
$meta = $yaml->getYaml('content', $filename);
|
||||
|
||||
$extended[$item->urlRelWoF]['hide'] = isset($meta['meta']['hide']) ? $meta['meta']['hide'] : false;
|
||||
$extended[$item->urlRelWoF]['navtitle'] = isset($meta['meta']['navtitle']) ? $meta['meta']['navtitle'] : '';
|
||||
}
|
||||
|
||||
if ($item->elementType == 'folder')
|
||||
{
|
||||
$extended = $this->createExtended($contentPath, $yaml, $item->folderContent, $extended);
|
||||
}
|
||||
}
|
||||
return $extended;
|
||||
}
|
||||
|
||||
public function createNavigationFromStructure($navigation)
|
||||
{
|
||||
foreach ($navigation as $key => $element)
|
||||
{
|
||||
if($element->hide === true)
|
||||
{
|
||||
unset($navigation[$key]);
|
||||
}
|
||||
elseif(isset($element->folderContent))
|
||||
{
|
||||
$navigation[$key]->folderContent = $this->createNavigationFromStructure($element->folderContent);
|
||||
}
|
||||
}
|
||||
|
||||
return $navigation;
|
||||
}
|
||||
|
||||
# checks if there is a hidden page, returns true on first find
|
||||
protected function containsHiddenPages($extended)
|
||||
{
|
||||
foreach($extended as $element)
|
||||
{
|
||||
if(isset($element['hide']) && $element['hide'] === true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ $app->post('/api/v1/article/html', ArticleApiController::class . ':getArticleHtm
|
||||
$app->post('/api/v1/article/publish', ArticleApiController::class . ':publishArticle')->setName('api.article.publish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/article/unpublish', ArticleApiController::class . ':unpublishArticle')->setName('api.article.unpublish')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/article/discard', ArticleApiController::class . ':discardArticleChanges')->setName('api.article.discard')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/rename', ArticleApiController::class . ':renameArticle')->setName('api.article.rename')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article/sort', ArticleApiController::class . ':sortArticle')->setName('api.article.sort')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/article', ArticleApiController::class . ':createArticle')->setName('api.article.create')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/article', ArticleApiController::class . ':updateArticle')->setName('api.article.update')->add(new RestrictApiAccess($container['router']));
|
||||
|
@@ -2,22 +2,22 @@
|
||||
* TRANSITION *
|
||||
**********************/
|
||||
|
||||
a, a:link, a:visited, a:focus, a:hover, a:active, .link, button, .button, .tab-button, input, .control-group, .sidebar-menu, .sidebar-menu--content, .menu-action, .button-arrow{
|
||||
-webkit-transition: color 0.2s ease;
|
||||
-moz-transition: color 0.2s ease;
|
||||
-o-transition: color 0.2s ease;
|
||||
-ms-transition: color 0.2s ease;
|
||||
transition: color 0.2s ease;
|
||||
-webkit-transition: background-color 0.2s ease;
|
||||
-moz-transition: background-color 0.2s ease;
|
||||
-o-transition: background-color 0.2s ease;
|
||||
-ms-transition: background-color 0.2s ease;
|
||||
transition: border-color 0.2s ease;
|
||||
-webkit-transition: border-color 0.2s ease;
|
||||
-moz-transition: border-color 0.2s ease;
|
||||
-o-transition: border-color 0.2s ease;
|
||||
-ms-transition: border-color 0.2s ease;
|
||||
transition: border-color 0.2s ease;
|
||||
a, a:link, a:visited, a:focus, a:hover, a:active, .blox, .link, button, .button, .tab-button, input, .control-group, .sidebar-menu, .sidebar-menu--content, .menu-action, .button-arrow{
|
||||
-webkit-transition: color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
-moz-transition: color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
-o-transition: color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
-ms-transition: color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
transition: color 0.2s ease,
|
||||
background-color 0.2s ease,
|
||||
border-color 0.2s ease;
|
||||
}
|
||||
.navi-item a,
|
||||
.navi-item.file a .iconwrapper,
|
||||
@@ -239,7 +239,7 @@ aside.sidebar{
|
||||
display: block;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 50px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.right{
|
||||
@@ -449,7 +449,7 @@ li.menu-item{
|
||||
position: relative;
|
||||
}
|
||||
.navi-item .iconwrapper{
|
||||
display: inline-block;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
background: transparent;
|
||||
@@ -459,6 +459,7 @@ li.menu-item{
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.navi-item .status{
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
@@ -2700,6 +2701,11 @@ footer a:focus, footer a:hover, footer a:active
|
||||
|
||||
.mbfix{ margin-bottom: 0px!important; }
|
||||
|
||||
.slugbutton{
|
||||
right: 20px;
|
||||
height: 52px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 600px) {
|
||||
section{
|
||||
@@ -2900,7 +2906,10 @@ footer a:focus, footer a:hover, footer a:active
|
||||
}
|
||||
.navi-item .status{
|
||||
left: -30px;
|
||||
}
|
||||
}
|
||||
.navi-item .iconwrapper{
|
||||
display: block;
|
||||
}
|
||||
.navi-item a .movewrapper,
|
||||
.navi-item a:link .movewrapper,
|
||||
.navi-item a:visited .movewrapper{
|
||||
|
@@ -13,7 +13,19 @@ Vue.filter('translate', function (value) {
|
||||
|
||||
Vue.component('tab-meta', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema', 'userroles'],
|
||||
data: function () {
|
||||
return {
|
||||
slug: false,
|
||||
originalSlug: false,
|
||||
slugerror: false,
|
||||
disabled: "disabled",
|
||||
}
|
||||
},
|
||||
template: '<section><form>' +
|
||||
'<div><div class="large relative">' +
|
||||
'<label>Slug / Name in URL</label><input type="text" v-model="slug" @input="changeSlug()"><button @click.prevent="storeSlug()" :disabled="disabled" class="button slugbutton bn br2 bg-tm-green white absolute">change slug</button>' +
|
||||
'<div v-if="slugerror" class="f6 tm-red mt1">{{ slugerror }}</div>' +
|
||||
'</div></div>' +
|
||||
'<div v-for="(field, index) in schema.fields">' +
|
||||
'<fieldset v-if="field.type == \'fieldset\'" class="fs-formbuilder"><legend>{{field.legend}}</legend>' +
|
||||
'<component v-for="(subfield, index) in field.fields "' +
|
||||
@@ -40,6 +52,11 @@ Vue.component('tab-meta', {
|
||||
'<div v-if="errors" class="metasubmit"><div class="metaErrors">{{ \'Please correct the errors above\'|translate }}</div></div>' +
|
||||
'<div class="metasubmit"><input type="submit" @click.prevent="saveInput" :value="\'save\'|translate"></input></div>' +
|
||||
'</form></section>',
|
||||
mounted: function()
|
||||
{
|
||||
this.slug = this.$parent.item.slug;
|
||||
this.originalSlug = this.slug;
|
||||
},
|
||||
methods: {
|
||||
selectComponent: function(field)
|
||||
{
|
||||
@@ -49,6 +66,52 @@ Vue.component('tab-meta', {
|
||||
{
|
||||
this.$emit('saveform');
|
||||
},
|
||||
changeSlug: function()
|
||||
{
|
||||
if(this.slug == this.originalSlug)
|
||||
{
|
||||
this.slugerror = false;
|
||||
this.disabled = "disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.slug.match(/^[a-z0-9\-]*$/))
|
||||
{
|
||||
this.slugerror = false;
|
||||
this.disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.slugerror = 'Only lowercase a-z and 0-9 and "-" is allowed for slugs.';
|
||||
this.disabled = "disabled";
|
||||
}
|
||||
},
|
||||
storeSlug: function()
|
||||
{
|
||||
|
||||
if(this.slug.match(/^[a-z0-9\-]*$/) && this.slug != this.originalSlug)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
myaxios.post('/api/v1/article/rename',{
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
'slug': this.slug,
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@@ -523,7 +523,7 @@ Vue.component('component-image', {
|
||||
'@input="update($event, name)">' +
|
||||
'</div>' +
|
||||
'<div class="dib w-100 mt2">' +
|
||||
'<button class="w-100 pointer ba br1 b--tm-green bg--tm-gray black pa2 ma0 tc" @click.prevent="switchQuality()">{{ getQualityLabel() }}</button>' +
|
||||
'<button class="w-100 pointer ba br1 b--tm-green bg--tm-gray black pa2 ma0 tc" @click.prevent="switchQuality()">{{ qualitylabel }}</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div v-if="description" class="w-100 dib"><p>{{ description|translate }}</p></div>' +
|
||||
@@ -543,6 +543,7 @@ Vue.component('component-image', {
|
||||
showmedialib: false,
|
||||
load: false,
|
||||
quality: false,
|
||||
qualitylabel: false,
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
@@ -552,10 +553,12 @@ Vue.component('component-image', {
|
||||
if(this.value.indexOf("media/live") > -1 )
|
||||
{
|
||||
this.quality = 'live';
|
||||
this.qualitylabel = 'switch quality to: original';
|
||||
}
|
||||
else if(this.value.indexOf("media/original") > -1)
|
||||
{
|
||||
this.quality = 'original';
|
||||
this.qualitylabel = 'switch quality to: live';
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -579,14 +582,6 @@ Vue.component('component-image', {
|
||||
this.imgpreview = false;
|
||||
this.update('');
|
||||
},
|
||||
getQualityLabel: function()
|
||||
{
|
||||
if(this.quality == 'live')
|
||||
{
|
||||
return 'switch quality to: original';
|
||||
}
|
||||
return 'switch quality to: resized';
|
||||
},
|
||||
switchQuality: function()
|
||||
{
|
||||
if(this.quality == 'live')
|
||||
@@ -594,12 +589,14 @@ Vue.component('component-image', {
|
||||
var newUrl = this.value.replace("media/live", "media/original");
|
||||
this.update(newUrl);
|
||||
this.quality = 'original';
|
||||
this.qualitylabel = 'switch quality to: live';
|
||||
}
|
||||
else
|
||||
{
|
||||
var newUrl = this.value.replace("media/original", "media/live");
|
||||
this.update(newUrl);
|
||||
this.quality = 'live';
|
||||
this.qualitylabel = 'switch quality to: original';
|
||||
}
|
||||
},
|
||||
openmedialib: function()
|
||||
|
@@ -201,8 +201,8 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium">
|
||||
<div class="label">{{ __('Delete all cache files') }}</div>
|
||||
<button id="clearcache" class="link bg-tm-green white dim bn br1 ph3 pv2 f6">{{ __('Clear Cache') }}</button><div id="cacheresult" class="dib ph3 pv2"></div>
|
||||
<div class="label">{{ __('Recreate cached files') }}</div>
|
||||
<button id="clearcache" class="link bg-tm-green white dim bn br1 ph3 pv2 f6">{{ __('Recreate Cache') }}</button><div id="cacheresult" class="dib ph3 pv2"></div>
|
||||
</div>
|
||||
<div class="medium{{ errors.settings.images.live.width ? ' error' : '' }}">
|
||||
<label for="imagewidth">{{ __('Standard width for images') }}</label>
|
||||
|
@@ -42,7 +42,7 @@ article pre, article code{
|
||||
}
|
||||
article pre{
|
||||
white-space: pre;
|
||||
padding: 1em;
|
||||
padding: 0em;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
@@ -55,7 +55,11 @@ article code{
|
||||
}
|
||||
pre > code{
|
||||
font-size: 0.8em;
|
||||
padding: 0;
|
||||
padding: 1em;
|
||||
display: inline-block;
|
||||
}
|
||||
pre > code.language-pagebreak{
|
||||
display: none;
|
||||
}
|
||||
dl{}
|
||||
dt{}
|
||||
|
Reference in New Issue
Block a user