mirror of
https://github.com/typemill/typemill.git
synced 2025-01-16 13:00:26 +01:00
Version 1.5.2: Shortcode component for visual editor
This commit is contained in:
parent
e2fedd8878
commit
105680b1bc
22
data/ebookproducts/ebookproducts.yaml
Normal file
22
data/ebookproducts/ebookproducts.yaml
Normal file
@ -0,0 +1,22 @@
|
||||
flatfilecms:
|
||||
title: 'Flat File CMS for simple projects'
|
||||
cover: media/live/cover-report.png
|
||||
description: 'Another publication from cmsstash that will uncover the secrets of database-less web publishing. Read about all flat file cms and make an informed choice.'
|
||||
downloadlabel: ''
|
||||
downloadurl: ''
|
||||
firstbuttonlabel: ''
|
||||
firstbuttonurl: ''
|
||||
secondbuttonlabel: ''
|
||||
secondbuttonurl: ''
|
||||
downloadlabel1: 'Download now'
|
||||
downloadlabel2: 'Buy on amazon'
|
||||
enterprisecms:
|
||||
title: 'Das CMS Drupal: Open Source für Enterprise'
|
||||
cover: ''
|
||||
description: ''
|
||||
downloadlabel: ''
|
||||
downloadurl: ''
|
||||
firstbuttonlabel: ''
|
||||
firstbuttonurl: ''
|
||||
secondbuttonlabel: ''
|
||||
secondbuttonurl: ''
|
@ -5,6 +5,7 @@ namespace Typemill\Controllers;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
use Typemill\Events\OnShortcodeFound;
|
||||
|
||||
class ControllerAuthorBlockApi extends ControllerAuthor
|
||||
{
|
||||
@ -570,4 +571,27 @@ class ControllerAuthorBlockApi extends ControllerAuthor
|
||||
|
||||
return $response->withJson(array('markdown' => $pageMarkdown, 'toc' => $toc, 'errors' => $errors));
|
||||
}
|
||||
|
||||
public function getShortcodeData(Request $request, Response $response, $args)
|
||||
{
|
||||
/* get params from call */
|
||||
$this->params = $request->getParams();
|
||||
$this->uri = $request->getUri()->withUserInfo('');
|
||||
$errors = false;
|
||||
|
||||
# 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' => ['message' => 'You are not allowed to delete this content.']), 403);
|
||||
}
|
||||
|
||||
$shortcodeData = $this->c->dispatcher->dispatch('onShortcodeFound', new OnShortcodeFound(['name' => 'registershortcode', 'data' => []]))->getData();
|
||||
|
||||
if(empty($shortcodeData['data']))
|
||||
{
|
||||
return $response->withJson(array('shortcodedata' => false));
|
||||
}
|
||||
|
||||
return $response->withJson(array('shortcodedata' => $shortcodeData['data']));
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ $app->post('/api/v1/block', ControllerAuthorBlockApi::class . ':addBlock')->setN
|
||||
$app->put('/api/v1/block', ControllerAuthorBlockApi::class . ':updateBlock')->setName('api.block.update')->add(new RestrictApiAccess($container['router']));
|
||||
$app->delete('/api/v1/block', ControllerAuthorBlockApi::class . ':deleteBlock')->setName('api.block.delete')->add(new RestrictApiAccess($container['router']));
|
||||
$app->put('/api/v1/moveblock', ControllerAuthorBlockApi::class . ':moveBlock')->setName('api.block.move')->add(new RestrictApiAccess($container['router']));
|
||||
$app->get('/api/v1/shortcodedata', ControllerAuthorBlockApi::class . ':getShortcodeData')->setName('api.shortcodedata.get')->add(new RestrictApiAccess($container['router']));
|
||||
$app->post('/api/v1/video', ControllerAuthorMediaApi::class . ':saveVideoImage')->setName('api.video.save')->add(new RestrictApiAccess($container['router']));
|
||||
|
||||
$app->get('/api/v1/medialib/images', ControllerAuthorMediaApi::class . ':getMediaLibImages')->setName('api.medialibimg.get')->add(new RestrictApiAccess($container['router']));
|
||||
|
@ -82,7 +82,7 @@ class Settings
|
||||
'userPath' => $rootPath . 'settings' . DIRECTORY_SEPARATOR . 'users',
|
||||
'authorPath' => __DIR__ . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR,
|
||||
'editor' => 'visual',
|
||||
'formats' => ['markdown', 'headline', 'ulist', 'olist', 'table', 'quote', 'notice', 'image', 'video', 'file', 'toc', 'hr', 'definition', 'code'],
|
||||
'formats' => ['markdown', 'headline', 'ulist', 'olist', 'table', 'quote', 'notice', 'image', 'video', 'file', 'toc', 'hr', 'definition', 'code', 'shortcode'],
|
||||
'contentFolder' => 'content',
|
||||
'version' => '1.5.1.1',
|
||||
'setup' => true,
|
||||
|
@ -63,6 +63,13 @@ let determiner = {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
shortcode: function(block,lines,firstChar,secondChar,thirdChar){
|
||||
if( firstChar == '[' && secondChar == ':')
|
||||
{
|
||||
return "shortcode-component";
|
||||
}
|
||||
return false;
|
||||
},
|
||||
notice: function(block,lines,firstChar,secondChar,thirdChar){
|
||||
if( firstChar == '!' && ( secondChar == '!' || secondChar == ' ') )
|
||||
{
|
||||
@ -94,4 +101,5 @@ let bloxFormats = {
|
||||
hr: { label: '<svg class="icon icon-pagebreak"><use xlink:href="#icon-pagebreak"></use></svg>', title: 'Horizontal Line', component: 'hr-component' },
|
||||
definition: { label: '<svg class="icon icon-dots-two-vertical"><use xlink:href="#icon-dots-two-vertical"></use></svg>', title: 'Definition List', component: 'definition-component' },
|
||||
code: { label: '<svg class="icon icon-embed"><use xlink:href="#icon-embed"></use></svg>', title: 'Code', component: 'code-component' },
|
||||
shortcode: { label: '<svg class="icon icon-square-brackets"><use xlink:href="#icon-square-brackets"></use></svg>', title: 'Shortcode', component: 'shortcode-component' },
|
||||
};
|
@ -781,6 +781,132 @@ const codeComponent = Vue.component('code-component', {
|
||||
},
|
||||
})
|
||||
|
||||
const shortcodeComponent = Vue.component('shortcode-component', {
|
||||
props: ['compmarkdown', 'disabled'],
|
||||
data: function(){
|
||||
return {
|
||||
shortcodedata: false,
|
||||
shortcodename: '',
|
||||
markdown: '',
|
||||
searchresults: [],
|
||||
}
|
||||
},
|
||||
template: '<div>' +
|
||||
'<div class="contenttype"><svg class="icon icon-square-brackets"><use xlink:href="#icon-square-brackets"></use></svg></div>' +
|
||||
'<div v-if="shortcodedata" class="pa4 bg-tm-gray" ref="markdown">' +
|
||||
'<label class="w-20 dib" for="shortcodename">{{ \'Shortcode\'|translate }}: </label>' +
|
||||
'<select class="w-80 dib bg-white" title="shortcodename" v-model="shortcodename"><option v-for="shortcode,name in shortcodedata" :value="name">{{ name }}</option></select>' +
|
||||
'<div class="mt1 mb1" v-for="key,attribute in shortcodedata[shortcodename]">' +
|
||||
'<label class="w-20 dib" for="key">{{ attribute }}: </label>' +
|
||||
'<input class="w-80 dib bg-white" type="text" v-model="shortcodedata[shortcodename][attribute].value" @input="createmarkdown(shortcodename,attribute)">' +
|
||||
'<div class="w-20 dib v-top tr"> </div>' +
|
||||
'<div class="w-80 dib mb1 bg-white">' +
|
||||
'<span class="db bt b--light-gray pa2 hover-bg-near-white pointer" v-for="item in searchresults" @click="selectsearch(item,attribute)">{{item}}</span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<textarea v-else class="mdcontent" ref="markdown" placeholder="No shortcodes are registered" disabled></textarea>' +
|
||||
'</div>',
|
||||
mounted: function(){
|
||||
|
||||
var myself = this;
|
||||
|
||||
myaxios.get('/api/v1/shortcodedata',{
|
||||
params: {
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
if(response.data.shortcodedata !== false)
|
||||
{
|
||||
myself.shortcodedata = response.data.shortcodedata;
|
||||
myself.parseshortcode();
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
parseshortcode: function()
|
||||
{
|
||||
if(this.compmarkdown)
|
||||
{
|
||||
var shortcodestring = this.compmarkdown.trim();
|
||||
shortcodestring = shortcodestring.slice(2,-2);
|
||||
this.shortcodename = shortcodestring.substr(0,shortcodestring.indexOf(' '));
|
||||
|
||||
var regexp = /(\w+)\s*=\s*("[^"]*"|\'[^\']*\'|[^"\'\\s>]*)/g;
|
||||
var matches = shortcodestring.matchAll(regexp);
|
||||
matches = Array.from(matches);
|
||||
matchlength = matches.length;
|
||||
|
||||
if(matchlength > 0)
|
||||
{
|
||||
for(var i=0;i<matchlength;i++)
|
||||
{
|
||||
var attribute = matches[i][1];
|
||||
var attributeValue = matches[i][2].replaceAll('"','');
|
||||
|
||||
this.shortcodedata[this.shortcodename][attribute].value = attributeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
createmarkdown: function(shortcodename,attribute)
|
||||
{
|
||||
|
||||
/* search */
|
||||
this.searchresults = [];
|
||||
|
||||
if(this.shortcodedata[shortcodename][attribute].content !== undefined && this.shortcodedata[shortcodename][attribute].value != '')
|
||||
{
|
||||
var searchterm = this.shortcodedata[shortcodename][attribute].value;
|
||||
var searchitems = this.shortcodedata[shortcodename][attribute].content;
|
||||
|
||||
for(var item in searchitems)
|
||||
{
|
||||
if(searchitems[item].indexOf(searchterm) > -1 && searchitems[item] !== searchterm)
|
||||
{
|
||||
this.searchresults.push(searchitems[item]);
|
||||
if(this.searchresults.length > 4){ break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* markdown */
|
||||
var attributes = '';
|
||||
for (var attribute in this.shortcodedata[shortcodename])
|
||||
{
|
||||
if(this.shortcodedata[shortcodename].hasOwnProperty(attribute))
|
||||
{
|
||||
attributes += ' ' + attribute + '="' + this.shortcodedata[shortcodename][attribute].value + '"';
|
||||
}
|
||||
}
|
||||
|
||||
this.markdown = '[:' + shortcodename + attributes + ' :]';
|
||||
|
||||
this.$emit('updatedMarkdown', this.markdown);
|
||||
},
|
||||
selectsearch: function(item,attribute)
|
||||
{
|
||||
/* check if still reactive */
|
||||
this.shortcodedata[this.shortcodename][attribute].value = item;
|
||||
this.createmarkdown(this.shortcodename,attribute);
|
||||
},
|
||||
updatemarkdown: function(event)
|
||||
{
|
||||
this.$emit('updatedMarkdown', event.target.value);
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const quoteComponent = Vue.component('quote-component', {
|
||||
props: ['compmarkdown', 'disabled'],
|
||||
template: '<div>' +
|
||||
|
@ -174,6 +174,9 @@
|
||||
<symbol id="icon-shrink2" viewBox="0 0 32 32">
|
||||
<path d="M14 18v13l-5-5-6 6-3-3 6-6-5-5zM32 3l-6 6 5 5h-13v-13l5 5 6-6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-square-brackets" viewBox="0 0 21 21">
|
||||
<path d="M 4.791 18.885 L 4.791 20.518 L 0 20.518 L 0 0 L 4.791 0 L 4.791 1.622 L 2.052 1.622 L 2.052 18.885 L 4.791 18.885 Z M 20.958 0 L 20.958 20.518 L 16.178 20.518 L 16.178 18.885 L 18.906 18.885 L 18.906 1.622 L 16.178 1.622 L 16.178 0 L 20.958 0 Z M 6.542 4.952 A 1.326 1.326 0 0 0 6.404 5.11 Q 6.102 5.516 6.102 6.166 A 2.167 2.167 0 0 0 6.15 6.638 A 1.453 1.453 0 0 0 6.553 7.38 A 1.472 1.472 0 0 0 7.616 7.82 A 1.702 1.702 0 0 0 7.626 7.82 A 1.445 1.445 0 0 0 8.669 7.385 Q 9.109 6.95 9.109 6.166 A 2.149 2.149 0 0 0 9.058 5.685 A 1.429 1.429 0 0 0 8.658 4.958 A 1.482 1.482 0 0 0 7.595 4.522 Q 6.982 4.522 6.542 4.952 Z M 12.311 4.952 A 1.326 1.326 0 0 0 12.173 5.11 Q 11.87 5.516 11.87 6.166 A 2.167 2.167 0 0 0 11.919 6.638 A 1.453 1.453 0 0 0 12.321 7.38 A 1.472 1.472 0 0 0 13.385 7.82 A 1.702 1.702 0 0 0 13.394 7.82 A 1.445 1.445 0 0 0 14.437 7.385 Q 14.878 6.95 14.878 6.166 A 2.149 2.149 0 0 0 14.827 5.685 A 1.429 1.429 0 0 0 14.427 4.958 A 1.482 1.482 0 0 0 13.363 4.522 Q 12.751 4.522 12.311 4.952 Z M 9.06 14.192 A 1.427 1.427 0 0 0 8.653 13.455 Q 8.196 13.02 7.584 13.02 A 1.442 1.442 0 0 0 6.542 13.449 A 1.326 1.326 0 0 0 6.404 13.607 Q 6.102 14.013 6.102 14.663 A 2.679 2.679 0 0 0 6.102 14.698 Q 6.105 14.959 6.16 15.18 A 1.407 1.407 0 0 0 6.542 15.866 A 1.455 1.455 0 0 0 7.595 16.296 Q 8.207 16.296 8.658 15.866 A 1.405 1.405 0 0 0 9.056 15.154 A 2.131 2.131 0 0 0 9.109 14.663 A 2.134 2.134 0 0 0 9.06 14.192 Z M 14.829 14.192 A 1.427 1.427 0 0 0 14.421 13.455 Q 13.965 13.02 13.353 13.02 A 1.442 1.442 0 0 0 12.311 13.449 A 1.326 1.326 0 0 0 12.173 13.607 Q 11.87 14.013 11.87 14.663 A 2.679 2.679 0 0 0 11.87 14.698 Q 11.874 14.959 11.928 15.18 A 1.407 1.407 0 0 0 12.311 15.866 A 1.455 1.455 0 0 0 13.363 16.296 Q 13.976 16.296 14.427 15.866 A 1.405 1.405 0 0 0 14.825 15.154 A 2.131 2.131 0 0 0 14.878 14.663 A 2.134 2.134 0 0 0 14.829 14.192 Z" />
|
||||
</symbol>
|
||||
{{ assets.renderSvg() }}
|
||||
</defs>
|
||||
<defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
Loading…
x
Reference in New Issue
Block a user