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:
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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()
|
||||
{
|
||||
|
@@ -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>
|
||||
|
@@ -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() }}
|
||||
|
||||
|
@@ -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>
|
||||
|
@@ -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() }}
|
||||
|
||||
|
@@ -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() }}
|
||||
|
||||
|
@@ -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') }}
|
||||
|
Reference in New Issue
Block a user