@livinglogic/livingapi 0.13.2 → 0.14.2

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/src/livingapi.js CHANGED
@@ -34,6 +34,30 @@ export { version };
34
34
  import * as ul4 from '@livinglogic/ul4';
35
35
 
36
36
 
37
+ export function element(name, ...args)
38
+ {
39
+ let dom_node = document.createElement(name);
40
+ for (let arg of args)
41
+ {
42
+ if (typeof(arg) === "string")
43
+ dom_node.appendChild(document.createTextNode(arg));
44
+ let ismap = arg instanceof Map;
45
+ let isobject = ul4._isobject(arg);
46
+ if (ismap || isobject)
47
+ {
48
+ if (isobject)
49
+ arg = Object.entries(arg);
50
+ for (let [name, value] of arg)
51
+ {
52
+ if (value !== null)
53
+ dom_node.setAttribute(name, value);
54
+ }
55
+ }
56
+ }
57
+ return dom_node;
58
+ }
59
+
60
+
37
61
  export class Base extends ul4.Proto
38
62
  {
39
63
  constructor(id)
@@ -99,9 +123,24 @@ export class Base extends ul4.Proto
99
123
  }
100
124
  return value;
101
125
  }
126
+ else if (name.startsWith("x_"))
127
+ {
128
+ return this.hasOwnProperty(name) ? this[name] : null;
129
+ }
102
130
  throw new ul4.AttributeError(this, name);
103
131
  }
104
132
 
133
+ [ul4.symbols.setattr](name, value)
134
+ {
135
+ if (name.startsWith("x_"))
136
+ {
137
+ this[name] = value;
138
+ }
139
+ else
140
+ throw new ul4.AttributeError(this, name);
141
+ }
142
+
143
+
105
144
  [ul4.symbols.repr]()
106
145
  {
107
146
  return "<" + this.constructor.name + ">";
@@ -126,10 +165,19 @@ export class Handler
126
165
  };
127
166
 
128
167
 
129
- export class Globals extends Base
168
+ class GlobalsType extends ul4.Type
130
169
  {
131
- static classdoc = "Global information";
170
+ instancecheck(obj)
171
+ {
172
+ return obj instanceof Globals;
173
+ }
174
+ };
175
+
176
+ let globalstype = new GlobalsType("la", "Globals", "Global information");
132
177
 
178
+
179
+ export class Globals extends Base
180
+ {
133
181
  constructor(id)
134
182
  {
135
183
  super(id);
@@ -138,16 +186,27 @@ export class Globals extends Base
138
186
  this.platform = null;
139
187
  this.user = null;
140
188
  this.lang = null;
189
+ this.datasources = null;
141
190
  this.app = null;
142
191
  this.record = null;
192
+ this.mode = null;
143
193
  this.maxdbactions = null;
144
194
  this.maxtemplateruntime = null;
145
195
  this.flashmessages = null;
196
+ this.view_template_id = null;
197
+ this.email_template_id = null;
146
198
  this.handler = new Handler();
199
+ this._log_stack = [];
200
+ this._current_geo = null;
201
+ }
202
+
203
+ [ul4.symbols.type]()
204
+ {
205
+ return globalstype;
147
206
  }
148
207
 
149
208
  // distance between two geo coordinates (see https://de.wikipedia.org/wiki/Orthodrome#Genauere_Formel_zur_Abstandsberechnung_auf_der_Erde)
150
- static geodist(geo1, geo2)
209
+ geo_dist(geo1, geo2)
151
210
  {
152
211
  let sqsin = function sqsin(x) {x = Math.sin(x); return x*x};
153
212
  let sqcos = function sqsos(x) {x = Math.cos(x); return x*x};
@@ -173,15 +232,15 @@ export class Globals extends Base
173
232
  return s;
174
233
  }
175
234
 
176
- scaledURL(url, width, height, type="fill", enlarge=true, gravity="sm", quality=null, rotate=null, blur=null, sharpen=null, format=null, cache=true)
235
+ scaled_url(image, width, height, type="fill", enlarge=true, gravity="sm", quality=null, rotate=null, blur=null, sharpen=null, format=null, cache=true)
177
236
  {
178
237
  let filename = null;
179
238
 
180
- if (url instanceof File)
239
+ if (image instanceof File)
181
240
  {
182
- url = "https://" + this.hostname + url.url;
183
- filename = encodeURIComponent(url.filename);
184
- if (filename != url.filename)
241
+ image = "https://" + this.hostname + image.archive_url;
242
+ filename = encodeURIComponent(image.filename);
243
+ if (filename != image.filename)
185
244
  filename = null;
186
245
  }
187
246
 
@@ -225,24 +284,207 @@ export class Globals extends Base
225
284
  if (filename !== null && filename !== undefined)
226
285
  result += "/fn:" + filename;
227
286
 
228
- result += "/plain/" + encodeURIComponent(url);
287
+ result += "/plain/" + encodeURIComponent(image);
229
288
 
230
289
  return result;
231
290
  }
232
291
 
233
292
  [ul4.symbols.repr]()
234
293
  {
235
- return "<Globals version=" + ul4._repr(this.version) + ">";
294
+ return "<Globals version=" + ul4._repr(this.version) + " mode=" + ul4._repr(this.mode) + ">";
295
+ }
296
+
297
+ current_geo()
298
+ {
299
+ return this._current_geo;
300
+ }
301
+
302
+ set_current_geo(position)
303
+ {
304
+ this._current_geo = new Geo(position.coords.latitude, position.coords.longitude);
305
+ }
306
+
307
+ _in_form()
308
+ {
309
+ return this.mode !== null && this.mode.startsWith("form/");
310
+ }
311
+
312
+ msg_bool(value)
313
+ {
314
+ switch (value)
315
+ {
316
+ case true:
317
+ return this.msg_bool_true();
318
+ case false:
319
+ return this.msg_bool_false();
320
+ default:
321
+ return null;
322
+ }
323
+ }
324
+
325
+ msg_bool_true(value)
326
+ {
327
+ switch (this.lang)
328
+ {
329
+ case "de":
330
+ return "Ja";
331
+ default:
332
+ return "Yes";
333
+ }
334
+ }
335
+
336
+ msg_bool_false(value)
337
+ {
338
+ switch (this.lang)
339
+ {
340
+ case "de":
341
+ return "Nein";
342
+ default:
343
+ return "No";
344
+ }
345
+ }
346
+
347
+ msg_no_fields()
348
+ {
349
+ switch (this.lang)
350
+ {
351
+ case "de":
352
+ return "(Keine Felder gefunden)";
353
+ default:
354
+ return "(No fields found)";
355
+ }
356
+ }
357
+
358
+ msg_nothing_selected()
359
+ {
360
+ switch (this.lang)
361
+ {
362
+ case "de":
363
+ return "(Nichts ausgewählt)";
364
+ default:
365
+ return "(Nothing selected)";
366
+ }
367
+ }
368
+
369
+ _make_log_message(messages)
370
+ {
371
+ return messages
372
+ .map(m => typeof(m) !== "string" ? ul4._repr(m) : m)
373
+ .join(" ")
374
+ ;
375
+ }
376
+
377
+ begin_logging(header)
378
+ {
379
+ this._log_stack.push({header: header, output: false});
380
+ }
381
+
382
+ end_logging()
383
+ {
384
+ if (this._log_stack)
385
+ {
386
+ if (this._log_stack[this._log_stack.length-1].output && console && console.groupEnd)
387
+ console.groupEnd();
388
+ this._log_stack.pop();
389
+ }
390
+ }
391
+
392
+ group_logging(header, callback)
393
+ {
394
+ this.begin_logging(header);
395
+ try
396
+ {
397
+ callback();
398
+ }
399
+ finally
400
+ {
401
+ this.end_logging();
402
+ }
403
+ }
404
+
405
+ _start_log_message()
406
+ {
407
+ for (let level of this._log_stack)
408
+ {
409
+ if (!level.output)
410
+ {
411
+ if (console && console.group)
412
+ console.group(level.header)
413
+ level.output = true;
414
+ }
415
+ }
416
+ }
417
+
418
+ log_debug(...message)
419
+ {
420
+ this._start_log_message();
421
+ if (console && console.debug)
422
+ console.debug(this._make_log_message(message))
423
+ }
424
+
425
+ log_info(...message)
426
+ {
427
+ this._start_log_message();
428
+ if (console && console.info)
429
+ console.info(this._make_log_message(message))
430
+ }
431
+
432
+ log_warning(...message)
433
+ {
434
+ this._start_log_message();
435
+ if (console && console.warn)
436
+ console.warn(this._make_log_message(message))
437
+ }
438
+
439
+ log_error(...message)
440
+ {
441
+ this._start_log_message();
442
+ if (console && console.error)
443
+ console.error(this._make_log_message(message))
236
444
  }
237
445
  };
238
446
 
239
- Globals.prototype._ul4onattrs = ["version", "platform", "user", "maxdbactions", "maxtemplateruntime", "flashmessages", "lang", "datasources", "hostname", "app", "record", "google_api_key", "mode", "view_template_id", "email_template_id", "view_id"];
240
- Globals.prototype._ul4attrs = new Set(["version", "hostname", "platform", "user", "lang", "app", "record", "maxdbactions", "maxtemplateruntime", "flashmessages", "mode"]);
447
+ Globals.prototype._ul4onattrs = ["version", "platform", "user", "maxdbactions", "maxtemplateruntime", "lang", "datasources", "hostname", "app", "record", "mode", "view_template_id", "email_template_id", "view_id"];
448
+ Globals.prototype._ul4attrs = new Set(["version", "hostname", "platform", "user", "lang", "datasources", "app", "record", "maxdbactions", "maxtemplateruntime", "flashmessages", "mode", "scaled_url", "geo_dist", "current_geo", "log_debug", "log_info", "log_warning", "log_error"]);
449
+ ul4.expose(Globals.prototype.log_debug, ["message", "*"]);
450
+ ul4.expose(Globals.prototype.log_info, ["message", "*"]);
451
+ ul4.expose(Globals.prototype.log_warning, ["message", "*"]);
452
+ ul4.expose(Globals.prototype.log_error, ["message", "*"]);
453
+ ul4.expose(Globals.prototype.geo_dist, ["geo1", "pk", "geo2", "pk"]);
454
+ ul4.expose(Globals.prototype.current_geo, []);
455
+ ul4.expose(Globals.prototype.scaled_url, [
456
+ "image", "p",
457
+ "width", "p",
458
+ "height", "p",
459
+ "type", "k=", "fill",
460
+ "enlarge", "k=", true,
461
+ "gravity", "k=", "sm",
462
+ "quality", "k=", null,
463
+ "rotate", "k=", null,
464
+ "blur", "k=", null,
465
+ "sharpen", "k=", null,
466
+ "format", "k=", null,
467
+ "cache", "k=", true
468
+ ]);
469
+
470
+
471
+ class FlashMessageType extends ul4.Type
472
+ {
473
+ instancecheck(obj)
474
+ {
475
+ return obj instanceof FlashMessage;
476
+ }
477
+ };
478
+
479
+ let flashmessagetype = new FlashMessageType("la", "FlashMessage", "A flash message in a web page");
241
480
 
242
481
 
243
482
  export class FlashMessage extends Base
244
483
  {
245
- static classdoc = "A flash message in a web page";
484
+ [ul4.symbols.type]()
485
+ {
486
+ return flashmessagetype;
487
+ }
246
488
 
247
489
  [ul4.symbols.repr]()
248
490
  {
@@ -254,9 +496,23 @@ FlashMessage.prototype._ul4onattrs = ["timestamp", "type", "title", "message"];
254
496
  FlashMessage.prototype._ul4attrs = new Set(["timestamp", "type", "title", "message"]);
255
497
 
256
498
 
499
+ class AppType extends ul4.Type
500
+ {
501
+ instancecheck(obj)
502
+ {
503
+ return obj instanceof App;
504
+ }
505
+ };
506
+
507
+ let apptype = new AppType("la", "App", "A LivingApps application");
508
+
509
+
257
510
  export class App extends Base
258
511
  {
259
- static classdoc = "A LivingApps application";
512
+ [ul4.symbols.type]()
513
+ {
514
+ return apptype;
515
+ }
260
516
 
261
517
  [ul4.symbols.repr]()
262
518
  {
@@ -311,6 +567,24 @@ export class App extends Base
311
567
  throw new ul4.AttributeError(this, name);
312
568
  return this.controls.get(name.substr(2));
313
569
  }
570
+ else if (name.startsWith("lc_"))
571
+ {
572
+ if (this.layout_controls === null || !this.layout_controls.has(name.substr(3)))
573
+ throw new ul4.AttributeError(this, name);
574
+ return this.layout_controls.get(name.substr(3));
575
+ }
576
+ else if (name.startsWith("p_") && this.params !== null)
577
+ {
578
+ if (!this.params.has(name.substr(2)))
579
+ throw new ul4.AttributeError(this, name);
580
+ return this.params.get(name.substr(2));
581
+ }
582
+ else if (name.startsWith("pv_") && this.params !== null)
583
+ {
584
+ if (!this.params.has(name.substr(3)))
585
+ throw new ul4.AttributeError(this, name);
586
+ return this.params.get(name.substr(3)).value;
587
+ }
314
588
  else
315
589
  return super[ul4.symbols.getattr](name);
316
590
  }
@@ -345,18 +619,39 @@ export class App extends Base
345
619
 
346
620
  this._active_view = view;
347
621
  }
622
+
623
+ get layout_controls()
624
+ {
625
+ if (this.active_views === null)
626
+ return new Map();
627
+ return this.active_view.layout_controls;
628
+ }
348
629
  };
349
630
 
350
631
 
351
632
  App.prototype._ul4onattrs = ["globals", "name", "description", "lang", "startlink", "iconlarge", "iconsmall", "createdby", "controls", "records", "recordcount", "installation", "categories", "params", "views", "datamanagement_identifier", "basetable", "primarykey", "insertprocedure", "updateprocedure", "deleteprocedure", "templates", "createdat", "updatedat", "updatedby", "superid", "favorite", "_active_view"];
352
- App.prototype._ul4attrs = new Set(["id", "globals", "name", "description", "lang", "startlink", "iconlarge", "iconsmall", "createdat", "createdby", "updatedat", "updatedby", "controls", "records", "recordcount", "installation", "categories", "params", "views", "datamanagement_identifier", "insert", "favorite", "_active_view"]);
353
- ul4.expose(App.prototype[ul4.symbols.call], ["**values"], {"needsobject": true});
354
- ul4.expose(App.prototype.insert, ["**values"], {"needsobject": true});
633
+ App.prototype._ul4attrs = new Set(["id", "globals", "name", "description", "lang", "startlink", "iconlarge", "iconsmall", "createdat", "createdby", "updatedat", "updatedby", "controls", "layout_controls", "records", "recordcount", "installation", "categories", "params", "views", "datamanagement_identifier", "insert", "favorite", "_active_view"]);
634
+ ul4.expose(App.prototype[ul4.symbols.call], ["values", "**"], {"needsobject": true});
635
+ ul4.expose(App.prototype.insert, ["values", "**"], {"needsobject": true});
636
+
637
+
638
+ class ViewType extends ul4.Type
639
+ {
640
+ instancecheck(obj)
641
+ {
642
+ return obj instanceof View;
643
+ }
644
+ };
645
+
646
+ let viewtype = new ViewType("la", "View", "An input form for a LivingViews application");
355
647
 
356
648
 
357
649
  export class View extends Base
358
650
  {
359
- static classdoc = "An input form for a LivingApps application";
651
+ [ul4.symbols.type]()
652
+ {
653
+ return viewtype;
654
+ }
360
655
 
361
656
  [ul4.symbols.repr]()
362
657
  {
@@ -364,28 +659,51 @@ export class View extends Base
364
659
  }
365
660
  };
366
661
 
367
- View.prototype._ul4onattrs = ["name", "combined_type", "app", "order", "width", "height", "start", "end", "controls", "layout_controls", "lang"];
368
- View.prototype._ul4attrs = new Set(["id", "name", "combined_type", "app", "order", "width", "height", "start", "end", "controls", "layout_controls", "lang"]);
662
+ View.prototype._ul4onattrs = ["name", "combined_type", "app", "order", "width", "height", "start", "end", "controls", "layout_controls", "lang", "login_required", "result_page", "use_geo"];
663
+ View.prototype._ul4attrs = new Set(["id", "name", "combined_type", "app", "order", "width", "height", "start", "end", "controls", "layout_controls", "lang", "login_required", "result_page", "use_geo"]);
369
664
 
370
665
 
371
- export class DataSourceData extends Base
666
+ class DataSourceType extends ul4.Type
372
667
  {
373
- static classdoc = "The data resulting from a data source configuration";
668
+ instancecheck(obj)
669
+ {
670
+ return obj instanceof DataSource;
671
+ }
672
+ };
673
+
674
+ let datasourcetype = new DataSourceType("la", "DataSource", "The data resulting from a data source configuration");
675
+
676
+
677
+ export class DataSource extends Base
678
+ {
679
+ [ul4.symbols.type]()
680
+ {
681
+ return datasourcetype;
682
+ }
374
683
 
375
684
  [ul4.symbols.repr]()
376
685
  {
377
- return "<DataSourceData id=" + ul4._repr(this.id) + " identifier=" + ul4._repr(this.identifier) + ">";
686
+ return "<DataSource id=" + ul4._repr(this.id) + " identifier=" + ul4._repr(this.identifier) + ">";
378
687
  }
379
688
  };
380
689
 
381
- DataSourceData.prototype._ul4onattrs = ["identifier", "app", "apps"];
382
- DataSourceData.prototype._ul4attrs = new Set(["id", "identifier", "app", "apps"]);
690
+ DataSource.prototype._ul4onattrs = ["identifier", "app", "apps"];
691
+ DataSource.prototype._ul4attrs = new Set(["id", "identifier", "app", "apps"]);
383
692
 
384
693
 
385
- export class Record extends Base
694
+ class RecordType extends ul4.Type
386
695
  {
387
- static classdoc = "A record of a LivingApp application";
696
+ instancecheck(obj)
697
+ {
698
+ return obj instanceof Record;
699
+ }
700
+ };
701
+
702
+ let recordtype = new RecordType("la", "Record", "A record of a LivingApp application");
388
703
 
704
+
705
+ export class Record extends Base
706
+ {
389
707
  constructor(id, app)
390
708
  {
391
709
  super(id);
@@ -407,6 +725,35 @@ export class Record extends Base
407
725
  this._is_new = true;
408
726
  }
409
727
 
728
+ [ul4.symbols.type]()
729
+ {
730
+ return recordtype;
731
+ }
732
+
733
+ as_text(maxlevel=3, controls=null)
734
+ {
735
+ if (maxlevel == 0)
736
+ return "...";
737
+ let fields = [];
738
+ for (let [identifier, control] of (controls || this.app.controls))
739
+ {
740
+ if (controls !== null || control.priority)
741
+ {
742
+ let fieldvalue = this.fields.get(identifier).value_as_text(maxlevel-1);
743
+ if (fieldvalue !== null)
744
+ fields.push([control.label, fieldvalue]);
745
+ }
746
+ }
747
+ if (fields.length === 0)
748
+ return this.globals.msg_no_fields();
749
+ else if (fields.length === 1)
750
+ return fields[0][1];
751
+ let result = [];
752
+ for (let [label, fieldvalue] of fields)
753
+ result.push(label + ": " + fieldvalue);
754
+ return result.join(", ");
755
+ }
756
+
410
757
  _make_fields(defaults, values, errors, lookupdata)
411
758
  {
412
759
  let fields = new Map();
@@ -436,6 +783,13 @@ export class Record extends Base
436
783
  this._sparselookupdata = null;
437
784
  }
438
785
 
786
+ _in_form()
787
+ {
788
+ let globals = this.app.globals;
789
+
790
+ return globals._in_form() && this === globals.record;
791
+ }
792
+
439
793
  [ul4.symbols.repr]()
440
794
  {
441
795
  let v = ["<Record id=", ul4._repr(this.id)];
@@ -596,9 +950,9 @@ export class Record extends Base
596
950
  else if (name.startsWith("f_"))
597
951
  return this.fields.get(name.substr(2))
598
952
  else if (name.startsWith("v_"))
599
- return this.values.get(name.substr(2))
953
+ return this.fields.get(name.substr(2)).value
600
954
  else
601
- return this[name];
955
+ return super[ul4.symbols.getattr](name);
602
956
  }
603
957
 
604
958
  [ul4.symbols.setattr](name, value)
@@ -608,38 +962,58 @@ export class Record extends Base
608
962
  else if (name.startsWith("v_"))
609
963
  this.fields.get(name.substr(2)).value = value;
610
964
  else
611
- throw new ul4.AttributeError(this, name);
965
+ return super[ul4.symbols.setattr](name, value);
612
966
  }
613
967
  };
614
968
 
615
969
  Record.prototype._ul4onattrs = ["app", "createdat", "createdby", "updatedat", "updatedby", "updatecount", "_sparsevalues", "attachments", "children", "errors", "_sparsefielderrors", "_sparsefieldlookupdata"];
616
- Record.prototype._ul4attrs = new Set(["id", "app", "createdat", "createdby", "updatedat", "updatedby", "updatecount", "values", "attachments", "children", "errors"]);
970
+ Record.prototype._ul4attrs = new Set(["id", "app", "createdat", "createdby", "updatedat", "updatedby", "updatecount", "values", "fields", "attachments", "children", "errors"]);
617
971
  ul4.expose(Record.prototype.is_dirty, []);
618
972
  ul4.expose(Record.prototype.has_errors, []);
619
973
  ul4.expose(Record.prototype.delete, []);
620
974
  ul4.expose(Record.prototype.save, []);
621
- ul4.expose(Record.prototype.update, ["**values"], {"needsobject": true});
975
+ ul4.expose(Record.prototype.update, ["values", "**"], {"needsobject": true});
622
976
 
623
977
 
624
- export class Field extends Base
978
+ class FieldType extends ul4.Type
625
979
  {
626
- static classdoc = "Holds the value of a field of a record (and related information)";
980
+ instancecheck(obj)
981
+ {
982
+ return obj instanceof Field;
983
+ }
984
+ };
985
+
986
+ let fieldtype = new FieldType("la", "Field", "Holds the value of a field of a record (and related information)");
987
+
627
988
 
989
+ export class Field extends Base
990
+ {
628
991
  constructor(control, record, value)
629
992
  {
630
993
  super(null);
631
994
  this.control = control;
632
995
  this.record = record;
633
996
  this._label = null;
634
- this._lookupdate = null;
997
+ this._lookupdata = null;
635
998
  this.errors = [];
636
999
  this._value = null;
637
- this.value = value;
1000
+ if (!this._in_form())
1001
+ this.value = value;
638
1002
  this._dirty = false;
1003
+ this._enabled = true;
1004
+ this._writable = true;
1005
+ this._visible = true;
1006
+ }
1007
+
1008
+ [ul4.symbols.type]()
1009
+ {
1010
+ return fieldtype;
639
1011
  }
640
1012
 
641
1013
  get value()
642
1014
  {
1015
+ if (this._in_form())
1016
+ return this._get_dom_value();
643
1017
  return this._value;
644
1018
  }
645
1019
 
@@ -652,11 +1026,19 @@ export class Field extends Base
652
1026
 
653
1027
  if (ul4._ne(oldvalue, change.value))
654
1028
  {
655
- this.record.values.set(this.control.identifier, change.value);
1029
+ if (this.record._values !== null)
1030
+ this.record._values.set(this.control.identifier, change.value);
656
1031
  this._value = change.value;
657
1032
  this._dirty = true;
658
1033
  }
659
1034
  this.errors = change.errors;
1035
+ if (this._in_form())
1036
+ this._set_dom_value(this._value);
1037
+ }
1038
+
1039
+ value_as_text(maxlevel=3)
1040
+ {
1041
+ return null;
660
1042
  }
661
1043
 
662
1044
  _validate(change)
@@ -664,16 +1046,21 @@ export class Field extends Base
664
1046
  // Do nothing, i.e. accept the value unchanged and without errors
665
1047
  }
666
1048
 
1049
+ _set_dom_label()
1050
+ {
1051
+ if (this._in_form())
1052
+ this._dom_label.textContent = this.label;
1053
+ }
1054
+
667
1055
  get label()
668
1056
  {
669
- if (this._label !== null)
670
- return this._label;
671
- return this.control.label;
1057
+ return this._label ?? this.control.label;
672
1058
  }
673
1059
 
674
1060
  set label(value)
675
1061
  {
676
1062
  this._label = value;
1063
+ this._set_dom_label();
677
1064
  }
678
1065
 
679
1066
  get globals()
@@ -683,7 +1070,7 @@ export class Field extends Base
683
1070
 
684
1071
  is_empty()
685
1072
  {
686
- return this._value === null || (ul4._islist(this._value) && this._value.length === 0);
1073
+ return this._value === null;
687
1074
  }
688
1075
 
689
1076
  is_dirty()
@@ -724,7 +1111,7 @@ export class Field extends Base
724
1111
 
725
1112
  msg_string_tooshort(value)
726
1113
  {
727
- return `"${this.label}" is too short. Tou must use at least ${this.control.minlength} characters!`;
1114
+ return `"${this.label}" is too short. You must use at least ${this.control.minlength} characters!`;
728
1115
  }
729
1116
 
730
1117
  msg_string_toolong(value)
@@ -752,6 +1139,11 @@ export class Field extends Base
752
1139
  return `"${this.label}" doesn't support this date format!`;
753
1140
  }
754
1141
 
1142
+ msg_number_format(value)
1143
+ {
1144
+ return `"${this.label}" doesn't support this number format!`;
1145
+ }
1146
+
755
1147
  msg_lookup_wrongitem(value)
756
1148
  {
757
1149
  return `The option ${ul4._repr(value)} for "${this.label}" doesn't belong to this lookup!`;
@@ -772,70 +1164,360 @@ export class Field extends Base
772
1164
  return `The record ${ul4._repr(value)} for "${this.label}" can't be found!`;
773
1165
  }
774
1166
 
775
- [ul4.symbols.repr]()
1167
+ /*
1168
+ The following methods are used in the input form.
1169
+
1170
+ I.e. they are expected to be executed inside a browser.
1171
+ */
1172
+ _in_form()
776
1173
  {
777
- let s = "<Field identifier=";
778
- s += ul4._repr(this.control.identifier)
779
- if (this._dirty)
780
- s += " is_dirty()=True";
781
- if (this.errors.length > 0)
782
- s += " has_errors()=True";
783
- s += ">"
784
- return s;
1174
+ return this.record._in_form();
785
1175
  }
786
- };
787
1176
 
788
- Field.prototype._ul4onattrs = ["control", "record", "label", "value", "errors", "enabled", "writable", "visible"];
789
- Field.prototype._ul4attrs = new Set(["control", "record", "label", "value", "errors", "enabled", "writable", "visible"]);
1177
+ get _sel_root()
1178
+ {
1179
+ return "#livingapps-form ." + this.control._cssclass_root + ".llft-id-" + this.control.identifier;
1180
+ }
790
1181
 
1182
+ get _sel_label()
1183
+ {
1184
+ return this._sel_root + " label span";
1185
+ }
791
1186
 
792
- export class BoolField extends Field
793
- {
794
- static classdoc = "Holds the value of a bool field of a record (and related information)";
1187
+ get _sel_control()
1188
+ {
1189
+ return this._sel_root + " " + this.control._cssclass_control;
1190
+ }
795
1191
 
796
- _validate(change)
1192
+ get _dom_root()
797
1193
  {
798
- if (change.value === null)
799
- {
800
- if (this.control.required)
801
- change.errors.push(this.msg_field_required(change.value));
802
- }
803
- else if (typeof(change.value) === "boolean")
804
- {
805
- if (this.control.required && !change.value)
806
- change.errors.push(this.msg_bool_truerequired(change.value));
807
- }
808
- else
809
- {
810
- change.errors.push(this.msg_field_wrong_type(change.value));
811
- change.value = null;
812
- }
1194
+ return document.querySelector(this._sel_root);
813
1195
  }
814
- };
815
1196
 
1197
+ get _dom_label()
1198
+ {
1199
+ return document.querySelector(this._sel_label);
1200
+ }
816
1201
 
817
- export class IntField extends Field
818
- {
819
- static classdoc = "Holds the value of an int field of a record (and related information)";
1202
+ get _dom_control()
1203
+ {
1204
+ return document.querySelector(this._sel_control);
1205
+ }
820
1206
 
821
- _validate(change)
1207
+ get _dom_controls()
822
1208
  {
823
- if (change.value === null)
824
- {
825
- if (this.control.required)
826
- change.errors.push(this.msg_field_required(change.value));
827
- }
828
- else if (typeof(change.value) !== "number" || Math.round(change.value) !== change.value)
829
- {
1209
+ return document.querySelectorAll(this._sel_control);
1210
+ }
1211
+
1212
+ _get_dom_value()
1213
+ {
1214
+ return this._dom_control.value;
1215
+ }
1216
+
1217
+ _set_dom_value(value)
1218
+ {
1219
+ this._dom_control.value = value !== null ? value : "";
1220
+ }
1221
+
1222
+ get visible()
1223
+ {
1224
+ return this._visible;
1225
+ }
1226
+
1227
+ set visible(value)
1228
+ {
1229
+ if (this._in_form())
1230
+ this._dom_root.hidden = !value;
1231
+ this._visible = value;
1232
+ }
1233
+
1234
+ get enabled()
1235
+ {
1236
+ if (this._in_form())
1237
+ return !this._dom_root.classList.contains("llft-control-readonly");
1238
+ else
1239
+ return this._enabled;
1240
+ }
1241
+
1242
+ set enabled(value)
1243
+ {
1244
+ if (this._in_form())
1245
+ {
1246
+ let disabled = !value;
1247
+ for (let node of this._dom_controls)
1248
+ node.disabled = disabled;
1249
+ this._dom_root.classList.toggle("llft-control-readonly", disabled);
1250
+ }
1251
+ this._enabled = value;
1252
+ }
1253
+
1254
+ get writable()
1255
+ {
1256
+ return this._writable;
1257
+ }
1258
+
1259
+ set writable(value)
1260
+ {
1261
+ this._writable = value;
1262
+ }
1263
+
1264
+ [ul4.symbols.repr]()
1265
+ {
1266
+ let s = "<" + this.constructor.name + " identifier=";
1267
+ s += ul4._repr(this.control.identifier)
1268
+ if (this._dirty)
1269
+ s += " is_dirty()=True";
1270
+ if (this.errors.length > 0)
1271
+ s += " has_errors()=True";
1272
+ s += ">"
1273
+ return s;
1274
+ }
1275
+
1276
+ [ul4.symbols.setattr](name, value)
1277
+ {
1278
+ if (name === "value")
1279
+ this.value = value;
1280
+ else if (name === "visible")
1281
+ this.visible = ul4._bool(value);
1282
+ else if (name === "enabled")
1283
+ this.enabled = ul4._bool(value);
1284
+ else if (name === "writable")
1285
+ this.writable = ul4._bool(value);
1286
+ else
1287
+ return super[ul4.symbols.getattr](name);
1288
+ }
1289
+ };
1290
+
1291
+ Field.prototype._ul4onattrs = ["control", "record", "label", "value", "errors", "_visible", "_enabled", "_writable"];
1292
+ Field.prototype._ul4attrs = new Set(["control", "record", "label", "value", "errors", "visible", "enabled", "writable"]);
1293
+ Field.prototype._inputevent = "input";
1294
+
1295
+
1296
+ class BoolFieldType extends FieldType
1297
+ {
1298
+ instancecheck(obj)
1299
+ {
1300
+ return obj instanceof BoolField;
1301
+ }
1302
+ };
1303
+
1304
+ let boolfieldtype = new BoolFieldType("la", "BoolField", "Holds the value of a bool field of a record (and related information)");
1305
+
1306
+
1307
+ export class BoolField extends Field
1308
+ {
1309
+ [ul4.symbols.type]()
1310
+ {
1311
+ return boolfieldtype;
1312
+ }
1313
+
1314
+ _validate(change)
1315
+ {
1316
+ if (change.value === null)
1317
+ {
1318
+ if (this.control.required)
1319
+ change.errors.push(this.msg_field_required(change.value));
1320
+ }
1321
+ else if (typeof(change.value) === "boolean")
1322
+ {
1323
+ if (this.control.required && !change.value)
1324
+ change.errors.push(this.msg_bool_truerequired(change.value));
1325
+ }
1326
+ else
1327
+ {
830
1328
  change.errors.push(this.msg_field_wrong_type(change.value));
1329
+ change.value = null;
831
1330
  }
832
1331
  }
1332
+
1333
+ _get_dom_value()
1334
+ {
1335
+ return this._dom_control.checked;
1336
+ }
1337
+
1338
+ _set_dom_value(value)
1339
+ {
1340
+ this._dom_control.checked = value;
1341
+ }
1342
+
1343
+ value_as_text(maxlevel=3)
1344
+ {
1345
+ return this.globals.msg_bool(this.value);
1346
+ }
833
1347
  };
834
1348
 
835
1349
 
1350
+ class IntFieldType extends FieldType
1351
+ {
1352
+ instancecheck(obj)
1353
+ {
1354
+ return obj instanceof IntField;
1355
+ }
1356
+ };
1357
+
1358
+ let intfieldtype = new IntFieldType("la", "IntField", "Holds the value of an int field of a record (and related information)");
1359
+
1360
+
1361
+ export class IntField extends Field
1362
+ {
1363
+ [ul4.symbols.type]()
1364
+ {
1365
+ return intfieldtype;
1366
+ }
1367
+
1368
+ _parse(value)
1369
+ {
1370
+ if (/^\s*[-+]?\d+\s*$/.test(value))
1371
+ return parseInt(value);
1372
+ else
1373
+ return null;
1374
+ }
1375
+
1376
+ _validate(change)
1377
+ {
1378
+ if (change.value === null)
1379
+ {
1380
+ if (this.control.required)
1381
+ change.errors.push(this.msg_field_required(change.value));
1382
+ }
1383
+ else if (typeof(change.value) === "string")
1384
+ {
1385
+ let value = this._parse(change.value);
1386
+ if (value !== null)
1387
+ change.value = value;
1388
+ else
1389
+ change.errors.push(this.msg_number_format(change.value));
1390
+ // Keep original invalid string
1391
+ }
1392
+ else if (typeof(change.value) === "number")
1393
+ {
1394
+ if (Math.round(change.value) !== change.value)
1395
+ change.errors.push(this.msg_field_wrong_type(change.value));
1396
+ // Keep original floating point number
1397
+ }
1398
+ else
1399
+ {
1400
+ change.errors.push(this.msg_field_wrong_type(change.value));
1401
+ change.value = null;
1402
+ }
1403
+ }
1404
+
1405
+ _get_dom_value()
1406
+ {
1407
+ let value = super._get_dom_value();
1408
+ if (value)
1409
+ {
1410
+ let testvalue = this._parse(value);
1411
+ if (testvalue !== null)
1412
+ value = testvalue;
1413
+ }
1414
+ return value;
1415
+ }
1416
+
1417
+ _set_dom_value(value)
1418
+ {
1419
+ super._set_dom_value(value !== null ? value + "" : "");
1420
+ }
1421
+
1422
+ value_as_text(maxlevel=3)
1423
+ {
1424
+ let value = this.value;
1425
+ return value != null ? value + "" : null;
1426
+ }
1427
+
1428
+ get writable()
1429
+ {
1430
+ return this._writable;
1431
+ }
1432
+
1433
+ set writable(value)
1434
+ {
1435
+ if (this._in_form())
1436
+ {
1437
+ let readonly = !value;
1438
+ for (let node of this._dom_controls)
1439
+ node.readOnly = readonly;
1440
+ }
1441
+ super.writable = value;
1442
+ }
1443
+ };
1444
+
1445
+
1446
+ class NumberFieldType extends FieldType
1447
+ {
1448
+ instancecheck(obj)
1449
+ {
1450
+ return obj instanceof NumberField;
1451
+ }
1452
+ };
1453
+
1454
+ let numberfieldtype = new NumberFieldType("la", "NumberField", "Holds the value of a number field of a record (and related information)");
1455
+
1456
+
836
1457
  export class NumberField extends Field
837
1458
  {
838
- static classdoc = "Holds the value of a number field of a record (and related information)";
1459
+ [ul4.symbols.type]()
1460
+ {
1461
+ return numberfieldtype;
1462
+ }
1463
+
1464
+ _parse(value)
1465
+ {
1466
+ if (value === null)
1467
+ return null;
1468
+
1469
+ // Try to ignore thousands separators and return the value as a number
1470
+ let testvalue = value;
1471
+ // Count decimal delimiters
1472
+ let seps = "";
1473
+ let commas = 0;
1474
+ let dots = 0
1475
+ for (let i = 0; i < value.length; ++i)
1476
+ {
1477
+ let c = value[i];
1478
+ if (c == ",")
1479
+ {
1480
+ commas++;
1481
+ seps += c;
1482
+ }
1483
+ else if (c == ".")
1484
+ {
1485
+ dots++;
1486
+ seps += c;
1487
+ }
1488
+ }
1489
+ let convert = null;
1490
+ if (commas == 0)
1491
+ {
1492
+ if (dots <= 1)
1493
+ ; // nothing to do
1494
+ else
1495
+ convert = "de";
1496
+ }
1497
+ else if (commas == 1)
1498
+ {
1499
+ if (dots == 1)
1500
+ convert = (seps == ".,") ? "de" : "en";
1501
+ else
1502
+ convert = "de";
1503
+ }
1504
+ else // commas > 1
1505
+ {
1506
+ if (dots <= 1)
1507
+ convert = "en";
1508
+ else
1509
+ return null; // We can't guess what the user meant
1510
+ }
1511
+
1512
+ if (convert === "de")
1513
+ testvalue = testvalue.replace(/\./g, "").replace(/,/g, ".");
1514
+ else if (convert === "en")
1515
+ testvalue = testvalue.replace(/,/g, "");
1516
+ let floatvalue = parseFloat(testvalue);
1517
+ if (isNaN(floatvalue))
1518
+ return value;
1519
+ return floatvalue;
1520
+ }
839
1521
 
840
1522
  _validate(change)
841
1523
  {
@@ -845,17 +1527,133 @@ export class NumberField extends Field
845
1527
  change.errors.push(this.msg_field_required(change.value));
846
1528
  change.value = null;
847
1529
  }
848
- else if (typeof(change.value) !== "number")
1530
+ else if (typeof(change.value) === "string")
1531
+ {
1532
+ let value = this._parse(change.value);
1533
+ if (value !== null)
1534
+ {
1535
+ value = this._bound_value(value);
1536
+ if (this.control.precision !== null)
1537
+ value = ul4._round(value, this.control.precision);
1538
+ change.value = value;
1539
+ }
1540
+ else
1541
+ change.errors.push(this.msg_number_format(change.value));
1542
+ // Keep original invalid string
1543
+ }
1544
+ else if (typeof(change.value) === "number")
1545
+ {
1546
+ let value = this._bound_value(change.value);
1547
+ if (this.control.precision !== null)
1548
+ value = ul4._round(value, this.control.precision);
1549
+ change.value = value;
1550
+ }
1551
+ else
849
1552
  {
850
1553
  change.errors.push(this.msg_field_wrong_type(change.value));
1554
+ change.value = null;
851
1555
  }
852
1556
  }
1557
+
1558
+ _bound_value(value)
1559
+ {
1560
+ if (this.control.minimum !== null)
1561
+ {
1562
+ if (value < this.control.minimum)
1563
+ value = this.control.minimum;
1564
+ }
1565
+ if (this.control.maximum !== null)
1566
+ {
1567
+ if (value > this.control.maximum)
1568
+ value = this.control.maximum;
1569
+ }
1570
+ return value;
1571
+ }
1572
+
1573
+ _get_dom_value()
1574
+ {
1575
+ let value = super._get_dom_value();
1576
+ if (value)
1577
+ {
1578
+ if (typeof(value) == "string")
1579
+ {
1580
+ let testvalue = this._parse(value);
1581
+ if (testvalue !== null)
1582
+ value = testvalue;
1583
+ }
1584
+ if (typeof(value) === "number")
1585
+ {
1586
+ if (this.control.precision !== null)
1587
+ value = ul4._round(value, this.control.precision);
1588
+ value = this._bound_value(value);
1589
+ }
1590
+ }
1591
+ else
1592
+ value = null;
1593
+ return value;
1594
+ }
1595
+
1596
+ _set_dom_value(value)
1597
+ {
1598
+ if (typeof(value) === "number")
1599
+ {
1600
+ value = this._bound_value(value);
1601
+ if (this.control.precision !== null)
1602
+ value = value.toFixed(this.control.precision);
1603
+ }
1604
+ else if (value === null)
1605
+ value = "";
1606
+ value += "";
1607
+ if (this.globals.lang == "de" && this.control.precision === null)
1608
+ value = value.replace(".", ",");
1609
+ super._set_dom_value(value);
1610
+ }
1611
+
1612
+ value_as_text(maxlevel=3)
1613
+ {
1614
+ let value = this.value;
1615
+ if (value === null)
1616
+ return null;
1617
+ if (this.control.precision !== null)
1618
+ return value.toFixed(this.control.precision);
1619
+ return value.toString();
1620
+ }
1621
+
1622
+ get writable()
1623
+ {
1624
+ return this._writable;
1625
+ }
1626
+
1627
+ set writable(value)
1628
+ {
1629
+ if (this._in_form())
1630
+ {
1631
+ let readonly = !value;
1632
+ for (let node of this._dom_controls)
1633
+ node.readOnly = readonly;
1634
+ }
1635
+ super.writable = value;
1636
+ }
853
1637
  };
854
1638
 
855
1639
 
1640
+ class StringFieldType extends FieldType
1641
+ {
1642
+ instancecheck(obj)
1643
+ {
1644
+ return obj instanceof StringField;
1645
+ }
1646
+ };
1647
+
1648
+ let stringfieldtype = new StringFieldType("la", "StringField", "Holds the value of a string field of a record (and related information)");
1649
+
1650
+
856
1651
  export class StringField extends Field
857
1652
  {
858
- static classdoc = "Holds the value of a string field of a record (and related information)";
1653
+ [ul4.symbols.type]()
1654
+ {
1655
+ return stringfieldtype;
1656
+ }
859
1657
 
860
1658
  _validate(change)
861
1659
  {
@@ -880,12 +1678,67 @@ export class StringField extends Field
880
1678
  change.value = null;
881
1679
  }
882
1680
  }
1681
+
1682
+ get writable()
1683
+ {
1684
+ return this._writable;
1685
+ }
1686
+
1687
+ set writable(value)
1688
+ {
1689
+ if (this._in_form())
1690
+ {
1691
+ let readonly = !value;
1692
+ for (let node of this._dom_controls)
1693
+ node.readOnly = readonly;
1694
+ }
1695
+ super.writable = value;
1696
+ }
1697
+
1698
+ value_as_text(maxlevel=3)
1699
+ {
1700
+ return this.value;
1701
+ }
1702
+ };
1703
+
1704
+
1705
+ class PasswordFieldType extends StringFieldType
1706
+ {
1707
+ instancecheck(obj)
1708
+ {
1709
+ return obj instanceof PasswordField;
1710
+ }
1711
+ };
1712
+
1713
+ let passwordfieldtype = new PasswordFieldType("la", "PasswordField", "Holds the value of a string/password field of a record (and related information)");
1714
+
1715
+
1716
+ export class PasswordField extends StringField
1717
+ {
1718
+ [ul4.symbols.type]()
1719
+ {
1720
+ return passwordfieldtype;
1721
+ }
1722
+ };
1723
+
1724
+
1725
+ class EmailFieldType extends StringFieldType
1726
+ {
1727
+ instancecheck(obj)
1728
+ {
1729
+ return obj instanceof EmailField;
1730
+ }
883
1731
  };
884
1732
 
1733
+ let emailfieldtype = new EmailFieldType("la", "EmailField", "Holds the value of a string/email field of a record (and related information)");
1734
+
885
1735
 
886
1736
  export class EmailField extends StringField
887
1737
  {
888
- static classdoc = "Holds the value of a string/email field of a record (and related information)";
1738
+ [ul4.symbols.type]()
1739
+ {
1740
+ return emailfieldtype;
1741
+ }
889
1742
 
890
1743
  _validate(change)
891
1744
  {
@@ -900,9 +1753,23 @@ export class EmailField extends StringField
900
1753
  };
901
1754
 
902
1755
 
1756
+ class URLFieldType extends StringFieldType
1757
+ {
1758
+ instancecheck(obj)
1759
+ {
1760
+ return obj instanceof URLField;
1761
+ }
1762
+ };
1763
+
1764
+ let urlfieldtype = new URLFieldType("la", "URLField", "Holds the value of a string/url field of a record (and related information)");
1765
+
1766
+
903
1767
  export class URLField extends StringField
904
1768
  {
905
- static classdoc = "Holds the value of a string/url field of a record (and related information)";
1769
+ [ul4.symbols.type]()
1770
+ {
1771
+ return urlfieldtype;
1772
+ }
906
1773
 
907
1774
  _validate(change)
908
1775
  {
@@ -927,9 +1794,23 @@ export class URLField extends StringField
927
1794
  };
928
1795
 
929
1796
 
1797
+ class TelFieldType extends StringFieldType
1798
+ {
1799
+ instancecheck(obj)
1800
+ {
1801
+ return obj instanceof TelField;
1802
+ }
1803
+ };
1804
+
1805
+ let telfieldtype = new TelFieldType("la", "TelField", "Holds the value of a string/tel field of a record (and related information)");
1806
+
1807
+
930
1808
  export class TelField extends StringField
931
1809
  {
932
- static classdoc = "Holds the value of a string/tel field of a record (and related information)";
1810
+ [ul4.symbols.type]()
1811
+ {
1812
+ return telfieldtype;
1813
+ }
933
1814
 
934
1815
  _validate(change)
935
1816
  {
@@ -944,21 +1825,131 @@ export class TelField extends StringField
944
1825
  };
945
1826
 
946
1827
 
1828
+ class TextAreaFieldType extends StringFieldType
1829
+ {
1830
+ instancecheck(obj)
1831
+ {
1832
+ return obj instanceof TextAreaField;
1833
+ }
1834
+ };
1835
+
1836
+ let textareafieldtype = new TextAreaFieldType("la", "TextAreaField", "Holds the value of a string/textarea field of a record (and related information)");
1837
+
1838
+
947
1839
  export class TextAreaField extends StringField
948
1840
  {
949
- static classdoc = "Holds the value of a string/textarea field of a record (and related information)";
1841
+ [ul4.symbols.type]()
1842
+ {
1843
+ return textareafieldtype;
1844
+ }
950
1845
  };
951
1846
 
952
1847
 
1848
+ class HTMLFieldType extends StringFieldType
1849
+ {
1850
+ instancecheck(obj)
1851
+ {
1852
+ return obj instanceof HTMLField;
1853
+ }
1854
+ };
1855
+
1856
+ let htmlfieldtype = new HTMLFieldType("la", "HTMLField", "Holds the value of a string/html field of a record (and related information)");
1857
+
1858
+
953
1859
  export class HTMLField extends StringField
954
1860
  {
955
- static classdoc = "Holds the value of a string/html field of a record (and related information)";
1861
+ [ul4.symbols.type]()
1862
+ {
1863
+ return htmlfieldtype;
1864
+ }
1865
+ };
1866
+
1867
+
1868
+ class GeoFieldType extends FieldType
1869
+ {
1870
+ instancecheck(obj)
1871
+ {
1872
+ return obj instanceof GeoField;
1873
+ }
956
1874
  };
957
1875
 
1876
+ let geofieldtype = new GeoFieldType("la", "GeoField", "Holds the value of a geo field of a record (and related information)");
1877
+
958
1878
 
959
1879
  export class GeoField extends Field
960
1880
  {
961
- static classdoc = "Holds the value of a geo field of a record (and related information)";
1881
+ [ul4.symbols.type]()
1882
+ {
1883
+ return geofieldtype;
1884
+ }
1885
+
1886
+ _get_dom_value()
1887
+ {
1888
+ for (let dom_node of this._dom_controls)
1889
+ {
1890
+ if (dom_node.id.endsWith("_geoinfo"))
1891
+ {
1892
+ let value = dom_node.value;
1893
+ if (value)
1894
+ {
1895
+ value = JSON.parse(value);
1896
+ return new Geo(
1897
+ value.geometry.coordinates[0],
1898
+ value.geometry.coordinates[1],
1899
+ value.properties.formatted_address
1900
+ );
1901
+ }
1902
+ }
1903
+ }
1904
+ return null;
1905
+ }
1906
+
1907
+ _set_dom_value(value)
1908
+ {
1909
+ if (value === null)
1910
+ {
1911
+ for (let dom_node of this._dom_controls)
1912
+ {
1913
+ dom_node.value = null;
1914
+ }
1915
+ }
1916
+ else
1917
+ {
1918
+ for (let dom_node of this._dom_controls)
1919
+ {
1920
+ if (dom_node.id.endsWith("_geoinfo"))
1921
+ {
1922
+ let dom_value = {
1923
+ "type": "Feature",
1924
+ "geometry": {
1925
+ "coordinates": [
1926
+ value.lat,
1927
+ value.long
1928
+ ]
1929
+ },
1930
+ "properties": {
1931
+ "formatted_address": value.info
1932
+ }
1933
+ };
1934
+ dom_node.value = ul4._asjson(dom_value);
1935
+ }
1936
+ else
1937
+ dom_node.value = value.info;
1938
+ }
1939
+ }
1940
+ }
1941
+
1942
+ value_as_text(maxlevel=3)
1943
+ {
1944
+ let value = this.value;
1945
+ if (this.value === null)
1946
+ return null;
1947
+ // FIXME: Show N/S and W/E? Show arc minutes/seconds?
1948
+ let result = value.lat.toFixed(5) + ", " + value.long.toFixed(5);
1949
+ if (value.info !== null)
1950
+ result += " (" + value.info + ")";
1951
+ return result;
1952
+ }
962
1953
 
963
1954
  _validate(change)
964
1955
  {
@@ -975,11 +1966,26 @@ export class GeoField extends Field
975
1966
  }
976
1967
  }
977
1968
  };
1969
+ GeoField.prototype._inputevent = "llgeo";
1970
+
1971
+
1972
+ class FileFieldType extends FieldType
1973
+ {
1974
+ instancecheck(obj)
1975
+ {
1976
+ return obj instanceof FileField;
1977
+ }
1978
+ };
1979
+
1980
+ let filefieldtype = new FileFieldType("la", "FileField", "Holds the value of a file field of a record (and related information)");
978
1981
 
979
1982
 
980
1983
  export class FileField extends Field
981
1984
  {
982
- static classdoc = "Holds the value of a file field of a record (and related information)";
1985
+ [ul4.symbols.type]()
1986
+ {
1987
+ return filefieldtype;
1988
+ }
983
1989
 
984
1990
  _validate(change)
985
1991
  {
@@ -995,12 +2001,37 @@ export class FileField extends Field
995
2001
  change.value = null;
996
2002
  }
997
2003
  }
2004
+
2005
+ _get_dom_value()
2006
+ {
2007
+ // Always return `null``
2008
+ return null;
2009
+ }
2010
+
2011
+ _set_dom_value()
2012
+ {
2013
+ // Do nothing
2014
+ }
2015
+ };
2016
+
2017
+
2018
+ class FileSignatureFieldType extends FileFieldType
2019
+ {
2020
+ instancecheck(obj)
2021
+ {
2022
+ return obj instanceof FileSignatureField;
2023
+ }
998
2024
  };
999
2025
 
2026
+ let filesignaturefieldtype = new FileSignatureFieldType("la", "FileSignatureField", "Holds the value of a file/signature field of a record (and related information)");
2027
+
1000
2028
 
1001
2029
  export class FileSignatureField extends FileField
1002
2030
  {
1003
- static classdoc = "Holds the value of a file/signature field of a record (and related information)";
2031
+ [ul4.symbols.type]()
2032
+ {
2033
+ return filesignaturefieldtype;
2034
+ }
1004
2035
 
1005
2036
  _validate(change)
1006
2037
  {
@@ -1010,9 +2041,196 @@ export class FileSignatureField extends FileField
1010
2041
  };
1011
2042
 
1012
2043
 
2044
+ class DateFieldBaseType extends FieldType
2045
+ {
2046
+ instancecheck(obj)
2047
+ {
2048
+ return obj instanceof DateFieldBase;
2049
+ }
2050
+ };
2051
+
2052
+ let datefieldbasetype = new DateFieldBaseType("la", "DateFieldBase", "Holds the value of a date field of a record (and related information)");
2053
+
2054
+
1013
2055
  export class DateFieldBase extends Field
1014
2056
  {
1015
- static classdoc = "Holds the value of a date field of a record (and related information)";
2057
+ [ul4.symbols.type]()
2058
+ {
2059
+ return datefieldbasetype;
2060
+ }
2061
+
2062
+ value_as_text(maxlevel=3)
2063
+ {
2064
+ let value = this.value;
2065
+ if (value === null)
2066
+ return null;
2067
+ if (typeof(value) === "string")
2068
+ return value;
2069
+ return ul4._format(value, this.control.formatstring())
2070
+ }
2071
+
2072
+ _parse(value, format)
2073
+ {
2074
+ let year = null, month = null, day = null, hour = 0, minute = 0, second = 0, ispm = null;
2075
+
2076
+ function _int(v, len, min, max)
2077
+ {
2078
+ v = v.substring(0, len);
2079
+ if (v.length != len)
2080
+ return null;
2081
+ v = parseInt(v, 10);
2082
+ if (isNaN(v) || v < min || v > max)
2083
+ return null;
2084
+ return v;
2085
+ }
2086
+
2087
+ while (value)
2088
+ {
2089
+ // Are both `value` and `format` not `null`,
2090
+ // i.e. neither `value` nor `format` is exhaused?
2091
+ if (!format)
2092
+ return null;
2093
+ if (format.startsWith("%Y"))
2094
+ {
2095
+ year = _int(value, 4);
2096
+ if (year === null)
2097
+ return null;
2098
+ value = value.substring(4);
2099
+ format = format.substring(2);
2100
+ }
2101
+ else if (format.startsWith("%y"))
2102
+ {
2103
+ year = _int(value, 2);
2104
+ if (year === null)
2105
+ return null;
2106
+ value = value.substring(2);
2107
+ format = format.substring(2);
2108
+ }
2109
+ else if (format.startsWith("%m"))
2110
+ {
2111
+ month = _int(value, 2);
2112
+ if (month === null)
2113
+ return null;
2114
+ value = value.substring(2);
2115
+ format = format.substring(2);
2116
+ }
2117
+ else if (format.startsWith("%d"))
2118
+ {
2119
+ day = _int(value, 2);
2120
+ if (day === null)
2121
+ return null;
2122
+ value = value.substring(2);
2123
+ format = format.substring(2);
2124
+ }
2125
+ else if (format.startsWith("%H"))
2126
+ {
2127
+ hour = _int(value, 2);
2128
+ if (hour === null)
2129
+ return null;
2130
+ value = value.substring(2);
2131
+ format = format.substring(2);
2132
+ }
2133
+ else if (format.startsWith("%I"))
2134
+ {
2135
+ hour = _int(value, 2);
2136
+ if (hour === null)
2137
+ return null;
2138
+ value = value.substring(2);
2139
+ format = format.substring(2);
2140
+ }
2141
+ else if (format.startsWith("%M"))
2142
+ {
2143
+ minute = _int(value, 2);
2144
+ if (minute === null)
2145
+ return null;
2146
+ value = value.substring(2);
2147
+ format = format.substring(2);
2148
+ }
2149
+ else if (format.startsWith("%S"))
2150
+ {
2151
+ second = _int(value, 2);
2152
+ if (second === null)
2153
+ return null;
2154
+ value = value.substring(2);
2155
+ format = format.substring(2);
2156
+ }
2157
+ else if (format.startsWith("%p"))
2158
+ {
2159
+ if (value.toLowerCase().startsWith("pm"))
2160
+ ispm = true;
2161
+ else if (value.toLowerCase().startsWith("am"))
2162
+ ispm = false;
2163
+ else
2164
+ return null;
2165
+ value = value.substring(2);
2166
+ format = format.substring(2);
2167
+ }
2168
+ else if (format.startsWith("%%"))
2169
+ {
2170
+ if (!value.startsWith("%"))
2171
+ return null;
2172
+ value = value.substring(1);
2173
+ format = format.substring(2);
2174
+ }
2175
+ else if (format.startsWith("%z"))
2176
+ {
2177
+ if (!value.startsWith("-") && !value.startsWith("+"))
2178
+ return null;
2179
+ value = value.substring(1);
2180
+ let _tzhour = _int(value, 2);
2181
+ if (_tzhour === null)
2182
+ return null;
2183
+ value = value.substring(2);
2184
+ if (!value.startsWith(":"))
2185
+ return null;
2186
+ value = value.substring(1);
2187
+ let _tzminute = _int(value, 2);
2188
+ if (_tzminute === null)
2189
+ return null;
2190
+ value = value.substring(2);
2191
+ format = format.substring(2);
2192
+ }
2193
+ else
2194
+ {
2195
+ if (!value.startsWith(format.substring(0, 1)))
2196
+ return null;
2197
+ value = value.substring(1);
2198
+ format = format.substring(1);
2199
+ }
2200
+ }
2201
+ // Are both `value` and `format` `null`?
2202
+ // I.e. both `value` and `format` must be exhausted, otherwise ...
2203
+ if (format)
2204
+ // ... `format` has remaining content that the value didn't provide
2205
+ return null;
2206
+
2207
+ // Check existance of values and their range
2208
+ if (year === null)
2209
+ return null;
2210
+ if (month === null || month < 1 || month > 12)
2211
+ return null;
2212
+ if (day === null || day < 1 || day > 31) // FIXME: Use the actuall number of days
2213
+ return null;
2214
+ if (ispm === null)
2215
+ {
2216
+ if (hour < 0 || hour > 23)
2217
+ return null;
2218
+ }
2219
+ else
2220
+ {
2221
+ if (hour < 0 || hour > 11)
2222
+ return null;
2223
+ if (ispm)
2224
+ hour += 12;
2225
+ }
2226
+ if (minute < 0 || minute > 59)
2227
+ return null;
2228
+ if (minute < 0 || minute > 59)
2229
+ return null;
2230
+ if (second < 0 || second > 60)
2231
+ return null;
2232
+ return new Date(year, month-1, day, hour, minute, second);
2233
+ }
1016
2234
 
1017
2235
  _validate(change)
1018
2236
  {
@@ -1033,22 +2251,17 @@ export class DateFieldBase extends Field
1033
2251
  else if (typeof(change.value) === "string")
1034
2252
  {
1035
2253
  let value = null;
1036
- if (change.value.length === 10)
1037
- value = new Date(change.value + "T00:00:00");
1038
- else if (change.value.length === 16)
1039
- value = new Date(change.value + ":00");
1040
- else if (change.value.length === 19)
1041
- value = new Date(change.value);
1042
-
1043
- if (value === null || Number.isNaN(value.getYear()))
2254
+ for (let format of this.control.formatstrings_parse())
1044
2255
  {
1045
- change.errors.push(this.msg_date_format(change.value));
1046
- // Keep original invalid string
2256
+ value = this._parse(change.value, format);
2257
+ if (value !== null)
2258
+ break;
1047
2259
  }
1048
- else
1049
- {
2260
+ if (value !== null)
1050
2261
  change.value = this._convert(value);
1051
- }
2262
+ else
2263
+ change.errors.push(this.msg_date_format(change.value));
2264
+ // Keep original invalid string
1052
2265
  }
1053
2266
  else
1054
2267
  {
@@ -1056,12 +2269,50 @@ export class DateFieldBase extends Field
1056
2269
  change.value = null;
1057
2270
  }
1058
2271
  }
2272
+
2273
+ _get_dom_value()
2274
+ {
2275
+ let value = super._get_dom_value();
2276
+ if (!value)
2277
+ return null;
2278
+
2279
+ for (let format of this.control.formatstrings_parse())
2280
+ {
2281
+ let date = this._parse(value, format);
2282
+ if (date !== null)
2283
+ return this._convert(date);
2284
+ }
2285
+ return null;
2286
+ }
2287
+
2288
+ _set_dom_value(value)
2289
+ {
2290
+ if (value !== null)
2291
+ value = ul4._format(value, this.control.formatstring(), this.globals.lang);
2292
+ else
2293
+ value = "";
2294
+ super._set_dom_value(value);
2295
+ }
2296
+ };
2297
+
2298
+
2299
+ class DateFieldType extends DateFieldBaseType
2300
+ {
2301
+ instancecheck(obj)
2302
+ {
2303
+ return obj instanceof DateField;
2304
+ }
1059
2305
  };
1060
2306
 
2307
+ let datefieldtype = new DateFieldType("la", "DateField", "Holds the value of a date/date field of a record (and related information)");
2308
+
1061
2309
 
1062
2310
  export class DateField extends DateFieldBase
1063
2311
  {
1064
- static classdoc = "Holds the value of a date/date field of a record (and related information)";
2312
+ [ul4.symbols.type]()
2313
+ {
2314
+ return datefieldtype;
2315
+ }
1065
2316
 
1066
2317
  _convert(date)
1067
2318
  {
@@ -1070,13 +2321,27 @@ export class DateField extends DateFieldBase
1070
2321
  };
1071
2322
 
1072
2323
 
2324
+ class DatetimeMinuteFieldType extends DateFieldBaseType
2325
+ {
2326
+ instancecheck(obj)
2327
+ {
2328
+ return obj instanceof DatetimeMinuteField;
2329
+ }
2330
+ };
2331
+
2332
+ let datetimeminutefieldtype = new DatetimeMinuteFieldType("la", "DatetimeMinuteField", "Holds the value of a date/datetimeminute field of a record (and related information)");
2333
+
2334
+
1073
2335
  export class DatetimeMinuteField extends DateFieldBase
1074
2336
  {
1075
- static classdoc = "Holds the value of a date/datetimeminute field of a record (and related information)";
2337
+ [ul4.symbols.type]()
2338
+ {
2339
+ return datetimeminutefieldtype;
2340
+ }
1076
2341
 
1077
2342
  _convert(date)
1078
2343
  {
1079
- // Get rid of seconds and milliseconds
2344
+ // Get rid of seconds and milliseconds, this modifies the object passed in.
1080
2345
  date.setSeconds(0);
1081
2346
  date.setMilliseconds(0);
1082
2347
  return date;
@@ -1084,34 +2349,197 @@ export class DatetimeMinuteField extends DateFieldBase
1084
2349
  };
1085
2350
 
1086
2351
 
2352
+ class DatetimeSecondFieldType extends DateFieldBaseType
2353
+ {
2354
+ instancecheck(obj)
2355
+ {
2356
+ return obj instanceof DatetimeSecondField;
2357
+ }
2358
+ };
2359
+
2360
+ let datetimesecondfieldtype = new DatetimeSecondFieldType("la", "DatetimeSecondField", "Holds the value of a date/datetimesecond field of a record (and related information)");
2361
+
2362
+
1087
2363
  export class DatetimeSecondField extends DateFieldBase
1088
2364
  {
1089
- static classdoc = "Holds the value of a date/datetimesecond field of a record (and related information)";
2365
+ [ul4.symbols.type]()
2366
+ {
2367
+ return datetimesecondfieldtype;
2368
+ }
1090
2369
 
1091
2370
  _convert(date)
1092
2371
  {
1093
- // Get rid of milliseconds
2372
+ // Get rid of milliseconds, this modifies the object passed in.
1094
2373
  date.setMilliseconds(0);
1095
2374
  return date;
1096
2375
  }
1097
2376
  };
1098
2377
 
2378
+ /*
2379
+ `ChoiceFieldBase` is used as the base class for all `lookup`, `multiplelookup`,
2380
+ `applookup` and `multipleapplookup` fields.
2381
+
2382
+ Since the inheritance hierarchy follows the data model *not* which HTML element
2383
+ is used for editing, we would have to implement the same DOM interaction logic
2384
+ in multiple classes (i.e. we would have to handle a HTML `select` element in
2385
+ `LookupSelectField`, `MultipleLookupSelectField`, `AppLookupSelectField`
2386
+ and `MultipleAppLookupSelectField`).
2387
+
2388
+ To solve this problem, all methods that handle HTML elements are implemented in
2389
+ this class. Subclasses then simply call the appropriate method.
2390
+ */
2391
+ export class ChoiceFieldBase extends Field
2392
+ {
2393
+ _make_option(selected, value, label)
2394
+ {
2395
+ let option = element(
2396
+ "option",
2397
+ label,
2398
+ {
2399
+ "value": value,
2400
+ "class": value === this.control.nonekey ? "la-none-option" : null,
2401
+ "selected": selected ? "selected" : null,
2402
+ }
2403
+ );
2404
+ return option;
2405
+ }
2406
+
2407
+ _set_dom_lookupdata_select(lookupdata)
2408
+ {
2409
+ if (lookupdata === null)
2410
+ lookupdata = this.control.lookup_data;
2411
+ if (ul4._isobject(lookupdata))
2412
+ lookupdata = new Map(Object.entries(lookupdata));
2413
+
2414
+ let none_selected = false;
2415
+ let selected = new Set();
2416
+ for (let dom_option of this._dom_control.querySelectorAll("option:checked"))
2417
+ {
2418
+ let value = dom_option.getAttribute("value");
2419
+ if (lookupdata.has(value))
2420
+ selected.add(value);
2421
+ else if (value === this.control.nonekey)
2422
+ none_selected = true;
2423
+ }
2424
+
2425
+ let new_children = [];
2426
+ if (this.control.nonekey !== null)
2427
+ {
2428
+ new_children.push(
2429
+ this._make_option(
2430
+ none_selected,
2431
+ this.control.nonekey,
2432
+ this.control.nonelabel !== null ? this.control.nonelabel : this.globals.msg_nothing_selected()
2433
+ )
2434
+ );
2435
+ }
2436
+
2437
+ for (let [key, value] of lookupdata)
2438
+ {
2439
+ new_children.push(
2440
+ this._make_option(
2441
+ selected.has(key),
2442
+ key,
2443
+ this._make_label(value)
2444
+ )
2445
+ );
2446
+ }
2447
+ this._dom_control.replaceChildren(...new_children);
2448
+ }
2449
+
2450
+ _set_dom_lookupdata_input(lookupdata)
2451
+ {
2452
+ if (lookupdata === null)
2453
+ lookupdata = this.control.lookupdata;
2454
+ else if (ul4._isobject(lookupdata))
2455
+ lookupdata = new Map(Object.entries(lookupdata));
2456
+
2457
+ let none_selected = false;
2458
+ let selected = new Set();
2459
+ for (let dom_input of this._dom_controls)
2460
+ {
2461
+ let value = dom_input.getAttribute("value");
2462
+ if (dom_input.checked)
2463
+ {
2464
+ if (lookupdata.has(value))
2465
+ selected.add(value);
2466
+ else if (value === this.control.nonekey)
2467
+ none_selected = true;
2468
+
2469
+ }
2470
+ }
2471
+
2472
+ let dom_none_input = this._dom_root.querySelector("input[value=" + this.control.nonekey + "]");
2473
+ if (dom_none_input !== null)
2474
+ dom_none_input.checked = none_selected;
2475
+
2476
+ for (let [key, item] of this.control.lookupdata)
2477
+ {
2478
+ let dom_input = this._dom_root.querySelector("input[value=" + key + "]");
2479
+ let dom_label = this._dom_root.querySelector("label[for=" + dom_input.id + "]")
2480
+
2481
+ if (lookupdata.has(key))
2482
+ {
2483
+ dom_input.style.display = "inline";
2484
+ dom_label.style.display = "inline";
2485
+ dom_label.innerText = this._make_label(lookupdata.get(key));
2486
+ }
2487
+ else
2488
+ {
2489
+ dom_input.style.display = "none";
2490
+ dom_label.style.display = "none";
2491
+ dom_label.checked = false;
2492
+ }
2493
+ }
2494
+ }
2495
+ };
2496
+
2497
+
2498
+ class LookupFieldBaseType extends FieldType
2499
+ {
2500
+ instancecheck(obj)
2501
+ {
2502
+ return obj instanceof LookupFieldBase;
2503
+ }
2504
+ };
2505
+
2506
+ let lookupfieldbasetype = new LookupFieldBaseType("la", "LookupFieldBase", "Base type of LookupField and MultipleLookupField");
2507
+
1099
2508
 
1100
- export class LookupFieldBase extends Field
2509
+ export class LookupFieldBase extends ChoiceFieldBase
1101
2510
  {
1102
- static classdoc = "Base type of LookupField and MultipleLookupField";
2511
+ [ul4.symbols.type]()
2512
+ {
2513
+ return lookupfieldbasetype;
2514
+ }
1103
2515
 
1104
2516
  get lookupdata()
1105
2517
  {
1106
- if (this._lookupdate !== null)
1107
- return this._lookupdate;
2518
+ if (this._lookupdata !== null)
2519
+ return this._lookupdata;
1108
2520
  else
1109
2521
  return this.control.lookupdata;
1110
2522
  }
1111
2523
 
1112
2524
  set lookupdata(value)
1113
2525
  {
1114
- this._lookupdate = value;
2526
+ if (this._in_form())
2527
+ this._set_dom_lookupdata(value);
2528
+ this._lookupdata = value;
2529
+ }
2530
+
2531
+ _set_dom_lookupdata(lookupdata)
2532
+ {
2533
+ }
2534
+
2535
+ _make_label(value)
2536
+ {
2537
+ if (typeof(value) === "string")
2538
+ return value;
2539
+ else if (value instanceof LookupItem)
2540
+ return value.label;
2541
+ else
2542
+ return ul4._str(value);
1115
2543
  }
1116
2544
 
1117
2545
  _find_lookupitem(change)
@@ -1119,12 +2547,12 @@ export class LookupFieldBase extends Field
1119
2547
  let v = change.value;
1120
2548
  if (typeof(v) === "string")
1121
2549
  {
1122
- // If `lookupdata`} is `null`, this is probably an interface,
2550
+ // If `lookupdata` is `null`, this probably an interface,
1123
2551
  // so we can't validate anything (note that interfaces will however go
1124
2552
  // away in the future)
1125
2553
  if (this.lookupdata === null)
1126
2554
  return;
1127
- let lookupitem = this.lookupdata.get(v);
2555
+ let lookupitem = this.control.lookupdata.get(v);
1128
2556
  if (lookupitem === undefined)
1129
2557
  {
1130
2558
  // If the lookup control is auto expandable,
@@ -1171,30 +2599,199 @@ export class LookupFieldBase extends Field
1171
2599
  };
1172
2600
 
1173
2601
 
1174
- export class LookupField extends LookupFieldBase
2602
+ class LookupFieldType extends LookupFieldBaseType
2603
+ {
2604
+ instancecheck(obj)
2605
+ {
2606
+ return obj instanceof LookupField;
2607
+ }
2608
+ };
2609
+
2610
+ let lookupfieldtype = new LookupFieldType("la", "LookupField", "Holds the value of a lookup field of a record (and related information)");
2611
+
2612
+
2613
+ export class LookupField extends LookupFieldBase
2614
+ {
2615
+ [ul4.symbols.type]()
2616
+ {
2617
+ return lookupfieldtype;
2618
+ }
2619
+
2620
+ value_as_text(maxlevel=3)
2621
+ {
2622
+ let value = this.value;
2623
+ if (value === null)
2624
+ return null;
2625
+ return value.label;
2626
+ }
2627
+
2628
+ _validate(change)
2629
+ {
2630
+ let v = change.value;
2631
+ if (v === null || v === "" || this.control.nonekey === v)
2632
+ {
2633
+ if (this.control.required)
2634
+ change.errors.push(this.msg_field_required(v));
2635
+ change.value = null;
2636
+ }
2637
+ else
2638
+ {
2639
+ this._find_lookupitem(change);
2640
+ }
2641
+ }
2642
+ };
2643
+
2644
+
2645
+ class LookupRadioFieldType extends LookupFieldType
2646
+ {
2647
+ instancecheck(obj)
2648
+ {
2649
+ return obj instanceof LookupRadioField;
2650
+ }
2651
+ };
2652
+
2653
+ let lookupradiofieldtype = new LookupRadioFieldType("la", "LookupRadioField", "Holds the value of a lookup/radio field of a record (and related information)");
2654
+
2655
+
2656
+ export class LookupRadioField extends LookupField
2657
+ {
2658
+ [ul4.symbols.type]()
2659
+ {
2660
+ return lookupradiofieldtype;
2661
+ }
2662
+
2663
+ get _sel_label()
2664
+ {
2665
+ return this._sel_root + " label:not([for]) > span";
2666
+ }
2667
+
2668
+ _get_dom_value()
2669
+ {
2670
+ for (let node of this._dom_controls)
2671
+ {
2672
+ if (node.checked)
2673
+ {
2674
+ let key = node.getAttribute("value");
2675
+ return this.control.lookupdata.get(key);
2676
+ }
2677
+
2678
+ }
2679
+ return null;
2680
+ }
2681
+
2682
+ _set_dom_value(value)
2683
+ {
2684
+ if (value instanceof LookupItem)
2685
+ value = value.key;
2686
+ if (value === null)
2687
+ value = this.control.nonekey;
2688
+
2689
+ for (let node of this._dom_controls)
2690
+ node.checked = node.getAttribute("value") === value;
2691
+ }
2692
+
2693
+ _set_dom_lookupdata(lookupdata)
2694
+ {
2695
+ this._set_dom_lookupdata_input(lookupdata);
2696
+ }
2697
+ };
2698
+
2699
+
2700
+ class LookupSelectFieldType extends LookupFieldType
1175
2701
  {
1176
- static classdoc = "Holds the value of a lookup field of a record (and related information)";
2702
+ instancecheck(obj)
2703
+ {
2704
+ return obj instanceof LookupSelectField;
2705
+ }
2706
+ };
1177
2707
 
1178
- _validate(change)
2708
+ let lookupselectfieldtype = new LookupSelectFieldType("la", "LookupSelectField", "Holds the value of a lookup/select field of a record (and related information)");
2709
+
2710
+
2711
+ export class LookupSelectField extends LookupField
2712
+ {
2713
+ [ul4.symbols.type]()
1179
2714
  {
1180
- let v = change.value;
1181
- if (v === null || v === "" || this.control.nonekey === v)
1182
- {
1183
- if (this.control.required)
1184
- change.errors.push(this.msg_field_required(v));
1185
- change.value = null;
1186
- }
1187
- else
2715
+ return lookupselectfieldtype;
2716
+ }
2717
+
2718
+ _get_dom_value()
2719
+ {
2720
+ let value = super._get_dom_value();
2721
+ if (value)
1188
2722
  {
1189
- this._find_lookupitem(change);
2723
+ if (value === this.control.nonekey)
2724
+ value = null;
2725
+ else
2726
+ value = this.control.lookupdata.get(value);
1190
2727
  }
2728
+ return value;
2729
+ }
2730
+
2731
+ _set_dom_value(value)
2732
+ {
2733
+ let change = {value: value, errors: []};
2734
+ this._validate(change);
2735
+ super._set_dom_value(change.value != null ? change.value.key : this.control.nonekey);
2736
+ }
2737
+
2738
+ _set_dom_lookupdata(lookupdata)
2739
+ {
2740
+ this._set_dom_lookupdata_select(lookupdata);
2741
+ }
2742
+ };
2743
+
2744
+
2745
+ class LookupChoiceFieldType extends LookupFieldType
2746
+ {
2747
+ instancecheck(obj)
2748
+ {
2749
+ return obj instanceof LookupChoiceField;
2750
+ }
2751
+ };
2752
+
2753
+ let lookupchoicefieldtype = new LookupChoiceFieldType("la", "LookupChoiceField", "Holds the value of a lookup/choice field of a record (and related information)");
2754
+
2755
+
2756
+ export class LookupChoiceField extends LookupField
2757
+ {
2758
+ [ul4.symbols.type]()
2759
+ {
2760
+ return lookupchoicefieldtype;
2761
+ }
2762
+ };
2763
+
2764
+
2765
+ class MultipleLookupFieldType extends LookupFieldBaseType
2766
+ {
2767
+ instancecheck(obj)
2768
+ {
2769
+ return obj instanceof MultipleLookupField;
1191
2770
  }
1192
2771
  };
1193
2772
 
2773
+ let multiplelookupfieldtype = new MultipleLookupFieldType("la", "MultipleLookupField", "Holds the value of a multiple lookup field of a record (and related information)");
2774
+
1194
2775
 
1195
2776
  export class MultipleLookupField extends LookupFieldBase
1196
2777
  {
1197
- static classdoc = "Holds the value of a multiple lookup field of a record (and related information)";
2778
+ [ul4.symbols.type]()
2779
+ {
2780
+ return multiplelookupfieldtype;
2781
+ }
2782
+
2783
+ is_empty()
2784
+ {
2785
+ return this._value.length === 0;
2786
+ }
2787
+
2788
+ value_as_text(maxlevel=3)
2789
+ {
2790
+ let value = this.value;
2791
+ if (value === null || value.length === 0)
2792
+ return null;
2793
+ return value.map(item => item.label).join(", ");
2794
+ }
1198
2795
 
1199
2796
  _validate(change)
1200
2797
  {
@@ -1233,9 +2830,146 @@ export class MultipleLookupField extends LookupFieldBase
1233
2830
  };
1234
2831
 
1235
2832
 
1236
- export class AppLookupFieldBase extends Field
2833
+ class MultipleLookupCheckboxFieldType extends MultipleLookupFieldType
2834
+ {
2835
+ instancecheck(obj)
2836
+ {
2837
+ return obj instanceof MultipleLookupCheckboxField;
2838
+ }
2839
+ };
2840
+
2841
+ let multiplelookupcheckboxfieldtype = new MultipleLookupCheckboxFieldType("la", "MultipleLookupCheckboxField", "Holds the value of a multiplelookup/radio field of a record (and related information)");
2842
+
2843
+
2844
+ export class MultipleLookupCheckboxField extends MultipleLookupField
2845
+ {
2846
+ [ul4.symbols.type]()
2847
+ {
2848
+ return multiplelookupcheckboxfieldtype;
2849
+ }
2850
+
2851
+ get _sel_label()
2852
+ {
2853
+ return this._sel_root + " label:not([for]) > span";
2854
+ }
2855
+
2856
+ _get_dom_value()
2857
+ {
2858
+ let value = [];
2859
+ for (let node of this._dom_controls)
2860
+ {
2861
+ if (node.checked)
2862
+ {
2863
+ let key = node.getAttribute("value");
2864
+ value.push(this.control.lookupdata.get(key));
2865
+ }
2866
+
2867
+ }
2868
+ return value;
2869
+ }
2870
+
2871
+ _set_dom_value(value)
2872
+ {
2873
+ let change = {value: value, errors: []};
2874
+ this._validate(change);
2875
+ let values = new Set();
2876
+ for (let value of change.value)
2877
+ values.add(value.key);
2878
+
2879
+ for (let node of this._dom_controls)
2880
+ node.checked = values.has(node.getAttribute("value"));
2881
+ }
2882
+
2883
+ _set_dom_lookupdata(lookupdata)
2884
+ {
2885
+ this._set_dom_lookupdata_input(lookupdata);
2886
+ }
2887
+ };
2888
+
2889
+
2890
+ class MultipleLookupSelectFieldType extends MultipleLookupFieldType
2891
+ {
2892
+ instancecheck(obj)
2893
+ {
2894
+ return obj instanceof MultipleLookupSelectField;
2895
+ }
2896
+ };
2897
+
2898
+ let multiplelookupselectfieldtype = new MultipleLookupSelectFieldType("la", "MultipleLookupSelectField", "Holds the value of a multiplelookup/select field of a record (and related information)");
2899
+
2900
+ export class MultipleLookupSelectField extends MultipleLookupField
2901
+ {
2902
+ [ul4.symbols.type]()
2903
+ {
2904
+ return multiplelookupselectfieldtype;
2905
+ }
2906
+
2907
+ _get_dom_value()
2908
+ {
2909
+ let value = [];
2910
+ for (let option of this._dom_control.querySelectorAll("option"))
2911
+ {
2912
+ if (option.selected)
2913
+ value.push(this.control.lookupdata.get(option.getAttribute("value")));
2914
+ }
2915
+ return value;
2916
+ }
2917
+
2918
+ _set_dom_value(value)
2919
+ {
2920
+ let change = {value: value, errors: []};
2921
+ this._validate(change);
2922
+ let values = new Set();
2923
+ for (let value of change.value)
2924
+ values.add(value.key);
2925
+ for (let option of this._dom_control.querySelectorAll("option"))
2926
+ option.selected = values.has(option.getAttribute("value"));
2927
+ }
2928
+
2929
+ _set_dom_lookupdata(lookupdata)
2930
+ {
2931
+ this._set_dom_lookupdata_select(lookupdata);
2932
+ }
2933
+ };
2934
+
2935
+
2936
+ class MultipleLookupChoiceFieldType extends MultipleLookupFieldType
2937
+ {
2938
+ instancecheck(obj)
2939
+ {
2940
+ return obj instanceof MultipleLookupChoiceField;
2941
+ }
2942
+ };
2943
+
2944
+ let multiplelookupchoicefieldtype = new MultipleLookupChoiceFieldType("la", "MultipleLookupChoiceField", "Holds the value of a multiplelookup/choice field of a record (and related information)");
2945
+
2946
+
2947
+ export class MultipleLookupChoiceField extends MultipleLookupField
2948
+ {
2949
+ [ul4.symbols.type]()
2950
+ {
2951
+ return multiplelookupchoicefieldtype;
2952
+ }
2953
+ };
2954
+
2955
+
2956
+ class AppLookupFieldBaseType extends FieldType
2957
+ {
2958
+ instancecheck(obj)
2959
+ {
2960
+ return obj instanceof AppLookupFieldBase;
2961
+ }
2962
+ };
2963
+
2964
+ let applookupfieldbasetype = new AppLookupFieldBaseType("la", "AppLookupFieldBase", "Base type of AppLookupField and MultipleAppLookupField");
2965
+
2966
+
2967
+ export class AppLookupFieldBase extends ChoiceFieldBase
1237
2968
  {
1238
- static classdoc = "Base type of AppLookupField and MultipleAppLookupField";
2969
+ [ul4.symbols.type]()
2970
+ {
2971
+ return applookupfieldbasetype;
2972
+ }
1239
2973
 
1240
2974
  get lookupdata()
1241
2975
  {
@@ -1251,15 +2985,35 @@ export class AppLookupFieldBase extends Field
1251
2985
 
1252
2986
  set lookupdata(value)
1253
2987
  {
2988
+ if (this._in_form())
2989
+ this._set_dom_lookupdata(value);
1254
2990
  this._lookupdata = value;
1255
2991
  }
1256
2992
 
2993
+ _set_dom_lookupdata(lookupdata)
2994
+ {
2995
+ }
2996
+
2997
+ _make_label(value)
2998
+ {
2999
+ if (typeof(value) === "string")
3000
+ return value;
3001
+ else if (value instanceof Record)
3002
+ return value.as_text(this.control.lookup_controls);
3003
+ else
3004
+ return ul4._str(value);
3005
+ }
3006
+
1257
3007
  _find_record(change)
1258
3008
  {
1259
3009
  let v = change.value;
1260
3010
  if (typeof(v) === "string")
1261
3011
  {
1262
- let record = this.lookupdata.get(v);
3012
+ let record = this.control.lookup_app.records !== null ?
3013
+ this.control.lookup_app.records.get(v) :
3014
+ undefined
3015
+ ;
3016
+
1263
3017
  if (record === undefined)
1264
3018
  {
1265
3019
  change.errors.push(this.msg_applookup_unknownkey(v))
@@ -1284,12 +3038,44 @@ export class AppLookupFieldBase extends Field
1284
3038
  change.value = null;
1285
3039
  }
1286
3040
  }
3041
+
3042
+ [ul4.symbols.setattr](key, value)
3043
+ {
3044
+ if (key === "lookupdata")
3045
+ this.lookupdata = value;
3046
+ else
3047
+ super[ul4.symbols.setattr](key, value);
3048
+ }
3049
+ };
3050
+ AppLookupFieldBase.prototype._ul4attrs = new Set([...Field.prototype._ul4attrs, "lookupdata"]);
3051
+
3052
+
3053
+
3054
+ class AppLookupFieldType extends AppLookupFieldBaseType
3055
+ {
3056
+ instancecheck(obj)
3057
+ {
3058
+ return obj instanceof AppLookupField;
3059
+ }
1287
3060
  };
1288
3061
 
3062
+ let applookupfieldtype = new AppLookupFieldType("la", "AppLookupField", "Holds the value of a applookup field of a record (and related information)");
3063
+
1289
3064
 
1290
3065
  export class AppLookupField extends AppLookupFieldBase
1291
3066
  {
1292
- static classdoc = "Holds the value of a applookup field of a record (and related information)";
3067
+ [ul4.symbols.type]()
3068
+ {
3069
+ return applookupfieldtype;
3070
+ }
3071
+
3072
+ value_as_text(maxlevel=3)
3073
+ {
3074
+ let value = this.value;
3075
+ if (value === null)
3076
+ return null;
3077
+ return "(" + this.value.as_text(maxlevel) + ")";
3078
+ }
1293
3079
 
1294
3080
  _validate(change)
1295
3081
  {
@@ -1298,9 +3084,115 @@ export class AppLookupField extends AppLookupFieldBase
1298
3084
  };
1299
3085
 
1300
3086
 
3087
+ class AppLookupSelectFieldType extends AppLookupFieldType
3088
+ {
3089
+ instancecheck(obj)
3090
+ {
3091
+ return obj instanceof AppLookupSelectField;
3092
+ }
3093
+ };
3094
+
3095
+ let applookupselectfieldtype = new AppLookupSelectFieldType("la", "AppLookupSelectField", "Holds the value of a `applookup`/`select` field of a record (and related information)");
3096
+
3097
+
3098
+ export class AppLookupSelectField extends AppLookupField
3099
+ {
3100
+ [ul4.symbols.type]()
3101
+ {
3102
+ return applookupselectfieldtype;
3103
+ }
3104
+
3105
+ _get_dom_value()
3106
+ {
3107
+ let value = super._get_dom_value();
3108
+
3109
+ if (this.control.lookup_app.records !== null)
3110
+ {
3111
+ value = this.control.lookup_app.records.get(value);
3112
+ if (value === undefined)
3113
+ value = null;
3114
+ }
3115
+ else
3116
+ value = null;
3117
+ return value;
3118
+ }
3119
+
3120
+ _set_dom_value(value)
3121
+ {
3122
+ let change = {value: value, errors: []};
3123
+ this._validate(change);
3124
+ super._set_dom_value(change.value != null ? change.value.id : this.control.nonekey);
3125
+ }
3126
+
3127
+ _set_dom_lookupdata(lookupdata)
3128
+ {
3129
+ this._set_dom_lookupdata_select(lookupdata);
3130
+ }
3131
+ };
3132
+
3133
+
3134
+ class AppLookupRadioFieldType extends AppLookupFieldType
3135
+ {
3136
+ instancecheck(obj)
3137
+ {
3138
+ return obj instanceof AppLookupRadioField;
3139
+ }
3140
+ };
3141
+
3142
+ let applookupradiofieldtype = new AppLookupRadioFieldType("la", "AppLookupRadioField", "Holds the value of a `applookup`/`radio` field of a record (and related information)");
3143
+
3144
+
3145
+ export class AppLookupRadioField extends AppLookupField
3146
+ {
3147
+ [ul4.symbols.type]()
3148
+ {
3149
+ return applookupradiofieldtype;
3150
+ }
3151
+ };
3152
+
3153
+
3154
+ class AppLookupChoiceFieldType extends AppLookupFieldType
3155
+ {
3156
+ instancecheck(obj)
3157
+ {
3158
+ return obj instanceof AppLookupChoiceField;
3159
+ }
3160
+ };
3161
+
3162
+ let applookupchoicefieldtype = new AppLookupChoiceFieldType("la", "AppLookupChoiceField", "Holds the value of a `applookup`/`choice` field of a record (and related information)");
3163
+
3164
+
3165
+ export class AppLookupChoiceField extends AppLookupField
3166
+ {
3167
+ [ul4.symbols.type]()
3168
+ {
3169
+ return applookupchoicefieldtype;
3170
+ }
3171
+ };
3172
+
3173
+
3174
+ class MultipleAppLookupFieldType extends AppLookupFieldBaseType
3175
+ {
3176
+ instancecheck(obj)
3177
+ {
3178
+ return obj instanceof MultipleAppLookupField;
3179
+ }
3180
+ };
3181
+
3182
+ let multipleapplookupfieldtype = new MultipleAppLookupFieldType("la", "MultipleAppLookupField", "Holds the value of a multiple applookup field of a record (and related information)");
3183
+
3184
+
1301
3185
  export class MultipleAppLookupField extends AppLookupFieldBase
1302
3186
  {
1303
- static classdoc = "Holds the value of a multiple applookup field of a record (and related information)";
3187
+ [ul4.symbols.type]()
3188
+ {
3189
+ return multipleapplookupfieldtype;
3190
+ }
3191
+
3192
+ is_empty()
3193
+ {
3194
+ return this._value.length === 0;
3195
+ }
1304
3196
 
1305
3197
  _validate(change)
1306
3198
  {
@@ -1339,8 +3231,89 @@ export class MultipleAppLookupField extends AppLookupFieldBase
1339
3231
  };
1340
3232
 
1341
3233
 
3234
+ class MultipleAppLookupCheckboxFieldType extends MultipleAppLookupFieldType
3235
+ {
3236
+ instancecheck(obj)
3237
+ {
3238
+ return obj instanceof MultipleAppLookupCheckboxField;
3239
+ }
3240
+ };
3241
+
3242
+ let multipleapplookupcheckboxfieldtype = new MultipleAppLookupCheckboxFieldType("la", "MultipleAppLookupCheckboxField", "Holds the value of a `multipleapplookup`/`checkbox` field of a record (and related information)");
3243
+
3244
+
3245
+ export class MultipleAppLookupCheckboxField extends MultipleAppLookupField
3246
+ {
3247
+ [ul4.symbols.type]()
3248
+ {
3249
+ return multipleapplookupcheckboxfieldtype;
3250
+ }
3251
+ };
3252
+
3253
+
3254
+ class MultipleAppLookupSelectFieldType extends MultipleAppLookupFieldType
3255
+ {
3256
+ instancecheck(obj)
3257
+ {
3258
+ return obj instanceof MultipleAppLookupSelectField;
3259
+ }
3260
+ };
3261
+
3262
+ let multipleapplookupselectfieldtype = new MultipleAppLookupSelectFieldType("la", "MultipleAppLookupSelectField", "Holds the value of a `multipleapplookup`/`select` field of a record (and related information)");
3263
+
3264
+
3265
+ export class MultipleAppLookupSelectField extends MultipleAppLookupField
3266
+ {
3267
+ [ul4.symbols.type]()
3268
+ {
3269
+ return multipleapplookupselectfieldtype;
3270
+ }
3271
+
3272
+ _set_dom_lookupdata(lookupdata)
3273
+ {
3274
+ this._set_dom_lookupdata_select(lookupdata);
3275
+ }
3276
+ };
3277
+
3278
+
3279
+ class MultipleAppLookupChoiceFieldType extends MultipleAppLookupFieldType
3280
+ {
3281
+ instancecheck(obj)
3282
+ {
3283
+ return obj instanceof MultipleAppLookupChoiceField;
3284
+ }
3285
+ };
3286
+
3287
+ let multipleapplookupchoicefieldtype = new MultipleAppLookupChoiceFieldType("la", "MultipleAppLookupChoiceField", "Holds the value of a `multipleapplookup`/`choice` field of a record (and related information)");
3288
+
3289
+
3290
+ export class MultipleAppLookupChoiceField extends MultipleAppLookupField
3291
+ {
3292
+ [ul4.symbols.type]()
3293
+ {
3294
+ return multipleapplookupchoicefieldtype;
3295
+ }
3296
+ };
3297
+
3298
+
3299
+ class ControlType extends ul4.Type
3300
+ {
3301
+ instancecheck(obj)
3302
+ {
3303
+ return obj instanceof Control;
3304
+ }
3305
+ };
3306
+
3307
+ let controltype = new ControlType("la", "Control", "Metainformation about a field in a LivingApps application");
3308
+
3309
+
1342
3310
  export class Control extends Base
1343
3311
  {
3312
+ [ul4.symbols.type]()
3313
+ {
3314
+ return controltype;
3315
+ }
3316
+
1344
3317
  [ul4.symbols.repr]()
1345
3318
  {
1346
3319
  return "<" + this.constructor.name + " id=" + ul4._repr(this.id) + " identifier=" + ul4._repr(this.identifier) + ">";
@@ -1422,6 +3395,10 @@ export class Control extends Base
1422
3395
  get mode()
1423
3396
  {
1424
3397
  let view_control = this._view_control();
3398
+ if (this.app._active_view !== null && view_control === null)
3399
+ return null;
3400
+ if (this.app.globals.mode === null)
3401
+ return "display";
1425
3402
  return view_control !== null ? view_control.mode : "edit";
1426
3403
  }
1427
3404
 
@@ -1476,11 +3453,27 @@ Control.prototype.type = null;
1476
3453
  Control.prototype.subtype = null;
1477
3454
  Control.prototype._ul4onattrs = ["identifier", "fieldname", "app", "_label", "priority", "order", "ininsertprocedure", "inupdateprocedure"];
1478
3455
  Control.prototype._ul4attrs = new Set(["id", "identifier", "fieldname", "app", "priority", "order", "ininsertprocedure", "inupdateprocedure", "fulltype", "label", "top", "left", "width", "height", "liveupdate", "tabindex", "required", "mode", "labelpos", "autoalign", "in_active_view"]);
3456
+ Control.prototype._cssclass_root = "llft-control";
3457
+ Control.prototype._cssclass_control = "input";
3458
+
3459
+
3460
+ class BoolControlType extends ControlType
3461
+ {
3462
+ instancecheck(obj)
3463
+ {
3464
+ return obj instanceof BoolControl;
3465
+ }
3466
+ };
3467
+
3468
+ let boolcontroltype = new BoolControlType("la", "BoolControl", "A LivingApps boolean field (type 'bool')");
1479
3469
 
1480
3470
 
1481
3471
  export class BoolControl extends Control
1482
3472
  {
1483
- static classdoc = "A LivingApps boolean field (type 'bool')";
3473
+ [ul4.symbols.type]()
3474
+ {
3475
+ return boolcontroltype;
3476
+ }
1484
3477
 
1485
3478
  // ``search`` must by ``null``, ``false`` or ``true``
1486
3479
  search(value, search)
@@ -1497,9 +3490,23 @@ BoolControl.prototype.type = "bool";
1497
3490
  BoolControl.prototype.fieldtype = BoolField;
1498
3491
 
1499
3492
 
3493
+ class IntControlType extends ControlType
3494
+ {
3495
+ instancecheck(obj)
3496
+ {
3497
+ return obj instanceof IntControl;
3498
+ }
3499
+ };
3500
+
3501
+ let intcontroltype = new IntControlType("la", "IntControl", "A LivingApps integer field (type 'int')");
3502
+
3503
+
1500
3504
  export class IntControl extends Control
1501
3505
  {
1502
- static classdoc = "A LivingApps integer field (type 'int')";
3506
+ [ul4.symbols.type]()
3507
+ {
3508
+ return intcontroltype;
3509
+ }
1503
3510
 
1504
3511
  // ``search.value`` must by ``null`` or an integer
1505
3512
  search(value, search)
@@ -1516,9 +3523,23 @@ IntControl.prototype.type = "int";
1516
3523
  IntControl.prototype.fieldtype = IntField;
1517
3524
 
1518
3525
 
3526
+ class PlaceholderControlType extends ControlType
3527
+ {
3528
+ instancecheck(obj)
3529
+ {
3530
+ return obj instanceof PlaceholderControld;
3531
+ }
3532
+ };
3533
+
3534
+ let placeholdercontroltype = new PlaceholderControlType("la", "PlaceholderControl", "A LivingApps field that has a placeholder");
3535
+
3536
+
1519
3537
  class PlaceholderControl extends Control
1520
3538
  {
1521
- static classdoc = "A LivingApps multiplelookup field (type 'multiplelookup/select')";
3539
+ [ul4.symbols.type]()
3540
+ {
3541
+ return placeholdercontroltype;
3542
+ }
1522
3543
 
1523
3544
  get placeholder()
1524
3545
  {
@@ -1532,9 +3553,23 @@ class PlaceholderControl extends Control
1532
3553
  PlaceholderControl.prototype._ul4attrs = new Set([...Control.prototype._ul4attrs, "placeholder"]);
1533
3554
 
1534
3555
 
3556
+ class NumberControlType extends PlaceholderControlType
3557
+ {
3558
+ instancecheck(obj)
3559
+ {
3560
+ return obj instanceof NumberControl;
3561
+ }
3562
+ };
3563
+
3564
+ let numbercontroltype = new NumberControlType("la", "NumberControl", "A LivingApps number field (type 'number')");
3565
+
3566
+
1535
3567
  export class NumberControl extends PlaceholderControl
1536
3568
  {
1537
- static classdoc = "A LivingApps number field (type 'number')";
3569
+ [ul4.symbols.type]()
3570
+ {
3571
+ return numbercontroltype;
3572
+ }
1538
3573
 
1539
3574
  // ``search.value`` must by ``null`` or an integer
1540
3575
  search(value, search)
@@ -1555,10 +3590,28 @@ export class NumberControl extends PlaceholderControl
1555
3590
 
1556
3591
  NumberControl.prototype.type = "number";
1557
3592
  NumberControl.prototype.fieldtype = NumberField;
3593
+ NumberControl.prototype._ul4onattrs = [...Control.prototype._ul4onattrs, "precision", "minimum", "maximum"];
3594
+ NumberControl.prototype._ul4attrs = new Set([...Control.prototype._ul4attrs, "precision", "minimum", "maximum"]);
3595
+
3596
+
3597
+ class StringControlType extends PlaceholderControlType
3598
+ {
3599
+ instancecheck(obj)
3600
+ {
3601
+ return obj instanceof StringControl;
3602
+ }
3603
+ };
3604
+
3605
+ let stringcontroltype = new StringControlType("la", "StringControl", "A LivingApps number field (type 'string')");
1558
3606
 
1559
3607
 
1560
3608
  export class StringControl extends PlaceholderControl
1561
3609
  {
3610
+ [ul4.symbols.type]()
3611
+ {
3612
+ return stringcontroltype;
3613
+ }
3614
+
1562
3615
  _user_placeholder(user, placeholder)
1563
3616
  {
1564
3617
  if (placeholder === null)
@@ -1669,45 +3722,138 @@ export class StringControl extends PlaceholderControl
1669
3722
  StringControl.prototype.type = "string";
1670
3723
 
1671
3724
 
3725
+ class TextControlType extends StringControlType
3726
+ {
3727
+ instancecheck(obj)
3728
+ {
3729
+ return obj instanceof TextControl;
3730
+ }
3731
+ };
3732
+
3733
+ let textcontroltype = new TextControlType("la", "TextControl", "A LivingApps text field (type 'string/text')");
3734
+
3735
+
1672
3736
  export class TextControl extends StringControl
1673
3737
  {
1674
- static classdoc = "A LivingApps text field (type 'string/text')";
3738
+ [ul4.symbols.type]()
3739
+ {
3740
+ return textcontroltype;
3741
+ }
1675
3742
  };
1676
3743
 
1677
3744
  TextControl.prototype.subtype = "text";
1678
3745
  TextControl.prototype.fieldtype = StringField;
1679
3746
 
1680
3747
 
3748
+ class PasswordControlType extends StringControlType
3749
+ {
3750
+ instancecheck(obj)
3751
+ {
3752
+ return obj instanceof PasswordControl;
3753
+ }
3754
+ };
3755
+
3756
+ let passwordcontroltype = new PasswordControlType("la", "PasswordControl", "A LivingApps password field (type 'string/password')");
3757
+
3758
+
3759
+ export class PasswordControl extends StringControl
3760
+ {
3761
+ [ul4.symbols.type]()
3762
+ {
3763
+ return passwordcontroltype;
3764
+ }
3765
+ };
3766
+
3767
+ PasswordControl.prototype.subtype = "password";
3768
+ PasswordControl.prototype.fieldtype = PasswordField;
3769
+
3770
+
3771
+ class EmailControlType extends StringControlType
3772
+ {
3773
+ instancecheck(obj)
3774
+ {
3775
+ return obj instanceof EmailControl;
3776
+ }
3777
+ };
3778
+
3779
+ let emailcontroltype = new EmailControlType("la", "EmailControl", "A LivingApps email field (type 'string/email')");
3780
+
3781
+
1681
3782
  export class EmailControl extends StringControl
1682
3783
  {
1683
- static classdoc = "A LivingApps email field (type 'string/email')";
3784
+ [ul4.symbols.type]()
3785
+ {
3786
+ return emailcontroltype;
3787
+ }
1684
3788
  };
1685
3789
 
1686
3790
  EmailControl.prototype.subtype = "email";
1687
3791
  EmailControl.prototype.fieldtype = EmailField;
1688
3792
 
1689
3793
 
3794
+ class URLControlType extends StringControlType
3795
+ {
3796
+ instancecheck(obj)
3797
+ {
3798
+ return obj instanceof URLControl;
3799
+ }
3800
+ };
3801
+
3802
+ let urlcontroltype = new URLControlType("la", "URLControl", "A LivingApps URL field (type 'string/url')");
3803
+
3804
+
1690
3805
  export class URLControl extends StringControl
1691
3806
  {
1692
- static classdoc = "A LivingApps URL field (type 'string/url')";
3807
+ [ul4.symbols.type]()
3808
+ {
3809
+ return urlcontroltype;
3810
+ }
1693
3811
  };
1694
3812
 
1695
3813
  URLControl.prototype.subtype = "url";
1696
3814
  URLControl.prototype.fieldtype = URLField;
1697
3815
 
1698
3816
 
3817
+ class TelControlType extends StringControlType
3818
+ {
3819
+ instancecheck(obj)
3820
+ {
3821
+ return obj instanceof TelControl;
3822
+ }
3823
+ };
3824
+
3825
+ let telcontroltype = new TelControlType("la", "TelControl", "A LivingApps phone number field (type 'string/tel')");
3826
+
3827
+
1699
3828
  export class TelControl extends StringControl
1700
3829
  {
1701
- static classdoc = "A LivingApps phone number field (type 'string/tel')";
3830
+ [ul4.symbols.type]()
3831
+ {
3832
+ return telcontroltype;
3833
+ }
1702
3834
  };
1703
3835
 
1704
3836
  TelControl.prototype.subtype = "tel";
1705
3837
  TelControl.prototype.fieldtype = TelField;
1706
3838
 
1707
3839
 
3840
+ class TextAreaControlType extends StringControlType
3841
+ {
3842
+ instancecheck(obj)
3843
+ {
3844
+ return obj instanceof TextAreaControl;
3845
+ }
3846
+ };
3847
+
3848
+ let textareacontroltype = new TextAreaControlType("la", "TextAreaControl", "A LivingApps textarea field (type 'string/textarea')");
3849
+
3850
+
1708
3851
  export class TextAreaControl extends StringControl
1709
3852
  {
1710
- static classdoc = "A LivingApps textarea field (type 'string/textarea')";
3853
+ [ul4.symbols.type]()
3854
+ {
3855
+ return textareacontroltype;
3856
+ }
1711
3857
 
1712
3858
  get maxlength()
1713
3859
  {
@@ -1729,20 +3875,49 @@ TextAreaControl.prototype.subtype = "textarea";
1729
3875
  TextAreaControl.prototype.fieldtype = TextAreaField;
1730
3876
  TextAreaControl.prototype._ul4onattrs = [...StringControl.prototype._ul4onattrs, "encrypted"];
1731
3877
  TextAreaControl.prototype._ul4attrs = new Set([...StringControl.prototype._ul4attrs, "encrypted"]);
3878
+ TextAreaControl.prototype._cssclass_control = "textarea";
3879
+
3880
+
3881
+ class HTMLControlType extends StringControlType
3882
+ {
3883
+ instancecheck(obj)
3884
+ {
3885
+ return obj instanceof HTMLControl;
3886
+ }
3887
+ };
3888
+
3889
+ let htmlcontroltype = new HTMLControlType("la", "HTMLControl", "A LivingApps HTML field (type 'string/html')");
1732
3890
 
1733
3891
 
1734
3892
  export class HTMLControl extends StringControl
1735
3893
  {
1736
- static classdoc = "A LivingApps HTML field (type 'string/html')";
3894
+ [ul4.symbols.type]()
3895
+ {
3896
+ return htmlcontroltype;
3897
+ }
1737
3898
  };
1738
3899
 
1739
3900
  HTMLControl.prototype.subtype = "html";
1740
3901
  HTMLControl.prototype.fieldtype = HTMLField;
1741
3902
 
1742
3903
 
3904
+ class DateControlType extends PlaceholderControlType
3905
+ {
3906
+ instancecheck(obj)
3907
+ {
3908
+ return obj instanceof DateControl;
3909
+ }
3910
+ };
3911
+
3912
+ let datecontroltype = new DateControlType("la", "DateControl", "A LivingApps date field (type 'date/date')");
3913
+
3914
+
1743
3915
  export class DateControl extends PlaceholderControl
1744
3916
  {
1745
- static classdoc = "A LivingApps date field (type 'date/date')";
3917
+ [ul4.symbols.type]()
3918
+ {
3919
+ return datecontroltype;
3920
+ }
1746
3921
 
1747
3922
  get default()
1748
3923
  {
@@ -1754,14 +3929,25 @@ export class DateControl extends PlaceholderControl
1754
3929
  return view_control.default === "{today}" ? ul4.today() : null;
1755
3930
  }
1756
3931
 
1757
- formatstring(language)
3932
+ formatstring(lang)
1758
3933
  {
1759
- language = language || this.app.language;
3934
+ lang = lang || this.globals.lang;
1760
3935
 
1761
- if (language === "de")
1762
- return "%d.%m.%Y";
1763
- else
1764
- return "%m/%d/%Y";
3936
+ if (lang !== "de" && lang !== "fr" && lang !== "it")
3937
+ lang = "en";
3938
+ return this._formatstrings[lang];
3939
+ }
3940
+
3941
+ formatstrings_parse(lang)
3942
+ {
3943
+ lang = lang || this.globals.lang;
3944
+ if (lang !== "de" && lang !== "fr" && lang !== "it")
3945
+ lang = "en";
3946
+
3947
+ return [
3948
+ ...this._formatstrings_parse[lang],
3949
+ ...this._formatstrings_parse["intl"]
3950
+ ];
1765
3951
  }
1766
3952
 
1767
3953
  // searchvalue must be ``null``, a ``Date`` object or a string
@@ -1792,11 +3978,62 @@ export class DateControl extends PlaceholderControl
1792
3978
  DateControl.prototype.type = "date";
1793
3979
  DateControl.prototype.subtype = "date";
1794
3980
  DateControl.prototype.fieldtype = DateField;
3981
+ DateControl.prototype._formatstrings = {
3982
+ "de": "%d.%m.%Y",
3983
+ "fr": "%d.%m.%Y",
3984
+ "it": "%d.%m.%Y",
3985
+ "en": "%m/%d/%Y",
3986
+ "intl": "%Y-%m-%d"
3987
+ };
3988
+
3989
+ let _suffixes = [
3990
+ "",
3991
+ " %H:%M",
3992
+ "T%H:%M",
3993
+ " %H:%M:%S",
3994
+ "T%H:%M:%S",
3995
+ " %H:%M:%S.%f",
3996
+ "T%H:%M:%S.%f",
3997
+ " %H:%M%z",
3998
+ "T%H:%M%z",
3999
+ " %H:%M:%S%z",
4000
+ "T%H:%M:%S%z",
4001
+ " %H:%M:%S.%f%z",
4002
+ "T%H:%M:%S.%f%z",
4003
+ " %H:%M %z",
4004
+ "T%H:%M %z",
4005
+ " %H:%M:%S %z",
4006
+ "T%H:%M:%S %z",
4007
+ " %H:%M:%S.%f %z",
4008
+ "T%H:%M:%S.%f %z"
4009
+ ]
4010
+
4011
+ DateControl.prototype._formatstrings_parse = {
4012
+ "en": _suffixes.map(s => "%m/%d/%Y" + s),
4013
+ "de": _suffixes.map(s => "%d.%m.%Y" + s),
4014
+ "fr": _suffixes.map(s => "%d.%m.%Y" + s),
4015
+ "it": _suffixes.map(s => "%d.%m.%Y" + s),
4016
+ "intl": _suffixes.map(s => "%Y-%m-%d" + s)
4017
+ };
4018
+
4019
+
4020
+ class DatetimeMinuteControlType extends DateControlType
4021
+ {
4022
+ instancecheck(obj)
4023
+ {
4024
+ return obj instanceof DatetimeMinuteControl;
4025
+ }
4026
+ };
4027
+
4028
+ let datetimeminutecontroltype = new DatetimeMinuteControlType("la", "DatetimeMinuteControl", "A LivingApps date field (type 'date/datetimeminute')");
1795
4029
 
1796
4030
 
1797
4031
  export class DatetimeMinuteControl extends DateControl
1798
4032
  {
1799
- static classdoc = "A LivingApps date field (type 'date/datetimeminute')";
4033
+ [ul4.symbols.type]()
4034
+ {
4035
+ return datetimeminutecontroltype;
4036
+ }
1800
4037
 
1801
4038
  get default()
1802
4039
  {
@@ -1815,25 +4052,36 @@ export class DatetimeMinuteControl extends DateControl
1815
4052
  else
1816
4053
  return null;
1817
4054
  }
4055
+ };
1818
4056
 
1819
- formatstring(language)
1820
- {
1821
- language = language || this.app.language;
4057
+ DatetimeMinuteControl.prototype.subtype = "datetimeminute";
4058
+ DatetimeMinuteControl.prototype.fieldtype = DatetimeMinuteField;
4059
+ DatetimeMinuteControl.prototype._formatstrings = {
4060
+ "de": "%d.%m.%Y %H:%M",
4061
+ "fr": "%d.%m.%Y %H:%M",
4062
+ "it": "%d.%m.%Y %H:%M",
4063
+ "en": "%m/%d/%Y %H:%M",
4064
+ "intl": "%Y-%m-%d %H:%M"
4065
+ };
1822
4066
 
1823
- if (language === "de")
1824
- return "%d.%m.%Y %H:%M";
1825
- else
1826
- return "%m/%d/%Y %H:%M";
4067
+
4068
+ class DatetimeSecondControlType extends DateControlType
4069
+ {
4070
+ instancecheck(obj)
4071
+ {
4072
+ return obj instanceof DatetimeSecondControl;
1827
4073
  }
1828
4074
  };
1829
4075
 
1830
- DatetimeMinuteControl.prototype.subtype = "datetimeminute";
1831
- DatetimeMinuteControl.prototype.fieldtype = DatetimeMinuteField;
4076
+ let datetimesecondcontroltype = new DatetimeSecondControlType("la", "DatetimeSecondControl", "A LivingApps date field (type 'date/datetimesecond')");
1832
4077
 
1833
4078
 
1834
4079
  export class DatetimeSecondControl extends DateControl
1835
4080
  {
1836
- static classdoc = "A LivingApps date field (type 'date/datetimesecond')";
4081
+ [ul4.symbols.type]()
4082
+ {
4083
+ return datetimesecondcontroltype;
4084
+ }
1837
4085
 
1838
4086
  get default()
1839
4087
  {
@@ -1851,24 +4099,37 @@ export class DatetimeSecondControl extends DateControl
1851
4099
  else
1852
4100
  return null;
1853
4101
  }
4102
+ };
1854
4103
 
1855
- formatstring(language)
1856
- {
1857
- language = language || this.app.language;
4104
+ DatetimeSecondControl.prototype.subtype = "datetimesecond";
4105
+ DatetimeSecondControl.prototype.fieldtype = DatetimeSecondField;
4106
+ DatetimeSecondControl.prototype._formatstrings = {
4107
+ "de": "%d.%m.%Y %H:%M:%S",
4108
+ "fr": "%d.%m.%Y %H:%M:%S",
4109
+ "it": "%d.%m.%Y %H:%M:%S",
4110
+ "en": "%m/%d/%Y %H:%M:%S",
4111
+ "intl": "%Y-%m-%d %H:%M:%S"
4112
+ };
1858
4113
 
1859
- if (language === "de")
1860
- return "%d.%m.%Y %H:%M:%S";
1861
- else
1862
- return "%m/%d/%Y %H:%M:%S";
4114
+
4115
+ class LookupControlType extends ControlType
4116
+ {
4117
+ instancecheck(obj)
4118
+ {
4119
+ return obj instanceof LookupControl;
1863
4120
  }
1864
4121
  };
1865
4122
 
1866
- DatetimeSecondControl.prototype.subtype = "datetimesecond";
1867
- DatetimeSecondControl.prototype.fieldtype = DatetimeSecondField;
4123
+ let lookupcontroltype = new LookupControlType("la", "LookupControl", "A LivingApps date field (type 'lookup')");
1868
4124
 
1869
4125
 
1870
4126
  export class LookupControl extends Control
1871
4127
  {
4128
+ [ul4.symbols.type]()
4129
+ {
4130
+ return lookupcontroltype;
4131
+ }
4132
+
1872
4133
  get default()
1873
4134
  {
1874
4135
  let view_control = this._view_control();
@@ -1924,35 +4185,119 @@ LookupControl.prototype._ul4onattrs = [...Control.prototype._ul4onattrs, "lookup
1924
4185
  LookupControl.prototype._ul4attrs = new Set([...Control.prototype._ul4attrs, "lookupdata"]);
1925
4186
 
1926
4187
 
1927
- export class LookupSelectControl extends LookupControl
4188
+ class LookupSelectControlType extends LookupControlType
1928
4189
  {
1929
- static classdoc = "A LivingApps lookup field (type 'lookup/select')";
4190
+ instancecheck(obj)
4191
+ {
4192
+ return obj instanceof LookupSelectControl;
4193
+ }
4194
+ };
1930
4195
 
4196
+ let lookupselectcontroltype = new LookupSelectControlType("la", "LookupSelectControl", "A LivingApps lookup field (type 'lookup/select')");
4197
+
4198
+
4199
+ export class LookupSelectControl extends LookupControl
4200
+ {
4201
+ [ul4.symbols.type]()
4202
+ {
4203
+ return lookupselectcontroltype;
4204
+ }
1931
4205
  };
1932
4206
 
1933
4207
  LookupSelectControl.prototype.subtype = "select";
4208
+ LookupSelectControl.prototype.fieldtype = LookupSelectField;
4209
+ LookupSelectControl.prototype._cssclass_control = "select";
1934
4210
 
1935
4211
 
1936
- export class LookupRadioControl extends LookupControl
4212
+ class LookupRadioControlType extends LookupControlType
1937
4213
  {
1938
- static classdoc = "A LivingApps lookup field (type 'lookup/radio')";
4214
+ instancecheck(obj)
4215
+ {
4216
+ return obj instanceof LookupRadioControl;
4217
+ }
4218
+ };
4219
+
4220
+ let lookupradiocontroltype = new LookupRadioControlType("la", "LookupRadioControl", "A LivingApps lookup field (type 'lookup/radio')");
4221
+
1939
4222
 
4223
+ export class LookupRadioControl extends LookupControl
4224
+ {
4225
+ [ul4.symbols.type]()
4226
+ {
4227
+ return lookupradiocontroltype;
4228
+ }
1940
4229
  };
1941
4230
 
1942
4231
  LookupRadioControl.prototype.subtype = "radio";
4232
+ LookupRadioControl.prototype.fieldtype = LookupRadioField;
4233
+ LookupRadioControl.prototype._cssclass_root = "llft-element";
1943
4234
 
1944
4235
 
1945
- export class LookupChoiceControl extends LookupControl
4236
+ class LookupChoiceControlType extends LookupControlType
1946
4237
  {
1947
- static classdoc = "A LivingApps lookup field (type 'lookup/choice')";
4238
+ instancecheck(obj)
4239
+ {
4240
+ return obj instanceof LookupChoiceControl;
4241
+ }
4242
+ };
1948
4243
 
4244
+ let lookupchoicecontroltype = new LookupChoiceControlType("la", "LookupChoiceControl", "A LivingApps lookup field (type 'lookup/choice')");
4245
+
4246
+
4247
+ export class LookupChoiceControl extends LookupControl
4248
+ {
4249
+ [ul4.symbols.type]()
4250
+ {
4251
+ return lookupchoicecontroltype;
4252
+ }
1949
4253
  };
1950
4254
 
1951
4255
  LookupChoiceControl.prototype.subtype = "choice";
4256
+ LookupChoiceControl.prototype.fieldtype = LookupChoiceField;
4257
+
4258
+
4259
+ class AppLookupControlType extends ControlType
4260
+ {
4261
+ instancecheck(obj)
4262
+ {
4263
+ return obj instanceof AppLookupControl;
4264
+ }
4265
+ };
4266
+
4267
+ let applookupcontroltype = new AppLookupControlType("la", "AppLookupControl", "A LivingApps lookup field (type 'applookup')");
4268
+
4269
+
4270
+ export class AppLookupControl extends Control
4271
+ {
4272
+ [ul4.symbols.type]()
4273
+ {
4274
+ return applookupcontroltype;
4275
+ }
4276
+
4277
+ get lookupdata()
4278
+ {
4279
+ if (this.lookup_app !== null && this.lookup_app.records !== null)
4280
+ return this.lookup_app.records;
4281
+ else
4282
+ return new Map();
4283
+ }
4284
+
4285
+ get nonekey()
4286
+ {
4287
+ let view_control = this._view_control();
4288
+ if (view_control === null)
4289
+ return null;
4290
+ return view_control.lookupnonekey;
4291
+ }
1952
4292
 
4293
+ get nonelabel()
4294
+ {
4295
+ let view_control = this._view_control();
4296
+ if (view_control === null)
4297
+ return null;
4298
+ return view_control.lookupnonelabel;
4299
+ }
1953
4300
 
1954
- export class AppLookupControl extends Control
1955
- {
1956
4301
  // ``search.value`` must be an object containing the search criteria for the referenced record
1957
4302
  search(value, search)
1958
4303
  {
@@ -1969,35 +4314,94 @@ AppLookupControl.prototype._ul4onattrs = [...Control.prototype._ul4onattrs, "loo
1969
4314
  AppLookupControl.prototype._ul4attrs = new Set([...Control.prototype._ul4attrs, "lookup_app", "lookup_controls", "local_master_control", "local_detail_controls", "remote_master_control"]);
1970
4315
 
1971
4316
 
1972
- export class AppLookupSelectControl extends AppLookupControl
4317
+ class AppLookupSelectControlType extends AppLookupControlType
1973
4318
  {
1974
- static classdoc = "A LivingApps applookup field (type 'applookup/select')";
4319
+ instancecheck(obj)
4320
+ {
4321
+ return obj instanceof AppLookupSelectControl;
4322
+ }
4323
+ };
4324
+
4325
+ let applookupselectcontroltype = new AppLookupSelectControlType("la", "AppLookupSelectControl", "A LivingApps applookup field (type 'applookup/select')");
4326
+
1975
4327
 
4328
+ export class AppLookupSelectControl extends AppLookupControl
4329
+ {
4330
+ [ul4.symbols.type]()
4331
+ {
4332
+ return applookupselectcontroltype;
4333
+ }
1976
4334
  };
1977
4335
 
1978
4336
  AppLookupSelectControl.prototype.subtype = "select";
4337
+ AppLookupSelectControl.prototype.fieldtype = AppLookupSelectField;
4338
+ AppLookupSelectControl.prototype._cssclass_control = "select";
1979
4339
 
1980
4340
 
1981
- export class AppLookupRadioControl extends AppLookupControl
4341
+ class AppLookupRadioControlType extends AppLookupControlType
1982
4342
  {
1983
- static classdoc = "A LivingApps applookup field (type 'applookup/radio')";
4343
+ instancecheck(obj)
4344
+ {
4345
+ return obj instanceof AppLookupRadioControl;
4346
+ }
4347
+ };
1984
4348
 
4349
+ let applookupradiocontroltype = new AppLookupRadioControlType("la", "AppLookupRadioControl", "A LivingApps applookup field (type 'applookup/radio')");
4350
+
4351
+
4352
+ export class AppLookupRadioControl extends AppLookupControl
4353
+ {
4354
+ [ul4.symbols.type]()
4355
+ {
4356
+ return applookupradiocontroltype;
4357
+ }
1985
4358
  };
1986
4359
 
1987
4360
  AppLookupRadioControl.prototype.subtype = "radio";
4361
+ AppLookupRadioControl.prototype.fieldtype = AppLookupRadioField;
1988
4362
 
1989
4363
 
1990
- export class AppLookupChoiceControl extends AppLookupControl
4364
+ class AppLookupChoiceControlType extends AppLookupControlType
1991
4365
  {
1992
- static classdoc = "A LivingApps applookup field (type 'applookup/choice')";
4366
+ instancecheck(obj)
4367
+ {
4368
+ return obj instanceof AppLookupChoiceControl;
4369
+ }
4370
+ };
4371
+
4372
+ let applookupchoicecontroltype = new AppLookupChoiceControlType("la", "AppLookupChoiceControl", "A LivingApps applookup field (type 'applookup/choice')");
4373
+
1993
4374
 
4375
+ export class AppLookupChoiceControl extends AppLookupControl
4376
+ {
4377
+ [ul4.symbols.type]()
4378
+ {
4379
+ return applookupchoicecontroltype;
4380
+ }
1994
4381
  };
1995
4382
 
1996
4383
  AppLookupChoiceControl.prototype.subtype = "choice";
4384
+ AppLookupChoiceControl.prototype.fieldtype = AppLookupChoiceField;
4385
+
4386
+
4387
+ class MultipleLookupControlType extends LookupControlType
4388
+ {
4389
+ instancecheck(obj)
4390
+ {
4391
+ return obj instanceof MultipleLookupControl;
4392
+ }
4393
+ };
4394
+
4395
+ let multiplelookupcontroltype = new MultipleLookupControlType("la", "MultipleLookupControl", "A LivingApps multiple applookup field (type 'multipleapplookup')");
1997
4396
 
1998
4397
 
1999
4398
  export class MultipleLookupControl extends LookupControl
2000
4399
  {
4400
+ [ul4.symbols.type]()
4401
+ {
4402
+ return multiplelookupcontroltype;
4403
+ }
4404
+
2001
4405
  get default()
2002
4406
  {
2003
4407
  let view_control = this._view_control();
@@ -2027,39 +4431,104 @@ export class MultipleLookupControl extends LookupControl
2027
4431
  }
2028
4432
  };
2029
4433
 
2030
- MultipleLookupControl.prototype.subtype = "multiplelookup";
4434
+ MultipleLookupControl.prototype.type = "multiplelookup";
2031
4435
  MultipleLookupControl.prototype.fieldtype = MultipleLookupField;
2032
4436
 
2033
4437
 
2034
- export class MultipleLookupSelectControl extends MultipleLookupControl
4438
+ class MultipleLookupCheckboxControlType extends MultipleLookupControlType
2035
4439
  {
2036
- static classdoc = "A LivingApps multiplelookup field (type 'multiplelookup/select')";
2037
-
4440
+ instancecheck(obj)
4441
+ {
4442
+ return obj instanceof MultipleLookupCheckboxControl;
4443
+ }
2038
4444
  };
2039
4445
 
2040
- MultipleLookupSelectControl.prototype.subtype = "select";
4446
+ let multiplelookupcheckboxcontroltype = new MultipleLookupCheckboxControlType("la", "MultipleLookupCheckboxControl", "A LivingApps multiplelookup field (type 'multiplelookup/checkbox')");
2041
4447
 
2042
4448
 
2043
4449
  export class MultipleLookupCheckboxControl extends MultipleLookupControl
2044
4450
  {
2045
- static classdoc = "A LivingApps multiplelookup field (type 'multiplelookup/checkbox')";
4451
+ [ul4.symbols.type]()
4452
+ {
4453
+ return multiplelookupcheckboxcontroltype;
4454
+ }
2046
4455
 
4456
+ get _sel_label()
4457
+ {
4458
+ return this._sel_root + " label:not([for]) > span";
4459
+ }
2047
4460
  };
2048
4461
 
2049
4462
  MultipleLookupCheckboxControl.prototype.subtype = "checkbox";
4463
+ MultipleLookupCheckboxControl.prototype.fieldtype = MultipleLookupCheckboxField;
4464
+ MultipleLookupCheckboxControl.prototype._cssclass_root = "llft-element";
2050
4465
 
2051
4466
 
2052
- export class MultipleLookupChoiceControl extends MultipleLookupControl
4467
+ class MultipleLookupSelectControlType extends MultipleLookupControlType
4468
+ {
4469
+ instancecheck(obj)
4470
+ {
4471
+ return obj instanceof MultipleLookupSelectControl;
4472
+ }
4473
+ };
4474
+
4475
+ let multiplelookupselectcontroltype = new MultipleLookupSelectControlType("la", "MultipleLookupSelectControl", "A LivingApps multiplelookup field (type 'multiplelookup/select')");
4476
+
4477
+
4478
+ export class MultipleLookupSelectControl extends MultipleLookupControl
4479
+ {
4480
+ [ul4.symbols.type]()
4481
+ {
4482
+ return multiplelookupselectcontroltype;
4483
+ }
4484
+ };
4485
+
4486
+ MultipleLookupSelectControl.prototype.subtype = "select";
4487
+ MultipleLookupSelectControl.prototype.fieldtype = MultipleLookupSelectField;
4488
+ MultipleLookupSelectControl.prototype._cssclass_control = "select";
4489
+
4490
+
4491
+ class MultipleLookupChoiceControlType extends MultipleLookupControlType
2053
4492
  {
2054
- static classdoc = "A LivingApps multiplelookup field (type 'multiplelookup/choice')";
4493
+ instancecheck(obj)
4494
+ {
4495
+ return obj instanceof MultipleLookupChoiceControl;
4496
+ }
4497
+ };
4498
+
4499
+ let multiplelookupchoicecontroltype = new MultipleLookupChoiceControlType("la", "MultipleLookupChoiceControl", "A LivingApps multiplelookup field (type 'multiplelookup/choice')");
2055
4500
 
4501
+
4502
+ export class MultipleLookupChoiceControl extends MultipleLookupControl
4503
+ {
4504
+ [ul4.symbols.type]()
4505
+ {
4506
+ return multiplelookupchoicecontroltype;
4507
+ }
2056
4508
  };
2057
4509
 
2058
4510
  MultipleLookupChoiceControl.prototype.subtype = "choice";
4511
+ MultipleLookupChoiceControl.prototype.fieldtype = MultipleLookupChoiceField;
4512
+
4513
+
4514
+ class MultipleAppLookupControlType extends AppLookupControlType
4515
+ {
4516
+ instancecheck(obj)
4517
+ {
4518
+ return obj instanceof MultipleAppLookupControl;
4519
+ }
4520
+ };
4521
+
4522
+ let multipleapplookupcontroltype = new MultipleAppLookupControlType("la", "MultipleAppLookupControl", "A LivingApps multiple applookup field (type 'multipleapplookup')");
2059
4523
 
2060
4524
 
2061
4525
  export class MultipleAppLookupControl extends AppLookupControl
2062
4526
  {
4527
+ [ul4.symbols.type]()
4528
+ {
4529
+ return multipleapplookupcontroltype;
4530
+ }
4531
+
2063
4532
  // ``search.value`` must be an object containing the search criteria for the referenced record
2064
4533
  search(value, search)
2065
4534
  {
@@ -2086,69 +4555,186 @@ MultipleAppLookupControl.prototype.type = "multipleapplookup";
2086
4555
  MultipleAppLookupControl.prototype.fieldtype = MultipleAppLookupField;
2087
4556
 
2088
4557
 
2089
- export class MultipleAppLookupSelectControl extends MultipleAppLookupControl
4558
+ class MultipleAppLookupSelectControlType extends MultipleAppLookupControlType
2090
4559
  {
2091
- static classdoc = "A LivingApps multiple applookup field (type 'multipleapplookup/select')";
4560
+ instancecheck(obj)
4561
+ {
4562
+ return obj instanceof MultipleAppLookupSelectControl;
4563
+ }
4564
+ };
4565
+
4566
+ let multipleapplookupselectcontroltype = new MultipleAppLookupSelectControlType("la", "MultipleAppLookupSelectControl", "A LivingApps multiple applookup field (type 'multipleapplookup/select')");
2092
4567
 
4568
+
4569
+ export class MultipleAppLookupSelectControl extends MultipleAppLookupControl
4570
+ {
4571
+ [ul4.symbols.type]()
4572
+ {
4573
+ return multipleapplookupselectcontroltype;
4574
+ }
2093
4575
  };
2094
4576
 
2095
4577
  MultipleAppLookupSelectControl.prototype.subtype = "select";
4578
+ MultipleAppLookupSelectControl.prototype.fieldtype = MultipleAppLookupSelectField;
4579
+ MultipleAppLookupSelectControl.prototype._cssclass_control = "select";
2096
4580
 
2097
4581
 
2098
- export class MultipleAppLookupCheckboxControl extends MultipleAppLookupControl
4582
+ class MultipleAppLookupCheckboxControlType extends MultipleAppLookupControlType
2099
4583
  {
2100
- static classdoc = "A LivingApps multiple applookup field (type 'multipleapplookup/checkbox')";
4584
+ instancecheck(obj)
4585
+ {
4586
+ return obj instanceof MultipleAppLookupCheckboxControl;
4587
+ }
4588
+ };
4589
+
4590
+ let multipleapplookupcheckboxcontroltype = new MultipleAppLookupCheckboxControlType("la", "MultipleAppLookupCheckboxControl", "A LivingApps multiple applookup field (type 'multipleapplookup/checkbox')");
2101
4591
 
4592
+
4593
+ export class MultipleAppLookupCheckboxControl extends MultipleAppLookupControl
4594
+ {
4595
+ [ul4.symbols.type]()
4596
+ {
4597
+ return multipleapplookupcheckboxcontroltype;
4598
+ }
2102
4599
  };
2103
4600
 
2104
4601
  MultipleAppLookupCheckboxControl.prototype.subtype = "checkbox";
4602
+ MultipleAppLookupCheckboxControl.prototype.fieldtype = MultipleAppLookupCheckboxField;
4603
+
4604
+
4605
+ class MultipleAppLookupChoiceControlType extends MultipleAppLookupControlType
4606
+ {
4607
+ instancecheck(obj)
4608
+ {
4609
+ return obj instanceof MultipleAppLookupChoiceControl;
4610
+ }
4611
+ };
4612
+
4613
+ let multipleapplookupchoicecontroltype = new MultipleAppLookupChoiceControlType("la", "MultipleAppLookupChoiceControl", "A LivingApps multiple applookup field (type 'multipleapplookup/choice')");
2105
4614
 
2106
4615
 
2107
4616
  export class MultipleAppLookupChoiceControl extends MultipleAppLookupControl
2108
4617
  {
2109
- static classdoc = "A LivingApps multiple applookup field (type 'multipleapplookup/choice')";
4618
+ [ul4.symbols.type]()
4619
+ {
4620
+ return multipleapplookupchoicecontroltype;
4621
+ }
2110
4622
  };
2111
4623
 
2112
4624
  MultipleAppLookupChoiceControl.prototype.subtype = "choice";
4625
+ MultipleAppLookupChoiceControl.prototype.fieldtype = MultipleAppLookupChoiceField;
4626
+
4627
+
4628
+ class GeoControlType extends ControlType
4629
+ {
4630
+ instancecheck(obj)
4631
+ {
4632
+ return obj instanceof GeoControl;
4633
+ }
4634
+ };
4635
+
4636
+ let geocontroltype = new GeoControlType("la", "GeoControl", "A LivingApps geo field (type 'geo')");
2113
4637
 
2114
4638
 
2115
4639
  export class GeoControl extends Control
2116
4640
  {
2117
- static classdoc = "A LivingApps geo field (type 'geo')";
4641
+ [ul4.symbols.type]()
4642
+ {
4643
+ return geocontroltype;
4644
+ }
2118
4645
  };
2119
4646
 
2120
4647
  GeoControl.prototype.type = "geo";
2121
4648
  GeoControl.prototype.fieldtype = GeoField;
4649
+ GeoControl.prototype._cssclass_root = "llft-element";
4650
+
4651
+
4652
+ class FileControlType extends ControlType
4653
+ {
4654
+ instancecheck(obj)
4655
+ {
4656
+ return obj instanceof FileControl;
4657
+ }
4658
+ };
4659
+
4660
+ let filecontroltype = new FileControlType("la", "FileControl", "A LivingApps upload field (type 'file')");
2122
4661
 
2123
4662
 
2124
4663
  export class FileControl extends Control
2125
4664
  {
2126
- static classdoc = "A LivingApps upload field (type 'file')";
4665
+ [ul4.symbols.type]()
4666
+ {
4667
+ return filecontroltype;
4668
+ }
2127
4669
  };
2128
4670
 
2129
4671
  FileControl.prototype.type = "file";
2130
4672
  FileControl.prototype.fieldtype = FileField;
4673
+ FileControl.prototype._cssclass_root = "llft-element";
4674
+
4675
+
4676
+ class FileSignatureControlType extends FileControlType
4677
+ {
4678
+ instancecheck(obj)
4679
+ {
4680
+ return obj instanceof FileSignatureControl;
4681
+ }
4682
+ };
4683
+
4684
+ let filesignaturecontroltype = new FileSignatureControlType("la", "FileSignatureControl", "A LivingApps signature image field (type 'file/signature')");
2131
4685
 
2132
4686
 
2133
4687
  export class FileSignatureControl extends FileControl
2134
4688
  {
2135
- static classdoc = "A LivingApps signature image field (type 'file/signature')";
4689
+ [ul4.symbols.type]()
4690
+ {
4691
+ return filesignaturecontroltype;
4692
+ }
2136
4693
  };
2137
4694
 
2138
4695
  FileSignatureControl.prototype.subtype = "signature";
2139
4696
  FileSignatureControl.prototype.fieldtype = FileSignatureField;
2140
4697
 
2141
4698
 
4699
+ class ButtonControlType extends ControlType
4700
+ {
4701
+ instancecheck(obj)
4702
+ {
4703
+ return obj instanceof ButtonControl;
4704
+ }
4705
+ };
4706
+
4707
+ let buttoncontroltype = new ButtonControlType("la", "ButtonControl", "A submit button");
4708
+
4709
+
2142
4710
  export class ButtonControl extends Control
2143
4711
  {
4712
+ [ul4.symbols.type]()
4713
+ {
4714
+ return buttoncontroltype;
4715
+ }
2144
4716
  };
2145
4717
 
2146
4718
  ButtonControl.prototype.type = "button";
2147
4719
 
2148
4720
 
4721
+ class LookupItemType extends ul4.Type
4722
+ {
4723
+ instancecheck(obj)
4724
+ {
4725
+ return obj instanceof LookupItem;
4726
+ }
4727
+ };
4728
+
4729
+ let lookupitemtype = new LookupItemType("la", "LookupItem", "An option in a lookup control/field");
4730
+
4731
+
2149
4732
  export class LookupItem extends Base
2150
4733
  {
2151
- static classdoc = "An option in a lookup control/field";
4734
+ [ul4.symbols.type]()
4735
+ {
4736
+ return lookupitemtype;
4737
+ }
2152
4738
 
2153
4739
  get label()
2154
4740
  {
@@ -2190,71 +4776,201 @@ export class LookupItem extends Base
2190
4776
  return null;
2191
4777
  }
2192
4778
 
2193
- [ul4.symbols.repr]()
4779
+ [ul4.symbols.repr]()
4780
+ {
4781
+ let repr = "<LookupItem key=" + ul4._repr(this.key) + " label=" + ul4._repr(this.label);
4782
+ if (!this.visible)
4783
+ repr += "visible=False"
4784
+ return repr + ">";
4785
+ }
4786
+ };
4787
+
4788
+ LookupItem.prototype._ul4onattrs = ["control", "key", "_label"];
4789
+ LookupItem.prototype._ul4attrs = new Set(["id", "control", "key", "label"]);
4790
+
4791
+
4792
+ class ViewLookupItemType extends ul4.Type
4793
+ {
4794
+ instancecheck(obj)
4795
+ {
4796
+ return obj instanceof ViewLookupItem;
4797
+ }
4798
+ };
4799
+
4800
+ let viewlookupitemtype = new ViewLookupItemType("la", "ViewLookupItem", "View specific information about a lookup item");
4801
+
4802
+
4803
+ export class ViewLookupItem extends Base
4804
+ {
4805
+ [ul4.symbols.type]()
4806
+ {
4807
+ return viewlookupitemtype;
4808
+ }
4809
+
4810
+ [ul4.symbols.repr]()
4811
+ {
4812
+ let repr = "<ViewLookupItem key=" + ul4._repr(this.key) + " label=" + ul4._repr(this.label);
4813
+ if (!this.visible)
4814
+ repr += " visible=False"
4815
+ return repr + ">";
4816
+ }
4817
+ };
4818
+
4819
+ ViewLookupItem.prototype._ul4onattrs = ["key", "label", "visible"];
4820
+ ViewLookupItem.prototype._ul4attrs = new Set(["key", "label", "visible"]);
4821
+
4822
+
4823
+ class LayoutControlType extends ul4.Type
4824
+ {
4825
+ instancecheck(obj)
4826
+ {
4827
+ return obj instanceof LayoutControl;
4828
+ }
4829
+ };
4830
+
4831
+ let layoutcontroltype = new LayoutControlType("la", "LayoutControl", "A decoration in an input form");
4832
+
4833
+
4834
+ export class LayoutControl extends Base
4835
+ {
4836
+ [ul4.symbols.type]()
4837
+ {
4838
+ return layoutcontroltype;
4839
+ }
4840
+
4841
+ [ul4.symbols.repr]()
4842
+ {
4843
+ return "<" + this.constructor.name + " id=" + ul4._repr(this.id) + " identifier=" + ul4._repr(this.identifier) + ">";
4844
+ }
4845
+
4846
+ get globals()
4847
+ {
4848
+ return this.view.app.globals;
4849
+ }
4850
+
4851
+ get _sel_root()
4852
+ {
4853
+ return "#livingapps-form .llft-element.llft-id-" + this.identifier;
4854
+ }
4855
+
4856
+ get _dom_root()
4857
+ {
4858
+ return document.querySelector(this._sel_root);
4859
+ }
4860
+ };
4861
+
4862
+ LayoutControl.prototype._ul4onattrs = ["label", "identifier", "view", "top", "left", "width", "height"];
4863
+ LayoutControl.prototype._ul4attrs = new Set(["id", "label", "identifier", "view", "top", "left", "width", "height"]);
4864
+
4865
+
4866
+ class HTMLLayoutControlType extends LayoutControlType
4867
+ {
4868
+ instancecheck(obj)
4869
+ {
4870
+ return obj instanceof HTMLLayoutControl;
4871
+ }
4872
+ };
4873
+
4874
+ let htmllayoutcontroltype = new HTMLLayoutControlType("la", "HTMLLayoutControl", "HTML decoration in an input form");
4875
+
4876
+
4877
+ export class HTMLLayoutControl extends LayoutControl
4878
+ {
4879
+ [ul4.symbols.type]()
4880
+ {
4881
+ return htmllayoutcontroltype;
4882
+ }
4883
+
4884
+ get value()
4885
+ {
4886
+ return this._value;
4887
+ }
4888
+
4889
+ set value(value)
2194
4890
  {
2195
- let repr = "<LookupItem key=" + ul4._repr(this.key) + " label=" + ul4._repr(this.label);
2196
- if (!this.visible)
2197
- repr += "visible=False"
2198
- return repr + ">";
4891
+ this._value = value;
4892
+ if (this.globals._in_form())
4893
+ this._set_dom_value(this._value);
4894
+ }
4895
+
4896
+ _set_dom_value(value)
4897
+ {
4898
+ this._dom_root.innerHTML = value;
4899
+ }
4900
+
4901
+ [ul4.symbols.setattr](name, value)
4902
+ {
4903
+ if (name === "value")
4904
+ this.value = value;
4905
+ else
4906
+ return super[ul4.symbols.getattr](name);
2199
4907
  }
2200
4908
  };
2201
4909
 
2202
- LookupItem.prototype._ul4onattrs = ["control", "key", "_label"];
2203
- LookupItem.prototype._ul4attrs = new Set(["id", "control", "key", "label"]);
4910
+ HTMLLayoutControl.prototype._ul4onattrs = [...LayoutControl.prototype._ul4onattrs, "_value"];
4911
+ HTMLLayoutControl.prototype._ul4attrs = new Set([...LayoutControl.prototype._ul4attrs, "value"]);
2204
4912
 
2205
4913
 
2206
- export class ViewLookupItem extends Base
4914
+ class ImageLayoutControlType extends LayoutControlType
2207
4915
  {
2208
- static classdoc = "View specific information about a lookup item";
2209
-
2210
- [ul4.symbols.repr]()
4916
+ instancecheck(obj)
2211
4917
  {
2212
- let repr = "<ViewLookupItem key=" + ul4._repr(this.key) + " label=" + ul4._repr(this.label);
2213
- if (!this.visible)
2214
- repr += " visible=False"
2215
- return repr + ">";
4918
+ return obj instanceof ImageLayoutControl;
2216
4919
  }
2217
4920
  };
2218
4921
 
2219
- ViewLookupItem.prototype._ul4onattrs = ["key", "label", "visible"];
2220
- ViewLookupItem.prototype._ul4attrs = new Set(["key", "label", "visible"]);
4922
+ let imagelayoutcontroltype = new ImageLayoutControlType("la", "ImageLayoutControl", "An image decoration in an input form");
2221
4923
 
2222
4924
 
2223
- export class LayoutControl extends Base
4925
+ export class ImageLayoutControl extends LayoutControl
2224
4926
  {
2225
- static classdoc = "A decoration in an input form";
2226
-
2227
- [ul4.symbols.repr]()
4927
+ [ul4.symbols.type]()
2228
4928
  {
2229
- return "<" + this.constructor.name + " id=" + ul4._repr(this.id) + " identifier=" + ul4._repr(this.identifier) + ">";
4929
+ return imagelayoutcontroltype;
2230
4930
  }
2231
4931
  };
2232
4932
 
2233
- LayoutControl.prototype._ul4onattrs = ["label", "identifier", "view", "top", "left", "width", "height"];
2234
- LayoutControl.prototype._ul4attrs = new Set(["id", "label", "identifier", "view", "top", "left", "width", "height"]);
4933
+ ImageLayoutControl.prototype._ul4onattrs = [...LayoutControl.prototype._ul4onattrs, "original", "scaled"];
4934
+ ImageLayoutControl.prototype._ul4attrs = new Set([...LayoutControl.prototype._ul4attrs, "original", "scaled"]);
2235
4935
 
2236
4936
 
2237
- export class HTMLLayoutControl extends LayoutControl
4937
+ class ButtonLayoutControlType extends LayoutControlType
2238
4938
  {
2239
- static classdoc = "An HTML decoration in an input form";
4939
+ instancecheck(obj)
4940
+ {
4941
+ return obj instanceof ButtonLayoutControl;
4942
+ }
2240
4943
  };
2241
4944
 
2242
- HTMLLayoutControl.prototype._ul4onattrs = [...LayoutControl.prototype._ul4onattrs, "value"];
2243
- HTMLLayoutControl.prototype._ul4attrs = new Set([LayoutControl.prototype._ul4attrs, "value"]);
4945
+ let buttonlayoutcontroltype = new ButtonLayoutControlType("la", "ButtonLayoutControl", "A submit button in an input form");
2244
4946
 
2245
4947
 
2246
- export class ImageLayoutControl extends LayoutControl
4948
+ export class ButtonLayoutControl extends LayoutControl
4949
+ {
4950
+ [ul4.symbols.type]()
4951
+ {
4952
+ return buttonlayoutcontroltype;
4953
+ }
4954
+ };
4955
+
4956
+
4957
+ class ViewControlType extends ul4.Type
2247
4958
  {
2248
- static classdoc = "An image decoration in an input form";
4959
+ instancecheck(obj)
4960
+ {
4961
+ return obj instanceof ViewControl;
4962
+ }
2249
4963
  };
2250
4964
 
2251
- ImageLayoutControl.prototype._ul4onattrs = [...LayoutControl.prototype._ul4onattrs, "original", "scaled"];
2252
- ImageLayoutControl.prototype._ul4attrs = new Set([LayoutControl.prototype._ul4attrs, "original", "scaled"]);
4965
+ let viewcontroltype = new ViewControlType("la", "ViewControl", "Contains view specific information about a control");
2253
4966
 
2254
4967
 
2255
4968
  export class ViewControl extends Base
2256
4969
  {
2257
- static classdoc = "Contains view specific information aboutn a control";
4970
+ [ul4.symbols.type]()
4971
+ {
4972
+ return viewcontroltype;
4973
+ }
2258
4974
 
2259
4975
  get mode()
2260
4976
  {
@@ -2266,9 +4982,23 @@ ViewControl.prototype._ul4onattrs = ["view", "control", "top", "left", "width",
2266
4982
  ViewControl.prototype._ul4attrs = new Set(["id", "view", "control", "top", "left", "width", "height", "liveupdate", "default", "tabindex", "minlength", "maxlength", "required", "placeholder", "mode", "labelpos", "lookupnonekey", "lookupnonelabel", "label", "autoalign", "labelwidth", "lookupdata", "autoexpandable"]);
2267
4983
 
2268
4984
 
4985
+ class UserType extends ul4.Type
4986
+ {
4987
+ instancecheck(obj)
4988
+ {
4989
+ return obj instanceof User;
4990
+ }
4991
+ };
4992
+
4993
+ let usertype = new UserType("la", "User", "A LivingApps user/account");
4994
+
4995
+
2269
4996
  export class User extends Base
2270
4997
  {
2271
- static classdoc = "A LivingApps user/account";
4998
+ [ul4.symbols.type]()
4999
+ {
5000
+ return usertype;
5001
+ }
2272
5002
 
2273
5003
  [ul4.symbols.repr]()
2274
5004
  {
@@ -2280,25 +5010,60 @@ User.prototype._ul4onattrs = ["_id", "gender", "title", "firstname", "surname",
2280
5010
  User.prototype._ul4attrs = new Set(["id", "_id", "gender", "title", "firstname", "surname", "initials", "email", "streetname", "streetnumber", "zip", "city", "phone", "fax", "lang", "avatarsmall", "avatarlarge", "summary", "interests", "personalwebsite", "companywebsite", "company", "position", "department", "keyviews"]);
2281
5011
 
2282
5012
 
5013
+ class FileType extends ul4.Type
5014
+ {
5015
+ instancecheck(obj)
5016
+ {
5017
+ return obj instanceof File;
5018
+ }
5019
+ };
5020
+
5021
+ let filetype = new FileType("la", "File", "An uploaded file");
5022
+
5023
+
2283
5024
  export class File extends Base
2284
5025
  {
2285
- static classdoc = "An uploaded file";
5026
+ [ul4.symbols.type]()
5027
+ {
5028
+ return filetype;
5029
+ }
2286
5030
 
2287
5031
  [ul4.symbols.repr]()
2288
5032
  {
2289
5033
  return "<File id=" + ul4._repr(this.id) + " url=" + ul4._repr(this.url) + " filename=" + ul4._repr(this.filename) + ">";
2290
5034
  }
5035
+
5036
+ get url()
5037
+ {
5038
+ return "/gateway/files/" + this.id;
5039
+ }
5040
+
5041
+ get archive_url()
5042
+ {
5043
+ if (this.archive === null)
5044
+ return this.url;
5045
+ return this.archive.url + "/" + this.filename;
5046
+ }
2291
5047
  };
2292
5048
 
2293
- File.prototype._ul4onattrs = ["url", "filename", "mimetype", "width", "height", "internalid", "createdat", "size"];
2294
- File.prototype._ul4attrs = new Set(["id", "url", "filename", "mimetype", "width", "height", "size", "createdat"]);
5049
+ File.prototype._ul4onattrs = ["filename", "mimetype", "width", "height", "internalid", "createdat", "size", "duration", "geo", "storagefilename", "archive"];
5050
+ File.prototype._ul4attrs = new Set(["id", "url", "archive_url", "filename", "mimetype", "width", "height", "size", "duration", "geo", "archive", "createdat"]);
2295
5051
 
2296
5052
 
2297
- export class Geo extends Base
5053
+ class GeoType extends ul4.Type
2298
5054
  {
2299
- static classdoc = "Geographical coordinates and location information";
5055
+ instancecheck(obj)
5056
+ {
5057
+ return obj instanceof Geo;
5058
+ }
5059
+ };
5060
+
5061
+ let geotype = new GeoType("la", "Geo", "Geographical coordinates and location information");
5062
+
2300
5063
 
2301
- constructor(lat, long, info)
5064
+ export class Geo extends Base
5065
+ {
5066
+ constructor(lat, long, info=null)
2302
5067
  {
2303
5068
  super(null);
2304
5069
  this.lat = lat;
@@ -2306,6 +5071,11 @@ export class Geo extends Base
2306
5071
  this.info = info;
2307
5072
  }
2308
5073
 
5074
+ [ul4.symbols.type]()
5075
+ {
5076
+ return geotype;
5077
+ }
5078
+
2309
5079
  [ul4.symbols.repr]()
2310
5080
  {
2311
5081
  return "<Geo lat=" + ul4._repr(this.lat) + " long=" + ul4._repr(this.long) + " info=" + ul4._repr(this.info) + ">";
@@ -2316,8 +5086,24 @@ Geo.prototype._ul4onattrs = ["lat", "long", "info"];
2316
5086
  Geo.prototype._ul4attrs = new Set(["lat", "long", "info"]);
2317
5087
 
2318
5088
 
5089
+ class AttachmentType extends ul4.Type
5090
+ {
5091
+ instancecheck(obj)
5092
+ {
5093
+ return obj instanceof Attachment;
5094
+ }
5095
+ };
5096
+
5097
+ let attachmenttype = new AttachmentType("la", "Attachment", "An attachment of a record");
5098
+
5099
+
2319
5100
  export class Attachment extends Base
2320
5101
  {
5102
+ [ul4.symbols.type]()
5103
+ {
5104
+ return attachmenttype;
5105
+ }
5106
+
2321
5107
  [ul4.symbols.repr]()
2322
5108
  {
2323
5109
  return "<" + this.constructor.name + " id=" + ul4._repr(this.id) + " label=" + ul4._repr(this.label) + ">";
@@ -2328,10 +5114,23 @@ Attachment.prototype._ul4onattrs = ["record", "label", "active"];
2328
5114
  Attachment.prototype._ul4attrs = new Set(["id", "record", "label", "active"]);
2329
5115
 
2330
5116
 
2331
- export class NoteAttachment extends Attachment
5117
+ class NoteAttachmentType extends AttachmentType
2332
5118
  {
2333
- static classdoc = "A note attachment of a record";
5119
+ instancecheck(obj)
5120
+ {
5121
+ return obj instanceof NoteAttachment;
5122
+ }
5123
+ };
5124
+
5125
+ let noteattachmenttype = new NoteAttachmentType("la", "NoteAttachment", "A note attachment of a record");
2334
5126
 
5127
+
5128
+ export class NoteAttachment extends Attachment
5129
+ {
5130
+ [ul4.symbols.type]()
5131
+ {
5132
+ return noteattachmenttype;
5133
+ }
2335
5134
  };
2336
5135
 
2337
5136
  NoteAttachment.prototype.type = "noteattachment";
@@ -2339,10 +5138,23 @@ NoteAttachment.prototype._ul4onattrs = [...Attachment.prototype._ul4onattrs, "va
2339
5138
  NoteAttachment.prototype._ul4attrs = new Set([...Attachment.prototype._ul4onattrs, "value"]);
2340
5139
 
2341
5140
 
2342
- export class URLAttachment extends Attachment
5141
+ class URLAttachmentType extends AttachmentType
2343
5142
  {
2344
- static classdoc = "A URL attachment of a record";
5143
+ instancecheck(obj)
5144
+ {
5145
+ return obj instanceof URLAttachment;
5146
+ }
5147
+ };
5148
+
5149
+ let urlattachmenttype = new URLAttachmentType("la", "URLAttachment", "A URL attachment of a record");
2345
5150
 
5151
+
5152
+ export class URLAttachment extends Attachment
5153
+ {
5154
+ [ul4.symbols.type]()
5155
+ {
5156
+ return urlattachmenttype;
5157
+ }
2346
5158
  };
2347
5159
 
2348
5160
  URLAttachment.prototype.type = "urlattachment";
@@ -2350,10 +5162,23 @@ URLAttachment.prototype._ul4onattrs = [...Attachment.prototype._ul4onattrs, "val
2350
5162
  URLAttachment.prototype._ul4attrs = new Set([...Attachment.prototype._ul4onattrs, "value"]);
2351
5163
 
2352
5164
 
2353
- export class FileAttachment extends Attachment
5165
+ class FileAttachmentType extends AttachmentType
2354
5166
  {
2355
- static classdoc = "A file attachment of a record";
5167
+ instancecheck(obj)
5168
+ {
5169
+ return obj instanceof FileAttachment;
5170
+ }
5171
+ };
5172
+
5173
+ let fileattachmenttype = new FileAttachmentType("la", "FileAttachment", "A file attachment of a record");
2356
5174
 
5175
+
5176
+ export class FileAttachment extends Attachment
5177
+ {
5178
+ [ul4.symbols.type]()
5179
+ {
5180
+ return fileattachmenttype;
5181
+ }
2357
5182
  };
2358
5183
 
2359
5184
  FileAttachment.prototype.type = "fileattachment";
@@ -2361,10 +5186,23 @@ FileAttachment.prototype._ul4onattrs = [...Attachment.prototype._ul4onattrs, "va
2361
5186
  FileAttachment.prototype._ul4attrs = new Set([...Attachment.prototype._ul4onattrs, "value"]);
2362
5187
 
2363
5188
 
2364
- export class ImageAttachment extends Attachment
5189
+ class ImageAttachmentType extends AttachmentType
2365
5190
  {
2366
- static classdoc = "An image attachment of a record";
5191
+ instancecheck(obj)
5192
+ {
5193
+ return obj instanceof ImageAttachment;
5194
+ }
5195
+ };
5196
+
5197
+ let imageattachmenttype = new ImageAttachmentType("la", "ImageAttachment", "An image attachment of a record");
2367
5198
 
5199
+
5200
+ export class ImageAttachment extends Attachment
5201
+ {
5202
+ [ul4.symbols.type]()
5203
+ {
5204
+ return imageattachmenttype;
5205
+ }
2368
5206
  };
2369
5207
 
2370
5208
  ImageAttachment.prototype.type = "imageattachment";
@@ -2372,9 +5210,23 @@ ImageAttachment.prototype._ul4onattrs = [...Attachment.prototype._ul4onattrs, "o
2372
5210
  ImageAttachment.prototype._ul4attrs = new Set([...Attachment.prototype._ul4onattrs, "original", "thumb", "small", "medium", "large"]);
2373
5211
 
2374
5212
 
5213
+ class JSONAttachmentType extends AttachmentType
5214
+ {
5215
+ instancecheck(obj)
5216
+ {
5217
+ return obj instanceof JSONAttachment;
5218
+ }
5219
+ };
5220
+
5221
+ let jsonattachmenttype = new JSONAttachmentType("la", "JSONAttachment", "A JSON attachment of a record");
5222
+
5223
+
2375
5224
  export class JSONAttachment extends Attachment
2376
5225
  {
2377
- static classdoc = "A JSON attachment of a record";
5226
+ [ul4.symbols.type]()
5227
+ {
5228
+ return jsonattachmenttype;
5229
+ }
2378
5230
 
2379
5231
  _dumpUL4ONAttr(name)
2380
5232
  {
@@ -2398,9 +5250,23 @@ JSONAttachment.prototype._ul4onattrs = [...Attachment.prototype._ul4onattrs, "va
2398
5250
  JSONAttachment.prototype._ul4attrs = new Set([...Attachment.prototype._ul4onattrs, "value"]);
2399
5251
 
2400
5252
 
5253
+ class InstallationType extends ul4.Type
5254
+ {
5255
+ instancecheck(obj)
5256
+ {
5257
+ return obj instanceof Installation;
5258
+ }
5259
+ };
5260
+
5261
+ let installationtype = new InstallationType("la", "Installation", "The installation that created an app");
5262
+
5263
+
2401
5264
  export class Installation extends Base
2402
5265
  {
2403
- static classdoc = "The installation that created an app";
5266
+ [ul4.symbols.type]()
5267
+ {
5268
+ return installationtype;
5269
+ }
2404
5270
 
2405
5271
  [ul4.symbols.repr]()
2406
5272
  {
@@ -2412,9 +5278,23 @@ Installation.prototype._ul4onattrs = ["name"];
2412
5278
  Installation.prototype._ul4attrs = new Set(["id", "name"]);
2413
5279
 
2414
5280
 
5281
+ class CategoryType extends ul4.Type
5282
+ {
5283
+ instancecheck(obj)
5284
+ {
5285
+ return obj instanceof Category;
5286
+ }
5287
+ };
5288
+
5289
+ let categorytype = new CategoryType("la", "Category", "A navigation category");
5290
+
5291
+
2415
5292
  export class Category extends Base
2416
5293
  {
2417
- static classdoc = "A navigation category";
5294
+ [ul4.symbols.type]()
5295
+ {
5296
+ return categorytype;
5297
+ }
2418
5298
 
2419
5299
  [ul4.symbols.repr]()
2420
5300
  {
@@ -2433,9 +5313,23 @@ Category.prototype._ul4onattrs = ["identifier", "name", "order", "parent", "chil
2433
5313
  Category.prototype._ul4attrs = new Set(["id", "identifier", "name", "order", "parent", "children", "apps"]);
2434
5314
 
2435
5315
 
5316
+ class KeyViewType extends ul4.Type
5317
+ {
5318
+ instancecheck(obj)
5319
+ {
5320
+ return obj instanceof KeyView;
5321
+ }
5322
+ };
5323
+
5324
+ let keyviewtype = new KeyViewType("la", "KeyView", "Object granting access to a view template");
5325
+
5326
+
2436
5327
  export class KeyView extends Base
2437
5328
  {
2438
- static classdoc = "Object granting access to a view template";
5329
+ [ul4.symbols.type]()
5330
+ {
5331
+ return keyviewtype;
5332
+ }
2439
5333
 
2440
5334
  [ul4.symbols.repr]()
2441
5335
  {
@@ -2447,9 +5341,23 @@ KeyView.prototype._ul4onattrs = ["identifier", "name", "key", "user"];
2447
5341
  KeyView.prototype._ul4attrs = new Set(["id", "identifier", "name", "key", "user"]);
2448
5342
 
2449
5343
 
5344
+ class AppParameterType extends ul4.Type
5345
+ {
5346
+ instancecheck(obj)
5347
+ {
5348
+ return obj instanceof AppParameter;
5349
+ }
5350
+ };
5351
+
5352
+ let appparametertype = new AppParameterType("la", "AppParameter", "A parameter of a LivingApps application");
5353
+
5354
+
2450
5355
  export class AppParameter extends Base
2451
5356
  {
2452
- static classdoc = "A parameter of a LivingApps application";
5357
+ [ul4.symbols.type]()
5358
+ {
5359
+ return appparametertype;
5360
+ }
2453
5361
 
2454
5362
  [ul4.symbols.repr]()
2455
5363
  {
@@ -2461,12 +5369,175 @@ AppParameter.prototype._ul4onattrs = ["app", "identifier", "description", "value
2461
5369
  AppParameter.prototype._ul4attrs = new Set(["id", "app", "identifier", "description", "value"]);
2462
5370
 
2463
5371
 
5372
+ class FormType extends ul4.Type
5373
+ {
5374
+ instancecheck(obj)
5375
+ {
5376
+ return obj instanceof Form;
5377
+ }
5378
+ };
5379
+
5380
+ let formtype = new FormType("la", "Form", "The input form.");
5381
+
5382
+ export class Form extends ul4.Proto
5383
+ {
5384
+ constructor(globals, template)
5385
+ {
5386
+ super();
5387
+ this.globals = globals;
5388
+ this.template = template;
5389
+ this._geo_wired = false;
5390
+
5391
+ for (let field of globals.record.fields.values())
5392
+ this.wire_field(field);
5393
+ this.render_template(null);
5394
+ }
5395
+
5396
+ [ul4.symbols.type]()
5397
+ {
5398
+ return formtype;
5399
+ }
5400
+
5401
+ get _dom_button()
5402
+ {
5403
+ return document.querySelector(this._sel_form + " " + this._sel_button);
5404
+ }
5405
+
5406
+ get enabled()
5407
+ {
5408
+ return !this._dom_button.disabled;
5409
+ }
5410
+
5411
+ set enabled(value)
5412
+ {
5413
+ this._dom_button.disabled = !value;
5414
+ }
5415
+
5416
+ [ul4.symbols.getattr](key)
5417
+ {
5418
+ if (key === "enabled")
5419
+ return this.enabled;
5420
+ else
5421
+ throw new ul4.AttributeError(this, key);
5422
+ }
5423
+
5424
+ [ul4.symbols.setattr](key, value)
5425
+ {
5426
+ if (key === "enabled")
5427
+ this.enabled = ul4._bool(value);
5428
+ else
5429
+ throw new ul4.AttributeError(this, key);
5430
+ }
5431
+
5432
+ [ul4.symbols.repr]()
5433
+ {
5434
+ return "<" + this.constructor.name + " enabled=" + ul4._repr(this.enabled) + ">";
5435
+ }
5436
+
5437
+ toString()
5438
+ {
5439
+ return this[ul4.symbols.repr]();
5440
+ }
5441
+
5442
+ render_template(identifier)
5443
+ {
5444
+ let vars = {
5445
+ "record": this.globals.record,
5446
+ "fields": this.globals.record.fields,
5447
+ "identifier": identifier
5448
+ };
5449
+
5450
+ let globalVars = {
5451
+ "globals": this.globals,
5452
+ "form": this,
5453
+ "la": module
5454
+ };
5455
+
5456
+ let msg = "LivingApps update template: ";
5457
+ if (identifier === null)
5458
+ msg += "Initialization";
5459
+ else
5460
+ msg += "Value change in " + ul4._repr(identifier);
5461
+
5462
+ this.globals.group_logging(msg, () => {
5463
+ try
5464
+ {
5465
+ this.template.renders(vars, globalVars);
5466
+ }
5467
+ catch (exc)
5468
+ {
5469
+ if (console && console.error)
5470
+ {
5471
+ this.globals._start_log_message();
5472
+ if (console.group)
5473
+ console.group("UL4 stacktrace");
5474
+ ul4.report_exc(exc);
5475
+ if (console.groupEnd)
5476
+ console.groupEnd();
5477
+
5478
+ if (console.groupCollapsed)
5479
+ console.groupCollapsed("Javascript stacktrace");
5480
+ console.error(exc);
5481
+ if (console.groupEnd)
5482
+ console.groupEnd();
5483
+ }
5484
+ }
5485
+ });
5486
+ }
5487
+
5488
+ wire_geo()
5489
+ {
5490
+ if (this._geo_wired)
5491
+ return;
5492
+
5493
+ if (this.globals.app.active_view !== null && navigator.geolocation)
5494
+ {
5495
+ let use_geo = this.globals.app.active_view.use_geo;
5496
+ if (use_geo === "once" || use_geo === "watch")
5497
+ {
5498
+ navigator.geolocation.getCurrentPosition((position) => {
5499
+ this.globals.mode = this.globals.mode.substring(0, this.globals.mode.lastIndexOf("/") + 1) + "geo";
5500
+ this.globals.set_current_geo(position);
5501
+ this.render_template(null);
5502
+ });
5503
+ }
5504
+
5505
+ if (use_geo === "watch")
5506
+ {
5507
+ navigator.geolocation.watchPosition((position) => {
5508
+ this.globals.mode = this.globals.mode.substring(0, this.globals.mode.lastIndexOf("/") + 1) + "geo";
5509
+ this.globals.set_current_geo(position);
5510
+ this.render_template(null);
5511
+ });
5512
+ }
5513
+ }
5514
+ this._geo_wired = true;
5515
+ }
5516
+
5517
+ wire_field(field)
5518
+ {
5519
+ for (let dom_node of field._dom_controls)
5520
+ {
5521
+ dom_node.addEventListener(field._inputevent, (event) => {
5522
+ this.wire_geo();
5523
+ this.globals.mode = this.globals.mode.substring(0, this.globals.mode.lastIndexOf("/") + 1) + "input";
5524
+ this.render_template(field.control.identifier);
5525
+ });
5526
+ }
5527
+ }
5528
+ };
5529
+
5530
+ Form.prototype._ul4attrs = new Set(["enabled"]);
5531
+ Form.prototype._sel_form = "#livingapps-form form";
5532
+ Form.prototype._sel_button = "[type=submit]";
5533
+
5534
+
2464
5535
  let classes = [
2465
5536
  Globals,
2466
5537
  FlashMessage,
2467
5538
  App,
2468
5539
  View,
2469
- DataSourceData,
5540
+ DataSource,
2470
5541
  Record,
2471
5542
  BoolControl,
2472
5543
  IntControl,
@@ -2527,6 +5598,7 @@ let classes = [
2527
5598
  LayoutControl,
2528
5599
  HTMLLayoutControl,
2529
5600
  ImageLayoutControl,
5601
+ ButtonLayoutControl,
2530
5602
  ViewControl,
2531
5603
  User,
2532
5604
  File,
@@ -2546,3 +5618,62 @@ for (let constructor of classes)
2546
5618
  {
2547
5619
  ul4.register("de.livinglogic.livingapi." + constructor.name.toLowerCase(), constructor);
2548
5620
  }
5621
+
5622
+ export const module = new ul4.Module(
5623
+ "la",
5624
+ "LivingAPI types",
5625
+ {
5626
+ FlashMessage: FlashMessage,
5627
+ File: File,
5628
+ Geo: Geo,
5629
+ User: User,
5630
+ KeyView: KeyView,
5631
+ Globals: Globals,
5632
+ App: App,
5633
+ TextControl: TextControl,
5634
+ URLControl: URLControl,
5635
+ EmailControl: EmailControl,
5636
+ PasswordControl: PasswordControl,
5637
+ TelControl: TelControl,
5638
+ TextAreaControl: TextAreaControl,
5639
+ HTMLControl: HTMLControl,
5640
+ IntControl: IntControl,
5641
+ NumberControl: NumberControl,
5642
+ DateControl: DateControl,
5643
+ DatetimeMinuteControl: DatetimeMinuteControl,
5644
+ DatetimeSecondControl: DatetimeSecondControl,
5645
+ BoolControl: BoolControl,
5646
+ LookupSelectControl: LookupSelectControl,
5647
+ LookupRadioControl: LookupRadioControl,
5648
+ LookupChoiceControl: LookupChoiceControl,
5649
+ AppLookupSelectControl: AppLookupSelectControl,
5650
+ AppLookupRadioControl: AppLookupRadioControl,
5651
+ AppLookupChoiceControl: AppLookupChoiceControl,
5652
+ MultipleLookupSelectControl: MultipleLookupSelectControl,
5653
+ MultipleLookupCheckboxControl: MultipleLookupCheckboxControl,
5654
+ MultipleLookupChoiceControl: MultipleLookupChoiceControl,
5655
+ MultipleAppLookupSelectControl: MultipleAppLookupSelectControl,
5656
+ MultipleAppLookupCheckboxControl: MultipleAppLookupCheckboxControl,
5657
+ MultipleAppLookupChoiceControl: MultipleAppLookupChoiceControl,
5658
+ FileControl: FileControl,
5659
+ FileSignatureControl: FileSignatureControl,
5660
+ GeoControl: GeoControl,
5661
+ ViewControl: ViewControl,
5662
+ Record: Record,
5663
+ ImageAttachment: ImageAttachment,
5664
+ FileAttachment: FileAttachment,
5665
+ URLAttachment: URLAttachment,
5666
+ NoteAttachment: NoteAttachment,
5667
+ JSONAttachment: JSONAttachment,
5668
+ Installation: Installation,
5669
+ HTMLLayoutControl: HTMLLayoutControl,
5670
+ ImageLayoutControl: ImageLayoutControl,
5671
+ ButtonLayoutControl: ButtonLayoutControl,
5672
+ View: View,
5673
+ DataSource: DataSource,
5674
+ LookupItem: LookupItem,
5675
+ ViewLookupItem: ViewLookupItem,
5676
+ Category: Category,
5677
+ AppParameter: AppParameter,
5678
+ }
5679
+ );