mirror of
https://github.com/typemill/typemill.git
synced 2025-08-05 05:37:45 +02:00
Version 1.4.1: Custom Fields half ready
This commit is contained in:
29
plugins/adamhall/adamhall.php
Normal file
29
plugins/adamhall/adamhall.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Plugins\Adamhall;
|
||||
|
||||
use Typemill\Plugin;
|
||||
|
||||
class Adamhall extends Plugin
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
'onTwigLoaded' => 'onTwigLoaded',
|
||||
'onMetaLoaded' => 'onMetaLoaded'
|
||||
);
|
||||
}
|
||||
|
||||
public function onTwigLoaded()
|
||||
{
|
||||
$this->addEditorJS('/adamhall/js/adamhall.js');
|
||||
}
|
||||
|
||||
public function onMetaLoaded($meta)
|
||||
{
|
||||
$meta = $meta->getData();
|
||||
|
||||
# do something with the fields:
|
||||
$myTabInformation = $meta['mytab'];
|
||||
}
|
||||
}
|
15
plugins/adamhall/adamhall.yaml
Normal file
15
plugins/adamhall/adamhall.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Adam Hall Plugin
|
||||
version: 1.0.0
|
||||
description: Plugin for Adam Hall that integrates Custom Fields
|
||||
author: Sebastian Schürmanns
|
||||
homepage: http://trendschau.net
|
||||
licence: Owned by Adam Hall
|
||||
|
||||
metatabs:
|
||||
adamhall:
|
||||
fields:
|
||||
myfield:
|
||||
type: customfields
|
||||
label: Simple Custom Field
|
||||
description: Please add some custom fields
|
||||
data: array
|
26
plugins/adamhall/js/adamhall.js
Normal file
26
plugins/adamhall/js/adamhall.js
Normal file
@@ -0,0 +1,26 @@
|
||||
Vue.component('tab-adamhall', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema'],
|
||||
template: '<section><form>' +
|
||||
'<component v-for="(field, index) in schema.fields"' +
|
||||
':key="index"' +
|
||||
':is="selectComponent(field)"' +
|
||||
':errors="errors"' +
|
||||
':name="index"' +
|
||||
'v-model="formdata[index]"' +
|
||||
'v-bind="field">' +
|
||||
'</component>' +
|
||||
'<div v-if="saved" class="metaLarge"><div class="metaSuccess">Saved successfully</div></div>' +
|
||||
'<div v-if="errors" class="metaLarge"><div class="metaErrors">Please correct the errors above</div></div>' +
|
||||
'<div class="large"><input type="submit" @click.prevent="saveInput" value="save"></input></div>' +
|
||||
'</form></section>',
|
||||
methods: {
|
||||
selectComponent: function(field)
|
||||
{
|
||||
return 'component-'+field.type;
|
||||
},
|
||||
saveInput: function()
|
||||
{
|
||||
this.$emit('saveform');
|
||||
},
|
||||
}
|
||||
})
|
@@ -122,6 +122,28 @@ class MetaApiController extends ContentController
|
||||
{
|
||||
$metascheme[$tabname][$fieldname] = true;
|
||||
$metadata[$tabname][$fieldname] = isset($pagemeta[$tabname][$fieldname]) ? $pagemeta[$tabname][$fieldname] : null;
|
||||
|
||||
# special treatment for customfields
|
||||
if(isset($fielddefinitions['type']) && ($fielddefinitions['type'] == 'customfields' ) )
|
||||
{
|
||||
# loop through the customdata
|
||||
foreach($metadata[$tabname][$fieldname] as $key => $value)
|
||||
{
|
||||
# and make sure that arrays are transformed back into strings
|
||||
if(isset($value['value']) && is_array($value['value']))
|
||||
{
|
||||
$valuestring = implode('\n',$value['value']);
|
||||
$metadata[$tabname][$fieldname][$key]['value'] = $valuestring;
|
||||
}
|
||||
}
|
||||
/*
|
||||
echo 'fielddefinition: <pre>';
|
||||
print_r($fielddefinitions);
|
||||
echo '</pre>metadata: <pre>';
|
||||
print_r($pagemeta[$tabname][$fieldname]);
|
||||
die();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +230,21 @@ class MetaApiController extends ContentController
|
||||
{
|
||||
$errors[$tab][$fieldName] = $result[$fieldName][0];
|
||||
}
|
||||
|
||||
# special treatment for customfields
|
||||
if($fieldDefinition && isset($fieldDefinition['type']) && ($fieldDefinition['type'] == 'customfields' ) && isset($fieldDefinition['data']) && ($fieldDefinition['data'] == 'array' ) )
|
||||
{
|
||||
foreach($fieldValue as $key => $valuePair)
|
||||
{
|
||||
if(isset($valuePair['value']))
|
||||
{
|
||||
$arrayValues = explode(PHP_EOL,$valuePair['value']);
|
||||
echo '<pre>';
|
||||
print_r($arrayValues);
|
||||
}
|
||||
}
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -63,6 +63,23 @@ class Validation
|
||||
return true;
|
||||
}, 'contains one or more invalid ip-adress');
|
||||
|
||||
Validator::addRule('customfields', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
foreach($value as $customfield)
|
||||
{
|
||||
if(!isset($customfield['key']) OR empty($customfield['key']) OR (preg_match('/^([a-z0-9])+$/i', $customfield['key']) == false) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($customfield['value']) OR empty($customfield['value']) OR ( $customfield['value'] != strip_tags($customfield['value']) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, 'contains one or more invalid values');
|
||||
|
||||
Validator::addRule('checkPassword', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$userdata = $user->getUser($fields['username']);
|
||||
@@ -459,6 +476,10 @@ class Validation
|
||||
$v->rule('lengthMax', $fieldName, 1000);
|
||||
$v->rule('image_types', $fieldName);
|
||||
break;
|
||||
case "customfields":
|
||||
$v->rule('array', $fieldName);
|
||||
$v->rule('customfields', $fieldName);
|
||||
break;
|
||||
default:
|
||||
$v->rule('lengthMax', $fieldName, 1000);
|
||||
$v->rule('regex', $fieldName, '/^[\pL0-9_ \-]*$/u');
|
||||
|
@@ -128,6 +128,9 @@ input.upload{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* fix wrong text-align/family */
|
||||
input, textarea, button {font-family: arial, sans-serif}
|
||||
|
||||
/****************************
|
||||
* download-commponent *
|
||||
****************************/
|
||||
@@ -1280,6 +1283,16 @@ span.error{
|
||||
background: #70c1b3;
|
||||
}
|
||||
|
||||
/********************
|
||||
* Customfields *
|
||||
********************/
|
||||
|
||||
.customkey{
|
||||
width: 29%;
|
||||
}
|
||||
.customvalue{
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
/********************
|
||||
* UPDATE-BANNER *
|
||||
|
@@ -1248,13 +1248,13 @@ const definitionComponent = Vue.component('definition-component', {
|
||||
template: '<div class="definitionList">' +
|
||||
'<div class="contenttype"><svg class="icon icon-dots-two-vertical"><use xlink:href="#icon-dots-two-vertical"></use></svg></div>' +
|
||||
'<draggable v-model="definitionList" :animation="150" @end="moveDefinition">' +
|
||||
'<div class="definitionRow" v-for="(definition, dindex) in definitionList" :key="definition.id">' +
|
||||
'<div class="definitionRow" v-for="(definition, dindex) in definitionList" :key="definition.id">' +
|
||||
'<svg class="icon icon-arrows-v"><use xlink:href="#icon-arrows-v"></use></svg>' +
|
||||
'<input type="text" class="definitionTerm" v-bind:placeholder="\'term\'|translate" :value="definition.term" :disabled="disabled" @input="updateterm($event,dindex)" @blur="updateMarkdown">' +
|
||||
'<svg class="icon icon-dots-two-vertical"><use xlink:href="#icon-dots-two-vertical"></use></svg>' +
|
||||
'<textarea class="definitionDescription" v-bind:placeholder="\'description\'|translate" v-html="definition.description" :disabled="disabled" @input="updatedescription($event, dindex)" @keydown.13.prevent="enter" @blur="updateMarkdown"></textarea>' +
|
||||
'<button class="delDL" @click.prevent="deleteDefinition(dindex)"><svg class="icon icon-minus"><use xlink:href="#icon-minus"></use></svg></button>' +
|
||||
'</div>' +
|
||||
'<svg class="icon icon-dots-two-vertical"><use xlink:href="#icon-dots-two-vertical"></use></svg>' +
|
||||
'<textarea class="definitionDescription" v-bind:placeholder="\'description\'|translate" v-html="definition.description" :disabled="disabled" @input="updatedescription($event, dindex)" @keydown.13.prevent="enter" @blur="updateMarkdown"></textarea>' +
|
||||
'<button class="delDL" @click.prevent="deleteDefinition(dindex)"><svg class="icon icon-minus"><use xlink:href="#icon-minus"></use></svg></button>' +
|
||||
'</div>' +
|
||||
'</draggable>' +
|
||||
'<button class="addDL" @click.prevent="addDefinition()"><svg class="icon icon-plus"><use xlink:href="#icon-plus"></use></svg> {{ \'add definition\'|translate }}</button>' +
|
||||
'<div v-if="load" class="loadwrapper"><span class="load"></span></div>' +
|
||||
|
@@ -332,6 +332,7 @@ Vue.component('component-checkboxlist', {
|
||||
'<span class="checkmark"></span>' +
|
||||
'<span v-if="errors[name]" class="error">{{ errors[name] }}</span>' +
|
||||
'<span v-else class="fielddescription"><small>{{ description|translate }}</small></span>' +
|
||||
'</label>' +
|
||||
'</div>',
|
||||
methods: {
|
||||
update: function($event, value, optionvalue, name)
|
||||
@@ -373,6 +374,92 @@ Vue.component('component-radio', {
|
||||
},
|
||||
})
|
||||
|
||||
Vue.component('component-customfields', {
|
||||
props: ['class', 'id', 'description', 'readonly', 'required', 'disabled', 'options', 'label', 'name', 'type', 'value', 'errors'],
|
||||
data: function () {
|
||||
return {
|
||||
fielderrors: false,
|
||||
fielddetails: {},
|
||||
}
|
||||
},
|
||||
|
||||
template: '<div class="large">' +
|
||||
'<label class="mb2">{{ label|translate }}</label>' +
|
||||
'<div v-if="fielderrors" class="error mb2"><small>{{ fielderrors }}</small></div>' +
|
||||
'<div v-else="description" class="fielddescription mb2"><small>{{ description|translate }}</small></div>' +
|
||||
'<div class="customrow flex items-start mb3" v-for="(pairobject, pairindex) in value">' +
|
||||
'<input type="text" placeholder="key" class="customkey" :class="pairobject.keyerror" :value="pairobject.key" @input="updatePairKey(pairindex,$event)">' +
|
||||
'<div class="mt3"><svg class="icon icon-dots-two-vertical"><use xlink:href="#icon-dots-two-vertical"></use></svg></div>' +
|
||||
'<textarea placeholder="value" class="customvalue pa3" :class="pairobject.valueerror" v-html="pairobject.value" @input="updatePairValue(pairindex,$event)"></textarea>' +
|
||||
'<button class="bg-tm-red white bn ml2 h1 w2 br1" @click.prevent="deleteField(pairindex)"><svg class="icon icon-minus"><use xlink:href="#icon-minus"></use></svg></button>' +
|
||||
'</div>' +
|
||||
'<button class="bg-tm-green white bn br1 pa2 f6" @click.prevent="addField()"><svg class="icon icon-plus f7"><use xlink:href="#icon-plus"></use></svg> Add Fields</button>' +
|
||||
'</div>',
|
||||
mounted: function(){
|
||||
|
||||
if(this.value === null)
|
||||
{
|
||||
this.value = [{}];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update: function(value, name)
|
||||
{
|
||||
FormBus.$emit('forminput', {'name': name, 'value': value});
|
||||
},
|
||||
updatePairKey: function(index,event)
|
||||
{
|
||||
this.value[index].key = event.target.value;
|
||||
|
||||
var regex = /^[a-z0-9]+$/i;
|
||||
if(regex.test(event.target.value))
|
||||
{
|
||||
this.fielderrors = false;
|
||||
delete this.value[index].keyerror;
|
||||
this.update(this.value,this.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.value[index].keyerror = 'red';
|
||||
this.fielderrors = 'Only alphanumeric for keys allowed';
|
||||
}
|
||||
},
|
||||
updatePairValue: function(index, event)
|
||||
{
|
||||
this.value[index].value = event.target.value;
|
||||
|
||||
var regex = /<.*(?=>)/gm;
|
||||
if(event.target.value == '' || regex.test(event.target.value))
|
||||
{
|
||||
this.value[index].valueerror = 'red';
|
||||
this.fielderrors = 'No empty values or html tags are allowed';
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fielderrors = false;
|
||||
delete this.value[index].valueerror;
|
||||
this.update(this.value,this.name);
|
||||
}
|
||||
},
|
||||
addField: function()
|
||||
{
|
||||
for(object in this.value)
|
||||
{
|
||||
if(Object.keys(this.value[object]).length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.value.push({});
|
||||
},
|
||||
deleteField: function(index)
|
||||
{
|
||||
this.value.splice(index,1);
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Vue.component('tab-meta', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema'],
|
||||
template: '<section><form>' +
|
||||
@@ -473,9 +560,18 @@ let meta = new Vue({
|
||||
}
|
||||
});
|
||||
|
||||
/* 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 }) */
|
||||
|
||||
FormBus.$on('forminputobject', formdata => {
|
||||
this.formData[this.currentTab][formdata.name] = Object.assign({}, this.formData[this.currentTab][formdata.name], formdata.value);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
saveForm: function()
|
||||
|
Reference in New Issue
Block a user