UNPKG

nv-data-selection

Version:

nv-data-selection ============ - nv-data-selection ,nest selection - multi, radio,value,validator - notifier callback

447 lines (426 loc) 12.7 kB
const {_UiNode} = require("nv-data-tree-csp-node"); const {noexist,kvlist2d,is_str} = require("nv-facutil-basic"); const { wfs_eng, wfs_tac, } = require("nv-data-tree-csp-jconvert") const ERROR = { can_only_change_type_between_radio_and_multi:'can_only_change_type_between_radio_and_multi', only_value_or_setter_can_assign_value:'ERROR.only_value_or_setter_can_assign_value', only_setter_have_validate:'only_setter_have_validate', type_must_in_option_type:'type_must_in_option_type', setter_validate_failed:'setter_validate_failed', slcted_children_gt_one:'slcted_children_gt_one' } const sym_typ = Symbol(""); const sym_slct_self = Symbol(""); const sym_recv = Symbol(""); const sym_val = Symbol(""); const sym_as = Symbol(""); function _calc(that) { if(that.type_ === 'Multi') { let opts = that.slcted_children_; opts = opts.filter(opt=>opt.val_!==noexist); let ks = opts.map(opt=>opt.key_); let vs = opts.map(opt=>opt.val_); if(that.as_ === 'ary') { that[sym_val] = vs } else { that[sym_val] = kvlist2d(ks,vs); } } else if(that.type_ === 'Radio') { let opts = that.slcted_children_; if(opts.length === 1) { that[sym_val] = opts[0].val_; } else { that[sym_val] = noexist; } } else if( that.type_ === 'Setter' || that.type_ === 'Value' ) { } else { let opts = that.slcted_children_; opts = opts.filter(opt=>opt.val_!==noexist); let ks = opts.map(opt=>opt.key_); let vs = opts.map(opt=>opt.val_); that[sym_val] = kvlist2d(ks,vs); } } function _unparse(rt) { let nrt = rt.$clone( (nd,nnd) => { if(nd.type_==='Root') { nnd.T = '%root%'; nnd.A = {}; } else { nnd.T = nd.key_; if(nd.type_==='Value' && is_str(nd.val_)) { nnd.A = {} } else { nnd.A = {type:nd.type_} if(nd.as_!=='val') { nnd.A.as = nd.as_} if(nd.type_==='Setter') { if(nd.val_ !== noexist) { nnd.A.val = nd.val_; } else {} if(nd.validate_!==noexist) { nnd.A.validate = nd.validate_ } else { nnd.A.validate = DFLT_VALI; } } if(nd.noti_!==noexist) { nnd.A.as = nd.as_} if(nd.type_==='Value' && !is_str(nd.val_)) { nnd.A.val = nd.val_ } } if(nd.is_slcted()) {nnd.A.slcted = true} } } ); return(nrt) } const DFLT_VALI = (v,self) => true; const DFLT_NOTI = (src,msg,self)=>{}; class Option extends _UiNode { #slcted = false #type = 'Root' #as = 'val' #val = noexist #validate = noexist #key = noexist #noti = noexist //// regis_$noti$(f=(src,msg,self)=>{}) {this.#noti = f} get noti_() {return(this.#noti)} [sym_recv](src,msg) { //// _calc(this); //// let p = this.$parent_; if(p!==null && this.is_slcted()) { p[sym_recv](src,msg) } else {} //// if(this.#noti !== noexist) { this.#noti(src,msg,this); } else {} } //// get [sym_typ]() {return(this.#type)} set [sym_typ](T) { if(Object.values(Option.TYPE).includes(T)) { this.#type = T } else { console.log(ERROR.type_must_in_option_type) } } //// get validate_() { if(this.#type !== Option.TYPE.setter) { console.log(ERROR.only_setter_have_validate) } else { return(this.#validate) } } regis_$validate$(f=(v,self)=>true) { if(this.#type !== Option.TYPE.setter) { console.log(ERROR.only_setter_have_validate) } else { this.#validate = f; } } //// get key_() {return(this.#key)} set key_(k) {this.#key = k} //// get type_() {return(this.#type)} change_$type_to_multi$() { if(this.#type === Option.TYPE.multi || this.#type === Option.TYPE.radio) { this.#type = Option.TYPE.multi } else { console.log(ERROR.can_only_change_type_between_radio_and_multi) } } change_$type_to_radio$() { if(this.#type === Option.TYPE.multi || this.#type === Option.TYPE.radio) { if( this.#type === Option.TYPE.multi && this.slcted_children_.length>1 ) { console.log(ERROR.slcted_children_gt_one) } else { this.#type = Option.TYPE.radio } } else { console.log(ERROR.can_only_change_type_between_radio_and_multi) } } //// set [sym_val](v) {this.#val=v} //internal using get val_() {return(this.#val)} set val_(v) { if(this.#type === Option.TYPE.value) { this.#val = v; let p = this.$parent_; if(p!==null) {p[sym_recv](this,'set')} } else if(this.#type === Option.TYPE.setter) { if(this.#validate === noexist) { this.#val = v; let p = this.$parent_; if(p!==null) {p[sym_recv](this,'set')} } else { let cond = this.#validate(v,this); if(cond) { this.#val = v; let p = this.$parent_; if(p!==null) {p[sym_recv](this,'set')} } else { console.log(ERROR.setter_validate_failed) } } } else { console.log(ERROR.only_value_or_setter_can_assign_value) } } //// set [sym_as](v) {this.#as =v} get as_() {return(this.#as)} set_$as_ary$() { if(this.#type === Option.TYPE.multi) { this[sym_as] = Option.AS.ary; } else { console.log(ERROR.only_multi_can_set_as) } } set_$as_dict$() { if(this.#type === Option.TYPE.multi) { this[sym_as] = Option.AS.dict; } else { console.log(ERROR.only_multi_can_set_as) } } //// ////return this [sym_slct_self] () { this.#slcted=true; let p = this.$parent_ if(p!==null){p[sym_recv](this,'slct')} } slct_self() { let p = this.$parent_ if(p!==null && p.type_ === Option.TYPE.radio) { let i = this.$sibseq_; p.slct_child(i) } else { this.#slcted = true; } if(p!==null){p[sym_recv](this,'slct')} return(this) } unslct_self() { this.#slcted = false; let p = this.$parent_; if(p!==null){p[sym_recv](this,'unslct')} return(this) } //// get opts_() { return(this.$children_)} ////return child or undefined slct_child(i) { let opts = this.opts_; if(opts[i]!==undefined) { opts[i][sym_slct_self](); if(this.#type === Option.TYPE.radio) { for(let idx=0;idx<i;idx++) { opts[idx].unslct_self(); } for(let idx=i+1;idx<opts.length;idx++) { opts[idx].unslct_self(); } } else {} return(opts[i]) } else { } } unslct_child(i) { let opts = this.opts_; if(opts[i]!==undefined) { opts[i].unslct_self(); return(opts[i]) } else { } } ////return array | undefined slct_all_children() { if(this.#type === Option.TYPE.radio) { console.log(ERROR.radio_can_not_slct_all) } else { this.opts_.forEach(child=>child.slct_self()) return(this.opts_) } } unslct_all_children() { this.opts_.forEach(child=>child.unslct_self()); return(this.opts_) } //// is_slcted() {return(this.#slcted)} get slcted_children_() { return(this.opts_.filter(c=>c.is_slcted())) } get unslcted_children_() { return(this.opts_.filter(c=>!c.is_slcted())) } //// json() { let nrt = _unparse(this); let j = wfs_tac.jsonize(nrt); nrt.$erase_r(); return(j) } //// tree() { let rd = {} let unhandled = [{d:rd,nd:rt}]; let next_unhandled = [] while(unhandled.length>0) { for(let ele of unhandled) { let {d,nd} = ele; let children = nd.$children_; for(let c of children) { if(c.is_slcted()) { d[c.key_] = {} let D = d[c.key_]; if(c.$is_leaf()) { d[c.key_] = c.val_; } else { next_unhandled.push({d:D,nd:c}) } } else { } } } unhandled = next_unhandled; next_unhandled = [] } return(rd) } //// get chks_() { let opts = this.opts_; return(opts.map(r=>r.key_)) } kget(k) { let opts = this.opts_; opts = opts.filter(r=>r.key_ === k); if(opts.length === 0) { return(noexist) } else if(opts.length ===1) { return(opts[0]) } else { return(opts) } } //// get [Symbol.toStringTag]() { if(this.#type === 'Root') { return(` ${this.#type} `) } else { let slcted = this.is_slcted()?'<slcted>':'<unslcted>'; return(` ${this.#type} : ${slcted} `) } } } Option.TYPE = { multi:'Multi', radio:'Radio', value:'Value', setter:'Setter' } Object.freeze(Option.TYPE) Option.MSG = { slct:'slct', unslct:'unslct', set:'set', } Object.freeze(Option.MSG) Option.AS = { ary:'ary', dict:'dict', } Object.freeze(Option.AS) function _add_getter(nd,k) { let children = nd.$children_; children.forEach( ch=>{ Object.defineProperty(nd,ch[k],{get:function(){return(ch)}}) } ); } function load_from_json(j) { let [rt,forest] = wfs_tac.tree_lize(j,undefined,Option); //// rt[sym_as] = 'dict'; rt[sym_val] = {}; delete rt.T; delete rt.A; _add_getter(rt,'T'); //// let sdfs = rt.$sdfs_; sdfs = sdfs.slice(1) sdfs.forEach( nd => { nd.key_ = nd.T; //// if(nd.A.noti !== undefined) { nd.regis_$noti$(nd.A.noti); } else {} //// if(nd.A.slcted === true) { nd.slct_self(); } else {} //// if(nd.A.type === undefined) { nd[sym_typ] = Option.TYPE.value; nd.val_ = nd.T; } else if(nd.A.type === Option.TYPE.value) { nd[sym_typ] = Option.TYPE.value; nd.val_ = nd.A.val; } else if(nd.A.type === Option.TYPE.setter) { nd[sym_typ] = Option.TYPE.setter; if(nd.A.validate === undefined) { } else { nd.regis_$validate$(nd.A.validate); if(nd.A.hasOwnProperty('dflt')) { let cond = nd.A.validate(nd.A.dflt); if(cond) { nd.val_ = nd.A.dflt; } else {} } else {} } } else if(nd.A.type === Option.TYPE.radio) { nd[sym_typ] = Option.TYPE.radio; } else if(nd.A.type === Option.TYPE.multi) { nd[sym_typ] = Option.TYPE.multi; nd[sym_as] = nd.A.as??'ary'; nd[sym_val] = (nd.as_ === 'ary')?[]:{} } else { } delete nd.T; delete nd.A; _add_getter(nd,'T') } ); rt.slct_all_children(); return([rt,forest]) } module.exports = { noexist, ERROR, DFLT_VALI, DFLT_NOTI, Option, load_from_json, }