complete object-setter

This commit is contained in:
kangwei 2020-03-13 16:35:30 +08:00
parent a0e9531c03
commit f37743327b
6 changed files with 103 additions and 74 deletions

View File

@ -205,6 +205,9 @@ export default class Prop implements IPropParent {
if (this.type === 'list') {
return this.size === other.size ? 1 : 2;
}
if (this.type === 'map') {
return 1;
}
// 'literal' | 'map' | 'expression' | 'slot'
return this.code === other.code ? 0 : 2;
@ -286,25 +289,12 @@ export default class Prop implements IPropParent {
*/
get(path: string | number, stash = true): Prop | null {
const type = this._type;
// todo: support list get
if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) {
return null;
}
const maps = type === 'map' ? this.maps : null;
const items = type === 'list' ? this.items : null;
let prop: any;
if (type === 'list') {
if (isValidArrayIndex(path, this.size)) {
prop = items![path];
}
} else if (type === 'map') {
prop = maps?.get(path);
}
if (prop) {
return prop;
}
let entry = path;
let nest = '';
@ -314,22 +304,23 @@ export default class Prop implements IPropParent {
nest = path.slice(i + 1);
if (nest) {
entry = path.slice(0, i);
if (type === 'list') {
if (isValidArrayIndex(entry, this.size)) {
prop = items![entry];
}
} else if (type === 'map') {
prop = maps?.get(entry);
}
if (prop) {
return prop.get(nest, stash);
}
}
}
}
let prop: any;
if (type === 'list') {
if (isValidArrayIndex(entry, this.size)) {
prop = items![entry];
}
} else if (type === 'map') {
prop = maps?.get(entry);
}
if (prop) {
return nest ? prop.get(nest, stash) : prop;
}
if (stash) {
if (!this.stash) {
this.stash = new PropStash(this.props, item => {
@ -549,7 +540,7 @@ export function isProp(obj: any): obj is Prop {
return obj && obj.isProp;
}
function isValidArrayIndex(key: any, limit = -1): key is number {
export function isValidArrayIndex(key: any, limit = -1): key is number {
const n = parseFloat(String(key));
return n >= 0 && Math.floor(n) === n && isFinite(n) && (limit < 0 || n < limit);
}

View File

@ -81,7 +81,7 @@ export default class Props implements IPropParent {
});
}
export(serialize = false): { props?: PropsMap | PropsList; extras?: object} {
export(serialize = false): { props?: PropsMap | PropsList; extras?: object } {
if (this.items.length < 1) {
return {};
}
@ -126,15 +126,17 @@ export default class Props implements IPropParent {
});
}
return { props, extras };
return { props, extras };
}
/**
* path
*
* @useStash
* @param stash
*/
query(path: string, useStash: boolean = true): Prop | null {
query(path: string, stash = true): Prop | null {
return this.get(path, stash);
// todo: future support list search
let matchedLength = 0;
let firstMatched = null;
if (this.items) {
@ -165,7 +167,7 @@ export default class Props implements IPropParent {
if (firstMatched) {
ret = firstMatched.get(path.slice(matchedLength + 1), true);
}
if (!ret && useStash) {
if (!ret && stash) {
return this.stash.get(path);
}
@ -174,10 +176,26 @@ export default class Props implements IPropParent {
/**
* ,
* @param useStash
* @param stash
*/
get(name: string, useStash = false): Prop | null {
return this.maps.get(name) || (useStash && this.stash.get(name)) || null;
get(path: string, stash = false): Prop | null {
let entry = path;
let nest = '';
const i = path.indexOf('.');
if (i > 0) {
nest = path.slice(i + 1);
if (nest) {
entry = path.slice(0, i);
}
}
const prop = this.maps.get(entry) || (stash && this.stash.get(entry)) || null;
if (prop) {
return nest ? prop.get(nest, stash) : prop;
}
return null;
}
/**

View File

@ -137,6 +137,8 @@ export class ListSetter extends Component<ArraySetterProps, ArraySetterState> {
// check is ObjectSetter then check if show columns
}
console.info(this.state.items);
const { items } = this.state;
const scrollToLast = this.scrollToLast;
this.scrollToLast = false;
@ -265,7 +267,7 @@ export default class ArraySetter extends Component<{
return (
<Button
onClick={e => {
this.pipe.show((e as any).target);
this.pipe.show((e as any).target, field.id);
}}
>
<Icon type="edit" />

View File

@ -25,7 +25,7 @@ export default class ObjectSetter extends Component<{
}
} else {
// form
return <FormSetter />;
return <FormSetter {...props} />;
}
}
}
@ -77,31 +77,26 @@ class RowSetter extends Component<RowSetterProps> {
this.items = items;
}
if (descriptor) {
if (typeof descriptor === 'function') {
let firstRun: boolean = true;
field.onEffect(() => {
const state = {
descriptor: descriptor(field),
};
if (firstRun) {
firstRun = false;
this.state = state;
} else {
this.setState(state);
}
});
let firstRun: boolean = true;
field.onEffect(() => {
let state: any = {};
if (descriptor) {
if (typeof descriptor === 'function') {
state.descriptor = descriptor(field);
} else {
state.descriptor = field.getPropValue(descriptor);
}
} else {
this.state = {
descriptor,
};
state.descriptor = field.title;
}
} else {
// todo: onEffect change field.name
this.state = {
descriptor: field.title || `项目 ${field.name}`,
};
}
if (firstRun) {
firstRun = false;
this.state = state;
} else {
this.setState(state);
}
});
}
shouldComponentUpdate(_: any, nextState: any) {
@ -114,7 +109,7 @@ class RowSetter extends Component<RowSetterProps> {
private pipe: any;
render() {
const items = this.items;
const { field, primaryButton } = this.props;
const { field, primaryButton, config } = this.props;
if (!this.pipe) {
this.pipe = (this.context as PopupPipe).create({ width: 320 });
@ -127,7 +122,7 @@ class RowSetter extends Component<RowSetterProps> {
</Fragment>
);
this.pipe.send(<FormSetter key={field.id} />, title);
this.pipe.send(<FormSetter key={field.id} field={field} config={config} />, title);
if (items) {
return (
@ -135,7 +130,7 @@ class RowSetter extends Component<RowSetterProps> {
<div
className="lc-setter-object-row-edit"
onClick={e => {
this.pipe.show((e as any).target);
this.pipe.show((e as any).target, field.id);
}}
>
<Icon size="small" type="edit" />
@ -149,7 +144,7 @@ class RowSetter extends Component<RowSetterProps> {
<Button
type={primaryButton === false ? 'normal' : 'primary'}
onClick={e => {
this.pipe.show((e as any).target);
this.pipe.show((e as any).target, field.id);
}}
>
<Icon type="edit" />
@ -159,9 +154,30 @@ class RowSetter extends Component<RowSetterProps> {
}
}
// form-field setter
class FormSetter extends Component<{}> {
interface FormSetterProps {
field: SettingField;
config: ObjectSetterConfig;
}
class FormSetter extends Component<FormSetterProps> {
private items: SettingField[];
constructor(props: RowSetterProps) {
super(props);
const { config, field } = props;
this.items = (config.items || []).map(conf => field.createField(conf));
// TODO: extraConfig for custom fields
}
shouldComponentUpdate() {
return false;
}
render() {
return 'yes';
const { field } = this.props;
return (
<div className="lc-setter-object lc-block-setter">
{this.items.map((item, index) => createSettingFieldView(item, field, index))}
</div>
);
}
}

View File

@ -200,7 +200,8 @@ export class SettingField implements SettingTarget {
}
// initial self properties
this._name = name;
this.title = title || String(name);
// make this reactive
this.title = title || (typeof name === 'number' ? `项目 ${name}` : name);
this.setter = setter;
this.extraProps = {
...rest,

View File

@ -26,10 +26,11 @@ export class PopupPipe {
});
}
},
show: (target: Element) => {
show: (target: Element, actionKey?: string) => {
this.currentId = id;
this.popup({
...props,
actionKey,
content: sendContent,
title: sendTitle,
}, target);
@ -55,7 +56,7 @@ export class PopupPipe {
}
}
export default class PopupService extends Component<{ safeId?: string }> {
export default class PopupService extends Component<{ actionKey?: string; safeId?: string }> {
private popupPipe = new PopupPipe();
componentWillUnmount() {
@ -63,10 +64,11 @@ export default class PopupService extends Component<{ safeId?: string }> {
}
render() {
const { children, actionKey, safeId } = this.props;
return (
<PopupContext.Provider value={this.popupPipe}>
{this.props.children}
<PopupContent safeId={this.props.safeId} />
{children}
<PopupContent key={'pop' + actionKey} safeId={safeId} />
</PopupContext.Provider>
);
}
@ -100,7 +102,7 @@ export class PopupContent extends PureComponent<{ safeId?: string }> {
}
render() {
const { content, visible, width, title, pos } = this.state;
const { content, visible, width, title, pos, actionKey } = this.state;
if (!visible) {
return null;
}
@ -116,7 +118,6 @@ export class PopupContent extends PureComponent<{ safeId?: string }> {
className="lc-ballon"
align="l"
id={this.props.safeId}
safeId={this.props.safeId}
safeNode={id}
visible={visible}
style={{ width }}
@ -135,7 +136,7 @@ export class PopupContent extends PureComponent<{ safeId?: string }> {
shouldUpdatePosition
>
<div className="lc-ballon-title">{title}</div>
<div className="lc-ballon-content"><PopupService safeId={id}>{content}</PopupService></div>
<div className="lc-ballon-content"><PopupService actionKey={actionKey} safeId={id}>{content}</PopupService></div>
</Balloon>
);
}