@andersonalmeidax0/webcomponents 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/XButton.jsx +56 -0
- package/XCheckbox.jsx +22 -0
- package/XDateSelect.jsx +22 -0
- package/XInput.jsx +140 -0
- package/XSelect.jsx +59 -0
- package/XTextArea.jsx +31 -0
- package/jzcomponents/ErrorCard.jsx +18 -0
- package/jzcomponents/ErrorCardAuth.jsx +15 -0
- package/jzcomponents/Errors.js +41 -0
- package/jzcomponents/JZEditComponent.jsx +173 -0
- package/jzcomponents/JZInPlaceListComponent.jsx +95 -0
- package/jzcomponents/JZListComponent.jsx +305 -0
- package/jzcomponents/XFormEdit.jsx +105 -0
- package/jzcomponents/XTableRead.jsx +271 -0
- package/package.json +19 -0
- package/releasenotes.txt +37 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {XButton} from "../XButton.jsx"
|
|
3
|
+
import {XInputExternal} from "../XInput.jsx"
|
|
4
|
+
import {XSelect3} from "../XSelect"
|
|
5
|
+
import {XTextArea} from "../XTextArea"
|
|
6
|
+
import {XCheckbox} from "../XCheckbox.jsx"
|
|
7
|
+
import {XDateSelect} from "../XDateSelect.jsx"
|
|
8
|
+
|
|
9
|
+
const DEBUG_ID=false;
|
|
10
|
+
const DEBUG_ID2=DEBUG_ID;
|
|
11
|
+
const DEBUG_ID3=false;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* View 2 model => number digitado com fmt para numero interno
|
|
16
|
+
*/
|
|
17
|
+
function NumberView2Model(n) {
|
|
18
|
+
var nStr = n+'';
|
|
19
|
+
nStr = nStr.replaceAll('.','@');
|
|
20
|
+
nStr = nStr.replaceAll(',','.');
|
|
21
|
+
nStr = nStr.replaceAll('@',',');
|
|
22
|
+
var nOk = nStr;// Number.parseFloat(nStr);
|
|
23
|
+
return nOk;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Mode 2 view => number interno para fmt
|
|
27
|
+
*/
|
|
28
|
+
function NumberModel2View(n) {
|
|
29
|
+
var nStr = n+'';
|
|
30
|
+
//nStr = nStr.replace('.','');
|
|
31
|
+
nStr = nStr.replaceAll('.','@');
|
|
32
|
+
nStr = nStr.replaceAll(',','.');
|
|
33
|
+
nStr = nStr.replaceAll('@',',');
|
|
34
|
+
var nOk = (nStr);
|
|
35
|
+
return nOk;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isNumeric(n) {
|
|
39
|
+
return !isNaN(n);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function nfmt(n) {
|
|
43
|
+
//alert("n:["+n+']'+new Error().stack);
|
|
44
|
+
if(isNumeric(n))
|
|
45
|
+
n = parseFloat(n).toFixed(0);
|
|
46
|
+
else
|
|
47
|
+
n=" - - - ";
|
|
48
|
+
// n="Num inv1("+n+")";
|
|
49
|
+
|
|
50
|
+
return NumberModel2View(n);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function nfmt2(n) {
|
|
54
|
+
if(isNumeric(n))
|
|
55
|
+
n = parseFloat(n).toFixed(2);
|
|
56
|
+
else
|
|
57
|
+
n=" - - - ";//+'['+n+']';
|
|
58
|
+
return NumberModel2View(n);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function nfmtM(n) {
|
|
62
|
+
if(isNumeric(n))
|
|
63
|
+
n = parseFloat(n).toFixed(2);
|
|
64
|
+
else
|
|
65
|
+
n=" - - - ";
|
|
66
|
+
return NumberModel2View(n);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/** *********************************************************
|
|
73
|
+
* XTableRead: metadata, list, onAction, onActionDelete
|
|
74
|
+
* Tabela readonly, permite chamar eventos de del e edit
|
|
75
|
+
* Nao renderiza elementos com atributo "isDeleted"
|
|
76
|
+
* =======================
|
|
77
|
+
* Faz inPlace edit se tiver isEditSelect ou edit
|
|
78
|
+
* renderHTML, renderFn, isButton, ==> custom CELL rendering
|
|
79
|
+
* NOVA FUNCIONALIDADE: para Edits, força o update
|
|
80
|
+
* ********************************************************* */
|
|
81
|
+
class XTableRead extends React.Component {
|
|
82
|
+
constructor(props) {
|
|
83
|
+
super(props)
|
|
84
|
+
//this.evt = this.evt.bind(this);
|
|
85
|
+
this.state={vi:0}
|
|
86
|
+
//this.renderListItem = this.renderListItem.bind(this);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
evtRefresh = () => {
|
|
90
|
+
//alert('UPD');
|
|
91
|
+
var vi = this.state.vi;
|
|
92
|
+
this.setState({vi:vi+1});
|
|
93
|
+
this.forceUpdate();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
cellChanged = () => {
|
|
98
|
+
console.log('u.xtable.cellchanged');
|
|
99
|
+
this.evtRefresh();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
render () {
|
|
103
|
+
return (
|
|
104
|
+
<React.Fragment>
|
|
105
|
+
<h6>{DEBUG_ID&&'['+this.props.id+']'}</h6>
|
|
106
|
+
{/* div para scroll vertical */}
|
|
107
|
+
<div xstyle={{maxHeight:'400px',overflow: 'auto'}} >
|
|
108
|
+
<table className="hoverable" xwidth={'99%'} xstyle={{border:1}} >
|
|
109
|
+
<thead>
|
|
110
|
+
<tr key={'header'+this.props.id} className="table-header">
|
|
111
|
+
<th key={'0'+this.props.id}></th>
|
|
112
|
+
{this.props.metadata.fields.filter((item)=>{return(item.show)}).map((v)=> {
|
|
113
|
+
return <th key={v.label+this.props.id} x='center' align={v.align} className={v.className} > <b>{v.label}</b></th>
|
|
114
|
+
})}
|
|
115
|
+
<th key={'actions'} align='center'><b></b></th>
|
|
116
|
+
</tr>
|
|
117
|
+
</thead>
|
|
118
|
+
<tbody>
|
|
119
|
+
{this.props.list.map((item,index,arr)=> {
|
|
120
|
+
return <XTableCell key={index} item={item} index={index} lastIndex={arr.length} {...this.props} notifyChangeFn={this.cellChanged} /> })}
|
|
121
|
+
</tbody>
|
|
122
|
+
</table>
|
|
123
|
+
</div>
|
|
124
|
+
<p >{DEBUG_ID2&&'Total_'+this.props.id}</p>
|
|
125
|
+
<p style={{visibility: 'hidden'}} id={'Total_'+this.props.id}>{this.props.list.length}</p>
|
|
126
|
+
{this.props.metadata.dynamicTotalFN&&this.props.metadata.dynamicTotalFN(this.props.list)}
|
|
127
|
+
</React.Fragment>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
//var XTableCell_ID=0;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
*
|
|
138
|
+
*/
|
|
139
|
+
class XTableCell extends React.Component {
|
|
140
|
+
constructor(props) {
|
|
141
|
+
super(props)
|
|
142
|
+
this.state={vi:0}
|
|
143
|
+
this.renderListItem = this.renderListItem.bind(this);
|
|
144
|
+
//this.inputChange = this.inputChange.bind(this);
|
|
145
|
+
//this.select3Change = this.select3Change.bind(this);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
evtRefresh = () => {
|
|
149
|
+
//alert('UPD');
|
|
150
|
+
var vi = this.state.vi;
|
|
151
|
+
this.setState({vi:vi+1});
|
|
152
|
+
this.forceUpdate();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
render () {
|
|
156
|
+
var item = this.props.item;
|
|
157
|
+
var index = this.props.index;
|
|
158
|
+
var lastIndex = this.props.lastIndex;
|
|
159
|
+
return this.renderListItem(item,index,lastIndex);
|
|
160
|
+
}
|
|
161
|
+
//Map args: o valor do elemento corrente, o índice do elemento corrente e o array original que está sendo percorrido.
|
|
162
|
+
//map(v,i,arr)
|
|
163
|
+
|
|
164
|
+
//para XDate e XCheck
|
|
165
|
+
inputChange = (ev,item,v) => {
|
|
166
|
+
//item[v.attr]=ev.target.value;
|
|
167
|
+
//item[v.attr]=ev;
|
|
168
|
+
//this.evtRefresh();
|
|
169
|
+
//this.props.notifyChangeFn();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
//new: recebe context para XInputExternal
|
|
173
|
+
inputChangeNew = (value,context) => {
|
|
174
|
+
console.log("u.xtableCell.inputChgNew.context"+context);
|
|
175
|
+
var v=context.v;
|
|
176
|
+
var item=context.item;
|
|
177
|
+
console.log("u.xtableCell.inputChgNew.value"+value);
|
|
178
|
+
item[v.attr]=value;
|
|
179
|
+
this.evtRefresh();
|
|
180
|
+
this.props.notifyChangeFn();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
select3Change = (ev,item,v) => {
|
|
184
|
+
item[v.attr]=ev.target.value;
|
|
185
|
+
this.evtRefresh();
|
|
186
|
+
this.props.notifyChangeFn();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
renderListItem(item,p1,lastIndex) {
|
|
190
|
+
//var kk='ASD'+(p1+1234);
|
|
191
|
+
//XTableCell_ID=XTableCell_ID+1;
|
|
192
|
+
if(item.isDeleted)
|
|
193
|
+
return null
|
|
194
|
+
else /* <td>{XTableCell_ID}</td> */
|
|
195
|
+
return (
|
|
196
|
+
<tr key={'TR_'+p1} >
|
|
197
|
+
<td key={(p1+1)+'_H_'+this.props.id} align='center' className="nudge--left "> {(p1+1)}.{DEBUG_ID3&&'['+(this.props.id)+'_R'+p1+']'} </td>
|
|
198
|
+
{this.props.metadata.fields.filter((item)=>{return(item.show)}).map((v,i,arr)=> {
|
|
199
|
+
if(item[v.attr]==null)
|
|
200
|
+
return <td key={i} align={v.align} className={v.className} >NAtr:{v.attr}</td>
|
|
201
|
+
else
|
|
202
|
+
//Se for editável
|
|
203
|
+
if(v.edit)
|
|
204
|
+
return <td key={i} align={v.align} className={v.className}><XInputExternal type={(v.type=='n'||v.type=='f')?'number':''} id={this.props.id+'_R'+p1+'_C'+i} width={v.width} cellStyle={1} value={item[v.attr]} onXG={(ev)=>{this.inputChange(ev)}} onChangeNew={this.inputChangeNew} context={{item:item,v:v}} />{DEBUG_ID2&&this.props.id+'_R'+p1+'_C'+i}</td>
|
|
205
|
+
else
|
|
206
|
+
if(v.isEditSelect) {
|
|
207
|
+
if(!v.lov)
|
|
208
|
+
v.lov=[{id:0,descr:"ERR: NULL"}];
|
|
209
|
+
else
|
|
210
|
+
if(v.lov.length==0)
|
|
211
|
+
v.lov=[{id:0,descr:"ERR:EMPTY"}];
|
|
212
|
+
//var selIdx = Number.parseInt(item[v.attr]);
|
|
213
|
+
//selIdx=isNaN(selIdx)?0:selIdx;
|
|
214
|
+
//var readValueDescr=v.lov[selIdx].descr;
|
|
215
|
+
//var readValueDescr='DEB:idx:'+selIdx+' item.v.atr:'+item[v.attr]+' JSON:'+JSON.stringify(v.lov);
|
|
216
|
+
//if(v.readOnly)
|
|
217
|
+
// return <td key={i} align={v.align} className={v.className} >{readValueDescr}</td>
|
|
218
|
+
//else
|
|
219
|
+
return <td key={i} align={v.align} className={v.className} ><XSelect3 id={this.props.id+'_R'+p1+'_C'+i} width={v.width} list={v.lov} value={item[v.attr]} disabled={v.readOnly} onChange={(ev)=>{this.select3Change(ev,item,v)}} onChange_xxx={(ev)=>item[v.attr]=ev.target.value} /></td>
|
|
220
|
+
}
|
|
221
|
+
else
|
|
222
|
+
if(v.renderHTML) {
|
|
223
|
+
//console.log("!!!!RENDER: HTML");
|
|
224
|
+
return <td key={i} align={v.align} className={v.className} ><div dangerouslySetInnerHTML={item[v.attr]} /></td>
|
|
225
|
+
}
|
|
226
|
+
else
|
|
227
|
+
if(v.renderFn)
|
|
228
|
+
{
|
|
229
|
+
//console.log("!!!!RENDER: fn");//]}
|
|
230
|
+
//chama a funcao custom de render, passando o valor como parametro!!!!!!!
|
|
231
|
+
return <td key={i} align={v.align} className={v.className}>{v.renderFn(item[v.attr],v,i,item,p1)}</td>
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
if(v.isButton)
|
|
235
|
+
return <td key={i} align={v.align} className={v.className}><XButton label={v.isButton} onClick={()=>v.isButtonEvt(item)}/></td>
|
|
236
|
+
else
|
|
237
|
+
if(v.isLink)
|
|
238
|
+
return <td key={i} align={v.align} className={v.className}><a href={v.isLink.href} > {item[v.attr]} </a> </td>
|
|
239
|
+
else {
|
|
240
|
+
//Renderização "NORMAL"
|
|
241
|
+
var cellFmt = item[v.attr];
|
|
242
|
+
if(v.type=='n')
|
|
243
|
+
cellFmt= nfmt(cellFmt);
|
|
244
|
+
if(v.type=='f')
|
|
245
|
+
cellFmt= nfmt2(cellFmt);
|
|
246
|
+
if(v.type=='m')
|
|
247
|
+
cellFmt= nfmtM(cellFmt);
|
|
248
|
+
|
|
249
|
+
if(v.type=='d'){
|
|
250
|
+
return <td key={i} align={v.align} className={v.className}><XDateSelect disabled={v.readOnly} id={this.props.id+'_R'+p1+'_C'+i} defaultValue={item[v.attr]} onChange={(ev)=>{this.inputChange(ev,item,v)}} xonChange={this.inputChangeNew} />{DEBUG_ID2&&this.props.id+'_R'+p1+'_C'+i}</td>
|
|
251
|
+
}
|
|
252
|
+
if(v.type=='c'){
|
|
253
|
+
return <td key={i} align={v.align} className={v.className}><XCheckbox disabled={v.readOnly} id={this.props.id+'_R'+p1+'_C'+i} defaultValue={item[v.attr]} onChange={(ev)=>{this.inputChange(ev,item,v)}} xonChange={this.inputChangeNew} />{DEBUG_ID2&&this.props.id+'_R'+p1+'_C'+i}</td>
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return <td key={i} align={v.align} className={v.className} id={this.props.id+'_R'+p1+'_C'+i}>{cellFmt} {DEBUG_ID2&&'['+this.props.id+'_R'+p1+'_C'+i+']'}</td>
|
|
257
|
+
}
|
|
258
|
+
})}
|
|
259
|
+
|
|
260
|
+
<td key={lastIndex+1} align='left'>
|
|
261
|
+
{!this.props.inPlaceEdit&&this.props.metadata.hasEditFn&&this.props.metadata.hasEditFn(item)&&<button id={'Edt_'+p1+'_'+this.props.id} onClick={()=>this.props.onAction(p1,item)} className="btn--flat nudge--right"><i className="fa fa-pencil"></i>{DEBUG_ID&&'Edt_'+p1+'_'+this.props.id}{this.props.textlabels?"Edit":""}</button>}
|
|
262
|
+
{this.props.metadata.hasDeleteFn&&this.props.metadata.hasDeleteFn(item)&&<button id={'Del_'+p1+'_'+this.props.id} onClick={()=>this.props.onDelete(p1,item)} className="btn--flat nudge--right"><i className="fa fa-trash"></i>{DEBUG_ID&&'Del_'+p1+'_'+this.props.id}{this.props.textlabels?"Delete":""}</button>}
|
|
263
|
+
</td>
|
|
264
|
+
|
|
265
|
+
</tr>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
export {XTableRead,nfmt,nfmt2,nfmtM};
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@andersonalmeidax0/webcomponents",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "webcomponents",
|
|
5
|
+
"main": "webcomponents",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/andersonalmeidax0/webcomponents.git"
|
|
12
|
+
},
|
|
13
|
+
"author": "aax0",
|
|
14
|
+
"license": "ISC",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/andersonalmeidax0/webcomponents/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/andersonalmeidax0/webcomponents#readme"
|
|
19
|
+
}
|
package/releasenotes.txt
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
0.1.0: beta
|
|
2
|
+
0.1.1: add all components
|
|
3
|
+
0.1.2: with text labels for buttons
|
|
4
|
+
|
|
5
|
+
TODO
|
|
6
|
+
-change "Errors" => string contants
|
|
7
|
+
-add "textIcon=true" option para JZEditTable ==> OK
|
|
8
|
+
-create NPM
|
|
9
|
+
-test
|
|
10
|
+
|
|
11
|
+
-readme: document capacities
|
|
12
|
+
JZ read and form: format specs, types
|
|
13
|
+
JZEdit: api spec, inplace, triggerUpdate cols, links, renders, totalRenders,
|
|
14
|
+
"Tester Friendly" hiden info (ex: last combo item), ID-based components
|
|
15
|
+
|
|
16
|
+
=====
|
|
17
|
+
TODO:
|
|
18
|
+
Exepctions de erros, criador para a)evitar tratar StatusCodesHttp e b)permitir "try catch" de erros "subindo" no stack
|
|
19
|
+
Expection "genericas" assim é só import de constantes, e tratar em qualquer camada com "Error.message==xxxx"
|
|
20
|
+
Package separado, assim dá para usar na aplicação "Error.message==xxxx", em npms, e também no server, com imports redundantes
|
|
21
|
+
1-criar test cases para PlatAPIError
|
|
22
|
+
2-criar uma classe com constantes string de error APIErrors
|
|
23
|
+
3-Incluir APIAdapter no código de JZComponents
|
|
24
|
+
4-Tratar erros vendo se e.message==APIErrors.API<messageCode>
|
|
25
|
+
-"Throw" erros com constructor == APIErrors.API<messageCode> (vai ficar no atributo message)
|
|
26
|
+
==>Alterar APIAdapter para dar "throw" de new Error(APIErrors.API<messageCode>)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
//Auth
|
|
30
|
+
PlatAPIAuthError
|
|
31
|
+
PlatAPIForbidden
|
|
32
|
+
//DB
|
|
33
|
+
PlatAPIDBNotFound
|
|
34
|
+
PlatAPIDBIntegrityConstraint
|
|
35
|
+
//Internal
|
|
36
|
+
PlatAPIError ==> PlatAPIPayloadError
|
|
37
|
+
PlatAPIReturnCodeError ==> PlatAPIServerError
|