@breakside/jskit 2026.6.0 → 2026.9.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.
- package/Frameworks/DOM.jsframework/Info.json +2 -2
- package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
- package/Frameworks/FontKit.jsframework/Info.json +2 -2
- package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
- package/Frameworks/Foundation.jsframework/Info.json +2 -2
- package/Frameworks/Foundation.jsframework/JS/JSContext.js +23 -1
- package/Frameworks/Foundation.jsframework/JS/JSGradient.js +25 -0
- package/Frameworks/Foundation.jsframework/JS/JSPath.js +80 -0
- package/Frameworks/Foundation.jsframework/JS/JSRect.js +12 -0
- package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
- package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
- package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
- package/Info.json +2 -2
- package/Node/io.breakside.jskit-bundle.js +4 -4
- package/Resources/doc-default.css +8 -0
- package/Root/Frameworks/APIKit/Info.yaml +1 -1
- package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/AuthKit/Info.yaml +1 -1
- package/Root/Frameworks/CSSOM/Info.yaml +1 -1
- package/Root/Frameworks/ChartKit/Info.yaml +1 -1
- package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
- package/Root/Frameworks/DBKit/Info.yaml +1 -1
- package/Root/Frameworks/DOM/Info.yaml +1 -1
- package/Root/Frameworks/Dispatch/Info.yaml +1 -1
- package/Root/Frameworks/FontKit/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/Info.yaml +1 -1
- package/Root/Frameworks/Foundation/JSContext.js +23 -1
- package/Root/Frameworks/Foundation/JSGradient.js +25 -0
- package/Root/Frameworks/Foundation/JSPath.js +80 -0
- package/Root/Frameworks/Foundation/JSRect.js +12 -0
- package/Root/Frameworks/ImageKit/IKHTMLCanvasBitmapContext.js +91 -13
- package/Root/Frameworks/ImageKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKit/Info.yaml +1 -1
- package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
- package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
- package/Root/Frameworks/PDFKit/Info.yaml +1 -1
- package/Root/Frameworks/QRKit/Info.yaml +1 -1
- package/Root/Frameworks/SearchKit/Info.yaml +1 -1
- package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKit/Info.yaml +1 -1
- package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
- package/Root/Frameworks/TestKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/Info.yaml +1 -1
- package/Root/Frameworks/UIKit/UIApplication.js +5 -1
- package/Root/Frameworks/UIKit/UIHTMLApplication.js +24 -0
- package/Root/Frameworks/UIKit/UIHTMLDisplayServerCanvasContext.js +87 -13
- package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +17 -3
- package/Root/Frameworks/UIKit/UIKit.js +2 -0
- package/Root/Frameworks/UIKit/UILayer.js +6 -0
- package/Root/Frameworks/UIKit/UIPopupWindow.js +15 -5
- package/Root/Frameworks/UIKit/UITextAction.js +16 -0
- package/Root/Frameworks/UIKit/UITextActionsMenu.js +95 -0
- package/Root/Frameworks/UIKit/UITextEditor.js +57 -7
- package/Root/Frameworks/UIKit/UITextField.js +102 -0
- package/Root/Frameworks/UIKit/en.lproj/Localizable.strings.yaml +4 -1
- package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
- package/package.json +1 -1
|
@@ -214,25 +214,69 @@ JSClass("UITextEditor", JSObject, {
|
|
|
214
214
|
_touchBeganInfo: null,
|
|
215
215
|
|
|
216
216
|
handleTouchesBeganAtLocation: function(location, touches, event){
|
|
217
|
-
this.
|
|
217
|
+
var newSelection = this._createSelectionAtLocation(location);
|
|
218
|
+
var existingSelection = null;
|
|
219
|
+
for (var i = 0, l = this.selections.length; i < l; ++i){
|
|
220
|
+
if (this.selections[i].containsIndex(newSelection.range.location)){
|
|
221
|
+
existingSelection = this.selections[i];
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (existingSelection === null){
|
|
226
|
+
this._setSingleSelectionAtLocation(location);
|
|
227
|
+
}
|
|
218
228
|
this._touchBeganInfo = {
|
|
219
229
|
timestamp: event.timestamp,
|
|
220
230
|
location: location,
|
|
231
|
+
selection: existingSelection,
|
|
221
232
|
moved: false
|
|
222
233
|
};
|
|
223
234
|
},
|
|
224
235
|
|
|
225
236
|
handleTouchesMovedAtLocation: function(location, touches, event){
|
|
226
|
-
this._setSingleSelectionAtLocation(location);
|
|
227
237
|
if (this._touchBeganInfo !== null){
|
|
238
|
+
if (this._touchBeganInfo.selection === null){
|
|
239
|
+
this._setSingleSelectionAtLocation(location);
|
|
240
|
+
}
|
|
228
241
|
this._touchBeganInfo.moved = this._touchBeganInfo.moved || location.distanceToPoint(this._touchBeganInfo.location) > 10;
|
|
242
|
+
if (this._touchBeganInfo.moved && this._touchBeganInfo.selection !== null){
|
|
243
|
+
var existingSelection = this._touchBeganInfo.selection;
|
|
244
|
+
var selection = this._createSelectionAtLocation(location);
|
|
245
|
+
if (selection.range.location < existingSelection.range.location){
|
|
246
|
+
selection.range.length = existingSelection.range.end - selection.range.location;
|
|
247
|
+
this._setSingleSelection(selection);
|
|
248
|
+
this._touchBeganInfo.selection = selection;
|
|
249
|
+
}else if (selection.range.location > existingSelection.range.end){
|
|
250
|
+
selection.range = JSRange(existingSelection.range.location, selection.range.location - existingSelection.range.location);
|
|
251
|
+
this._setSingleSelection(selection);
|
|
252
|
+
this._touchBeganInfo.selection = selection;
|
|
253
|
+
}else{
|
|
254
|
+
var dl = selection.range.location - existingSelection.range.location;
|
|
255
|
+
var de = existingSelection.range.end - selection.range.location;
|
|
256
|
+
if (dl > 0 && de > 0){
|
|
257
|
+
if (dl <= de){
|
|
258
|
+
selection.range.length = existingSelection.range.end - selection.range.location;
|
|
259
|
+
}else{
|
|
260
|
+
selection.range = JSRange(existingSelection.range.location, selection.range.location - existingSelection.range.location);
|
|
261
|
+
}
|
|
262
|
+
this._setSingleSelection(selection);
|
|
263
|
+
this._touchBeganInfo.selection = selection;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}else{
|
|
268
|
+
this._setSingleSelectionAtLocation(location);
|
|
229
269
|
}
|
|
230
270
|
},
|
|
231
271
|
|
|
232
272
|
handleTouchesEndedAtLocation: function(location, touches, event){
|
|
233
|
-
this._setSingleSelectionAtLocation(location);
|
|
234
273
|
if (this._touchBeganInfo !== null){
|
|
274
|
+
if (this._touchBeganInfo.selection === null){
|
|
275
|
+
this._setSingleSelectionAtLocation(location);
|
|
276
|
+
}
|
|
235
277
|
this._touchBeganInfo = null;
|
|
278
|
+
}else{
|
|
279
|
+
this._setSingleSelectionAtLocation(location);
|
|
236
280
|
}
|
|
237
281
|
},
|
|
238
282
|
|
|
@@ -241,10 +285,16 @@ JSClass("UITextEditor", JSObject, {
|
|
|
241
285
|
if (this.selections.length === 1 && !this._touchBeganInfo.moved){
|
|
242
286
|
if ((event.timestamp - this._touchBeganInfo.timestamp) > JSTimeInterval.seconds(0.5)){
|
|
243
287
|
var selection = this.selections[0];
|
|
244
|
-
var
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
this._setSingleSelection(
|
|
288
|
+
var updatedSelection;
|
|
289
|
+
if (this._touchBeganInfo.selection !== null){
|
|
290
|
+
updatedSelection = this._createSelection(JSRange(selection.range.location, 0));
|
|
291
|
+
this._setSingleSelection(updatedSelection);
|
|
292
|
+
}else{
|
|
293
|
+
var range = this.textLayoutManager.textStorage.string.rangeForWordAtIndex(selection.range.location);
|
|
294
|
+
if (range.length > 0){
|
|
295
|
+
updatedSelection = this._createSelection(range);
|
|
296
|
+
this._setSingleSelection(updatedSelection);
|
|
297
|
+
}
|
|
248
298
|
}
|
|
249
299
|
}
|
|
250
300
|
}
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
// #import "UIImageView.js"
|
|
23
23
|
// #import "UIPasteboard.js"
|
|
24
24
|
// #import "JSColor+UIKit.js"
|
|
25
|
+
// #import "UITextAction.js"
|
|
26
|
+
// #import "UIMenu.js"
|
|
27
|
+
// #import "UITextActionsMenu.js"
|
|
25
28
|
'use strict';
|
|
26
29
|
|
|
27
30
|
(function(){
|
|
@@ -794,6 +797,7 @@ JSClass("UITextField", UIControl, {
|
|
|
794
797
|
},
|
|
795
798
|
|
|
796
799
|
textEditorDidReplaceCharactersInRange: function(textEditor, range, insertedLength){
|
|
800
|
+
this.hideTextActionsMenu();
|
|
797
801
|
if (this._isEmpty && insertedLength > 0){
|
|
798
802
|
this._updateIsEmpty(false);
|
|
799
803
|
}else if (!this._isEmpty && insertedLength === 0 && !this._textLayer.hasText()){
|
|
@@ -889,6 +893,7 @@ JSClass("UITextField", UIControl, {
|
|
|
889
893
|
},
|
|
890
894
|
|
|
891
895
|
resignFirstResponder: function(){
|
|
896
|
+
this.hideTextActionsMenu();
|
|
892
897
|
this.active = false;
|
|
893
898
|
this._updateAccessoryViewHidden(this._leftAccessoryView, this._leftAccessoryVisibility);
|
|
894
899
|
this._updateAccessoryViewHidden(this._rightAccessoryView, this._rightAccessoryVisibility);
|
|
@@ -977,9 +982,27 @@ JSClass("UITextField", UIControl, {
|
|
|
977
982
|
UITextField.$super.mouseUp.call(this, event);
|
|
978
983
|
},
|
|
979
984
|
|
|
985
|
+
rightMouseDown: function(event){
|
|
986
|
+
var actions = this.textActions();
|
|
987
|
+
if (actions.length > 0){
|
|
988
|
+
var menu = UIMenu.init();
|
|
989
|
+
var action;
|
|
990
|
+
for (var i = 0, l = actions.length; i < l; ++i){
|
|
991
|
+
action = actions[i];
|
|
992
|
+
menu.addItemWithTitle(action.title, action.action, action.target);
|
|
993
|
+
}
|
|
994
|
+
var location = event.locationInView(this);
|
|
995
|
+
menu.openAtLocationInContextView(location, this);
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
UITextField.$super.rightMouseDown.call(this, event);
|
|
999
|
+
},
|
|
1000
|
+
|
|
980
1001
|
_touchOrigin: null,
|
|
1002
|
+
_touchesBeganSelections: null,
|
|
981
1003
|
|
|
982
1004
|
touchesBegan: function(touches, event){
|
|
1005
|
+
this._touchesBeganSelections = null;
|
|
983
1006
|
if (this.enabled){
|
|
984
1007
|
var location = touches[0].locationInView(this);
|
|
985
1008
|
this._touchOrigin = this.convertPointToView(this.bounds.origin, this.window);
|
|
@@ -989,6 +1012,7 @@ JSClass("UITextField", UIControl, {
|
|
|
989
1012
|
// when mobile safari ignores focus() calls that aren't tied to
|
|
990
1013
|
// user interaction
|
|
991
1014
|
this.window.firstResponder = this;
|
|
1015
|
+
this._touchesBeganSelections = this.selections.map(function(s){ return UITextInputSelection(s)});
|
|
992
1016
|
this._localEditor.handleTouchesBeganAtLocation(this.layer.convertPointToLayer(location, this._textLayer), touches, event);
|
|
993
1017
|
return;
|
|
994
1018
|
}
|
|
@@ -1012,6 +1036,26 @@ JSClass("UITextField", UIControl, {
|
|
|
1012
1036
|
var location = touches[0].locationInView(this);
|
|
1013
1037
|
if (this.isFirstResponder()){
|
|
1014
1038
|
this._localEditor.handleTouchesEnded(touches, event);
|
|
1039
|
+
if (this.textActionsMenu !== null){
|
|
1040
|
+
this.hideTextActionsMenu();
|
|
1041
|
+
}else if (this._touchesBeganSelections !== null){
|
|
1042
|
+
var selections = this.selections;
|
|
1043
|
+
var match = true;
|
|
1044
|
+
if (selections.length === this._touchesBeganSelections.length){
|
|
1045
|
+
for (var i = 0, l = selections.length; i < l; ++i){
|
|
1046
|
+
if (!selections[i].range.isEqual(this._touchesBeganSelections[i].range)){
|
|
1047
|
+
match = false;
|
|
1048
|
+
break;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}else{
|
|
1052
|
+
match = false;
|
|
1053
|
+
}
|
|
1054
|
+
if (match){
|
|
1055
|
+
this.showTextActionsMenu(location);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
this._touchesBeganSelections = null;
|
|
1015
1059
|
return;
|
|
1016
1060
|
}
|
|
1017
1061
|
if (this._touchOrigin !== null){
|
|
@@ -1022,10 +1066,12 @@ JSClass("UITextField", UIControl, {
|
|
|
1022
1066
|
}
|
|
1023
1067
|
}
|
|
1024
1068
|
}
|
|
1069
|
+
this._touchesBeganSelections = null;
|
|
1025
1070
|
UITextField.$super.touchesEnded.call(this, touches, event);
|
|
1026
1071
|
},
|
|
1027
1072
|
|
|
1028
1073
|
touchesCanceled: function(touches, event){
|
|
1074
|
+
this._touchesBeganSelections = null;
|
|
1029
1075
|
if (this.enabled){
|
|
1030
1076
|
var location = touches[0].locationInView(this);
|
|
1031
1077
|
this._localEditor.handleTouchesCanceled(touches, event);
|
|
@@ -1041,6 +1087,51 @@ JSClass("UITextField", UIControl, {
|
|
|
1041
1087
|
return text;
|
|
1042
1088
|
},
|
|
1043
1089
|
|
|
1090
|
+
// ----------------------------------------------------------------------
|
|
1091
|
+
// MARK: Text Actions
|
|
1092
|
+
|
|
1093
|
+
copyTextAction: JSLazyInitProperty(function(){
|
|
1094
|
+
return UITextAction.initWithTitle(UITextField.bundle.localizedString("textActions.copy"), "copy", this);
|
|
1095
|
+
}),
|
|
1096
|
+
|
|
1097
|
+
pasteTextAction: JSLazyInitProperty(function(){
|
|
1098
|
+
return UITextAction.initWithTitle(UITextField.bundle.localizedString("textActions.paste"), "paste", this);
|
|
1099
|
+
}),
|
|
1100
|
+
|
|
1101
|
+
textActions: function(){
|
|
1102
|
+
return [this.copyTextAction, this.pasteTextAction];
|
|
1103
|
+
},
|
|
1104
|
+
|
|
1105
|
+
textActionsMenu: null,
|
|
1106
|
+
|
|
1107
|
+
showTextActionsMenu: function(location){
|
|
1108
|
+
var responder = this;
|
|
1109
|
+
var actions = this.textActions().filter(function(textAction){
|
|
1110
|
+
var target = responder.targetForAction(textAction.action, null);
|
|
1111
|
+
return target !== null && target.canPerformAction(textAction.action, null);
|
|
1112
|
+
});
|
|
1113
|
+
if (actions.length === 0){
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
this.textActionsMenu = UITextActionsMenu.initWithActions(actions);
|
|
1117
|
+
this.textActionsMenu.delegate = this;
|
|
1118
|
+
this.textActionsMenu.openAtLocationInView(location, this);
|
|
1119
|
+
},
|
|
1120
|
+
|
|
1121
|
+
hideTextActionsMenu: function(){
|
|
1122
|
+
if (this.textActionsMenu !== null){
|
|
1123
|
+
this.textActionsMenu.close();
|
|
1124
|
+
this.textActionsMenu = null;
|
|
1125
|
+
}
|
|
1126
|
+
},
|
|
1127
|
+
|
|
1128
|
+
textActionsMenuDidClose: function(textActionsMenu){
|
|
1129
|
+
if (textActionsMenu === this.textActionsMenu){
|
|
1130
|
+
textActionsMenu.delegate = null;
|
|
1131
|
+
this.textActionsMenu = null;
|
|
1132
|
+
}
|
|
1133
|
+
},
|
|
1134
|
+
|
|
1044
1135
|
// --------------------------------------------------------------------
|
|
1045
1136
|
// MARK: - Accessibility
|
|
1046
1137
|
|
|
@@ -1265,6 +1356,17 @@ JSClass("UITextField", UIControl, {
|
|
|
1265
1356
|
|
|
1266
1357
|
});
|
|
1267
1358
|
|
|
1359
|
+
Object.defineProperties(UITextField, {
|
|
1360
|
+
bundle: {
|
|
1361
|
+
configurable: true,
|
|
1362
|
+
get: function(){
|
|
1363
|
+
var bundle = JSBundle.initWithIdentifier("io.breakside.JSKit.UIKit");
|
|
1364
|
+
Object.defineProperty(UITextField, "bundle", {value: bundle});
|
|
1365
|
+
return bundle;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
});
|
|
1369
|
+
|
|
1268
1370
|
UITextField.AccessoryVisibility = {
|
|
1269
1371
|
always: 0,
|
|
1270
1372
|
onlyWhenActive: 1,
|