mirror of
https://github.com/typemill/typemill.git
synced 2025-07-17 12:31:13 +02:00
Version 1.4.8: fieldsets for vue formbuilder
This commit is contained in:
@@ -29,8 +29,7 @@ class MetaApiController extends ContentController
|
||||
# the fields for user or role based access
|
||||
if(!isset($this->settings['pageaccess']) || $this->settings['pageaccess'] === NULL )
|
||||
{
|
||||
unset($metatabs['meta']['fields']['alloweduser']);
|
||||
unset($metatabs['meta']['fields']['allowedrole']);
|
||||
unset($metatabs['meta']['fields']['fieldsetrights']);
|
||||
}
|
||||
|
||||
# add radio buttons to choose posts or pages for folder.
|
||||
@@ -124,11 +123,12 @@ class MetaApiController extends ContentController
|
||||
{
|
||||
$metadata[$tabname] = [];
|
||||
|
||||
foreach($tab['fields'] as $fieldname => $fielddefinitions)
|
||||
$tab = $this->flattenTabFields($tab['fields'],[]);
|
||||
|
||||
foreach($tab as $fieldname => $fielddefinitions)
|
||||
{
|
||||
$metascheme[$tabname][$fieldname] = true;
|
||||
$metadata[$tabname][$fieldname] = isset($pagemeta[$tabname][$fieldname]) ? $pagemeta[$tabname][$fieldname] : null;
|
||||
|
||||
|
||||
# check if there is a selectfield for userroles
|
||||
if(isset($fielddefinitions['type']) && ($fielddefinitions['type'] == 'select' ) && isset($fielddefinitions['dataset']) && ($fielddefinitions['dataset'] == 'userroles' ) )
|
||||
@@ -214,6 +214,8 @@ class MetaApiController extends ContentController
|
||||
$metaDefinitions = $this->aggregateMetaDefinitions();
|
||||
}
|
||||
|
||||
$tabFieldDefinitions = $this->flattenTabFields($metaDefinitions[$tab]['fields'], []);
|
||||
|
||||
# create validation object
|
||||
$validate = $this->getValidator();
|
||||
|
||||
@@ -221,7 +223,7 @@ class MetaApiController extends ContentController
|
||||
foreach($metaInput as $fieldName => $fieldValue)
|
||||
{
|
||||
# get the corresponding field definition from original plugin settings */
|
||||
$fieldDefinition = isset($metaDefinitions[$tab]['fields'][$fieldName]) ? $metaDefinitions[$tab]['fields'][$fieldName] : false;
|
||||
$fieldDefinition = isset($tabFieldDefinitions[$fieldName]) ? $tabFieldDefinitions[$fieldName] : false;
|
||||
|
||||
if(!$fieldDefinition)
|
||||
{
|
||||
@@ -379,6 +381,24 @@ class MetaApiController extends ContentController
|
||||
return $response->withJson(array('metadata' => $metaInput, 'structure' => $structure, 'item' => $this->item, 'errors' => false));
|
||||
}
|
||||
|
||||
# we have to flatten field definitions for tabs if there are fieldsets in it
|
||||
public function flattenTabFields($tabfields, $flattab)
|
||||
{
|
||||
foreach($tabfields as $name => $field)
|
||||
{
|
||||
if($field['type'] == 'fieldset')
|
||||
{
|
||||
$flattab = $this->flattenTabFields($field['fields'], $flattab);
|
||||
}
|
||||
else
|
||||
{
|
||||
$flattab[$name] = $field;
|
||||
}
|
||||
}
|
||||
return $flattab;
|
||||
}
|
||||
|
||||
|
||||
# can be deleted ??
|
||||
private function customfieldsPrepareForEdit($customfields)
|
||||
{
|
||||
|
@@ -1021,6 +1021,17 @@ fieldset{
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
fieldset.fs-formbuilder{
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
margin: 20px;
|
||||
width: auto;
|
||||
}
|
||||
fieldset.fs-formbuilder legend{
|
||||
float: none;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
label,.label{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
|
@@ -11,9 +11,9 @@ Vue.filter('translate', function (value) {
|
||||
}
|
||||
})
|
||||
|
||||
Vue.component('tab-meta', {
|
||||
Vue.component('tab-metaoriginal', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema', 'userroles'],
|
||||
template: '<section><form>' +
|
||||
template: '<section><form>original' +
|
||||
'<component v-for="(field, index) in schema.fields"' +
|
||||
':key="index"' +
|
||||
':is="selectComponent(field)"' +
|
||||
@@ -39,6 +39,65 @@ Vue.component('tab-meta', {
|
||||
}
|
||||
})
|
||||
|
||||
Vue.component('tab-meta', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema', 'userroles'],
|
||||
template: '<section><form>' +
|
||||
'<div v-for="(field, index) in schema.fields" :class="getFieldClass(field)">' +
|
||||
'<fieldset class="fs-formbuilder" v-if="field.type == \'fieldset\'"><legend>{{field.legend}}</legend>' +
|
||||
'<component v-for="(subfield, index) in field.fields "' +
|
||||
' :key="index"' +
|
||||
' :class="getFieldClass(subfield)"' +
|
||||
' :is="selectComponent(subfield)"' +
|
||||
' :errors="errors"' +
|
||||
' :name="index"' +
|
||||
' :userroles="userroles"' +
|
||||
' v-model="formdata[index]"' +
|
||||
' v-bind="subfield">' +
|
||||
'</component>' +
|
||||
'</fieldset>' +
|
||||
'<component v-else' +
|
||||
' :key="index"' +
|
||||
' :is="selectComponent(field)"' +
|
||||
' :errors="errors"' +
|
||||
' :name="index"' +
|
||||
' :userroles="userroles"' +
|
||||
' v-model="formdata[index]"' +
|
||||
' v-bind="field">' +
|
||||
'</component>' +
|
||||
'</div>' +
|
||||
'<div v-if="saved" class="metaLarge"><div class="metaSuccess">{{ \'Saved successfully\'|translate }}</div></div>' +
|
||||
'<div v-if="errors" class="metaLarge"><div class="metaErrors">{{ \'Please correct the errors above\'|translate }}</div></div>' +
|
||||
'<div class="large"><input type="submit" @click.prevent="saveInput" :value="\'save\'|translate"></input></div>' +
|
||||
'</form></section>',
|
||||
methods: {
|
||||
selectComponent: function(field)
|
||||
{
|
||||
return 'component-'+field.type;
|
||||
},
|
||||
saveInput: function()
|
||||
{
|
||||
this.$emit('saveform');
|
||||
},
|
||||
getFieldClass: function(field)
|
||||
{
|
||||
if(field.type == 'fieldset')
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if(field.class === undefined )
|
||||
{
|
||||
return 'large';
|
||||
}
|
||||
else
|
||||
{
|
||||
var fieldclass = field.class;
|
||||
delete field.class;
|
||||
return fieldclass;
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
let meta = new Vue({
|
||||
delimiters: ['${', '}'],
|
||||
el: '#metanav',
|
||||
@@ -75,18 +134,18 @@ let meta = new Vue({
|
||||
|
||||
var self = this;
|
||||
|
||||
myaxios.get('/api/v1/article/metaobject',{
|
||||
params: {
|
||||
myaxios.get('/api/v1/article/metaobject',{
|
||||
params: {
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
.then(function (response) {
|
||||
|
||||
var formdefinitions = response.data.metadefinitions;
|
||||
var formdefinitions = response.data.metadefinitions;
|
||||
|
||||
for (var key in formdefinitions) {
|
||||
for (var key in formdefinitions) {
|
||||
if (formdefinitions.hasOwnProperty(key)) {
|
||||
self.tabs.push(key);
|
||||
self.formErrors[key] = false;
|
||||
@@ -96,36 +155,37 @@ let meta = new Vue({
|
||||
self.formErrorsReset = self.formErrors;
|
||||
self.formDefinitions = formdefinitions;
|
||||
|
||||
self.formData = response.data.metadata;
|
||||
self.formData = response.data.metadata;
|
||||
|
||||
self.userroles = response.data.userroles;
|
||||
self.userroles = response.data.userroles;
|
||||
|
||||
self.item = response.data.item;
|
||||
if(self.item.elementType == "folder" && self.item.contains == "posts")
|
||||
{
|
||||
posts.posts = self.item.folderContent;
|
||||
posts.folderid = self.item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
}
|
||||
});
|
||||
self.item = response.data.item;
|
||||
|
||||
if(self.item.elementType == "folder" && self.item.contains == "posts")
|
||||
{
|
||||
posts.posts = self.item.folderContent;
|
||||
posts.folderid = self.item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
/* update single value or array
|
||||
this.$set(this.someObject, 'b', 2) */
|
||||
/* update single value or array
|
||||
this.$set(this.someObject, 'b', 2) */
|
||||
FormBus.$on('forminput', formdata => {
|
||||
this.$set(this.formData[this.currentTab], formdata.name, formdata.value);
|
||||
});
|
||||
|
||||
/* update values that are objects
|
||||
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) */
|
||||
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) */
|
||||
|
||||
FormBus.$on('forminputobject', formdata => {
|
||||
this.formData[this.currentTab][formdata.name] = Object.assign({}, this.formData[this.currentTab][formdata.name], formdata.value);
|
||||
@@ -138,43 +198,43 @@ let meta = new Vue({
|
||||
|
||||
self = this;
|
||||
|
||||
myaxios.post('/api/v1/article/metadata',{
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
'tab': self.currentTab,
|
||||
'data': self.formData[self.currentTab]
|
||||
myaxios.post('/api/v1/article/metadata',{
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
'tab': self.currentTab,
|
||||
'data': self.formData[self.currentTab]
|
||||
})
|
||||
.then(function (response) {
|
||||
self.saved = true;
|
||||
self.formErrors = self.formErrorsReset;
|
||||
if(response.data.structure)
|
||||
{
|
||||
navi.items = response.data.structure;
|
||||
}
|
||||
.then(function (response) {
|
||||
self.saved = true;
|
||||
self.formErrors = self.formErrorsReset;
|
||||
if(response.data.structure)
|
||||
{
|
||||
navi.items = response.data.structure;
|
||||
}
|
||||
|
||||
var item = response.data.item;
|
||||
if(item.elementType == "folder" && item.contains == "posts")
|
||||
{
|
||||
posts.posts = item.folderContent;
|
||||
posts.folderid = item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
self.formErrors = error.response.data.errors;
|
||||
}
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
var item = response.data.item;
|
||||
if(item.elementType == "folder" && item.contains == "posts")
|
||||
{
|
||||
posts.posts = item.folderContent;
|
||||
posts.folderid = item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
self.formErrors = error.response.data.errors;
|
||||
}
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
@@ -1,6 +1,6 @@
|
||||
Vue.component('component-text', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'hidden', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'hidden', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="text"' +
|
||||
' :id="id"' +
|
||||
@@ -25,7 +25,7 @@ Vue.component('component-text', {
|
||||
})
|
||||
|
||||
Vue.component('component-hidden', {
|
||||
props: ['class', 'id', 'maxlength', 'required', 'disabled', 'name', 'type', 'value', 'errors'],
|
||||
props: ['id', 'maxlength', 'required', 'disabled', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="hidden">' +
|
||||
'<input type="hidden"' +
|
||||
' :id="id"' +
|
||||
@@ -43,13 +43,13 @@ Vue.component('component-hidden', {
|
||||
})
|
||||
|
||||
Vue.component('component-textarea', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
data: function () {
|
||||
return {
|
||||
textareaclass: ''
|
||||
}
|
||||
},
|
||||
template: '<div class="large">' +
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<textarea rows="8" ' +
|
||||
' :id="id"' +
|
||||
@@ -82,8 +82,8 @@ Vue.component('component-textarea', {
|
||||
})
|
||||
|
||||
Vue.component('component-url', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="url"' +
|
||||
' :id="id"' +
|
||||
@@ -107,8 +107,8 @@ Vue.component('component-url', {
|
||||
})
|
||||
|
||||
Vue.component('component-number', {
|
||||
props: ['class', 'id', 'description', 'min', 'max', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'min', 'max', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="number"' +
|
||||
' :id="id"' +
|
||||
@@ -134,8 +134,8 @@ Vue.component('component-number', {
|
||||
})
|
||||
|
||||
Vue.component('component-email', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="email"' +
|
||||
' :id="id"' +
|
||||
@@ -159,8 +159,8 @@ Vue.component('component-email', {
|
||||
})
|
||||
|
||||
Vue.component('component-tel', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="tel"' +
|
||||
' :id="id"' +
|
||||
@@ -184,8 +184,8 @@ Vue.component('component-tel', {
|
||||
})
|
||||
|
||||
Vue.component('component-password', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="password"' +
|
||||
' :id="id"' +
|
||||
@@ -209,8 +209,8 @@ Vue.component('component-password', {
|
||||
})
|
||||
|
||||
Vue.component('component-date', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="date" ' +
|
||||
' :id="id"' +
|
||||
@@ -233,8 +233,8 @@ Vue.component('component-date', {
|
||||
})
|
||||
|
||||
Vue.component('component-color', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'maxlength', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<input type="color" ' +
|
||||
' :id="id"' +
|
||||
@@ -257,8 +257,8 @@ Vue.component('component-color', {
|
||||
})
|
||||
|
||||
Vue.component('component-select', {
|
||||
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'label', 'name', 'type', 'options', 'value', 'errors', 'dataset', 'userroles'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'readonly', 'required', 'disabled', 'label', 'name', 'type', 'options', 'value', 'errors', 'dataset', 'userroles'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<select' +
|
||||
' :id="id"' +
|
||||
@@ -281,8 +281,8 @@ Vue.component('component-select', {
|
||||
})
|
||||
|
||||
Vue.component('component-checkbox', {
|
||||
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<label class="control-group">{{ checkboxlabel|translate }}' +
|
||||
'<input type="checkbox"' +
|
||||
@@ -307,8 +307,8 @@ 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">' +
|
||||
props: ['description', 'readonly', 'required', 'disabled', 'label', 'checkboxlabel', 'options', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<label v-for="option, optionvalue in options" class="control-group">{{ option }}' +
|
||||
'<input type="checkbox"' +
|
||||
@@ -335,8 +335,8 @@ Vue.component('component-checkboxlist', {
|
||||
})
|
||||
|
||||
Vue.component('component-radio', {
|
||||
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large">' +
|
||||
props: ['id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div>' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<label v-for="option,optionvalue in options" class="control-group">{{ option }}' +
|
||||
'<input type="radio"' +
|
||||
@@ -362,7 +362,7 @@ Vue.component('component-radio', {
|
||||
})
|
||||
|
||||
Vue.component('component-customfields', {
|
||||
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
|
||||
props: ['id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
|
||||
data: function () {
|
||||
return {
|
||||
fielderrors: false,
|
||||
@@ -371,7 +371,7 @@ Vue.component('component-customfields', {
|
||||
cfvalue: [{}]
|
||||
}
|
||||
},
|
||||
template: '<div class="large">' +
|
||||
template: '<div>' +
|
||||
'<label class="mb2">{{ label|translate }}</label>' +
|
||||
'<div class="fielddescription mb2 f7">{{ description|translate }}</div>' +
|
||||
'<div v-if="errors[name]" class="error mb2 f7">{{ errors[name] }}</div>' +
|
||||
@@ -489,7 +489,7 @@ Vue.component('component-customfields', {
|
||||
})
|
||||
|
||||
Vue.component('component-image', {
|
||||
props: ['class', 'id', 'description', 'maxlength', 'hidden', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
props: ['id', 'description', 'maxlength', 'hidden', 'readonly', 'required', 'disabled', 'placeholder', 'label', 'name', 'type', 'value', 'errors'],
|
||||
template: '<div class="large img-component">' +
|
||||
'<label>{{ label|translate }}</label>' +
|
||||
'<div class="flex flex-wrap item-start">' +
|
||||
|
@@ -1,75 +1,95 @@
|
||||
meta:
|
||||
fields:
|
||||
title:
|
||||
type: text
|
||||
label: Meta title
|
||||
maxlength: 60
|
||||
class: large
|
||||
description:
|
||||
type: textarea
|
||||
label: Meta description
|
||||
size: 160
|
||||
class: large
|
||||
description: If not filled, the description is extracted from content.
|
||||
heroimage:
|
||||
type: image
|
||||
label: Hero Image
|
||||
description: Maximum size for an image is 5 MB. Hero images are not supported by all themes.
|
||||
heroimagealt:
|
||||
type: text
|
||||
label: Alternative Text for the hero image
|
||||
owner:
|
||||
type: text
|
||||
label: owner (username)
|
||||
class: medium
|
||||
description: Has edit rights for this article.
|
||||
author:
|
||||
type: text
|
||||
label: author
|
||||
class: medium
|
||||
description: Can be used for author line in frontend.
|
||||
manualdate:
|
||||
type: date
|
||||
label: Manual date
|
||||
modified:
|
||||
type: date
|
||||
label: Last modified live (readonly)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
description: Used as fallback when no manual date is set.
|
||||
created:
|
||||
type: date
|
||||
label: Created at (read only)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
time:
|
||||
type: text
|
||||
readonly: readonly
|
||||
hidden: true
|
||||
class: hidden
|
||||
pattern: '[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
|
||||
navtitle:
|
||||
type: text
|
||||
label: Navigation Title
|
||||
class: medium
|
||||
maxlength: 60
|
||||
hide:
|
||||
type: checkbox
|
||||
label: Hide
|
||||
checkboxlabel: Hide page from navigation
|
||||
class: medium
|
||||
allowedrole:
|
||||
type: select
|
||||
label: For access the user must have this minimum role
|
||||
class: medium
|
||||
dataset: userroles
|
||||
options:
|
||||
description: Select the lowest userrole. Higher roles will have access too.
|
||||
alloweduser:
|
||||
type: text
|
||||
label: Only the following users have access
|
||||
class: medium
|
||||
description: Add one or more usernames separated with comma.
|
||||
fieldsetcontent:
|
||||
type: fieldset
|
||||
legend: Meta-Content
|
||||
fields:
|
||||
title:
|
||||
type: text
|
||||
label: Meta title
|
||||
maxlength: 60
|
||||
class: large
|
||||
description:
|
||||
type: textarea
|
||||
label: Meta description
|
||||
size: 160
|
||||
class: large
|
||||
description: If not filled, the description is extracted from content.
|
||||
heroimage:
|
||||
type: image
|
||||
label: Hero Image
|
||||
description: Maximum size for an image is 5 MB. Hero images are not supported by all themes.
|
||||
heroimagealt:
|
||||
type: text
|
||||
label: Alternative Text for the hero image
|
||||
fieldsetauthor:
|
||||
type: fieldset
|
||||
legend: Author
|
||||
fields:
|
||||
owner:
|
||||
type: text
|
||||
label: owner (username)
|
||||
class: medium
|
||||
description: Has edit rights for this article.
|
||||
author:
|
||||
type: text
|
||||
label: author
|
||||
class: medium
|
||||
description: Can be used for author line in frontend.
|
||||
fieldsetrights:
|
||||
type: fieldset
|
||||
legend: Access & Rights
|
||||
fields:
|
||||
allowedrole:
|
||||
type: select
|
||||
label: For access the user must have this minimum role
|
||||
class: medium
|
||||
dataset: userroles
|
||||
options:
|
||||
description: Select the lowest userrole. Higher roles will have access too.
|
||||
alloweduser:
|
||||
type: text
|
||||
label: Only the following users have access
|
||||
class: medium
|
||||
description: Add one or more usernames separated with comma.
|
||||
fieldsetpubdate:
|
||||
type: fieldset
|
||||
legend: Article Date
|
||||
fields:
|
||||
manualdate:
|
||||
type: date
|
||||
label: Manual date
|
||||
modified:
|
||||
type: date
|
||||
label: Last modified live (readonly)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
description: Used as fallback when no manual date is set.
|
||||
created:
|
||||
type: date
|
||||
label: Created at (read only)
|
||||
readonly: readonly
|
||||
class: medium
|
||||
time:
|
||||
type: text
|
||||
readonly: readonly
|
||||
hidden: true
|
||||
class: hidden
|
||||
pattern: '[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
|
||||
fieldsetnavi:
|
||||
type: fieldset
|
||||
legend: Navigation
|
||||
fields:
|
||||
navtitle:
|
||||
type: text
|
||||
label: Navigation Title
|
||||
class: medium
|
||||
maxlength: 60
|
||||
hide:
|
||||
type: checkbox
|
||||
label: Hide
|
||||
checkboxlabel: Hide page from navigation
|
||||
class: medium
|
||||
contains:
|
||||
type: radio
|
||||
label: This folder contains
|
||||
|
@@ -36,7 +36,7 @@
|
||||
|
||||
{% block stylesheets %}
|
||||
|
||||
<link rel="stylesheet" href="{{ base_url }}/themes/cyanine/css/style.css??20210806" />
|
||||
<link rel="stylesheet" href="{{ base_url }}/themes/cyanine/css/style.css??20210807" />
|
||||
|
||||
<style>
|
||||
|
||||
|
Reference in New Issue
Block a user