@breakside/jskit 2022.25.1 → 2022.28.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 (62) 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+HTML.js +29 -19
  7. package/Frameworks/Foundation.jsframework/JS/JSUserDefaults.js +2 -2
  8. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  9. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  10. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  11. package/Info.json +2 -2
  12. package/Node/io.breakside.jskit-bundle.js +2 -2
  13. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  14. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  15. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  16. package/Root/Frameworks/AuthKit/OAService.js +8 -0
  17. package/Root/Frameworks/AuthKit/Services.yaml +2 -0
  18. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  19. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  20. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  21. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  22. package/Root/Frameworks/DOM/Info.yaml +1 -1
  23. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  24. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  25. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  26. package/Root/Frameworks/Foundation/JSFileManager+HTML.js +29 -19
  27. package/Root/Frameworks/Foundation/JSUserDefaults.js +2 -2
  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/UICursor.js +19 -4
  41. package/Root/Frameworks/UIKit/UIDisplayServer.js +51 -10
  42. package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +2 -48
  43. package/Root/Frameworks/UIKit/UIHTMLDisplayServerContext.js +0 -6
  44. package/Root/Frameworks/UIKit/UIHTMLDisplayServerSVGContext.js +6 -77
  45. package/Root/Frameworks/UIKit/UIHTMLTextField.js +9 -3
  46. package/Root/Frameworks/UIKit/UIHTMLTextTypesetter.js +2 -29
  47. package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +6 -79
  48. package/Root/Frameworks/UIKit/UIKit.js +1 -0
  49. package/Root/Frameworks/UIKit/UILabel.js +72 -1
  50. package/Root/Frameworks/UIKit/UILayer.js +3 -0
  51. package/Root/Frameworks/UIKit/UIMouseTrackingArea.js +55 -0
  52. package/Root/Frameworks/UIKit/UINavigationBar.js +45 -22
  53. package/Root/Frameworks/UIKit/UIState.js +18 -0
  54. package/Root/Frameworks/UIKit/UITextEditor.js +277 -76
  55. package/Root/Frameworks/UIKit/UITextEditorDelegate.js +3 -1
  56. package/Root/Frameworks/UIKit/UITextLayer.js +1 -1
  57. package/Root/Frameworks/UIKit/UIView.js +129 -46
  58. package/Root/Frameworks/UIKit/UIViewController.js +6 -0
  59. package/Root/Frameworks/UIKit/UIWindow.js +89 -0
  60. package/Root/Frameworks/UIKit/UIWindowServer.js +20 -79
  61. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  62. package/package.json +1 -1
@@ -39,6 +39,7 @@ JSClass("UIDisplayServer", JSObject, {
39
39
  this.layerAnimationQueue = {};
40
40
  this._scheduleQueue = [];
41
41
  this._scheduled = [];
42
+ this._completedAnimations = [];
42
43
  },
43
44
 
44
45
  // -------------------------------------------------------------------------
@@ -100,7 +101,7 @@ JSClass("UIDisplayServer", JSObject, {
100
101
  this._scheduled = this._scheduleQueue;
101
102
  this._scheduleQueue = [];
102
103
  this._isUpdating = true;
103
- var completedAnimations = this._updateAnimations(t);
104
+ this._updateAnimations(t);
104
105
  this._flushLayerLayoutQueue();
105
106
  this._flushLayerDisplayQueue();
106
107
  this._flushLayerRepositionQueue();
@@ -110,9 +111,7 @@ JSClass("UIDisplayServer", JSObject, {
110
111
  this._isUpdating = false;
111
112
 
112
113
  // Call any animation callbacks
113
- for (var i = 0, l = completedAnimations.length; i < l; ++i){
114
- completedAnimations[i].completionFunction(completedAnimations[i]);
115
- }
114
+ this._flushCompletedAnimations();
116
115
 
117
116
  // Call any window insert/remove callbacks
118
117
  var window;
@@ -228,8 +227,22 @@ JSClass("UIDisplayServer", JSObject, {
228
227
  if (this.layerDisplayQueue.remove(layer)){
229
228
  layer._needsDisplay = true;
230
229
  }
230
+ var key;
231
+ var animation;
232
+ var completedAnimationKeys;
233
+ var i, l;
231
234
  this.layerRepositionQueue.remove(layer);
232
235
  if (layer.objectID in this.layerAnimationQueue){
236
+ completedAnimationKeys = [];
237
+ for (key in layer.animationsByKey){
238
+ animation = layer.animationsByKey[key];
239
+ this.completeAnimation(animation);
240
+ completedAnimationKeys.push(key);
241
+ }
242
+ for (i = 0, l = completedAnimationKeys.length; i < l; ++i){
243
+ key = completedAnimationKeys[i];
244
+ layer.removeAnimationForKey(key);
245
+ }
233
246
  delete this.layerAnimationQueue[layer.objectID];
234
247
  --this._animationCount;
235
248
  }
@@ -246,24 +259,53 @@ JSClass("UIDisplayServer", JSObject, {
246
259
  this.setUpdateNeeded();
247
260
  },
248
261
 
262
+ _completedAnimations: null,
263
+
264
+ completeAnimation: function(animation){
265
+ this._completedAnimations.push(animation);
266
+ },
267
+
268
+ _flushCompletedAnimations: function(){
269
+ var i, l;
270
+ var animation;
271
+ for (i = 0, l = this._completedAnimations.length; i < l; ++i){
272
+ animation = this._completedAnimations[i];
273
+ if (animation.completionFunction){
274
+ animation.completionFunction(animation);
275
+ }
276
+ }
277
+ this._completedAnimations = [];
278
+ },
279
+
249
280
  _updateAnimations: function(t){
250
281
  t /= this._animationScale;
251
282
  var animation;
252
- var completedAnimations = [];
253
283
  var id, key;
254
284
  var layer;
285
+ var completedAnimationKeys;
286
+ var i, l;
287
+ var parts;
255
288
  for (id in this.layerAnimationQueue){
256
289
  layer = this.layerAnimationQueue[id];
290
+ completedAnimationKeys = [];
257
291
  for (key in layer.animationsByKey){
258
292
  animation = layer.animationsByKey[key];
259
293
  animation.updateForTime(t);
260
294
  if (this.reducedMotionEnabled || animation.isComplete){
261
- layer.removeAnimationForKey(key);
262
- if (animation.completionFunction){
263
- completedAnimations.push(animation);
295
+ completedAnimationKeys.push(key);
296
+ }else{
297
+ parts = key.split('.');
298
+ if (parts[0] in layer.presentation){
299
+ this.layerDidChangeProperty(layer, key);
264
300
  }
265
301
  }
266
- var parts = key.split('.');
302
+ }
303
+ for (i = 0, l = completedAnimationKeys.length; i < l; ++i){
304
+ key = completedAnimationKeys[i];
305
+ animation = layer.animationsByKey[key];
306
+ layer.removeAnimationForKey(key);
307
+ this.completeAnimation(animation);
308
+ parts = key.split('.');
267
309
  if (parts[0] in layer.presentation){
268
310
  this.layerDidChangeProperty(layer, key);
269
311
  }
@@ -273,7 +315,6 @@ JSClass("UIDisplayServer", JSObject, {
273
315
  --this._animationCount;
274
316
  }
275
317
  }
276
- return completedAnimations;
277
318
  },
278
319
 
279
320
  // -------------------------------------------------------------------------
@@ -79,7 +79,6 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
79
79
  // MARK: - Destroying a Context
80
80
 
81
81
  destroy: function(){
82
- this.trackingElement = null;
83
82
  this.style = null;
84
83
  UIHTMLDisplayServerCanvasContext.$super.destroy.call(this);
85
84
  },
@@ -140,11 +139,7 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
140
139
  // instead of a separate element. Needs investigation. Browser support? Behavior?
141
140
  this.borderElement = this.element.ownerDocument.createElement('div');
142
141
  this.borderElement.setAttribute("role", "none presentation");
143
- if (this.trackingElement !== null){
144
- this.element.insertBefore(this.borderElement, this.trackingElement);
145
- }else{
146
- this.element.appendChild(this.borderElement);
147
- }
142
+ this.element.appendChild(this.borderElement);
148
143
  this.borderElement.style.position = 'absolute';
149
144
  this.borderElement.style.top = '0';
150
145
  this.borderElement.style.left = '0';
@@ -465,48 +460,7 @@ JSClass("UIHTMLDisplayServerCanvasContext", UIHTMLDisplayServerContext, {
465
460
  },
466
461
 
467
462
  // ----------------------------------------------------------------------
468
- // MARK: - Tracking
469
-
470
- trackingElement: null,
471
- trackingListener: null,
472
-
473
- startMouseTracking: function(trackingType, listener, layer){
474
- if (this.trackingElement === null){
475
- this.trackingElement = this.element.ownerDocument.createElement('div');
476
- this.trackingElement.setAttribute("role", "none presentation");
477
- this.trackingElement.style.position = 'absolute';
478
- this.trackingElement.style.top = '0';
479
- this.trackingElement.style.left = '0';
480
- this.trackingElement.style.bottom = '0';
481
- this.trackingElement.style.right = '0';
482
- this.trackingElement.dataset.tag = "tracking";
483
- this.element.appendChild(this.trackingElement);
484
- }else if (this.trackingListener !== null){
485
- this.trackingElement.removeEventListener('mouseenter', this.trackingListener);
486
- this.trackingElement.removeEventListener('mouseleave', this.trackingListener);
487
- this.trackingElement.removeEventListener('mousemove', this.trackingListener);
488
- }
489
- this.trackingListener = listener;
490
- if (trackingType & UIView.MouseTracking.enterAndExit){
491
- this.trackingElement.addEventListener('mouseenter', this.trackingListener);
492
- this.trackingElement.addEventListener('mouseleave', this.trackingListener);
493
- }
494
- if (trackingType & UIView.MouseTracking.move){
495
- this.trackingElement.addEventListener('mousemove', this.trackingListener);
496
- }
497
- },
498
-
499
- stopMouseTracking: function(){
500
- if (this.trackingElement === null || this.trackingListener === null){
501
- return;
502
- }
503
- this.trackingElement.removeEventListener('mouseenter', this.trackingListener);
504
- this.trackingElement.removeEventListener('mouseleave', this.trackingListener);
505
- this.trackingElement.removeEventListener('mousemove', this.trackingListener);
506
- this.trackingElement.parentNode.removeChild(this.trackingElement);
507
- this.trackingElement = null;
508
- this.trackingListener = null;
509
- },
463
+ // MARK: - Cursor
510
464
 
511
465
  setCursor: function(cursor){
512
466
  this.element.style.cursor = '';
@@ -43,12 +43,6 @@ JSClass("UIHTMLDisplayServerContext", JSContext, {
43
43
  layerDidChangeProperty: function(layer, property){
44
44
  },
45
45
 
46
- startMouseTracking: function(trackingType, listener){
47
- },
48
-
49
- stopMouseTracking: function(){
50
- },
51
-
52
46
  addExternalElementInRect: function(element, rect){
53
47
  },
54
48
 
@@ -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);
@@ -28,6 +28,7 @@
28
28
  // #import "UIPlatform.js"
29
29
  // #import "JSColor+UIKit.js"
30
30
  // #import "UIColorSpace.js"
31
+ // #import "UIState.js"
31
32
 
32
33
  // Layers & Views
33
34
  // #import "UIResponder.js"
@@ -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){
@@ -375,6 +374,78 @@ JSClass('UILabel', UIView, {
375
374
  this._updateSelectionHighlightLayers();
376
375
  },
377
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
+
378
449
  // -------------------------------------------------------------------------
379
450
  // MARK: - Accessibility
380
451
 
@@ -608,6 +608,9 @@ JSClass("UILayer", JSObject, {
608
608
  },
609
609
 
610
610
  removeAnimationForKey: function(key){
611
+ if (!(key in this.animationsByKey)){
612
+ return;
613
+ }
611
614
  --this.animationCount;
612
615
  if (this.animationCount === 0){
613
616
  // If we're all done with animations, reset our presentation to be identical to our model