@breakside/jskit 2026.8.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/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/JSRect.js +12 -0
- 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/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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.DOM",
|
|
4
|
-
"JSBundleVersion": "2026.
|
|
4
|
+
"JSBundleVersion": "2026.9.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "DOM+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
13
13
|
}
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.DOM",
|
|
6
|
-
"JSBundleVersion": "2026.
|
|
6
|
+
"JSBundleVersion": "2026.9.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.DOM'] = {
|
|
|
11
11
|
"node": "DOM+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [],
|
|
17
17
|
"ResourceLookup": {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.FontKit",
|
|
4
|
-
"JSBundleVersion": "2026.
|
|
4
|
+
"JSBundleVersion": "2026.9.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
8
8
|
"html": "FontKit+HTML.js"
|
|
9
9
|
},
|
|
10
10
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
11
|
-
"GitRevision": "
|
|
11
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
12
12
|
}
|
|
@@ -3,14 +3,14 @@ JSBundle.bundles['io.breakside.JSKit.FontKit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.FontKit",
|
|
6
|
-
"JSBundleVersion": "2026.
|
|
6
|
+
"JSBundleVersion": "2026.9.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
10
10
|
"html": "FontKit+HTML.js"
|
|
11
11
|
},
|
|
12
12
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
13
|
-
"GitRevision": "
|
|
13
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
14
14
|
},
|
|
15
15
|
"Resources": [],
|
|
16
16
|
"ResourceLookup": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.Foundation",
|
|
4
|
-
"JSBundleVersion": "2026.
|
|
4
|
+
"JSBundleVersion": "2026.9.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "Foundation+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
13
13
|
}
|
|
@@ -77,6 +77,18 @@ JSRect.prototype = {
|
|
|
77
77
|
return JSRect(origin, size);
|
|
78
78
|
},
|
|
79
79
|
|
|
80
|
+
unioningRect: function(other){
|
|
81
|
+
var origin = JSPoint(
|
|
82
|
+
Math.min(this.origin.x, other.origin.x),
|
|
83
|
+
Math.min(this.origin.y, other.origin.y)
|
|
84
|
+
);
|
|
85
|
+
var size = JSSize(
|
|
86
|
+
Math.max(0, Math.max(this.origin.x + this.size.width, other.origin.x + other.size.width) - origin.x),
|
|
87
|
+
Math.max(0, Math.max(this.origin.y + this.size.height, other.origin.y + other.size.height) - origin.y)
|
|
88
|
+
);
|
|
89
|
+
return JSRect(origin, size);
|
|
90
|
+
},
|
|
91
|
+
|
|
80
92
|
isEqual: function(other){
|
|
81
93
|
return this.origin.isEqual(other.origin) && this.size.isEqual(other.size);
|
|
82
94
|
},
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.Foundation",
|
|
6
|
-
"JSBundleVersion": "2026.
|
|
6
|
+
"JSBundleVersion": "2026.9.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.Foundation'] = {
|
|
|
11
11
|
"node": "Foundation+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [
|
|
17
17
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "framework",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
|
|
4
|
-
"JSBundleVersion": "2026.
|
|
4
|
+
"JSBundleVersion": "2026.9.0",
|
|
5
5
|
"JSDevelopmentLanguage": "en",
|
|
6
6
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
7
7
|
"JSBundleEnvironments": {
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"node": "SecurityKit+Node.js"
|
|
10
10
|
},
|
|
11
11
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
12
|
-
"GitRevision": "
|
|
12
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
13
13
|
}
|
|
@@ -3,7 +3,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "framework",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.JSKit.SecurityKit",
|
|
6
|
-
"JSBundleVersion": "2026.
|
|
6
|
+
"JSBundleVersion": "2026.9.0",
|
|
7
7
|
"JSDevelopmentLanguage": "en",
|
|
8
8
|
"JSCopyright": "Copyright © 2020 Breakside Inc.",
|
|
9
9
|
"JSBundleEnvironments": {
|
|
@@ -11,7 +11,7 @@ JSBundle.bundles['io.breakside.JSKit.SecurityKit'] = {
|
|
|
11
11
|
"node": "SecurityKit+Node.js"
|
|
12
12
|
},
|
|
13
13
|
"JSLicenseNotice": "Licensed under the Breakside Public License, Version 1.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nIf a copy of the License was not distributed with this file, you may\nobtain a copy at\n\n http://breakside.io/licenses/LICENSE-1.0.txt\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
|
|
14
|
-
"GitRevision": "
|
|
14
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
15
15
|
},
|
|
16
16
|
"Resources": [],
|
|
17
17
|
"ResourceLookup": {
|
package/Info.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"JSBundleType": "node",
|
|
3
3
|
"JSBundleIdentifier": "io.breakside.jskit",
|
|
4
|
-
"JSBundleVersion": "2026.
|
|
4
|
+
"JSBundleVersion": "2026.9.0",
|
|
5
5
|
"JSExecutableName": "jskit",
|
|
6
6
|
"NPMOrganization": "breakside",
|
|
7
7
|
"JSResources": [
|
|
8
8
|
"Tests/HTMLTestRunner.js",
|
|
9
9
|
"Tests/NodeTestRunner.js"
|
|
10
10
|
],
|
|
11
|
-
"GitRevision": "
|
|
11
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
12
12
|
}
|
|
@@ -3,22 +3,22 @@ JSBundle.bundles['io.breakside.jskit'] = {
|
|
|
3
3
|
"Info": {
|
|
4
4
|
"JSBundleType": "node",
|
|
5
5
|
"JSBundleIdentifier": "io.breakside.jskit",
|
|
6
|
-
"JSBundleVersion": "2026.
|
|
6
|
+
"JSBundleVersion": "2026.9.0",
|
|
7
7
|
"JSExecutableName": "jskit",
|
|
8
8
|
"NPMOrganization": "breakside",
|
|
9
9
|
"JSResources": [
|
|
10
10
|
"Tests/HTMLTestRunner.js",
|
|
11
11
|
"Tests/NodeTestRunner.js"
|
|
12
12
|
],
|
|
13
|
-
"GitRevision": "
|
|
13
|
+
"GitRevision": "7481a2557e5555dbf2a58e88ba6720b16de86277"
|
|
14
14
|
},
|
|
15
15
|
"Resources": [
|
|
16
16
|
{
|
|
17
17
|
"path": "doc-default.css",
|
|
18
18
|
"ext": ".css",
|
|
19
|
-
"byte_size":
|
|
19
|
+
"byte_size": 11088,
|
|
20
20
|
"mimetype": "text/css",
|
|
21
|
-
"hash": "
|
|
21
|
+
"hash": "fb20238b7c988f0d959bad2d071b06000068a39d",
|
|
22
22
|
"nodeBundlePath": "Resources/doc-default.css"
|
|
23
23
|
},
|
|
24
24
|
{
|
|
@@ -21,6 +21,14 @@ article.doc h1,h2,h3,h4,h5,h5,b,strong{
|
|
|
21
21
|
font-weight: 600;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
article.doc > section > header > h1, article.doc > section > h1{
|
|
25
|
+
font-size: 1.4em;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
article.doc > section > section > header > h1{
|
|
29
|
+
font-size: 1em;
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
article.doc a{
|
|
25
33
|
text-decoration: none;
|
|
26
34
|
color: rgb(90,90,200);
|
|
@@ -77,6 +77,18 @@ JSRect.prototype = {
|
|
|
77
77
|
return JSRect(origin, size);
|
|
78
78
|
},
|
|
79
79
|
|
|
80
|
+
unioningRect: function(other){
|
|
81
|
+
var origin = JSPoint(
|
|
82
|
+
Math.min(this.origin.x, other.origin.x),
|
|
83
|
+
Math.min(this.origin.y, other.origin.y)
|
|
84
|
+
);
|
|
85
|
+
var size = JSSize(
|
|
86
|
+
Math.max(0, Math.max(this.origin.x + this.size.width, other.origin.x + other.size.width) - origin.x),
|
|
87
|
+
Math.max(0, Math.max(this.origin.y + this.size.height, other.origin.y + other.size.height) - origin.y)
|
|
88
|
+
);
|
|
89
|
+
return JSRect(origin, size);
|
|
90
|
+
},
|
|
91
|
+
|
|
80
92
|
isEqual: function(other){
|
|
81
93
|
return this.origin.isEqual(other.origin) && this.size.isEqual(other.size);
|
|
82
94
|
},
|
|
@@ -438,11 +438,15 @@ JSClass('UIApplication', UIResponder, {
|
|
|
438
438
|
target = this.firstTargetForAction(action, target, sender);
|
|
439
439
|
if (target !== null){
|
|
440
440
|
actionLogger.debug("sendAction " + action + " to %{public}#%d from %{public}#%d", target.$class.className, target.objectID, sender.$class.className, sender.objectID);
|
|
441
|
-
target
|
|
441
|
+
this._sendAction(action, target, sender, event);
|
|
442
442
|
}
|
|
443
443
|
}
|
|
444
444
|
},
|
|
445
445
|
|
|
446
|
+
_sendAction: function(action, target, sender, event){
|
|
447
|
+
target[action](sender, event);
|
|
448
|
+
},
|
|
449
|
+
|
|
446
450
|
targetForAction: function(action, sender){
|
|
447
451
|
var target = UIApplication.$super.targetForAction.call(this, action, sender);
|
|
448
452
|
if (target !== null){
|
|
@@ -140,6 +140,30 @@ JSClass("UIHTMLApplication", UIApplication, {
|
|
|
140
140
|
return url;
|
|
141
141
|
},
|
|
142
142
|
|
|
143
|
+
_sendAction: function(action, target, sender, event){
|
|
144
|
+
var application = this;
|
|
145
|
+
var window = this.domWindow;
|
|
146
|
+
if (action === "paste" && sender !== this.windowServer){
|
|
147
|
+
if (this.domWindow.navigator.clipboard){
|
|
148
|
+
logger.info("sending paste action with clipboard.readText");
|
|
149
|
+
window.navigator.clipboard.readText().then(function(text){
|
|
150
|
+
var strings = {};
|
|
151
|
+
strings[UIPasteboard.ContentType.plainText] = text;
|
|
152
|
+
UIPasteboard.general.withStrings(strings, function(){
|
|
153
|
+
UIHTMLApplication.$super._sendAction.call(application, action, target, sender, event);
|
|
154
|
+
});
|
|
155
|
+
}, function(e){
|
|
156
|
+
logger.warn("could not readText() from clipboard: %{error}", e);
|
|
157
|
+
});
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
logger.info("sending paste action with document.execCommand");
|
|
161
|
+
this.domWindow.document.execCommand("paste");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
UIHTMLApplication.$super._sendAction.call(this, action, target, sender, event);
|
|
165
|
+
},
|
|
166
|
+
|
|
143
167
|
addEventListeners: function(){
|
|
144
168
|
this.domWindow.addEventListener("error", this);
|
|
145
169
|
this.domWindow.addEventListener("unhandledrejection", this);
|
|
@@ -690,7 +690,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
|
|
|
690
690
|
return;
|
|
691
691
|
}
|
|
692
692
|
UIPasteboard.general.withDataTransfer(e.clipboardData, function(){
|
|
693
|
-
this.keyWindow.application.sendAction('cut');
|
|
693
|
+
this.keyWindow.application.sendAction('cut', null, this);
|
|
694
694
|
}, this);
|
|
695
695
|
},
|
|
696
696
|
|
|
@@ -702,7 +702,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
|
|
|
702
702
|
return;
|
|
703
703
|
}
|
|
704
704
|
UIPasteboard.general.withDataTransfer(e.clipboardData, function(){
|
|
705
|
-
this.keyWindow.application.sendAction('copy');
|
|
705
|
+
this.keyWindow.application.sendAction('copy', null, this);
|
|
706
706
|
}, this);
|
|
707
707
|
},
|
|
708
708
|
|
|
@@ -714,7 +714,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
|
|
|
714
714
|
return;
|
|
715
715
|
}
|
|
716
716
|
UIPasteboard.general.withDataTransfer(e.clipboardData, function(){
|
|
717
|
-
this.keyWindow.application.sendAction('paste');
|
|
717
|
+
this.keyWindow.application.sendAction('paste', null, this);
|
|
718
718
|
}, this);
|
|
719
719
|
},
|
|
720
720
|
|
|
@@ -1513,6 +1513,20 @@ JSClass("UIHTMLDataTransferPasteboard", UIPasteboard, {
|
|
|
1513
1513
|
}
|
|
1514
1514
|
return UIHTMLDataTransferPasteboard.$super.containsType.call(this, type);
|
|
1515
1515
|
},
|
|
1516
|
+
|
|
1517
|
+
withStrings: function(strings, action, target){
|
|
1518
|
+
var locallySetTypes = JSCopy(this._locallySetTypes);
|
|
1519
|
+
try{
|
|
1520
|
+
for (var type in strings){
|
|
1521
|
+
this.setStringForType(strings[type], type);
|
|
1522
|
+
}
|
|
1523
|
+
action.call(target);
|
|
1524
|
+
}finally{
|
|
1525
|
+
this._locallySetTypes = locallySetTypes;
|
|
1526
|
+
this.dataTransfer = null;
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
|
|
1516
1530
|
});
|
|
1517
1531
|
|
|
1518
1532
|
|
|
@@ -116,17 +116,27 @@ JSClass("UIPopupWindow", UIWindow, {
|
|
|
116
116
|
},
|
|
117
117
|
|
|
118
118
|
openAdjacentToView: function(view, preferredPlacement, animated){
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
var rect = view.bounds;
|
|
120
|
+
if (view.sourceRectForPopupWindow){
|
|
121
|
+
rect = view.sourceRectForPopupWindow(this);
|
|
121
122
|
}
|
|
123
|
+
this.openAdjacentToRectInView(rect, view, preferredPlacement, animated);
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
openAtLocationInView: function(location, view, preferredPlacement, animated){
|
|
127
|
+
var rect = JSRect(location, JSSize.Zero);
|
|
128
|
+
this.openAdjacentToRectInView(rect, view, preferredPlacement, animated);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
openAdjacentToRectInView: function(rect, view, preferredPlacement, animated){
|
|
122
132
|
if (view.window === null || view.window.screen === null){
|
|
123
133
|
JSNotificationCenter.shared.post("UIWindowWillClose", this);
|
|
124
134
|
return;
|
|
125
135
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
sourceBounds = view.sourceRectForPopupWindow(this);
|
|
136
|
+
if (animated === undefined){
|
|
137
|
+
animated = true;
|
|
129
138
|
}
|
|
139
|
+
var sourceBounds = rect;
|
|
130
140
|
var sourceFrame = view.convertRectToScreen(sourceBounds).rectWithInsets(-this._sourceSpacing);
|
|
131
141
|
var safeFrame = view.window.screen.availableFrame.rectWithInsets(20);
|
|
132
142
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// #import Foundation
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
JSClass("UITextAction", JSObject, {
|
|
5
|
+
|
|
6
|
+
title: null,
|
|
7
|
+
action: null,
|
|
8
|
+
target: null,
|
|
9
|
+
|
|
10
|
+
initWithTitle: function(title, action, target){
|
|
11
|
+
this.title = title;
|
|
12
|
+
this.action = action;
|
|
13
|
+
this.target = target || null;
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// #import "UIPopupWindow.js"
|
|
2
|
+
// #import "UIButton.js"
|
|
3
|
+
// #import "UIStackView.js"
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
JSClass("UITextActionsMenu", JSObject, {
|
|
7
|
+
|
|
8
|
+
delegate: null,
|
|
9
|
+
|
|
10
|
+
initWithActions: function(actions){
|
|
11
|
+
this.actions = actions;
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
openAtLocationInView: function(location, sourceView){
|
|
15
|
+
if (this._window !== null){
|
|
16
|
+
this._window.orderFront();
|
|
17
|
+
}else{
|
|
18
|
+
var window = UITextActionsMenuWindow.init(UITextActionsMenu.Styler.default);
|
|
19
|
+
window.contentInsets = JSInsets.Zero;
|
|
20
|
+
var buttons = [];
|
|
21
|
+
var button;
|
|
22
|
+
var action;
|
|
23
|
+
for (var i = 0, l = this.actions.length; i < l; ++i){
|
|
24
|
+
action = this.actions[i];
|
|
25
|
+
button = UIButton.initWithStyler(UITextActionsMenu.ButtonStyler.default);
|
|
26
|
+
button.titleLabel.text = action.title;
|
|
27
|
+
button.addAction(action.action, action.target);
|
|
28
|
+
button.addAction("close", this);
|
|
29
|
+
buttons.push(button);
|
|
30
|
+
}
|
|
31
|
+
var stackView = UIStackView.initWithArrangedSubviews(buttons);
|
|
32
|
+
stackView.cornerRadius = window.cornerRadius;
|
|
33
|
+
stackView.clipsToBounds = true;
|
|
34
|
+
stackView.backgroundColor = JSColor.separator;
|
|
35
|
+
stackView.viewSpacing = 1;
|
|
36
|
+
stackView.axis = UIStackView.Axis.horizontal;
|
|
37
|
+
window.contentView = stackView;
|
|
38
|
+
window.openAtLocationInView(location, sourceView, UIPopupWindow.Placement.above, false);
|
|
39
|
+
this._window = window;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
close: function(){
|
|
44
|
+
if (this._window !== null){
|
|
45
|
+
this._window.close();
|
|
46
|
+
this._window = null;
|
|
47
|
+
if (this.delegate && this.delegate.textActionsMenuDidClose){
|
|
48
|
+
this.delegate.textActionsMenuDidClose(this);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
_window: null,
|
|
54
|
+
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
UITextActionsMenu.Styler = Object.create({}, {
|
|
58
|
+
|
|
59
|
+
default: {
|
|
60
|
+
configurable: true,
|
|
61
|
+
get: function(){
|
|
62
|
+
var styler = UIPopupWindowStyler.init();
|
|
63
|
+
styler.cornerRadius = 7;
|
|
64
|
+
Object.defineProperty(this, "default", {value: styler, writable: true});
|
|
65
|
+
return styler;
|
|
66
|
+
},
|
|
67
|
+
set: function(value){
|
|
68
|
+
Object.defineProperty(this, "default", {value: value, writable: true});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
UITextActionsMenu.ButtonStyler = Object.create({}, {
|
|
75
|
+
|
|
76
|
+
default: {
|
|
77
|
+
configurable: true,
|
|
78
|
+
get: function(){
|
|
79
|
+
var styler = UIButtonCustomStyler.initWithBackgroundColor(JSColor.background, JSColor.highlight);
|
|
80
|
+
styler.titleInsets = JSInsets(10, 10, 10, 10);
|
|
81
|
+
Object.defineProperty(this, "default", {value: styler, writable: true});
|
|
82
|
+
return styler;
|
|
83
|
+
},
|
|
84
|
+
set: function(value){
|
|
85
|
+
Object.defineProperty(this, "default", {value: value, writable: true});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
JSClass("UITextActionsMenuWindow", UIPopupWindow, {
|
|
92
|
+
|
|
93
|
+
canBecomeKey: false,
|
|
94
|
+
|
|
95
|
+
});
|
|
@@ -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,
|