x4js 2.3.19 → 2.3.21
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/aicontext.md +48 -28
- package/package.json +1 -1
- package/src/components/autocomplete/autocomplete.ts +3 -0
- package/src/components/boxes/boxes.ts +1 -1
- package/src/components/chart/chart.ts +12 -3
- package/src/components/colorinput/colorinput.module.scss +11 -2
- package/src/components/colorinput/colorinput.ts +37 -4
- package/src/components/colorpicker/colorpicker.module.scss +14 -2
- package/src/components/colorpicker/colorpicker.ts +57 -11
- package/src/components/dialog/dialog.ts +16 -5
- package/src/components/form/form.ts +3 -4
- package/src/components/gridview/gridview.module.scss +18 -16
- package/src/components/gridview/gridview.ts +5 -0
- package/src/components/icon/icon.ts +34 -18
- package/src/components/keyboard/keyboard.ts +7 -3
- package/src/components/link/link.ts +18 -7
- package/src/components/messages/messages.ts +1 -1
- package/src/components/panel/panel.ts +3 -2
- package/src/components/spreadsheet/spreadsheet.module.scss +18 -16
- package/src/components/textarea/textarea.module.scss +10 -3
- package/src/components/video/video.ts +17 -3
- package/src/core/core_colors.ts +21 -10
- package/src/core/core_dragdrop.ts +5 -4
- package/src/core/core_i18n.ts +34 -54
- package/src/core/core_pdf.ts +524 -8
- package/src/core/core_shortcuts.ts +5 -1
- package/src/core/core_styles.ts +46 -25
- package/src/core/core_svg.ts +24 -16
- package/src/core/core_tools.ts +18 -9
package/src/core/core_styles.ts
CHANGED
|
@@ -121,33 +121,42 @@ export function isUnitLess( name: string ) {
|
|
|
121
121
|
return unitless[name] ? true : false;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
// one sheet for the page, shared by all the Stylesheet: a name is one rule,
|
|
125
|
+
// whatever instance sets it
|
|
126
|
+
let page_sheet: CSSStyleSheet = null;
|
|
127
|
+
const page_rules = new Map<string, CSSRule>( );
|
|
128
|
+
|
|
129
|
+
function pageSheet( ): CSSStyleSheet {
|
|
130
|
+
if( !page_sheet ) {
|
|
131
|
+
// found by its id: a title would make it a "preferred" style sheet,
|
|
132
|
+
// of which a page applies only one
|
|
133
|
+
let dom = document.getElementById( 'x4-dynamic-css' ) as HTMLStyleElement;
|
|
134
|
+
if( !dom ) {
|
|
135
|
+
dom = document.createElement( 'style' );
|
|
136
|
+
dom.id = 'x4-dynamic-css';
|
|
137
|
+
document.head.appendChild( dom );
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
page_sheet = dom.sheet;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return page_sheet;
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
/**
|
|
125
|
-
*
|
|
147
|
+
* Rules added to the page while it runs, in one <style id="x4-dynamic-css">.
|
|
148
|
+
* @deprecated the CSS variables do it: setStyleVariable( ) on a component,
|
|
149
|
+
* var( --name ) in its stylesheet
|
|
126
150
|
*/
|
|
127
151
|
|
|
128
152
|
export class Stylesheet {
|
|
129
153
|
|
|
130
154
|
readonly _sheet: CSSStyleSheet;
|
|
131
|
-
readonly _rules: Map<string,
|
|
155
|
+
readonly _rules: Map<string, CSSRule>;
|
|
132
156
|
|
|
133
157
|
constructor() {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
for(let i=0; i<document.styleSheets.length; i++) {
|
|
137
|
-
let sheet = document.styleSheets[i];
|
|
138
|
-
if(sheet.title === name ) {
|
|
139
|
-
return sheet;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
this._sheet = getStyleSheet( 'x4-dynamic-css' );
|
|
145
|
-
if( !this._sheet ) {
|
|
146
|
-
const dom = document.createElement( 'style' );
|
|
147
|
-
dom.setAttribute('id', 'x4-dynamic-css' );
|
|
148
|
-
document.head.appendChild(dom);
|
|
149
|
-
this._sheet = dom.sheet
|
|
150
|
-
}
|
|
158
|
+
this._sheet = pageSheet( );
|
|
159
|
+
this._rules = page_rules;
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
/**
|
|
@@ -156,20 +165,31 @@ export class Stylesheet {
|
|
|
156
165
|
* @param {string} definition - css definition of the rule
|
|
157
166
|
* @example
|
|
158
167
|
* setRule('xbody', "body { background-color: #ff0000; }" );
|
|
168
|
+
* @deprecated a CSS variable: setStyleVariable( ) on a component, var( --name ) in its stylesheet
|
|
159
169
|
*/
|
|
160
170
|
|
|
161
171
|
public setRule(name: string, definition: any ) {
|
|
162
172
|
|
|
163
173
|
if( isString(definition) ) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
174
|
+
const sheet = this._sheet;
|
|
175
|
+
const old = this._rules.get( name );
|
|
176
|
+
|
|
177
|
+
// in the place of the rule of that name, else at the end
|
|
178
|
+
let index = sheet.cssRules.length;
|
|
179
|
+
if( old ) {
|
|
180
|
+
const at = Array.prototype.indexOf.call( sheet.cssRules, old );
|
|
181
|
+
if( at>=0 ) {
|
|
182
|
+
index = at;
|
|
183
|
+
}
|
|
167
184
|
}
|
|
168
|
-
|
|
169
|
-
|
|
185
|
+
|
|
186
|
+
// inserted first: a definition that is not valid throws, the old rule stays
|
|
187
|
+
sheet.insertRule( definition, index );
|
|
188
|
+
if( old && sheet.cssRules[index+1]===old ) {
|
|
189
|
+
sheet.deleteRule( index+1 );
|
|
170
190
|
}
|
|
171
191
|
|
|
172
|
-
this._rules.set( name,
|
|
192
|
+
this._rules.set( name, sheet.cssRules[index] );
|
|
173
193
|
}
|
|
174
194
|
else {
|
|
175
195
|
let idx = 1;
|
|
@@ -203,6 +223,7 @@ export class Stylesheet {
|
|
|
203
223
|
* ```
|
|
204
224
|
* let color = Component.getCss( ).getVar( 'button-color' );
|
|
205
225
|
* ```
|
|
226
|
+
* @deprecated getStyleVariable( ) of a component, or getComputedStyle( document.documentElement ).getPropertyValue( "--name" )
|
|
206
227
|
*/
|
|
207
228
|
|
|
208
229
|
public static getVar( name: string ) : any {
|
package/src/core/core_svg.ts
CHANGED
|
@@ -156,7 +156,7 @@ class SvgItem {
|
|
|
156
156
|
* @param cap
|
|
157
157
|
*/
|
|
158
158
|
|
|
159
|
-
strokeCap( cap: "butt" | "round" | "
|
|
159
|
+
strokeCap( cap: "butt" | "round" | "square" ) {
|
|
160
160
|
return this.setAttr( "stroke-linecap", cap );
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -218,12 +218,13 @@ class SvgItem {
|
|
|
218
218
|
*/
|
|
219
219
|
|
|
220
220
|
getNumAttr( name: string ) {
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
// not set or empty: 0; "1.5" is 1.5
|
|
222
|
+
const a = this._dom.getAttribute( name );
|
|
223
|
+
if( !a ) {
|
|
223
224
|
return 0;
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
return
|
|
227
|
+
return parseFloat( a );
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
/**
|
|
@@ -271,7 +272,9 @@ class SvgItem {
|
|
|
271
272
|
*/
|
|
272
273
|
|
|
273
274
|
addClass( cls: string ): this {
|
|
274
|
-
if( !cls )
|
|
275
|
+
if( !cls ) {
|
|
276
|
+
return this;
|
|
277
|
+
}
|
|
275
278
|
|
|
276
279
|
cls = cls.trim();
|
|
277
280
|
if( cls.indexOf(' ')>=0 ) {
|
|
@@ -484,12 +487,13 @@ export class SvgPath extends SvgItem {
|
|
|
484
487
|
|
|
485
488
|
/**
|
|
486
489
|
* draw an arc
|
|
487
|
-
*
|
|
490
|
+
* A circular arc around (x, y), from the angle start to end in degrees: 0 is the top,
|
|
491
|
+
* 90 the right (clockwise). It starts a new subpath at its first point.
|
|
488
492
|
*
|
|
489
|
-
* @param x - The x-coordinate of the center
|
|
490
|
-
* @param y - The y-coordinate of the center
|
|
493
|
+
* @param x - The x-coordinate of the center.
|
|
494
|
+
* @param y - The y-coordinate of the center.
|
|
491
495
|
* @param r - The radius of the arc.
|
|
492
|
-
* @param start - The start angle of the arc in degrees (0 is
|
|
496
|
+
* @param start - The start angle of the arc in degrees (0 is the top, 90 is the right).
|
|
493
497
|
* @param end - The end angle of the arc in degrees.
|
|
494
498
|
* @param clockwise - If `true`, the arc is drawn clockwise; otherwise, counter-clockwise. Defaults to `true`.
|
|
495
499
|
*
|
|
@@ -612,12 +616,16 @@ export class SvgIcon extends SvgItem {
|
|
|
612
616
|
constructor( svg: string ) {
|
|
613
617
|
super( "svg" );
|
|
614
618
|
|
|
619
|
+
// a data url is decoded when it is encoded ("data:image/svg+xml,%3Csvg..."), a raw svg never
|
|
615
620
|
if( svg.startsWith("data:image/svg+xml,") ) {
|
|
616
621
|
svg = svg.substring( 19 );
|
|
622
|
+
if( !svg.startsWith( "<" ) ) {
|
|
623
|
+
svg = decodeURIComponent( svg );
|
|
624
|
+
}
|
|
617
625
|
}
|
|
618
626
|
|
|
619
627
|
const parser = new DOMParser();
|
|
620
|
-
const doc = parser.parseFromString(
|
|
628
|
+
const doc = parser.parseFromString( svg, "image/svg+xml");
|
|
621
629
|
|
|
622
630
|
const parserErrorElement = doc.querySelector("parsererror");
|
|
623
631
|
if( parserErrorElement ) {
|
|
@@ -629,11 +637,9 @@ export class SvgIcon extends SvgItem {
|
|
|
629
637
|
this._dom.setAttribute( svgRoot.attributes[i].name, svgRoot.attributes[i].value );
|
|
630
638
|
}
|
|
631
639
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
this._dom.appendChild(child);
|
|
636
|
-
}
|
|
640
|
+
// the elements, all of them: each one moved leaves the list
|
|
641
|
+
for( const child of Array.from( svgRoot.children ) ) {
|
|
642
|
+
this._dom.appendChild( child );
|
|
637
643
|
}
|
|
638
644
|
}
|
|
639
645
|
}
|
|
@@ -707,7 +713,9 @@ export class SvgGradient extends SvgItem {
|
|
|
707
713
|
* @returns The current `SvgGradient` instance for chaining.
|
|
708
714
|
*/
|
|
709
715
|
addStop( offset: number_or_perc, color: string ): this {
|
|
710
|
-
|
|
716
|
+
// a number is a percentage: 20 is "20%"
|
|
717
|
+
const o = isString( offset ) ? offset : offset + "%";
|
|
718
|
+
this._dom.insertAdjacentHTML( "beforeend", `<stop offset="${o}" stop-color="${color}"></stop>`);
|
|
711
719
|
return this;
|
|
712
720
|
}
|
|
713
721
|
}
|
package/src/core/core_tools.ts
CHANGED
|
@@ -124,8 +124,8 @@ export function unsafeHtml(x: string): UnsafeHtml {
|
|
|
124
124
|
export function unsafe(strings: TemplateStringsArray, ...values: any[]): UnsafeHtml {
|
|
125
125
|
|
|
126
126
|
const resolve = ( value: any ) : string | UnsafeHtml => {
|
|
127
|
-
|
|
128
|
-
if(
|
|
127
|
+
// nothing to write: null, undefined (after the last part of the template)
|
|
128
|
+
if( value===undefined || value===null ) {
|
|
129
129
|
return "";
|
|
130
130
|
}
|
|
131
131
|
|
|
@@ -137,7 +137,8 @@ export function unsafe(strings: TemplateStringsArray, ...values: any[]): UnsafeH
|
|
|
137
137
|
return value.toString();
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
// a number, a boolean...: its text, escaped
|
|
141
|
+
return sanitizeHtml( String( value ) );
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
const result = strings.reduce((acc, str, i) => {
|
|
@@ -561,7 +562,8 @@ export function date_format(date: Date, options?: any): string {
|
|
|
561
562
|
|
|
562
563
|
export function date_diff(date1: Date, date2: Date, options?: any): string {
|
|
563
564
|
|
|
564
|
-
|
|
565
|
+
// the gap, whichever date comes first
|
|
566
|
+
let dt = Math.abs(date1.getTime() - date2.getTime()) / 1000;
|
|
565
567
|
|
|
566
568
|
// seconds
|
|
567
569
|
let sec = dt;
|
|
@@ -575,7 +577,7 @@ export function date_diff(date1: Date, date2: Date, options?: any): string {
|
|
|
575
577
|
return sprintf(_tr.global.diff_date_minutes, Math.round(min));
|
|
576
578
|
}
|
|
577
579
|
|
|
578
|
-
// hours
|
|
580
|
+
// hours, and the minutes left
|
|
579
581
|
let hrs = Math.floor(min / 60);
|
|
580
582
|
return sprintf(_tr.global.diff_date_hours, hrs, min % 60);
|
|
581
583
|
}
|
|
@@ -626,13 +628,20 @@ export function date_clone(date: Date): Date {
|
|
|
626
628
|
}
|
|
627
629
|
|
|
628
630
|
/**
|
|
629
|
-
* return the week number of a date
|
|
631
|
+
* return the week number of a date, ISO 8601: weeks from monday,
|
|
632
|
+
* the week 1 holds the first thursday of the year (the 29/12/2025 is in the week 1 of 2026)
|
|
630
633
|
*/
|
|
631
634
|
|
|
632
635
|
export function date_calc_weeknum(date: Date): number {
|
|
633
|
-
|
|
634
|
-
const
|
|
635
|
-
|
|
636
|
+
// in UTC: a day of 23 or 25 hours (summer time) does not move the weeks
|
|
637
|
+
const d = new Date( Date.UTC( date.getFullYear( ), date.getMonth( ), date.getDate( ) ) );
|
|
638
|
+
|
|
639
|
+
// the thursday of its week gives the year of the week
|
|
640
|
+
const day = d.getUTCDay( ) || 7; // monday 1 .. sunday 7
|
|
641
|
+
d.setUTCDate( d.getUTCDate( ) + 4 - day );
|
|
642
|
+
|
|
643
|
+
const jan1 = Date.UTC( d.getUTCFullYear( ), 0, 1 );
|
|
644
|
+
return Math.ceil( ( ( d.getTime( ) - jan1 ) / 86400000 + 1 ) / 7 );
|
|
636
645
|
}
|
|
637
646
|
|
|
638
647
|
|