backend-plus 2.0.0-rc.3 → 2.0.0-rc.31

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.
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  "use strict";
3
3
 
4
- var {datetime, changing, coalesce} = require('best-globals');
4
+ var {datetime, changing, coalesce, splitRawRowIntoRow} = require('best-globals');
5
5
  var XLSX = require('xlsx');
6
6
  var fs = require('fs/promises')
7
7
  var fsSync = require('fs');
@@ -78,13 +78,14 @@ ProcedureTables = [
78
78
  {name: 'table', encoding:'plain'},
79
79
  {name: 'fixedFields', defaultValue:[]},
80
80
  {name: 'paramfun', defaultValue:[]},
81
- {name: 'pick', defaultValue:'', encoding:'plain'}
81
+ {name: 'pick', defaultValue:'', encoding:'plain'},
82
+ {name: 'retrieveIgnoringWhere', defaultValue:false}
82
83
  ],
83
84
  coreFunction:
84
85
  /**
85
86
  *
86
87
  * @param {*} context
87
- * @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string}} parameters
88
+ * @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string, retrieveIgnoringWhere:boolean}} parameters * @param {{table:string, fixedFields:{fieldName:string, value:any, range:string}[], paramfun:string[], pick:string}} parameters
88
89
  */
89
90
  async function tableDatum(context, parameters){
90
91
  var be=context.be;
@@ -148,7 +149,7 @@ ProcedureTables = [
148
149
  /** @type {string} */
149
150
  var sql="SELECT "+[...defTable.sql.select].join(', ')+
150
151
  "\n FROM "+defTable.sql.from+
151
- "\n WHERE "+(defTable.sql.where||(defTable.allow.select && !defTable.forInsertOnlyMode?'true':'false'))+fixedClausule.join("")+
152
+ "\n WHERE "+((parameters.retrieveIgnoringWhere?'true':defTable.sql.where)||(defTable.allow.select && !defTable.forInsertOnlyMode?'true':'false'))+fixedClausule.join("")+
152
153
  // " ORDER BY "+defTable.primaryKey.map(be.db.quoteIdent.bind(be.db)).join(',')
153
154
  "\n ORDER BY "+(defTable.sql.orderBy||defTable.primaryKey).map(function(fieldName){ return be.db.quoteIdent(fieldName); }).join(',')
154
155
  if(specialFixedClause.length){
@@ -200,7 +201,7 @@ ProcedureTables = [
200
201
  tables:{},
201
202
  tableNames:{}
202
203
  };
203
- var expectedMainPrimaryKeyValues=parameters.primaryKeyValues;
204
+ var expectedMainPrimaryKeyValues = parameters.primaryKeyValues;
204
205
  /** @type { TableUpdater } */
205
206
  // @ts-expect-error parece no asignada pero al menos un nombre hay en el ciclo y por lo tanto va a tener valor
206
207
  var updateTarget = {}
@@ -256,6 +257,7 @@ ProcedureTables = [
256
257
  });
257
258
  var result;
258
259
  var mainResult;
260
+ var initialUpdatesLength = updates.length;
259
261
  while(updates.length){
260
262
  var {fieldNames, values, defTable, main} = notnull(updates.shift());
261
263
  var values4Insert = values.slice(0);
@@ -271,7 +273,7 @@ ProcedureTables = [
271
273
  values4Insert[i] = value;
272
274
  }
273
275
  }
274
- if(defField.generatedAs){
276
+ if(defField.generatedAs || defField.inTable === false){
275
277
  var i = fieldNames4Insert.indexOf(defField.name);
276
278
  if(i!==-1){
277
279
  fieldNames4Insert.splice(i,1);
@@ -283,10 +285,11 @@ ProcedureTables = [
283
285
  var primaryKeyValues=[]
284
286
  var primaryKeyValuesForUpdate=[]
285
287
  var primaryKeyValueObject={};
288
+ var fieldNames4InsertWithoutPkAddings = fieldNames4Insert.slice(0);
286
289
  defTable.primaryKey.forEach(function(name,i){
287
290
  var value = main?parameters.primaryKeyValues[i]:coalesce(parameters.newRow[name],parameters.oldRow[name],undefined);
291
+ var defField = defTable.field[name];
288
292
  if(value===undefined){
289
- var defField = defTable.field[name];
290
293
  value = defTable.prefilledField && name in defTable.prefilledField ? defTable.prefilledField[name] : (
291
294
  'defaultValue' in defField?defField.defaultValue:(
292
295
  'specialDefaultValue' in defField?new Error("my.specialDefaultValue[defField.specialDefaultValue](name, {row:{}}, {row:previousRow})"):undefined
@@ -303,13 +306,16 @@ ProcedureTables = [
303
306
  }else{
304
307
  primaryKeyValuesForUpdate[i]=value;
305
308
  }
306
- if(!fieldNames4Insert.includes(name) && value != null){
309
+ if(!fieldNames4Insert.includes(name) && value != null && defField.inTable !== false){
307
310
  fieldNames4Insert.push(name);
308
311
  values4Insert.push(value);
309
312
  }
310
313
  });
311
- if(main){
312
- expectedMainPrimaryKeyValues=primaryKeyValues;
314
+ if (main) {
315
+ expectedMainPrimaryKeyValues = primaryKeyValues;
316
+ } else if (defTable.sql.setExpectedPkValues) {
317
+ expectedMainPrimaryKeyValues = primaryKeyValues.slice(0);
318
+ while (expectedMainPrimaryKeyValues.length < mainDefTable.primaryKey.length) expectedMainPrimaryKeyValues.push(null);
313
319
  }
314
320
  var returningClausule='';
315
321
  if(opts && opts.forImport){
@@ -330,7 +336,9 @@ ProcedureTables = [
330
336
  return result;
331
337
  }
332
338
  var sql;
333
- if(defTable && parameters.status=='new'){
339
+ if (defTable?.sql?.isTable === false && initialUpdatesLength > 1 && fieldNames4InsertWithoutPkAddings.length == 0) {
340
+ // New feature. Ignore attempts to save to non tables when pseudo tables save in others
341
+ } else if(defTable && parameters.status=='new'){
334
342
  result = await insertFun();
335
343
  }else if(defTable && primaryKeyValues.length==defTable.primaryKey.length){
336
344
  var values4Update = [];
@@ -399,6 +407,12 @@ ProcedureTables = [
399
407
  var rowFrom = parameters.status!='new' && !plainUpdate.values.length?
400
408
  likeAr.toPlainObject(mainDefTable.primaryKey,expectedMainPrimaryKeyValues):
401
409
  (mainResult||result).row;
410
+ for (var fieldname of mainDefTable.primaryKey) {
411
+ if (rowFrom[fieldname] == null) {
412
+ var newValue = parameters.newRow[fieldname] ?? parameters.oldRow[fieldname];
413
+ if (newValue != null) rowFrom[fieldname] = newValue
414
+ }
415
+ }
402
416
  result = await be.queryValuesOfUniqueRow(context, mainDefTable, rowFrom);
403
417
  }
404
418
  return {command:insertOrUpdate, row:result.row};
@@ -416,16 +430,26 @@ ProcedureTables = [
416
430
  if(!defTable.allow.delete){
417
431
  throw changing(new Error("Deletes not allowed"),{status:403});
418
432
  }
419
- var primaryKeyFields=defTable.primaryKey4Delete||defTable.primaryKey;
420
- var primaryKeyValues=parameters.primaryKeyValues;
433
+ if (defTable.primaryKey4Delete) {
434
+ console.log("DEPRECATED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! defTable.primaryKey4Delete", defTable.name);
435
+ }
436
+ var primaryKeyFields = defTable.primaryKey4Delete ?? defTable.sql.primaryKey4Delete ?? defTable.primaryKey;
437
+ var primaryKeyValues = [];
438
+ var tableName4Delete = defTable.sql.tableName4Delete ?? defTable.sql.tableName;
439
+ for (var fieldName of primaryKeyFields) {
440
+ var pos = defTable.primaryKey.indexOf(fieldName);
441
+ if (pos > -1) {
442
+ primaryKeyValues.push(parameters.primaryKeyValues[pos]);
443
+ }
444
+ }
421
445
  if(defTable && primaryKeyValues.length==primaryKeyFields.length){
422
446
  var sqlDelete;
423
447
  if(defTable.sql.logicalDeletes){
424
- sqlDelete="UPDATE "+be.db.quoteIdent(defTable.sql.tableName)+
448
+ sqlDelete="UPDATE "+be.db.quoteIdent(tableName4Delete)+
425
449
  " SET "+be.db.quoteIdent(defTable.sql.logicalDeletes.fieldName)+
426
450
  " = "+be.db.quoteNullable(defTable.sql.logicalDeletes.valueToDelete);
427
451
  }else{
428
- sqlDelete="DELETE FROM "+be.db.quoteIdent(defTable.sql.tableName);
452
+ sqlDelete="DELETE FROM "+be.db.quoteIdent(tableName4Delete);
429
453
  }
430
454
  sqlDelete+=" WHERE "+primaryKeyFields.map(function(fieldName, i){
431
455
  return be.db.quoteIdent(fieldName)+" = $"+(i+1);
@@ -452,6 +476,7 @@ ProcedureTables = [
452
476
  context.informProgress({message:be.messages.server.deleting})
453
477
  var be=context.be;
454
478
  var defTable=be.tableStructures[parameters.table](context);
479
+ var tableName4Delete = defTable.sql.tableName4Delete ?? defTable.sql.tableName;
455
480
  if(!defTable.allow.delete && !defTable.allow.deleteAll){
456
481
  throw changing(new Error("Deletes not allowed"),{status:403});
457
482
  }
@@ -479,7 +504,7 @@ ProcedureTables = [
479
504
  }
480
505
  });
481
506
  return context.client.query(
482
- "DELETE FROM "+be.db.quoteIdent(defTable.sql.tableName)+
507
+ "DELETE FROM "+be.db.quoteIdent(tableName4Delete)+
483
508
  " WHERE "+whereParts.join(" AND ")+" RETURNING 1",
484
509
  dataParams
485
510
  ).fetchUniqueRow().then(function(){
@@ -489,7 +514,7 @@ ProcedureTables = [
489
514
  };
490
515
  var result = await Promise.all(parameters.rowsToDelete.map(deleteOneRow)).then(function(){
491
516
  return context.client.query(
492
- "SELECT count(*) remaining_record_count FROM "+be.db.quoteIdent(defTable.sql.tableName)
517
+ "SELECT count(*) remaining_record_count FROM "+be.db.quoteIdent(tableName4Delete)
493
518
  ).fetchUniqueRow().then(function(result){
494
519
  context.informProgress({lengthComputable:true, loaded:deleteCounter, total:parameters.rowsToDelete.length, force:true});
495
520
  return result.row;
@@ -692,7 +717,7 @@ ProcedureTables = [
692
717
  {name: 'replaceNewLineWithSpace'},
693
718
  ],
694
719
  files:{count:1},
695
- coreFunction:async function(context, parameters, files){
720
+ coreFunction:async function table_upload(context, parameters, files){
696
721
  var be=context.be;
697
722
  var doing="opening file";
698
723
  var skipUnknownFieldsAtImport = coalesce(parameters.skipUnknownFieldsAtImport, be.config.skipUnknownFieldsAtImport);
@@ -804,7 +829,8 @@ ProcedureTables = [
804
829
  var rowsForUpsert=lines.slice(1).map(function(line){
805
830
  var othersArray = [];
806
831
  if(separator=='|'){
807
- var row = line.split(/(?<!(?:^|[^\\])(?:\\\\)*\\)\|/).map(item => item.trimRight().replace(/\\(.)/g,(_,l)=>(l=='t'?'\t':l=='r'?'\r':l=='n'?'\n':l=='s'?' ':l)));
832
+ var row = splitRawRowIntoRow(line);
833
+
808
834
  }else{
809
835
  var row=line.split(separator);
810
836
  }
@@ -821,6 +847,9 @@ ProcedureTables = [
821
847
  if(value != null && parameters.skipUnknownFieldsAtImport){
822
848
  value = value.replace(/(\s|\u00A0)+/g,' ').trim()
823
849
  }
850
+ if (value == null && field.allowEmptyText && ('nullable' in field) && !field.nullable ) {
851
+ value = ''
852
+ }
824
853
  newRow[field.name]=value;
825
854
  }
826
855
  });
@@ -900,6 +929,9 @@ ProcedureTables = [
900
929
  if(Number.isNaN(value)){
901
930
  value=null;
902
931
  }
932
+ if (value == null && field.allowEmptyText && ('nullable' in field) && !field.nullable ) {
933
+ value = ''
934
+ }
903
935
  if(field.defaultForOtherFields){
904
936
  addFieldToOthers(othersArray, field, value);
905
937
  }else{
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "backend-plus",
3
3
  "description": "Backend for the anti Pareto rule",
4
- "version": "2.0.0-rc.3",
4
+ "version": "2.0.0-rc.31",
5
5
  "author": "Codenautas <codenautas@googlegroups.com>",
6
6
  "license": "MIT",
7
7
  "repository": "codenautas/backend-plus",
@@ -11,7 +11,8 @@
11
11
  "lib",
12
12
  "for-client",
13
13
  "unlogged",
14
- "src"
14
+ "src",
15
+ "install"
15
16
  ],
16
17
  "contributors": [
17
18
  {
@@ -29,48 +30,48 @@
29
30
  ],
30
31
  "dependencies": {
31
32
  "@upgraded/locate-path": "^6.0.0-alfa.1",
32
- "ajax-best-promise": "^0.4.0",
33
+ "ajax-best-promise": "^0.4.2",
33
34
  "backend-skins": "^0.1.15",
34
- "best-globals": "^1.1.2",
35
- "big.js": "^6.2.1",
36
- "body-parser": "^1.20.2",
37
- "cast-error": "^0.1.0",
38
- "castellano": "^0.1.3",
39
- "connect-pg-simple": "^9.0.1",
35
+ "best-globals": "^1.1.6",
36
+ "big.js": "^6.2.2",
37
+ "body-parser": "^1.20.3",
38
+ "cast-error": "^0.1.1",
39
+ "castellano": "^0.1.4",
40
+ "connect-pg-simple": "^10.0.0",
40
41
  "cookie-parser": "^1.4.6",
41
- "dialog-promise": "^0.9.15",
42
+ "dialog-promise": "^0.10.0",
42
43
  "discrepances": "^0.2.8",
43
- "express": "^4.18.2",
44
- "express-session": "^1.17.3",
44
+ "express": "^4.21.0",
45
+ "express-session": "^1.18.0",
45
46
  "express-useragent": "^1.0.15",
46
47
  "fs-extra": "^11.2.0",
47
48
  "js-to-html": "^1.3.2",
48
49
  "js-yaml": "^4.1.0",
49
- "json4all": "^1.3.0-beta.1",
50
+ "json4all": "^1.4.0",
50
51
  "lazy-some": "^0.1.0",
51
- "like-ar": "^0.3.9",
52
+ "like-ar": "^0.5.1",
52
53
  "login-plus": "^1.7.1",
53
54
  "memorystore": "^1.6.7",
54
- "mini-tools": "^1.12.1",
55
+ "mini-tools": "^1.12.2",
55
56
  "moment": "^2.30.1",
56
57
  "multiparty": "^4.2.3",
57
- "nodemailer": "^6.9.8",
58
+ "nodemailer": "^6.9.15",
58
59
  "numeral": "^2.0.6",
59
- "pg-promise-strict": "^1.3.3",
60
+ "pg-promise-strict": "^1.4.1",
60
61
  "pikaday": "^1.8.2",
61
- "pug": "^3.0.2",
62
+ "pug": "^3.0.3",
62
63
  "read-yaml-promise": "^1.0.2",
63
64
  "regexplicit": "^0.1.3",
64
65
  "require-bro": "^0.3.1",
65
- "self-explain": "^0.10.22",
66
- "serve-content": "^0.3.19",
66
+ "self-explain": "^0.11.0",
67
+ "serve-content": "^0.3.20",
67
68
  "session-file-store": "^1.5.0",
68
69
  "sql-tools": "^0.1.2",
69
70
  "stack-trace": "^0.0.10",
70
- "stylus": "0.62.0",
71
- "type-store": "^0.4.0",
72
- "typed-controls": "^0.12.0",
73
- "xlsx": "https://cdn.sheetjs.com/xlsx-0.19.3/xlsx-0.19.3.tgz"
71
+ "stylus": "0.63.0",
72
+ "type-store": "^0.4.2",
73
+ "typed-controls": "^0.12.1",
74
+ "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
74
75
  },
75
76
  "devDependencies": {
76
77
  "@types/big.js": "^6.2.2",
@@ -79,31 +80,31 @@
79
80
  "@types/express-useragent": "^1.0.5",
80
81
  "@types/fs-extra": "^11.0.4",
81
82
  "@types/js-yaml": "^4.0.9",
82
- "@types/mocha": "^10.0.6",
83
+ "@types/mocha": "^10.0.8",
83
84
  "@types/multiparty": "~0.0.36",
84
- "@types/node": "^20.11.9",
85
- "@types/nodemailer": "^6.4.14",
85
+ "@types/node": "^22.5.5",
86
+ "@types/nodemailer": "^6.4.16",
86
87
  "@types/numeral": "~2.0.5",
87
88
  "@types/session-file-store": "^1.2.5",
88
89
  "@types/stack-trace": "~0.0.33",
89
90
  "@types/websql": "~0.0.30",
90
91
  "esprima": "^4.0.1",
91
92
  "expect.js": "~0.3.1",
92
- "karma": "6.4.2",
93
+ "karma": "6.4.4",
93
94
  "karma-chrome-launcher": "^3.2.0",
94
95
  "karma-expect": "^1.1.3",
95
- "karma-firefox-launcher": "^2.1.2",
96
+ "karma-firefox-launcher": "^2.1.3",
96
97
  "karma-ie-launcher": "^1.0.0",
97
98
  "karma-mocha": "^2.0.1",
98
99
  "kill-9": "~0.4.3",
99
- "mocha": "^10.2.0",
100
- "nyc": "^15.1.0",
101
- "puppeteer": "^21.9.0",
102
- "sinon": "^17.0.1",
103
- "supertest": "^6.3.4",
100
+ "mocha": "^10.7.3",
101
+ "nyc": "^17.1.0",
102
+ "puppeteer": "^23.4.0",
103
+ "sinon": "^19.0.2",
104
+ "supertest": "^7.0.0",
104
105
  "types.d.ts": "~0.6.21",
105
- "typescript": "^5.3.3",
106
- "why-is-node-running": "^2.2.2"
106
+ "typescript": "^5.6.2",
107
+ "why-is-node-running": "^3.2.0"
107
108
  },
108
109
  "engines": {
109
110
  "node": ">= 18"
@@ -193,14 +193,17 @@ myAjax.ajaxPromise = function ajaxPromise(procedureDef,data,opts){
193
193
  }
194
194
  var result=[];
195
195
  var progress=procedureDef.progress!==false;
196
+ /** @type {Record<string,{ divBar, progressBar, progresIndicator, divBarLabel }>} */
197
+ var progressStruct = {}
196
198
  var divProgress;
197
- var divBarProgress;
198
- var progressBar;
199
- var progressIndicator;
200
- var divBarProgressLabel;
199
+ // var divBarProgress = {};
200
+ // var progressBar;
201
+ // var progressIndicator;
202
+ // var divBarProgressLabel = {};
201
203
  var onClose=function(){}
202
204
  var defaultInformProgress = function defaultInformProgress(progressInfo){
203
205
  if(progressInfo.message || progressInfo.end || progressInfo.start || progressInfo.loaded){
206
+ // progressInfo.idGroup
204
207
  if(!divProgress){
205
208
  var idAutoClose='id-auto-close-'+Math.random();
206
209
  var checkAutoClose=html.input({type:'checkbox', id:idAutoClose, checked:myAjax.ajaxPromise.autoClose}).create();
@@ -235,8 +238,12 @@ myAjax.ajaxPromise = function ajaxPromise(procedureDef,data,opts){
235
238
  }
236
239
  }
237
240
  }
238
- if(progressInfo.ephemeral && divBarProgressLabel){
239
- divBarProgressLabel.textContent=progressInfo.message;
241
+ if (progressStruct[progressInfo.idGroup] == null) {
242
+ progressStruct[progressInfo.idGroup] = {}
243
+ }
244
+ var ps = progressStruct[progressInfo.idGroup];
245
+ if(progressInfo.ephemeral && ps.divBarLabel){
246
+ ps.divBarLabel.textContent = progressInfo.message;
240
247
  }else if(progressInfo.message || progressInfo.end){
241
248
  var now=bestGlobals.datetime.now();
242
249
  var elapsed = now.sub(tickTime);
@@ -265,23 +272,23 @@ myAjax.ajaxPromise = function ajaxPromise(procedureDef,data,opts){
265
272
  );
266
273
  }
267
274
  }
268
- if(progressInfo.loaded){
269
- if(!divBarProgress){
270
- divBarProgressLabel = html.div().create();
271
- progressIndicator=html.div({class:'indicator'},' ').create();
272
- progressBar=html.div({class:'progress-bar', style:'width:400px; height:8px;'},[progressIndicator]).create();
273
- divBarProgress = html.div([
274
- divBarProgressLabel,
275
- progressBar
275
+ if(progressInfo.loaded != null){
276
+ if(!ps.divBar){
277
+ ps.divBarLabel = html.div().create();
278
+ ps.progressIndicator=html.div({class:'indicator'},' ').create();
279
+ ps.progressBar=html.div({class:'progress-bar', style:'width:400px; height:8px;'},[ps.progressIndicator]).create();
280
+ ps.divBar = html.div([
281
+ ps.divBarLabel,
282
+ ps.progressBar
276
283
  ]).create();
277
- divProgress.parentNode.insertBefore(divBarProgress, divProgress);
284
+ divProgress.parentNode.insertBefore(ps.divBar, divProgress);
278
285
  }
279
286
  if(progressInfo.lengthComputable){
280
- progressIndicator.style.width=progressInfo.loaded*100/progressInfo.total+'%';
281
- progressIndicator.title=Math.round(progressInfo.loaded*100/progressInfo.total)+'%';
287
+ ps.progressIndicator.style.width=progressInfo.loaded*100/progressInfo.total+'%';
288
+ ps.progressIndicator.title=Math.round(progressInfo.loaded*100/progressInfo.total)+'%';
282
289
  }else{
283
- progressIndicator.style.backgroundColor='#D4D';
284
- progressIndicator.title='N/D %';
290
+ ps.progressIndicator.style.backgroundColor='#D4D';
291
+ ps.progressIndicator.title='N/D %';
285
292
  }
286
293
  }
287
294
  }
@@ -304,7 +311,6 @@ myAjax.ajaxPromise = function ajaxPromise(procedureDef,data,opts){
304
311
  }
305
312
  var controlLoggedIn = function controlLoggedIn(result, informNotLoggedIn){
306
313
  if(informNotLoggedIn || result && result[0]=="<" && result.match(/login/m)){
307
- console.log('xxxxxxxxxxx',procedureDef.action)
308
314
  my.informDetectedStatus('notLogged');
309
315
  throw bestGlobals.changing(new Error(my.messages.notLogged),{displayed:true, isNotLoggedError:true});
310
316
  }
@@ -495,13 +501,27 @@ function agregar_json_default_ubicaciones(div, o, a){
495
501
  var table = div2.laTabla;
496
502
  var row = table.insertRow(-1);
497
503
  var cellName = row.insertCell(-1);
498
- cellName.className='attr-name';
499
- cellName.textContent = a;
504
+ agregar_class_textInDiv(cellName, 'attr-name', a)
500
505
  var cell = row.insertCell(-1);
501
506
  cell.colSpan=99;
502
507
  return {title:cellName, data:cell, skip:o[a] == null}
503
508
  }
504
509
 
510
+ /**
511
+ *
512
+ * @param {HTMLTableDataElement} td
513
+ * @param {string|number} text
514
+ * @param {string} className
515
+ */
516
+ function agregar_class_textInDiv(td, className, text){
517
+ var div = document.createElement('div');
518
+ td.className = className;
519
+ div.className = 'json-container';
520
+ div.textContent = text;
521
+ td.innerHTML = '';
522
+ td.appendChild(div);
523
+ }
524
+
505
525
  /**
506
526
  *
507
527
  * @param {HTMLElement} div
@@ -524,9 +544,7 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
524
544
  if(o[a]!=null){
525
545
  var row = table.insertRow(-1);
526
546
  var cellName = row.insertCell(-1);
527
- cellName.className='row-num';
528
- // @ts-ignore numero y texto
529
- cellName.textContent = isNaN(a)?a:Number(a)+1;
547
+ agregar_class_textInDiv(cellName, 'row-num', isNaN(a)?a:Number(a)+1);
530
548
  agregar_json(row, o[a], function(div, _o, a){
531
549
  // @ts-ignore sé que es Row
532
550
  /** @type {HTMLTableRowElement} */
@@ -554,11 +572,9 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
554
572
  if(!cells.skip){
555
573
  if(cells.title){
556
574
  if(o instanceof Array && !isNaN(a)){
557
- cells.title.className='row-num';
558
- cells.title.textContent = Number(a) + 1;
575
+ agregar_class_textInDiv(cells.title, 'row-num', Number(a) + 1);
559
576
  }else{
560
- cells.title.className='attr-name';
561
- cells.title.textContent = a;
577
+ agregar_class_textInDiv(cells.title, 'attr-name', a);
562
578
  }
563
579
  }
564
580
  agregar_json(cells.data, o[a]);
@@ -566,13 +582,16 @@ function agregar_json(div, o, ubicaciones=agregar_json_default_ubicaciones){
566
582
  }
567
583
  }
568
584
  }else{
569
- div.className='plain-content';
585
+ var textContent;
570
586
  if(typeof o == "boolean"){
571
- div.textContent = o?'Sí':'No'
587
+ textContent = o ? 'Sí' : 'No'
572
588
  }else if(o && o instanceof Date && o.isRealDate){
573
- div.textContent = o.toDmy();
589
+ textContent = o.toDmy();
574
590
  }else{
575
- div.textContent = o.toLocaleString();
591
+ textContent = o.toLocaleString();
592
+ }
593
+ if (textContent) {
594
+ agregar_class_textInDiv(div, 'plain-content', textContent)
576
595
  }
577
596
  }
578
597
  }