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') { if (this.type === 'list') {
return this.size === other.size ? 1 : 2; return this.size === other.size ? 1 : 2;
} }
if (this.type === 'map') {
return 1;
}
// 'literal' | 'map' | 'expression' | 'slot' // 'literal' | 'map' | 'expression' | 'slot'
return this.code === other.code ? 0 : 2; 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 { get(path: string | number, stash = true): Prop | null {
const type = this._type; const type = this._type;
// todo: support list get
if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) { if (type !== 'map' && type !== 'list' && type !== 'unset' && !stash) {
return null; return null;
} }
const maps = type === 'map' ? this.maps : null; const maps = type === 'map' ? this.maps : null;
const items = type === 'list' ? this.items : 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 entry = path;
let nest = ''; let nest = '';
@ -314,22 +304,23 @@ export default class Prop implements IPropParent {
nest = path.slice(i + 1); nest = path.slice(i + 1);
if (nest) { if (nest) {
entry = path.slice(0, i); 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 (stash) {
if (!this.stash) { if (!this.stash) {
this.stash = new PropStash(this.props, item => { this.stash = new PropStash(this.props, item => {
@ -549,7 +540,7 @@ export function isProp(obj: any): obj is Prop {
return obj && obj.isProp; 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)); const n = parseFloat(String(key));
return n >= 0 && Math.floor(n) === n && isFinite(n) && (limit < 0 || n < limit); 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) { if (this.items.length < 1) {
return {}; return {};
} }
@ -126,15 +126,17 @@ export default class Props implements IPropParent {
}); });
} }
return { props, extras }; return { props, extras };
} }
/** /**
* path * 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 matchedLength = 0;
let firstMatched = null; let firstMatched = null;
if (this.items) { if (this.items) {
@ -165,7 +167,7 @@ export default class Props implements IPropParent {
if (firstMatched) { if (firstMatched) {
ret = firstMatched.get(path.slice(matchedLength + 1), true); ret = firstMatched.get(path.slice(matchedLength + 1), true);
} }
if (!ret && useStash) { if (!ret && stash) {
return this.stash.get(path); 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 { get(path: string, stash = false): Prop | null {
return this.maps.get(name) || (useStash && this.stash.get(name)) || 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 // check is ObjectSetter then check if show columns
} }
console.info(this.state.items);
const { items } = this.state; const { items } = this.state;
const scrollToLast = this.scrollToLast; const scrollToLast = this.scrollToLast;
this.scrollToLast = false; this.scrollToLast = false;
@ -265,7 +267,7 @@ export default class ArraySetter extends Component<{
return ( return (
<Button <Button
onClick={e => { onClick={e => {
this.pipe.show((e as any).target); this.pipe.show((e as any).target, field.id);
}} }}
> >
<Icon type="edit" /> <Icon type="edit" />

View File

@ -25,7 +25,7 @@ export default class ObjectSetter extends Component<{
} }
} else { } else {
// form // form
return <FormSetter />; return <FormSetter {...props} />;
} }
} }
} }
@ -77,31 +77,26 @@ class RowSetter extends Component<RowSetterProps> {
this.items = items; this.items = items;
} }
if (descriptor) { let firstRun: boolean = true;
if (typeof descriptor === 'function') { field.onEffect(() => {
let firstRun: boolean = true; let state: any = {};
field.onEffect(() => { if (descriptor) {
const state = { if (typeof descriptor === 'function') {
descriptor: descriptor(field), state.descriptor = descriptor(field);
}; } else {
if (firstRun) { state.descriptor = field.getPropValue(descriptor);
firstRun = false; }
this.state = state;
} else {
this.setState(state);
}
});
} else { } else {
this.state = { state.descriptor = field.title;
descriptor,
};
} }
} else {
// todo: onEffect change field.name if (firstRun) {
this.state = { firstRun = false;
descriptor: field.title || `项目 ${field.name}`, this.state = state;
}; } else {
} this.setState(state);
}
});
} }
shouldComponentUpdate(_: any, nextState: any) { shouldComponentUpdate(_: any, nextState: any) {
@ -114,7 +109,7 @@ class RowSetter extends Component<RowSetterProps> {
private pipe: any; private pipe: any;
render() { render() {
const items = this.items; const items = this.items;
const { field, primaryButton } = this.props; const { field, primaryButton, config } = this.props;
if (!this.pipe) { if (!this.pipe) {
this.pipe = (this.context as PopupPipe).create({ width: 320 }); this.pipe = (this.context as PopupPipe).create({ width: 320 });
@ -127,7 +122,7 @@ class RowSetter extends Component<RowSetterProps> {
</Fragment> </Fragment>
); );
this.pipe.send(<FormSetter key={field.id} />, title); this.pipe.send(<FormSetter key={field.id} field={field} config={config} />, title);
if (items) { if (items) {
return ( return (
@ -135,7 +130,7 @@ class RowSetter extends Component<RowSetterProps> {
<div <div
className="lc-setter-object-row-edit" className="lc-setter-object-row-edit"
onClick={e => { onClick={e => {
this.pipe.show((e as any).target); this.pipe.show((e as any).target, field.id);
}} }}
> >
<Icon size="small" type="edit" /> <Icon size="small" type="edit" />
@ -149,7 +144,7 @@ class RowSetter extends Component<RowSetterProps> {
<Button <Button
type={primaryButton === false ? 'normal' : 'primary'} type={primaryButton === false ? 'normal' : 'primary'}
onClick={e => { onClick={e => {
this.pipe.show((e as any).target); this.pipe.show((e as any).target, field.id);
}} }}
> >
<Icon type="edit" /> <Icon type="edit" />
@ -159,9 +154,30 @@ class RowSetter extends Component<RowSetterProps> {
} }
} }
// form-field setter interface FormSetterProps {
class FormSetter extends Component<{}> { 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() { 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 // initial self properties
this._name = name; this._name = name;
this.title = title || String(name); // make this reactive
this.title = title || (typeof name === 'number' ? `项目 ${name}` : name);
this.setter = setter; this.setter = setter;
this.extraProps = { this.extraProps = {
...rest, ...rest,

View File

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