@breakside/jskit 2022.24.0 → 2022.26.0

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.
Files changed (61) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/JSFileManager+Node.js +2 -2
  7. package/Frameworks/Foundation.jsframework/JS/JSURL.js +3 -0
  8. package/Frameworks/Foundation.jsframework/JS/JSZip.js +97 -76
  9. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  10. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  11. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  12. package/Info.json +2 -2
  13. package/Node/io.breakside.jskit-bundle.js +2 -2
  14. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  15. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  16. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  17. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  18. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  19. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  20. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  21. package/Root/Frameworks/DOM/Info.yaml +1 -1
  22. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  23. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  24. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  25. package/Root/Frameworks/Foundation/JSFileManager+Node.js +2 -2
  26. package/Root/Frameworks/Foundation/JSURL.js +3 -0
  27. package/Root/Frameworks/Foundation/JSZip.js +97 -76
  28. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  29. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  30. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  31. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  32. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  33. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  34. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  35. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  36. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  37. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  38. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  39. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  40. package/Root/Frameworks/UIKit/UIBasicAnimation.js +1 -1
  41. package/Root/Frameworks/UIKit/UICursor.js +19 -4
  42. package/Root/Frameworks/UIKit/UIHTMLApplication.js +53 -15
  43. package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +2 -48
  44. package/Root/Frameworks/UIKit/UIHTMLDisplayServerContext.js +0 -6
  45. package/Root/Frameworks/UIKit/UIHTMLDisplayServerSVGContext.js +6 -77
  46. package/Root/Frameworks/UIKit/UIHTMLTextField.js +9 -3
  47. package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +2 -29
  48. package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +6 -79
  49. package/Root/Frameworks/UIKit/UIImageLayer.js +14 -7
  50. package/Root/Frameworks/UIKit/UILabel.js +74 -1
  51. package/Root/Frameworks/UIKit/UIMouseTrackingArea.js +55 -0
  52. package/Root/Frameworks/UIKit/UIState.js +23 -0
  53. package/Root/Frameworks/UIKit/UITextEditor.js +277 -76
  54. package/Root/Frameworks/UIKit/UITextEditorDelegate.js +3 -1
  55. package/Root/Frameworks/UIKit/UITextLayer.js +1 -1
  56. package/Root/Frameworks/UIKit/UIView.js +118 -46
  57. package/Root/Frameworks/UIKit/UIViewController.js +6 -0
  58. package/Root/Frameworks/UIKit/UIWindow.js +89 -0
  59. package/Root/Frameworks/UIKit/UIWindowServer.js +20 -79
  60. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  61. package/package.json +1 -1
@@ -25,7 +25,6 @@
25
25
  // Context element
26
26
  // g
27
27
  // shadow?
28
- // tracking?
29
28
  // backgroundColor?
30
29
  // backgroundGradient?
31
30
  // customDrawing?
@@ -35,7 +34,6 @@
35
34
 
36
35
  JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
37
36
 
38
- _trackingIndex: 0,
39
37
  _backgroundIndex: 0,
40
38
  _backgroundGradientIndex: 0,
41
39
  _sublayersIndex: 0,
@@ -56,15 +54,7 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
56
54
  this.element.style.left = '0';
57
55
  this._definitions = _UIHTMLDisplayServerSVGContextDefs.initWithSVGElement(this.element);
58
56
  this.element.appendChild(this._definitions.element);
59
- this._trackingPath = doc.createElementNS(SVGNamespace, "rect");
60
- this._trackingPath.x.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 0);
61
- this._trackingPath.x.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 0);
62
- this._trackingPath.width.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 100);
63
- this._trackingPath.height.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_NUMBER, 100);
64
- this._trackingPath.style.pointerEvents = 'all';
65
- this._trackingPath.style.visibility = 'hidden';
66
- this.element.appendChild(this._trackingPath);
67
- this._sublayersIndex = 2;
57
+ this._sublayersIndex = 1;
68
58
  },
69
59
 
70
60
  initForScreenContext: function(screenContext){
@@ -134,10 +124,6 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
134
124
  // only called for the root context, which has an svg element
135
125
  this.element.width.baseVal.value = size.width;
136
126
  this.element.height.baseVal.value = size.height;
137
- if (this._trackingPath){
138
- this._trackingPath.width.baseVal.value = size.width;
139
- this._trackingPath.height.baseVal.value = size.height;
140
- }
141
127
  },
142
128
 
143
129
  originTransform: null,
@@ -195,9 +181,6 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
195
181
  if (this._shadowPath !== null){
196
182
  this._updateShadowPath(layer);
197
183
  }
198
- if (this._trackingPath !== null){
199
- this._updateTrackingPath(layer);
200
- }
201
184
  if (this._boundsClipPath !== null){
202
185
  this._updateBoundsClipPath(layer);
203
186
  }
@@ -262,7 +245,6 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
262
245
  this._shadowPath.style.fill = 'black';
263
246
  this.element.insertBefore(this._shadowPath, this.element.childNodes[0]);
264
247
  this._updateShadowPath(layer);
265
- ++this._trackingIndex;
266
248
  ++this._backgroundIndex;
267
249
  ++this._backgroundGradientIndex;
268
250
  ++this._sublayersIndex;
@@ -539,68 +521,15 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
539
521
  },
540
522
 
541
523
  // ----------------------------------------------------------------------
542
- // MARK: - Tracking
543
-
544
- _trackingPath: null,
545
- trackingListener: null,
546
-
547
- startMouseTracking: function(trackingType, listener, layer){
548
- this._createTrackingPathIfNeeded(layer);
549
- if (this.trackingListener !== null){
550
- this._trackingPath.removeEventListener('mouseenter', this.trackingListener);
551
- this._trackingPath.removeEventListener('mouseleave', this.trackingListener);
552
- this._trackingPath.removeEventListener('mousemove', this.trackingListener);
553
- }
554
- this.trackingListener = listener;
555
- if (trackingType & UIView.MouseTracking.enterAndExit){
556
- this._trackingPath.addEventListener('mouseenter', this.trackingListener);
557
- this._trackingPath.addEventListener('mouseleave', this.trackingListener);
558
- }
559
- if (trackingType & UIView.MouseTracking.move){
560
- this._trackingPath.addEventListener('mousemove', this.trackingListener);
561
- }
562
- },
563
-
564
- stopMouseTracking: function(){
565
- if (this.trackingElement === null || this.trackingListener === null){
566
- return;
567
- }
568
- this._trackingPath.removeEventListener('mouseenter', this.trackingListener);
569
- this._trackingPath.removeEventListener('mouseleave', this.trackingListener);
570
- this._trackingPath.removeEventListener('mousemove', this.trackingListener);
571
- this.trackingListener = null;
572
- },
573
-
574
- _createTrackingPathIfNeeded: function(layer){
575
- if (this._trackingPath !== null){
576
- return null;
577
- }
578
- this._trackingPath = this.element.ownerDocument.createElementNS(SVGNamespace, "path");
579
- this._trackingPath.style.pointerEvents = 'visible';
580
- this._trackingPath.style.fill = 'none';
581
- this._trackingPath.style.stroke = 'none';
582
- this._updateTrackingPath(layer);
583
- this.element.insertBefore(this._trackingPath, this.element.childNodes[this._trackingIndex]);
584
- ++this._backgroundIndex;
585
- ++this._backgroundGradientIndex;
586
- ++this._sublayersIndex;
587
- },
588
-
589
- _updateTrackingPath: function(layer){
590
- this._trackingPath.pathSegList.clear();
591
- this._currentPath = this._trackingPath;
592
- this.addBorderPathForLayerProperties(layer.presentation, UILayer.Path.shadow);
593
- this._currentPath = null;
594
- },
524
+ // MARK: - Cursor
595
525
 
596
526
  setCursor: function(cursor, layer){
597
527
  if (cursor === null){
598
- if (this._trackingPath){
599
- this._trackingPath.style.cursor = '';
528
+ if (this.element){
529
+ this.element.style.cursor = '';
600
530
  }
601
531
  return;
602
532
  }
603
- this._createTrackingPathIfNeeded(layer);
604
533
  var cssCursorStrings = cursor.cssStrings();
605
534
  // UICursor.cssStrings() returns a set of css strings, one of which
606
535
  // should work in our browser, but some of which may fail because they
@@ -608,8 +537,8 @@ JSClass("UIHTMLDisplayServerSVGContext", UIHTMLDisplayServerContext, {
608
537
  // style.cursor is an empty string, so we'll keep going until it's
609
538
  // not an empty string, or we're out of options
610
539
  for (var i = 0, l = cssCursorStrings.length; i < l; ++i){
611
- this._trackingPath.style.cursor = cssCursorStrings[i];
612
- if (this._trackingPath.style.cursor !== ''){
540
+ this.element.style.cursor = cssCursorStrings[i];
541
+ if (this.element.style.cursor !== ''){
613
542
  break;
614
543
  }
615
544
  }
@@ -267,6 +267,7 @@ JSClass("UIHTMLTextField", UIControl, {
267
267
  this.inputElement.style.margin = "0";
268
268
  this.inputElement.style.webkitAppearance = "none";
269
269
  this.inputElement.style.backgroundColor = "transparent";
270
+ this.inputElement.style.webkitTapHighlightColor = "transparent";
270
271
  // this.inputElement.style.cursor = "text";
271
272
  this.inputElement.style.outline = "none";
272
273
  this.inputElement.setAttribute("role", "textbox");
@@ -425,10 +426,15 @@ JSClass("UIHTMLTextField", UIControl, {
425
426
 
426
427
  drawLayerInContext: function(layer, context){
427
428
  UIHTMLTextField.$super.drawLayerInContext.call(this, layer, context);
429
+ this.inputElement.style.boxSizing = "border-box";
430
+ this.inputElement.style.paddingLeft = this._textInsets.left + "px";
431
+ this.inputElement.style.paddingRight = this._textInsets.right + "px";
432
+ this.inputElement.style.paddingTop = this._textInsets.top + "px";
433
+ this.inputElement.style.paddingBottom = this._textInsets.bottom + "px";
428
434
  this.inputElement.style.width = layer.element.style.width;
429
435
  this.inputElement.style.height = layer.element.style.height;
430
- this.inputElement.value = this._text;
431
- this.inputElement.placeholder = this._placeholder;
436
+ this.inputElement.value = this._text || "";
437
+ this.inputElement.placeholder = this._placeholder || "";
432
438
  var autocomplete = htmlAutocompleteByTextContentType[this._textContentType];
433
439
  if (autocomplete === ""){
434
440
  if (this._secureEntry){
@@ -486,7 +492,7 @@ JSClass("UIHTMLTextField", UIControl, {
486
492
  },
487
493
 
488
494
  updateElementInsets: function(){
489
- var insets = JSInsets(this._textInsets);
495
+ var insets = JSInsets.Zero;
490
496
  if (this._leftAccessoryView !== null){
491
497
  insets.left += this._leftAccessoryInsets.width + this._leftAccessorySize.width;
492
498
  }
@@ -197,22 +197,7 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
197
197
  var backgroundColor = attributes[JSAttributedString.Attribute.backgroundColor];
198
198
  span.style.color = textColor ? textColor.cssString() : 'black';
199
199
  span.style.backgroundColor = backgroundColor ? backgroundColor.cssString() : '';
200
-
201
- // Cursor
202
- var cursor = attributes[JSAttributedString.Attribute.cursor];
203
- if (cursor){
204
- var cssCursorStrings = cursor.cssStrings();
205
- for (var i = 0, l = cssCursorStrings.length; i < l; ++i){
206
- span.style.cursor = cssCursorStrings[i];
207
- if (span.style.cursor !== ''){
208
- break;
209
- }
210
- }
211
- span.style.pointerEvents = 'all';
212
- }else{
213
- span.style.cursor = '';
214
- span.style.pointerEvents = 'none';
215
- }
200
+ span.style.pointerEvents = 'none';
216
201
  },
217
202
 
218
203
  _styleAttachmentElementWithAttributes: function(span, attributes, attachment){
@@ -226,18 +211,6 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
226
211
  span.style.color = '';
227
212
  span.style.backgroundColor = '';
228
213
  span.style.pointerEvents = 'all';
229
- var cursor = attributes[JSAttributedString.Attribute.cursor];
230
- if (cursor){
231
- var cssCursorStrings = cursor.cssStrings();
232
- for (var i = 0, l = cssCursorStrings.length; i < l; ++i){
233
- span.style.cursor = cssCursorStrings[i];
234
- if (span.style.cursor !== ''){
235
- break;
236
- }
237
- }
238
- }else{
239
- span.style.cursor = '';
240
- }
241
214
  },
242
215
 
243
216
  // MARK: - Private Helpers for Line Break Suggestion
@@ -272,7 +245,7 @@ JSClass("UIHTMLTextTypesetter", JSTextTypesetter, {
272
245
  }
273
246
  newline = iterator.isMandatoryLineBreak;
274
247
  printable = !newline && !iterator.isWhiteSpace;
275
- attachment = runIterator.attachment;
248
+ attachment = attributes[JSAttributedString.Attribute.attachment] || null;
276
249
  if (attachment !== null){
277
250
  attachment.layout(preferredFont, width);
278
251
  usedWidth += attachment.size.width;
@@ -43,7 +43,6 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
43
43
  this.rootElement = rootElement;
44
44
  this.domDocument = this.rootElement.ownerDocument;
45
45
  this.domWindow = this.domDocument.defaultView;
46
- this._cursorViewsById = {};
47
46
  this.setupRenderingEnvironment();
48
47
  this.setupEventListeners();
49
48
  this.startObservingAccessibilityNotifications();
@@ -112,24 +111,9 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
112
111
 
113
112
  // --------------------------------------------------------------------
114
113
  // MARK: - Cursor Management
115
-
116
- _cursorViewsById: null,
117
- _isOverridingCursor: false,
118
-
119
- viewDidChangeCursor: function(view, cursor){
120
- if (cursor === null){
121
- delete this._cursorViewsById[view.objecID];
122
- }else{
123
- this._cursorViewsById[view.objectID] = view;
124
- }
125
- if (!this._isOverridingCursor){
126
- var context = this.displayServer.contextForLayer(view.layer);
127
- context.setCursor(cursor, view.layer);
128
- }
129
- },
130
114
 
131
115
  hideCursor: function(){
132
- this._setCursor(UICursor.none, true);
116
+ this._setCursor(UICursor.none);
133
117
  },
134
118
 
135
119
  unhideCursor: function(){
@@ -137,60 +121,11 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
137
121
  },
138
122
 
139
123
  setCursor: function(cursor){
140
- this._setCursor(cursor, UICursor._stack.length > 1);
141
- },
142
-
143
- _setCursor: function(cursor, isOverride){
144
- this.displayServer.screenContext.setCursor(cursor, null);
145
- var id;
146
- var view;
147
- var context;
148
- if (isOverride){
149
- if (!this._isOverridingCursor){
150
- this._isOverridingCursor = true;
151
- for (id in this._cursorViewsById){
152
- context = this.displayServer.contextForLayer(this._cursorViewsById[id].layer);
153
- context.setCursor(null, this._cursorViewsById[id].layer);
154
- }
155
- }
156
- }else{
157
- if (this._isOverridingCursor){
158
- this._isOverridingCursor = false;
159
- for (id in this._cursorViewsById){
160
- view = this._cursorViewsById[id];
161
- context = this.displayServer.contextForLayer(view.layer);
162
- context.setCursor(view.cursor, view.layer);
163
- }
164
- }
165
- }
124
+ this._setCursor(cursor);
166
125
  },
167
126
 
168
- viewDidChangeMouseTracking: function(view, trackingType){
169
- var context = this.displayServer.contextForLayer(view.layer);
170
- var windowServer = this;
171
- if (trackingType === UIView.MouseTracking.none){
172
- context.stopMouseTracking();
173
- }else{
174
- var listener = {
175
- handleEvent: function(e){
176
- e.stopPropagation();
177
- this[e.type](e);
178
- },
179
-
180
- mouseenter: function(e){
181
- windowServer._createMouseTrackingEventFromDOMEvent(e, UIEvent.Type.mouseEntered, view);
182
- },
183
-
184
- mouseleave: function(e){
185
- windowServer._createMouseTrackingEventFromDOMEvent(e, UIEvent.Type.mouseExited, view);
186
- },
187
-
188
- mousemove: function(e){
189
- windowServer._createMouseTrackingEventFromDOMEvent(e, UIEvent.Type.mouseMoved, view);
190
- }
191
- };
192
- context.startMouseTracking(trackingType, listener, view.layer);
193
- }
127
+ _setCursor: function(cursor){
128
+ this.displayServer.screenContext.setCursor(cursor);
194
129
  },
195
130
 
196
131
  // --------------------------------------------------------------------
@@ -395,6 +330,8 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
395
330
  if (this._draggingSession === null || this._draggingSession.source === null){
396
331
  this.resetMouseState(e.timeStamp / 1000.0);
397
332
  }
333
+ var modifiers = this._modifiersFromDOMEvent(e);
334
+ this.mouseDidMove(e.timeStamp / 1000.0, modifiers);
398
335
  },
399
336
 
400
337
  wheel: function(e){
@@ -409,16 +346,6 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
409
346
  this.createMouseEvent(type, timestamp, this.mouseLocation, modifiers);
410
347
  },
411
348
 
412
- _createMouseTrackingEventFromDOMEvent: function(e, type, view){
413
- this._updateMouseLocation(e);
414
- var timestamp = e.timeStamp / 1000.0;
415
- var modifiers = this._modifiersFromDOMEvent(e);
416
- if (type === UIEvent.Type.mouseMoved){
417
- this.mouseDidMove(timestamp, modifiers);
418
- }
419
- this.createMouseTrackingEvent(type, timestamp, this.mouseLocation, modifiers, view);
420
- },
421
-
422
349
  _createScrollEventFromDOMEvent: function(e, type){
423
350
  var timestamp = e.timeStamp / 1000.0;
424
351
  var modifiers = this._modifiersFromDOMEvent(e);
@@ -19,13 +19,12 @@
19
19
  JSClass("UIImageLayer", UILayer, {
20
20
 
21
21
  image: JSDynamicProperty('_image', null),
22
- imageFrame: JSDynamicProperty('_imageFrame', null),
22
+ imageFrame: UILayerAnimatedProperty(),
23
23
  templateColor: UILayerAnimatedProperty(),
24
24
  automaticRenderMode: JSDynamicProperty('_automaticRenderMode', JSImage.RenderMode.original),
25
25
 
26
26
  init: function(){
27
27
  UIImageLayer.$super.init.call(this);
28
- this._imageFrame = JSRect.Zero;
29
28
  this.model.templateColor = JSColor.black;
30
29
  },
31
30
 
@@ -42,17 +41,20 @@ JSClass("UIImageLayer", UILayer, {
42
41
  },
43
42
 
44
43
  setImageFrame: function(imageFrame){
45
- this._imageFrame = imageFrame;
46
- this.setNeedsDisplay();
44
+ if (!imageFrame.isEqual(this.model.imageFrame)){
45
+ this._addImplicitAnimationForKey('imageFrame');
46
+ this.model.imageFrame = JSRect(imageFrame);
47
+ this.didChangeProperty('imageFrame');
48
+ }
47
49
  },
48
50
 
49
51
  drawInContext: function(context){
50
- if (this._image !== null && this._imageFrame.size.width > 0 && this._imageFrame.size.height > 0){
52
+ if (this._image !== null && this.presentation.imageFrame.size.width > 0 && this.presentation.imageFrame.size.height > 0){
51
53
  if (this._image.renderMode === JSImage.RenderMode.template || (this._image.renderMode === JSImage.RenderMode.automatic && this._automaticRenderMode === JSImage.RenderMode.template)){
52
54
  context.setFillColor(this.presentation.templateColor);
53
- context.fillMaskedRect(this._imageFrame, this._image);
55
+ context.fillMaskedRect(this.presentation.imageFrame, this._image);
54
56
  }else{
55
- context.drawImage(this._image, this._imageFrame);
57
+ context.drawImage(this._image, this.presentation.imageFrame);
56
58
  }
57
59
  }
58
60
  },
@@ -75,6 +77,11 @@ JSClass("UIImageLayer", UILayer, {
75
77
 
76
78
  UIImageLayer.Properties = Object.create(UILayer.Properties, {
77
79
 
80
+ imageFrame: {
81
+ writable: true,
82
+ value: JSRect.Zero
83
+ },
84
+
78
85
  templateColor: {
79
86
  writable: true,
80
87
  value: null
@@ -32,7 +32,6 @@ JSClass('UILabel', UIView, {
32
32
  textInsets: UIViewLayerProperty(),
33
33
  allowsSelection: JSDynamicProperty('_allowsSelection', false),
34
34
  selectionColor: JSDynamicProperty("_selectionColor", null),
35
- userInteractionEnabled: false,
36
35
  _accessibilityHidden: true,
37
36
 
38
37
  initWithFrame: function(frame){
@@ -40,10 +39,12 @@ JSClass('UILabel', UIView, {
40
39
  this.maximumNumberOfLines = 1;
41
40
  this.textColor = JSColor.text;
42
41
  this._selectionColor = JSColor.initWithUIStyles(JSColor.black.colorWithAlpha(0.2), JSColor.white.colorWithAlpha(0.2));
42
+ this.layer.textContainer.framesetter.typesetter.delegate = this;
43
43
  },
44
44
 
45
45
  initWithSpec: function(spec){
46
46
  UILabel.$super.initWithSpec.call(this, spec);
47
+ this.layer.textContainer.framesetter.typesetter.delegate = this;
47
48
  if (spec.containsKey("font")){
48
49
  this.font = spec.valueForKey("font", JSFont);
49
50
  }
@@ -373,6 +374,78 @@ JSClass('UILabel', UIView, {
373
374
  this._updateSelectionHighlightLayers();
374
375
  },
375
376
 
377
+ // -------------------------------------------------------------------------
378
+ // MARK: - Layout
379
+
380
+ sizeToFitSize: function(maxSize){
381
+ UILabel.$super.sizeToFitSize.call(this, maxSize);
382
+ this.updateMouseTrackingAreas();
383
+ },
384
+
385
+ layoutSubviews: function(){
386
+ UILabel.$super.layoutSubviews.call(this);
387
+ this.updateMouseTrackingAreas();
388
+ },
389
+
390
+ linkMouseTrackingAreas: null,
391
+
392
+ updateMouseTrackingAreas: function(){
393
+ UILabel.$super.updateMouseTrackingAreas.call(this);
394
+ if (this.linkMouseTrackingAreas === null && !this._userInteractionEnabled){
395
+ return;
396
+ }
397
+ if (this.linkMouseTrackingAreas === null){
398
+ this.linkMouseTrackingAreas = [];
399
+ }
400
+ var rects;
401
+ var rectIndex, rectCount;
402
+ var linkIndex = 0;
403
+ var range;
404
+ var attributes;
405
+ var attributedString = this.attributedText;
406
+ var end = attributedString.string.length;
407
+ var rect;
408
+ var area;
409
+ if (this._userInteractionEnabled){
410
+ range = attributedString.longestRangeOfAttributeAtIndex("link", 0);
411
+ attributes = attributedString.attributesAtIndex(range.location);
412
+ while (range.length > 0 && range.location < end){
413
+ if (attributes.link){
414
+ rects = this.layer.textLayoutManager.rectsForCharacterRange(range);
415
+ for (rectIndex = 0, rectCount = rects.length; rectIndex < rectCount; ++rectIndex, ++linkIndex){
416
+ rect = rects[rectIndex];
417
+ if (linkIndex < this.linkMouseTrackingAreas.length){
418
+ area = this.linkMouseTrackingAreas[linkIndex];
419
+ area.rect = rect;
420
+ }else{
421
+ area = UIMouseTrackingArea.initWithResponder(this, rect, UIMouseTrackingArea.TrackingType.enterAndExit);
422
+ area.cursor = UICursor.pointingHand;
423
+ this.linkMouseTrackingAreas.push(area);
424
+ this.addMouseTrackingArea(area);
425
+ }
426
+ }
427
+ }
428
+ if (range.end == end){
429
+ range = JSRange(end, 0);
430
+ }else{
431
+ range = attributedString.longestRangeOfAttributeAtIndex("link", range.end);
432
+ attributes = attributedString.attributesAtIndex(range.location);
433
+ }
434
+ }
435
+ }
436
+ for (var j = this.linkMouseTrackingAreas.length - 1; j >= linkIndex; --j){
437
+ area = this.linkMouseTrackingAreas.pop();
438
+ this.removeMouseTrackingArea(area);
439
+ }
440
+ },
441
+
442
+ userInteractionEnabled: JSDynamicProperty("_userInteractionEnabled", false),
443
+
444
+ setUserInteractionEnabled: function(userInteractionEnabled){
445
+ this._userInteractionEnabled = userInteractionEnabled;
446
+ this.updateMouseTrackingAreas();
447
+ },
448
+
376
449
  // -------------------------------------------------------------------------
377
450
  // MARK: - Accessibility
378
451
 
@@ -0,0 +1,55 @@
1
+ // #import "UIResponder.js"
2
+ "use strict";
3
+
4
+ JSClass("UIMouseTrackingArea", UIResponder, {
5
+
6
+ responder: null,
7
+ rect: JSDynamicProperty("_rect", null),
8
+ trackingType: 0,
9
+ view: null,
10
+ cursor: null,
11
+ userInfo: null,
12
+ _entered: false,
13
+
14
+ initWithResponder: function(responder, rect, trackingType){
15
+ this.responder = responder;
16
+ this.rect = rect;
17
+ this.trackingType = trackingType;
18
+ },
19
+
20
+ setRect: function(rect){
21
+ this._rect = JSRect(rect);
22
+ },
23
+
24
+ containsPoint: function(location){
25
+ return this._rect.containsPoint(location);
26
+ },
27
+
28
+ mouseEntered: function(event){
29
+ if (this.cursor !== null){
30
+ this.cursor.set();
31
+ }else{
32
+ this.responder.mouseEntered(event);
33
+ }
34
+ },
35
+
36
+ mouseExited: function(event){
37
+ if (this.cursor !== null){
38
+ this.cursor.unset();
39
+ }else{
40
+ this.responder.mouseExited(event);
41
+ }
42
+ },
43
+
44
+ mouseMoved: function(event){
45
+ this.responder.mouseMoved(event);
46
+ },
47
+
48
+ });
49
+
50
+ UIMouseTrackingArea.TrackingType = {
51
+ none: 0,
52
+ move: 1,
53
+ enterAndExit: 2,
54
+ all: 3
55
+ };
@@ -161,6 +161,29 @@ JSClass("UIState", JSObject, {
161
161
  var state = UIState.initWithPath(this._path);
162
162
  state._removeFileExtension();
163
163
  return state;
164
+ },
165
+
166
+ isEqual: function(other){
167
+ if (other === null || other === undefined){
168
+ return false;
169
+ }
170
+ return this._path === other._path;
171
+ },
172
+
173
+ beginsWithState: function(state){
174
+ if (state === null || state === undefined){
175
+ return false;
176
+ }
177
+ if (this._pathComponents.length < state._pathComponents.length){
178
+ return false;
179
+ }
180
+ var i, l;
181
+ for (i = 0, l = state._pathComponents.length; i < l; ++i){
182
+ if (this._pathComponents[i] != state._pathComponents[i]){
183
+ return false;
184
+ }
185
+ }
186
+ return true;
164
187
  }
165
188
 
166
189
  });