don'T knOW òÒ

This commit is contained in:
2021-12-21 00:53:17 +01:00
parent e2d98b48b5
commit 43a14817e4
72 changed files with 447 additions and 527 deletions
@@ -19,9 +19,9 @@
<script>
import { selectorToArray } from '../utils/arrays';
import { setObjectValue } from '../utils/objects';
import { localize } from '../services/localization';
import { selectorToArray } from '../../utils/arrays';
import { setObjectValue } from '../../utils/objects';
import { localize } from '../../services/localization';
//import Overlay from 'zero/helpers/overlay.js';
export default {
@@ -27,6 +27,8 @@
<script>
export default {
name: 'uiEditorInfos',
props: {
modelValue: {
type: [Object, Array]
@@ -30,13 +30,14 @@
<script>
import './editor.scss';
import EditorComponent from './editor-component.vue';
import EditorAside from './editor-aside.vue';
import { createBlueprintConfig } from './editor-blueprint';
import BlueprintProperty from './blueprint/property.vue';
import './ui-editor.scss';
import EditorComponent from './ui-editor-component.vue';
//import { createBlueprintConfig } from './editor-blueprint';
//import BlueprintProperty from './blueprint/property.vue';
import { defineComponent } from 'vue';
let createBlueprintConfig = () => null;
export default defineComponent({
name: 'uiEditor',
@@ -70,7 +71,7 @@
},
},
components: { EditorComponent, EditorAside, BlueprintProperty },
components: { EditorComponent },
data: () => ({
editorConfig: {},
+9 -1
View File
@@ -28,6 +28,10 @@ import uiDatagrid from './ui-datagrid.vue';
import uiProgress from './ui-progress.vue';
import uiDate from './ui-date.vue';
import uiEditor from './editor/ui-editor.vue';
import uiEditorInfos from './editor/ui-editor-infos.vue';
import uiEditorHeader from './editor/ui-editor-header.vue';
export {
uiIcon,
uiLoading,
@@ -57,5 +61,9 @@ export {
uiPick,
uiDatagrid,
uiProgress,
uiDate
uiDate,
uiEditor,
uiEditorInfos,
uiEditorHeader
};
+12 -3
View File
@@ -7,13 +7,14 @@ import { createRouter, RouteRecordRaw, RouterOptions } from 'vue-router';
import registerDirectives from '../directives/register';
import registerComponents from '../components/register';
import registerFormComponents from '../forms/register';
import registerEditorComponents from '../editor/register';
//import registerEditorComponents from '../editor/register';
import { getRouterConfig, appendRouterGuards } from './router/routerConfig';
import { countryPlugin, applicationPlugin, settingsPlugin, languagePlugin, mediaPlugin, spacePlugin, pagePlugin } from '../modules';
import editorPlugin from '../editor/new/plugin';
import editorPlugin from '../editor/_new/plugin';
import { ZeroSchema } from 'zero/schemas';
import { ZeroSchemaProp } from './zero';
import * as zeroOptions from '../options';
import { createEditor } from '../editor/_new/editor';
export class ZeroRuntime implements Zero
{
@@ -60,7 +61,7 @@ export class ZeroRuntime implements Zero
registerDirectives(app);
registerComponents(app);
registerFormComponents(app);
registerEditorComponents(app);
//registerEditorComponents(app);
}
@@ -128,6 +129,14 @@ export class ZeroRuntime implements Zero
if (typeof schema === 'function')
{
const res = await schema();
if (typeof res.default === 'function')
{
const editor = createEditor();
res.default(editor);
return editor;
}
return res.default;
}
@@ -18,4 +18,19 @@ export class Editor
this.fields.push(proxy);
return proxy;
}
}
//export interface Editor
//{
// field(alias: string, config?: EditorFieldConfiguration): EditorField;
//}
export declare type EditorBuilderExpression = (editor: Editor) => void;
export function createEditor(): Editor
{
return new Editor();
}
@@ -25,7 +25,7 @@ export const createFieldProxy = (field: EditorFieldBase) => new Proxy(field, {
export function createFieldConfiguration(): EditorFieldConfiguration
{
return {
required: false,
optional: false,
readonly: false,
hidden: false,
label: null,
@@ -40,23 +40,23 @@ export function createFieldConfiguration(): EditorFieldConfiguration
export class EditorFieldBase
{
alias: string;
path: string;
configuration: EditorFieldConfiguration;
fieldType?: string;
options?: any;
constructor(alias: string, config?: EditorFieldConfiguration)
constructor(path: string, config?: EditorFieldConfiguration)
{
this.alias = alias;
this.path = path;
this.configuration = config || createFieldConfiguration();
}
/**
* Set this field as required
* Set this field as optional
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
setRequired(condition: Function | boolean): EditorField
setOptional(condition: Function | boolean): EditorField
{
this.configuration.required = condition;
return this;
@@ -1,13 +1,13 @@
import { Component } from "vue";
import { Component } from 'vue';
declare module 'zero/editor'
{
export interface EditorFieldConfiguration
{
/**
* Whether this field is required (additional validation is done on the server)
* Whether this field is optional or required (additional validation is done on the server)
*/
required?: Function | boolean;
optional?: Function | boolean;
/**
* Whether this field is readonly and can't be changed
*/
@@ -56,10 +56,10 @@ declare module 'zero/editor'
export interface EditorField
{
/**
* Set this field as required
* Set this field as optional
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
setRequired(condition: Function | boolean): EditorField;
setOptional(condition: Function | boolean): EditorField;
/**
* Whether the input next to the headline or below
+34
View File
@@ -0,0 +1,34 @@
declare module 'zero/editor'
{
//export interface FieldSupportsMaxLength
//{
// maxLength?: number;
//}
//export interface FieldSupportsPlaceholder
//{
// placeholder?: string | null;
//}
//export type TextFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
//export type NumberFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
//export interface EditorField
//{
// /**
// * Set this field as required
// * @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
// */
// text(options?: TextFieldOptions): EditorField;
// /**
// * Set this field as required
// * @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
// */
// number(options?: NumberFieldOptions): EditorField;
//}
}
-24
View File
@@ -1,24 +0,0 @@
declare module 'zerox/editor'
{
export interface FieldSupportsMaxLength
{
maxLength?: number;
}
export interface FieldSupportsPlaceholder
{
placeholder?: string;
}
export type TextFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export type NumberFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export interface EditorField
{
text(options?: TextFieldOptions): void;
number(options?: NumberFieldOptions): void;
}
}
@@ -1,18 +0,0 @@
import { EditorField } from "zero/editor";
export const fieldTypes: Record<string, any> = {};
export const proxy = new Proxy(fieldTypes, {
get(target, handler)
{
console.info({ target, handler });
return target[handler];
}
}) as EditorField;
//fieldTypes.number = (maxLength?: number, placeholder?: string | Function) => console.log(`number() called with maxLength: ${maxLength}, placeholder: ${placeholder}`);
//proxy.number({ maxLength: 17, placeholder: 'Enter your number...' });
//var field = editor.field('name').text("hallo");
@@ -1,55 +0,0 @@
<template>
<div class="testcmp">
testcmp
</div>
</template>
// @ts-ignore
<script lang="ts">
import { defineComponent } from 'vue';
interface Props
{
maxLength: number;
placeholder: string | Function;
}
//function TestCmpOptions(maxLength?: number, placeholder?: string)
//{
// this.maxLenght =
//}
export default defineComponent({
name: 'editorTestCmp',
props: {
options: {
type: Object as Props,
default: {
maxLength: null,
placeholder: null
} as Props
}
},
data: () => ({
}),
mounted()
{
},
methods: {
}
});
</script>
<style lang="scss">
</style>
@@ -1,72 +0,0 @@
<template>
<div>
<ui-property v-if="modelValue.id && modelValue.lastModifiedDate" field="lastModifiedDate" label="@ui.modifiedDate" :is-text="true" :vertical="true">
<ui-date v-model="modelValue.lastModifiedDate" />
</ui-property>
<ui-property v-if="modelValue.id" label="@ui.createdDate" field="createdDate" :is-text="true" :vertical="true">
<ui-date v-model="modelValue.createdDate" />
</ui-property>
</div>
</template>
<script>
export default {
name: 'uiEditorAside',
inject: [ 'meta' ],
props: {
editor: {
type: Object,
required: true
},
modelValue: {
type: Object,
required: true
},
infos: {
type: String,
default: 'aside'
},
activeToggle: {
type: Boolean,
default: true
},
nested: {
type: Boolean,
default: false
},
isPage: {
type: Boolean,
default: false
},
disabled: {
type: [Boolean, Function],
default: false
}
},
data: () => ({
component: null
}),
created()
{
//this.component = zero.overrides['editor-aside'] || null;
}
}
</script>
<style lang="scss">
.editor-aside
{
padding-top: var(--padding);
padding-left: var(--padding-s);
}
.editor-aside .ui-property + .ui-property
{
margin-top: var(--padding-m);
}
</style>
@@ -1,75 +0,0 @@
<template>
<ui-form ref="form" v-slot="form" @submit="onSubmit" class="editor-form">
<ui-form-header v-if="rendered" v-model="model" prefix="@country.list" title="@country.name" :disabled="disabled" :is-create="!$route.params.id" :state="form.state" :can-delete="meta.canDelete" @delete="onDelete" />
<ui-editor v-if="rendered" :config="config" v-model="model" :meta="meta" :disabled="disabled" :on-configure="onLoad">
<template v-slot:below>
<ui-editor-infos v-model="model" :disabled="disabled" />
</template>
</ui-editor>
</ui-form>
</template>
<script>
import './editor.scss';
export default {
name: 'uiEditorForm',
props: {
config: {
type: [String, Object],
required: true
}
},
data: () => ({
meta: {},
model: {},
route: __zero.alias.settings.countries + '-edit',
disabled: false,
collection: null,
rendered: false
}),
mounted()
{
this.rendered = true;
},
methods: {
onLoad(editor)
{
this.collection = editor.editorConfig.collection;
if (!this.collection)
{
// TODO error
}
//this.$refs.form.load(!this.$route.params.id ? this.collection.getEmpty() : this.collection.getById(this.$route.params.id)).then(response =>
//{
// this.disabled = !response.meta.canEdit;
// this.meta = response.meta;
// this.model = response.entity;
//});
},
onSubmit(form)
{
form.handle(this.collection.save(this.model));
},
onDelete(item, opts)
{
opts.hide();
this.$refs.form.onDelete(this.collection.delete.bind(this, this.$route.params.id));
}
}
}
</script>
@@ -1,156 +0,0 @@
.editor > .ui-view-box
{
padding-top: 0;
}
.editor
{
.ui-tabs-list
{
padding-top: 0;
}
.ui-tab > h3
{
border-bottom: 1px solid var(--color-line);
padding-bottom: var(--padding-m);
margin-bottom: var(--padding);
}
}
.editor-outer
{
width: 100%;
max-width: 1320px;
margin: 0 auto;
&.-infos-aside:not(.is-page)
{
display: grid;
//grid-template-columns: 1fr 340px var(--padding);
align-items: flex-start;
}
&:not(.has-tabs)
{
.ui-tabs-list
{
display: none;
}
.ui-tab, .editor-infos
{
margin-top: 0;
}
}
}
.editor-infos
{
margin: 61px 0 0;
position: sticky;
top: var(--padding);
.ui-box
{
margin-left: 0;
margin-right: 0;
margin-bottom: 0;
}
.ui-box:first-child
{
margin-top: 0;
}
.ui-box + .ui-box
{
margin-top: 16px;
}
.ui-box + .ui-box.is-light
{
margin-top: 1px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.ui-property + .ui-property
{
margin-top: 15px;
padding-top: 10px;
border-top: none;
}
.is-toggle
{
align-items: center;
}
.ui-property-label
{
width: auto;
padding-right: 20px;
}
.ui-property-content
{
flex: 0 1 auto;
}
.ui-property
{
display: flex;
justify-content: space-between;
}
}
.editor-active-toggle
{
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
/*.editor-active-toggle.is-active
{
background: var(--color-accent-info-bg);
.ui-property-label
{
color: var(--color-accent-info);
}
}*/
.editor-error
{
background: transparent;
min-height: calc(100vh - 100px);
}
/// tabs as boxes
.editor-outer.as-boxes
{
.ui-tabs-list
{
display: none !important;
}
.ui-tab
{
display: block !important;
}
.ui-tab:first-child
{
margin-top: 0;
}
.editor-infos
{
margin-top: 0;
}
}
@@ -0,0 +1,12 @@
declare module 'zero/schemas'
{
export interface ZeroEditorField
{
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
number(options?: NumberFieldOptions): ZeroEditorField;
}
}
@@ -0,0 +1,40 @@
<template>
<input :value="modelValue" @input="$emit('input', $event.target.value)" type="text" class="ui-input" v-placeholder="{ placeholder, model: entity }" :maxlength="maxLength" :disabled="disabled" />
</template>
<script>
declare module 'zero/schemas'
{
export interface ZeroEditorField
{
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
text(options?: TextFieldOptions): ZeroEditorField;
}
}
export default {
props: {
value: {
type: String,
default: null
},
maxLength: {
type: Number,
default: null
},
disabled: {
type: Boolean,
default: false
},
placeholder: {
type: [String, Function],
default: null
},
entity: Object
}
}
</script>
-34
View File
@@ -1,34 +0,0 @@
declare module 'zero/editor'
{
export interface FieldSupportsMaxLength
{
maxLength?: number;
}
export interface FieldSupportsPlaceholder
{
placeholder?: string | null;
}
export type TextFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export type NumberFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export interface EditorField
{
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
text(options?: TextFieldOptions): EditorField;
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
number(options?: NumberFieldOptions): EditorField;
}
}
@@ -1,32 +0,0 @@
<template>
<input :value="value" @input="$emit('input', $event.target.value)" type="text" class="ui-input" v-placeholder="{ placeholder: options.placeholder, model: entity }" :maxlength="options.maxLength" :disabled="disabled" />
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { TextFieldOptions } from 'zero/editor';
export default defineComponent({
props: {
value: {
type: String,
default: null
},
maxLength: {
type: Number,
default: null
},
disabled: {
type: Boolean,
default: false
},
placeholder: {
type: [String, Function],
default: null
},
entity: Object,
options: Object as PropType<TextFieldOptions>
}
});
</script>
@@ -1,22 +1,10 @@
import { Editor } from '../../../editor/new/editor';
import { ZeroEditor } from "../../../schemas/editor/editor";
const editor = new Editor(); //'@country.fields.');
const editor = new ZeroEditor();
const field = editor.field('name').setRequired(true).text({ maxLength: 80 });
editor.field('name').text({ maxLength: 120 });
editor.field('code').text({ maxLength: 2 });
editor.field('isPreferred', { optional: true }).toggle();
console.info(editor);
export default editor;
//import Editor from '../../../editor/editor';
//const editor = new Editor('@country.fields.');
//editor.blueprintAlias = 'countries';
//editor.field('name', { label: '@ui.name' }).text(120).required();
////editor.field('alias', { label: '@ui.alias' }).text().required();
//editor.field('code').text(2).required();
//editor.field('isPreferred').toggle();
//export default editor;
export default editor;
@@ -1,12 +1,13 @@
import Editor from '../../../editor/editor';
export default {};
//import Editor from '../../../editor/editor';
const editor = new Editor('@language.fields.');
editor.blueprintAlias = 'languages';
editor.field('name', { label: '@ui.name' }).text(60).required();
editor.field('code').text(10).required();
editor.field('inheritedLanguageId').languagePicker();
editor.field('isDefault').toggle();
editor.field('isOptional').toggle();
//const editor = new Editor('@language.fields.');
//editor.blueprintAlias = 'languages';
//editor.field('name', { label: '@ui.name' }).text(60).required();
//editor.field('code').text(10).required();
//editor.field('inheritedLanguageId').languagePicker();
//editor.field('isDefault').toggle();
//editor.field('isOptional').toggle();
export default editor;
//export default editor;
@@ -1,14 +1,15 @@
import Editor from '../../../editor/editor';
import { getFilesize, formatDate } from '../../../utils';
import MetadataEditor from '../pages/detail/metadata.vue';
export default {};
//import Editor from '../../../editor/editor';
//import { getFilesize, formatDate } from '../../../utils';
//import MetadataEditor from '../pages/detail/metadata.vue';
const editor = new Editor('media:edit', '@media.fields.');
editor.blueprintAlias = 'media';
//const editor = new Editor('media:edit', '@media.fields.');
//editor.blueprintAlias = 'media';
editor.field('name', { label: '@ui.name' }).text().required();
editor.field('imageMeta.alternativeText').when(x => x.imageMeta).text();
editor.field('caption').textarea();
editor.field('createdDate', { hideLabel: true }).custom(MetadataEditor);
//editor.field('name', { label: '@ui.name' }).text().required();
//editor.field('imageMeta.alternativeText').when(x => x.imageMeta).text();
//editor.field('caption').textarea();
//editor.field('createdDate', { hideLabel: true }).custom(MetadataEditor);
export default editor;
//export default editor;
@@ -0,0 +1,48 @@
import { ZeroEditorField } from "zero/schemas";
import { ZeroEditorFieldImpl, ZeroEditorFieldConfiguration, createFieldProxy } from "./editor-field";
export class ZeroEditorCanvasBase
{
fields: ZeroEditorField[] = [];
field(path: string, config?: ZeroEditorFieldConfiguration): ZeroEditorField
{
const field = new ZeroEditorFieldImpl(path, config);
const proxy = createFieldProxy(field) as ZeroEditorField;
this.fields.push(proxy);
return proxy;
}
}
export class ZeroEditorCanvasBaseWithFieldset extends ZeroEditorCanvasBase
{
fieldset(): ZeroEditorCanvasBase
{
return new ZeroEditorCanvasBase();
}
}
export class ZeroEditorCanvas extends ZeroEditorCanvasBaseWithFieldset
{
tab(alias: string, name: string): ZeroEditorTab
{
return new ZeroEditorTab(alias, name);
}
}
export class ZeroEditorTab extends ZeroEditorCanvasBaseWithFieldset
{
alias: string;
name: string;
constructor(alias: string, name: string)
{
super();
this.alias = alias;
this.name = name;
}
}
@@ -0,0 +1,151 @@
import { ZeroEditorField } from "zero/schemas";
export declare type BooleanExpression = (model: any, value: any) => boolean;
export const createFieldProxy = (field: ZeroEditorFieldImpl) => new Proxy(field, {
get: function (target: ZeroEditorFieldImpl, prop: string | symbol, receiver: any): any
{
// handle internals
if (prop in target)
{
return target[prop]; // @tsignore
}
// handle dynamic fields + extensions
return (...args) =>
{
target.custom(prop, args);
return target;
};
}
})// as EditorField;
export class ZeroEditorFieldImpl implements ZeroEditorField
{
path: string;
configuration: ZeroEditorFieldConfiguration;
fieldType?: string;
options?: any;
constructor(path: string, config?: ZeroEditorFieldConfiguration)
{
this.path = path;
this.configuration = config || createDefaultFieldConfiguration();
}
/**
* Set this field as optional
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
setOptional(condition: Function | boolean): ZeroEditorField
{
this.configuration.optional = condition;
return this;
}
/**
* Whether the input next to the headline or below
* @param {boolean} isHorizontal
* @returns {EditorField}
*/
setHorizontal(isHorizontal: boolean): ZeroEditorField
{
this.configuration.horizontal = !isHorizontal;
return this;
}
/**
* Set this field to disabled
*/
setReadonly(condition: Function | boolean): ZeroEditorField
{
this.configuration.readonly = condition;
return this;
}
/**
* Conditionally hide this field
* @param {function} condition - function which returns a boolean and gets passed the current model
*/
setHidden(condition: Function | boolean): ZeroEditorField
{
this.configuration.hidden = condition;
return this;
}
/**
* Set a custom component for a field
* @param {Component} component - The component to render (can be an async component too)
* @param {T} [options] = Custom options to pass to this editor
*/
custom<T>(fieldType: string, options?: T): ZeroEditorField
{
this.fieldType = fieldType;
this.options = options;
return this;
}
}
export function createDefaultFieldConfiguration(): ZeroEditorFieldConfiguration
{
return {
optional: false,
readonly: false,
hidden: false,
label: null,
hideLabel: false,
description: null,
helpText: null,
classes: null,
horizontal: false
} as ZeroEditorFieldConfiguration;
}
export interface ZeroEditorFieldConfiguration
{
/**
* Whether this field is optional or required (additional validation is done on the server)
*/
optional?: Function | boolean;
/**
* Whether this field is readonly and can't be changed
*/
readonly?: Function | boolean;
/**
* Conditionally hide the field
*/
hidden?: Function | boolean;
/**
* A custom label for this field (otherwise it's generated via `onLabelCreate`)
**/
label?: string | null,
/**
* Hide the field label
**/
hideLabel?: boolean,
/**
* A custom description for this field (otherwise it's generated via `onDescriptionCreate`)
**/
description?: string | null,
/**
* Display a help text below the field
**/
helpText?: string | null,
/**
* Append HTML class to the generated property
**/
classes?: string | null,
/**
* Whether to render the label next to the input
**/
horizontal?: boolean
}
+65
View File
@@ -0,0 +1,65 @@
declare module 'zero/schemas'
{
export interface FieldSupportsMaxLength
{
maxLength?: number;
}
export interface FieldSupportsPlaceholder
{
placeholder?: string | null;
}
export type TextFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export type NumberFieldOptions = FieldSupportsMaxLength | FieldSupportsPlaceholder;
export interface ZeroEditorField
{
/**
* Set this field as optional
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
setOptional(condition: Function | boolean): ZeroEditorField;
/**
* Whether the input next to the headline or below
* @param {boolean} isHorizontal
* @returns {EditorField}
*/
setHorizontal(isHorizontal: boolean): ZeroEditorField;
/**
* Set this field to disabled
*/
setReadonly(condition: Function | boolean): ZeroEditorField;
/**
* Conditionally hide this field
* @param {function} condition - function which returns a boolean and gets passed the current model
*/
setHidden(condition: Function | boolean): ZeroEditorField;
/**
* Set a custom component for a field
* @param {Component} component - The component to render (can be an async component too)
* @param {T} [options] = Custom options to pass to this editor
*/
custom<T>(component: Component, options?: T): ZeroEditorField;
/**
* Set this field as required
* @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
*/
//text(options?: TextFieldOptions): EditorField;
///**
// * Set this field as required
// * @param {function|boolean} [condition] - Optionally only require this field when a condition is fulfilled or reset the required state with true/false
// */
//number(options?: NumberFieldOptions): EditorField;
}
}
@@ -0,0 +1,11 @@
import { Component, ComponentPropsOptions } from "vue";
import { EditorSchema } from "zero/schemas";
import { ZeroEditorCanvas } from "./editor-canvas";
export class ZeroEditor extends ZeroEditorCanvas
{
constructor()
{
super();
}
}