1
0
mirror of https://github.com/typemill/typemill.git synced 2025-01-17 21:38:25 +01:00

Version 1.3.1: Improved Meta-Tabs and Translations

This commit is contained in:
trendschau 2020-01-06 17:23:30 +01:00
parent e09487e668
commit 0d09fe60b1
18 changed files with 471 additions and 66 deletions

2
cache/lastCache.txt vendored
View File

@ -1 +1 @@
1577899842
1578262565

View File

@ -30,10 +30,13 @@ class MetaApiController extends ContentController
# loop through all plugins
foreach($this->settings['plugins'] as $name => $plugin)
{
$pluginSettings = \Typemill\Settings::getObjectSettings('plugins', $name);
if($pluginSettings && isset($pluginSettings['metatabs']))
if($plugin['active'])
{
$metatabs = array_merge_recursive($metatabs, $pluginSettings['metatabs']);
$pluginSettings = \Typemill\Settings::getObjectSettings('plugins', $name);
if($pluginSettings && isset($pluginSettings['metatabs']))
{
$metatabs = array_merge_recursive($metatabs, $pluginSettings['metatabs']);
}
}
}
@ -155,4 +158,6 @@ class MetaApiController extends ContentController
# return with the new metadata
return $response->withJson(array('metadata' => $metaData, 'errors' => false));
}
}
}
# check models -> writeYaml for getPageMeta and getPageMetaDefaults.

View File

@ -463,7 +463,7 @@ class SettingsController extends Controller
if($validate->newUser($params, $userroles))
{
$userdata = array('username' => $params['username'], 'email' => $params['email'], 'userrole' => $params['userrole'], 'password' => $params['password']);
$userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole'], 'password' => $params['password']);
$user->createUser($userdata);
@ -511,7 +511,7 @@ class SettingsController extends Controller
if($validate->existingUser($params, $userroles))
{
$userdata = array('username' => $params['username'], 'email' => $params['email'], 'userrole' => $params['userrole']);
$userdata = array('username' => $params['username'], 'firstname' => $params['firstname'], 'lastname' => $params['lastname'], 'email' => $params['email'], 'userrole' => $params['userrole']);
if(empty($params['password']) AND empty($params['newpassword']))
{

View File

@ -64,6 +64,7 @@ class Field
'id',
'autocomplete',
'placeholder',
'maxlength',
'size',
'rows',
'cols',

View File

@ -38,6 +38,15 @@ class User extends WriteYaml
'password' => $this->generatePassword($params['password']),
'userrole' => $params['userrole']
);
if(isset($params['firstname']))
{
$userdata['firstname'] = $params['firstname'];
}
if(isset($params['lastname']))
{
$userdata['lastname'] = $params['lastname'];
}
if($this->updateYaml('settings/users', $userdata['username'] . '.yaml', $userdata))
{
@ -58,8 +67,20 @@ class User extends WriteYaml
$update = array_merge($userdata, $params);
$this->updateYaml('settings/users', $userdata['username'] . '.yaml', $update);
$_SESSION['user'] = $update['username'];
$_SESSION['role'] = $update['userrole'];
if(isset($update['firstname']))
{
$_SESSION['firstname'] = $update['firstname'];
}
if(isset($update['lastname']))
{
$_SESSION['lastname'] = $update['lastname'];
}
return $userdata['username'];
return $userdata['username'];
}
public function deleteUser($username)
@ -88,6 +109,15 @@ class User extends WriteYaml
$_SESSION['user'] = $user['username'];
$_SESSION['role'] = $user['userrole'];
$_SESSION['login'] = $user['lastlogin'];
if(isset($user['firstname']))
{
$_SESSION['firstname'] = $user['firstname'];
}
if(isset($user['lastname']))
{
$_SESSION['lastname'] = $user['lastname'];
}
}
}

View File

@ -124,6 +124,10 @@ class Validation
$v->rule('lengthBetween', 'password', 5, 20)->message("Length between 5 - 20");
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
$v->rule('userAvailable', 'username')->message("User already exists");
$v->rule('noHTML', 'firstname')->message(" contains HTML");
$v->rule('lengthBetween', 'firstname', 2, 40);
$v->rule('noHTML', 'lastname')->message(" contains HTML");
$v->rule('lengthBetween', 'lastname', 2, 40);
$v->rule('email', 'email')->message("e-mail is invalid");
$v->rule('in', 'userrole', $userroles);
@ -137,10 +141,14 @@ class Validation
$v->rule('alphaNum', 'username')->message("invalid");
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
$v->rule('userExists', 'username')->message("user does not exist");
$v->rule('noHTML', 'firstname')->message(" contains HTML");
$v->rule('lengthBetween', 'firstname', 2, 40);
$v->rule('noHTML', 'lastname')->message(" contains HTML");
$v->rule('lengthBetween', 'lastname', 2, 40);
$v->rule('email', 'email')->message("e-mail is invalid");
$v->rule('in', 'userrole', $userroles);
return $this->validationResult($v);
return $this->validationResult($v);
}
public function username($username)
@ -329,7 +337,23 @@ class Validation
{
$v->rule('required', $fieldName);
}
if(isset($fieldDefinitions['maxlength']))
{
$v->rule('lengthMax', $fieldName, $fieldDefinitions['maxlength']);
}
if(isset($fieldDefinitions['max']))
{
$v->rule('max', $fieldName, $fieldDefinitions['max']);
}
if(isset($fieldDefinitions['min']))
{
$v->rule('min', $fieldName, $fieldDefinitions['min']);
}
if(isset($fieldDefinitions['pattern']))
{
$v->rule('regex', $fieldName, '/^' . $fieldDefinitions['pattern'] . '$/');
}
switch($fieldDefinitions['type'])
{
case "select":
@ -350,7 +374,7 @@ class Validation
{
$v->rule('in', $key, $options);
}
break;
break;
case "color":
$v->rule('regex', $fieldName, '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/');
break;
@ -361,33 +385,35 @@ class Validation
$v->rule('date', $fieldName);
break;
case "checkbox":
$v->rule('accepted', $fieldName);
if(isset($fieldDefinitions['required']))
{
$v->rule('accepted', $fieldName);
}
break;
case "url":
$v->rule('lengthMax', $fieldName, 200);
$v->rule('url', $fieldName);
$v->rule('lengthMax', $fieldName, 200);
break;
case "text":
$v->rule('lengthMax', $fieldName, 200);
$v->rule('noHTML', $fieldName);
$v->rule('lengthMax', $fieldName, 500);
$v->rule('regex', $fieldName, '/^[\pL0-9_ \-\.\?\!\/\:]*$/u');
break;
case "textarea":
$v->rule('lengthMax', $fieldName, 1000);
$v->rule('noHTML', $fieldName);
// $v->rule('regex', $fieldName, '/<[^<]+>/');
$v->rule('lengthMax', $fieldName, 1000);
break;
case "paragraph":
$v->rule('lengthMax', $fieldName, 1000);
$v->rule('noHTML', $fieldName);
$v->rule('lengthMax', $fieldName, 1000);
break;
case "password":
$v->rule('lengthMax', $fieldName, 100);
break;
default:
$v->rule('lengthMax', $fieldName, 1000);
$v->rule('regex', $fieldName, '/^[\pL0-9_ \-]*$/u');
$v->rule('regex', $fieldName, '/^[\pL0-9_ \-]*$/u');
}
return $this->validationResult($v, $objectName);
}

View File

@ -86,12 +86,27 @@ class WriteYaml extends Write
$description = substr($description, 0, $lastSpace);
}
$author = $settings['author'];
if(isset($_SESSION))
{
if(isset($_SESSION['firstname']) && $_SESSION['firstname'] !='' && isset($_SESSION['lastname']) && $_SESSION['lastname'] != '')
{
$author = $_SESSION['firstname'] . ' ' . $_SESSION['lastname'];
}
elseif(isset($_SESSION['user']))
{
$author = $_SESSION['user'];
}
}
# create new meta-file
$meta = [
'meta' => [
'title' => $title,
'description' => $description,
'author' => $settings['author'], # change to session, extend userdata
'author' => $author,
'created' => date("Y-m-d"),
]
];

View File

@ -1773,7 +1773,6 @@ button.format-item.close:hover{
top: 0;
left: 0;
transform: translate(-50%, -100%);
transition: 0.2s all;
display: flex;
justify-content: center;
align-items: center;
@ -1809,7 +1808,7 @@ button.format-item.close:hover{
margin-right: 2px;
}
.urlinput{
width: 80%;
width: 75%;
min-height: auto;
background: #555;
color: #fff;

View File

@ -5,6 +5,27 @@
<div class="formWrapper">
<div id="metanav" class="metanav" v-cloak>
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>${tab}</button>
<component
class="tab"
v-bind:is="currentTabComponent"
:saved="saved"
:errors="formErrors[currentTab]"
:schema="formDefinitions[currentTab]"
:formdata="formData[currentTab]"
v-on:saveform="saveForm">
</component>
</div>
<div id="editor" class="editor">
<form action="#" v-cloak>

View File

@ -393,7 +393,7 @@ const contentComponent = Vue.component('content-block', {
})
const inlineFormatsComponent = Vue.component('inline-formats', {
template: '<div><div :style="{ left: `${x}px`, top: `${y}px` }" @mousedown.prevent="" v-show="showInlineFormat" id="formatBar" class="inlineFormatBar">' +
template: '<div><div :style="{ left: `${x}px`, top: `${y}px`, width: `${z}px` }" @mousedown.prevent="" v-show="showInlineFormat" id="formatBar" class="inlineFormatBar">' +
'<div v-if="link">' +
'<input v-model="url" @keyup.13="formatLink" ref="urlinput" class="urlinput" type="text" placeholder="insert url">' +
'<span class="inlineFormatItem inlineFormatLink" @mousedown.prevent="formatLink"><svg class="icon icon-check"><use xlink:href="#icon-check"></use></svg></span>' +
@ -410,10 +410,12 @@ const inlineFormatsComponent = Vue.component('inline-formats', {
data: function(){
return {
formatBar: false,
formatElements: 0,
startX: 0,
startY: 0,
x: 0,
y: 0,
z: 150,
textComponent: '',
selectedText: '',
startPos: false,
@ -500,6 +502,10 @@ const inlineFormatsComponent = Vue.component('inline-formats', {
this.y = event.offsetY - 15;
/* calculate the width of the format bar */
this.formatElements = document.getElementsByClassName('inlineFormatItem').length;
this.z = this.formatElements * 30;
this.showInlineFormat = true;
this.selectedText = selectedText;
},
@ -508,30 +514,35 @@ const inlineFormatsComponent = Vue.component('inline-formats', {
content = this.textComponent.value;
content = content.substring(0, this.startPos) + '**' + this.selectedText + '**' + content.substring(this.endPos, content.length);
this.$parent.updatemarkdown(content);
this.showInlineFormat = false;
},
formatItalic()
{
content = this.textComponent.value;
content = content.substring(0, this.startPos) + '_' + this.selectedText + '_' + content.substring(this.endPos, content.length);
this.$parent.updatemarkdown(content);
this.showInlineFormat = false;
},
formatCode()
{
content = this.textComponent.value;
content = content.substring(0, this.startPos) + '`' + this.selectedText + '`' + content.substring(this.endPos, content.length);
this.$parent.updatemarkdown(content);
this.$parent.updatemarkdown(content);
this.showInlineFormat = false;
},
formatMath()
{
content = this.textComponent.value;
content = content.substring(0, this.startPos) + '$' + this.selectedText + '$' + content.substring(this.endPos, content.length);
this.$parent.updatemarkdown(content);
this.showInlineFormat = false;
},
formatLink()
{
if(this.url == "")
{
this.link = false;
this.link = false;
this.showInlineFormat = false;
return;
}
content = this.textComponent.value;
@ -543,11 +554,15 @@ const inlineFormatsComponent = Vue.component('inline-formats', {
openLink()
{
this.link = true;
this.url = '';
this.z = 200;
this.$nextTick(() => this.$refs.urlinput.focus());
},
closeLink()
{
this.link = false;
this.url = '';
this.showInlineFormat = false;
}
}
})

View File

@ -1,26 +1,21 @@
const FormBus = new Vue();
Vue.component('component-text', {
props: ['class', 'placeholder', 'label', 'name', 'type', 'size', 'value', 'errors'],
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="text" :name="name" :placeholder="placeholder" :value="value" @input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-date', {
props: ['class', 'placeholder', 'readonly', 'label', 'name', 'type', 'size', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="date" :readonly="readonly" :name="name" :placeholder="placeholder" :value="value" @input="update($event, name)">' +
'<input type="text"' +
' :id="id"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
@ -31,11 +26,195 @@ Vue.component('component-date', {
})
Vue.component('component-textarea', {
props: ['class', 'placeholder', 'label', 'name', 'type', 'size', 'value', 'errors'],
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{label}}</label>' +
'<textarea :name="name" v-model="value" @input="update($event, name)"></textarea>' +
'<label>{{ label }}</label>' +
'<textarea ' +
' :id="id"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
' @input="update($event, name)"></textarea>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-url', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="url"' +
' :id="id"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-number', {
props: ['class', 'id', 'description', 'min', 'max', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="number"' +
' :id="id"' +
' :min="min"' +
' :min="max"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-email', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="email"' +
' :id="id"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-tel', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="tel"' +
' :id="id"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-password', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="password"' +
' :id="id"' +
' :maxlength="maxlength"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
'@input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-date', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="date" ' +
' :id="id"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
' @input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
{
FormBus.$emit('forminput', {'name': name, 'value' : $event.target.value});
},
},
})
Vue.component('component-color', {
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<input type="color" ' +
' :id="id"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :placeholder="placeholder"' +
' :value="value"' +
' @input="update($event, name)">' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
@ -46,13 +225,20 @@ Vue.component('component-textarea', {
})
Vue.component('component-select', {
props: ['class', 'placeholder', 'label', 'name', 'type', 'size', 'options', 'value', 'errors'],
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'label', 'name', 'type', 'options', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{label}}</label>' +
'<select v-model="value" @change="update($event,name)">' +
'<option v-for="option,optionkey in options" v-bind:value="optionkey">{{option}}</option>' +
'<select' +
' :id="id"' +
' :name="name"' +
' :required="required"' +
' :disabled="disabled"' +
' v-model="value"' +
' @change="update($event,name)">' +
'<option v-for="option,optionkey in options" v-bind:value="optionkey">{{option}}</option>' +
'</select>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, name)
@ -63,13 +249,21 @@ Vue.component('component-select', {
})
Vue.component('component-checkbox', {
props: ['class', 'label', 'checkboxlabel', 'name', 'type', 'value', 'errors'],
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<label class="control-group">{{ checkboxlabel }}' +
'<input type="checkbox" :name="name" v-model="value" @change="update($event, value, name)">' +
'<input type="checkbox"' +
' :id="id"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' v-model="value"' +
' @change="update($event, value, name)">' +
'<span class="checkmark"></span>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</label>' +
'</div>',
methods: {
@ -80,14 +274,50 @@ Vue.component('component-checkbox', {
},
})
Vue.component('component-checkboxlist', {
props: ['class', 'description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'options', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<label v-for="option, optionvalue in options" class="control-group">{{ option }}' +
'<input type="checkbox"' +
' :id="optionvalue"' +
' :value="optionvalue"' +
' v-model="value" ' +
' @change="update($event, value, optionvalue, name)">' +
'<span class="checkmark"></span>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</div>',
methods: {
update: function($event, value, optionvalue, name)
{
/* if value (array) for checkboxlist is not initialized yet */
if(value === true || value === false)
{
value = [optionvalue];
}
FormBus.$emit('forminput', {'name': name, 'value' : value});
},
},
})
Vue.component('component-radio', {
props: ['label', 'options', 'name', 'type', 'value', 'errors'],
template: '<div class="medium">' +
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
template: '<div class="large">' +
'<label>{{ label }}</label>' +
'<label v-for="option,optionvalue in options" class="control-group">{{ option }}' +
'<input type="radio" :name="name" :value="optionvalue" v-model="value" @change="update($event, value, name)">' +
'<input type="radio"' +
' :id="id"' +
' :readonly="readonly"' +
' :required="required"' +
' :disabled="disabled"' +
' :name="name"' +
' :value="optionvalue"' +
' v-model="value" ' +
' @change="update($event, value, name)">' +
'<span class="radiomark"></span>' +
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
'<span v-else class="fielddescription"><small>{{ description }}</small></span>' +
'</label>' +
'</div>',
methods: {
@ -167,12 +397,14 @@ let meta = new Vue({
.then(function (response) {
var formdefinitions = response.data.metadefinitions;
for (var key in formdefinitions) {
if (formdefinitions.hasOwnProperty(key)) {
self.tabs.push(key);
self.formErrors[key] = false;
}
}
self.formErrorsReset = self.formErrors;
self.formDefinitions = formdefinitions;

View File

@ -20,6 +20,9 @@
<link rel="stylesheet" href="{{ base_url }}/system/author/css/normalize.css" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/style.css?20191231" />
<link rel="stylesheet" href="{{ base_url }}/system/author/css/color-picker.min.css" />
{{ assets.renderCSS() }}
</head>
<body>
<svg style="position: absolute; width: 0; height: 0; overflow: hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
@ -56,13 +59,25 @@
</article>
<footer></footer>
</div>
<script src="{{ base_url }}/system/author/js/axios.min.js?20191124"></script>
<script>
const myaxios = axios.create();
myaxios.defaults.baseURL = "{{ base_url }}";
</script>
<script src="{{ base_url }}/system/author/js/vue.min.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/autosize.min.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/sortable.min.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/vuedraggable.umd.min.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/author.js?20191231"></script>
{{ assets.renderEditorJS() }}
<script src="{{ base_url }}/system/author/js/vue-publishcontroller.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/vue-editor.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/vue-meta.js?20191231"></script>
<script src="{{ base_url }}/system/author/js/vue-navi.js?20191231"></script>
{{ assets.renderJS() }}
</body>
</html>

View File

@ -3,19 +3,30 @@ meta:
title:
type: text
label: Meta title
size: 60
maxlength: 60
class: large
description:
type: textarea
label: Meta description
size: 160
class: large
description: If not filled, the description is extracted from content.
author:
type: text
label: author
class: large
description: Taken from your user account if set.
manualdate:
type: date
label: Manual date
modified:
type: date
label: Last modified at (readonly)
label: Last modified live (readonly)
readonly: readonly
class: large
class: medium
description: Used as fallback when no manual date is set.
created:
type: date
label: Created at (readonly)
readonly: readonly
class: medium

View File

@ -23,6 +23,22 @@
<span class="error">{{ errors.username | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.firstname ? ' errors' : '' }}">
<label for="firstname">First Name</label>
<input type="text" name="firstname" value="{{ old.firstname ? old.firstname : userdata.firstname }}">
{% if errors.firstname %}
<span class="error">{{ errors.firstname | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.lastname ? ' errors' : '' }}">
<label for="lastname">Last Name</label>
<input type="text" name="lastname" value="{{ old.lastname ? old.lastname : userdata.lastname }}">
{% if errors.lastname %}
<span class="error">{{ errors.lastname | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.email ? ' errors' : '' }}">
<label for="email">E-Mail <abbr title="required">*</abbr></label>
@ -48,7 +64,7 @@
<div class="large{{ errors.password ? ' errors' : '' }}">
<label for="password">Actual Password</label>
<input type="password" name="password">
<input type="password" name="password" autocomplete="off">
{% if errors.password %}
<span class="error">{{ errors.password | first }}</span>
{% endif %}
@ -56,7 +72,7 @@
<div class="large{{ errors.newpassword ? ' errors' : '' }}">
<label for="newpassword">New Password</label>
<input type="password" name="newpassword">
<input type="password" name="newpassword" autocomplete="off">
{% if errors.newpassword %}
<span class="error">{{ errors.newpassword | first }}</span>
{% endif %}

View File

@ -22,7 +22,23 @@
<span class="error">{{ errors.username | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.firstname ? ' errors' : '' }}">
<label for="firstname">First Name</label>
<input type="text" name="firstname" value="{{ old.firstname ? old.firstname : userdata.firstname }}">
{% if errors.firstname %}
<span class="error">{{ errors.firstname | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.lastname ? ' errors' : '' }}">
<label for="lastname">Last Name</label>
<input type="text" name="lastname" value="{{ old.lastname ? old.lastname : userdata.lastname }}">
{% if errors.lastname %}
<span class="error">{{ errors.lastname | first }}</span>
{% endif %}
</div>
<div class="large{{ errors.email ? ' errors' : '' }}">
<label for="email">E-Mail <abbr title="required">*</abbr></label>
<input type="text" name="email" value="{{ old.email ? old.email : '' }}" required>
@ -45,7 +61,7 @@
<div class="large{{ errors.password ? ' errors' : '' }}">
<label for="password">Password <abbr title="required">*</abbr></label>
<input type="password" name="password" required>
<input type="password" name="password" autocomplete="off" required>
{% if errors.password %}
<span class="error">{{ errors.password | first }}</span>
{% endif %}

View File

@ -1,3 +1,5 @@
{% set published = metatabs.meta.manualdate ? metatabs.meta.manualdate : metatabs.meta.modified %}
{% if content is empty %}
<h1>{{ item.name }}</h1>
@ -9,10 +11,10 @@
{% if (settings.themes.typemill.socialPosition.top or settings.themes.typemill.modifiedPosition.top or settings.themes.typemill.authorPosition.top or settings.themes.typemill.gitPosition.top) %}
<div class="meta-info">
{% if settings.themes.typemill.authorPosition.top %}
<small>{{ settings.themes.typemill.authorIntro }}: {{ settings.author }}</small>
<small>{{ settings.themes.typemill.authorIntro }}: {{ metatabs.meta.author|default(settings.author) }}</small>
{% endif %}
{% if settings.themes.typemill.modifiedPosition.top %}
<small>{{ settings.themes.typemill.modifiedText }}: {{ metatabs.meta.modified|date(settings.themes.typemill.modifiedFormat) }}</small>
<small>{{ settings.themes.typemill.modifiedText }}: {{ published|date(settings.themes.typemill.modifiedFormat) }}</small>
{% endif %}
{% if settings.themes.typemill.socialPosition.top %}
<div id="share-icons" class="share-icons hide">
@ -34,10 +36,10 @@
{% if (settings.themes.typemill.socialPosition.bottom or settings.themes.typemill.modifiedPosition.bottom or settings.themes.typemill.authorPosition.bottom or settings.themes.typemill.gitPosition.bottom) %}
<div class="meta-info">
{% if settings.themes.typemill.authorPosition.bottom %}
<small>{{ settings.themes.typemill.authorIntro }}: {{ settings.author }}</small>
<small>{{ settings.themes.typemill.authorIntro }}: {{ metatabs.meta.author|default(settings.author) }}</small>
{% endif %}
{% if settings.themes.typemill.modifiedPosition.bottom %}
<small>{{ settings.themes.typemill.modifiedText }}: {{ metatabs.meta.modified|date(settings.themes.typemill.modifiedFormat) }}</small>
<small>{{ settings.themes.typemill.modifiedText }}: {{ published|date(settings.themes.typemill.modifiedFormat) }}</small>
{% endif %}
{% if settings.themes.typemill.socialPosition.bottom %}
<div id="share-icons-bottom" class="share-icons hide">

View File

@ -69,6 +69,7 @@
<script src="{{ base_url }}/themes/typemill/js/script.js"></script>
<script src="{{ base_url }}/system/author/js/lazy-video.js?20190602"></script>
<script>typemillUtilities.start();</script>
{{ assets.renderJS() }}
{% endblock %}

View File

@ -1,5 +1,5 @@
name: Typemill Theme
version: 1.2.0
version: 1.2.1
description: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. No JavaScript is used.
author: Sebastian Schürmanns
homepage: https://typemill.net