@breakside/jskit 2026.8.0 → 2026.10.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/JSColor.js +5 -0
- package/Frameworks/Foundation.jsframework/JS/JSPath.js +482 -49
- package/Frameworks/Foundation.jsframework/JS/JSRect.js +12 -0
- package/Frameworks/Foundation.jsframework/JS/JSSpec.js +5 -1
- package/Frameworks/Foundation.jsframework/JS/String+JS.js +78 -2
- 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/DocCommand.js +5 -2
- package/Node/Docs/DocClass.js +2 -2
- package/Node/Docs/DocComponent.js +6 -4
- package/Node/Docs/DocDictionaryProperty.js +2 -2
- package/Node/Docs/DocEnumOption.js +2 -2
- package/Node/Docs/DocFunction.js +2 -2
- package/Node/Docs/DocProperty.js +2 -2
- package/Node/Docs/DocProtocol.js +1 -1
- package/Node/Docs/DocSpec.js +1 -1
- package/Node/Docs/DocSpecProperty.js +2 -2
- package/Node/Docs/DocTopicBasedComponent.js +2 -2
- package/Node/Documentation.js +10 -2
- package/Node/HTMLBuilder.js +3 -1
- package/Node/HTMLProjectServer.js +39 -1
- package/Node/io.breakside.jskit-bundle.js +4 -4
- package/Resources/doc-default.css +4 -4
- 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/JSColor.js +5 -0
- package/Root/Frameworks/Foundation/JSPath.js +482 -49
- package/Root/Frameworks/Foundation/JSRect.js +12 -0
- package/Root/Frameworks/Foundation/JSSpec.js +5 -1
- package/Root/Frameworks/Foundation/String+JS.js +78 -2
- 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/UIHTMLWindowServer.js +17 -3
- package/Root/Frameworks/UIKit/UIKit.js +2 -0
- package/Root/Frameworks/UIKit/UIListView.js +11 -3
- package/Root/Frameworks/UIKit/UIOutlineView.js +65 -5
- 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,
|