1
0
mirror of https://github.com/typemill/typemill.git synced 2025-08-08 07:06:44 +02:00

Add svg support

This commit is contained in:
trendschau
2021-09-02 14:50:42 +02:00
parent b722b639fc
commit 5f597c31ad
14 changed files with 142 additions and 68 deletions

View File

@@ -1,15 +1,15 @@
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: ''
heroimage: media/live/1528492471.svg
heroimagealt: null
owner: trendschau
author: 'Sebastian Schürmanns'
allowedrole: null
alloweduser: null
manualdate: null
modified: '2021-05-27'
modified: '2021-09-02'
created: '2021-05-27'
time: 21-02-24
navtitle: 'setup your website'
hide: false
allowedrole: null
alloweduser: null

View File

@@ -99,24 +99,57 @@ class MediaApiController extends ContentController
$this->params = $request->getParams();
$this->uri = $request->getUri()->withUserInfo('');
$imageProcessor = new ProcessImage($this->settings['images']);
$imageProcessor = new ProcessImage($this->settings['images']);
if(!$imageProcessor->checkFolders('images'))
{
return $response->withJson(['errors' => 'Please check if your media-folder exists and all folders inside are writable.'], 500);
}
return $response->withJson(['errors' => ['message' => 'Please check if your media-folder exists and all folders inside are writable.']], 500);
}
if($imageProcessor->createImage($this->params['image'], $this->params['name'], $this->settings['images']))
$imageParts = explode(";base64,", $this->params['image']);
$imageType = explode("/", $imageParts[0]);
if(!isset($imageType[1]))
{
return $response->withJson(['errors' => ['message' => 'We did not find an image type, the file might be corrupted.']], 422);
}
$acceptedTypes = [
'png' => true,
'jpg' => true,
'jpeg' => true,
'gif' => true,
'webp' => true,
];
if(isset($this->settings['svg']) && $this->settings['svg'])
{
$acceptedTypes['svg+xml'] = true;
}
if(!isset($acceptedTypes[$imageType[1]]))
{
return $response->withJson(['errors' => ['message' => 'The image type is not supported.']], 422);
}
$imageResult = $imageProcessor->createImage($this->params['image'], $this->params['name'], $this->settings['images']);
if($imageResult)
{
if(is_array($imageResult) && isset($imageResult['errors']))
{
return $response->withJson($imageResult,422);
}
# publish image directly, used for example by image field for meta-tabs
if($this->params['publish'])
{
$imageProcessor->publishImage();
}
return $response->withJson(['name' => 'media/live/' . $imageProcessor->getFullName(),'errors' => false]);
return $response->withJson(['name' => 'media/live/' . $imageProcessor->getFullName(),'errors' => false]);
}
return $response->withJson(['errors' => 'could not store image to temporary folder']);
return $response->withJson(['errors' => 'could not store image to temporary folder'],422);
}
public function uploadFile(Request $request, Response $response, $args)

View File

@@ -111,6 +111,7 @@ class SettingsController extends Controller
'trustedproxies' => $newSettings['trustedproxies'],
'headersoff' => isset($newSettings['headersoff']) ? true : null,
'urlschemes' => $newSettings['urlschemes'],
'svg' => isset($newSettings['svg']) ? true : null,
);
# https://www.slimframework.com/docs/v3/cookbook/uploading-files.html;

View File

@@ -22,6 +22,19 @@ class ProcessImage extends ProcessAssets
$imageData = $imageDecoded["image"];
$imageType = $imageDecoded["type"];
if($imageType == 'svg+xml')
{
# store the original name as txt-file
$tmpname = fopen($this->tmpFolder . $this->getName() . ".svg.txt", "w");
# store the same svg file for original, live and thumb.
$this->saveOriginal($this->tmpFolder, $imageData, $name = 'original', 'svg');
$this->saveOriginal($this->tmpFolder, $imageData, $name = 'live', 'svg');
$this->saveOriginal($this->tmpFolder, $imageData, $name = 'thumbs', 'svg');
return true;
}
$this->setExtension($imageType);
# transform image-stream into image
@@ -325,17 +338,34 @@ class ProcessImage extends ProcessAssets
{
$imageinfo = getimagesize($this->liveFolder . $name);
$imagedetails = [
'name' => $name,
'timestamp' => filemtime($this->liveFolder . $name),
'bytes' => filesize($this->liveFolder . $name),
'width' => $imageinfo[0],
'height' => $imageinfo[1],
'type' => $imageinfo['mime'],
'src_thumb' => 'media/thumbs/' . $name,
'src_live' => 'media/live/' . $name,
'pages' => $this->findPagesWithUrl($structure, $name, $result = [])
];
if(!$imageinfo && pathinfo($this->liveFolder . $name, PATHINFO_EXTENSION) == 'svg')
{
$imagedetails = [
'name' => $name,
'timestamp' => filemtime($this->liveFolder . $name),
'bytes' => filesize($this->liveFolder . $name),
'width' => '---',
'height' => '---',
'type' => 'svg',
'src_thumb' => 'media/thumbs/' . $name,
'src_live' => 'media/live/' . $name,
'pages' => $this->findPagesWithUrl($structure, $name, $result = [])
];
}
else
{
$imagedetails = [
'name' => $name,
'timestamp' => filemtime($this->liveFolder . $name),
'bytes' => filesize($this->liveFolder . $name),
'width' => $imageinfo[0],
'height' => $imageinfo[1],
'type' => $imageinfo['mime'],
'src_thumb' => 'media/thumbs/' . $name,
'src_live' => 'media/live/' . $name,
'pages' => $this->findPagesWithUrl($structure, $name, $result = [])
];
}
return $imagedetails;
}

View File

@@ -29,12 +29,12 @@ class Validation
Validator::addRule('image_types', function($field, $value, array $params, array $fields) use ($user)
{
$allowed = ['jpg', 'jpeg', 'png', 'webp'];
$allowed = ['jpg', 'jpeg', 'png', 'webp', 'svg'];
$pathinfo = pathinfo($value);
$extension = strtolower($pathinfo['extension']);
if(in_array($extension, $allowed)){ return true; }
return false;
}, 'only jpg, jpeg, png, webp, allowed');
}, 'only jpg, jpeg, png, webp, svg allowed');
# checks if email is available if user is created
Validator::addRule('emailAvailable', function($field, $value, array $params, array $fields) use ($user)

View File

@@ -84,7 +84,7 @@ class Settings
'editor' => 'visual',
'formats' => ['markdown', 'headline', 'ulist', 'olist', 'table', 'quote', 'notice', 'image', 'video', 'file', 'toc', 'hr', 'definition', 'code'],
'contentFolder' => 'content',
'version' => '1.4.8',
'version' => '1.4.8.2',
'setup' => true,
'welcome' => true,
'images' => ['live' => ['width' => 820], 'thumbs' => ['width' => 250, 'height' => 150]],
@@ -185,6 +185,7 @@ class Settings
'trustedproxies' => true,
'headersoff' => true,
'urlschemes' => true,
'svg' => true,
];
# cleanup the existing usersettings

View File

@@ -2151,12 +2151,14 @@ button.post-button:hover{
padding: 0 0 0 20px;
font-size: 0.9em;
line-height: 30px;
height: 30px;
background: #66b0a1;
margin-bottom: 2px;
color: #fff;
}
.newblock-close{
line-height: 30px;
height: 30px;
border: 0px;
color: #fff;
background: #e0474c;

View File

@@ -618,7 +618,7 @@ Vue.component('component-image', {
if(result.errors)
{
publishController.errors.message = result.errors;
publishController.errors.message = result.errors.message;
}
else
{
@@ -837,8 +837,8 @@ const medialib = Vue.component('medialib', {
});
}
return filteredFiles;
}
},
}
},
methods: {
isImagesActive: function()
{

View File

@@ -16,8 +16,8 @@
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url }}/system/author/img/favicon-144.png" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url }}/system/author/img/favicon-180.png" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210901" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210901" />
{{ assets.renderCSS() }}
@@ -39,16 +39,16 @@
</article>
<footer></footer>
</div>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210901"></script>
<script>
const myaxios = axios.create();
myaxios.defaults.baseURL = "{{ base_url }}";
</script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/typemillutils.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/typemillutils.js?20210901"></script>
<script>
typemillUtilities.start()
</script>

View File

@@ -17,7 +17,7 @@
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url }}/system/author/img/favicon-144.png" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url }}/system/author/img/favicon-180.png" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210901" />
{{ assets.renderCSS() }}

View File

@@ -16,7 +16,7 @@
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url }}/system/author/img/favicon-144.png" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url }}/system/author/img/favicon-180.png" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210901" />
</head>
<body>

View File

@@ -16,8 +16,8 @@
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url }}/system/author/img/favicon-144.png" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url }}/system/author/img/favicon-180.png" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210901" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210901" />
{{ assets.renderCSS() }}
@@ -41,17 +41,17 @@
</article>
<footer></footer>
</div>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210901"></script>
<script>
const myaxios = axios.create();
myaxios.defaults.baseURL = "{{ base_url }}";
</script>
<script src="{{ base_url }}/system/author/js/typemillutils.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-publishcontroller.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-blox-config.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/typemillutils.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-publishcontroller.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-blox-config.js?20210901"></script>
<script>
let formatConfig = {{ settings.formats|json_encode() }};
let language = {{ settings.language|json_encode() }};
@@ -61,13 +61,13 @@
{{ assets.renderEditorJS() }}
<script src="{{ base_url }}/system/author/js/vue-blox.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-posts.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/sortable.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vuedraggable.umd.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-navi.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-meta.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-blox.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-posts.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/sortable.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vuedraggable.umd.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-navi.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-meta.js?20210901"></script>
{{ assets.renderJS() }}

View File

@@ -16,8 +16,8 @@
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url }}/system/author/img/favicon-144.png" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url }}/system/author/img/favicon-180.png" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210821" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/tachyons.min.css?20210901" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20210901" />
{{ assets.renderCSS() }}
@@ -41,15 +41,15 @@
</article>
<footer></footer>
</div>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/axios.min.js?20210901"></script>
<script>
const myaxios = axios.create();
myaxios.defaults.baseURL = "{{ base_url }}";
</script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-publishcontroller.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/author.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-publishcontroller.js?20210901"></script>
<script>
let language = {{ settings.language|json_encode() }};
let labels = {{ translations|json_encode() }};
@@ -58,13 +58,13 @@
{{ assets.renderEditorJS() }}
<script src="{{ base_url }}/system/author/js/vue-editor.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-posts.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/sortable.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vuedraggable.umd.min.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-navi.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-meta.js?20210821"></script>
<script src="{{ base_url }}/system/author/js/vue-editor.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-posts.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/sortable.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vuedraggable.umd.min.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-navi.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-shared.js?20210901"></script>
<script src="{{ base_url }}/system/author/js/vue-meta.js?20210901"></script>
{{ assets.renderJS() }}

View File

@@ -220,6 +220,13 @@
<span class="error">{{ errors.settings.images.live.height | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.settings.svg ? ' error' : '' }}">
<label for="settings[svg]">{{ __('Upload svg images') }}</label>
<label class="control-group">{{ __('Allow upload of svg images (on your own risk, has security implications)') }}
<input name="settings[svg]" type="checkbox" {% if (settings.svg or old.settings.svg) %} checked {% endif %}>
<span class="checkmark"></span>
</label>
</div>
<div class="medium{{ errors.settings.proxy ? ' error' : '' }}">
<label for="settings[proxy]">{{ __('Proxy') }}</label>
<label class="control-group">{{ __('Use X-Forwarded Headers') }}