x4js 1.4.24 → 1.4.28
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/lib/application.js +5 -1
- package/lib/dialog.js +30 -17
- package/lib/fileupload.d.ts +2 -2
- package/lib/fileupload.js +5 -5
- package/lib/gridview.js +11 -9
- package/lib/icon.js +6 -8
- package/lib/listview.d.ts +2 -2
- package/lib/menu.js +3 -3
- package/lib/popup.js +4 -1
- package/lib/spreadsheet.js +3 -1
- package/lib/tools.js +2 -3
- package/lib/x4.css +21 -1
- package/package.json +2 -2
- package/src/application.ts +6 -1
- package/src/dialog.ts +34 -19
- package/src/fileupload.ts +2 -2
- package/src/gridview.ts +13 -11
- package/src/icon.ts +6 -8
- package/src/listview.ts +1 -1
- package/src/menu.ts +3 -3
- package/src/popup.ts +5 -2
- package/src/spreadsheet.ts +3 -1
- package/src/tools.ts +5 -4
- package/src/x4.less +21 -2
- package/tsconfig.json +0 -4
- package/src/texthiliter.ts +0 -288
package/lib/application.js
CHANGED
|
@@ -92,6 +92,7 @@ class Application extends base_component_1.BaseComponent {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
ApplicationCreated() {
|
|
95
|
+
this.setTitle('');
|
|
95
96
|
}
|
|
96
97
|
get app_name() {
|
|
97
98
|
return this.m_app_name;
|
|
@@ -128,6 +129,9 @@ class Application extends base_component_1.BaseComponent {
|
|
|
128
129
|
setMainView(root, clearBefore) {
|
|
129
130
|
const ddom = this.m_props.renderTo ?? x4dom_1.x4document.body;
|
|
130
131
|
const dest = (0, x4js_1.flyWrap)(ddom);
|
|
132
|
+
if (!this.m_props.renderTo) {
|
|
133
|
+
dest.setStyleValue('position', 'absolute');
|
|
134
|
+
}
|
|
131
135
|
dest.addClass('x4-root-element');
|
|
132
136
|
if (clearBefore) {
|
|
133
137
|
dest._empty();
|
|
@@ -144,7 +148,7 @@ class Application extends base_component_1.BaseComponent {
|
|
|
144
148
|
return this.m_mainView;
|
|
145
149
|
}
|
|
146
150
|
setTitle(title) {
|
|
147
|
-
x4dom_1.x4document.title = this.m_app_name + ' > ' + title;
|
|
151
|
+
x4dom_1.x4document.title = this.m_app_name + (title ? (' > ' + title) : '');
|
|
148
152
|
}
|
|
149
153
|
disableZoomWheel() {
|
|
150
154
|
window.addEventListener('wheel', function (ev) {
|
package/lib/dialog.js
CHANGED
|
@@ -346,14 +346,14 @@ class Dialog extends popup_1.Popup {
|
|
|
346
346
|
let trc = this.m_el_title.getBoundingRect();
|
|
347
347
|
let dx = x - rc.left, dy = y - rc.top;
|
|
348
348
|
let cstyle = this.getComputedStyle();
|
|
349
|
-
let topw = cstyle.parse('marginTop') + cstyle.parse('paddingTop') + cstyle.parse('borderTopWidth');
|
|
350
|
-
let botw = cstyle.parse('marginBottom') + cstyle.parse('paddingBottom') + cstyle.parse('borderBottomWidth');
|
|
351
|
-
let lftw = cstyle.parse('marginLeft') + cstyle.parse('paddingLeft') + cstyle.parse('borderLeftWidth');
|
|
352
|
-
let rgtw = cstyle.parse('marginRight') + cstyle.parse('paddingRight') + cstyle.parse('borderRightWidth');
|
|
353
|
-
wrc.top += topw - trc.height;
|
|
354
|
-
wrc.height -= topw + botw - trc.height;
|
|
355
|
-
wrc.left += lftw;
|
|
356
|
-
wrc.width -= lftw + rgtw;
|
|
349
|
+
//let topw = cstyle.parse('marginTop') + cstyle.parse('paddingTop') + cstyle.parse('borderTopWidth');
|
|
350
|
+
//let botw = cstyle.parse('marginBottom') + cstyle.parse('paddingBottom') + cstyle.parse('borderBottomWidth');
|
|
351
|
+
//let lftw = cstyle.parse('marginLeft') + cstyle.parse('paddingLeft') + cstyle.parse('borderLeftWidth');
|
|
352
|
+
//let rgtw = cstyle.parse('marginRight') + cstyle.parse('paddingRight') + cstyle.parse('borderRightWidth');
|
|
353
|
+
//wrc.top += topw - trc.height;
|
|
354
|
+
//wrc.height -= topw + botw - trc.height;
|
|
355
|
+
//wrc.left += lftw;
|
|
356
|
+
//wrc.width -= lftw + rgtw;
|
|
357
357
|
// custom handling double click
|
|
358
358
|
const now = Date.now();
|
|
359
359
|
const delta = now - this.m_last_down;
|
|
@@ -367,19 +367,32 @@ class Dialog extends popup_1.Popup {
|
|
|
367
367
|
return;
|
|
368
368
|
}
|
|
369
369
|
let __move = (ex, ey) => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
x = wrc.left - rc.width;
|
|
370
|
+
if (ex > wrc.right) {
|
|
371
|
+
ex = wrc.right;
|
|
373
372
|
}
|
|
374
|
-
else if (
|
|
375
|
-
|
|
373
|
+
else if (ex < wrc.left) {
|
|
374
|
+
ex = wrc.left;
|
|
376
375
|
}
|
|
377
|
-
if (
|
|
378
|
-
|
|
376
|
+
if (ey > wrc.bottom) {
|
|
377
|
+
ey = wrc.bottom;
|
|
379
378
|
}
|
|
380
|
-
else if (
|
|
381
|
-
|
|
379
|
+
else if (ey < wrc.top) {
|
|
380
|
+
ey = wrc.top;
|
|
382
381
|
}
|
|
382
|
+
let x = ex - dx, y = ey - dy;
|
|
383
|
+
//if (x + rc.width < wrc.left) {
|
|
384
|
+
// x = wrc.left - rc.width;
|
|
385
|
+
//}
|
|
386
|
+
//else if (x > wrc.right) {
|
|
387
|
+
// x = wrc.right;
|
|
388
|
+
//}
|
|
389
|
+
//
|
|
390
|
+
//if (y < wrc.top) { // title grip is on top
|
|
391
|
+
// y = wrc.top;
|
|
392
|
+
//}
|
|
393
|
+
//else if (y > wrc.bottom) {
|
|
394
|
+
// y = wrc.bottom;
|
|
395
|
+
//}
|
|
383
396
|
this.setStyle({
|
|
384
397
|
left: x,
|
|
385
398
|
top: y
|
package/lib/fileupload.d.ts
CHANGED
|
@@ -55,10 +55,10 @@ export declare class ImageUpload extends FileUpload {
|
|
|
55
55
|
* @param extensions - string - ex: '.doc,.docx'
|
|
56
56
|
* @param cb - callback to call when user select a file
|
|
57
57
|
*/
|
|
58
|
-
export declare function
|
|
58
|
+
export declare function openFileDialog(extensions: string, cb: (filename: FileList) => void, multiple?: boolean): void;
|
|
59
59
|
/**
|
|
60
60
|
* open saveas dialog
|
|
61
61
|
* @param defFileName - string - proposed filename
|
|
62
62
|
* @param cb - callback to call when user choose the destination
|
|
63
63
|
*/
|
|
64
|
-
export declare function
|
|
64
|
+
export declare function saveFileDialog(defFileName: string, extensions: string, cb: (filename: File) => void): void;
|
package/lib/fileupload.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.
|
|
31
|
+
exports.saveFileDialog = exports.openFileDialog = exports.ImageUpload = exports.FileUpload = void 0;
|
|
32
32
|
const x4dom_1 = require("./x4dom");
|
|
33
33
|
const component_1 = require("./component");
|
|
34
34
|
const layout_1 = require("./layout");
|
|
@@ -136,7 +136,7 @@ function _createFileInput() {
|
|
|
136
136
|
* @param extensions - string - ex: '.doc,.docx'
|
|
137
137
|
* @param cb - callback to call when user select a file
|
|
138
138
|
*/
|
|
139
|
-
function
|
|
139
|
+
function openFileDialog(extensions, cb, multiple = false) {
|
|
140
140
|
let fi = _createFileInput();
|
|
141
141
|
fi.removeAttribute('nwsaveas');
|
|
142
142
|
fi.setAttribute('accept', extensions);
|
|
@@ -149,13 +149,13 @@ function openFile(extensions, cb, multiple = false) {
|
|
|
149
149
|
});
|
|
150
150
|
fi.dom.click();
|
|
151
151
|
}
|
|
152
|
-
exports.
|
|
152
|
+
exports.openFileDialog = openFileDialog;
|
|
153
153
|
/**
|
|
154
154
|
* open saveas dialog
|
|
155
155
|
* @param defFileName - string - proposed filename
|
|
156
156
|
* @param cb - callback to call when user choose the destination
|
|
157
157
|
*/
|
|
158
|
-
function
|
|
158
|
+
function saveFileDialog(defFileName, extensions, cb) {
|
|
159
159
|
let fi = _createFileInput();
|
|
160
160
|
fi.setAttribute('nwsaveas', defFileName);
|
|
161
161
|
fi.setAttribute('accept', extensions);
|
|
@@ -167,4 +167,4 @@ function saveFile(defFileName, extensions, cb) {
|
|
|
167
167
|
});
|
|
168
168
|
fi.dom.click();
|
|
169
169
|
}
|
|
170
|
-
exports.
|
|
170
|
+
exports.saveFileDialog = saveFileDialog;
|
package/lib/gridview.js
CHANGED
|
@@ -844,16 +844,18 @@ class GridView extends layout_1.VLayout {
|
|
|
844
844
|
}
|
|
845
845
|
this.m_footer.enumChilds((c) => {
|
|
846
846
|
let cid = c.getData('col');
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
847
|
+
if (cid) {
|
|
848
|
+
let col = this.m_columns[cid];
|
|
849
|
+
let fmt = col.formatter;
|
|
850
|
+
let text;
|
|
851
|
+
if (fmt && fmt instanceof Function) {
|
|
852
|
+
text = fmt(rec[col.id], rec);
|
|
853
|
+
}
|
|
854
|
+
else {
|
|
855
|
+
text = rec[col.id];
|
|
856
|
+
}
|
|
857
|
+
c.setContent(text, false);
|
|
855
858
|
}
|
|
856
|
-
c.setContent(text, false);
|
|
857
859
|
});
|
|
858
860
|
}
|
|
859
861
|
}
|
package/lib/icon.js
CHANGED
|
@@ -76,7 +76,8 @@ class Loader extends x4events_1.EventSource {
|
|
|
76
76
|
if (r.ok) {
|
|
77
77
|
const svg = await r.text();
|
|
78
78
|
// check response, must be svg
|
|
79
|
-
|
|
79
|
+
//TODO: find better
|
|
80
|
+
if (!svg.startsWith("<svg") && !svg.startsWith('<?xml')) {
|
|
80
81
|
console.error("svg loading error: ", svg);
|
|
81
82
|
this.signal('loaded', EvLoaded(url, ""));
|
|
82
83
|
}
|
|
@@ -180,13 +181,10 @@ class Icon extends component_1.Component {
|
|
|
180
181
|
let match_url = reUrl.exec(icon);
|
|
181
182
|
if (match_url) {
|
|
182
183
|
url = trimQuotes(match_url[1].trim());
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
else {
|
|
188
|
-
name = url.replace(/[/\\\.\* ]/g, '_');
|
|
189
|
-
}
|
|
184
|
+
// this value is escaped
|
|
185
|
+
url = url.replaceAll("\\", "");
|
|
186
|
+
this._setSVG(url);
|
|
187
|
+
return;
|
|
190
188
|
}
|
|
191
189
|
else {
|
|
192
190
|
// todo: deprecated
|
package/lib/listview.d.ts
CHANGED
|
@@ -134,8 +134,8 @@ export declare class ListView extends VLayout<ListViewProps, ListViewEventMap> {
|
|
|
134
134
|
/**
|
|
135
135
|
* return the current selection or null
|
|
136
136
|
*/
|
|
137
|
-
get selection():
|
|
138
|
-
set selection(id:
|
|
137
|
+
get selection(): any;
|
|
138
|
+
set selection(id: any);
|
|
139
139
|
private _findItemWithId;
|
|
140
140
|
/**
|
|
141
141
|
* append or prepend a new item
|
package/lib/menu.js
CHANGED
|
@@ -203,10 +203,10 @@ class MenuItem extends component_1.Component {
|
|
|
203
203
|
}
|
|
204
204
|
/** @ignore */
|
|
205
205
|
render(props) {
|
|
206
|
-
let icon = props.icon ??
|
|
206
|
+
let icon = props.icon ?? 0;
|
|
207
207
|
let text = props.text;
|
|
208
208
|
if (props.checked !== undefined) {
|
|
209
|
-
icon = props.checked ? '
|
|
209
|
+
icon = props.checked ? 'var( --x4-icon-check )' : 0;
|
|
210
210
|
}
|
|
211
211
|
if (this.m_action) {
|
|
212
212
|
if (!icon) {
|
|
@@ -219,7 +219,7 @@ class MenuItem extends component_1.Component {
|
|
|
219
219
|
let popIco = null;
|
|
220
220
|
if (this.isPopup) {
|
|
221
221
|
this.addClass('@popup-menu-item');
|
|
222
|
-
popIco = new icon_1.Icon("var( --x4-icon-chevron-right )");
|
|
222
|
+
popIco = new icon_1.Icon({ icon: "var( --x4-icon-chevron-right )", cls: "pop-mark" });
|
|
223
223
|
}
|
|
224
224
|
if (!text && !icon) {
|
|
225
225
|
this.addClass('@separator');
|
package/lib/popup.js
CHANGED
|
@@ -126,7 +126,10 @@ class Popup extends component_1.Container {
|
|
|
126
126
|
}
|
|
127
127
|
centerOnScreen() {
|
|
128
128
|
let rc = this.getBoundingRect();
|
|
129
|
-
let x = (
|
|
129
|
+
//let x = (x4document.body.clientWidth - rc.width) / 2,
|
|
130
|
+
// y = (x4document.body.clientHeight - rc.height) / 2;
|
|
131
|
+
const x = `max( 0px, 50vw - ${rc.width / 2}px )`; //(x4dom_1.x4document.body.clientWidth - rc.width) / 2;
|
|
132
|
+
const y = `max( 0px, 50vh - ${rc.height / 2}px )`; //(x4dom_1.x4document.body.clientHeight - rc.height) / 2;
|
|
130
133
|
this.setStyleValue('left', x);
|
|
131
134
|
this.setStyleValue('top', y);
|
|
132
135
|
}
|
package/lib/spreadsheet.js
CHANGED
|
@@ -389,6 +389,7 @@ class Spreadsheet extends layout_1.VLayout {
|
|
|
389
389
|
if (this.m_recycler.length) {
|
|
390
390
|
cell = this.m_recycler.pop();
|
|
391
391
|
cell.clearClasses();
|
|
392
|
+
cell.addClass('@comp'); // todo: find better to reset to default
|
|
392
393
|
}
|
|
393
394
|
else {
|
|
394
395
|
cell = new component_1.Component({
|
|
@@ -492,7 +493,8 @@ class Spreadsheet extends layout_1.VLayout {
|
|
|
492
493
|
cell.setStyle({
|
|
493
494
|
left: x,
|
|
494
495
|
top: top + y,
|
|
495
|
-
width: calcw[colIdx]
|
|
496
|
+
width: calcw[colIdx],
|
|
497
|
+
height: this.m_itemHeight
|
|
496
498
|
});
|
|
497
499
|
if (this.m_selection.row == rowIdx && this.m_selection.col == colIdx) {
|
|
498
500
|
cell.addClass('@selected');
|
package/lib/tools.js
CHANGED
|
@@ -300,10 +300,9 @@ exports.escapeHtml = escapeHtml;
|
|
|
300
300
|
* console.log( removeHtmlTags('<h1>sss</h1>') );
|
|
301
301
|
*/
|
|
302
302
|
function removeHtmlTags(unsafe, nl_br = false) {
|
|
303
|
-
if (!unsafe || unsafe.length == 0) {
|
|
304
|
-
return
|
|
303
|
+
if (unsafe === undefined || unsafe === null || !isString(unsafe) || unsafe.length == 0) {
|
|
304
|
+
return "";
|
|
305
305
|
}
|
|
306
|
-
debugger;
|
|
307
306
|
let ret_val = '';
|
|
308
307
|
for (let i = 0; i < unsafe.length; i++) {
|
|
309
308
|
const ch = unsafe.codePointAt(i);
|
package/lib/x4.css
CHANGED
|
@@ -58,7 +58,8 @@
|
|
|
58
58
|
--x4-icon-xmark: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" fill="currentColor"><path d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/></svg>';
|
|
59
59
|
--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>';
|
|
60
60
|
--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>';
|
|
61
|
-
--x4-icon-tip: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"
|
|
61
|
+
--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>';
|
|
62
|
+
--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>';
|
|
62
63
|
}
|
|
63
64
|
/* source: https://tailwindcss.com/docs/customizing-colors/#default-color-palette */
|
|
64
65
|
:root {
|
|
@@ -693,6 +694,9 @@ textarea::selection {
|
|
|
693
694
|
margin-right: 8px;
|
|
694
695
|
color: var(--gray-700);
|
|
695
696
|
}
|
|
697
|
+
.x-menu-item .x-icon.pop-mark {
|
|
698
|
+
height: 0.8em;
|
|
699
|
+
}
|
|
696
700
|
.x-menu-item .x-label {
|
|
697
701
|
padding: 4px;
|
|
698
702
|
}
|
|
@@ -1079,6 +1083,10 @@ textarea::selection {
|
|
|
1079
1083
|
color: var(--gray-900);
|
|
1080
1084
|
height: 2em;
|
|
1081
1085
|
}
|
|
1086
|
+
.x-spreadsheet .x-cell span,
|
|
1087
|
+
.x-grid-view .x-cell span {
|
|
1088
|
+
width: 100%;
|
|
1089
|
+
}
|
|
1082
1090
|
.x-spreadsheet .x-footer,
|
|
1083
1091
|
.x-grid-view .x-footer,
|
|
1084
1092
|
.x-spreadsheet .x-header,
|
|
@@ -1123,6 +1131,16 @@ textarea::selection {
|
|
|
1123
1131
|
display: flex;
|
|
1124
1132
|
align-items: center;
|
|
1125
1133
|
}
|
|
1134
|
+
.x-spreadsheet .x-header .x-cell span,
|
|
1135
|
+
.x-grid-view .x-header .x-cell span {
|
|
1136
|
+
width: unset;
|
|
1137
|
+
}
|
|
1138
|
+
.x-spreadsheet .x-header .x-cell .sort,
|
|
1139
|
+
.x-grid-view .x-header .x-cell .sort {
|
|
1140
|
+
width: 1em;
|
|
1141
|
+
height: 1em;
|
|
1142
|
+
padding-left: 4px;
|
|
1143
|
+
}
|
|
1126
1144
|
.x-spreadsheet .x-row,
|
|
1127
1145
|
.x-grid-view .x-row {
|
|
1128
1146
|
position: absolute;
|
|
@@ -1178,6 +1196,8 @@ textarea::selection {
|
|
|
1178
1196
|
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
|
1179
1197
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
1180
1198
|
height: 2em;
|
|
1199
|
+
align-items: center;
|
|
1200
|
+
display: flex;
|
|
1181
1201
|
}
|
|
1182
1202
|
.x-spreadsheet .x-cell.x-selected {
|
|
1183
1203
|
background-color: rgba(0, 0, 0, 0.1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x4js",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.28",
|
|
4
4
|
"description": "X4js core files",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"framework"
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "
|
|
17
|
+
"build": "tsc && lessc src/x4.less >lib/x4.css",
|
|
18
18
|
"mkdoc": "typedoc --tsconfig tsconfig.json --readme none"
|
|
19
19
|
},
|
|
20
20
|
"author": "etienne cochard",
|
package/src/application.ts
CHANGED
|
@@ -128,6 +128,7 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
ApplicationCreated( ) {
|
|
131
|
+
this.setTitle( '' );
|
|
131
132
|
}
|
|
132
133
|
|
|
133
134
|
public get app_name( ) {
|
|
@@ -174,6 +175,10 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
|
|
|
174
175
|
const ddom = this.m_props.renderTo ?? x4document.body;
|
|
175
176
|
const dest = flyWrap( ddom );
|
|
176
177
|
|
|
178
|
+
if( !this.m_props.renderTo ) {
|
|
179
|
+
dest.setStyleValue( 'position', 'absolute' );
|
|
180
|
+
}
|
|
181
|
+
|
|
177
182
|
dest.addClass( 'x4-root-element' );
|
|
178
183
|
if( clearBefore ) {
|
|
179
184
|
dest._empty( );
|
|
@@ -196,7 +201,7 @@ export class Application<P extends ApplicationProps = ApplicationProps, E extend
|
|
|
196
201
|
}
|
|
197
202
|
|
|
198
203
|
public setTitle( title: string ) {
|
|
199
|
-
x4document.title = this.m_app_name + ' > ' + title;
|
|
204
|
+
x4document.title = this.m_app_name + (title ? (' > ' + title) : '');
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
public disableZoomWheel( ) {
|
package/src/dialog.ts
CHANGED
|
@@ -469,16 +469,16 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogBoxEven
|
|
|
469
469
|
|
|
470
470
|
let cstyle = this.getComputedStyle();
|
|
471
471
|
|
|
472
|
-
let topw = cstyle.parse('marginTop') + cstyle.parse('paddingTop') + cstyle.parse('borderTopWidth');
|
|
473
|
-
let botw = cstyle.parse('marginBottom') + cstyle.parse('paddingBottom') + cstyle.parse('borderBottomWidth');
|
|
474
|
-
let lftw = cstyle.parse('marginLeft') + cstyle.parse('paddingLeft') + cstyle.parse('borderLeftWidth');
|
|
475
|
-
let rgtw = cstyle.parse('marginRight') + cstyle.parse('paddingRight') + cstyle.parse('borderRightWidth');
|
|
472
|
+
//let topw = cstyle.parse('marginTop') + cstyle.parse('paddingTop') + cstyle.parse('borderTopWidth');
|
|
473
|
+
//let botw = cstyle.parse('marginBottom') + cstyle.parse('paddingBottom') + cstyle.parse('borderBottomWidth');
|
|
474
|
+
//let lftw = cstyle.parse('marginLeft') + cstyle.parse('paddingLeft') + cstyle.parse('borderLeftWidth');
|
|
475
|
+
//let rgtw = cstyle.parse('marginRight') + cstyle.parse('paddingRight') + cstyle.parse('borderRightWidth');
|
|
476
476
|
|
|
477
|
-
wrc.top += topw - trc.height;
|
|
478
|
-
wrc.height -= topw + botw - trc.height;
|
|
477
|
+
//wrc.top += topw - trc.height;
|
|
478
|
+
//wrc.height -= topw + botw - trc.height;
|
|
479
479
|
|
|
480
|
-
wrc.left += lftw;
|
|
481
|
-
wrc.width -= lftw + rgtw;
|
|
480
|
+
//wrc.left += lftw;
|
|
481
|
+
//wrc.width -= lftw + rgtw;
|
|
482
482
|
|
|
483
483
|
// custom handling double click
|
|
484
484
|
const now = Date.now();
|
|
@@ -496,23 +496,38 @@ export class Dialog<P extends DialogProps = DialogProps, E extends DialogBoxEven
|
|
|
496
496
|
}
|
|
497
497
|
|
|
498
498
|
let __move = (ex, ey) => {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
if (x + rc.width < wrc.left) {
|
|
503
|
-
x = wrc.left - rc.width;
|
|
499
|
+
|
|
500
|
+
if( ex>wrc.right ) {
|
|
501
|
+
ex = wrc.right;
|
|
504
502
|
}
|
|
505
|
-
else if
|
|
506
|
-
|
|
503
|
+
else if( ex<wrc.left ) {
|
|
504
|
+
ex = wrc.left;
|
|
507
505
|
}
|
|
508
506
|
|
|
509
|
-
if
|
|
510
|
-
|
|
507
|
+
if( ey>wrc.bottom ) {
|
|
508
|
+
ey = wrc.bottom;
|
|
511
509
|
}
|
|
512
|
-
else if
|
|
513
|
-
|
|
510
|
+
else if( ey<wrc.top ) {
|
|
511
|
+
ey = wrc.top;
|
|
514
512
|
}
|
|
515
513
|
|
|
514
|
+
let x = ex - dx,
|
|
515
|
+
y = ey - dy;
|
|
516
|
+
|
|
517
|
+
//if (x + rc.width < wrc.left) {
|
|
518
|
+
// x = wrc.left - rc.width;
|
|
519
|
+
//}
|
|
520
|
+
//else if (x > wrc.right) {
|
|
521
|
+
// x = wrc.right;
|
|
522
|
+
//}
|
|
523
|
+
//
|
|
524
|
+
//if (y < wrc.top) { // title grip is on top
|
|
525
|
+
// y = wrc.top;
|
|
526
|
+
//}
|
|
527
|
+
//else if (y > wrc.bottom) {
|
|
528
|
+
// y = wrc.bottom;
|
|
529
|
+
//}
|
|
530
|
+
|
|
516
531
|
this.setStyle({
|
|
517
532
|
left: x,
|
|
518
533
|
top: y
|
package/src/fileupload.ts
CHANGED
|
@@ -171,7 +171,7 @@ function _createFileInput() {
|
|
|
171
171
|
* @param cb - callback to call when user select a file
|
|
172
172
|
*/
|
|
173
173
|
|
|
174
|
-
export function
|
|
174
|
+
export function openFileDialog(extensions: string, cb: (filename: FileList) => void, multiple = false) {
|
|
175
175
|
|
|
176
176
|
let fi = _createFileInput();
|
|
177
177
|
|
|
@@ -195,7 +195,7 @@ export function openFile(extensions: string, cb: (filename: FileList) => void, m
|
|
|
195
195
|
* @param cb - callback to call when user choose the destination
|
|
196
196
|
*/
|
|
197
197
|
|
|
198
|
-
export function
|
|
198
|
+
export function saveFileDialog(defFileName: string, extensions: string, cb: (filename: File) => void) {
|
|
199
199
|
|
|
200
200
|
let fi = _createFileInput();
|
|
201
201
|
fi.setAttribute('nwsaveas', defFileName);
|
package/src/gridview.ts
CHANGED
|
@@ -1126,19 +1126,21 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
|
|
|
1126
1126
|
|
|
1127
1127
|
this.m_footer.enumChilds( (c) => {
|
|
1128
1128
|
let cid = c.getData( 'col' );
|
|
1129
|
-
|
|
1129
|
+
if( cid ) {
|
|
1130
|
+
let col = this.m_columns[cid];
|
|
1130
1131
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1132
|
+
let fmt = col.formatter;
|
|
1133
|
+
|
|
1134
|
+
let text;
|
|
1135
|
+
if (fmt && fmt instanceof Function) {
|
|
1136
|
+
text = fmt(rec[col.id], rec);
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
text = rec[col.id];
|
|
1140
|
+
}
|
|
1140
1141
|
|
|
1141
|
-
|
|
1142
|
+
c.setContent( text, false );
|
|
1143
|
+
}
|
|
1142
1144
|
});
|
|
1143
1145
|
}
|
|
1144
1146
|
}
|
package/src/icon.ts
CHANGED
|
@@ -101,7 +101,8 @@ class Loader extends EventSource<LoadingEventMap> {
|
|
|
101
101
|
if( r.ok ) {
|
|
102
102
|
const svg = await r.text();
|
|
103
103
|
// check response, must be svg
|
|
104
|
-
|
|
104
|
+
//TODO: find better
|
|
105
|
+
if (!svg.startsWith("<svg") && !svg.startsWith('<?xml') ) {
|
|
105
106
|
console.error( "svg loading error: ", svg );
|
|
106
107
|
this.signal( 'loaded', EvLoaded(url,"") );
|
|
107
108
|
}
|
|
@@ -225,13 +226,10 @@ export class Icon extends Component<IconProps>
|
|
|
225
226
|
let match_url = reUrl.exec( icon );
|
|
226
227
|
if( match_url ) {
|
|
227
228
|
url = trimQuotes( match_url[1].trim( ) );
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
else {
|
|
233
|
-
name = url.replace( /[/\\\.\* ]/g, '_' );
|
|
234
|
-
}
|
|
229
|
+
// this value is escaped
|
|
230
|
+
url = url.replaceAll( "\\", "" );
|
|
231
|
+
this._setSVG( url );
|
|
232
|
+
return;
|
|
235
233
|
}
|
|
236
234
|
else {
|
|
237
235
|
// todo: deprecated
|
package/src/listview.ts
CHANGED
|
@@ -551,7 +551,7 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
551
551
|
return this.m_selection ? this.m_selection.item : null;
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
public set selection(id) {
|
|
554
|
+
public set selection(id: any) {
|
|
555
555
|
if (id === null || id === undefined) {
|
|
556
556
|
this._selectItem(null, null);
|
|
557
557
|
}
|
package/src/menu.ts
CHANGED
|
@@ -293,11 +293,11 @@ export class MenuItem extends Component<MenuItemProps, MenuItemEventMap> {
|
|
|
293
293
|
/** @ignore */
|
|
294
294
|
render(props: MenuItemProps) {
|
|
295
295
|
|
|
296
|
-
let icon = props.icon ??
|
|
296
|
+
let icon = props.icon ?? 0;
|
|
297
297
|
let text = props.text;
|
|
298
298
|
|
|
299
299
|
if (props.checked !== undefined) {
|
|
300
|
-
icon = props.checked ? '
|
|
300
|
+
icon = props.checked ? 'var( --x4-icon-check )' : 0;
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
if( this.m_action ) {
|
|
@@ -313,7 +313,7 @@ export class MenuItem extends Component<MenuItemProps, MenuItemEventMap> {
|
|
|
313
313
|
let popIco = null;
|
|
314
314
|
if (this.isPopup) {
|
|
315
315
|
this.addClass('@popup-menu-item');
|
|
316
|
-
popIco = new Icon( "var( --x4-icon-chevron-right )" );
|
|
316
|
+
popIco = new Icon( { icon: "var( --x4-icon-chevron-right )", cls: "pop-mark" } );
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
if (!text && !icon) {
|
package/src/popup.ts
CHANGED
|
@@ -169,8 +169,11 @@ export class Popup<P extends PopupProps = PopupProps, E extends PopupEventMap =
|
|
|
169
169
|
centerOnScreen( ) {
|
|
170
170
|
let rc = this.getBoundingRect();
|
|
171
171
|
|
|
172
|
-
let x = (x4document.body.clientWidth - rc.width) / 2,
|
|
173
|
-
|
|
172
|
+
//let x = (x4document.body.clientWidth - rc.width) / 2,
|
|
173
|
+
// y = (x4document.body.clientHeight - rc.height) / 2;
|
|
174
|
+
|
|
175
|
+
const x = `max( 0px, 50vw - ${rc.width/2}px )`; //(x4dom_1.x4document.body.clientWidth - rc.width) / 2;
|
|
176
|
+
const y = `max( 0px, 50vh - ${rc.height/2}px )`; //(x4dom_1.x4document.body.clientHeight - rc.height) / 2;
|
|
174
177
|
|
|
175
178
|
this.setStyleValue('left', x);
|
|
176
179
|
this.setStyleValue('top', y);
|
package/src/spreadsheet.ts
CHANGED
|
@@ -546,6 +546,7 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
|
|
|
546
546
|
if (this.m_recycler.length) {
|
|
547
547
|
cell = this.m_recycler.pop();
|
|
548
548
|
cell.clearClasses();
|
|
549
|
+
cell.addClass( '@comp' ); // todo: find better to reset to default
|
|
549
550
|
}
|
|
550
551
|
else {
|
|
551
552
|
cell = new Component({
|
|
@@ -681,7 +682,8 @@ export class Spreadsheet extends VLayout<SpreadsheetProps, SpreadsheetEventSet>
|
|
|
681
682
|
cell.setStyle({
|
|
682
683
|
left: x,
|
|
683
684
|
top: top + y,
|
|
684
|
-
width: calcw[colIdx]
|
|
685
|
+
width: calcw[colIdx],
|
|
686
|
+
height: this.m_itemHeight
|
|
685
687
|
});
|
|
686
688
|
|
|
687
689
|
if (this.m_selection.row == rowIdx && this.m_selection.col == colIdx) {
|
package/src/tools.ts
CHANGED
|
@@ -369,10 +369,11 @@ export function escapeHtml(unsafe: string, nl_br = false): string {
|
|
|
369
369
|
*/
|
|
370
370
|
|
|
371
371
|
export function removeHtmlTags(unsafe: string, nl_br = false): string {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
372
|
+
|
|
373
|
+
if ( unsafe===undefined || unsafe===null || !isString(unsafe) || unsafe.length == 0 ) {
|
|
374
|
+
return "";
|
|
375
|
+
}
|
|
376
|
+
|
|
376
377
|
let ret_val = '';
|
|
377
378
|
for (let i = 0; i < unsafe.length; i++) {
|
|
378
379
|
const ch = unsafe.codePointAt(i);
|
package/src/x4.less
CHANGED
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
--x4-icon-xmark: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512" fill="currentColor"><path d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25C304.4 412.9 296.2 416 288 416s-16.38-3.125-22.62-9.375L160 301.3L54.63 406.6C48.38 412.9 40.19 416 32 416S15.63 412.9 9.375 406.6c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/></svg>';
|
|
71
71
|
--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>';
|
|
72
72
|
--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>';
|
|
73
|
-
--x4-icon-tip: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"
|
|
73
|
+
--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>';
|
|
74
|
+
--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>';
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
@BLACK10: rgba(0,0,0,0.1);
|
|
@@ -862,6 +863,10 @@ textarea {
|
|
|
862
863
|
width: 1em;
|
|
863
864
|
margin-right: 8px;
|
|
864
865
|
color: var( --gray-700 );
|
|
866
|
+
|
|
867
|
+
&.pop-mark {
|
|
868
|
+
height: 0.8em;
|
|
869
|
+
}
|
|
865
870
|
}
|
|
866
871
|
|
|
867
872
|
.x-label {
|
|
@@ -1329,9 +1334,12 @@ textarea {
|
|
|
1329
1334
|
overflow: hidden;
|
|
1330
1335
|
padding: 4px;
|
|
1331
1336
|
white-space: nowrap;
|
|
1332
|
-
//min-width: 50px;
|
|
1333
1337
|
color: var( --gray-900 );
|
|
1334
1338
|
height: @def-height;
|
|
1339
|
+
|
|
1340
|
+
span {
|
|
1341
|
+
width: 100%;
|
|
1342
|
+
}
|
|
1335
1343
|
}
|
|
1336
1344
|
|
|
1337
1345
|
.x-footer,
|
|
@@ -1368,6 +1376,15 @@ textarea {
|
|
|
1368
1376
|
.x-cell {
|
|
1369
1377
|
display: flex;
|
|
1370
1378
|
align-items: center;
|
|
1379
|
+
span {
|
|
1380
|
+
width: unset;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
.sort {
|
|
1384
|
+
width: 1em;
|
|
1385
|
+
height: 1em;
|
|
1386
|
+
padding-left: 4px;
|
|
1387
|
+
}
|
|
1371
1388
|
}
|
|
1372
1389
|
}
|
|
1373
1390
|
|
|
@@ -1441,6 +1458,8 @@ textarea {
|
|
|
1441
1458
|
border-right: 1px solid rgba(0,0,0,0.1);
|
|
1442
1459
|
border-bottom: 1px solid rgba(0,0,0,0.1);
|
|
1443
1460
|
height: 2em;
|
|
1461
|
+
align-items: center;
|
|
1462
|
+
display: flex;
|
|
1444
1463
|
}
|
|
1445
1464
|
|
|
1446
1465
|
.x-cell.x-selected {
|
package/tsconfig.json
CHANGED
package/src/texthiliter.ts
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ___ ___ __
|
|
3
|
-
* \ \_/ / / _
|
|
4
|
-
* \ / /_| |_
|
|
5
|
-
* / _ \____ _|
|
|
6
|
-
* /__/ \__\ |_|
|
|
7
|
-
*
|
|
8
|
-
* @file texthiliter.ts
|
|
9
|
-
* @author Etienne Cochard
|
|
10
|
-
*
|
|
11
|
-
* Copyright (c) 2019-2022 R-libre ingenierie
|
|
12
|
-
*
|
|
13
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
15
|
-
* in the Software without restriction, including without limitation the rights
|
|
16
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
17
|
-
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
18
|
-
* subject to the following conditions:
|
|
19
|
-
* The above copyright notice and this permission notice shall be included in all copies
|
|
20
|
-
* or substantial portions of the Software.
|
|
21
|
-
*
|
|
22
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
23
|
-
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
24
|
-
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
25
|
-
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
26
|
-
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
|
-
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
|
-
**/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* idea came from https://www.cdolivet.com/editarea
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import { Component, CProps, CEventMap } from './component'
|
|
35
|
-
import { EvChange } from './x4_events'
|
|
36
|
-
|
|
37
|
-
interface TextHiliterEventMap extends CEventMap {
|
|
38
|
-
change: EvChange;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
interface TextHiliterProps extends CProps {
|
|
43
|
-
text: string;
|
|
44
|
-
kwList?: Set<string>;
|
|
45
|
-
change?: EvChange;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
export class TextHiliter extends Component<TextHiliterProps,TextHiliterEventMap> {
|
|
50
|
-
|
|
51
|
-
private m_text: string;
|
|
52
|
-
private m_ed: Component;
|
|
53
|
-
private m_hi: Component;
|
|
54
|
-
private m_top: number;
|
|
55
|
-
private m_kwList: Set<string>;
|
|
56
|
-
|
|
57
|
-
constructor( props: TextHiliterProps ) {
|
|
58
|
-
super( props );
|
|
59
|
-
|
|
60
|
-
this.m_kwList = props.kwList;
|
|
61
|
-
this.m_top = 0;
|
|
62
|
-
this.m_text = props.text ?? '';
|
|
63
|
-
|
|
64
|
-
this.mapPropEvents( props, 'change' );
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** @ignore */
|
|
68
|
-
render( ) {
|
|
69
|
-
this.setContent( [
|
|
70
|
-
this.m_hi = new Component( {
|
|
71
|
-
tag: 'span',
|
|
72
|
-
cls: '@fit @syntax-hiliter',
|
|
73
|
-
}),
|
|
74
|
-
this.m_ed = new Component( {
|
|
75
|
-
tag: 'textarea',
|
|
76
|
-
cls: '@fit',
|
|
77
|
-
width: '100%',
|
|
78
|
-
attrs: {
|
|
79
|
-
spellcheck: 'false',
|
|
80
|
-
wrap: 'off',
|
|
81
|
-
},
|
|
82
|
-
dom_events: {
|
|
83
|
-
input: ()=>this._hiliteText(),
|
|
84
|
-
scroll: ()=> this._updateScroll( ),
|
|
85
|
-
keydown: (e)=> this._keydown(e),
|
|
86
|
-
}
|
|
87
|
-
}),
|
|
88
|
-
|
|
89
|
-
])
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
componentCreated() {
|
|
93
|
-
super.componentCreated( );
|
|
94
|
-
this.value = this.m_text;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
get value( ) : string {
|
|
98
|
-
|
|
99
|
-
if( this.dom ) {
|
|
100
|
-
return (<HTMLTextAreaElement>this.m_ed.dom).value;
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
return this.m_text;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
set value( t: string ) {
|
|
108
|
-
if( this.dom ) {
|
|
109
|
-
(<HTMLTextAreaElement>this.m_ed.dom).value = t;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
this.m_text = t;
|
|
113
|
-
this._hiliteText( );
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private _keydown( e: KeyboardEvent ) {
|
|
117
|
-
if(e.key=='Tab' ){
|
|
118
|
-
e.preventDefault();
|
|
119
|
-
e.stopPropagation( );
|
|
120
|
-
|
|
121
|
-
let dom = <HTMLTextAreaElement>this.m_ed.dom;
|
|
122
|
-
|
|
123
|
-
let ss = dom.selectionStart;
|
|
124
|
-
let se = dom.selectionEnd;
|
|
125
|
-
dom.setRangeText( '\t', ss, se );
|
|
126
|
-
dom.setSelectionRange( ss+1, ss+1 );
|
|
127
|
-
dom.dispatchEvent( new Event( 'input' ) );
|
|
128
|
-
}
|
|
129
|
-
else if( e.key=='Enter' ) {
|
|
130
|
-
e.stopPropagation( );
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private _hiliteText( ) {
|
|
135
|
-
let text = (<HTMLTextAreaElement>this.m_ed.dom).value;
|
|
136
|
-
|
|
137
|
-
if( !this.m_hi.dom.firstChild ) {
|
|
138
|
-
this.m_hi.dom.innerHTML = '<div style="position:absolute"></div>';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
(<HTMLElement>this.m_hi.dom.firstChild).innerHTML = this._tokenize(text);
|
|
142
|
-
// this._updateScroll( );
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
private _updateScroll( ) {
|
|
146
|
-
|
|
147
|
-
this.startTimer('sync', 0, false, ( ) => {
|
|
148
|
-
let top = this.m_ed.dom.scrollTop;
|
|
149
|
-
if( top!=this.m_top ) {
|
|
150
|
-
this.m_hi.dom.scrollTop = top;
|
|
151
|
-
this.m_top = top;
|
|
152
|
-
}
|
|
153
|
-
this.m_hi.dom.scrollLeft = this.m_ed.dom.scrollLeft;
|
|
154
|
-
//this.m_hi.setStyleValue( 'width', this.m_ed.dom.clientWidth );
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private _escape( text: string ) : string {
|
|
159
|
-
text = text.replace( /&/gm, '&' );
|
|
160
|
-
text = text.replace( /</gm, '<' );
|
|
161
|
-
text = text.replace( />/gm, '>' );
|
|
162
|
-
return text;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
private _tokenize( text: string ) : string {
|
|
168
|
-
|
|
169
|
-
const reNUM = /\d/;
|
|
170
|
-
const reNUM2 = /[\d.]/;
|
|
171
|
-
const rePUNC = /\+|-|,|\/|\*|=|%|!|\||;|\.|\[|\]|\{|\|\(|\)|}|<|>|&/;
|
|
172
|
-
const reKW = /[a-zA-Z_]/;
|
|
173
|
-
const reKW2 = /[a-zA-Z0-9_]/;
|
|
174
|
-
|
|
175
|
-
let result = '';
|
|
176
|
-
|
|
177
|
-
let i = 0;
|
|
178
|
-
let length = text.length;
|
|
179
|
-
let s;
|
|
180
|
-
|
|
181
|
-
console.time( "hilite" );
|
|
182
|
-
|
|
183
|
-
while( i<length ) {
|
|
184
|
-
|
|
185
|
-
let c = text.charAt( i );
|
|
186
|
-
|
|
187
|
-
// numbers
|
|
188
|
-
if( reNUM.test(c) ) {
|
|
189
|
-
|
|
190
|
-
let s = i;
|
|
191
|
-
do {
|
|
192
|
-
c = text.charAt( ++i );
|
|
193
|
-
} while( reNUM2.test(c) && i<length );
|
|
194
|
-
|
|
195
|
-
result += '<span class="num">' + text.substring( s, i ) + '</span>';
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// keywords
|
|
200
|
-
if( this.m_kwList ) {
|
|
201
|
-
if( reKW.test(c) ) {
|
|
202
|
-
|
|
203
|
-
let s = i;
|
|
204
|
-
|
|
205
|
-
do {
|
|
206
|
-
c = text.charAt( ++i );
|
|
207
|
-
} while( reKW2.test(c) && i<length );
|
|
208
|
-
|
|
209
|
-
let kw = text.substring( s, i );
|
|
210
|
-
if( this.m_kwList.has( kw ) ) {
|
|
211
|
-
result += '<span class="kword">' + kw + '</span>';
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
result += kw;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
if( c=='#' ) {
|
|
222
|
-
let ne = text.indexOf( '\n', i+1 );
|
|
223
|
-
if( ne<0 ) {
|
|
224
|
-
ne = text.length;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
result += '<span class="cmt">' + this._escape(text.substring( i, ne )) + '</span>';
|
|
228
|
-
i = ne;
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// comments
|
|
233
|
-
if( c=='/' ) {
|
|
234
|
-
let cn = text.charAt( i+1 );
|
|
235
|
-
if( cn=='*' ) {
|
|
236
|
-
let ne = text.indexOf( '*/', i+2 );
|
|
237
|
-
if( ne<0 ) {
|
|
238
|
-
ne = text.length;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
result += '<span class="cmt">' + this._escape(text.substring( i, ne+2 )) + '</span>';
|
|
242
|
-
i = ne+2;
|
|
243
|
-
continue;
|
|
244
|
-
}
|
|
245
|
-
else if( cn=='/' ) {
|
|
246
|
-
let ne = text.indexOf( '\n', i+2 );
|
|
247
|
-
if( ne<0 ) {
|
|
248
|
-
ne = text.length;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
result += `<span class="cmt">${this._escape(text.substring( i, ne ))}</span>`;
|
|
252
|
-
i = ne;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// punctuation
|
|
258
|
-
if( rePUNC.test(c) ) {
|
|
259
|
-
s = i;
|
|
260
|
-
do {
|
|
261
|
-
c = text.charAt( ++i );
|
|
262
|
-
} while( rePUNC.test(c) && i<length );
|
|
263
|
-
|
|
264
|
-
result += `<span class="punc">${text.substring( s, i )}</span>`;
|
|
265
|
-
continue;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// strings
|
|
269
|
-
if( c=='"' || c=='\'' || c=='\`' ) {
|
|
270
|
-
s = i;
|
|
271
|
-
|
|
272
|
-
let delim = c;
|
|
273
|
-
do {
|
|
274
|
-
c = text.charAt( ++i );
|
|
275
|
-
} while( c!=delim && i<length );
|
|
276
|
-
|
|
277
|
-
result += `<span class="str">${this._escape(text.substring( s, ++i ))}</span>`;
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
i++;
|
|
282
|
-
result += c;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
console.timeEnd( "hilite" );
|
|
286
|
-
return result + '\n\n\n';
|
|
287
|
-
}
|
|
288
|
-
}
|