uicore-ts 1.1.101 → 1.1.102
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/compiledScripts/UICore.js +3 -0
- package/compiledScripts/UICore.js.map +2 -2
- package/compiledScripts/UITableView.d.ts +33 -0
- package/compiledScripts/UITableView.js +213 -25
- package/compiledScripts/UITableView.js.map +3 -3
- package/compiledScripts/UITextView.d.ts +49 -39
- package/compiledScripts/UITextView.js +131 -132
- package/compiledScripts/UITextView.js.map +2 -2
- package/compiledScripts/UIView.d.ts +21 -1
- package/compiledScripts/UIView.js +66 -8
- package/compiledScripts/UIView.js.map +2 -2
- package/package.json +1 -1
- package/scripts/UICore.ts +5 -0
- package/scripts/UITableView.ts +328 -93
- package/scripts/UITextView.ts +266 -376
- package/scripts/UIView.ts +131 -7
package/scripts/UITextView.ts
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
import { UIColor } from "./UIColor"
|
|
2
2
|
import { UILocalizedTextObject } from "./UIInterfaces"
|
|
3
|
-
import { FIRST,
|
|
3
|
+
import { FIRST, IS_LIKE_NULL, nil, NO, UIObject, ValueOf, YES } from "./UIObject"
|
|
4
4
|
import { UIRectangle } from "./UIRectangle"
|
|
5
|
-
import type { ValueOf } from "./UIObject"
|
|
6
5
|
import { TextMeasurementStyle, UITextMeasurement } from "./UITextMeasurement"
|
|
7
6
|
import { UIView, UIViewBroadcastEvent } from "./UIView"
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
export class UITextView extends UIView {
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
_textColor: UIColor = UITextView.defaultTextColor
|
|
14
|
-
_textAlignment?: ValueOf<typeof UITextView.textAlignment>
|
|
15
|
-
|
|
16
|
-
_isSingleLine = YES
|
|
17
|
-
|
|
18
|
-
textPrefix = ""
|
|
19
|
-
textSuffix = ""
|
|
20
|
-
|
|
21
|
-
_notificationAmount = 0
|
|
22
|
-
|
|
23
|
-
_minFontSize?: number
|
|
24
|
-
_maxFontSize?: number
|
|
25
|
-
|
|
26
|
-
_automaticFontSizeSelection = NO
|
|
27
|
-
|
|
28
|
-
changesOften = NO
|
|
11
|
+
//#region Static Properties
|
|
29
12
|
|
|
30
13
|
static defaultTextColor = UIColor.blackColor
|
|
31
14
|
static notificationTextColor = UIColor.redColor
|
|
@@ -34,19 +17,33 @@ export class UITextView extends UIView {
|
|
|
34
17
|
static _intrinsicHeightCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
35
18
|
static _intrinsicWidthCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
36
19
|
|
|
37
|
-
// Local cache for this instance if the label changes often
|
|
38
|
-
_intrinsicHeightCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
39
|
-
_intrinsicWidthCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
40
|
-
|
|
41
|
-
|
|
42
20
|
static _ptToPx: number
|
|
43
21
|
static _pxToPt: number
|
|
44
|
-
_text?: string
|
|
45
22
|
|
|
46
|
-
|
|
47
|
-
|
|
23
|
+
static type = {
|
|
24
|
+
"paragraph": "p",
|
|
25
|
+
"header1": "h1",
|
|
26
|
+
"header2": "h2",
|
|
27
|
+
"header3": "h3",
|
|
28
|
+
"header4": "h4",
|
|
29
|
+
"header5": "h5",
|
|
30
|
+
"header6": "h6",
|
|
31
|
+
"textArea": "textarea",
|
|
32
|
+
"textField": "input",
|
|
33
|
+
"span": "span",
|
|
34
|
+
"label": "label"
|
|
35
|
+
} as const
|
|
48
36
|
|
|
49
|
-
|
|
37
|
+
static textAlignment = {
|
|
38
|
+
"left": "left",
|
|
39
|
+
"center": "center",
|
|
40
|
+
"right": "right",
|
|
41
|
+
"justify": "justify"
|
|
42
|
+
} as const
|
|
43
|
+
|
|
44
|
+
//#endregion
|
|
45
|
+
|
|
46
|
+
//#region Constructor
|
|
50
47
|
|
|
51
48
|
constructor(
|
|
52
49
|
elementID?: string,
|
|
@@ -66,64 +63,128 @@ export class UITextView extends UIView {
|
|
|
66
63
|
|
|
67
64
|
this.userInteractionEnabled = YES
|
|
68
65
|
|
|
69
|
-
|
|
70
66
|
if (textViewType == UITextView.type.textArea) {
|
|
71
|
-
|
|
72
67
|
this.pausesPointerEvents = YES
|
|
73
|
-
|
|
74
68
|
this.addTargetForControlEvent(
|
|
75
69
|
UIView.controlEvent.PointerUpInside,
|
|
76
70
|
(sender, event) => sender.focus()
|
|
77
71
|
)
|
|
78
|
-
|
|
79
|
-
|
|
80
72
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
73
|
}
|
|
84
74
|
|
|
75
|
+
//#endregion
|
|
85
76
|
|
|
86
|
-
|
|
77
|
+
//#region Lifecycle Methods
|
|
78
|
+
|
|
79
|
+
override didReceiveBroadcastEvent(event: UIViewBroadcastEvent) {
|
|
80
|
+
super.didReceiveBroadcastEvent(event)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override willMoveToSuperview(superview: UIView) {
|
|
84
|
+
super.willMoveToSuperview(superview)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override layoutSubviews() {
|
|
88
|
+
super.layoutSubviews()
|
|
87
89
|
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
+
if (this._automaticFontSizeSelection) {
|
|
91
|
+
this.fontSize = UITextView.automaticallyCalculatedFontSize(
|
|
92
|
+
new UIRectangle(0, 0, 1 *
|
|
93
|
+
this.viewHTMLElement.offsetHeight, 1 *
|
|
94
|
+
this.viewHTMLElement.offsetWidth),
|
|
95
|
+
this.intrinsicContentSize(),
|
|
96
|
+
this.fontSize,
|
|
97
|
+
this._minFontSize,
|
|
98
|
+
this._maxFontSize
|
|
99
|
+
)
|
|
90
100
|
}
|
|
91
|
-
|
|
92
|
-
const o = document.createElement("div")
|
|
93
|
-
o.style.width = "1000pt"
|
|
94
|
-
document.body.appendChild(o)
|
|
95
|
-
UITextView._ptToPx = o.clientWidth / 1000
|
|
96
|
-
document.body.removeChild(o)
|
|
97
|
-
UITextView._pxToPt = 1 / UITextView._ptToPx
|
|
98
|
-
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
//#endregion
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
//#region Measurement & Sizing - Private Methods
|
|
106
|
+
|
|
107
|
+
private _invalidateMeasurementStyles(): void {
|
|
108
|
+
this._cachedMeasurementStyles = undefined
|
|
109
|
+
UITextMeasurement.invalidateElement(this.viewHTMLElement)
|
|
110
|
+
this._intrinsicSizesCache = {}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private _getMeasurementStyles(): TextMeasurementStyle {
|
|
114
|
+
if (this._cachedMeasurementStyles) {
|
|
115
|
+
return this._cachedMeasurementStyles
|
|
116
|
+
}
|
|
103
117
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
"header2": "h2",
|
|
107
|
-
"header3": "h3",
|
|
108
|
-
"header4": "h4",
|
|
109
|
-
"header5": "h5",
|
|
110
|
-
"header6": "h6",
|
|
111
|
-
"textArea": "textarea",
|
|
112
|
-
"textField": "input",
|
|
113
|
-
"span": "span",
|
|
114
|
-
"label": "label"
|
|
118
|
+
const computed = window.getComputedStyle(this.viewHTMLElement)
|
|
119
|
+
const fontSize = parseFloat(computed.fontSize)
|
|
115
120
|
|
|
116
|
-
|
|
121
|
+
this._cachedMeasurementStyles = {
|
|
122
|
+
font: [
|
|
123
|
+
computed.fontStyle,
|
|
124
|
+
computed.fontVariant,
|
|
125
|
+
computed.fontWeight,
|
|
126
|
+
computed.fontSize,
|
|
127
|
+
computed.fontFamily
|
|
128
|
+
].join(" "),
|
|
129
|
+
fontSize: fontSize,
|
|
130
|
+
lineHeight: this._parseLineHeight(computed.lineHeight, fontSize),
|
|
131
|
+
whiteSpace: computed.whiteSpace,
|
|
132
|
+
paddingLeft: parseFloat(computed.paddingLeft) || 0,
|
|
133
|
+
paddingRight: parseFloat(computed.paddingRight) || 0,
|
|
134
|
+
paddingTop: parseFloat(computed.paddingTop) || 0,
|
|
135
|
+
paddingBottom: parseFloat(computed.paddingBottom) || 0
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return this._cachedMeasurementStyles
|
|
139
|
+
}
|
|
117
140
|
|
|
141
|
+
private _parseLineHeight(lineHeight: string, fontSize: number): number {
|
|
142
|
+
if (lineHeight === "normal") {
|
|
143
|
+
return fontSize * 1.2
|
|
144
|
+
}
|
|
145
|
+
if (lineHeight.endsWith("px")) {
|
|
146
|
+
return parseFloat(lineHeight)
|
|
147
|
+
}
|
|
148
|
+
const numericLineHeight = parseFloat(lineHeight)
|
|
149
|
+
if (!isNaN(numericLineHeight)) {
|
|
150
|
+
return fontSize * numericLineHeight
|
|
151
|
+
}
|
|
152
|
+
return fontSize * 1.2
|
|
153
|
+
}
|
|
118
154
|
|
|
119
|
-
|
|
155
|
+
private _shouldUseFastMeasurement(): boolean {
|
|
156
|
+
const content = this.text || this.innerHTML
|
|
120
157
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
"justify": "justify"
|
|
158
|
+
if (this._innerHTMLKey || this._localizedTextObject) {
|
|
159
|
+
return false
|
|
160
|
+
}
|
|
125
161
|
|
|
126
|
-
|
|
162
|
+
if (this.notificationAmount > 0) {
|
|
163
|
+
return false
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const hasComplexHTML = /<(?!\/?(b|i|em|strong|span|br)\b)[^>]+>/i.test(content)
|
|
167
|
+
|
|
168
|
+
return !hasComplexHTML
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//#endregion
|
|
172
|
+
|
|
173
|
+
//#region Measurement & Sizing - Public Methods
|
|
174
|
+
|
|
175
|
+
setUseFastMeasurement(useFast: boolean): void {
|
|
176
|
+
this._useFastMeasurement = useFast
|
|
177
|
+
this._intrinsicSizesCache = {}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
invalidateMeasurementStrategy(): void {
|
|
181
|
+
this._useFastMeasurement = undefined
|
|
182
|
+
this._invalidateMeasurementStyles()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
|
|
187
|
+
//#region Getters & Setters - Text Alignment
|
|
127
188
|
|
|
128
189
|
get textAlignment() {
|
|
129
190
|
// @ts-ignore
|
|
@@ -135,81 +196,70 @@ export class UITextView extends UIView {
|
|
|
135
196
|
this.style.textAlign = textAlignment
|
|
136
197
|
}
|
|
137
198
|
|
|
199
|
+
//#endregion
|
|
200
|
+
|
|
201
|
+
//#region Getters & Setters - Text Color
|
|
138
202
|
|
|
139
203
|
get textColor() {
|
|
140
204
|
return this._textColor
|
|
141
205
|
}
|
|
142
206
|
|
|
143
207
|
set textColor(color: UIColor) {
|
|
144
|
-
|
|
145
208
|
this._textColor = color || UITextView.defaultTextColor
|
|
146
209
|
this.style.color = this._textColor.stringValue
|
|
147
|
-
|
|
148
210
|
}
|
|
149
211
|
|
|
212
|
+
//#endregion
|
|
213
|
+
|
|
214
|
+
//#region Getters & Setters - Single Line
|
|
150
215
|
|
|
151
216
|
get isSingleLine() {
|
|
152
|
-
|
|
153
217
|
return this._isSingleLine
|
|
154
|
-
|
|
155
218
|
}
|
|
156
219
|
|
|
157
220
|
set isSingleLine(isSingleLine: boolean) {
|
|
158
|
-
|
|
159
221
|
this._isSingleLine = isSingleLine
|
|
160
222
|
|
|
161
223
|
this._intrinsicHeightCache = new UIObject() as any
|
|
162
224
|
this._intrinsicWidthCache = new UIObject() as any
|
|
163
225
|
|
|
164
226
|
if (isSingleLine) {
|
|
165
|
-
|
|
166
227
|
this.style.whiteSpace = "pre"
|
|
167
|
-
|
|
168
228
|
return
|
|
169
|
-
|
|
170
229
|
}
|
|
171
230
|
|
|
172
231
|
this.style.whiteSpace = "pre-wrap"
|
|
173
|
-
|
|
174
232
|
this.invalidateMeasurementStrategy()
|
|
175
|
-
|
|
176
233
|
}
|
|
177
234
|
|
|
235
|
+
//#endregion
|
|
236
|
+
|
|
237
|
+
//#region Getters & Setters - Notification Amount
|
|
178
238
|
|
|
179
239
|
get notificationAmount() {
|
|
180
|
-
|
|
181
240
|
return this._notificationAmount
|
|
182
|
-
|
|
183
241
|
}
|
|
184
242
|
|
|
185
243
|
set notificationAmount(notificationAmount: number) {
|
|
186
|
-
|
|
187
244
|
if (this._notificationAmount == notificationAmount) {
|
|
188
|
-
|
|
189
245
|
return
|
|
190
|
-
|
|
191
246
|
}
|
|
192
247
|
|
|
193
248
|
this._notificationAmount = notificationAmount
|
|
194
|
-
|
|
195
249
|
this.text = this.text
|
|
196
|
-
|
|
197
250
|
this.setNeedsLayoutUpToRootView()
|
|
198
|
-
|
|
199
251
|
this.notificationAmountDidChange(notificationAmount)
|
|
200
|
-
|
|
201
252
|
}
|
|
202
253
|
|
|
203
254
|
notificationAmountDidChange(notificationAmount: number) {
|
|
204
|
-
|
|
205
|
-
|
|
206
255
|
}
|
|
207
256
|
|
|
257
|
+
//#endregion
|
|
258
|
+
|
|
259
|
+
//#region Getters & Setters - Text Content
|
|
208
260
|
|
|
209
261
|
get text() {
|
|
210
|
-
|
|
211
262
|
return (this._text || this.viewHTMLElement.innerHTML)
|
|
212
|
-
|
|
213
263
|
}
|
|
214
264
|
|
|
215
265
|
set text(text) {
|
|
@@ -228,7 +278,7 @@ export class UITextView extends UIView {
|
|
|
228
278
|
this._intrinsicHeightCache = new UIObject() as any
|
|
229
279
|
this._intrinsicWidthCache = new UIObject() as any
|
|
230
280
|
}
|
|
231
|
-
|
|
281
|
+
|
|
232
282
|
this._useFastMeasurement = undefined
|
|
233
283
|
this._intrinsicSizesCache = {}
|
|
234
284
|
this.invalidateMeasurementStrategy()
|
|
@@ -236,69 +286,117 @@ export class UITextView extends UIView {
|
|
|
236
286
|
this.clearIntrinsicSizeCache()
|
|
237
287
|
|
|
238
288
|
this.setNeedsLayout()
|
|
239
|
-
|
|
240
289
|
}
|
|
241
290
|
|
|
242
291
|
override set innerHTML(innerHTML: string) {
|
|
243
|
-
|
|
244
292
|
this.text = innerHTML
|
|
245
293
|
this.invalidateMeasurementStrategy()
|
|
246
|
-
|
|
247
294
|
}
|
|
248
295
|
|
|
249
296
|
override get innerHTML() {
|
|
250
|
-
|
|
251
297
|
return this.viewHTMLElement.innerHTML
|
|
252
|
-
|
|
253
298
|
}
|
|
254
299
|
|
|
255
|
-
|
|
256
300
|
setText(key: string, defaultString: string, parameters?: { [x: string]: string | UILocalizedTextObject }) {
|
|
257
|
-
|
|
258
301
|
this.setInnerHTML(key, defaultString, parameters)
|
|
259
302
|
this.invalidateMeasurementStrategy()
|
|
260
|
-
|
|
261
303
|
}
|
|
262
304
|
|
|
305
|
+
//#endregion
|
|
306
|
+
|
|
307
|
+
//#region Getters & Setters - Font Size
|
|
263
308
|
|
|
264
309
|
get fontSize() {
|
|
265
|
-
|
|
266
310
|
const style = this.style.fontSize || window.getComputedStyle(this.viewHTMLElement, null).fontSize
|
|
267
|
-
|
|
268
311
|
const result = (parseFloat(style) * UITextView._pxToPt)
|
|
269
|
-
|
|
270
312
|
return result
|
|
271
|
-
|
|
272
313
|
}
|
|
273
314
|
|
|
274
315
|
set fontSize(fontSize: number) {
|
|
275
|
-
|
|
276
316
|
if (fontSize != this.fontSize) {
|
|
277
|
-
|
|
278
317
|
this.style.fontSize = "" + fontSize + "pt"
|
|
279
318
|
|
|
280
319
|
this._intrinsicHeightCache = new UIObject() as any
|
|
281
|
-
this._intrinsicWidthCache = new UIObject() as any
|
|
320
|
+
this._intrinsicWidthCache = new UIObject() as any
|
|
282
321
|
|
|
283
|
-
this.
|
|
322
|
+
this._invalidateFontCache()
|
|
323
|
+
this._invalidateMeasurementStyles()
|
|
284
324
|
this.clearIntrinsicSizeCache()
|
|
285
|
-
|
|
286
325
|
}
|
|
287
|
-
|
|
288
326
|
}
|
|
289
327
|
|
|
290
|
-
|
|
291
328
|
useAutomaticFontSize(minFontSize: number = nil, maxFontSize: number = nil) {
|
|
292
|
-
|
|
293
329
|
this._automaticFontSizeSelection = YES
|
|
294
|
-
|
|
295
330
|
this._minFontSize = minFontSize
|
|
296
331
|
this._maxFontSize = maxFontSize
|
|
297
|
-
|
|
298
332
|
this.setNeedsLayout()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
//#endregion
|
|
336
|
+
|
|
337
|
+
//#region Font Caching - Private Methods
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get a stable cache key for the font without triggering reflow.
|
|
341
|
+
* Only computes font on first access or when font properties change.
|
|
342
|
+
*/
|
|
343
|
+
private _getFontCacheKey(): string {
|
|
344
|
+
// Check if font-related properties have changed
|
|
345
|
+
const currentTriggers = {
|
|
346
|
+
fontSize: this.style.fontSize || "",
|
|
347
|
+
fontFamily: this.style.fontFamily || "",
|
|
348
|
+
fontWeight: this.style.fontWeight || "",
|
|
349
|
+
fontStyle: this.style.fontStyle || "",
|
|
350
|
+
styleClasses: this.styleClasses.join(",")
|
|
351
|
+
}
|
|
299
352
|
|
|
353
|
+
const hasChanged =
|
|
354
|
+
currentTriggers.fontSize !== this._fontInvalidationTriggers.fontSize ||
|
|
355
|
+
currentTriggers.fontFamily !== this._fontInvalidationTriggers.fontFamily ||
|
|
356
|
+
currentTriggers.fontWeight !== this._fontInvalidationTriggers.fontWeight ||
|
|
357
|
+
currentTriggers.fontStyle !== this._fontInvalidationTriggers.fontStyle ||
|
|
358
|
+
currentTriggers.styleClasses !== this._fontInvalidationTriggers.styleClasses
|
|
359
|
+
|
|
360
|
+
if (!this._cachedFontKey || hasChanged) {
|
|
361
|
+
// Only access computedStyle when we know something changed
|
|
362
|
+
const computed = this.computedStyle
|
|
363
|
+
this._cachedFontKey = [
|
|
364
|
+
computed.fontStyle,
|
|
365
|
+
computed.fontVariant,
|
|
366
|
+
computed.fontWeight,
|
|
367
|
+
computed.fontSize,
|
|
368
|
+
computed.fontFamily
|
|
369
|
+
].join("_").replace(/[.\s]/g, "_")
|
|
370
|
+
|
|
371
|
+
this._fontInvalidationTriggers = currentTriggers
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return this._cachedFontKey
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Invalidate font cache when font properties change
|
|
379
|
+
*/
|
|
380
|
+
private _invalidateFontCache(): void {
|
|
381
|
+
this._cachedFontKey = undefined
|
|
300
382
|
}
|
|
301
383
|
|
|
384
|
+
//#endregion
|
|
385
|
+
|
|
386
|
+
//#region Static Methods
|
|
387
|
+
|
|
388
|
+
static _determinePXAndPTRatios() {
|
|
389
|
+
if (UITextView._ptToPx) {
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const o = document.createElement("div")
|
|
394
|
+
o.style.width = "1000pt"
|
|
395
|
+
document.body.appendChild(o)
|
|
396
|
+
UITextView._ptToPx = o.clientWidth / 1000
|
|
397
|
+
document.body.removeChild(o)
|
|
398
|
+
UITextView._pxToPt = 1 / UITextView._ptToPx
|
|
399
|
+
}
|
|
302
400
|
|
|
303
401
|
static automaticallyCalculatedFontSize(
|
|
304
402
|
bounds: UIRectangle,
|
|
@@ -307,7 +405,6 @@ export class UITextView extends UIView {
|
|
|
307
405
|
minFontSize?: number,
|
|
308
406
|
maxFontSize?: number
|
|
309
407
|
) {
|
|
310
|
-
|
|
311
408
|
minFontSize = FIRST(minFontSize, 1)
|
|
312
409
|
maxFontSize = FIRST(maxFontSize, 100000000000)
|
|
313
410
|
|
|
@@ -330,328 +427,121 @@ export class UITextView extends UIView {
|
|
|
330
427
|
}
|
|
331
428
|
|
|
332
429
|
return maxFittingFontSize
|
|
333
|
-
|
|
334
430
|
}
|
|
335
431
|
|
|
432
|
+
//#endregion
|
|
336
433
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
super.didReceiveBroadcastEvent(event)
|
|
340
|
-
|
|
341
|
-
}
|
|
434
|
+
//#region Instance Properties - Text Content
|
|
342
435
|
|
|
436
|
+
_text?: string
|
|
437
|
+
textPrefix = ""
|
|
438
|
+
textSuffix = ""
|
|
439
|
+
_notificationAmount = 0
|
|
343
440
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
super.willMoveToSuperview(superview)
|
|
347
|
-
|
|
348
|
-
}
|
|
441
|
+
//#endregion
|
|
349
442
|
|
|
443
|
+
//#region Instance Properties - Styling
|
|
350
444
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
445
|
+
_textColor: UIColor = UITextView.defaultTextColor
|
|
446
|
+
_textAlignment?: ValueOf<typeof UITextView.textAlignment>
|
|
447
|
+
_isSingleLine = YES
|
|
448
|
+
|
|
449
|
+
//#endregion
|
|
450
|
+
|
|
451
|
+
//#region Instance Properties - Font & Sizing
|
|
452
|
+
|
|
453
|
+
_minFontSize?: number
|
|
454
|
+
_maxFontSize?: number
|
|
455
|
+
_automaticFontSizeSelection = NO
|
|
456
|
+
|
|
457
|
+
// Cache for the computed font string
|
|
458
|
+
private _cachedFontKey?: string
|
|
459
|
+
private _fontInvalidationTriggers = {
|
|
460
|
+
fontSize: this.style.fontSize || "",
|
|
461
|
+
fontFamily: this.style.fontFamily || "",
|
|
462
|
+
fontWeight: this.style.fontWeight || "",
|
|
463
|
+
fontStyle: this.style.fontStyle || "",
|
|
464
|
+
styleClasses: this.styleClasses.join(",")
|
|
372
465
|
}
|
|
373
466
|
|
|
467
|
+
//#endregion
|
|
468
|
+
|
|
469
|
+
//#region Instance Properties - Caching & Performance
|
|
470
|
+
|
|
471
|
+
changesOften = NO
|
|
472
|
+
|
|
473
|
+
// Local cache for this instance if the label changes often
|
|
474
|
+
_intrinsicHeightCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
475
|
+
_intrinsicWidthCache: { [x: string]: { [x: string]: number; }; } & UIObject = new UIObject() as any
|
|
476
|
+
|
|
477
|
+
private _useFastMeasurement: boolean | undefined
|
|
478
|
+
private _cachedMeasurementStyles: TextMeasurementStyle | undefined
|
|
479
|
+
|
|
480
|
+
override usesVirtualLayoutingForIntrinsicSizing = NO
|
|
481
|
+
|
|
482
|
+
//#endregion
|
|
483
|
+
|
|
484
|
+
|
|
374
485
|
|
|
375
486
|
override intrinsicContentHeight(constrainingWidth = 0) {
|
|
376
487
|
|
|
377
|
-
const keyPath = (this.viewHTMLElement.innerHTML + "_csf_" + this.
|
|
378
|
-
"\\.",
|
|
379
|
-
"g"
|
|
380
|
-
), "_") + "." +
|
|
488
|
+
const keyPath = (this.viewHTMLElement.innerHTML + "_csf_" + this._getFontCacheKey()) + "." +
|
|
381
489
|
("" + constrainingWidth).replace(new RegExp("\\.", "g"), "_")
|
|
382
490
|
|
|
383
491
|
let cacheObject = UITextView._intrinsicHeightCache
|
|
384
492
|
|
|
385
493
|
if (this.changesOften) {
|
|
386
|
-
|
|
387
|
-
// @ts-ignore
|
|
388
494
|
cacheObject = this._intrinsicHeightCache
|
|
389
|
-
|
|
390
|
-
|
|
391
495
|
}
|
|
392
496
|
|
|
393
|
-
|
|
394
497
|
var result = cacheObject.valueForKeyPath(keyPath)
|
|
395
498
|
|
|
396
|
-
|
|
397
499
|
if (IS_LIKE_NULL(result)) {
|
|
398
|
-
|
|
399
500
|
result = super.intrinsicContentHeight(constrainingWidth)
|
|
400
|
-
|
|
401
501
|
cacheObject.setValueForKeyPath(keyPath, result)
|
|
402
|
-
|
|
403
|
-
|
|
404
502
|
}
|
|
405
503
|
|
|
406
|
-
|
|
407
|
-
if (isNaN(result) || (!result && !this.text) ) {
|
|
408
|
-
|
|
409
|
-
// console.error("Failed to calculate intrinsic height (" + this.elementID + ")", this, this.viewHTMLElement)
|
|
410
|
-
var asd = 1
|
|
411
|
-
|
|
504
|
+
if (isNaN(result) || (!result && !this.text)) {
|
|
412
505
|
result = super.intrinsicContentHeight(constrainingWidth)
|
|
413
|
-
|
|
414
506
|
cacheObject.setValueForKeyPath(keyPath, result)
|
|
415
|
-
|
|
416
|
-
var asdasd = 1
|
|
417
|
-
|
|
418
|
-
|
|
419
507
|
}
|
|
420
508
|
|
|
421
509
|
return result
|
|
422
|
-
|
|
423
510
|
}
|
|
424
511
|
|
|
425
512
|
override intrinsicContentWidth(constrainingHeight = 0) {
|
|
426
513
|
|
|
427
|
-
const keyPath = (this.viewHTMLElement.innerHTML + "_csf_" + this.
|
|
428
|
-
"\\.",
|
|
429
|
-
"g"
|
|
430
|
-
), "_") + "." +
|
|
514
|
+
const keyPath = (this.viewHTMLElement.innerHTML + "_csf_" + this._getFontCacheKey()) + "." +
|
|
431
515
|
("" + constrainingHeight).replace(new RegExp("\\.", "g"), "_")
|
|
432
516
|
|
|
433
517
|
let cacheObject = UITextView._intrinsicWidthCache
|
|
434
518
|
|
|
435
519
|
if (this.changesOften) {
|
|
436
|
-
|
|
437
|
-
// @ts-ignore
|
|
438
520
|
cacheObject = this._intrinsicWidthCache
|
|
439
|
-
|
|
440
|
-
|
|
441
521
|
}
|
|
442
522
|
|
|
443
|
-
|
|
444
523
|
var result = cacheObject.valueForKeyPath(keyPath)
|
|
445
524
|
|
|
446
|
-
|
|
447
525
|
if (IS_LIKE_NULL(result)) {
|
|
448
|
-
|
|
449
526
|
result = super.intrinsicContentWidth(constrainingHeight)
|
|
450
|
-
|
|
451
527
|
cacheObject.setValueForKeyPath(keyPath, result)
|
|
452
|
-
|
|
453
|
-
|
|
454
528
|
}
|
|
455
529
|
|
|
456
|
-
|
|
457
530
|
return result
|
|
458
|
-
|
|
459
531
|
}
|
|
460
532
|
|
|
461
533
|
|
|
462
|
-
//
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
this._intrinsicSizesCache = {}
|
|
534
|
+
// Override addStyleClass to invalidate font cache
|
|
535
|
+
override addStyleClass(styleClass: string) {
|
|
536
|
+
super.addStyleClass(styleClass)
|
|
537
|
+
this._invalidateFontCache()
|
|
467
538
|
}
|
|
468
539
|
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Only call getComputedStyle once and cache the result
|
|
476
|
-
const computed = window.getComputedStyle(this.viewHTMLElement)
|
|
477
|
-
const fontSize = parseFloat(computed.fontSize)
|
|
478
|
-
|
|
479
|
-
this._cachedMeasurementStyles = {
|
|
480
|
-
font: [
|
|
481
|
-
computed.fontStyle,
|
|
482
|
-
computed.fontVariant,
|
|
483
|
-
computed.fontWeight,
|
|
484
|
-
computed.fontSize,
|
|
485
|
-
computed.fontFamily
|
|
486
|
-
].join(" "),
|
|
487
|
-
fontSize: fontSize,
|
|
488
|
-
lineHeight: this._parseLineHeight(computed.lineHeight, fontSize),
|
|
489
|
-
whiteSpace: computed.whiteSpace,
|
|
490
|
-
paddingLeft: parseFloat(computed.paddingLeft) || 0,
|
|
491
|
-
paddingRight: parseFloat(computed.paddingRight) || 0,
|
|
492
|
-
paddingTop: parseFloat(computed.paddingTop) || 0,
|
|
493
|
-
paddingBottom: parseFloat(computed.paddingBottom) || 0
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
return this._cachedMeasurementStyles
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
private _parseLineHeight(lineHeight: string, fontSize: number): number {
|
|
500
|
-
if (lineHeight === "normal") {
|
|
501
|
-
return fontSize * 1.2
|
|
502
|
-
}
|
|
503
|
-
if (lineHeight.endsWith("px")) {
|
|
504
|
-
return parseFloat(lineHeight)
|
|
505
|
-
}
|
|
506
|
-
const numericLineHeight = parseFloat(lineHeight)
|
|
507
|
-
if (!isNaN(numericLineHeight)) {
|
|
508
|
-
return fontSize * numericLineHeight
|
|
509
|
-
}
|
|
510
|
-
return fontSize * 1.2
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
// Override the intrinsic size method
|
|
514
|
-
override intrinsicContentSizeWithConstraints(
|
|
515
|
-
constrainingHeight: number = 0,
|
|
516
|
-
constrainingWidth: number = 0
|
|
517
|
-
): UIRectangle {
|
|
518
|
-
const cacheKey = "h_" + constrainingHeight + "__w_" + constrainingWidth
|
|
519
|
-
const cachedResult = this._intrinsicSizesCache[cacheKey]
|
|
520
|
-
if (cachedResult) {
|
|
521
|
-
return cachedResult
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// Determine measurement strategy
|
|
525
|
-
const shouldUseFastPath = this._useFastMeasurement ?? this._shouldUseFastMeasurement()
|
|
526
|
-
|
|
527
|
-
let result: UIRectangle
|
|
528
|
-
|
|
529
|
-
if (shouldUseFastPath) {
|
|
530
|
-
// Fast path: canvas-based measurement with pre-extracted styles
|
|
531
|
-
const styles = this._getMeasurementStyles()
|
|
532
|
-
const size = UITextMeasurement.calculateTextSize(
|
|
533
|
-
this.viewHTMLElement,
|
|
534
|
-
this.text || this.innerHTML,
|
|
535
|
-
constrainingWidth || undefined,
|
|
536
|
-
constrainingHeight || undefined,
|
|
537
|
-
styles // Pass pre-computed styles to avoid getComputedStyle!
|
|
538
|
-
)
|
|
539
|
-
result = new UIRectangle(0, 0, size.height, size.width)
|
|
540
|
-
}
|
|
541
|
-
else {
|
|
542
|
-
// Fallback: original DOM-based measurement for complex content
|
|
543
|
-
result = super.intrinsicContentSizeWithConstraints(constrainingHeight, constrainingWidth)
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
if (isNaN(result.height) || isNaN(result.width)) {
|
|
547
|
-
|
|
548
|
-
// console.error("Failed to calculate intrinsic height (" + this.elementID + ")", this)
|
|
549
|
-
var asd = 1
|
|
550
|
-
|
|
551
|
-
// Fallback: original DOM-based measurement
|
|
552
|
-
result = super.intrinsicContentSizeWithConstraints(constrainingHeight, constrainingWidth)
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
this._intrinsicSizesCache[cacheKey] = result.copy()
|
|
558
|
-
return result
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// Helper to determine if we can use fast measurement
|
|
562
|
-
private _shouldUseFastMeasurement(): boolean {
|
|
563
|
-
const content = this.text || this.innerHTML
|
|
564
|
-
|
|
565
|
-
// If using dynamic innerHTML with parameters, use DOM measurement
|
|
566
|
-
if (this._innerHTMLKey || this._localizedTextObject) {
|
|
567
|
-
return false
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// Check for notification badges
|
|
571
|
-
if (this.notificationAmount > 0) {
|
|
572
|
-
return false // Has span with colored text
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Check content complexity
|
|
576
|
-
const hasComplexHTML = /<(?!\/?(b|i|em|strong|span|br)\b)[^>]+>/i.test(content)
|
|
577
|
-
|
|
578
|
-
return !hasComplexHTML
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Optional: Allow manual override for specific instances
|
|
582
|
-
setUseFastMeasurement(useFast: boolean): void {
|
|
583
|
-
this._useFastMeasurement = useFast
|
|
584
|
-
this._intrinsicSizesCache = {}
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Optional: Force re-evaluation of measurement strategy
|
|
588
|
-
invalidateMeasurementStrategy(): void {
|
|
589
|
-
this._useFastMeasurement = undefined
|
|
590
|
-
this._invalidateMeasurementStyles()
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
override intrinsicContentSize() {
|
|
595
|
-
|
|
596
|
-
// This works but is slow
|
|
597
|
-
const result = this.intrinsicContentSizeWithConstraints(nil, nil)
|
|
598
|
-
|
|
599
|
-
return result
|
|
600
|
-
|
|
540
|
+
// Override removeStyleClass to invalidate font cache
|
|
541
|
+
override removeStyleClass(styleClass: string) {
|
|
542
|
+
super.removeStyleClass(styleClass)
|
|
543
|
+
this._invalidateFontCache()
|
|
601
544
|
}
|
|
602
545
|
|
|
603
546
|
|
|
604
547
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
UITextView._determinePXAndPTRatios()
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
// /**
|
|
611
|
-
// * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
|
|
612
|
-
// *
|
|
613
|
-
// * @param {String} text The text to be rendered.
|
|
614
|
-
// * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
|
|
615
|
-
// *
|
|
616
|
-
// * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
|
|
617
|
-
// */
|
|
618
|
-
// function getTextMetrics(text, font) {
|
|
619
|
-
// // re-use canvas object for better performance
|
|
620
|
-
// var canvas = getTextMetrics.canvas || (getTextMetrics.canvas = document.createElement("canvas"));
|
|
621
|
-
// var context = canvas.getContext("2d");
|
|
622
|
-
// context.font = font;
|
|
623
|
-
// var metrics = context.measureText(text);
|
|
624
|
-
// return metrics;
|
|
625
|
-
// }
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|