x4js 1.4.41 → 1.4.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,10 +6,14 @@ X4 is a full typescript framework to develop Web or Desktop applications.
6
6
  Included more than 50 controls like grids, charts, etc. Everything needed to push the limits of your creativity.
7
7
  If these components are not enough, you can create your in few lines.
8
8
 
9
+ ## Home page
10
+ see [home](https://x4js.org)
11
+
12
+
9
13
  ## Documentation
10
14
  see [documentation](https://x4js.org/doc/)
15
+
11
16
  ## API
12
17
  see [API](https://x4js.org/api/)
13
18
 
14
19
 
15
- [web site](https://x4js.org)
package/lib/action.d.ts CHANGED
@@ -26,10 +26,10 @@
26
26
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27
27
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
  **/
29
- import { BasicEvent } from './x4events';
29
+ import { BasicEvent, EvChange } from './x4events';
30
30
  import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component';
31
31
  import { IconID } from "./icon";
32
- import { EvChange, EventHandler } from 'x4js';
32
+ import { EventHandler } from './component';
33
33
  export interface EvAction extends BasicEvent {
34
34
  }
35
35
  export declare function EvAction(source: Action): EvAction;
package/lib/action.js CHANGED
@@ -31,7 +31,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
31
31
  exports.Action = exports.EvAction = void 0;
32
32
  const x4events_1 = require("./x4events");
33
33
  const base_component_1 = require("./base_component");
34
- const x4js_1 = require("x4js");
35
34
  function EvAction(source) {
36
35
  return (0, x4events_1.BasicEvent)({ source });
37
36
  }
@@ -46,11 +45,11 @@ class Action extends base_component_1.BaseComponent {
46
45
  }
47
46
  set text(t) {
48
47
  this.m_props.text = t;
49
- this.emit("change", (0, x4js_1.EvChange)(this));
48
+ this.emit("change", (0, x4events_1.EvChange)(this));
50
49
  }
51
50
  set icon(i) {
52
51
  this.m_props.icon = i;
53
- this.emit("change", (0, x4js_1.EvChange)(this));
52
+ this.emit("change", (0, x4events_1.EvChange)(this));
54
53
  }
55
54
  fire() {
56
55
  this.emit("run", EvAction(this));
@@ -33,7 +33,6 @@ const x4dom_1 = require("./x4dom");
33
33
  const base_component_1 = require("./base_component");
34
34
  const component_1 = require("./component");
35
35
  const settings_1 = require("./settings");
36
- const x4js_1 = require("x4js");
37
36
  const _x4_touch_time = Symbol();
38
37
  /**
39
38
  * Represents an x4 application, which is typically a single page app.
@@ -128,7 +127,7 @@ class Application extends base_component_1.BaseComponent {
128
127
  */
129
128
  setMainView(root, clearBefore) {
130
129
  const ddom = this.m_props.renderTo ?? x4dom_1.x4document.body;
131
- const dest = (0, x4js_1.flyWrap)(ddom);
130
+ const dest = (0, component_1.flyWrap)(ddom);
132
131
  if (!this.m_props.renderTo) {
133
132
  dest.setStyleValue('position', 'absolute');
134
133
  }
package/lib/cardview.js CHANGED
@@ -99,6 +99,9 @@ class CardView extends component_1.Component {
99
99
  if (!page.dom) {
100
100
  this._preparePage(page);
101
101
  }
102
+ if (this.m_cpage.selector) {
103
+ this.m_cpage.selector.addClass('@active');
104
+ }
102
105
  }
103
106
  this.emit('change', (0, x4events_1.EvChange)(this.m_cpage.name));
104
107
  }
package/lib/gridview.d.ts CHANGED
@@ -120,6 +120,10 @@ export declare class GridView extends VLayout<GridViewProps, GridViewEventMap> {
120
120
  /** @ignore */
121
121
  render(): void;
122
122
  private _on_col_resize;
123
+ /**
124
+ *
125
+ */
126
+ sortCol(name: string, asc?: boolean): void;
123
127
  /**
124
128
  *
125
129
  */
package/lib/gridview.js CHANGED
@@ -69,17 +69,24 @@ class ColHeader extends component_1.Component {
69
69
  get sorted() {
70
70
  return this.m_sorted;
71
71
  }
72
- set sorted(v) {
72
+ //set sorted( v ) {
73
+ // this.m_sorted = v;
74
+ // this.m_sens = 'dn';
75
+ // this.itemWithRef<Icon>( 'sorter' ).show( v );
76
+ //}
77
+ sort(v, sens) {
73
78
  this.m_sorted = v;
74
- this.m_sens = 'dn';
75
- this.itemWithRef('sorter').show(v);
79
+ this.m_sens = sens;
80
+ const ic = this.itemWithRef('sorter');
81
+ ic.icon = this.m_sens == 'up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
82
+ ic.show(v);
76
83
  }
77
84
  get sens() {
78
85
  return this.m_sens;
79
86
  }
80
87
  toggleSens() {
81
88
  this.m_sens = this.m_sens == 'up' ? 'dn' : 'up';
82
- this.itemWithRef('sorter').icon = this.m_sens == 'dn' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
89
+ this.itemWithRef('sorter').icon = this.m_sens == 'up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
83
90
  }
84
91
  }
85
92
  /**
@@ -426,13 +433,24 @@ class GridView extends layout_1.VLayout {
426
433
  /**
427
434
  *
428
435
  */
429
- _sortCol(col) {
436
+ sortCol(name, asc = true) {
437
+ const col = this.m_columns.find(c => c.id == name);
438
+ if (col === undefined) {
439
+ console.assert(false, "unknown field " + name + " in grid.sortCol");
440
+ return;
441
+ }
442
+ this._sortCol(col, asc ? "dn" : "up");
443
+ }
444
+ /**
445
+ *
446
+ */
447
+ _sortCol(col, sens = "up") {
430
448
  if (col.sortable === false) {
431
449
  return;
432
450
  }
433
451
  this.m_columns.forEach((c) => {
434
452
  if (c !== col) {
435
- c.$hdr.sorted = false;
453
+ c.$hdr.sort(false, "dn");
436
454
  }
437
455
  });
438
456
  const $hdr = col.$hdr;
@@ -440,7 +458,7 @@ class GridView extends layout_1.VLayout {
440
458
  $hdr.toggleSens();
441
459
  }
442
460
  else {
443
- $hdr.sorted = true;
461
+ $hdr.sort(true, sens);
444
462
  }
445
463
  if (this.m_dataview) {
446
464
  this.m_dataview.sort([
@@ -852,15 +870,23 @@ class GridView extends layout_1.VLayout {
852
870
  let cid = c.getData('col');
853
871
  if (cid) {
854
872
  let col = this.m_columns[cid];
855
- let fmt = col.formatter;
856
- let text;
857
- if (fmt && fmt instanceof Function) {
858
- text = fmt(rec[col.id], rec);
859
- }
860
- else {
861
- text = rec[col.id];
873
+ let value = rec[col.id];
874
+ if (value !== undefined) {
875
+ if ((0, tools_1.isFunction)(value)) { // FooterRenderer
876
+ value(c);
877
+ }
878
+ else {
879
+ let text;
880
+ const fmt = col.formatter;
881
+ if (fmt && fmt instanceof Function) {
882
+ text = fmt(value, rec);
883
+ }
884
+ else {
885
+ text = value;
886
+ }
887
+ c.setContent(text, false);
888
+ }
862
889
  }
863
- c.setContent(text, false);
864
890
  }
865
891
  });
866
892
  }
package/lib/tools.d.ts CHANGED
@@ -384,4 +384,11 @@ interface PasswordRule {
384
384
  min: number;
385
385
  }
386
386
  export declare function generatePassword(length: number, rules?: PasswordRule[]): string;
387
+ /**
388
+ * taken from live-server
389
+ * https://github.com/tapio/live-server
390
+ * @param host
391
+ * @param port
392
+ */
393
+ export declare function installHMR(host?: string, port?: string, reloadCallback?: Function): void;
387
394
  export {};
package/lib/tools.js CHANGED
@@ -28,7 +28,7 @@
28
28
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
29
  **/
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.generatePassword = exports.classNames = exports.mix = exports.crc32 = exports.Clipboard = exports.isHtmlString = exports.html = exports.HtmlString = exports.clamp = exports.getMousePos = exports.NetworkError = exports.markdownToHtml = exports.asap = exports.deferCall = exports.waitFontLoading = exports.isNumber = exports.pad = exports.isLiteralObject = exports.isFunction = exports.isArray = exports.isString = exports.downloadData = exports.calcAge = exports.formatIntlDate = exports.parseIntlDate = exports.date_calc_weeknum = exports.date_clone = exports.date_hash = exports.date_sql_utc = exports.date_to_sql = exports.date_diff = exports.date_format = exports._date_set_locale = exports.removeHtmlTags = exports.escapeHtml = exports.sprintf = exports.Rect = exports.Size = exports.Point = exports.camelCase = exports.pascalCase = exports.parseIntlFloat = exports.roundTo = exports.isTouchDevice = void 0;
31
+ exports.installHMR = exports.generatePassword = exports.classNames = exports.mix = exports.crc32 = exports.Clipboard = exports.isHtmlString = exports.html = exports.HtmlString = exports.clamp = exports.getMousePos = exports.NetworkError = exports.markdownToHtml = exports.asap = exports.deferCall = exports.waitFontLoading = exports.isNumber = exports.pad = exports.isLiteralObject = exports.isFunction = exports.isArray = exports.isString = exports.downloadData = exports.calcAge = exports.formatIntlDate = exports.parseIntlDate = exports.date_calc_weeknum = exports.date_clone = exports.date_hash = exports.date_sql_utc = exports.date_to_sql = exports.date_diff = exports.date_format = exports._date_set_locale = exports.removeHtmlTags = exports.escapeHtml = exports.sprintf = exports.Rect = exports.Size = exports.Point = exports.camelCase = exports.pascalCase = exports.parseIntlFloat = exports.roundTo = exports.isTouchDevice = void 0;
32
32
  const x4dom_1 = require("./x4dom");
33
33
  const i18n_1 = require("./i18n"); // you MUST create a file named translation.js
34
34
  // :: ENVIRONMENT ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@@ -1153,3 +1153,51 @@ function shuffle(str, maxlength) {
1153
1153
  }
1154
1154
  return shuffled;
1155
1155
  }
1156
+ /**
1157
+ * taken from live-server
1158
+ * https://github.com/tapio/live-server
1159
+ * @param host
1160
+ * @param port
1161
+ */
1162
+ function installHMR(host = "127.0.0.1", port = "9876", reloadCallback) {
1163
+ let tm;
1164
+ function refreshCSS() {
1165
+ document.body.style.visibility = "hidden";
1166
+ let sheets = [].slice.call(document.getElementsByTagName("link"));
1167
+ let head = document.getElementsByTagName("head")[0];
1168
+ for (let i = 0; i < sheets.length; ++i) {
1169
+ let elem = sheets[i];
1170
+ head.removeChild(elem);
1171
+ let rel = elem.rel;
1172
+ if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
1173
+ let url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
1174
+ elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
1175
+ }
1176
+ head.appendChild(elem);
1177
+ }
1178
+ if (tm) {
1179
+ clearTimeout(tm);
1180
+ }
1181
+ tm = setTimeout(() => {
1182
+ document.body.style.visibility = "unset";
1183
+ }, 50);
1184
+ }
1185
+ const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
1186
+ const address = `${protocol}${host}:${port}/ws`;
1187
+ const socket = new WebSocket(address);
1188
+ socket.onmessage = function (msg) {
1189
+ if (msg.data == 'reload') {
1190
+ if (reloadCallback) {
1191
+ reloadCallback();
1192
+ }
1193
+ else {
1194
+ window.location.reload();
1195
+ }
1196
+ }
1197
+ else if (msg.data == 'refreshcss') {
1198
+ refreshCSS();
1199
+ }
1200
+ };
1201
+ console.log('Live reload enabled.');
1202
+ }
1203
+ exports.installHMR = installHMR;
package/lib/x4.css CHANGED
@@ -61,7 +61,7 @@
61
61
  --x4-icon-angle-down: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" fill="currentColor"><path d="M192 384c-8.188 0-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L192 306.8l137.4-137.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-160 160C208.4 380.9 200.2 384 192 384z"/></svg>';
62
62
  --x4-icon-calendar-days: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M160 32V64H288V32C288 14.33 302.3 0 320 0C337.7 0 352 14.33 352 32V64H400C426.5 64 448 85.49 448 112V160H0V112C0 85.49 21.49 64 48 64H96V32C96 14.33 110.3 0 128 0C145.7 0 160 14.33 160 32zM0 192H448V464C448 490.5 426.5 512 400 512H48C21.49 512 0 490.5 0 464V192zM64 304C64 312.8 71.16 320 80 320H112C120.8 320 128 312.8 128 304V272C128 263.2 120.8 256 112 256H80C71.16 256 64 263.2 64 272V304zM192 304C192 312.8 199.2 320 208 320H240C248.8 320 256 312.8 256 304V272C256 263.2 248.8 256 240 256H208C199.2 256 192 263.2 192 272V304zM336 256C327.2 256 320 263.2 320 272V304C320 312.8 327.2 320 336 320H368C376.8 320 384 312.8 384 304V272C384 263.2 376.8 256 368 256H336zM64 432C64 440.8 71.16 448 80 448H112C120.8 448 128 440.8 128 432V400C128 391.2 120.8 384 112 384H80C71.16 384 64 391.2 64 400V432zM208 384C199.2 384 192 391.2 192 400V432C192 440.8 199.2 448 208 448H240C248.8 448 256 440.8 256 432V400C256 391.2 248.8 384 240 384H208zM320 432C320 440.8 327.2 448 336 448H368C376.8 448 384 440.8 384 432V400C384 391.2 376.8 384 368 384H336C327.2 384 320 391.2 320 400V432z"/></svg>';
63
63
  --x4-icon-tip: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464zM296 336h-16V248C280 234.8 269.3 224 256 224H224C210.8 224 200 234.8 200 248S210.8 272 224 272h8v64h-16C202.8 336 192 346.8 192 360S202.8 384 216 384h80c13.25 0 24-10.75 24-24S309.3 336 296 336zM256 192c17.67 0 32-14.33 32-32c0-17.67-14.33-32-32-32S224 142.3 224 160C224 177.7 238.3 192 256 192z"/></svg>';
64
- --x4-check: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M440.1 103C450.3 112.4 450.3 127.6 440.1 136.1L176.1 400.1C167.6 410.3 152.4 410.3 143 400.1L7.029 264.1C-2.343 255.6-2.343 240.4 7.029 231C16.4 221.7 31.6 221.7 40.97 231L160 350.1L407 103C416.4 93.66 431.6 93.66 440.1 103V103z"/></svg>';
64
+ --x4-icon-check: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M440.1 103C450.3 112.4 450.3 127.6 440.1 136.1L176.1 400.1C167.6 410.3 152.4 410.3 143 400.1L7.029 264.1C-2.343 255.6-2.343 240.4 7.029 231C16.4 221.7 31.6 221.7 40.97 231L160 350.1L407 103C416.4 93.66 431.6 93.66 440.1 103V103z"/></svg>';
65
65
  }
66
66
  /* source: https://tailwindcss.com/docs/customizing-colors/#default-color-palette */
67
67
  :root {
@@ -1115,17 +1115,17 @@ textarea::selection {
1115
1115
  .x-spreadsheet .x-header .x-cell,
1116
1116
  .x-grid-view .x-header .x-cell {
1117
1117
  border-right: 1px solid rgba(0, 0, 0, 0.1);
1118
- height: unset;
1118
+ height: 100%;
1119
+ display: flex;
1120
+ align-items: center;
1119
1121
  }
1120
1122
  .x-spreadsheet .x-footer .x-cell span,
1121
1123
  .x-grid-view .x-footer .x-cell span,
1122
1124
  .x-spreadsheet .x-header .x-cell span,
1123
1125
  .x-grid-view .x-header .x-cell span {
1124
1126
  min-width: 0;
1125
- text-transform: uppercase;
1126
1127
  text-overflow: ellipsis;
1127
1128
  overflow: hidden;
1128
- font-weight: bold;
1129
1129
  }
1130
1130
  .x-spreadsheet .x-footer .x-cell.sort,
1131
1131
  .x-grid-view .x-footer .x-cell.sort,
@@ -1134,14 +1134,11 @@ textarea::selection {
1134
1134
  height: 0.7rem;
1135
1135
  opacity: 0.7;
1136
1136
  }
1137
- .x-spreadsheet .x-header .x-cell,
1138
- .x-grid-view .x-header .x-cell {
1139
- display: flex;
1140
- align-items: center;
1141
- }
1142
1137
  .x-spreadsheet .x-header .x-cell span,
1143
1138
  .x-grid-view .x-header .x-cell span {
1144
1139
  width: unset;
1140
+ text-transform: uppercase;
1141
+ font-weight: bold;
1145
1142
  }
1146
1143
  .x-spreadsheet .x-header .x-cell .sort,
1147
1144
  .x-grid-view .x-header .x-cell .sort {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x4js",
3
- "version": "1.4.41",
3
+ "version": "1.4.44",
4
4
  "description": "X4js core files",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
package/src/action.ts CHANGED
@@ -27,10 +27,10 @@
27
27
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
  **/
29
29
 
30
- import { BasicEvent } from './x4events'
30
+ import { BasicEvent, EvChange } from './x4events'
31
31
  import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component'
32
32
  import { IconID } from "./icon"
33
- import { EvChange, EventHandler } from 'x4js';
33
+ import { EventHandler } from './component';
34
34
 
35
35
  //TODO: implement all
36
36
 
@@ -30,11 +30,9 @@
30
30
  import { x4document } from './x4dom'
31
31
  import { EvMessage } from './x4events'
32
32
  import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component'
33
- import { Component } from './component'
33
+ import { Component, flyWrap } from './component'
34
34
  import { Settings } from './settings'
35
- import { deferCall } from './tools'
36
35
  import { _tr } from './i18n'
37
- import { flyWrap } from 'x4js'
38
36
 
39
37
  const _x4_touch_time = Symbol( );
40
38
 
package/src/cardview.ts CHANGED
@@ -137,13 +137,16 @@ export class CardView<P extends CardViewProps = CardViewProps, E extends CardVie
137
137
  }
138
138
 
139
139
  let page = this.m_cpage.page as Component;
140
-
141
140
  page.addClass('@active');
142
141
  page.removeClass('@hidden');
143
142
 
144
143
  if (!page.dom) {
145
144
  this._preparePage(page);
146
145
  }
146
+
147
+ if (this.m_cpage.selector) {
148
+ this.m_cpage.selector.addClass('@active');
149
+ }
147
150
  }
148
151
 
149
152
  this.emit('change', EvChange(this.m_cpage.name));
package/src/component.ts CHANGED
@@ -33,7 +33,7 @@
33
33
  * create Container class
34
34
  */
35
35
 
36
- import { pascalCase, Rect, isString, isArray, Size, Point, isNumber, asap, HtmlString, isHtmlString, Constructor, getMousePos } from './tools';
36
+ import { pascalCase, Rect, isString, isArray, Size, isNumber, asap, HtmlString, isHtmlString, Constructor, getMousePos } from './tools';
37
37
  import { x4document } from './x4dom';
38
38
 
39
39
  import { Stylesheet, ComputedStyle } from './styles';
@@ -41,7 +41,6 @@ import { _tr } from './i18n';
41
41
  import { BasicEvent, EventCallback } from './x4events';
42
42
  import { BaseComponent, BaseComponentProps, BaseComponentEventMap } from './base_component';
43
43
  import { IDOMEvents, X4ElementEventMap } from './dom_events';
44
- import { IconID } from 'x4js';
45
44
 
46
45
  export { HtmlString, isHtmlString, html } from './tools'
47
46
 
package/src/gridview.ts CHANGED
@@ -41,7 +41,7 @@ import { Component, ContainerEventMap, EvSize, EvDblClick, CProps, flyWrap, html
41
41
  import { Label } from './label'
42
42
  import { _tr } from './i18n'
43
43
  import * as Formatters from './formatters'
44
- import { downloadData } from './tools'
44
+ import { downloadData, isFunction } from './tools'
45
45
  import { DataView, DataStore, Record } from './datastore'
46
46
 
47
47
  import { EvContextMenu, EvSelectionChange, BasicEvent, EventDisposer } from "./x4events";
@@ -134,10 +134,19 @@ class ColHeader extends Component {
134
134
  return this.m_sorted;
135
135
  }
136
136
 
137
- set sorted( v ) {
137
+ //set sorted( v ) {
138
+ // this.m_sorted = v;
139
+ // this.m_sens = 'dn';
140
+ // this.itemWithRef<Icon>( 'sorter' ).show( v );
141
+ //}
142
+
143
+ sort( v: boolean, sens: "up" | "dn" ) {
138
144
  this.m_sorted = v;
139
- this.m_sens = 'dn';
140
- this.itemWithRef<Icon>( 'sorter' ).show( v );
145
+ this.m_sens = sens;
146
+
147
+ const ic = this.itemWithRef<Icon>('sorter');
148
+ ic.icon = this.m_sens == 'up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
149
+ ic.show(v);
141
150
  }
142
151
 
143
152
  get sens( ) {
@@ -146,7 +155,7 @@ class ColHeader extends Component {
146
155
 
147
156
  toggleSens( ) {
148
157
  this.m_sens = this.m_sens=='up' ? 'dn' : 'up';
149
- this.itemWithRef<Icon>( 'sorter' ).icon = this.m_sens=='dn' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
158
+ this.itemWithRef<Icon>( 'sorter' ).icon = this.m_sens=='up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
150
159
  }
151
160
  }
152
161
 
@@ -588,7 +597,21 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
588
597
  *
589
598
  */
590
599
 
591
- private _sortCol(col: GridColumn ) {
600
+ sortCol( name: string, asc = true ) {
601
+ const col = this.m_columns.find(c => c.id==name );
602
+ if( col===undefined ) {
603
+ console.assert( false, "unknown field "+name+" in grid.sortCol" );
604
+ return;
605
+ }
606
+
607
+ this._sortCol( col, asc ? "dn" : "up" );
608
+ }
609
+
610
+ /**
611
+ *
612
+ */
613
+
614
+ private _sortCol(col: GridColumn, sens: "up" | "dn" = "up" ) {
592
615
 
593
616
  if (col.sortable === false) {
594
617
  return;
@@ -596,7 +619,7 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
596
619
 
597
620
  this.m_columns.forEach((c) => {
598
621
  if (c !== col) {
599
- (c as GridColumnInternal).$hdr.sorted = false;
622
+ (c as GridColumnInternal).$hdr.sort( false, "dn" );
600
623
  }
601
624
  });
602
625
 
@@ -606,7 +629,7 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
606
629
  $hdr.toggleSens( );
607
630
  }
608
631
  else {
609
- $hdr.sorted = true;
632
+ $hdr.sort( true, sens );
610
633
  }
611
634
 
612
635
  if (this.m_dataview) {
@@ -1137,17 +1160,24 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
1137
1160
  if( cid ) {
1138
1161
  let col = this.m_columns[cid];
1139
1162
 
1140
- let fmt = col.formatter;
1141
-
1142
- let text;
1143
- if (fmt && fmt instanceof Function) {
1144
- text = fmt(rec[col.id], rec);
1145
- }
1146
- else {
1147
- text = rec[col.id];
1148
- }
1163
+ let value = rec[col.id];
1164
+ if( value!==undefined ) {
1165
+ if( isFunction(value) ) { // FooterRenderer
1166
+ value( c );
1167
+ }
1168
+ else {
1169
+ let text;
1170
+ const fmt = col.formatter;
1171
+ if (fmt && fmt instanceof Function) {
1172
+ text = fmt(value, rec);
1173
+ }
1174
+ else {
1175
+ text = value;
1176
+ }
1149
1177
 
1150
- c.setContent( text, false );
1178
+ c.setContent( text, false );
1179
+ }
1180
+ }
1151
1181
  }
1152
1182
  });
1153
1183
  }
package/src/tools.ts CHANGED
@@ -1406,3 +1406,63 @@ function shuffle(str: string, maxlength?: number) {
1406
1406
 
1407
1407
  return shuffled;
1408
1408
  }
1409
+
1410
+
1411
+
1412
+ /**
1413
+ * taken from live-server
1414
+ * https://github.com/tapio/live-server
1415
+ * @param host
1416
+ * @param port
1417
+ */
1418
+
1419
+ export function installHMR(host = "127.0.0.1", port = "9876", reloadCallback?: Function ) {
1420
+
1421
+ let tm;
1422
+
1423
+ function refreshCSS() {
1424
+
1425
+ document.body.style.visibility = "hidden";
1426
+
1427
+ let sheets = [].slice.call(document.getElementsByTagName("link"));
1428
+ let head = document.getElementsByTagName("head")[0];
1429
+
1430
+ for (let i = 0; i < sheets.length; ++i) {
1431
+ let elem = sheets[i];
1432
+ head.removeChild(elem);
1433
+
1434
+ let rel = elem.rel;
1435
+ if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
1436
+ let url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
1437
+ elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
1438
+ }
1439
+
1440
+ head.appendChild(elem);
1441
+ }
1442
+
1443
+ if( tm ) { clearTimeout(tm); }
1444
+ tm = setTimeout( () => {
1445
+ document.body.style.visibility = "unset";
1446
+ }, 50 );
1447
+ }
1448
+
1449
+ const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
1450
+ const address = `${protocol}${host}:${port}/ws`;
1451
+ const socket = new WebSocket(address);
1452
+
1453
+ socket.onmessage = function (msg) {
1454
+ if (msg.data == 'reload') {
1455
+ if( reloadCallback ) {
1456
+ reloadCallback( );
1457
+ }
1458
+ else {
1459
+ window.location.reload();
1460
+ }
1461
+ }
1462
+ else if (msg.data == 'refreshcss') {
1463
+ refreshCSS();
1464
+ }
1465
+ };
1466
+
1467
+ console.log('Live reload enabled.');
1468
+ }
package/src/x4.less CHANGED
@@ -75,7 +75,7 @@
75
75
  --x4-icon-angle-down: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" fill="currentColor"><path d="M192 384c-8.188 0-16.38-3.125-22.62-9.375l-160-160c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L192 306.8l137.4-137.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-160 160C208.4 380.9 200.2 384 192 384z"/></svg>';
76
76
  --x4-icon-calendar-days: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M160 32V64H288V32C288 14.33 302.3 0 320 0C337.7 0 352 14.33 352 32V64H400C426.5 64 448 85.49 448 112V160H0V112C0 85.49 21.49 64 48 64H96V32C96 14.33 110.3 0 128 0C145.7 0 160 14.33 160 32zM0 192H448V464C448 490.5 426.5 512 400 512H48C21.49 512 0 490.5 0 464V192zM64 304C64 312.8 71.16 320 80 320H112C120.8 320 128 312.8 128 304V272C128 263.2 120.8 256 112 256H80C71.16 256 64 263.2 64 272V304zM192 304C192 312.8 199.2 320 208 320H240C248.8 320 256 312.8 256 304V272C256 263.2 248.8 256 240 256H208C199.2 256 192 263.2 192 272V304zM336 256C327.2 256 320 263.2 320 272V304C320 312.8 327.2 320 336 320H368C376.8 320 384 312.8 384 304V272C384 263.2 376.8 256 368 256H336zM64 432C64 440.8 71.16 448 80 448H112C120.8 448 128 440.8 128 432V400C128 391.2 120.8 384 112 384H80C71.16 384 64 391.2 64 400V432zM208 384C199.2 384 192 391.2 192 400V432C192 440.8 199.2 448 208 448H240C248.8 448 256 440.8 256 432V400C256 391.2 248.8 384 240 384H208zM320 432C320 440.8 327.2 448 336 448H368C376.8 448 384 440.8 384 432V400C384 391.2 376.8 384 368 384H336C327.2 384 320 391.2 320 400V432z"/></svg>';
77
77
  --x4-icon-tip: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor"><path d="M256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464zM296 336h-16V248C280 234.8 269.3 224 256 224H224C210.8 224 200 234.8 200 248S210.8 272 224 272h8v64h-16C202.8 336 192 346.8 192 360S202.8 384 216 384h80c13.25 0 24-10.75 24-24S309.3 336 296 336zM256 192c17.67 0 32-14.33 32-32c0-17.67-14.33-32-32-32S224 142.3 224 160C224 177.7 238.3 192 256 192z"/></svg>';
78
- --x4-check: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M440.1 103C450.3 112.4 450.3 127.6 440.1 136.1L176.1 400.1C167.6 410.3 152.4 410.3 143 400.1L7.029 264.1C-2.343 255.6-2.343 240.4 7.029 231C16.4 221.7 31.6 221.7 40.97 231L160 350.1L407 103C416.4 93.66 431.6 93.66 440.1 103V103z"/></svg>';
78
+ --x4-icon-check: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" fill="currentColor"><path d="M440.1 103C450.3 112.4 450.3 127.6 440.1 136.1L176.1 400.1C167.6 410.3 152.4 410.3 143 400.1L7.029 264.1C-2.343 255.6-2.343 240.4 7.029 231C16.4 221.7 31.6 221.7 40.97 231L160 350.1L407 103C416.4 93.66 431.6 93.66 440.1 103V103z"/></svg>';
79
79
  }
80
80
 
81
81
  @BLACK10: rgba(0,0,0,0.1);
@@ -1366,14 +1366,14 @@ textarea {
1366
1366
 
1367
1367
  .x-cell {
1368
1368
  border-right: 1px solid rgba(0,0,0,0.1);
1369
- height: unset;
1369
+ height: 100%;
1370
+ display: flex;
1371
+ align-items: center;
1370
1372
 
1371
1373
  span {
1372
1374
  min-width: 0;
1373
- text-transform: uppercase;
1374
1375
  text-overflow: ellipsis;
1375
1376
  overflow: hidden;
1376
- font-weight: bold;
1377
1377
  }
1378
1378
 
1379
1379
  &.sort {
@@ -1385,10 +1385,10 @@ textarea {
1385
1385
 
1386
1386
  .x-header {
1387
1387
  .x-cell {
1388
- display: flex;
1389
- align-items: center;
1390
1388
  span {
1391
1389
  width: unset;
1390
+ text-transform: uppercase;
1391
+ font-weight: bold;
1392
1392
  }
1393
1393
 
1394
1394
  .sort {