├── README.md
└── docs
├── .nojekyll
├── README.md
├── _asset
└── favicon.png
├── _navbar.md
├── _sidebar.md
├── _style
├── custom.css
├── dark.css
└── light.css
├── en
├── README.md
├── _navbar.md
├── _sidebar.md
├── fs
│ ├── intro.md
│ ├── paths.md
│ └── protocol.md
├── native-modules
│ ├── addin.md
│ ├── app.md
│ ├── audio.md
│ ├── calendar.md
│ ├── clipboard.md
│ ├── contact.md
│ ├── detector.md
│ ├── device.md
│ ├── drive.md
│ ├── imagekit.md
│ ├── input.md
│ ├── intro.md
│ ├── l10n.md
│ ├── location.md
│ ├── message.md
│ ├── motion.md
│ ├── photo.md
│ ├── push.md
│ ├── qrcode.md
│ ├── quicklook.md
│ ├── reminder.md
│ ├── safari.md
│ ├── share.md
│ ├── speech.md
│ ├── system.md
│ └── ui.md
├── node-modules
│ ├── builtin.md
│ └── deps.md
├── others
│ └── changelog.md
├── quickstart
│ ├── examples.md
│ └── intro.md
└── vm
│ ├── context.md
│ ├── intro.md
│ ├── jsbox-node.md
│ ├── node-jsbox.md
│ └── objc.md
├── fs
├── intro.md
├── paths.md
└── protocol.md
├── index.html
├── native-modules
├── addin.md
├── app.md
├── audio.md
├── calendar.md
├── clipboard.md
├── contact.md
├── detector.md
├── device.md
├── drive.md
├── imagekit.md
├── input.md
├── intro.md
├── l10n.md
├── location.md
├── message.md
├── motion.md
├── photo.md
├── push.md
├── qrcode.md
├── quicklook.md
├── reminder.md
├── safari.md
├── share.md
├── speech.md
├── system.md
└── ui.md
├── node-modules
├── builtin.md
└── deps.md
├── others
└── changelog.md
├── quickstart
├── examples.md
└── intro.md
└── vm
├── context.md
├── intro.md
├── jsbox-node.md
├── node-jsbox.md
└── objc.md
/README.md:
--------------------------------------------------------------------------------
1 | # JSBox Node.js Online Documentation
2 |
3 | To be continued...
4 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanzhong/jsbox-nodejs/9cf3f42d437edac2dfbbc098d2bafc7ca3eff19f/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | *本文档基于 [Docsify](https://docsify.js.org) 部署在 [GitHub](https://github.com/cyanzhong/jsbox-nodejs),欢迎一起改进*
2 |
3 | # JSBox Node.js
4 |
5 | [JSBox](https://apps.apple.com/cn/app/id1312014438) 2.0 提供了对 Node.js 运行时的支持,由于其工作方式与 JSBox 原生运行时有较大差别,所以文档将单独陈列。
6 |
7 | 关于 JSBox 原生运行时的文档,可以在[这里](https://docs.xteko.com)找到。
8 |
9 | # 联系我们
10 |
11 | 对文档有任何疑问都可以通过以下方式联系我们:
12 |
13 | - Email: [log.e@qq.com](mailto:log.e@qq.com)
14 | - Weibo: [@StackOverflowError](https://weibo.com/0x00eeee)
15 | - Twitter: [@JSBoxApp](https://twitter.com/JSBoxApp)
16 |
17 | *准备好了,[快速开始 >](quickstart/intro.md)*
18 |
19 | > 此文档目前处于测试阶段,之后可能会有变化,如有错误欢迎指正。
--------------------------------------------------------------------------------
/docs/_asset/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cyanzhong/jsbox-nodejs/9cf3f42d437edac2dfbbc098d2bafc7ca3eff19f/docs/_asset/favicon.png
--------------------------------------------------------------------------------
/docs/_navbar.md:
--------------------------------------------------------------------------------
1 | - [EN / **CN**](/en/)
--------------------------------------------------------------------------------
/docs/_sidebar.md:
--------------------------------------------------------------------------------
1 | - 快速开始
2 | - [README](README.md)
3 | - [简要介绍](quickstart/intro.md)
4 | - [样例项目](quickstart/examples.md)
5 |
6 | - Node 模块
7 | - [内置模块](node-modules/builtin.md)
8 | - [依赖管理](node-modules/deps.md)
9 |
10 | - 文件系统
11 | - [简要介绍](fs/intro.md)
12 | - [文件路径](fs/paths.md)
13 | - [文件协议](fs/protocol.md)
14 |
15 | - Native 模块
16 | - [简要介绍](native-modules/intro.md)
17 | - [应用相关](native-modules/app.md)
18 | - [系统相关](native-modules/system.md)
19 | - [设备相关](native-modules/device.md)
20 | - [用户输入](native-modules/input.md)
21 | - [用户界面](native-modules/ui.md)
22 | - [本地化](native-modules/l10n.md)
23 | - [剪贴板](native-modules/clipboard.md)
24 | - [图片](native-modules/photo.md)
25 | - [图像处理](native-modules/imagekit.md)
26 | - [iCloud 云盘](native-modules/drive.md)
27 | - [预览](native-modules/quicklook.md)
28 | - [社交分享](native-modules/share.md)
29 | - [二维码](native-modules/qrcode.md)
30 | - [地理位置](native-modules/location.md)
31 | - [Safari](native-modules/safari.md)
32 | - [推送](native-modules/push.md)
33 | - [音频](native-modules/audio.md)
34 | - [语音合成](native-modules/speech.md)
35 | - [日历](native-modules/calendar.md)
36 | - [提醒事项](native-modules/reminder.md)
37 | - [通讯录](native-modules/contact.md)
38 | - [消息](native-modules/message.md)
39 | - [传感数据](native-modules/motion.md)
40 | - [数据检测](native-modules/detector.md)
41 | - [脚本管理](native-modules/addin.md)
42 |
43 | - 通信机制
44 | - [简要介绍](vm/intro.md)
45 | - [Node 调用 JSBox](vm/node-jsbox.md)
46 | - [Node 获取参数](vm/context.md)
47 | - [Objective-C](vm/objc.md)
48 | - [JSBox 调用 Node](vm/jsbox-node.md)
49 |
50 | - 其他内容
51 | - [更新日志](others/changelog.md)
--------------------------------------------------------------------------------
/docs/_style/custom.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 17px;
3 | }
4 |
5 | input {
6 | border-radius: 4px;
7 | }
8 |
9 | h2 > a.anchor {
10 | margin-top: 12px;
11 | }
12 |
13 | .app-nav a {
14 | font-size: 17px;
15 | }
16 |
17 | .app-nav > ul > li > a.active {
18 | color: inherit;
19 | border-bottom: none;
20 | }
21 |
22 | .sidebar > h1 {
23 | font-weight: 700;
24 | }
25 |
26 | .sidebar ul, .sidebar ul li {
27 | font-weight: 600;
28 | }
29 |
30 | .sidebar ul li a {
31 | font-size: 15px;
32 | }
33 |
34 | .sidebar-toggle {
35 | margin-left: 0px;
36 | margin-right: 0px;
37 | bottom: -6px;
38 | }
39 |
40 | .sidebar-toggle span {
41 | width: 24px;
42 | margin-bottom: 6px;
43 | }
44 |
45 | .sidebar-toggle:hover .sidebar-toggle-button {
46 | opacity: 1;
47 | }
48 |
49 | .sidebar-nav {
50 | margin-bottom: 80px;
51 | }
52 |
53 | .markdown-section pre {
54 | border-radius: 4px;
55 | }
56 |
57 | .markdown-section code {
58 | color: #ff9500;
59 | font-weight: 600;
60 | }
61 |
62 | .markdown-section blockquote {
63 | background: #f8f8f8;
64 | padding-top: 2px;
65 | padding-bottom: 2px;
66 | }
67 |
68 | .markdown-section blockquote p {
69 | margin-top: 0.5em;
70 | margin-bottom: 0.5em;
71 | }
72 |
73 | @media screen and (max-width: 768px) {
74 | .sidebar-toggle {
75 | bottom: -10px;
76 | }
77 | .sidebar-toggle span {
78 | width: 32px;
79 | margin-bottom: 8px;
80 | height: 3px;
81 | }
82 | .markdown-section {
83 | max-width: 95%;
84 | }
85 | .markdown-section pre {
86 | padding: 0 0.8rem;
87 | }
88 | .markdown-section pre > code {
89 | padding: 1.5em 5px;
90 | }
91 | }
92 |
93 | .token.comment,
94 | .token.block-comment,
95 | .token.prolog,
96 | .token.doctype,
97 | .token.cdata {
98 | color: #7D8B99;
99 | }
100 |
101 | .token.punctuation {
102 | color: #5F6364;
103 | }
104 |
105 | .token.property,
106 | .token.tag,
107 | .token.boolean,
108 | .token.number,
109 | .token.function-name,
110 | .token.constant,
111 | .token.symbol,
112 | .token.deleted {
113 | color: #c92c2c;
114 | }
115 |
116 | .token.selector,
117 | .token.attr-name,
118 | .token.string,
119 | .token.char,
120 | .token.function,
121 | .token.builtin,
122 | .token.inserted {
123 | color: #2f9c0a;
124 | }
125 |
126 | .token.operator {
127 | color: #a67f59;
128 | }
129 |
130 | .token.entity,
131 | .token.url,
132 | .token.variable {
133 | color: #a67f59;
134 | background: rgba(255, 255, 255, 0.5);
135 | }
136 |
137 | .token.atrule,
138 | .token.attr-value,
139 | .token.keyword,
140 | .token.class-name {
141 | color: #1990b8;
142 | }
143 |
144 | .token.regex,
145 | .token.important {
146 | color: #e90;
147 | }
148 |
149 | .language-css .token.string,
150 | .style .token.string {
151 | color: #a67f59;
152 | background: rgba(255, 255, 255, 0.5);
153 | }
154 |
155 | .token.important {
156 | font-weight: normal;
157 | }
158 |
159 | .token.bold {
160 | font-weight: bold;
161 | }
162 |
163 | .token.italic {
164 | font-style: italic;
165 | }
166 |
167 | .token.entity {
168 | cursor: help;
169 | }
170 |
171 | .token.namespace {
172 | opacity: .7;
173 | }
174 |
175 | .markdown-section pre {
176 | background-color: #fafafa;
177 | }
178 |
179 | .markdown-section pre > code {
180 | background-color: #fafafa;
181 | color: #34495e;
182 | font-weight: normal;
183 | }
184 |
185 | pre::after {
186 | content: "";
187 | }
--------------------------------------------------------------------------------
/docs/_style/dark.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | background-color: #0c0c0c;
3 | color: #e3e3e3;
4 | }
5 |
6 | kbd {
7 | border-color: #444444;
8 | }
9 |
10 | .app-nav li ul {
11 | background-color: #0c0c0c;
12 | border: #333333;
13 | border-bottom-color: #444444;
14 | }
15 |
16 | .search {
17 | border-bottom-color: rgba(255, 255, 255, 0.07) !important;
18 | }
19 |
20 | .search input {
21 | color: #e3e3e3;
22 | }
23 |
24 | .docsify-pagination-container {
25 | border-top-color: rgba(255, 255, 255, 0.07) !important;
26 | }
27 |
28 | input {
29 | background-color: #0c0c0c;
30 | }
31 |
32 | .sidebar {
33 | background-color: #0c0c0c;
34 | color: #ffffff;
35 | border-right-color: rgba(255, 255, 255, 0.07);
36 | }
37 |
38 | .sidebar-toggle {
39 | background-color: rgba(12, 12, 12, 0.8);
40 | }
41 |
42 | .sidebar ul li a {
43 | color: rgba(255, 255, 255, 0.8);
44 | }
45 |
46 | .markdown-section hr {
47 | border-bottom-color: #222222;
48 | }
49 |
50 | .markdown-section iframe {
51 | border-color: #222222;
52 | }
53 |
54 | .github-corner svg {
55 | color: #0c0c0c;
56 | }
57 |
58 | .markdown-section th {
59 | border-color: #333333;
60 | background-color: #1e1e1e;
61 | }
62 |
63 | .markdown-section td {
64 | border-color: #333333;
65 | }
66 |
67 | .markdown-section tr {
68 | border-top-color: #444;
69 | }
70 |
71 | .markdown-section tr:nth-child(2n) {
72 | background-color: #1e1e1e;
73 | }
74 |
75 | .markdown-section p.tip {
76 | background-color: #1e1e1e;
77 | }
78 |
79 | .markdown-section p.tip:before {
80 | color: #0c0c0c;
81 | }
82 |
83 | .markdown-section p.tip code {
84 | background-color: #222222;
85 | }
86 |
87 | .markdown-section h1,
88 | .markdown-section h2,
89 | .markdown-section h3,
90 | .markdown-section h4,
91 | .anchor span {
92 | color: #ffffff;
93 | }
94 |
95 | .markdown-section strong {
96 | color: #c5e2ff;
97 | }
98 |
99 | .markdown-section code {
100 | color: #ff9f0a;
101 | background-color: #1e1e1e;
102 | }
103 |
104 | .markdown-section blockquote {
105 | background: #1e1e1e;
106 | }
107 |
108 | @media screen and (max-width: 768px) {
109 | .sidebar-toggle {
110 | background-color: transparent;
111 | }
112 | body.close .sidebar-toggle {
113 | background-color: rgba(12, 12, 12, 0.8);
114 | }
115 | }
116 |
117 | section.cover.has-mask .mask {
118 | background-color: #0c0c0c;
119 | }
120 |
121 | section.cover .cover-main > p:last-child a:last-child {
122 | color: #0c0c0c;
123 | }
124 |
125 | .token.comment,
126 | .token.prolog,
127 | .token.doctype,
128 | .token.cdata {
129 | color: #7C7C7C;
130 | }
131 |
132 | .token.punctuation {
133 | color: #c5c8c6;
134 | }
135 |
136 | .namespace {
137 | opacity: .7;
138 | }
139 |
140 | .token.property,
141 | .token.keyword,
142 | .token.tag {
143 | color: #96CBFE;
144 | }
145 |
146 | .token.class-name {
147 | color: #FFFFB6;
148 | text-decoration: underline;
149 | }
150 |
151 | .token.boolean,
152 | .token.constant {
153 | color: #99CC99;
154 | }
155 |
156 | .token.symbol,
157 | .token.deleted {
158 | color: #f92672;
159 | }
160 |
161 | .token.number {
162 | color: #FF73FD;
163 | }
164 |
165 | .token.selector,
166 | .token.attr-name,
167 | .token.string,
168 | .token.char,
169 | .token.builtin,
170 | .token.inserted {
171 | color: #A8FF60;
172 | }
173 |
174 | .token.variable {
175 | color: #C6C5FE;
176 | }
177 |
178 | .token.operator {
179 | color: #EDEDED;
180 | }
181 |
182 | .token.entity {
183 | color: #FFFFB6;
184 | cursor: help;
185 | }
186 |
187 | .token.url {
188 | color: #96CBFE;
189 | }
190 |
191 | .language-css .token.string,
192 | .style .token.string {
193 | color: #87C38A;
194 | }
195 |
196 | .token.atrule,
197 | .token.attr-value {
198 | color: #F9EE98;
199 | }
200 |
201 | .token.function {
202 | color: #DAD085;
203 | }
204 |
205 | .token.regex {
206 | color: #E9C062;
207 | }
208 |
209 | .token.important {
210 | color: #fd971f;
211 | }
212 |
213 | .token.important,
214 | .token.bold {
215 | font-weight: bold;
216 | }
217 |
218 | .token.italic {
219 | font-style: italic;
220 | }
221 |
222 | .markdown-section pre {
223 | background-color: #1d1f21;
224 | }
225 |
226 | .markdown-section pre > code {
227 | background-color: #1d1f21;
228 | color: #e3e3e3;
229 | }
--------------------------------------------------------------------------------
/docs/_style/light.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");
2 | * {
3 | -webkit-font-smoothing: antialiased;
4 | -webkit-overflow-scrolling: touch;
5 | -webkit-tap-highlight-color: rgba(0,0,0,0);
6 | -webkit-text-size-adjust: none;
7 | -webkit-touch-callout: none;
8 | box-sizing: border-box;
9 | }
10 | body:not(.ready) {
11 | overflow: hidden;
12 | }
13 | body:not(.ready) [data-cloak],
14 | body:not(.ready) .app-nav,
15 | body:not(.ready) > nav {
16 | display: none;
17 | }
18 | div#app {
19 | font-size: 30px;
20 | font-weight: lighter;
21 | margin: 40vh auto;
22 | text-align: center;
23 | }
24 | div#app:empty::before {
25 | content: 'Loading...';
26 | }
27 | .emoji {
28 | height: 1.2rem;
29 | vertical-align: middle;
30 | }
31 | .progress {
32 | background-color: var(--theme-color, #42b983);
33 | height: 2px;
34 | left: 0px;
35 | position: fixed;
36 | right: 0px;
37 | top: 0px;
38 | transition: width 0.2s, opacity 0.4s;
39 | width: 0%;
40 | z-index: 999999;
41 | }
42 | .search a:hover {
43 | color: var(--theme-color, #42b983);
44 | }
45 | .search .search-keyword {
46 | color: var(--theme-color, #42b983);
47 | font-style: normal;
48 | font-weight: bold;
49 | }
50 | html,
51 | body {
52 | height: 100%;
53 | }
54 | body {
55 | -moz-osx-font-smoothing: grayscale;
56 | -webkit-font-smoothing: antialiased;
57 | color: #34495e;
58 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
59 | font-size: 15px;
60 | letter-spacing: 0;
61 | margin: 0;
62 | overflow-x: hidden;
63 | }
64 | img {
65 | max-width: 100%;
66 | }
67 | a[disabled] {
68 | cursor: not-allowed;
69 | opacity: 0.6;
70 | }
71 | kbd {
72 | border: solid 1px #ccc;
73 | border-radius: 3px;
74 | display: inline-block;
75 | font-size: 12px !important;
76 | line-height: 12px;
77 | margin-bottom: 3px;
78 | padding: 3px 5px;
79 | vertical-align: middle;
80 | }
81 | li input[type='checkbox'] {
82 | margin: 0 0.2em 0.25em 0;
83 | vertical-align: middle;
84 | }
85 | .app-nav {
86 | margin: 25px 60px 0 0;
87 | position: absolute;
88 | right: 0;
89 | text-align: right;
90 | z-index: 10;
91 | /* navbar dropdown */
92 | }
93 | .app-nav.no-badge {
94 | margin-right: 25px;
95 | }
96 | .app-nav p {
97 | margin: 0;
98 | }
99 | .app-nav > a {
100 | margin: 0 1rem;
101 | padding: 5px 0;
102 | }
103 | .app-nav ul,
104 | .app-nav li {
105 | display: inline-block;
106 | list-style: none;
107 | margin: 0;
108 | }
109 | .app-nav a {
110 | color: inherit;
111 | font-size: 16px;
112 | text-decoration: none;
113 | transition: color 0.3s;
114 | }
115 | .app-nav a:hover {
116 | color: var(--theme-color, #42b983);
117 | }
118 | .app-nav a.active {
119 | border-bottom: 2px solid var(--theme-color, #42b983);
120 | color: var(--theme-color, #42b983);
121 | }
122 | .app-nav li {
123 | display: inline-block;
124 | margin: 0 1rem;
125 | padding: 5px 0;
126 | position: relative;
127 | cursor: pointer;
128 | }
129 | .app-nav li ul {
130 | background-color: #fff;
131 | border: 1px solid #ddd;
132 | border-bottom-color: #ccc;
133 | border-radius: 4px;
134 | box-sizing: border-box;
135 | display: none;
136 | max-height: calc(100vh - 61px);
137 | overflow-y: auto;
138 | padding: 10px 0;
139 | position: absolute;
140 | right: -15px;
141 | text-align: left;
142 | top: 100%;
143 | white-space: nowrap;
144 | }
145 | .app-nav li ul li {
146 | display: block;
147 | font-size: 14px;
148 | line-height: 1rem;
149 | margin: 0;
150 | margin: 8px 14px;
151 | white-space: nowrap;
152 | }
153 | .app-nav li ul a {
154 | display: block;
155 | font-size: inherit;
156 | margin: 0;
157 | padding: 0;
158 | }
159 | .app-nav li ul a.active {
160 | border-bottom: 0;
161 | }
162 | .app-nav li:hover ul {
163 | display: block;
164 | }
165 | .github-corner {
166 | border-bottom: 0;
167 | position: fixed;
168 | right: 0;
169 | text-decoration: none;
170 | top: 0;
171 | z-index: 1;
172 | }
173 | .github-corner:hover .octo-arm {
174 | -webkit-animation: octocat-wave 560ms ease-in-out;
175 | animation: octocat-wave 560ms ease-in-out;
176 | }
177 | .github-corner svg {
178 | color: #fff;
179 | fill: var(--theme-color, #42b983);
180 | height: 80px;
181 | width: 80px;
182 | }
183 | main {
184 | display: block;
185 | position: relative;
186 | width: 100vw;
187 | height: 100%;
188 | z-index: 0;
189 | }
190 | main.hidden {
191 | display: none;
192 | }
193 | .anchor {
194 | display: inline-block;
195 | text-decoration: none;
196 | transition: all 0.3s;
197 | }
198 | .anchor span {
199 | color: #34495e;
200 | }
201 | .anchor:hover {
202 | text-decoration: underline;
203 | }
204 | .sidebar {
205 | border-right: 1px solid rgba(0,0,0,0.07);
206 | overflow-y: auto;
207 | padding: 40px 0 0;
208 | position: absolute;
209 | top: 0;
210 | bottom: 0;
211 | left: 0;
212 | transition: transform 250ms ease-out;
213 | width: 300px;
214 | z-index: 20;
215 | }
216 | .sidebar > h1 {
217 | margin: 0 auto 1rem;
218 | font-size: 1.5rem;
219 | font-weight: 300;
220 | text-align: center;
221 | }
222 | .sidebar > h1 a {
223 | color: inherit;
224 | text-decoration: none;
225 | }
226 | .sidebar > h1 .app-nav {
227 | display: block;
228 | position: static;
229 | }
230 | .sidebar .sidebar-nav {
231 | line-height: 2em;
232 | padding-bottom: 40px;
233 | }
234 | .sidebar li.collapse .app-sub-sidebar {
235 | display: none;
236 | }
237 | .sidebar ul {
238 | margin: 0 0 0 15px;
239 | padding: 0;
240 | }
241 | .sidebar li > p {
242 | font-weight: 700;
243 | margin: 0;
244 | }
245 | .sidebar ul,
246 | .sidebar ul li {
247 | list-style: none;
248 | }
249 | .sidebar ul li a {
250 | border-bottom: none;
251 | display: block;
252 | }
253 | .sidebar ul li ul {
254 | padding-left: 20px;
255 | }
256 | .sidebar::-webkit-scrollbar {
257 | width: 4px;
258 | }
259 | .sidebar::-webkit-scrollbar-thumb {
260 | background: transparent;
261 | border-radius: 4px;
262 | }
263 | .sidebar:hover::-webkit-scrollbar-thumb {
264 | background: rgba(136,136,136,0.4);
265 | }
266 | .sidebar:hover::-webkit-scrollbar-track {
267 | background: rgba(136,136,136,0.1);
268 | }
269 | .sidebar-toggle {
270 | background-color: transparent;
271 | background-color: rgba(255,255,255,0.8);
272 | border: 0;
273 | outline: none;
274 | padding: 10px;
275 | position: absolute;
276 | bottom: 0;
277 | left: 0;
278 | text-align: center;
279 | transition: opacity 0.3s;
280 | width: 284px;
281 | z-index: 30;
282 | cursor: pointer;
283 | }
284 | .sidebar-toggle:hover .sidebar-toggle-button {
285 | opacity: 0.4;
286 | }
287 | .sidebar-toggle span {
288 | background-color: var(--theme-color, #42b983);
289 | display: block;
290 | margin-bottom: 4px;
291 | width: 16px;
292 | height: 2px;
293 | }
294 | body.sticky .sidebar,
295 | body.sticky .sidebar-toggle {
296 | position: fixed;
297 | }
298 | .content {
299 | padding-top: 60px;
300 | position: absolute;
301 | top: 0;
302 | right: 0;
303 | bottom: 0;
304 | left: 300px;
305 | transition: left 250ms ease;
306 | }
307 | .markdown-section {
308 | margin: 0 auto;
309 | max-width: 80%;
310 | padding: 30px 15px 40px 15px;
311 | position: relative;
312 | }
313 | .markdown-section > * {
314 | box-sizing: border-box;
315 | font-size: inherit;
316 | }
317 | .markdown-section > :first-child {
318 | margin-top: 0 !important;
319 | }
320 | .markdown-section hr {
321 | border: none;
322 | border-bottom: 1px solid #eee;
323 | margin: 2em 0;
324 | }
325 | .markdown-section iframe {
326 | border: 1px solid #eee;
327 | /* fix horizontal overflow on iOS Safari */
328 | width: 1px;
329 | min-width: 100%;
330 | }
331 | .markdown-section table {
332 | border-collapse: collapse;
333 | border-spacing: 0;
334 | display: block;
335 | margin-bottom: 1rem;
336 | overflow: auto;
337 | width: 100%;
338 | }
339 | .markdown-section th {
340 | border: 1px solid #ddd;
341 | font-weight: bold;
342 | padding: 6px 13px;
343 | background-color: #f8f8f8;
344 | }
345 | .markdown-section td {
346 | border: 1px solid #ddd;
347 | padding: 6px 13px;
348 | }
349 | .markdown-section tr {
350 | border-top: 1px solid #ccc;
351 | }
352 | .markdown-section tr:nth-child(2n) {
353 | background-color: #f8f8f8;
354 | }
355 | .markdown-section p.tip {
356 | background-color: #f8f8f8;
357 | border-bottom-right-radius: 2px;
358 | border-left: 4px solid #f66;
359 | border-top-right-radius: 2px;
360 | margin: 2em 0;
361 | padding: 12px 24px 12px 30px;
362 | position: relative;
363 | }
364 | .markdown-section p.tip:before {
365 | background-color: #f66;
366 | border-radius: 100%;
367 | color: #fff;
368 | content: '!';
369 | font-family: 'Dosis', 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
370 | font-size: 14px;
371 | font-weight: bold;
372 | left: -12px;
373 | line-height: 20px;
374 | position: absolute;
375 | height: 20px;
376 | width: 20px;
377 | text-align: center;
378 | top: 14px;
379 | }
380 | .markdown-section p.tip code {
381 | background-color: #efefef;
382 | }
383 | .markdown-section p.tip em {
384 | color: #34495e;
385 | }
386 | .markdown-section p.warn {
387 | background: rgba(66,185,131,0.1);
388 | border-radius: 2px;
389 | padding: 1rem;
390 | }
391 | .markdown-section ul.task-list > li {
392 | list-style-type: none;
393 | }
394 | body.close .sidebar {
395 | transform: translateX(-300px);
396 | }
397 | body.close .sidebar-toggle {
398 | width: auto;
399 | }
400 | body.close .content {
401 | left: 0;
402 | }
403 | @media print {
404 | .github-corner,
405 | .sidebar-toggle,
406 | .sidebar,
407 | .app-nav {
408 | display: none;
409 | }
410 | }
411 | @media screen and (max-width: 768px) {
412 | .github-corner,
413 | .sidebar-toggle,
414 | .sidebar {
415 | position: fixed;
416 | }
417 | .app-nav {
418 | margin-top: 16px;
419 | }
420 | .app-nav li ul {
421 | top: 30px;
422 | }
423 | main {
424 | height: auto;
425 | overflow-x: hidden;
426 | }
427 | .sidebar {
428 | left: -300px;
429 | transition: transform 250ms ease-out;
430 | }
431 | .content {
432 | left: 0;
433 | max-width: 100vw;
434 | position: static;
435 | padding-top: 20px;
436 | transition: transform 250ms ease;
437 | }
438 | .app-nav,
439 | .github-corner {
440 | transition: transform 250ms ease-out;
441 | }
442 | .sidebar-toggle {
443 | background-color: transparent;
444 | width: auto;
445 | padding: 30px 30px 10px 10px;
446 | }
447 | body.close .sidebar {
448 | transform: translateX(300px);
449 | }
450 | body.close .sidebar-toggle {
451 | background-color: rgba(255,255,255,0.8);
452 | transition: 1s background-color;
453 | width: 284px;
454 | padding: 10px;
455 | }
456 | body.close .content {
457 | transform: translateX(300px);
458 | }
459 | body.close .app-nav,
460 | body.close .github-corner {
461 | display: none;
462 | }
463 | .github-corner:hover .octo-arm {
464 | -webkit-animation: none;
465 | animation: none;
466 | }
467 | .github-corner .octo-arm {
468 | -webkit-animation: octocat-wave 560ms ease-in-out;
469 | animation: octocat-wave 560ms ease-in-out;
470 | }
471 | }
472 | @-webkit-keyframes octocat-wave {
473 | 0%, 100% {
474 | transform: rotate(0);
475 | }
476 | 20%, 60% {
477 | transform: rotate(-25deg);
478 | }
479 | 40%, 80% {
480 | transform: rotate(10deg);
481 | }
482 | }
483 | @keyframes octocat-wave {
484 | 0%, 100% {
485 | transform: rotate(0);
486 | }
487 | 20%, 60% {
488 | transform: rotate(-25deg);
489 | }
490 | 40%, 80% {
491 | transform: rotate(10deg);
492 | }
493 | }
494 | section.cover {
495 | align-items: center;
496 | background-position: center center;
497 | background-repeat: no-repeat;
498 | background-size: cover;
499 | height: 100vh;
500 | width: 100vw;
501 | display: none;
502 | }
503 | section.cover.show {
504 | display: flex;
505 | }
506 | section.cover.has-mask .mask {
507 | background-color: #fff;
508 | opacity: 0.8;
509 | position: absolute;
510 | top: 0;
511 | height: 100%;
512 | width: 100%;
513 | }
514 | section.cover .cover-main {
515 | flex: 1;
516 | margin: -20px 16px 0;
517 | text-align: center;
518 | position: relative;
519 | }
520 | section.cover a {
521 | color: inherit;
522 | text-decoration: none;
523 | }
524 | section.cover a:hover {
525 | text-decoration: none;
526 | }
527 | section.cover p {
528 | line-height: 1.5rem;
529 | margin: 1em 0;
530 | }
531 | section.cover h1 {
532 | color: inherit;
533 | font-size: 2.5rem;
534 | font-weight: 300;
535 | margin: 0.625rem 0 2.5rem;
536 | position: relative;
537 | text-align: center;
538 | }
539 | section.cover h1 a {
540 | display: block;
541 | }
542 | section.cover h1 small {
543 | bottom: -0.4375rem;
544 | font-size: 1rem;
545 | position: absolute;
546 | }
547 | section.cover blockquote {
548 | font-size: 1.5rem;
549 | text-align: center;
550 | }
551 | section.cover ul {
552 | line-height: 1.8;
553 | list-style-type: none;
554 | margin: 1em auto;
555 | max-width: 500px;
556 | padding: 0;
557 | }
558 | section.cover .cover-main > p:last-child a {
559 | border-color: var(--theme-color, #42b983);
560 | border-radius: 2rem;
561 | border-style: solid;
562 | border-width: 1px;
563 | box-sizing: border-box;
564 | color: var(--theme-color, #42b983);
565 | display: inline-block;
566 | font-size: 1.05rem;
567 | letter-spacing: 0.1rem;
568 | margin: 0.5rem 1rem;
569 | padding: 0.75em 2rem;
570 | text-decoration: none;
571 | transition: all 0.15s ease;
572 | }
573 | section.cover .cover-main > p:last-child a:last-child {
574 | background-color: var(--theme-color, #42b983);
575 | color: #fff;
576 | }
577 | section.cover .cover-main > p:last-child a:last-child:hover {
578 | color: inherit;
579 | opacity: 0.8;
580 | }
581 | section.cover .cover-main > p:last-child a:hover {
582 | color: inherit;
583 | }
584 | section.cover blockquote > p > a {
585 | border-bottom: 2px solid var(--theme-color, #42b983);
586 | transition: color 0.3s;
587 | }
588 | section.cover blockquote > p > a:hover {
589 | color: var(--theme-color, #42b983);
590 | }
591 | body {
592 | background-color: #fff;
593 | }
594 | /* sidebar */
595 | .sidebar {
596 | background-color: #fff;
597 | color: #364149;
598 | }
599 | .sidebar li {
600 | margin: 6px 0 6px 0;
601 | }
602 | .sidebar ul li a {
603 | color: #505d6b;
604 | font-size: 14px;
605 | font-weight: normal;
606 | overflow: hidden;
607 | text-decoration: none;
608 | text-overflow: ellipsis;
609 | white-space: nowrap;
610 | }
611 | .sidebar ul li a:hover {
612 | text-decoration: underline;
613 | }
614 | .sidebar ul li ul {
615 | padding: 0;
616 | }
617 | .sidebar ul li.active > a {
618 | border-right: 2px solid;
619 | color: var(--theme-color, #42b983);
620 | font-weight: 600;
621 | }
622 | .app-sub-sidebar li::before {
623 | content: '-';
624 | padding-right: 4px;
625 | float: left;
626 | }
627 | /* markdown content found on pages */
628 | .markdown-section h1,
629 | .markdown-section h2,
630 | .markdown-section h3,
631 | .markdown-section h4,
632 | .markdown-section strong {
633 | color: #2c3e50;
634 | font-weight: 600;
635 | }
636 | .markdown-section a {
637 | color: var(--theme-color, #42b983);
638 | font-weight: 600;
639 | }
640 | .markdown-section h1 {
641 | font-size: 2rem;
642 | margin: 0 0 1rem;
643 | }
644 | .markdown-section h2 {
645 | font-size: 1.75rem;
646 | margin: 45px 0 0.8rem;
647 | }
648 | .markdown-section h3 {
649 | font-size: 1.5rem;
650 | margin: 40px 0 0.6rem;
651 | }
652 | .markdown-section h4 {
653 | font-size: 1.25rem;
654 | }
655 | .markdown-section h5 {
656 | font-size: 1rem;
657 | }
658 | .markdown-section h6 {
659 | color: #777;
660 | font-size: 1rem;
661 | }
662 | .markdown-section figure,
663 | .markdown-section p {
664 | margin: 1.2em 0;
665 | }
666 | .markdown-section p,
667 | .markdown-section ul,
668 | .markdown-section ol {
669 | line-height: 1.6rem;
670 | word-spacing: 0.05rem;
671 | }
672 | .markdown-section ul,
673 | .markdown-section ol {
674 | padding-left: 1.5rem;
675 | }
676 | .markdown-section blockquote {
677 | border-left: 4px solid var(--theme-color, #42b983);
678 | color: #858585;
679 | margin: 2em 0;
680 | padding-left: 20px;
681 | }
682 | .markdown-section blockquote p {
683 | font-weight: 600;
684 | margin-left: 0;
685 | }
686 | .markdown-section iframe {
687 | margin: 1em 0;
688 | }
689 | .markdown-section em {
690 | color: #7f8c8d;
691 | }
692 | .markdown-section code {
693 | background-color: #f8f8f8;
694 | border-radius: 2px;
695 | color: #e96900;
696 | font-family: 'Roboto Mono', Monaco, courier, monospace;
697 | font-size: 0.8rem;
698 | margin: 0 2px;
699 | padding: 3px 5px;
700 | white-space: pre-wrap;
701 | }
702 | .markdown-section pre {
703 | -moz-osx-font-smoothing: initial;
704 | -webkit-font-smoothing: initial;
705 | background-color: #f8f8f8;
706 | font-family: 'Roboto Mono', Monaco, courier, monospace;
707 | line-height: 1.5rem;
708 | margin: 1.2em 0;
709 | overflow: auto;
710 | padding: 0 1.4rem;
711 | position: relative;
712 | word-wrap: normal;
713 | }
714 | /* code highlight */
715 | .token.comment,
716 | .token.prolog,
717 | .token.doctype,
718 | .token.cdata {
719 | color: #8e908c;
720 | }
721 | .token.namespace {
722 | opacity: 0.7;
723 | }
724 | .token.boolean,
725 | .token.number {
726 | color: #c76b29;
727 | }
728 | .token.punctuation {
729 | color: #525252;
730 | }
731 | .token.property {
732 | color: #c08b30;
733 | }
734 | .token.tag {
735 | color: #2973b7;
736 | }
737 | .token.string {
738 | color: var(--theme-color, #42b983);
739 | }
740 | .token.selector {
741 | color: #6679cc;
742 | }
743 | .token.attr-name {
744 | color: #2973b7;
745 | }
746 | .token.entity,
747 | .token.url,
748 | .language-css .token.string,
749 | .style .token.string {
750 | color: #22a2c9;
751 | }
752 | .token.attr-value,
753 | .token.control,
754 | .token.directive,
755 | .token.unit {
756 | color: var(--theme-color, #42b983);
757 | }
758 | .token.keyword,
759 | .token.function {
760 | color: #e96900;
761 | }
762 | .token.statement,
763 | .token.regex,
764 | .token.atrule {
765 | color: #22a2c9;
766 | }
767 | .token.placeholder,
768 | .token.variable {
769 | color: #3d8fd1;
770 | }
771 | .token.deleted {
772 | text-decoration: line-through;
773 | }
774 | .token.inserted {
775 | border-bottom: 1px dotted #202746;
776 | text-decoration: none;
777 | }
778 | .token.italic {
779 | font-style: italic;
780 | }
781 | .token.important,
782 | .token.bold {
783 | font-weight: bold;
784 | }
785 | .token.important {
786 | color: #c94922;
787 | }
788 | .token.entity {
789 | cursor: help;
790 | }
791 | .markdown-section pre > code {
792 | -moz-osx-font-smoothing: initial;
793 | -webkit-font-smoothing: initial;
794 | background-color: #f8f8f8;
795 | border-radius: 2px;
796 | color: #525252;
797 | display: block;
798 | font-family: 'Roboto Mono', Monaco, courier, monospace;
799 | font-size: 0.8rem;
800 | line-height: inherit;
801 | margin: 0 2px;
802 | max-width: inherit;
803 | overflow: inherit;
804 | padding: 2.2em 5px;
805 | white-space: inherit;
806 | }
807 | .markdown-section code::after,
808 | .markdown-section code::before {
809 | letter-spacing: 0.05rem;
810 | }
811 | code .token {
812 | -moz-osx-font-smoothing: initial;
813 | -webkit-font-smoothing: initial;
814 | min-height: 1.5rem;
815 | position: relative;
816 | left: auto;
817 | }
818 | pre::after {
819 | color: #ccc;
820 | content: attr(data-lang);
821 | font-size: 0.6rem;
822 | font-weight: 600;
823 | height: 15px;
824 | line-height: 15px;
825 | padding: 5px 10px 0;
826 | position: absolute;
827 | right: 0;
828 | text-align: right;
829 | top: 0;
830 | }
831 |
--------------------------------------------------------------------------------
/docs/en/README.md:
--------------------------------------------------------------------------------
1 | *This website is based on [Docsify](https://docsify.js.org) hosted on the [GitHub](https://github.com/cyanzhong/jsbox-nodejs),pull requests are welcome.*
2 |
3 | # JSBox Node.js
4 |
5 | [JSBox](https://apps.apple.com/us/app/id1312014438) 2.0 provides support for the Node.js runtime, the corresponding documentation is hosted separately since it's quite different compared to the JSBox runtime.
6 |
7 | If you are interested in the JSBox runtime's documentation, you could find it [here](https://docs.xteko.com/#/en/).
8 |
9 | # Contact us
10 |
11 | If you have any questions or suggestions, feel free to reach us out:
12 |
13 | - Email: [log.e@qq.com](mailto:log.e@qq.com)
14 | - Weibo: [@StackOverflowError](https://weibo.com/0x00eeee)
15 | - Twitter: [@JSBoxApp](https://twitter.com/JSBoxApp)
16 |
17 | *I'm ready, [let's get started >](en/quickstart/intro.md)*
18 |
19 | > This document is still under construction, please be aware of changes
--------------------------------------------------------------------------------
/docs/en/_navbar.md:
--------------------------------------------------------------------------------
1 | - [**EN** / CN](/)
--------------------------------------------------------------------------------
/docs/en/_sidebar.md:
--------------------------------------------------------------------------------
1 | - Quick Start
2 | - [README](en/README.md)
3 | - [Intro](en/quickstart/intro.md)
4 | - [Examples](en/quickstart/examples.md)
5 |
6 | - Node Modules
7 | - [Built-in Modules](en/node-modules/builtin.md)
8 | - [Dependencies](en/node-modules/deps.md)
9 |
10 | - File System
11 | - [Intro](en/fs/intro.md)
12 | - [Paths](en/fs/paths.md)
13 | - [File Protocol](en/fs/protocol.md)
14 |
15 | - Native Modules
16 | - [Intro](en/native-modules/intro.md)
17 | - [App](en/native-modules/app.md)
18 | - [System](en/native-modules/system.md)
19 | - [Device](en/native-modules/device.md)
20 | - [Input](en/native-modules/input.md)
21 | - [UI](en/native-modules/ui.md)
22 | - [Localization](en/native-modules/l10n.md)
23 | - [Clipboard](en/native-modules/clipboard.md)
24 | - [Photo](en/native-modules/photo.md)
25 | - [Image Processing](en/native-modules/imagekit.md)
26 | - [iCloud Drive](en/native-modules/drive.md)
27 | - [Quick Look](en/native-modules/quicklook.md)
28 | - [Sharing](en/native-modules/share.md)
29 | - [QR Code](en/native-modules/qrcode.md)
30 | - [Location](en/native-modules/location.md)
31 | - [Safari](en/native-modules/safari.md)
32 | - [Local Push](en/native-modules/push.md)
33 | - [Audio](en/native-modules/audio.md)
34 | - [Speech](en/native-modules/speech.md)
35 | - [Calendar](en/native-modules/calendar.md)
36 | - [Reminder](en/native-modules/reminder.md)
37 | - [Contact](en/native-modules/contact.md)
38 | - [Message](en/native-modules/message.md)
39 | - [Montion](en/native-modules/motion.md)
40 | - [Detector](en/native-modules/detector.md)
41 | - [Manage Scripts](en/native-modules/addin.md)
42 |
43 | - Virtual Runtimes
44 | - [Intro](en/vm/intro.md)
45 | - [Node -> JSBox](en/vm/node-jsbox.md)
46 | - [Node Context](en/vm/context.md)
47 | - [Objective-C](en/vm/objc.md)
48 | - [JSBox -> Node](en/vm/jsbox-node.md)
49 |
50 | - Others
51 | - [Changelog](en/others/changelog.md)
--------------------------------------------------------------------------------
/docs/en/fs/intro.md:
--------------------------------------------------------------------------------
1 | # File system
2 |
3 | We provided many [Native Modules](en/native-modules/intro.md) for the Node runtime, before introducing the details, we should talk about data transfer between native and Node environment first.
4 |
5 | This chapter contains some concepts like file path, and file protocol.
--------------------------------------------------------------------------------
/docs/en/fs/paths.md:
--------------------------------------------------------------------------------
1 | # The current path
2 |
3 | After a Node module is launched, the current path points to the current running folder:
4 |
5 | ```js
6 | // The running module's root
7 | console.log(process.cwd());
8 |
9 | const fs = require("fs");
10 | fs.writeFileSync("test.txt", "Hello, World!");
11 | ```
12 |
13 | The above code creates a text file under its root folder, the content is "Hello, World!".
14 |
15 | # HOME
16 |
17 | You can get JSBox's root folder like this:
18 |
19 | ```js
20 | const fs = require("fs");
21 | const path = require("path");
22 | const home = process.env["HOME"];
23 |
24 | fs.writeFileSync(path.join(home, "tmp/test.txt"), "Hello, World!");
25 | ```
26 |
27 | The above example creates a text file under the `tmp` folder, the content is "Hello, World!". When you trying to change files under HOME, please keep your mind clear, you may delete some required files otherwise.
28 |
29 | # Other paths
30 |
31 | JSBox has some other useful paths, if you want to access them with Node, here is how:
32 |
33 | ```js
34 | const path = $jsbox.path;
35 |
36 | // Equals to process.env["HOME"]
37 | const home = path.home;
38 | // JSBox shared folder
39 | const shared = path.shared;
40 | // Folder that stores scripts
41 | const scripts = path.scripts;
42 | // iCloud Drive folder
43 | const icloud = path.icloud;
44 | // The running module's root
45 | const current = path.current;
46 | ```
47 |
48 | Note, the above paths may include some very important files, please double-check before taking any action.
49 |
50 | Besides, for some folders under HOME, you may only have read access, and cannot make changes.
--------------------------------------------------------------------------------
/docs/en/fs/protocol.md:
--------------------------------------------------------------------------------
1 | # File protocol
2 |
3 | Files are frequently used as a medium when transferring data, such as Photos, iCloud Drive files, etc.
4 |
5 | In order to make those operations smoother, we designed a file protocol, it is used to send a file from Node to native.
6 |
7 | In the subsequent introduction of the Native module, we will use `File` to refer to this data type.
8 |
9 | There are 3 types of `File`, let's explain them with the `quicklook` module.
10 |
11 | # File path
12 |
13 | If you want to use an existing file on the disk, you can simply use its path:
14 |
15 | ```js
16 | const ql = require("quicklook");
17 | ql.file("test.txt");
18 | ```
19 |
20 | This opens the `test.txt` file under the project folder.
21 |
22 | # Buffer object
23 |
24 | A file could be a Node.js [Buffer](https://nodejs.org/api/buffer.html) as well:
25 |
26 | ```js
27 | const ql = require("quicklook");
28 | const buffer = Buffer.from("I'm a string!", "utf-8");
29 | ql.file(buffer);
30 | ```
31 |
32 | # Named Buffer
33 |
34 | Sometimes, you may want to specify a name for the file, for instance:
35 |
36 | ```js
37 | const fs = require("fs");
38 | const ql = require("quicklook");
39 | const buffer = fs.readFileSync("image.png");
40 | ql.file({
41 | name: "image.png",
42 | data: buffer
43 | });
44 | ```
45 |
46 | In a Node module, we can pass files to native using the above ways, and it may return a `Buffer` or `path` as the result, we can handle them in Node code.
--------------------------------------------------------------------------------
/docs/en/native-modules/addin.md:
--------------------------------------------------------------------------------
1 | # module: "addin"
2 |
3 | `addin` module provides APIs for local script management.
4 |
5 | # addin.list()
6 |
7 | Get all local scripts:
8 |
9 | ```js
10 | const addin = require("addin");
11 | const list = addin.list();
12 | console.log(list[0]);
13 | // name, url, version, icon, summary, author, website...
14 | ```
15 |
16 | # addin.categories()
17 |
18 | Get all script categories:
19 |
20 | ```js
21 | const addin = require("addin");
22 | const categories = addin.categories();
23 | console.log(categories);
24 | // [string]
25 | ```
26 |
27 | # addin.current()
28 |
29 | Get the current running script:
30 |
31 | ```js
32 | const addin = require("addin");
33 | const current = addin.current();
34 | // name, url, version, icon, summary, author, website...
35 | ```
36 |
37 | # addin.save(object)
38 |
39 | Save a script:
40 |
41 | ```js
42 | const addin = require("addin");
43 | addin.save({
44 | name: "Node Module",
45 | file: "downloaded/package.zip",
46 | // url, version, icon, summary, author, website
47 | });
48 | ```
49 |
50 | The `name` and `file` are required, and `file` is a zip file in `File` format.
51 |
52 | # addin.delete(string)
53 |
54 | Delete a script using its name:
55 |
56 | ```js
57 | const addin = require("addin");
58 | addin.delete("Node Module");
59 | ```
60 |
61 | # addin.run(object)
62 |
63 | Run another script:
64 |
65 | ```js
66 | const addin = require("addin");
67 | addin.run("Node Module");
68 | ```
69 |
70 | You can also specify input parameters:
71 |
72 | ```js
73 | const addin = require("addin");
74 | addin.run({
75 | name: "Node Module",
76 | query: {
77 | k1: "v1",
78 | k2: "v2"
79 | }
80 | });
81 | ```
82 |
83 | The script that will be executed can retrieve input parameters with `$context.query`.
84 |
85 | # addin.restart()
86 |
87 | Restart the current running script:
88 |
89 | ```js
90 | const addin = require("addin");
91 | addin.restart();
92 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/app.md:
--------------------------------------------------------------------------------
1 | # module: "app"
2 |
3 | `app` module provides APIs related to the app.
4 |
5 | # app.openURL(string)
6 |
7 | Opens a URL using the system built-in mechanism. For websites, it uses Safari. For URL schemes, it opens it directly:
8 |
9 | ```js
10 | const app = require("app");
11 |
12 | // Open a website
13 | app.openURL("https://apple.com");
14 |
15 | // Open a URL scheme
16 | app.openURL("twitter://user?id=734056753571241989");
17 | ```
18 |
19 | The return value indicates whether the action is succeeded.
--------------------------------------------------------------------------------
/docs/en/native-modules/audio.md:
--------------------------------------------------------------------------------
1 | # module: "audio"
2 |
3 | `audio` module provides audio APIs.
4 |
5 | # audio.play(object)
6 |
7 | Play audio with ID or path:
8 |
9 | ```js
10 | const audio = require("audio");
11 | audio.play(1000);
12 | ```
13 |
14 | This uses sound id for playing system built-in sounds. Refer to: https://github.com/TUNER88/iOSSystemSoundsLibrary.
15 |
16 | The parameter can also be a string, which is a remote URL or a local path:
17 |
18 | ```js
19 | const audio = require("audio");
20 | audio.play("https://");
21 | // audio.play("assets/test.wav");
22 | ```
23 |
24 | If you want to control it more precisely, use methods as below:
25 |
26 | ```js
27 | // Pause the audio
28 | audio.pause();
29 | ```
30 |
31 | ```js
32 | // Resume the audio
33 | audio.resume();
34 | ```
35 |
36 | ```js
37 | // Stop the audio
38 | audio.stop();
39 | ```
40 |
41 | ```js
42 | // Seek to location, second based
43 | audio.seek(60);
44 | ```
45 |
46 | ```js
47 | // Get the current status
48 | const status = audio.status();
49 | // 0: paused, 1: waiting, 2: playing
50 | ```
51 |
52 | ```js
53 | // Get the audio length
54 | const duration = audio.duration();
55 | ```
56 |
57 | ```js
58 | // Get the current offset
59 | const offset = audio.offset();
60 | ```
61 |
62 | # Events
63 |
64 | You can observe some events, such as:
65 |
66 | ```js
67 | const audio = require("audio");
68 | audio.play({
69 | events: {
70 | itemEnded: () => {},
71 | timeJumped: () => {},
72 | didPlayToEndTime: () => {},
73 | failedToPlayToEndTime: () => {},
74 | playbackStalled: () => {},
75 | newAccessLogEntry: () => {},
76 | newErrorLogEntry: () => {},
77 | }
78 | });
79 | ```
80 |
81 | Refer to: https://developer.apple.com/documentation/avfoundation/avplayeritem?language=objc
--------------------------------------------------------------------------------
/docs/en/native-modules/calendar.md:
--------------------------------------------------------------------------------
1 | # module: "calendar"
2 |
3 | `calendar` module provides calendar APIs.
4 |
5 | # calendar.fetch(object) -> Promise
6 |
7 | Fetch calendar items in the Calendar.app:
8 |
9 | ```js
10 | const calendar = require("calendar");
11 | calendar.fetch({
12 | startDate: new Date(),
13 | hours: 3 * 24,
14 | }).then(result => {
15 | const events = result.events;
16 | });
17 | ```
18 |
19 | It fetches items from now to 3 days later. Other than specifying with `hour`, `endDate` is also supported.
20 |
21 | The returned data contains an event list, it has the following properties:
22 |
23 | Prop | Type | Read/Write | Description
24 | ---|---|---|---
25 | title | string | rw | title
26 | identifier | string | r | id
27 | location | string | rw | location
28 | notes | string | rw | notes
29 | url | string | rw | url
30 | modifiedDate | date | r | last modified date
31 | creationDate | date | r | creation date
32 | allDay | boolean | r | is all day event
33 | startDate | date | r | start date
34 | endDate | date | r | end date
35 | status | number | r | [Refer](https://developer.apple.com/documentation/eventkit/ekeventstatus)
36 |
37 | # calendar.create(object) -> Promise
38 |
39 | Create a calendar item:
40 |
41 | ```js
42 | const calendar = require("calendar");
43 | calendar.create({
44 | title: "Hey!",
45 | startDate: new Date(),
46 | hours: 3,
47 | notes: "Hello, World!"
48 | }).then(result => {
49 | console.log(result);
50 | });
51 | ```
52 |
53 | # calendar.save(object) -> Promise
54 |
55 | Save a calendar item after some properties are changed:
56 |
57 | ```js
58 | const calendar = require("calendar");
59 | calendar.fetch({
60 | startDate: new Date(),
61 | hours: 3 * 24
62 | }).then(resp => {
63 | const event = resp.events[0];
64 | event.title = "Modified";
65 | calendar.save(event);
66 | });
67 | ```
68 |
69 | You can use `alarmDate` and `alarmDates` to set up alarms.
70 |
71 | # calendar.delete(object) -> Promise
72 |
73 | Delete a certain calendar item:
74 |
75 | ```js
76 | calendar.delete(event).then(result => {
77 | console.log(result);
78 | });
79 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/clipboard.md:
--------------------------------------------------------------------------------
1 | # module: "clipboard"
2 |
3 | `clipboard` module provides clipboard APIs.
4 |
5 | # clipboard.text()
6 |
7 | Get text in clipboard:
8 |
9 | ```js
10 | const clipboard = require("clipboard");
11 | const text = clipboard.text();
12 | ```
13 |
14 | # clipboard.setText(string)
15 |
16 | Set text to clipboard:
17 |
18 | ```js
19 | const clipboard = require("clipboard");
20 | clipboard.setText("Hey");
21 | ```
22 |
23 | # clipboard.setTextLocalOnly(string)
24 |
25 | Set text to local clipboard, it doesn't trigger the "Universal Clipboard" syncing:
26 |
27 | ```js
28 | const clipboard = require("clipboard");
29 | clipboard.setTextLocalOnly("Hey");
30 | ```
31 |
32 | # clipboard.image() -> Buffer
33 |
34 | Get image in clipboard:
35 |
36 | ```js
37 | const clipboard = require("clipboard");
38 | const buffer = clipboard.image();
39 | ```
40 |
41 | # clipboard.setImage(File)
42 |
43 | Set image to clipboard:
44 |
45 | ```js
46 | const clipboard = require("clipboard");
47 | clipboard.setImage(buffer);
48 | ```
49 |
50 | # clipboard.clear()
51 |
52 | Clear all contents in clipboard:
53 |
54 | ```js
55 | const clipboard = require("clipboard");
56 | clipboard.clear();
57 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/contact.md:
--------------------------------------------------------------------------------
1 | # module: "contact"
2 |
3 | `contact` module provides iOS contacts APIs.
4 |
5 | # contact.pick(object) -> Promise
6 |
7 | Select one or more contacts using the built-in picker:
8 |
9 | ```js
10 | const contact = require("contact");
11 | contact.pick({
12 | multi: false
13 | }).then(result => {
14 |
15 | });
16 | ```
17 |
18 | It allows multiple-selection when `multi` is `true`.
19 |
20 | # contact.fetch(object) -> Promise
21 |
22 | Search contacts using a keyword:
23 |
24 | ```js
25 | const contact = require("contact");
26 | contact.fetch({
27 | key: "Ying"
28 | }).then(results => {
29 |
30 | });
31 | ```
32 |
33 | It returns an array which supports many properties, refer to: https://developer.apple.com/documentation/contacts/cncontact for details.
34 |
35 | You can also retrieve all contacts under a certain group:
36 |
37 | ```js
38 | const contact = require("contact");
39 | contact.fetch({
40 | group
41 | }).then(results => {
42 |
43 | });
44 | ```
45 |
46 | # contact.create(object) -> Promise
47 |
48 | Create a contact:
49 |
50 | ```js
51 | const contact = require("contact");
52 | contact.create({
53 | givenName: "Ying",
54 | familyName: "Zhong",
55 | phoneNumbers: {
56 | "Home": "18000000000",
57 | "Office": "88888888"
58 | },
59 | emails: {
60 | "Home": "log.e@qq.com"
61 | }
62 | }).then(resp => {
63 |
64 | });
65 | ```
66 |
67 | # contact.save(object) -> Promise
68 |
69 | Save an updated contact:
70 |
71 | ```js
72 | const contact = require("contact");
73 | contact.save(object).then(resp => {
74 |
75 | });
76 | ```
77 |
78 | # contact.delete(object) -> Promise
79 |
80 | Delete some contacts:
81 |
82 | ```js
83 | const contact = require("contact");
84 | contact.delete(contacts).then(resp => {
85 |
86 | });
87 | ```
88 |
89 | # contact.fetchGroups() -> Promise
90 |
91 | Get all contact groups:
92 |
93 | ```js
94 | const contact = require("contact");
95 | contact.fetchGroups().then(groups => {
96 | console.log(`name: ${groups[0].name}`);
97 | });
98 | ```
99 |
100 | # contact.addGroup(string) -> Promise
101 |
102 | Create a new group:
103 |
104 | ```js
105 | const contact = require("contact");
106 | contact.addGroup("Group Name").then(group => {
107 |
108 | });
109 | ```
110 |
111 | # contact.deleteGroup(object) -> Promise
112 |
113 | Delete a group:
114 |
115 | ```js
116 | const contact = require("contact");
117 | contact.fetchGroups().then(groups => {
118 | contact.deleteGroup(groups[0]);
119 | });
120 | ```
121 |
122 | # contact.updateGroup(object) -> Promise
123 |
124 | Save an updated group:
125 |
126 | ```js
127 | const contact = require("contact");
128 | contact.fetchGroups().then(groups => {
129 | const group = groups[0];
130 | group.name = "New Name";
131 | contact.updateGroup(group);
132 | });
133 | ```
134 |
135 | # contact.addToGroup(object) -> Promise
136 |
137 | Add a contact into a group:
138 |
139 | ```js
140 | const contact = require("contact");
141 | contact.addToGroup({
142 | contact: contactObject,
143 | group: groupObject
144 | }).then(result => {
145 |
146 | });
147 | ```
148 |
149 | # contact.removeFromGroup(object) -> Promise
150 |
151 | Remove a contact from a group:
152 |
153 | ```js
154 | const contact = require("contact");
155 | contact.removeFromGroup({
156 | contact: contactObject,
157 | group: groupObject
158 | }).then(result => {
159 |
160 | });
161 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/detector.md:
--------------------------------------------------------------------------------
1 | # module: "detector"
2 |
3 | `detector` provides some data detection methods.
4 |
5 | # detector.dates(string)
6 |
7 | Retrieve all dates from a string:
8 |
9 | ```js
10 | const detector = require("detector");
11 | const dates = detector.dates("2017/10/10");
12 | ```
13 |
14 | # detector.date(string)
15 |
16 | Retrieve the first date from a string.
17 |
18 | # detector.addresses(string)
19 |
20 | Retrieve all addresses from a string:
21 |
22 | ```js
23 | const detector = require("detector");
24 | const addresses = detector.addresses("");
25 | ```
26 |
27 | # detector.address(string)
28 |
29 | Retrieve the first address from a string.
30 |
31 | # detector.links(string)
32 |
33 | Retrieve all links from a string:
34 |
35 | ```js
36 | const detector = require("detector");
37 | const links = detector.links("http://apple.com hello http://xteko.com");
38 | ```
39 |
40 | # detector.link(string)
41 |
42 | Retrieve the first link from a string.
43 |
44 | # detector.phoneNumbers(string)
45 |
46 | Retrieve all phone numbers from a string:
47 |
48 | ```js
49 | const detector = require("detector");
50 | const phoneNumbers = detector.phoneNumbers("18666666666 hello 18777777777");
51 | ```
52 |
53 | # detector.phoneNumber(string)
54 |
55 | Retrieve the first phone number from a string.
--------------------------------------------------------------------------------
/docs/en/native-modules/device.md:
--------------------------------------------------------------------------------
1 | # module: "device"
2 |
3 | `device` provides some device APIs.
4 |
5 | # device.info()
6 |
7 | Returns the device information:
8 |
9 | ```js
10 | const device = require("device");
11 | const info = device.info();
12 | ```
13 |
14 | Sample result:
15 |
16 | ```json
17 | {
18 | "model": "string",
19 | "language": "string",
20 | "version": "string",
21 | "name": "cyan's iPhone",
22 | "screen": {
23 | "width": 240,
24 | "height": 320,
25 | "scale": 2.0,
26 | "orientation": 1,
27 | }
28 | }
29 | ```
30 |
31 | # device.isDarkMode()
32 |
33 | Detect whether the device is using dark mode:
34 |
35 | ```js
36 | const device = require("device");
37 | if (device.isDarkMode()) {
38 |
39 | }
40 | ```
41 |
42 | # device.isXXX()
43 |
44 | Detect the device type quickly:
45 |
46 | ```js
47 | const device = require("device");
48 | const isIphoneX = device.isIphoneX();
49 | const isIphonePlus = device.isIphonePlus();
50 | const isIpad = device.isIpad();
51 | const isIpadPro = device.isIpadPro();
52 | ```
53 |
54 | # device.space()
55 |
56 | Detect the device memory/disk space:
57 |
58 | ```js
59 | const device = require("device");
60 | const space = device.space();
61 | ```
62 |
63 | Sample result:
64 |
65 | ```json
66 | {
67 | "disk": {
68 | "free": {
69 | "bytes": 87409733632,
70 | "string": "87.41 GB"
71 | },
72 | "total": {
73 | "bytes": 127989493760,
74 | "string": "127.99 GB"
75 | }
76 | },
77 | "memory": {
78 | "free": {
79 | "bytes": 217907200,
80 | "string": "207.8 MB"
81 | },
82 | "total": {
83 | "bytes": 3221225472,
84 | "string": "3 GB"
85 | }
86 | }
87 | }
88 | ```
89 |
90 | # device.ssid()
91 |
92 | Get the current Wi-Fi SSID:
93 |
94 | ```js
95 | const device = require("device");
96 | const ssid = device.ssid();
97 | ```
98 |
99 | Sample result:
100 |
101 | ```json
102 | {
103 | "SSIDDATA": {},
104 | "BSSID": "aa:bb:cc:dd:ee:ff",
105 | "SSID": "SSID"
106 | }
107 | ```
108 |
109 | Note: In iOS 13 and above, this API needs location access, you can use `$location` APIs to request the access.
110 |
111 | # device.networkType()
112 |
113 | Get the current network type:
114 |
115 | ```js
116 | const device = require("device");
117 | const networkType = device.networkType();
118 | ```
119 |
120 | Value | Type
121 | ---|---
122 | 0 | None
123 | 1 | Wi-Fi
124 | 2 | Cellular
125 |
126 | # device.wlanAddress()
127 |
128 | Get the current wlan address:
129 |
130 | ```js
131 | const device = require("device");
132 | const address = device.wlanAddress();
133 | ```
134 |
135 | # device.hasTouchID()
136 |
137 | Check if the device supports Touch ID:
138 |
139 | ```js
140 | const device = require("device");
141 | const hasTouchID = device.hasTouchID();
142 | ```
143 |
144 | # device.hasFaceID()
145 |
146 | Check if the device supports Face ID:
147 |
148 | ```js
149 | const device = require("device");
150 | const hasFaceID = device.hasFaceID();
151 | ```
152 |
153 | # device.taptic(number)
154 |
155 | Trigger a taptic feedback if supported:
156 |
157 | ```js
158 | const device = require("device");
159 | device.taptic(0);
160 | ```
161 |
162 | Param | Type | Description
163 | ---|---|---
164 | level | number | 0 ~ 2
165 |
166 | # device.isJailbroken()
167 |
168 | Check whether device is jailbroken:
169 |
170 | ```js
171 | const device = require("device");
172 | const isJailbroken = device.isJailbroken();
173 | ```
174 |
175 | # device.isVoiceOverOn()
176 |
177 | Check whether VoiceOver is running:
178 |
179 | ```js
180 | const device = require("device");
181 | const isVoiceOverOn = device.isVoiceOverOn();
182 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/drive.md:
--------------------------------------------------------------------------------
1 | # module: "drive"
2 |
3 | `drive` module provides support for the iCloud Drive.
4 |
5 | # drive.save(File) -> Promise
6 |
7 | Save a File to the iCloud Drive:
8 |
9 | ```js
10 | const drive = require("drive");
11 | drive.save(buffer).then(path => {
12 | console.log(path);
13 | })
14 | ```
15 |
16 | The return value is the file path.
17 |
18 | # drive.open() -> Promise
19 |
20 | Open an iCloud Drive file using the built-in file picker:
21 |
22 | ```js
23 | const drive = require("drive");
24 | drive.open({
25 | type: ["public.data", "public.content"]
26 | }).then(buffer => {
27 | console.log(buffer);
28 | });
29 | ```
30 |
31 | You can specify MIME with `type`, by default, it loads all files.
--------------------------------------------------------------------------------
/docs/en/native-modules/imagekit.md:
--------------------------------------------------------------------------------
1 | # Image Processing
2 |
3 | JSBox 2.1.0 brings `imagekit` module for image processing, you can achieve many effects easily:
4 |
5 | - Resize
6 | - Rotate
7 | - Grayscale
8 | - Masking
9 | ...
10 |
11 | In order to make it easier to understand, we created a demo project that uses all APIs: https://github.com/cyanzhong/jsbox-imagekit-node
12 |
13 | # imagekit.info(File)
14 |
15 | Get image information:
16 |
17 | ```js
18 | const imagekit = require("imagekit");
19 | const info = imagekit.info(source);
20 | // width, height, orientation, scale, props
21 | ```
22 |
23 | # imagekit.grayscale(File)
24 |
25 | Get grayscaled image:
26 |
27 | ```js
28 | const imagekit = require("imagekit");
29 | const output = imagekit.grayscale(source);
30 | ```
31 |
32 | # imagekit.invert(File)
33 |
34 | Invert colors:
35 |
36 | ```js
37 | const imagekit = require("imagekit");
38 | const output = imagekit.invert(source);
39 | ```
40 |
41 | # imagekit.sepia(File)
42 |
43 | Apply sepia filter:
44 |
45 | ```js
46 | const imagekit = require("imagekit");
47 | const output = imagekit.sepia(source);
48 | ```
49 |
50 | # imagekit.adjustEnhance(File)
51 |
52 | Enhance image automatically:
53 |
54 | ```js
55 | const imagekit = require("imagekit");
56 | const output = imagekit.adjustEnhance(source);
57 | ```
58 |
59 | # imagekit.adjustRedEye(File)
60 |
61 | Red-eye adjustment:
62 |
63 | ```js
64 | const imagekit = require("imagekit");
65 | const output = imagekit.adjustRedEye(source);
66 | ```
67 |
68 | # imagekit.adjustBrightness(File, value)
69 |
70 | Adjust brightness:
71 |
72 | ```js
73 | const imagekit = require("imagekit");
74 | const output = imagekit.adjustBrightness(source, 100);
75 | // value range: (-255, 255)
76 | ```
77 |
78 | # imagekit.adjustContrast(File, value)
79 |
80 | Adjust contrast:
81 |
82 | ```js
83 | const imagekit = require("imagekit");
84 | const output = imagekit.adjustContrast(source, 100);
85 | // value range: (-255, 255)
86 | ```
87 |
88 | # imagekit.adjustGamma(File, value)
89 |
90 | Adjust gamma value:
91 |
92 | ```js
93 | const imagekit = require("imagekit");
94 | const output = imagekit.adjustGamma(source, 4);
95 | // value range: (0.01, 8)
96 | ```
97 |
98 | # imagekit.adjustOpacity(File, value)
99 |
100 | Adjust opacity:
101 |
102 | ```js
103 | const imagekit = require("imagekit");
104 | const output = imagekit.adjustOpacity(source, 0.5);
105 | // value range: (0, 1)
106 | ```
107 |
108 | # imagekit.blur(File, bias)
109 |
110 | Apply gaussian blur:
111 |
112 | ```js
113 | const imagekit = require("imagekit");
114 | const output = imagekit.blur(source, 0);
115 | ```
116 |
117 | # imagekit.emboss(File, bias)
118 |
119 | Emboss effect:
120 |
121 | ```js
122 | const imagekit = require("imagekit");
123 | const output = imagekit.emboss(source, 0);
124 | ```
125 |
126 | # imagekit.sharpen(File, bias)
127 |
128 | Sharpen:
129 |
130 | ```js
131 | const imagekit = require("imagekit");
132 | const output = imagekit.sharpen(source, 0);
133 | ```
134 |
135 | # imagekit.unsharpen(File, bias)
136 |
137 | Unsharpen:
138 |
139 | ```js
140 | const imagekit = require("imagekit");
141 | const output = imagekit.unsharpen(source, 0);
142 | ```
143 |
144 | # imagekit.detectEdge(source, bias)
145 |
146 | Edge detection:
147 |
148 | ```js
149 | const imagekit = require("imagekit");
150 | const output = imagekit.detectEdge(source, 0);
151 | ```
152 |
153 | # imagekit.mask(File, mask)
154 |
155 | Crop an image with `mask`:
156 |
157 | ```js
158 | const imagekit = require("imagekit");
159 | const output = imagekit.mask(source, mask);
160 | ```
161 |
162 | # imagekit.reflect(File, height, fromAlpha, toAlpha)
163 |
164 | Create an up-down reflected image, from `height` position, change alpha value from `fromAlpha` to `toAlpha`:
165 |
166 | ```js
167 | const imagekit = require("imagekit");
168 | const output = imagekit.reflect(source, 100, 0, 1);
169 | ```
170 |
171 | # imagekit.cropTo(File, size, mode)
172 |
173 | Crop an image:
174 |
175 | ```js
176 | const imagekit = require("imagekit");
177 | const output = imagekit.cropTo(source, {width: 100, height: 100}, 0);
178 | // mode:
179 | // - 0: top-left
180 | // - 1: top-center
181 | // - 2: top-right
182 | // - 3: bottom-left
183 | // - 4: bottom-center
184 | // - 5: bottom-right
185 | // - 6: left-center
186 | // - 7: right-center
187 | // - 8: center
188 | ```
189 |
190 | # imagekit.scaleBy(File, value)
191 |
192 | Resize an image with scale:
193 |
194 | ```js
195 | const imagekit = require("imagekit");
196 | const output = imagekit.scaleBy(source, 0.5);
197 | ```
198 |
199 | # imagekit.scaleTo(File, size, mode)
200 |
201 | Resize an image to a specific size:
202 |
203 | ```js
204 | const imagekit = require("imagekit");
205 | const output = imagekit.scaleTo(source, {width: 100, height: 100}, 0);
206 | // mode:
207 | // - 0: scaleFill
208 | // - 1: scaleAspectFit
209 | // - 2: scaleAspectFill
210 | ```
211 |
212 | # imagekit.scaleFill(File, size)
213 |
214 | Resize an image using `scaleFill` mode:
215 |
216 | ```js
217 | const imagekit = require("imagekit");
218 | const output = imagekit.scaleFill(source, {width: 100, height: 100});
219 | ```
220 |
221 | # imagekit.scaleAspectFit(File, size)
222 |
223 | Resize an image using `scaleAspectFit` mode:
224 |
225 | ```js
226 | const imagekit = require("imagekit");
227 | const output = imagekit.scaleAspectFit(source, {width: 100, height: 100});
228 | ```
229 |
230 | # imagekit.scaleAspectFill(File, size)
231 |
232 | Resize an image using `scaleAspectFill` mode:
233 |
234 | ```js
235 | const imagekit = require("imagekit");
236 | const output = imagekit.scaleAspectFill(source, {width: 100, height: 100});
237 | ```
238 |
239 | # imagekit.rotate(File, radians)
240 |
241 | Rotate an image (it may change the size):
242 |
243 | ```js
244 | const imagekit = require("imagekit");
245 | const output = imagekit.rotate(source, Math.PI * 0.25);
246 | ```
247 |
248 | # imagekit.rotatePixels(File, radians)
249 |
250 | Rotate an image (keeps the image size, some contents might be clipped):
251 |
252 | ```js
253 | const imagekit = require("imagekit");
254 | const output = imagekit.rotatePixels(source, Math.PI * 0.25);
255 | ```
256 |
257 | # imagekit.flip(File, mode)
258 |
259 | Flip an image:
260 |
261 | ```js
262 | const imagekit = require("imagekit");
263 | const output = imagekit.flip(source, 0);
264 | // mode:
265 | // - 0: vertically
266 | // - 1: horizontally
267 | ```
268 |
269 | # imagekit.concatenate(Files, space, mode)
270 |
271 | Concatenate images with space:
272 |
273 | ```js
274 | const imagekit = require("imagekit");
275 | const output = imagekit.concatenate(Files, 10, 0);
276 | // mode:
277 | // - 0: vertically
278 | // - 1: horizontally
279 | ```
280 |
281 | # imagekit.combine(File, mask, mode)
282 |
283 | Add `mask` directly on `image`:
284 |
285 | ```js
286 | const imagekit = require("imagekit");
287 | const output = imagekit.combine(File1, File2, mode);
288 | // mode:
289 | // - 0: top-left
290 | // - 1: top-center
291 | // - 2: top-right
292 | // - 3: bottom-left
293 | // - 4: bottom-center
294 | // - 5: bottom-right
295 | // - 6: left-center
296 | // - 7: right-center
297 | // - 8: center (default)
298 | // - {x: number, y: number}: absolute position
299 | ```
300 |
301 | # imagekit.rounded(File, radius)
302 |
303 | Get an image with rounded corners:
304 |
305 | ```js
306 | const imagekit = require("imagekit");
307 | const output = imagekit.rounded(source, 10);
308 | ```
309 |
310 | # imagekit.circular(image)
311 |
312 | Get a circular image, it will be centered and clipped if the source image isn't a square:
313 |
314 | ```js
315 | const imagekit = require("imagekit");
316 | const output = imagekit.circular(source);
317 | ```
318 |
319 | # imagekit.extractGIF(data) -> Promise
320 |
321 | Extract GIF data to frames:
322 |
323 | ```js
324 | const imagekit = require("imagekit");
325 | const {images, durations} = await imagekit.extractGIF(data);
326 | // image: all image frames
327 | // durations: duration for each frame
328 | ```
329 |
330 | # imagekit.makeGIF(source, options) -> Promise
331 |
332 | Make GIF with image array or video data:
333 |
334 | ```js
335 | const imagekit = require("imagekit");
336 | const images = [File1, File2];
337 | const options = {
338 | durations: [0.5, 0.5],
339 | // size: 16, 12, 8, 4, 2
340 | }
341 | const data = await imagekit.makeGIF(Files, options);
342 | ```
343 |
344 | You can also use `duration` instead of `durations`, it makes the duration of each frame are the same.
345 |
346 | # imagekit.makeVideo(source, options) -> Promise
347 |
348 | Make video with image array or GIF data:
349 |
350 | ```js
351 | const imagekit = require("imagekit");
352 | const images = [File1, File2];
353 | const data = await imagekit.makeVideo(Files, {
354 | durations: [0.5, 0.5]
355 | });
356 | ```
357 |
358 | You can also use `duration` instead of `durations`, it makes the duration of each frame are the same, GIF data doesn't require durations.
--------------------------------------------------------------------------------
/docs/en/native-modules/input.md:
--------------------------------------------------------------------------------
1 | # User input
2 |
3 | In Node script, you can use `stdin` and `stdout` for I/O, but just like we mentioned before, you should use:
4 |
5 | - `$jsbox.stdin` instead of `process.stdin`
6 | - `$jsbox.stdout` instead of `process.stdout`
7 |
8 | Other than that difference, you can use them with your Node.js knowledge, for example:
9 |
10 | ```js
11 | const readline = require("readline");
12 |
13 | const interface = readline.createInterface({
14 | input: $jsbox.stdin,
15 | output: $jsbox.stdout,
16 | terminal: false
17 | });
18 |
19 | interface.on('line', line => {
20 | console.log(`Echo: ${line}`);
21 | });
22 | ```
23 |
24 | This is an echo program, it replicates what the user says.
25 |
26 | # module: "input"
27 |
28 | Other than stdin and stdout, using the `input` module is also a good solution.
29 |
30 | # input.text(object) -> Promise
31 |
32 | Using the JSBox text input component:
33 |
34 | ```js
35 | const input = require("input");
36 | input.text({
37 | type: 0,
38 | placeholder: "Input your name..",
39 | text: "Ying"
40 | }).then(text => {
41 | console.log(text);
42 | });
43 | ```
44 |
45 | The `type` parameter specifies the keyboard appearance, refer to https://docs.xteko.com/#/en/data/constant?id=kbtype
46 |
47 | This method returns a Promise object, you can also use it with async/await fashion.
48 |
49 | # input.speech(object) -> Promise
50 |
51 | Using the iOS built-in voice to text service:
52 |
53 | ```js
54 | const input = require("input");
55 | input.speech({
56 | locale: "en-US",
57 | autoFinish: true
58 | }).then(text => {
59 | console.log(text);
60 | });
61 | ```
62 |
63 | The `autoFinish` means whether autocomplete after voice stopped, default is `false`. `locale` specifies the language locale, default is the current device locale.
--------------------------------------------------------------------------------
/docs/en/native-modules/intro.md:
--------------------------------------------------------------------------------
1 | # Native modules
2 |
3 | You can use standard Node.js code in JSBox. At the same time, we also wrapped many native iOS modules, letting you touch iOS components with standard Node.js programs. Such as accessing the clipboard, files sharing.
4 |
5 | For those JSBox only modules, we call them native modules.
6 |
7 | Native modules are standard `node modules`, the usage has no difference compared using other npm modules:
8 |
9 | ```js
10 | const clipboard = require("clipboard");
11 |
12 | // Returns the clipboard text
13 | const text = clipboard.text();
14 |
15 | // Change the clipboard text
16 | clipboard.setText("Hey");
17 | ```
18 |
19 | # Supported modules
20 |
21 | Ideally, we would like to wrap everything you have in JSBox runtime. But it may take to long to achieve, in the current version, we only wrapped the following modules:
22 |
23 | - [Intro](en/native-modules/intro.md)
24 | - [App](en/native-modules/app.md)
25 | - [System](en/native-modules/system.md)
26 | - [Device](en/native-modules/device.md)
27 | - [Input](en/native-modules/input.md)
28 | - [UI](en/native-modules/ui.md)
29 | - [Localization](en/native-modules/l10n.md)
30 | - [Clipboard](en/native-modules/clipboard.md)
31 | - [Photo](en/native-modules/photo.md)
32 | - [iCloud Drive](en/native-modules/drive.md)
33 | - [Quick Look](en/native-modules/quicklook.md)
34 | - [Sharing](en/native-modules/share.md)
35 | - [QR Code](en/native-modules/qrcode.md)
36 | - [Location](en/native-modules/location.md)
37 | - [Safari](en/native-modules/safari.md)
38 | - [Local Push](en/native-modules/push.md)
39 | - [Audio](en/native-modules/audio.md)
40 | - [Speech](en/native-modules/speech.md)
41 | - [Calendar](en/native-modules/calendar.md)
42 | - [Reminder](en/native-modules/reminder.md)
43 | - [Contact](en/native-modules/contact.md)
44 | - [Message](en/native-modules/message.md)
45 | - [Montion](en/native-modules/motion.md)
46 | - [Detector](en/native-modules/detector.md)
47 |
48 | We believe those modules are enough for most scenarios, if you really need more, before we finish everything, you can consider calling JSBox from Node.
49 |
50 | Regarding communications between JSBox and Node, refer to: [Virtual runtimes](en/vm/intro.md).
--------------------------------------------------------------------------------
/docs/en/native-modules/l10n.md:
--------------------------------------------------------------------------------
1 | # module: "l10n"
2 |
3 | `l10n` module provides localization support for Node modules.
4 |
5 | # Providing localized strings
6 |
7 | It's simple, just create a `strings` folder under the project folder, then add your language files there:
8 |
9 | ```
10 | MyNodeModule/strings
11 | zh-Hans.strings
12 | zh-Hant.strings
13 | en.strings
14 | ```
15 |
16 | strings is a plain text file with key-value pairs:
17 |
18 | ```
19 | "KEY1" = "Value1";
20 | "KEY2" = "Value2";
21 | ```
22 |
23 | # Using localized strings
24 |
25 | It's simple to get a localized string with its key:
26 |
27 | ```js
28 | const l10n = require("l10n");
29 | const localized = l10n("KEY1");
30 | ```
31 |
32 | The fallback logic:
33 |
34 | - No suitable language pack, fallback to English (en)
35 | - No suitable string for a key, fallback to the key itself
--------------------------------------------------------------------------------
/docs/en/native-modules/location.md:
--------------------------------------------------------------------------------
1 | # module: "location"
2 |
3 | `location` module provides device location APIs.
4 |
5 | # location.available()
6 |
7 | Check whether location service is available:
8 |
9 | ```js
10 | const location = require("location");
11 | if (location.available()) {
12 |
13 | }
14 | ```
15 |
16 | # location.fetch() -> Promise
17 |
18 | Get the current location:
19 |
20 | ```js
21 | const location = require("location");
22 | location.fetch().then(result => {
23 | const latitude = result.lat;
24 | const longitude = result.lng;
25 | const altitude = result.alt;
26 | });
27 | ```
28 |
29 | It returns latitude, longitude, and altitude.
30 |
31 | # location.startUpdates(object)
32 |
33 | Start observing the location updates:
34 |
35 | ```js
36 | const location = require("location");
37 | location.startUpdates({
38 | once: false
39 | },result => {
40 | // lat, lng, alt
41 | });
42 | ```
43 |
44 | `once` indicates whether stop after the first result is returned.
45 |
46 | # location.trackHeading(object)
47 |
48 | Track heading changes:
49 |
50 | ```js
51 | const location = require("location");
52 | location.trackHeading(result => {
53 | const magneticHeading = result.magneticHeading;
54 | const trueHeading = result.trueHeading;
55 | const headingAccuracy = result.headingAccuracy;
56 | const x = result.x;
57 | const y = result.y;
58 | const z = result.z;
59 | });
60 | ```
61 |
62 | # location.stopUpdates()
63 |
64 | Stop location updates:
65 |
66 | ```js
67 | const location = require("location");
68 | location.stopUpdates();
69 | ```
70 |
71 | # location.select() -> Promise
72 |
73 | Select a location using the JSBox built-in map component:
74 |
75 | ```js
76 | const location = require("location");
77 | location.select().then(result => {
78 | const latitude = result.lat;
79 | const longitude = result.lng;
80 | });
81 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/message.md:
--------------------------------------------------------------------------------
1 | # module: "message"
2 |
3 | `message` provides support for the system mail and SMS service.
4 |
5 | # message.sms(object) -> Promise
6 |
7 | Sending SMS using the system built-in component:
8 |
9 | ```js
10 | const message = require("message");
11 | message.sms({
12 | recipients: ["18688888888", "10010"],
13 | body: "Message body",
14 | subject: "Message subject",
15 | attachments: [
16 | {
17 | name: "image.png",
18 | data: buffer
19 | }
20 | ]
21 | }).then(result => {
22 |
23 | });
24 | ```
25 |
26 | Param | Description
27 | ---|---
28 | recipients | receivers
29 | body | body
30 | subject | subject
31 | attachments | attachments (Files)
32 | result | 0: cancelled 1: succeeded 2: failed
33 |
34 | # message.mail(object) -> Promise
35 |
36 | Sending emails using the system built-in component:
37 |
38 | ```js
39 | message.mail({
40 | subject: "Message subject",
41 | to: ["18688888888", "10010"],
42 | cc: [],
43 | bcc: [],
44 | body: "Message body",
45 | attachments: [
46 | {
47 | name: "image.png",
48 | data: buffer
49 | }
50 | ]
51 | }).then(result => {
52 |
53 | });
54 | ```
55 |
56 | Param | Description
57 | ---|---
58 | subject | subject
59 | to | receiver
60 | cc | cc
61 | bcc | bcc
62 | body | body
63 | isHTML | is body an HTML
64 | attachments | attachments (Files)
65 | result | 0: cancelled 1: succeeded 2: failed
--------------------------------------------------------------------------------
/docs/en/native-modules/motion.md:
--------------------------------------------------------------------------------
1 | # module: "motion"
2 |
3 | `motion` module provides APIs for device sensors.
4 |
5 | # motion.available()
6 |
7 | Check whether the device supports motion sensors:
8 |
9 | ```js
10 | const motion = require("motion");
11 | if (motion.available()) {
12 |
13 | }
14 | ```
15 |
16 | # motion.startUpdates(object)
17 |
18 | Start tracking motion updates:
19 |
20 | ```js
21 | const motion = require("motion");
22 | motion.startUpdates({
23 | interval: 2,
24 | handler: resp => {
25 | console.log(resp);
26 | }
27 | })
28 | ```
29 |
30 | For details, refer to [CMDeviceMotion](https://developer.apple.com/documentation/coremotion/cmdevicemotion)。
31 |
32 | # motion.stopUpdates()
33 |
34 | Stop motion updates:
35 |
36 | ```js
37 | const motion = require("motion");
38 | motion.stopUpdates();
39 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/photo.md:
--------------------------------------------------------------------------------
1 | # module: "photo"
2 |
3 | `photo` module provides APIs for the iOS Photos app.
4 |
5 | # photo.take() -> Promise
6 |
7 | Take a photo using the built-in camera:
8 |
9 | ```js
10 | const photo = require("photo");
11 | photo.take().then(result => {
12 | const buffer = result.data;
13 | const metadata = result.metadata;
14 | });
15 | ```
16 |
17 | It returns a Buffer object photo, and a JSON format metadata.
18 |
19 | # photo.pick(object) -> Promise
20 |
21 | Select a photo from the iOS photo library:
22 |
23 | ```js
24 | const photo = require("photo");
25 | photo.take({
26 | multi: true
27 | }).then(result => {
28 | const buffer = result.data;
29 | const metadata = result.metadata;
30 | });
31 | ```
32 |
33 | `multi` indicates whether multiple-selection is allowed.
34 |
35 | # photo.scan() -> Promise
36 |
37 | Scan documents using the iOS built-in documents scanner:
38 |
39 | ```js
40 | const photo = require("photo");
41 | photo.scan().then(files => {
42 | console.log(files);
43 | });
44 | ```
45 |
46 | It returns multiple results as a Buffer array.
47 |
48 | # photo.save(File) -> Promise
49 |
50 | Save a File format photo to the iOS photo library:
51 |
52 | ```js
53 | const photo = require("photo");
54 | photo.save(buffer).then(success => {
55 | console.log(success);
56 | });
57 | ```
58 |
59 | # photo.fetch(object) -> Promise
60 |
61 | Fetch photos in the iOS photo library:
62 |
63 | ```js
64 | const photo = require("photo");
65 | photo.fetch({
66 | count: 10,
67 | type: 0,
68 | subType: 0
69 | }).then(files => {
70 | console.log(files);
71 | });
72 | ```
73 |
74 | The `type` and `subType` control fetching types, refer to: https://docs.xteko.com/#/en/data/constant?id=assetmedia
75 |
76 | # photo.delete(object) -> Promise
77 |
78 | Delete some photos in the iOS photo library:
79 |
80 | ```js
81 | const photo = require("photo");
82 | photo.delete({
83 | count: 10,
84 | type: 0,
85 | subType: 0
86 | }).then(success => {
87 | console.log(success);
88 | });
89 | ```
90 |
91 | The parameters are exactly the same as `photo.fetch(...)`, returns whether it's succeeded.
--------------------------------------------------------------------------------
/docs/en/native-modules/push.md:
--------------------------------------------------------------------------------
1 | # module: "push"
2 |
3 | `push` module provides support for the iOS local push notifications.
4 |
5 | # push.schedule(object) -> Promise
6 |
7 | Schedule a local push notification:
8 |
9 | ```js
10 | const push = require("push");
11 | push.schedule({
12 | title: "Title",
13 | body: "Body",
14 | delay: 5,
15 | handler: result => {
16 | const id = result.id;
17 | }
18 | });
19 | ```
20 |
21 | This notification will be delivered after 5 seconds.
22 |
23 | Param | Type | Description
24 | ---|---|---
25 | title | string | title
26 | body | string | body
27 | id | string | identifier (optional)
28 | sound | string | sound
29 | mute | bool | mute
30 | repeats | bool | repeats
31 | script | string | script name
32 | height | number | 3D Touch view height
33 | query | json | extra parameters, will be passed to $context.query
34 | attachments | array | media attachments, File format
35 | renew | bool | whether renew
36 |
37 | Above case is how to schedule a push with delay, you can also setup a date:
38 |
39 | ```js
40 | const date = new Date();
41 | date.setSeconds(date.getSeconds() + 10);
42 |
43 | const push = require("push");
44 | push.schedule({
45 | title: "Title",
46 | body: "Body",
47 | date,
48 | handler: result => {
49 | const id = result.id;
50 | }
51 | });
52 | ```
53 |
54 | Other than that, location based notifications are supported:
55 |
56 | ```js
57 | const push = require("push");
58 | push.schedule({
59 | title: "Title",
60 | body: "Body",
61 | region: {
62 | lat: 0, // latitude
63 | lng: 0, // longitude
64 | radius: 1000, // meters
65 | notifyOnEntry: true, // notify on entry
66 | notifyOnExit: true // notify on exit
67 | }
68 | });
69 | ```
70 |
71 | This requires location access, it will fail if the user rejected.
72 |
73 | Besides, a `script` parameter is supported to specify a script, it will be executed when the notification is tapped by the user. Also, the user can preview the script result by triggering 3D Touch.
74 |
75 | # push.cancel(object)
76 |
77 | Cancel a scheduled push notification:
78 |
79 | ```js
80 | const push = require("push");
81 | push.cancel({
82 | title: "Title",
83 | body: "Body",
84 | });
85 | ```
86 |
87 | JSBox will cancel all notifications that match the `title` and `body`.
88 |
89 | You can also can it the identifier:
90 |
91 | ```js
92 | const push = require("push");
93 | push.cancel({
94 | id: ""
95 | });
96 | ```
97 |
98 | # push.clear()
99 |
100 | Clears all push notifications:
101 |
102 | ```js
103 | const push = require("push");
104 | push.clear();
105 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/qrcode.md:
--------------------------------------------------------------------------------
1 | # module: "qrcode"
2 |
3 | `qrcode` module provides some APIs to handle QR Code.
4 |
5 | # qrcode.encode(string)
6 |
7 | Encode a string to QR Code image:
8 |
9 | ```js
10 | const qrcode = require("qrcode");
11 | const buffer = qrcode.encode("Hey");
12 | ```
13 |
14 | # qrcode.decode(File)
15 |
16 | Decode a File format QR Code image as string:
17 |
18 | ```js
19 | const qrcode = require("qrcode");
20 | const text = qrcode.decode(buffer);
21 | ```
22 |
23 | # qrcode.scan(object) -> Promise
24 |
25 | Scan QR Code with the JSBox built-in QR Code scanner:
26 |
27 | ```js
28 | const qrcode = require("qrcode");
29 | qrcode.scan({
30 | useFrontCamera: false,
31 | turnOnFlash: false
32 | }).then(text => {
33 | console.log(text);
34 | });
35 | ```
36 |
37 | useFrontCamera: whether to use the front camera,turnOnFlash: whether turn on the flashlight.
--------------------------------------------------------------------------------
/docs/en/native-modules/quicklook.md:
--------------------------------------------------------------------------------
1 | # module: "quicklook"
2 |
3 | `quicklook` module provides some APIs to leverage the iOS QuickLook.
4 |
5 | # quicklook.text(string) -> Promise
6 |
7 | Open a text with the quicklook component:
8 |
9 | ```js
10 | const quicklook = require("quicklook");
11 | quicklook.text("Hey");
12 | ```
13 |
14 | # quicklook.file(File) -> Promise
15 |
16 | Open a File with the quicklook component:
17 |
18 | ```js
19 | const quicklook = require("quicklook");
20 | quicklook.file({
21 | name: "demo.txt",
22 | data: buffer
23 | });
24 | ```
25 |
26 | # quicklook.files([File]) -> Promise
27 |
28 | Open a list of Files with the quicklook component:
29 |
30 | ```js
31 | const quicklook = require("quicklook");
32 | quicklook.files([
33 | {
34 | name: "demo.txt",
35 | data: buffer
36 | }
37 | ]);
38 | ```
39 |
40 | You can navigate files by swiping left and right.
41 |
42 | # quicklook.json(JSON) -> Promise
43 |
44 | Open a JSON object with the JSBox built-in JSON viewer:
45 |
46 | ```js
47 | const quicklook = require("quicklook");
48 | quicklook.json({
49 | "Key": "Value"
50 | });
51 | ```
52 |
53 | # quicklook.html(string) -> Promise
54 |
55 | Open an HTML with the quicklook component:
56 |
57 | ```js
58 | const quicklook = require("quicklook");
59 | quicklook.html("
Hey, there!");
60 | ```
61 |
62 | # quicklook.markdown(string) -> Promise
63 |
64 | Open a markdown text with the quicklook component:
65 |
66 | ```js
67 | const quicklook = require("quicklook");
68 | quicklook.markdown("**Bold** text");
69 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/reminder.md:
--------------------------------------------------------------------------------
1 | # module: "reminder"
2 |
3 | `reminder` module provides support for the Reminders
4 |
5 | # reminder.fetch(object) -> Promise
6 |
7 | Fetch reminders in the iOS Reminders.app:
8 |
9 | ```js
10 | const reminder = require("reminder");
11 | reminder.fetch({
12 | startDate: new Date(),
13 | hours: 2 * 24
14 | }).then(resp => {
15 | const events = resp.events;
16 | });
17 | ```
18 |
19 | It looks very similar to the `calendar` module, the object structure:
20 |
21 | Prop | Type | Read/Write | Description
22 | ---|---|---|---
23 | title | string | rw | title
24 | identifier | string | r | id
25 | location | string | rw | location
26 | notes | string | rw | notes
27 | url | string | rw | url
28 | modifiedDate | date | r | last modified date
29 | creationDate | date | r | creation date
30 | completed | boolean | rw | is completed
31 | completionDate | date | r | completion date
32 | alarmDate | date | rw | alarm date
33 | priority | number | rw | priority (1 ~ 9)
34 |
35 | # reminder.create(object) -> Promise
36 |
37 | Create a reminder item:
38 |
39 | ```js
40 | const reminder = require("reminder");
41 | reminder.create({
42 | title: "Hey!",
43 | alarmDate: new Date(),
44 | notes: "Hello, World!",
45 | url: "https://apple.com"
46 | }).then(resp => {
47 | console.log(result);
48 | });
49 | ```
50 |
51 | You can use `alarmDate` and `alarmDates` to set up alarms.
52 |
53 | # reminder.save(object) -> Promise
54 |
55 | Similar to `calendar.save(...)`, it saves an updated reminder item:
56 |
57 | ```js
58 | const reminder = require("reminder");
59 | reminder.save(event);
60 | ```
61 |
62 | # reminder.delete(object) -> Promise
63 |
64 | Delete a reminder item:
65 |
66 | ```js
67 | const reminder = require("reminder");
68 | reminder.delete(event).then(result => {
69 | console.log(result);
70 | });
71 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/safari.md:
--------------------------------------------------------------------------------
1 | # module: "safari"
2 |
3 | `safari` module provides support for Safari.
4 |
5 | # safari.open(object) -> Promise
6 |
7 | Open a link with Safari View Controller:
8 |
9 | ```js
10 | const safari = require("safari");
11 | safari.open("https://apple.com");
12 | ```
13 |
14 | We can also provide some parameters:
15 |
16 | ```js
17 | const safari = require("safari");
18 | safari.open({
19 | url: "https://apple.com",
20 | entersReader: true
21 | });
22 | ```
23 |
24 | `entersReader` indicates whether to enter reader mode automatically.
25 |
26 | # safari.exec(object)
27 |
28 | Execute JavaScript using Safari's WebKit core:
29 |
30 | ```js
31 | const safari = require("safari");
32 | const result = await safari.exec("const a = 100; return a;");
33 | //=> 100
34 | ```
35 |
36 | You can also use the `script` parameter, and listen to notifications:
37 |
38 | ```js
39 | const safari = require("safari");
40 | safari.exec({
41 | script:
42 | `
43 | const a = 100;
44 | const b = 100;
45 | $notify("customEvent", {a, b});
46 | `,
47 | customEvent: result => {
48 | console.log(result);
49 | }
50 | });
51 | ```
52 |
53 | In WebKit environment, messages can be sent back to Node with `$notify(...)`.
54 |
55 | # safari.addReadingItem(object)
56 |
57 | Add a link as Safari reading item:
58 |
59 | ```js
60 | const safari = require("safari");
61 | safari.addReadingItem({
62 | url: "https://apple.com",
63 | title: "Title",
64 | preview: "Preview text"
65 | });
66 | ```
67 |
68 | The return value indicates whether it's succeeded.
--------------------------------------------------------------------------------
/docs/en/native-modules/share.md:
--------------------------------------------------------------------------------
1 | # module: "share"
2 |
3 | `share` module provides support for the iOS share sheet.
4 |
5 | # share.text(string) -> Promise
6 |
7 | Share a text with the share sheet:
8 |
9 | ```js
10 | const share = require("share");
11 | share.text("Hey");
12 | ```
13 |
14 | # share.texts([string]) -> Promise
15 |
16 | Share a list of text with the share sheet:
17 |
18 | ```js
19 | const share = require("share");
20 | share.texts(["Hey", "Hey", "Hey"]);
21 | ```
22 |
23 | # share.file(File) -> Promise
24 |
25 | Share a File with the share sheet:
26 |
27 | ```js
28 | const share = require("share");
29 | share.file({
30 | name: "demo.png",
31 | data: buffer
32 | });
33 | ```
34 |
35 | # share.files([File]) -> Promise
36 |
37 | Share a list of File with the share sheet:
38 |
39 | ```js
40 | const share = require("share");
41 | share.files([
42 | {
43 | name: "demo.png",
44 | data: buffer
45 | }
46 | ]);
47 | ```
48 |
49 | # share.url(string) -> Promise
50 |
51 | Share a link with the share sheet:
52 |
53 | ```js
54 | const share = require("share");
55 | share.url("https://apple.com");
56 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/speech.md:
--------------------------------------------------------------------------------
1 | # module: "speech"
2 |
3 | `speech` module is a simple wrapper of the iOS TTS.
4 |
5 | # speech.voices()
6 |
7 | Returns all available voices:
8 |
9 | ```js
10 | const speech = require("speech");
11 | const voices = speech.voices();
12 | ```
13 |
14 | # speech.speak(object)
15 |
16 | Text to speech service:
17 |
18 | ```js
19 | const speech = require("speech");
20 | speech.speak({
21 | text: "Hello, World!",
22 | rate: 0.5, // 0 ~ 1
23 | pitch: 1.0, // 0 ~ 1,
24 | language: "zh-Hans",
25 | voiceIdentifier: ""
26 | });
27 | ```
28 |
29 | `voiceIdentifier` could be retrieved by calling `voices` method. Available `language` values:
30 |
31 | ```
32 | ar-SA
33 | cs-CZ
34 | da-DK
35 | de-DE
36 | el-GR
37 | en-AU
38 | en-GB
39 | en-IE
40 | en-US
41 | en-US
42 | en-ZA
43 | es-ES
44 | es-MX
45 | fi-FI
46 | fr-CA
47 | fr-FR
48 | he-IL
49 | hi-IN
50 | hu-HU
51 | id-ID
52 | it-IT
53 | ja-JP
54 | ko-KR
55 | nl-BE
56 | nl-NL
57 | no-NO
58 | pl-PL
59 | pt-BR
60 | pt-PT
61 | ro-RO
62 | ru-RU
63 | sk-SK
64 | sv-SE
65 | th-TH
66 | tr-TR
67 | zh-CN
68 | zh-HK
69 | zh-TW
70 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/system.md:
--------------------------------------------------------------------------------
1 | # module: "system"
2 |
3 | `system` module provides some system-related APIs.
4 |
5 | # system.brightness()
6 |
7 | Get the current brightness:
8 |
9 | ```js
10 | const system = require("system");
11 | const brightness = system.brightness();
12 | ```
13 |
14 | # system.setBrightness(number)
15 |
16 | Set the current brightness:
17 |
18 | ```js
19 | const system = require("system");
20 |
21 | // 0 ~ 1
22 | system.setBrightness(0.5);
23 | ```
24 |
25 | # system.volume()
26 |
27 | Get the current volume:
28 |
29 | ```js
30 | const system = require("system");
31 | const volume = system.volume();
32 | ```
33 |
34 | # system.setVolume(number)
35 |
36 | Set the current volume:
37 |
38 | ```js
39 | const system = require("system");
40 |
41 | // 0 ~ 1
42 | system.setVolume(0.5);
43 | ```
44 |
45 | # system.call(number)
46 |
47 | Make a phone call:
48 |
49 | ```js
50 | const system = require("system");
51 | system.call("18000000000");
52 | ```
53 |
54 | # system.sms(number)
55 |
56 | Send a text message:
57 |
58 | ```js
59 | const system = require("system");
60 | system.sms("18000000000");
61 | ```
62 |
63 | # system.mailto(string)
64 |
65 | Send an email:
66 |
67 | ```js
68 | const system = require("system");
69 | system.mailto("log.e@qq.com");
70 | ```
71 |
72 | # system.facetime(string)
73 |
74 | Initiate a FaceTime session:
75 |
76 | ```js
77 | const system = require("system");
78 | system.facetime("log.e@qq.com");
79 | ```
80 |
81 | # system.home()
82 |
83 | Returns to the iOS home screen:
84 |
85 | ```js
86 | const system = require("system");
87 | system.home();
88 | ```
--------------------------------------------------------------------------------
/docs/en/native-modules/ui.md:
--------------------------------------------------------------------------------
1 | # module: "ui"
2 |
3 | `ui` module provides some UI components.
4 |
5 | # ui.success(string, number)
6 |
7 | Similar to `toast`, but the bar color is green, indicates success:
8 |
9 | ```js
10 | const ui = require("ui");
11 | ui.success("Done");
12 | ```
13 |
14 | # ui.warning(string, number)
15 |
16 | Similar to `toast`, but the bar color is yellow, indicates warning:
17 |
18 | ```js
19 | const ui = require("ui");
20 | ui.warning("Be careful!");
21 | ```
22 |
23 | # ui.error(string, number)
24 |
25 | Similar to `toast`, but the bar color is red, indicates error:
26 |
27 | ```js
28 | const ui = require("ui");
29 | ui.error("Something went wrong!");
30 | ```
31 |
32 | # ui.alert(object)
33 |
34 | Present an alert, the simplest usage is:
35 |
36 | ```js
37 | const ui = require("ui");
38 | ui.alert("Hey");
39 | ```
40 |
41 | You can also use its global alias: `alert(...)`.
42 |
43 | When we need to use `title` and `message`:
44 |
45 | ```js
46 | const ui = require("ui");
47 | ui.alert({
48 | title: "Title",
49 | message: "Message"
50 | });
51 | ```
52 |
53 | By default, alert shows a confirm button, we can customize it with `actions`:
54 |
55 | ```js
56 | const ui = require("ui");
57 | ui.alert({
58 | title: "Title",
59 | message: "Message",
60 | actions: ["Action 1", "Action 2"]
61 | });
62 | ```
63 |
64 | # ui.action(object)
65 |
66 | Works exactly the same as `ui.alert(...)`, but shows as an action sheet.
67 |
68 | # ui.menu(object) -> Promise
69 |
70 | Present a menu for choosing an option:
71 |
72 | ```js
73 | const ui = require("ui");
74 | ui.menu(["A", "B", "C"]).then(option => {
75 | const index = option.index;
76 | const title = option.title;
77 | });
78 | ```
79 |
80 | It can be more descriptive with a `title`:
81 |
82 | ```js
83 | const ui = require("ui");
84 | ui.menu({
85 | title: "Options",
86 | items: ["A", "B", "C"]
87 | }).then(option => {});
88 | ```
89 |
90 | # ui.toast(string, number)
91 |
92 | Present a toast, it will be removed automatically after a delay:
93 |
94 | ```js
95 | const ui = require("ui");
96 | ui.toast("Hi", 3.0);
97 | ```
98 |
99 | By default, it lives 2 seconds.
100 |
101 | # ui.clearToast()
102 |
103 | Clears all toast on the screen:
104 |
105 | ```js
106 | const ui = require("ui");
107 | ui.clearToast();
108 | ```
109 |
110 | # ui.showHUD(string)
111 |
112 | Show a HUD message:
113 |
114 | ```js
115 | const ui = require("ui");
116 | ui.showHUD("Loading...");
117 | ```
118 |
119 | # ui.hideHUD()
120 |
121 | Hide HUD message on the screen:
122 |
123 | ```js
124 | const ui = require("ui");
125 | ui.hideHUD();
126 | ```
127 |
128 | # ui.showProgress(number, string)
129 |
130 | Display a loading progress bar (0 ~ 1):
131 |
132 | ```js
133 | const ui = require("ui");
134 | ui.showProgress(0.5, "Loading");
135 | ```
136 |
137 | # ui.hideProgress()
138 |
139 | Hide the loading progress bar on the screen:
140 |
141 | ```js
142 | const ui = require("ui");
143 | ui.hideProgress();
144 | ```
--------------------------------------------------------------------------------
/docs/en/node-modules/builtin.md:
--------------------------------------------------------------------------------
1 | # Built-in Node modules
2 |
3 | You can use 3rd-party node modules in JSBox, of course. In order to make your life easier, we bundled a few popular node modules as well:
4 |
5 | - [async v3.1.0](https://www.npmjs.com/package/async)
6 | - [lodash v4.17.15](https://www.npmjs.com/package/lodash)
7 | - [axios v0.19.0](https://www.npmjs.com/package/axios)
8 | - [cheerio v0.22.0](https://www.npmjs.com/package/cheerio)
9 | - [express v4.17.1](https://www.npmjs.com/package/express)
10 | - [lowdb v1.0.0](https://www.npmjs.com/package/lowdb)
11 |
12 | You can look for their official documentation if you have no idea how to use them.
13 |
14 | We will try to make them up to date as much as we can, you can use your preferred version as well.
--------------------------------------------------------------------------------
/docs/en/node-modules/deps.md:
--------------------------------------------------------------------------------
1 | # Dependency management
2 |
3 | JSBox has built-in support for the [npm](https://www.npmjs.com/) repository, which means you can resolve your node dependencies without leaving the app.
4 |
5 | Of course, you can also set up node_modules on your desktop environment, then sync the code to your device.
6 |
7 | # Install Node.js module
8 |
9 | - Open your Node.js project
10 | - Tap the "Node.js" button
11 | - Install Node.js module
12 | - Type in the module name, multiple values are separated by `,`, optionally, version can be specified with `@version`
13 |
14 | # package.json
15 |
16 | You can also manage dependencies using the `package.json` file:
17 |
18 | ```json
19 | {
20 | "dependencies": {
21 | "uuid": "*",
22 | "lodash": "*"
23 | }
24 | }
25 | ```
--------------------------------------------------------------------------------
/docs/en/others/changelog.md:
--------------------------------------------------------------------------------
1 | # 2019/12/25
2 |
3 | v1.0.0
--------------------------------------------------------------------------------
/docs/en/quickstart/examples.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | In order to make the Node.js runtime more easier to master, we prepared some example projects.
4 |
5 | Also, they are hosted on the GitHub, since we don't want to bundle them in the app. What you need to do is clone them, and follow the instructions.
6 |
7 | - [GitBox](https://github.com/cyanzhong/GitBox): A [isomorphic-git](https://isomorphic-git.org/) based Git GUI
8 | - [webtorrent-demo](https://github.com/cyanzhong/jsbox-webtorrent-demo): Download magnet links using [webtorrent](https://webtorrent.io/)
9 | - [vue-demo](https://github.com/cyanzhong/jsbox-vue-demo): [Vue.js](https://vuejs.org/) dev environment
10 | - [react-demo](https://github.com/cyanzhong/jsbox-react-demo): [React.js](https://reactjs.org/) dev environment
11 | - [youtube-dl](https://github.com/cyanzhong/jsbox-youtube-dl): A simple YouTube downloader
12 | - [cheerio](https://github.com/cyanzhong/jsbox-cheerio): Use [cheerio](https://github.com/cheeriojs/cheerio) in JSBox
13 | - [ts-playground](https://github.com/cyanzhong/jsbox-ts-playground): Transpile TypeScript to JavaScript
14 | - [browserify](https://github.com/cyanzhong/jsbox-browserify): Bundle node modules for JSBox using [browserify](http://browserify.org/)
15 | - [pdfkit](https://github.com/cyanzhong/jsbox-pdfkit): Render photos as PDF using [pdfkit](https://pdfkit.org/)
16 | - [local-web-server](https://github.com/cyanzhong/jsbox-local-web-server): A simple local web server
17 |
18 | We are planning to bring more examples, as a good way to understand the JSBox Node.js runtime.
--------------------------------------------------------------------------------
/docs/en/quickstart/intro.md:
--------------------------------------------------------------------------------
1 | # Node.js official documentation
2 |
3 | Before reading JSBox specific documentation, please make sure that you have some basic knowledge about [Node.js](https://nodejs.org), we are not going to provide its official documentation on our website.
4 |
5 | For now, JSBox uses `Node.js v10.13.0` internally, you can find its Node.js documentation here: https://nodejs.org/docs/latest-v10.x/api/
6 |
7 | This website is going to explain some differences in JSBox Node.js implementation, as well as some limitations when we use Node on mobile devices.
8 |
9 | # How to use Node.js in JSBox
10 |
11 | - You can initiate a Node environment with REPL
12 | - You can also create a Node.js module
13 | - You can use our [VS Code extension](https://marketplace.visualstudio.com/items?itemName=Ying.jsbox) to sync the code
14 |
15 | # Platform differences
16 |
17 | Due to some iOS-specific limitations, here are some differences:
18 |
19 | - `process.cwd()` returns the current running folder
20 | - `process.exit()` only closes the current running module
21 | - `process.stdin` and `process.stdout` are replaced with `$jsbox.stdin` and `$jsbox.stdout`
22 | - `child_process` is not available, such as `spawn`
23 | - The debugger is disabled due to the intl module for now
24 | - JSBox has no background mode, this is also a limitation for running Node.js
25 | - Since Node runtime uses too much memory, we disabled it for extensions for now, but we are trying to improve it
--------------------------------------------------------------------------------
/docs/en/vm/context.md:
--------------------------------------------------------------------------------
1 | # $context
2 |
3 | Sometimes, we want to pass parameters to a Node script, those parameters can be retrieved with the `$context` object.
4 |
5 | # $context.query
6 |
7 | If a script is invoked with URL scheme, or `$nodejs.run(...)`, it can be accessed like:
8 |
9 | ```js
10 | const query = $context.query;
11 | ```
12 |
13 | # $context.text/image/link/safari
14 |
15 | If we run a Node script via share sheet, the shared data can be found with:
16 |
17 | ```js
18 | // Get the first text
19 | const text = $context.text;
20 | // Get all text items
21 | const textItems = $context.textItems;
22 | // Get the first image
23 | const image = $context.image;
24 | // Get all image items
25 | const imageItems = $context.imageItems;
26 | // Get the first link
27 | const link = $context.link;
28 | // Get all link items
29 | const linkItems = $context.linkItems;
30 | // Get parameters from Safari sharing
31 | const safariParameters = $context.safari;
32 | // Get all items from share sheet
33 | const allItems = $context.allItems;
34 | ```
35 |
36 | It opens the main app directly, and you retrieve the shared data with the above methods.
--------------------------------------------------------------------------------
/docs/en/vm/intro.md:
--------------------------------------------------------------------------------
1 | # Virtual runtimes
2 |
3 | Currently, JSBox provides two runtimes, the `JSBox runtime`, and the `Node.js runtime`, it also supports bi-directional communications between two runtimes.
4 |
5 | This mechanism can benefit a lot when one runtime has some weakness:
6 |
7 | - JSBox script can use Node modules
8 | - Node script can leverage the UI power of JSBox script
9 | - Node script can call Objective-C runtime with JSBox script
10 |
11 | It's something similar to executing JavaScript on a WebView in JSBox, we implemented it based on message sending and observing.
--------------------------------------------------------------------------------
/docs/en/vm/jsbox-node.md:
--------------------------------------------------------------------------------
1 | # JSBox -> Node
2 |
3 | On the opposite of calling JSBox from Node, sometimes you want to call Node from JSBox. This will be frequently used as well, such as using an npm module in JSBox code.
4 |
5 | # $nodejs.run(object)
6 |
7 | This is a mirror of `$jsbox.run()`, running in JSBox script. You can run Node code in the same way:
8 |
9 | ```js
10 | $nodejs.run(`
11 | const request = require('request');
12 | request('http://www.google.com', function (error, response, body) {
13 | console.error('error:', error); // Print the error if one occurred
14 | console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
15 | console.log('body:', body); // Print the HTML for the Google homepage.
16 | });
17 | `
18 | );
19 | ```
20 |
21 | For installing node modules, tap the debug button in the project explorer, such as `request` in the above example.
22 |
23 | You can specify some details as well:
24 |
25 | ```js
26 | $nodejs.run({
27 | name: "MyNodeModule",
28 | // script: "",
29 | // path: "",
30 | query: {
31 | k1: "v1",
32 | k2: "v2"
33 | },
34 | // argv: [],
35 | listener: {
36 | id: "eventId",
37 | handler: result => {
38 | console.log("Message from Node: ", result);
39 | }
40 | }
41 | });
42 | ```
43 |
44 | Specify which script with `name`, `script` or `path`, and listen to notifications just like how `$jsbox.run` works.
45 |
46 | The parameters you specified with `query` can be retrieved like this:
47 |
48 | ```js
49 | const query = $context.query;
50 | ```
51 |
52 | As an alternative, you can also pass `argv` to the Node `process.argv`.
53 |
54 | In order to observe notifications, we can register a `listener` in JSBox code. Node script can notify the `handler` with `id`:
55 |
56 | ```js
57 | $jsbox.notify("eventId", {
58 | k1: "v1",
59 | k2: "v2"
60 | });
61 | ```
62 |
63 | The handler in the JSBox code will be called, and it prints the result. As you can see, `$nodejs.run/notify` and `$jsbox.run/notify` are paired, they will be used together to complete message dispatching.
64 |
65 | # $nodejs.listen(string, Function)
66 |
67 | Listen notifications from Node.js runtime:
68 |
69 | ```js
70 | $nodejs.listen("eventId", () => {
71 |
72 | });
73 | ```
74 |
75 | Node.js can send message to above observers with `$jsbox.notify(...)`.
76 |
77 | # $nodejs.version
78 |
79 | Returns the current Node.js version.
80 |
81 | # $nodejs.path
82 |
83 | Returns the current Node.js paths.
--------------------------------------------------------------------------------
/docs/en/vm/node-jsbox.md:
--------------------------------------------------------------------------------
1 | # Node -> JSBox
2 |
3 | Like we have just mentioned, Node runtime doesn't support so many APIs like JSBox does. If you want to use a native API which isn't provided you can run JSBox script:
4 |
5 | # $jsbox.run(object)
6 |
7 | This is the simplest example:
8 |
9 | ```js
10 | $jsbox.run(`
11 | $ui.render({
12 | views: [
13 | {
14 | type: "label",
15 | props: {
16 | text: "Hey"
17 | },
18 | layout: (make, view) => {
19 | make.center.equalTo(view.super);
20 | }
21 | }
22 | ]
23 | });`
24 | );
25 | ```
26 |
27 | That means a string parameter will be executed as the script.
28 |
29 | You can also specify some details:
30 |
31 | ```js
32 | $jsbox.run({
33 | name: "MyApp",
34 | // script: "",
35 | query: {
36 | k1: "v1",
37 | k2: "v2"
38 | },
39 | listener: {
40 | id: "eventId",
41 | handler: result => {
42 | console.log("Message from JSBox: ", result);
43 | }
44 | }
45 | });
46 | ```
47 |
48 | The `name` parameter specifies its script name, or `script` specifies the script content. Using `query` to pass parameters, JSBox script can retrieve them with:
49 |
50 | ```js
51 | const query = $context.query;
52 | ```
53 |
54 | In order to observe notifications, we can register a `listener` in Node code. JSBox script can notify the `handler` with `id`:
55 |
56 | ```js
57 | $nodejs.notify("eventId", {
58 | k1: "v1",
59 | k2: "v2"
60 | });
61 | ```
62 |
63 | The handler in Node code will be called, and it prints the result.
64 |
65 | # $jsbox.listen(string, Function)
66 |
67 | Listen notifications from JSBox runtime:
68 |
69 | ```js
70 | $jsbox.listen("eventId", () => {
71 |
72 | });
73 | ```
74 |
75 | JSBox can send message to above observers with `$nodejs.notify(...)`.
76 |
77 | # $jsbox.version
78 |
79 | Returns the current JSBox version.
80 |
81 | # $jsbox.path
82 |
83 | Returns the current JSBox paths.
--------------------------------------------------------------------------------
/docs/en/vm/objc.md:
--------------------------------------------------------------------------------
1 | # Node -> Objective-C
2 |
3 | Literally, this is not new, just a kind reminder. Sometimes, you cannot achieve your goal even using JSBox APIs.
4 |
5 | In that case, think about Objective-C Runtime. You can take look at this: https://docs.xteko.com/#/en/runtime/intro
6 |
7 | Here is a simple example:
8 |
9 | ```js
10 | $jsbox.run(`
11 | const url = $objc("NSURL").$URLWithString("https://google.com");
12 | $objc("UIApplication").$sharedApplication().$openURL(url);`
13 | );
14 | ```
15 |
16 | It opens a URL with Objective-C code. Of course, we don't encourage using it all the time, but just in case for some workarounds.
--------------------------------------------------------------------------------
/docs/fs/intro.md:
--------------------------------------------------------------------------------
1 | # 文件系统
2 |
3 | 我们为 JSBox 的 Node 环境实现了很多 [Native 模块](native-modules/intro.md),在介绍他们之前,我们需要了解一下 Node 模块与 JSBox 应用进行数据交换的方式。
4 |
5 | 这一章主要包括对文件路径的介绍,以及文件协议的介绍。
--------------------------------------------------------------------------------
/docs/fs/paths.md:
--------------------------------------------------------------------------------
1 | # 当前路径
2 |
3 | Node 模块运行起来之后,当前路径指向的是正在运行模块的根目录:
4 |
5 | ```js
6 | // The running module's root
7 | console.log(process.cwd());
8 |
9 | const fs = require("fs");
10 | fs.writeFileSync("test.txt", "Hello, World!");
11 | ```
12 |
13 | 上面的代码会在模块根目录创建一个文本文件,内容是 "Hello, World!"。
14 |
15 | # HOME
16 |
17 | 可以这样获取 JSBox 的文件根目录:
18 |
19 | ```js
20 | const fs = require("fs");
21 | const path = require("path");
22 | const home = process.env["HOME"];
23 |
24 | fs.writeFileSync(path.join(home, "tmp/test.txt"), "Hello, World!");
25 | ```
26 |
27 | 上面的代码会在 JSBox 的 `tmp` 目录创建一个文本文件,内容是 "Hello, World!"。当你操作 HOME 的时候,请明确地知道自己在做什么,否则可能会删除一些应用需要的文件。
28 |
29 | # 其他目录
30 |
31 | JSBox 有一些其他目录,如果你希望通过 Node 去读写他们,可以通过下面的方式获取:
32 |
33 | ```js
34 | const path = $jsbox.path;
35 |
36 | // Equals to process.env["HOME"]
37 | const home = path.home;
38 | // JSBox shared folder
39 | const shared = path.shared;
40 | // Folder that stores scripts
41 | const scripts = path.scripts;
42 | // iCloud Drive folder
43 | const icloud = path.icloud;
44 | // The running module's root
45 | const current = path.current;
46 | ```
47 |
48 | 请注意,上面的文件路径包含了一些对 JSBox 运行极为重要的文件,如果误删了其中的一些,可能会导致应用不能正常运行。所以,请再三确认自己正在做的事情。
49 |
50 | 另外,HOME 目录其中的一些子目录只具有只读权限,不能被写入。
--------------------------------------------------------------------------------
/docs/fs/protocol.md:
--------------------------------------------------------------------------------
1 | # 文件协议
2 |
3 | 在 Node 与 iOS 原生接口通信的过程中,文件是很常见的一种数据。例如读取照片、获取 iCloud Drive 文件等。
4 |
5 | 为了让这个过程更方便,我们设计了一个格式,用于从 Node 模块传递一个文件给 Native。
6 |
7 | 在之后关于 Native 模块的介绍里面,我们都用 `File` 来指代这种数据类型。
8 |
9 | `File` 可以是三种类型,下面使用 `quicklook` 模块来讲解。
10 |
11 | # 文件路径
12 |
13 | 如果使用磁盘上的文件,可以直接用它的路径来表示:
14 |
15 | ```js
16 | const ql = require("quicklook");
17 | ql.file("test.txt");
18 | ```
19 |
20 | 这将使用 iOS 的快速预览功能打开项目路径下的 `test.txt` 文件。
21 |
22 | # Buffer 对象
23 |
24 | 文件也可以是 Node.js 的一个 [Buffer](https://nodejs.org/api/buffer.html) 对象:
25 |
26 | ```js
27 | const ql = require("quicklook");
28 | const buffer = Buffer.from("I'm a string!", "utf-8");
29 | ql.file(buffer);
30 | ```
31 |
32 | # 包含名字的 Buffer
33 |
34 | 在很多时候你需要为文件起一个名字,这种情况可以使用:
35 |
36 | ```js
37 | const fs = require("fs");
38 | const ql = require("quicklook");
39 | const buffer = fs.readFileSync("image.png");
40 | ql.file({
41 | name: "image.png",
42 | data: buffer
43 | });
44 | ```
45 |
46 | 在 Node 模块里面,我们可以通过上述方式传递文件给 Native 模块,然后获取到 `Buffer` 或`路径`等文件,可以在 Node 代码里面将他们进行转换。
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | JSBox Node.js
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/docs/native-modules/addin.md:
--------------------------------------------------------------------------------
1 | # module: "addin"
2 |
3 | `addin` 模块封装了管理本地脚本的一些方法。
4 |
5 | # addin.list()
6 |
7 | 获取设备上所有的本地脚本:
8 |
9 | ```js
10 | const addin = require("addin");
11 | const list = addin.list();
12 | console.log(list[0]);
13 | // name, url, version, icon, summary, author, website...
14 | ```
15 |
16 | # addin.categories()
17 |
18 | 获取设备上所有的脚本分类:
19 |
20 | ```js
21 | const addin = require("addin");
22 | const categories = addin.categories();
23 | console.log(categories);
24 | // [string]
25 | ```
26 |
27 | # addin.current()
28 |
29 | 获取当前正在运行的脚本:
30 |
31 | ```js
32 | const addin = require("addin");
33 | const current = addin.current();
34 | // name, url, version, icon, summary, author, website...
35 | ```
36 |
37 | # addin.save(object)
38 |
39 | 保存一个脚本:
40 |
41 | ```js
42 | const addin = require("addin");
43 | addin.save({
44 | name: "Node Module",
45 | file: "downloaded/package.zip",
46 | // url, version, icon, summary, author, website
47 | });
48 | ```
49 |
50 | 其中 `name` 和 `file` 为必填字段,`file` 为 `File` 格式的 zip 文件。
51 |
52 | # addin.delete(string)
53 |
54 | 使用脚本名删除一个脚本:
55 |
56 | ```js
57 | const addin = require("addin");
58 | addin.delete("Node Module");
59 | ```
60 |
61 | # addin.run(object)
62 |
63 | 运行另一个脚本:
64 |
65 | ```js
66 | const addin = require("addin");
67 | addin.run("Node Module");
68 | ```
69 |
70 | 也可以指定运行时的输入参数:
71 |
72 | ```js
73 | const addin = require("addin");
74 | addin.run({
75 | name: "Node Module",
76 | query: {
77 | k1: "v1",
78 | k2: "v2"
79 | }
80 | });
81 | ```
82 |
83 | 被运行的脚本可以通过 `$context.query` 获得输入参数。
84 |
85 | # addin.restart()
86 |
87 | 重新运行当前的脚本:
88 |
89 | ```js
90 | const addin = require("addin");
91 | addin.restart();
92 | ```
--------------------------------------------------------------------------------
/docs/native-modules/app.md:
--------------------------------------------------------------------------------
1 | # module: "app"
2 |
3 | `app` 模块封装了和应用相关的一些函数。
4 |
5 | # app.openURL(string)
6 |
7 | 使用系统内置的机制打开一个 URL。如果是一个网页,将会被 Safari 打开,如果是一个 URL scheme,则将会打开对应的功能:
8 |
9 | ```js
10 | const app = require("app");
11 |
12 | // Open a website
13 | app.openURL("https://apple.com");
14 |
15 | // Open a URL scheme
16 | app.openURL("twitter://user?id=734056753571241989");
17 | ```
18 |
19 | 其返回值表示该 URL 是否被成功打开。
--------------------------------------------------------------------------------
/docs/native-modules/audio.md:
--------------------------------------------------------------------------------
1 | # module: "audio"
2 |
3 | `audio` 模块提供跟音频播放相关的接口:
4 |
5 | # audio.play(object)
6 |
7 | 播放一个音频:
8 |
9 | ```js
10 | const audio = require("audio");
11 | audio.play(1000);
12 | ```
13 |
14 | 该方式使用 sound id 播放内置音频,请参考:https://github.com/TUNER88/iOSSystemSoundsLibrary 。
15 |
16 | 也可以使用路径来播放一段音频,同时支持网络文件和本地文件:
17 |
18 | ```js
19 | const audio = require("audio");
20 | audio.play("https://");
21 | // audio.play("assets/test.wav");
22 | ```
23 |
24 | 如果对播放状态进行更精细的控制,可以使用下面这些方法:
25 |
26 | ```js
27 | // 暂停播放
28 | audio.pause();
29 | ```
30 |
31 | ```js
32 | // 恢复播放
33 | audio.resume();
34 | ```
35 |
36 | ```js
37 | // 停止播放
38 | audio.stop();
39 | ```
40 |
41 | ```js
42 | // 设置播放进度(秒)
43 | audio.seek(60);
44 | ```
45 |
46 | ```js
47 | // 获得当前的状态
48 | const status = audio.status();
49 | // 0: 已停止, 1: 等待播放, 2: 正在播放
50 | ```
51 |
52 | ```js
53 | // 获取时长
54 | const duration = audio.duration();
55 | ```
56 |
57 | ```js
58 | // 获取当前的播放时间
59 | const offset = audio.offset();
60 | ```
61 |
62 | # 事件消息
63 |
64 | 音频播放过程中可以监听一些消息,例如:
65 |
66 | ```js
67 | const audio = require("audio");
68 | audio.play({
69 | events: {
70 | itemEnded: () => {},
71 | timeJumped: () => {},
72 | didPlayToEndTime: () => {},
73 | failedToPlayToEndTime: () => {},
74 | playbackStalled: () => {},
75 | newAccessLogEntry: () => {},
76 | newErrorLogEntry: () => {},
77 | }
78 | });
79 | ```
80 |
81 | 参考:https://developer.apple.com/documentation/avfoundation/avplayeritem?language=objc
--------------------------------------------------------------------------------
/docs/native-modules/calendar.md:
--------------------------------------------------------------------------------
1 | # module: "calendar"
2 |
3 | `calendar` 模块提供了 iOS 系统日历相关的接口。
4 |
5 | # calendar.fetch(object) -> Promise
6 |
7 | 用于读取日历事件(会提示用户授权):
8 |
9 | ```js
10 | const calendar = require("calendar");
11 | calendar.fetch({
12 | startDate: new Date(),
13 | hours: 3 * 24,
14 | }).then(result => {
15 | const events = result.events;
16 | });
17 | ```
18 |
19 | 表示读取从现在开始往后 3 天的所有日历事件,除了指定 `hours` 以外,也可以自己计算并指定 `endDate`。
20 |
21 | 在返回的数据里面,events 内含的对象结构如下:
22 |
23 | 属性 | 类型 | 读写 | 说明
24 | ---|---|---|---
25 | title | string | 读写 | 标题
26 | identifier | string | 只读 | id
27 | location | string | 读写 | 位置
28 | notes | string | 读写 | 备注
29 | url | string | 读写 | 网址
30 | modifiedDate | date | 只读 | 修改时间
31 | creationDate | date | 只读 | 创建时间
32 | allDay | boolean | 只读 | 是否全天
33 | startDate | date | 只读 | 开始时间
34 | endDate | date | 只读 | 结束时间
35 | status | number | 只读 | 状态[请参考](https://developer.apple.com/documentation/eventkit/ekeventstatus)
36 |
37 | # calendar.create(object) -> Promise
38 |
39 | 用于创建一个日历事项:
40 |
41 | ```js
42 | const calendar = require("calendar");
43 | calendar.create({
44 | title: "Hey!",
45 | startDate: new Date(),
46 | hours: 3,
47 | notes: "Hello, World!"
48 | }).then(result => {
49 | console.log(result);
50 | });
51 | ```
52 |
53 | # calendar.save(object) -> Promise
54 |
55 | 通过 `calendar.fetch` 取出来的日历项,可以修改一些属性,然后通过 save 接口更新:
56 |
57 | ```js
58 | const calendar = require("calendar");
59 | calendar.fetch({
60 | startDate: new Date(),
61 | hours: 3 * 24
62 | }).then(resp => {
63 | const event = resp.events[0];
64 | event.title = "Modified";
65 | calendar.save(event);
66 | });
67 | ```
68 |
69 | 可以通过 `alarmDate` 和 `alarmDates` 来指定提醒闹钟时间。
70 |
71 | # calendar.delete(object) -> Promise
72 |
73 | 在系统日历中删除某个日历项:
74 |
75 | ```js
76 | calendar.delete(event).then(result => {
77 | console.log(result);
78 | });
79 | ```
--------------------------------------------------------------------------------
/docs/native-modules/clipboard.md:
--------------------------------------------------------------------------------
1 | # module: "clipboard"
2 |
3 | `clipboard` 模块提供了剪贴板相关的接口。
4 |
5 | # clipboard.text()
6 |
7 | 获取剪贴板里的文字:
8 |
9 | ```js
10 | const clipboard = require("clipboard");
11 | const text = clipboard.text();
12 | ```
13 |
14 | # clipboard.setText(string)
15 |
16 | 设置剪贴板里的文字:
17 |
18 | ```js
19 | const clipboard = require("clipboard");
20 | clipboard.setText("Hey");
21 | ```
22 |
23 | # clipboard.setTextLocalOnly(string)
24 |
25 | 设置剪贴板文字到本地,不会触发 iOS 的通用剪贴板同步:
26 |
27 | ```js
28 | const clipboard = require("clipboard");
29 | clipboard.setTextLocalOnly("Hey");
30 | ```
31 |
32 | # clipboard.image() -> Buffer
33 |
34 | 获取剪贴板里的图片:
35 |
36 | ```js
37 | const clipboard = require("clipboard");
38 | const buffer = clipboard.image();
39 | ```
40 |
41 | # clipboard.setImage(File)
42 |
43 | 设置剪贴板里的图片:
44 |
45 | ```js
46 | const clipboard = require("clipboard");
47 | clipboard.setImage(buffer);
48 | ```
49 |
50 | # clipboard.clear()
51 |
52 | 清除剪贴板的全部内容:
53 |
54 | ```js
55 | const clipboard = require("clipboard");
56 | clipboard.clear();
57 | ```
--------------------------------------------------------------------------------
/docs/native-modules/contact.md:
--------------------------------------------------------------------------------
1 | # module: "contact"
2 |
3 | `contact` 模块提供对系统通讯录相关的接口。
4 |
5 | # contact.pick(object) -> Promise
6 |
7 | 从通讯录中选择一个或多个联系人:
8 |
9 | ```js
10 | const contact = require("contact");
11 | contact.pick({
12 | multi: false
13 | }).then(result => {
14 |
15 | });
16 | ```
17 |
18 | 其中 `multi` 为 `true` 时表示选择多个联系人。
19 |
20 | # contact.fetch(object) -> Promise
21 |
22 | 通过关键字查找某些联系人:
23 |
24 | ```js
25 | const contact = require("contact");
26 | contact.fetch({
27 | key: "Ying"
28 | }).then(results => {
29 |
30 | });
31 | ```
32 |
33 | 获得的是一个数组,每个元素支持很多属性,请参考:https://developer.apple.com/documentation/contacts/cncontact
34 |
35 | 也可以查找某个分组下面的所有联系人:
36 |
37 | ```js
38 | const contact = require("contact");
39 | contact.fetch({
40 | group
41 | }).then(results => {
42 |
43 | });
44 | ```
45 |
46 | # contact.create(object) -> Promise
47 |
48 | 创建联系人:
49 |
50 | ```js
51 | const contact = require("contact");
52 | contact.create({
53 | givenName: "Ying",
54 | familyName: "Zhong",
55 | phoneNumbers: {
56 | "Home": "18000000000",
57 | "Office": "88888888"
58 | },
59 | emails: {
60 | "Home": "log.e@qq.com"
61 | }
62 | }).then(resp => {
63 |
64 | });
65 | ```
66 |
67 | # contact.save(object) -> Promise
68 |
69 | 将更新后的 contact 对象存储到系统通讯录:
70 |
71 | ```js
72 | const contact = require("contact");
73 | contact.save(object).then(resp => {
74 |
75 | });
76 | ```
77 |
78 | # contact.delete(object) -> Promise
79 |
80 | 删除一些联系人:
81 |
82 | ```js
83 | const contact = require("contact");
84 | contact.delete(contacts).then(resp => {
85 |
86 | });
87 | ```
88 |
89 | # contact.fetchGroups() -> Promise
90 |
91 | 获取联系人分组:
92 |
93 | ```js
94 | const contact = require("contact");
95 | contact.fetchGroups().then(groups => {
96 | console.log(`name: ${groups[0].name}`);
97 | });
98 | ```
99 |
100 | # contact.addGroup(string) -> Promise
101 |
102 | 添加一个新的分组:
103 |
104 | ```js
105 | const contact = require("contact");
106 | contact.addGroup("Group Name").then(group => {
107 |
108 | });
109 | ```
110 |
111 | # contact.deleteGroup(object) -> Promise
112 |
113 | 删除一个分组:
114 |
115 | ```js
116 | const contact = require("contact");
117 | contact.fetchGroups().then(groups => {
118 | contact.deleteGroup(groups[0]);
119 | });
120 | ```
121 |
122 | # contact.updateGroup(object) -> Promise
123 |
124 | 保存更新后的分组:
125 |
126 | ```js
127 | const contact = require("contact");
128 | contact.fetchGroups().then(groups => {
129 | const group = groups[0];
130 | group.name = "New Name";
131 | contact.updateGroup(group);
132 | });
133 | ```
134 |
135 | # contact.addToGroup(object) -> Promise
136 |
137 | 将联系人添加到分组:
138 |
139 | ```js
140 | const contact = require("contact");
141 | contact.addToGroup({
142 | contact: contactObject,
143 | group: groupObject
144 | }).then(result => {
145 |
146 | });
147 | ```
148 |
149 | # contact.removeFromGroup(object) -> Promise
150 |
151 | 将联系人从分组中移除:
152 |
153 | ```js
154 | const contact = require("contact");
155 | contact.removeFromGroup({
156 | contact: contactObject,
157 | group: groupObject
158 | }).then(result => {
159 |
160 | });
161 | ```
--------------------------------------------------------------------------------
/docs/native-modules/detector.md:
--------------------------------------------------------------------------------
1 | # module: "detector"
2 |
3 | `detector` 提供了一套检测数据的机制。
4 |
5 | # detector.dates(string)
6 |
7 | 将文本中所有的日期提取出来:
8 |
9 | ```js
10 | const detector = require("detector");
11 | const dates = detector.dates("2017年10月10日");
12 | ```
13 |
14 | # detector.date(string)
15 |
16 | 获取文本中的第一个日期。
17 |
18 | # detector.addresses(string)
19 |
20 | 将文本中所有的地址提取出来:
21 |
22 | ```js
23 | const detector = require("detector");
24 | const addresses = detector.addresses("");
25 | ```
26 |
27 | # detector.address(string)
28 |
29 | 获取文本中的第一个地址。
30 |
31 | # detector.links(string)
32 |
33 | 将文本中所有的链接提取出来:
34 |
35 | ```js
36 | const detector = require("detector");
37 | const links = detector.links("http://apple.com hello http://xteko.com");
38 | ```
39 |
40 | # detector.link(string)
41 |
42 | 获取文本中的第一个链接。
43 |
44 | # detector.phoneNumbers(string)
45 |
46 | 将文本中所有的电话号码提取出来:
47 |
48 | ```js
49 | const detector = require("detector");
50 | const phoneNumbers = detector.phoneNumbers("18666666666 hello 18777777777");
51 | ```
52 |
53 | # detector.phoneNumber(string)
54 |
55 | 获取文本中的第一个电话号码。
--------------------------------------------------------------------------------
/docs/native-modules/device.md:
--------------------------------------------------------------------------------
1 | # module: "device"
2 |
3 | `device` 模块提供了和当前设备有关的一些接口。
4 |
5 | # device.info()
6 |
7 | 返回当前设备的信息:
8 |
9 | ```js
10 | const device = require("device");
11 | const info = device.info();
12 | ```
13 |
14 | 样例输出:
15 |
16 | ```json
17 | {
18 | "model": "string",
19 | "language": "string",
20 | "version": "string",
21 | "name": "cyan's iPhone",
22 | "screen": {
23 | "width": 240,
24 | "height": 320,
25 | "scale": 2.0,
26 | "orientation": 1,
27 | }
28 | }
29 | ```
30 |
31 | # device.isDarkMode()
32 |
33 | 检查设备是否处于 Dark Mode 状态:
34 |
35 | ```js
36 | const device = require("device");
37 | if (device.isDarkMode()) {
38 |
39 | }
40 | ```
41 |
42 | # device.isXXX()
43 |
44 | 快速检查设备屏幕类型:
45 |
46 | ```js
47 | const device = require("device");
48 | const isIphoneX = device.isIphoneX();
49 | const isIphonePlus = device.isIphonePlus();
50 | const isIpad = device.isIpad();
51 | const isIpadPro = device.isIpadPro();
52 | ```
53 |
54 | # device.space()
55 |
56 | 获取设备的内存/磁盘空间:
57 |
58 | ```js
59 | const device = require("device");
60 | const space = device.space();
61 | ```
62 |
63 | 返回数据样例:
64 |
65 | ```json
66 | {
67 | "disk": {
68 | "free": {
69 | "bytes": 87409733632,
70 | "string": "87.41 GB"
71 | },
72 | "total": {
73 | "bytes": 127989493760,
74 | "string": "127.99 GB"
75 | }
76 | },
77 | "memory": {
78 | "free": {
79 | "bytes": 217907200,
80 | "string": "207.8 MB"
81 | },
82 | "total": {
83 | "bytes": 3221225472,
84 | "string": "3 GB"
85 | }
86 | }
87 | }
88 | ```
89 |
90 | # device.ssid()
91 |
92 | 获取当前 Wi-Fi 的 SSID 信息:
93 |
94 | ```js
95 | const device = require("device");
96 | const ssid = device.ssid();
97 | ```
98 |
99 | 返回数据样例:
100 |
101 | ```json
102 | {
103 | "SSIDDATA": {},
104 | "BSSID": "aa:bb:cc:dd:ee:ff",
105 | "SSID": "SSID"
106 | }
107 | ```
108 |
109 | 注:在 iOS 13 上,使用此接口需要应用具备地理位置权限,你可以通过 `location` 模块获得权限。
110 |
111 | # device.networkType()
112 |
113 | 获取当前设备的网络类型:
114 |
115 | ```js
116 | const device = require("device");
117 | const networkType = device.networkType();
118 | ```
119 |
120 | 数值 | 说明
121 | ---|---
122 | 0 | 无网络
123 | 1 | Wi-Fi
124 | 2 | 蜂窝数据
125 |
126 | # device.wlanAddress()
127 |
128 | 获得局域网 IP 地址:
129 |
130 | ```js
131 | const device = require("device");
132 | const address = device.wlanAddress();
133 | ```
134 |
135 | # device.hasTouchID()
136 |
137 | 检查是否支持 Touch ID:
138 |
139 | ```js
140 | const device = require("device");
141 | const hasTouchID = device.hasTouchID();
142 | ```
143 |
144 | # device.hasFaceID()
145 |
146 | 检查是否支持 Face ID:
147 |
148 | ```js
149 | const device = require("device");
150 | const hasFaceID = device.hasFaceID();
151 | ```
152 |
153 | # device.taptic(number)
154 |
155 | 在有 Taptic Engine 的设备上触发一个轻微的振动,例如:
156 |
157 | ```js
158 | const device = require("device");
159 | device.taptic(0);
160 | ```
161 |
162 | 参数 | 类型 | 说明
163 | ---|---|---
164 | level | number | 0 ~ 2 表示振动等级
165 |
166 | # device.isJailbroken()
167 |
168 | 检查设备是否越狱:
169 |
170 | ```js
171 | const device = require("device");
172 | const isJailbroken = device.isJailbroken();
173 | ```
174 |
175 | # device.isVoiceOverOn()
176 |
177 | 检查是否在使用 VoiceOver:
178 |
179 | ```js
180 | const device = require("device");
181 | const isVoiceOverOn = device.isVoiceOverOn();
182 | ```
--------------------------------------------------------------------------------
/docs/native-modules/drive.md:
--------------------------------------------------------------------------------
1 | # module: "drive"
2 |
3 | `drive` 模块提供了 iCloud 云盘相关的接口。
4 |
5 | # drive.save(File) -> Promise
6 |
7 | 将 File 格式的文件保存到 iCloud 云盘:
8 |
9 | ```js
10 | const drive = require("drive");
11 | drive.save(buffer).then(path => {
12 | console.log(path);
13 | })
14 | ```
15 |
16 | 返回值表示在 iCloud 云盘的路径。
17 |
18 | # drive.open() -> Promise
19 |
20 | 使用系统的文件选择器从 iCloud 云盘选择文件:
21 |
22 | ```js
23 | const drive = require("drive");
24 | drive.open({
25 | type: ["public.data", "public.content"]
26 | }).then(buffer => {
27 | console.log(buffer);
28 | });
29 | ```
30 |
31 | 其中 `type` 指定文件的 MIME 类型,默认为全部文件。
--------------------------------------------------------------------------------
/docs/native-modules/imagekit.md:
--------------------------------------------------------------------------------
1 | # 图像处理
2 |
3 | JSBox 2.1.0 增加了图像处理模块 `imagekit`,通过这个模块你可以很轻松的处理图像,例如:
4 |
5 | - 调整大小
6 | - 旋转
7 | - 制作灰度图像
8 | - 图像叠加
9 | ...
10 |
11 | 为了更直观的介绍,我们构建了一个使用了所有接口的样例项目:https://github.com/cyanzhong/jsbox-imagekit-node
12 |
13 | # imagekit.info(File)
14 |
15 | 获取图片信息:
16 |
17 | ```js
18 | const imagekit = require("imagekit");
19 | const info = imagekit.info(source);
20 | // width, height, orientation, scale, props
21 | ```
22 |
23 | # imagekit.grayscale(File)
24 |
25 | 转换成灰度图像:
26 |
27 | ```js
28 | const imagekit = require("imagekit");
29 | const output = imagekit.grayscale(source);
30 | ```
31 |
32 | # imagekit.invert(File)
33 |
34 | 将图像反色:
35 |
36 | ```js
37 | const imagekit = require("imagekit");
38 | const output = imagekit.invert(source);
39 | ```
40 |
41 | # imagekit.sepia(File)
42 |
43 | 添加棕褐色滤镜:
44 |
45 | ```js
46 | const imagekit = require("imagekit");
47 | const output = imagekit.sepia(source);
48 | ```
49 |
50 | # imagekit.adjustEnhance(File)
51 |
52 | 自动改善图像效果:
53 |
54 | ```js
55 | const imagekit = require("imagekit");
56 | const output = imagekit.adjustEnhance(source);
57 | ```
58 |
59 | # imagekit.adjustRedEye(File)
60 |
61 | 自动红眼消除:
62 |
63 | ```js
64 | const imagekit = require("imagekit");
65 | const output = imagekit.adjustRedEye(source);
66 | ```
67 |
68 | # imagekit.adjustBrightness(File, value)
69 |
70 | 调整图片亮度:
71 |
72 | ```js
73 | const imagekit = require("imagekit");
74 | const output = imagekit.adjustBrightness(source, 100);
75 | // value range: (-255, 255)
76 | ```
77 |
78 | # imagekit.adjustContrast(File, value)
79 |
80 | 调整图片对比度:
81 |
82 | ```js
83 | const imagekit = require("imagekit");
84 | const output = imagekit.adjustContrast(source, 100);
85 | // value range: (-255, 255)
86 | ```
87 |
88 | # imagekit.adjustGamma(File, value)
89 |
90 | 调整图片伽马值:
91 |
92 | ```js
93 | const imagekit = require("imagekit");
94 | const output = imagekit.adjustGamma(source, 4);
95 | // value range: (0.01, 8)
96 | ```
97 |
98 | # imagekit.adjustOpacity(File, value)
99 |
100 | 调整图片不透明度:
101 |
102 | ```js
103 | const imagekit = require("imagekit");
104 | const output = imagekit.adjustOpacity(source, 0.5);
105 | // value range: (0, 1)
106 | ```
107 |
108 | # imagekit.blur(File, bias)
109 |
110 | 高斯模糊效果:
111 |
112 | ```js
113 | const imagekit = require("imagekit");
114 | const output = imagekit.blur(source, 0);
115 | ```
116 |
117 | # imagekit.emboss(File, bias)
118 |
119 | 浮雕效果:
120 |
121 | ```js
122 | const imagekit = require("imagekit");
123 | const output = imagekit.emboss(source, 0);
124 | ```
125 |
126 | # imagekit.sharpen(File, bias)
127 |
128 | 锐化:
129 |
130 | ```js
131 | const imagekit = require("imagekit");
132 | const output = imagekit.sharpen(source, 0);
133 | ```
134 |
135 | # imagekit.unsharpen(File, bias)
136 |
137 | 钝化:
138 |
139 | ```js
140 | const imagekit = require("imagekit");
141 | const output = imagekit.unsharpen(source, 0);
142 | ```
143 |
144 | # imagekit.detectEdge(source, bias)
145 |
146 | 边缘检测:
147 |
148 | ```js
149 | const imagekit = require("imagekit");
150 | const output = imagekit.detectEdge(source, 0);
151 | ```
152 |
153 | # imagekit.mask(File, mask)
154 |
155 | 使用 `mask` 作为蒙版进行切图:
156 |
157 | ```js
158 | const imagekit = require("imagekit");
159 | const output = imagekit.mask(source, mask);
160 | ```
161 |
162 | # imagekit.reflect(File, height, fromAlpha, toAlpha)
163 |
164 | 创建上下镜像的图片,从 `height` 处折叠,透明度从 `fromAlpha` 变化到 `toAlpha`:
165 |
166 | ```js
167 | const imagekit = require("imagekit");
168 | const output = imagekit.reflect(source, 100, 0, 1);
169 | ```
170 |
171 | # imagekit.cropTo(File, size, mode)
172 |
173 | 图片裁剪:
174 |
175 | ```js
176 | const imagekit = require("imagekit");
177 | const output = imagekit.cropTo(source, {width: 100, height: 100}, 0);
178 | // mode:
179 | // - 0: top-left
180 | // - 1: top-center
181 | // - 2: top-right
182 | // - 3: bottom-left
183 | // - 4: bottom-center
184 | // - 5: bottom-right
185 | // - 6: left-center
186 | // - 7: right-center
187 | // - 8: center
188 | ```
189 |
190 | # imagekit.scaleBy(File, value)
191 |
192 | 使用比例调整图片大小:
193 |
194 | ```js
195 | const imagekit = require("imagekit");
196 | const output = imagekit.scaleBy(source, 0.5);
197 | ```
198 |
199 | # imagekit.scaleTo(File, size, mode)
200 |
201 | 使用 size 调整图片大小:
202 |
203 | ```js
204 | const imagekit = require("imagekit");
205 | const output = imagekit.scaleTo(source, {width: 100, height: 100}, 0);
206 | // mode:
207 | // - 0: scaleFill
208 | // - 1: scaleAspectFit
209 | // - 2: scaleAspectFill
210 | ```
211 |
212 | # imagekit.scaleFill(File, size)
213 |
214 | 使用 `scaleFill` 模式调整大小:
215 |
216 | ```js
217 | const imagekit = require("imagekit");
218 | const output = imagekit.scaleFill(source, {width: 100, height: 100});
219 | ```
220 |
221 | # imagekit.scaleAspectFit(File, size)
222 |
223 | 使用 `scaleAspectFit` 模式调整大小:
224 |
225 | ```js
226 | const imagekit = require("imagekit");
227 | const output = imagekit.scaleAspectFit(source, {width: 100, height: 100});
228 | ```
229 |
230 | # imagekit.scaleAspectFill(File, size)
231 |
232 | 使用 `scaleAspectFill` 模式调整大小:
233 |
234 | ```js
235 | const imagekit = require("imagekit");
236 | const output = imagekit.scaleAspectFill(source, {width: 100, height: 100});
237 | ```
238 |
239 | # imagekit.rotate(File, radians)
240 |
241 | 旋转图片(将会调整图像大小):
242 |
243 | ```js
244 | const imagekit = require("imagekit");
245 | const output = imagekit.rotate(source, Math.PI * 0.25);
246 | ```
247 |
248 | # imagekit.rotatePixels(File, radians)
249 |
250 | 旋转图片(不会改变图像大小,可能会裁剪):
251 |
252 | ```js
253 | const imagekit = require("imagekit");
254 | const output = imagekit.rotatePixels(source, Math.PI * 0.25);
255 | ```
256 |
257 | # imagekit.flip(File, mode)
258 |
259 | 获得镜像图片:
260 |
261 | ```js
262 | const imagekit = require("imagekit");
263 | const output = imagekit.flip(source, 0);
264 | // mode:
265 | // - 0: vertically
266 | // - 1: horizontally
267 | ```
268 |
269 | # imagekit.concatenate(Files, space, mode)
270 |
271 | 拼接多张图片,可以添加间距:
272 |
273 | ```js
274 | const imagekit = require("imagekit");
275 | const output = imagekit.concatenate(Files, 10, 0);
276 | // mode:
277 | // - 0: vertically
278 | // - 1: horizontally
279 | ```
280 |
281 | # imagekit.combine(File, mask, mode)
282 |
283 | 将两个图片叠加:
284 |
285 | ```js
286 | const imagekit = require("imagekit");
287 | const output = imagekit.combine(File1, File2, mode);
288 | // mode:
289 | // - 0: top-left
290 | // - 1: top-center
291 | // - 2: top-right
292 | // - 3: bottom-left
293 | // - 4: bottom-center
294 | // - 5: bottom-right
295 | // - 6: left-center
296 | // - 7: right-center
297 | // - 8: center (default)
298 | // - {x: number, y: number}: absolute position
299 | ```
300 |
301 | # imagekit.rounded(File, radius)
302 |
303 | 获取圆角图片:
304 |
305 | ```js
306 | const imagekit = require("imagekit");
307 | const output = imagekit.rounded(source, 10);
308 | ```
309 |
310 | # imagekit.circular(image)
311 |
312 | 获取正圆形图片,如果原图不是正方形则会居中并从来裁剪:
313 |
314 | ```js
315 | const imagekit = require("imagekit");
316 | const output = imagekit.circular(source);
317 | ```
318 |
319 | # imagekit.extractGIF(data) -> Promise
320 |
321 | 将 GIF 文件分解成单帧:
322 |
323 | ```js
324 | const imagekit = require("imagekit");
325 | const {images, durations} = await imagekit.extractGIF(data);
326 | // image: all image frames
327 | // durations: duration for each frame
328 | ```
329 |
330 | # imagekit.makeGIF(source, options) -> Promise
331 |
332 | 将 image 数组或视频文件 data 合成为 GIF 文件:
333 |
334 | ```js
335 | const imagekit = require("imagekit");
336 | const images = [File1, File2];
337 | const options = {
338 | durations: [0.5, 0.5],
339 | // size: 16, 12, 8, 4, 2
340 | }
341 | const data = await imagekit.makeGIF(Files, options);
342 | ```
343 |
344 | 若使用 `duration` 替代 `durations`,则每张图片时长一致。
345 |
346 | # imagekit.makeVideo(source, options) -> Promise
347 |
348 | 将 image 数组或 GIF 文件合成为视频文件:
349 |
350 | ```js
351 | const imagekit = require("imagekit");
352 | const images = [File1, File2];
353 | const data = await imagekit.makeVideo(Files, {
354 | durations: [0.5, 0.5]
355 | });
356 | ```
357 |
358 | 若使用 `duration` 替代 `durations`,则每张图片时长一致,使用 GIF 时不需要指定时长。
--------------------------------------------------------------------------------
/docs/native-modules/input.md:
--------------------------------------------------------------------------------
1 | # 用户输入
2 |
3 | 在 Node 环境你可以使用 `stdin` 和 `stdout` 来处理输入输出,但正如我们之前提到的那样,由于一些限制,你需要使用:
4 |
5 | - `$jsbox.stdin` 替代 `process.stdin`
6 | - `$jsbox.stdout` 替代 `process.stdout`
7 |
8 | 除此之外,你可以用自己已有的 Node.js 知识来用他们,正如这个程序:
9 |
10 | ```js
11 | const readline = require("readline");
12 |
13 | const interface = readline.createInterface({
14 | input: $jsbox.stdin,
15 | output: $jsbox.stdout,
16 | terminal: false
17 | });
18 |
19 | interface.on('line', line => {
20 | console.log(`Echo: ${line}`);
21 | });
22 | ```
23 |
24 | 这是一个 Echo 程序,用户输入什么,程序就输出什么。
25 |
26 | # module: "input"
27 |
28 | 除此之外,你还可以使用 JSBox 内建的 `input` 模块来获得用户输入。
29 |
30 | # input.text(object) -> Promise
31 |
32 | 使用 JSBox 原生组件输入文字内容:
33 |
34 | ```js
35 | const input = require("input");
36 | input.text({
37 | type: 0,
38 | placeholder: "Input your name..",
39 | text: "Ying"
40 | }).then(text => {
41 | console.log(text);
42 | });
43 | ```
44 |
45 | 其中 `placeholder` 和 `text` 分别指定了占位符和当前的文字,`type` 则指定了键盘类型,所有参数均可缺省。
46 |
47 | `type` 可以参考:https://docs.xteko.com/#/data/constant?id=kbtype
48 |
49 | 函数返回一个 Promise 对象,你也可以使用 async/await 的方式调用。
50 |
51 | # input.speech(object) -> Promise
52 |
53 | 使用 iOS 内建的语音识别来输入文字:
54 |
55 | ```js
56 | const input = require("input");
57 | input.speech({
58 | locale: "en-US",
59 | autoFinish: true
60 | }).then(text => {
61 | console.log(text);
62 | });
63 | ```
64 |
65 | 其中 `autoFinish` 表示是否在用户说完之后自动完成,默认为 `false`。`locale` 参数则指定语音的地区,默认为设备的地区。
--------------------------------------------------------------------------------
/docs/native-modules/intro.md:
--------------------------------------------------------------------------------
1 | # Native 模块
2 |
3 | 在 JSBox 里面使用 Node 运行时,你可以运行标准的 Node.js 程序。同时,我们也为 Node 运行时提供了很多 Native 模块,让你可以通过标准的 Node.js 程序来与 iOS 原生功能进行交互。例如:读取剪贴板、使用 share sheet 分享文件等等。
4 |
5 | 这些 JSBox 特有的模块,我们统一将其称为 Native 模块。
6 |
7 | Native 模块是标准的 `node module`,所以在使用上和普通的 node module 没有任何区别,例如这样:
8 |
9 | ```js
10 | const clipboard = require("clipboard");
11 |
12 | // Returns the clipboard text
13 | const text = clipboard.text();
14 |
15 | // Change the clipboard text
16 | clipboard.setText("Hey");
17 | ```
18 |
19 | # 支持的模块
20 |
21 | 在理想的状况下,我们希望 JSBox 的 Node 环境具有和原生运行时同样的能力。但做到这一点需要巨大的时间和精力,所以在目前的版本里面我们暂时只提供了大部分的模块:
22 |
23 | - [应用相关](native-modules/app.md)
24 | - [系统相关](native-modules/system.md)
25 | - [设备相关](native-modules/device.md)
26 | - [用户输入](native-modules/input.md)
27 | - [用户界面](native-modules/ui.md)
28 | - [本地化](native-modules/l10n.md)
29 | - [剪贴板](native-modules/clipboard.md)
30 | - [图片](native-modules/photo.md)
31 | - [iCloud 云盘](native-modules/drive.md)
32 | - [预览](native-modules/quicklook.md)
33 | - [社交分享](native-modules/share.md)
34 | - [二维码](native-modules/qrcode.md)
35 | - [地理位置](native-modules/location.md)
36 | - [Safari](native-modules/safari.md)
37 | - [推送](native-modules/push.md)
38 | - [音频](native-modules/audio.md)
39 | - [语音合成](native-modules/speech.md)
40 | - [日历](native-modules/calendar.md)
41 | - [提醒事项](native-modules/reminder.md)
42 | - [通讯录](native-modules/contact.md)
43 | - [消息](native-modules/message.md)
44 | - [传感数据](native-modules/motion.md)
45 | - [数据检测](native-modules/detector.md)
46 |
47 | 这些模块能够满足你绝大部分时候的需求,如果需要更灵活的功能,在我们完善 Native 模块之前,可以考虑通过 JSBox 与 Node 的通信来实现。
48 |
49 | 关于这部分的内容,可以在这里找到:[通信机制](vm/intro.md)。
--------------------------------------------------------------------------------
/docs/native-modules/l10n.md:
--------------------------------------------------------------------------------
1 | # module: "l10n"
2 |
3 | `l10n` 模块为 Node 脚本提供本地话文字支持。
4 |
5 | # 提供本地化字符串
6 |
7 | 你可以在项目路径下的 `strings` 目录放置 `.strings` 文件,类似这样:
8 |
9 | ```
10 | MyNodeModule/strings
11 | zh-Hans.strings
12 | zh-Hant.strings
13 | en.strings
14 | ```
15 |
16 | strings 文件是纯文本文件,结构就是多行键值对:
17 |
18 | ```
19 | "KEY1" = "Value1";
20 | "KEY2" = "Value2";
21 | ```
22 |
23 | # 使用本地化字符串
24 |
25 | 需要使用本地化的字符串时,使用其 key 去获取即可:
26 |
27 | ```js
28 | const l10n = require("l10n");
29 | const localized = l10n("KEY1");
30 | ```
31 |
32 | 请注意,当用户设备没能找到合适的字符串时,将会有如下回退策略:
33 |
34 | - 没有找到对应语言,回退到英语版本
35 | - 没有找到对于的 value,回退到 key 本身
--------------------------------------------------------------------------------
/docs/native-modules/location.md:
--------------------------------------------------------------------------------
1 | # module: "location"
2 |
3 | `location` 模块提供了地理位置相关的接口。
4 |
5 | # location.available()
6 |
7 | 返回当前是否有地理位置的权限:
8 |
9 | ```js
10 | const location = require("location");
11 | if (location.available()) {
12 |
13 | }
14 | ```
15 |
16 | # location.fetch() -> Promise
17 |
18 | 获取当前的地理位置:
19 |
20 | ```js
21 | const location = require("location");
22 | location.fetch().then(result => {
23 | const latitude = result.lat;
24 | const longitude = result.lng;
25 | const altitude = result.alt;
26 | });
27 | ```
28 |
29 | 会同时返回经纬度和海拔。
30 |
31 | # location.startUpdates(object)
32 |
33 | 开始监听位置变化:
34 |
35 | ```js
36 | const location = require("location");
37 | location.startUpdates({
38 | once: false
39 | },result => {
40 | // lat, lng, alt
41 | });
42 | ```
43 |
44 | `once` 表示是否只更新一次。
45 |
46 | # location.trackHeading(object)
47 |
48 | 监听 Heading 数据变化:
49 |
50 | ```js
51 | const location = require("location");
52 | location.trackHeading(result => {
53 | const magneticHeading = result.magneticHeading;
54 | const trueHeading = result.trueHeading;
55 | const headingAccuracy = result.headingAccuracy;
56 | const x = result.x;
57 | const y = result.y;
58 | const z = result.z;
59 | });
60 | ```
61 |
62 | # location.stopUpdates()
63 |
64 | 停止地理位置更新:
65 |
66 | ```js
67 | const location = require("location");
68 | location.stopUpdates();
69 | ```
70 |
71 | # location.select() -> Promise
72 |
73 | 在 JSBox 内建的地图组件里面选取一个位置:
74 |
75 | ```js
76 | const location = require("location");
77 | location.select().then(result => {
78 | const latitude = result.lat;
79 | const longitude = result.lng;
80 | });
81 | ```
--------------------------------------------------------------------------------
/docs/native-modules/message.md:
--------------------------------------------------------------------------------
1 | # module: "message"
2 |
3 | `message` 模块提供对短信、邮件相关接口的支持。
4 |
5 | # message.sms(object) -> Promise
6 |
7 | 调用系统接口发送短信:
8 |
9 | ```js
10 | const message = require("message");
11 | message.sms({
12 | recipients: ["18688888888", "10010"],
13 | body: "Message body",
14 | subject: "Message subject",
15 | attachments: [
16 | {
17 | name: "image.png",
18 | data: buffer
19 | }
20 | ]
21 | }).then(result => {
22 |
23 | });
24 | ```
25 |
26 | 参数 | 说明
27 | ---|---
28 | recipients | 接受者
29 | body | 内容
30 | subject | 主题
31 | attachments | File 格式附件
32 | result | 0: 取消 1: 成功 2: 失败
33 |
34 | # message.mail(object) -> Promise
35 |
36 | 调用系统接口发送邮件:
37 |
38 | ```js
39 | message.mail({
40 | subject: "Message subject",
41 | to: ["18688888888", "10010"],
42 | cc: [],
43 | bcc: [],
44 | body: "Message body",
45 | attachments: [
46 | {
47 | name: "image.png",
48 | data: buffer
49 | }
50 | ]
51 | }).then(result => {
52 |
53 | });
54 | ```
55 |
56 | 参数 | 说明
57 | ---|---
58 | subject | 主题
59 | to | 接受者
60 | cc | 抄送
61 | bcc | 密送
62 | body | 内容
63 | isHTML | 内容是否为 HTML
64 | attachments | File 格式附件
65 | result | 0: 取消 1: 保存 2: 成功 3: 失败
--------------------------------------------------------------------------------
/docs/native-modules/motion.md:
--------------------------------------------------------------------------------
1 | # module: "motion"
2 |
3 | `motion` 模块提供了传感器相关的接口。
4 |
5 | # motion.available()
6 |
7 | 检查当前设备是否支持相关的传感器:
8 |
9 | ```js
10 | const motion = require("motion");
11 | if (motion.available()) {
12 |
13 | }
14 | ```
15 |
16 | # motion.startUpdates(object)
17 |
18 | 监听数据变化:
19 |
20 | ```js
21 | const motion = require("motion");
22 | motion.startUpdates({
23 | interval: 2,
24 | handler: resp => {
25 | console.log(resp);
26 | }
27 | })
28 | ```
29 |
30 | 返回的数据请参考 [CMDeviceMotion](https://developer.apple.com/documentation/coremotion/cmdevicemotion)。
31 |
32 | # motion.stopUpdates()
33 |
34 | 停止更新数据:
35 |
36 | ```js
37 | const motion = require("motion");
38 | motion.stopUpdates();
39 | ```
--------------------------------------------------------------------------------
/docs/native-modules/photo.md:
--------------------------------------------------------------------------------
1 | # module: "photo"
2 |
3 | `photo` 模块提供照片相关的接口。
4 |
5 | # photo.take() -> Promise
6 |
7 | 使用系统相机拍摄照片:
8 |
9 | ```js
10 | const photo = require("photo");
11 | photo.take().then(result => {
12 | const buffer = result.data;
13 | const metadata = result.metadata;
14 | });
15 | ```
16 |
17 | 返回 Buffer 类型的数据,以及 JSON 结构的 metadata。
18 |
19 | # photo.pick(object) -> Promise
20 |
21 | 使用系统相册选取照片:
22 |
23 | ```js
24 | const photo = require("photo");
25 | photo.take({
26 | multi: true
27 | }).then(result => {
28 | const buffer = result.data;
29 | const metadata = result.metadata;
30 | });
31 | ```
32 |
33 | `multi` 表示是否需要选择多张照片。
34 |
35 | # photo.scan() -> Promise
36 |
37 | 使用系统内建的文档扫描功能扫描文档:
38 |
39 | ```js
40 | const photo = require("photo");
41 | photo.scan().then(files => {
42 | console.log(files);
43 | });
44 | ```
45 |
46 | 支持同时扫描多张图片,返回的数据是 Buffer 的一个数组。
47 |
48 | # photo.save(File) -> Promise
49 |
50 | 将 File 格式的照片保存到相册:
51 |
52 | ```js
53 | const photo = require("photo");
54 | photo.save(buffer).then(success => {
55 | console.log(success);
56 | });
57 | ```
58 |
59 | # photo.fetch(object) -> Promise
60 |
61 | 读取系统相册:
62 |
63 | ```js
64 | const photo = require("photo");
65 | photo.fetch({
66 | count: 10,
67 | type: 0,
68 | subType: 0
69 | }).then(files => {
70 | console.log(files);
71 | });
72 | ```
73 |
74 | 其中 `type` 和 `subType` 指定了读取的类型,请参考:https://docs.xteko.com/#/data/constant?id=assetmedia
75 |
76 | # photo.delete(object) -> Promise
77 |
78 | 删除系统相册的内容:
79 |
80 | ```js
81 | const photo = require("photo");
82 | photo.delete({
83 | count: 10,
84 | type: 0,
85 | subType: 0
86 | }).then(success => {
87 | console.log(success);
88 | });
89 | ```
90 |
91 | 参数类型与 `photo.fetch(...)` 一致,返回是否成功。
--------------------------------------------------------------------------------
/docs/native-modules/push.md:
--------------------------------------------------------------------------------
1 | # module: "push"
2 |
3 | `push` 模块提供了对本地消息推送的支持。
4 |
5 | # push.schedule(object) -> Promise
6 |
7 | 设定一个本地推送消息:
8 |
9 | ```js
10 | const push = require("push");
11 | push.schedule({
12 | title: "Title",
13 | body: "Body",
14 | delay: 5,
15 | handler: result => {
16 | const id = result.id;
17 | }
18 | });
19 | ```
20 |
21 | 将会在代码执行后 5 秒接收到一个本地推送消息。
22 |
23 | 参数 | 类型 | 说明
24 | ---|---|---
25 | title | string | 标题
26 | body | string | 内容
27 | id | string | 标识符(可选)
28 | sound | string | 声音
29 | mute | bool | 是否静音
30 | repeats | bool | 是否重复
31 | script | string | 脚本名称
32 | height | number | 3D Touch 页面高度
33 | query | json | 额外参数,会被传递到 $context.query
34 | attachments | array | 媒体文件,File 格式
35 | renew | bool | 是否重复创建(固定通知)
36 |
37 | 上述样例代码是通过 delay 来触发一个通知,你也可以通过 date 来触发:
38 |
39 | ```js
40 | const date = new Date();
41 | date.setSeconds(date.getSeconds() + 10);
42 |
43 | const push = require("push");
44 | push.schedule({
45 | title: "Title",
46 | body: "Body",
47 | date,
48 | handler: result => {
49 | const id = result.id;
50 | }
51 | });
52 | ```
53 |
54 | 除此之外,你还能设置一个基于地理位置触发的通知:
55 |
56 | ```js
57 | const push = require("push");
58 | push.schedule({
59 | title: "Title",
60 | body: "Body",
61 | region: {
62 | lat: 0, // latitude
63 | lng: 0, // longitude
64 | radius: 1000, // meters
65 | notifyOnEntry: true, // notify on entry
66 | notifyOnExit: true // notify on exit
67 | }
68 | });
69 | ```
70 |
71 | 该方法调用后会请求用户授权地理位置,若用户拒绝授权则推送不会成功。
72 |
73 | 此外,还支持通过 `script` 字段来设置一个脚本,在用户点击推送之后会执行脚本,也可以通过 3D Touch 来预览。
74 |
75 | # push.cancel(object)
76 |
77 | 取消一个计划内的推送消息:
78 |
79 | ```js
80 | const push = require("push");
81 | push.cancel({
82 | title: "Title",
83 | body: "Body",
84 | });
85 | ```
86 |
87 | 将会取消以 `title` 和 `body` 组成的所有推送消息。
88 |
89 | 当你有多个标题和内容重复的推送时,你可以使用上述代码得到的 id 来取消:
90 |
91 | ```js
92 | const push = require("push");
93 | push.cancel({
94 | id: ""
95 | });
96 | ```
97 |
98 | # push.clear()
99 |
100 | 清除当前脚本所有通知:
101 |
102 | ```js
103 | const push = require("push");
104 | push.clear();
105 | ```
--------------------------------------------------------------------------------
/docs/native-modules/qrcode.md:
--------------------------------------------------------------------------------
1 | # module: "qrcode"
2 |
3 | `qrcode` 模块提供了二维码相关的一些接口。
4 |
5 | # qrcode.encode(string)
6 |
7 | 将字符串编码为二维码图片:
8 |
9 | ```js
10 | const qrcode = require("qrcode");
11 | const buffer = qrcode.encode("Hey");
12 | ```
13 |
14 | # qrcode.decode(File)
15 |
16 | 将 File 格式的二维码文件解码为字符串:
17 |
18 | ```js
19 | const qrcode = require("qrcode");
20 | const text = qrcode.decode(buffer);
21 | ```
22 |
23 | # qrcode.scan(object) -> Promise
24 |
25 | 使用 JSBox 内建的二维码扫描组件扫描二维码:
26 |
27 | ```js
28 | const qrcode = require("qrcode");
29 | qrcode.scan({
30 | useFrontCamera: false,
31 | turnOnFlash: false
32 | }).then(text => {
33 | console.log(text);
34 | });
35 | ```
36 |
37 | useFrontCamera: 是否使用前置摄像头,turnOnFlash: 是否打开闪光灯。
--------------------------------------------------------------------------------
/docs/native-modules/quicklook.md:
--------------------------------------------------------------------------------
1 | # module: "quicklook"
2 |
3 | `quicklook` 模块提供了 iOS 内建的快速预览功能。
4 |
5 | # quicklook.text(string) -> Promise
6 |
7 | 使用预览功能打开一个文本:
8 |
9 | ```js
10 | const quicklook = require("quicklook");
11 | quicklook.text("Hey");
12 | ```
13 |
14 | # quicklook.file(File) -> Promise
15 |
16 | 使用预览功能打开一个文件:
17 |
18 | ```js
19 | const quicklook = require("quicklook");
20 | quicklook.file({
21 | name: "demo.txt",
22 | data: buffer
23 | });
24 | ```
25 |
26 | # quicklook.files([File]) -> Promise
27 |
28 | 使用预览功能打开一组文件:
29 |
30 | ```js
31 | const quicklook = require("quicklook");
32 | quicklook.files([
33 | {
34 | name: "demo.txt",
35 | data: buffer
36 | }
37 | ]);
38 | ```
39 |
40 | 多个文件被打开时,可以左右滑动切换文件。
41 |
42 | # quicklook.json(JSON) -> Promise
43 |
44 | 使用 JSBox 内置的 JSON 查看器预览 JSON:
45 |
46 | ```js
47 | const quicklook = require("quicklook");
48 | quicklook.json({
49 | "Key": "Value"
50 | });
51 | ```
52 |
53 | # quicklook.html(string) -> Promise
54 |
55 | 使用预览功能打开 HTML 格式文本:
56 |
57 | ```js
58 | const quicklook = require("quicklook");
59 | quicklook.html("Hey, there!");
60 | ```
61 |
62 | # quicklook.markdown(string) -> Promise
63 |
64 | 使用预览功能打开 Markdown 格式文本:
65 |
66 | ```js
67 | const quicklook = require("quicklook");
68 | quicklook.markdown("**Bold** text");
69 | ```
--------------------------------------------------------------------------------
/docs/native-modules/reminder.md:
--------------------------------------------------------------------------------
1 | # module: "reminder"
2 |
3 | `reminder` 模块提供了 iOS 系统提醒事项相关的接口。
4 |
5 | # reminder.fetch(object) -> Promise
6 |
7 | 用于读取提醒事项(会提示用户授权):
8 |
9 | ```js
10 | const reminder = require("reminder");
11 | reminder.fetch({
12 | startDate: new Date(),
13 | hours: 2 * 24
14 | }).then(resp => {
15 | const events = resp.events;
16 | });
17 | ```
18 |
19 | 看起来和 `calendar` 极为相似,返回的数据是如下结构:
20 |
21 | 属性 | 类型 | 读写 | 说明
22 | ---|---|---|---
23 | title | string | 读写 | 标题
24 | identifier | string | 只读 | id
25 | location | string | 读写 | 位置
26 | notes | string | 读写 | 备注
27 | url | string | 读写 | 网址
28 | modifiedDate | date | 只读 | 修改时间
29 | creationDate | date | 只读 | 创建时间
30 | completed | boolean | 读写 | 是否完成
31 | completionDate | date | 只读 | 完成时间
32 | alarmDate | date | 读写 | 闹钟时间
33 | priority | number | 读写 | 优先级(1 ~ 9)
34 |
35 | # reminder.create(object) -> Promise
36 |
37 | 用于创建一个提醒事项:
38 |
39 | ```js
40 | const reminder = require("reminder");
41 | reminder.create({
42 | title: "Hey!",
43 | alarmDate: new Date(),
44 | notes: "Hello, World!",
45 | url: "https://apple.com"
46 | }).then(resp => {
47 | console.log(result);
48 | });
49 | ```
50 |
51 | 可以通过 `alarmDate` 和 `alarmDates` 来指定提醒闹钟时间。
52 |
53 | # reminder.save(object) -> Promise
54 |
55 | 和 `calendar.save(...)` 类似,用于修改 event 后保存更新:
56 |
57 | ```js
58 | const reminder = require("reminder");
59 | reminder.save(event);
60 | ```
61 |
62 | # reminder.delete(object) -> Promise
63 |
64 | 删除某个提醒事项:
65 |
66 | ```js
67 | const reminder = require("reminder");
68 | reminder.delete(event).then(result => {
69 | console.log(result);
70 | });
71 | ```
--------------------------------------------------------------------------------
/docs/native-modules/safari.md:
--------------------------------------------------------------------------------
1 | # module: "safari"
2 |
3 | `safari` 模块提供了对 Safari 相关接口的支持。
4 |
5 | # safari.open(object) -> Promise
6 |
7 | 用 Safari View Controller 来打开一个链接:
8 |
9 | ```js
10 | const safari = require("safari");
11 | safari.open("https://apple.com");
12 | ```
13 |
14 | 也可以指定一些参数:
15 |
16 | ```js
17 | const safari = require("safari");
18 | safari.open({
19 | url: "https://apple.com",
20 | entersReader: true
21 | });
22 | ```
23 |
24 | 其中 `entersReader` 表示是否自动进入阅读模式。
25 |
26 | # safari.exec(object)
27 |
28 | 使用 Safari 自带的 WebKit 内核运行 JavaScript:
29 |
30 | ```js
31 | const safari = require("safari");
32 | const result = await safari.exec("const a = 100; return a;");
33 | //=> 100
34 | ```
35 |
36 | 也可以通过 `script` 参数运行,并监听 WebKit 环境的通知:
37 |
38 | ```js
39 | const safari = require("safari");
40 | safari.exec({
41 | script:
42 | `
43 | const a = 100;
44 | const b = 100;
45 | $notify("customEvent", {a, b});
46 | `,
47 | customEvent: result => {
48 | console.log(result);
49 | }
50 | });
51 | ```
52 |
53 | 在 WebKit 环境,可以通过 `$notify(...)` 函数将消息传递回 Node 环境。
54 |
55 | # safari.addReadingItem(object)
56 |
57 | 添加到 Safari 的阅读列表:
58 |
59 | ```js
60 | const safari = require("safari");
61 | safari.addReadingItem({
62 | url: "https://apple.com",
63 | title: "Title",
64 | preview: "Preview text"
65 | });
66 | ```
67 |
68 | 返回值表示是否添加成功。
--------------------------------------------------------------------------------
/docs/native-modules/share.md:
--------------------------------------------------------------------------------
1 | # module: "share"
2 |
3 | `share` 模块提供了对 iOS 内建 share sheet 的支持,可以用来分享文件或图片等。
4 |
5 | # share.text(string) -> Promise
6 |
7 | 使用 share sheet 分享文本:
8 |
9 | ```js
10 | const share = require("share");
11 | share.text("Hey");
12 | ```
13 |
14 | # share.texts([string]) -> Promise
15 |
16 | 使用 share sheet 分享一组文本:
17 |
18 | ```js
19 | const share = require("share");
20 | share.texts(["Hey", "Hey", "Hey"]);
21 | ```
22 |
23 | # share.file(File) -> Promise
24 |
25 | 使用 share sheet 分享 File 格式的文件:
26 |
27 | ```js
28 | const share = require("share");
29 | share.file({
30 | name: "demo.png",
31 | data: buffer
32 | });
33 | ```
34 |
35 | # share.files([File]) -> Promise
36 |
37 | 使用 share sheet 分享一组 File 格式的文件:
38 |
39 | ```js
40 | const share = require("share");
41 | share.files([
42 | {
43 | name: "demo.png",
44 | data: buffer
45 | }
46 | ]);
47 | ```
48 |
49 | # share.url(string) -> Promise
50 |
51 | 使用 share sheet 分享链接:
52 |
53 | ```js
54 | const share = require("share");
55 | share.url("https://apple.com");
56 | ```
--------------------------------------------------------------------------------
/docs/native-modules/speech.md:
--------------------------------------------------------------------------------
1 | # module: "speech"
2 |
3 | `speech` 模块提供了文字转语音相关的接口。
4 |
5 | # speech.voices()
6 |
7 | 返回所有可用的语言列表:
8 |
9 | ```js
10 | const speech = require("speech");
11 | const voices = speech.voices();
12 | ```
13 |
14 | # speech.speak(object)
15 |
16 | 调用文字转语音功能:
17 |
18 | ```js
19 | const speech = require("speech");
20 | speech.speak({
21 | text: "Hello, World!",
22 | rate: 0.5, // 0 ~ 1
23 | pitch: 1.0, // 0 ~ 1,
24 | language: "zh-Hans",
25 | voiceIdentifier: ""
26 | });
27 | ```
28 |
29 | 其中 `voiceIdentifier` 需要使用 `voices` 接口得到,`language` 列表:
30 |
31 | ```
32 | ar-SA
33 | cs-CZ
34 | da-DK
35 | de-DE
36 | el-GR
37 | en-AU
38 | en-GB
39 | en-IE
40 | en-US
41 | en-US
42 | en-ZA
43 | es-ES
44 | es-MX
45 | fi-FI
46 | fr-CA
47 | fr-FR
48 | he-IL
49 | hi-IN
50 | hu-HU
51 | id-ID
52 | it-IT
53 | ja-JP
54 | ko-KR
55 | nl-BE
56 | nl-NL
57 | no-NO
58 | pl-PL
59 | pt-BR
60 | pt-PT
61 | ro-RO
62 | ru-RU
63 | sk-SK
64 | sv-SE
65 | th-TH
66 | tr-TR
67 | zh-CN
68 | zh-HK
69 | zh-TW
70 | ```
--------------------------------------------------------------------------------
/docs/native-modules/system.md:
--------------------------------------------------------------------------------
1 | # module: "system"
2 |
3 | `system` 模块封装了和系统功能相关的一些函数。
4 |
5 | # system.brightness()
6 |
7 | 获取当前设备的亮度:
8 |
9 | ```js
10 | const system = require("system");
11 | const brightness = system.brightness();
12 | ```
13 |
14 | # system.setBrightness(number)
15 |
16 | 设置当前设备的亮度:
17 |
18 | ```js
19 | const system = require("system");
20 |
21 | // 0 ~ 1
22 | system.setBrightness(0.5);
23 | ```
24 |
25 | # system.volume()
26 |
27 | 获取当前设备的音量:
28 |
29 | ```js
30 | const system = require("system");
31 | const volume = system.volume();
32 | ```
33 |
34 | # system.setVolume(number)
35 |
36 | 设置当前设备的音量:
37 |
38 | ```js
39 | const system = require("system");
40 |
41 | // 0 ~ 1
42 | system.setVolume(0.5);
43 | ```
44 |
45 | # system.call(number)
46 |
47 | 拨打电话:
48 |
49 | ```js
50 | const system = require("system");
51 | system.call("18000000000");
52 | ```
53 |
54 | # system.sms(number)
55 |
56 | 发送短信:
57 |
58 | ```js
59 | const system = require("system");
60 | system.sms("18000000000");
61 | ```
62 |
63 | # system.mailto(string)
64 |
65 | 发送邮件:
66 |
67 | ```js
68 | const system = require("system");
69 | system.mailto("log.e@qq.com");
70 | ```
71 |
72 | # system.facetime(string)
73 |
74 | 进行 FaceTime 通话:
75 |
76 | ```js
77 | const system = require("system");
78 | system.facetime("log.e@qq.com");
79 | ```
80 |
81 | # system.home()
82 |
83 | 返回到系统桌面:
84 |
85 | ```js
86 | const system = require("system");
87 | system.home();
88 | ```
--------------------------------------------------------------------------------
/docs/native-modules/ui.md:
--------------------------------------------------------------------------------
1 | # module: "ui"
2 |
3 | `ui` 模块目前提了一些简单的 UI 控件,用于完成简单的用户交互。
4 |
5 | # ui.alert(object)
6 |
7 | 展示弹窗,最简单的调用方式可以是:
8 |
9 | ```js
10 | const ui = require("ui");
11 | ui.alert("Hey");
12 | ```
13 |
14 | 也可以使用其全局的别名:`alert(...)`。
15 |
16 | 需要指定标题和内容时,可以使用 `title` 和 `message` 参数:
17 |
18 | ```js
19 | const ui = require("ui");
20 | ui.alert({
21 | title: "Title",
22 | message: "Message"
23 | });
24 | ```
25 |
26 | 在默认情况下,alert 会展示一个确认按钮,如果需要指定按钮,可以使用 `actions` 参数:
27 |
28 | ```js
29 | const ui = require("ui");
30 | ui.alert({
31 | title: "Title",
32 | message: "Message",
33 | actions: ["Action 1", "Action 2"]
34 | });
35 | ```
36 |
37 | # ui.action(object)
38 |
39 | 参数与 `ui.alert(...)` 完全一样,但展示方式是弹出 action sheet。
40 |
41 | # ui.menu(object) -> Promise
42 |
43 | 弹出一个选项列表以供用于选择:
44 |
45 | ```js
46 | const ui = require("ui");
47 | ui.menu(["A", "B", "C"]).then(option => {
48 | const index = option.index;
49 | const title = option.title;
50 | });
51 | ```
52 |
53 | 也可以指定 `title` 用于提示用户:
54 |
55 | ```js
56 | const ui = require("ui");
57 | ui.menu({
58 | title: "Options",
59 | items: ["A", "B", "C"]
60 | }).then(option => {});
61 | ```
62 |
63 | # ui.toast(string, number)
64 |
65 | 显示一个消息,过一段时间后会自动消失:
66 |
67 | ```js
68 | const ui = require("ui");
69 | ui.toast("Hi", 3.0);
70 | ```
71 |
72 | 时间参数可以缺省,默认情况下是 2 秒。
73 |
74 | # ui.success(string, number)
75 |
76 | 与 `toast` 类似,但背景色为绿色,以表示成功:
77 |
78 | ```js
79 | const ui = require("ui");
80 | ui.success("Done");
81 | ```
82 |
83 | # ui.warning(string, number)
84 |
85 | 与 `toast` 类似,但背景色为黄色,以表示警告:
86 |
87 | ```js
88 | const ui = require("ui");
89 | ui.warning("Be careful!");
90 | ```
91 |
92 | # ui.error(string, number)
93 |
94 | 与 `toast` 类似,但背景色为红色,以表示错误:
95 |
96 | ```js
97 | const ui = require("ui");
98 | ui.error("Something went wrong!");
99 | ```
100 |
101 | # ui.clearToast()
102 |
103 | 清除屏幕上的 toast 消息:
104 |
105 | ```js
106 | const ui = require("ui");
107 | ui.clearToast();
108 | ```
109 |
110 | # ui.showHUD(string)
111 |
112 | 显示一个 HUD 提示文字:
113 |
114 | ```js
115 | const ui = require("ui");
116 | ui.showHUD("Loading...");
117 | ```
118 |
119 | # ui.hideHUD()
120 |
121 | 隐藏屏幕上的 HUD 提示文字:
122 |
123 | ```js
124 | const ui = require("ui");
125 | ui.hideHUD();
126 | ```
127 |
128 | # ui.showProgress(number, string)
129 |
130 | 在屏幕上显示加载进度条(0 ~ 1):
131 |
132 | ```js
133 | const ui = require("ui");
134 | ui.showProgress(0.5, "Loading");
135 | ```
136 |
137 | # ui.hideProgress()
138 |
139 | 取消屏幕上的进度条显示:
140 |
141 | ```js
142 | const ui = require("ui");
143 | ui.hideProgress();
144 | ```
--------------------------------------------------------------------------------
/docs/node-modules/builtin.md:
--------------------------------------------------------------------------------
1 | # 内置 Node 模块
2 |
3 | 你可以自行在 JSBox 内安装 node modules,以供你的脚本使用。为了让开发更方便,我们内置了几个十分常用的 node modules。
4 |
5 | - [async v3.1.0](https://www.npmjs.com/package/async)
6 | - [lodash v4.17.15](https://www.npmjs.com/package/lodash)
7 | - [axios v0.19.0](https://www.npmjs.com/package/axios)
8 | - [cheerio v0.22.0](https://www.npmjs.com/package/cheerio)
9 | - [express v4.17.1](https://www.npmjs.com/package/express)
10 | - [lowdb v1.0.0](https://www.npmjs.com/package/lowdb)
11 |
12 | 对于这些模块,请查询各自提供的官方文档来学习如何使用。
13 |
14 | 我们会尽量让这些内置的 modules 保持更新,但如果某个版本不满足你的需求,你可以在模块内使用别的版本。
--------------------------------------------------------------------------------
/docs/node-modules/deps.md:
--------------------------------------------------------------------------------
1 | # 依赖管理
2 |
3 | JSBox 内置了对 [npm](https://www.npmjs.com/) 仓库的支持,这意味着你可以直接在应用内完成 node modules 的安装。
4 |
5 | 当然,也可以在桌面端完成 node_modules 的配置,并将项目运行到设备上。
6 |
7 | # 安装 Node.js 模块
8 |
9 | - 打开项目目录
10 | - 点击左上角 Node 图标
11 | - 安装 Node.js 模块
12 | - 输入模块名,可以使用 `,` 分割多个模块,可以通过 `@version` 来指定版本号
13 |
14 | # package.json
15 |
16 | 你可以使用项目路径下的 `package.json` 文件来管理依赖,例如:
17 |
18 | ```json
19 | {
20 | "dependencies": {
21 | "uuid": "*",
22 | "lodash": "*"
23 | }
24 | }
25 | ```
--------------------------------------------------------------------------------
/docs/others/changelog.md:
--------------------------------------------------------------------------------
1 | # 2019/12/25
2 |
3 | v1.0.0
--------------------------------------------------------------------------------
/docs/quickstart/examples.md:
--------------------------------------------------------------------------------
1 | # 样例项目
2 |
3 | 为了让大家更好、更快地感受一下用这套系统能做什么,我们提供了一些样例项目。
4 |
5 | 同时,为了不让这些样例代码占用过多的应用空间,我们把这些项目放在了 GitHub 上,将他们 clone 下来之后推送到设备上,按照提示操作即可运行。
6 |
7 | - [GitBox](https://github.com/cyanzhong/GitBox): 基于 [isomorphic-git](https://isomorphic-git.org/) 的 Git 客户端
8 | - [webtorrent-demo](https://github.com/cyanzhong/jsbox-webtorrent-demo): 使用 [webtorrent](https://webtorrent.io/) 下载磁力链接
9 | - [vue-demo](https://github.com/cyanzhong/jsbox-vue-demo): [Vue.js](https://vuejs.org/) 开发环境
10 | - [react-demo](https://github.com/cyanzhong/jsbox-react-demo): [React.js](https://reactjs.org/) 开发环境
11 | - [youtube-dl](https://github.com/cyanzhong/jsbox-youtube-dl): 简单的 YouTube 视频下载工具
12 | - [cheerio](https://github.com/cyanzhong/jsbox-cheerio): 在 JSBox 内使用 [cheerio](https://github.com/cheeriojs/cheerio) 的样例
13 | - [ts-playground](https://github.com/cyanzhong/jsbox-ts-playground): TypeScript 编译成 JavaScript
14 | - [browserify](https://github.com/cyanzhong/jsbox-browserify): 通过 [browserify](http://browserify.org/) 为 JSBox 打包 node modules
15 | - [pdfkit](https://github.com/cyanzhong/jsbox-pdfkit): 通过 [pdfkit](https://pdfkit.org/) 将相册内的照片渲染成 PDF
16 | - [local-web-server](https://github.com/cyanzhong/jsbox-local-web-server): 一个简单的本地网页服务器
17 |
18 | 在之后我们也会上线更多的样例代码,作为了解 JSBox Node.js 运行时的一种方式。
--------------------------------------------------------------------------------
/docs/quickstart/intro.md:
--------------------------------------------------------------------------------
1 | # Node.js 官方文档
2 |
3 | 在阅读本文档之前,请确保您对 [Node.js](https://nodejs.org) 已经有一定的了解,本文档也不会提供 Node.js 官方文档提供的内容。
4 |
5 | 目前 JSBox 的运行时基于 `Node.js v10.13.0`, 相关的文档可以在这里找到:https://nodejs.org/docs/latest-v10.x/api/
6 |
7 | 本文档会着重介绍 JSBox 内置的 Node 环境有哪些差异,以及在移动平台上面使用 Node 时会碰到的问题。
8 |
9 | # 如何在 JSBox 使用 Node.js
10 |
11 | - 可以使用 JSBox 提供的 REPL 运行简单的代码
12 | - 可以在 JSBox 内新建一个 Node.js 模块,运行即可
13 | - 可以使用我们提供的 [VS Code 插件](https://marketplace.visualstudio.com/items?itemName=Ying.jsbox) 来将项目运行到 iOS 设备上
14 |
15 | # 平台差异
16 |
17 | 由于移动平台和 iOS 平台的限制,JSBox 提供的 Node 环境有如下差异:
18 |
19 | - `process.cwd()` 返回的是当前运行模块的根目录
20 | - 执行 `process.exit()` 之后,会退出当前运行的模块
21 | - `process.stdin` 和 `process.stdout` 需要使用 `$jsbox.stdin` 和 `$jsbox.stdout` 来替代
22 | - 无法使用 `child_process` 模块相关的功能,例如 `spawn`
23 | - 由于 intl 的限制,调试功能目前无法使用
24 | - JSBox 目前不具备后台运行的权限,这一个限制也同样作用于 Node.js 运行时
25 | - Node 运行时消耗过多内存,目前 JSBox 仅允许其在主应用运行,目前我们正在改进
--------------------------------------------------------------------------------
/docs/vm/context.md:
--------------------------------------------------------------------------------
1 | # $context
2 |
3 | 我们常常需要传递一些参数给脚本,这些参数可以通过 `$context` 对象获取。
4 |
5 | # $context.query
6 |
7 | 我们通过 URL scheme 方式运行脚本时,或者通过 `$nodejs.run(...)` 运行脚本时,参数可以这样获取:
8 |
9 | ```js
10 | const query = $context.query;
11 | ```
12 |
13 | # $context.text/image/link/safari
14 |
15 | 当我们在 share sheet 运行脚本时,可以通过这些方法来获取传递给脚本的数据:
16 |
17 | ```js
18 | // Get the first text
19 | const text = $context.text;
20 | // Get all text items
21 | const textItems = $context.textItems;
22 | // Get the first image
23 | const image = $context.image;
24 | // Get all image items
25 | const imageItems = $context.imageItems;
26 | // Get the first link
27 | const link = $context.link;
28 | // Get all link items
29 | const linkItems = $context.linkItems;
30 | // Get parameters from Safari sharing
31 | const safariParameters = $context.safari;
32 | // Get all items from share sheet
33 | const allItems = $context.allItems;
34 | ```
35 |
36 | 通过 share sheet 运行 Node 脚本时,将会自动打开应用来运行,你可以通过上述方法获取相应的数据。
--------------------------------------------------------------------------------
/docs/vm/intro.md:
--------------------------------------------------------------------------------
1 | # 通信机制
2 |
3 | 目前 JSBox 提供了两个运行时,分别是 `JSBox 运行时`,和 `Node.js 运行时`,并且提供了让两种运行时互相调用的机制。
4 |
5 | 两个运行时互相调用,可以取长补短,更容易地完成一些需求,比如说:
6 |
7 | - JSBox 脚本可以借助 Node 实现的解决方案
8 | - Node 脚本可以借助 JSBox 强大的 UI 能力
9 | - Node 脚本可以借助 JSBox 调用 Objective-C Runtime
10 |
11 | 这套机制,与在 JSBox 里的 WebView 运行 JavaScript 类似,本质上是消息传递和事件监听。
--------------------------------------------------------------------------------
/docs/vm/jsbox-node.md:
--------------------------------------------------------------------------------
1 | # JSBox 调用 Node
2 |
3 | 与 Node 调用 JSBox 相反的是,有时候你会希望在 JSBox 脚本里面调用 Node。这也是一个常见的需求,例如你希望在 JSBox 里面使用一个 npm 模块。
4 |
5 | # $nodejs.run(object)
6 |
7 | 这是一个与 `$jsbox.run()` 相对应的函数,运行在 JSBox 脚本里面。一样,你可以直接填写 Node 脚本:
8 |
9 | ```js
10 | $nodejs.run(`
11 | const request = require('request');
12 | request('http://www.google.com', function (error, response, body) {
13 | console.error('error:', error); // Print the error if one occurred
14 | console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
15 | console.log('body:', body); // Print the HTML for the Google homepage.
16 | });
17 | `
18 | );
19 | ```
20 |
21 | 你可以点击项目管理器左上角的调试图标,来安装对应的 Node 模块,例如这个例子里面的 `request` 模块。
22 |
23 | 同样的,JSBox 调用 Node 也支持指定更详细的参数:
24 |
25 | ```js
26 | $nodejs.run({
27 | name: "MyNodeModule",
28 | // script: "",
29 | // path: "",
30 | query: {
31 | k1: "v1",
32 | k2: "v2"
33 | },
34 | // argv: [],
35 | listener: {
36 | id: "eventId",
37 | handler: result => {
38 | console.log("Message from Node: ", result);
39 | }
40 | }
41 | });
42 | ```
43 |
44 | 可以通过 `name`, `script` 或 `path` 来指定需要运行的 Node 脚本,并且监听消息的方式和 `$jsbox.run` 也完全一样。
45 |
46 | 通过 `query` 传递的参数,在 Node 脚本里面可以这样获取:
47 |
48 | ```js
49 | const query = $context.query;
50 | ```
51 |
52 | 也可以通过 `argv` 参数将参数传递给 Node 的 `process.argv` 变量。
53 |
54 | 为了获取 Node 脚本的消息,可以通过 `listener` 来监听,该 Node 脚本可以通过 `id` 来将消息派发到 `handler` 函数:
55 |
56 | ```js
57 | $jsbox.notify("eventId", {
58 | k1: "v1",
59 | k2: "v2"
60 | });
61 | ```
62 |
63 | 这个时候 JSBox 程序中的 handler 会被调用,并打印出从 Node 获得的结果。可以看出,`$nodejs.run/notify` 和 `$jsbox.run/notify` 是两两对应的,共同完成两个环境的互相调用。
64 |
65 | # $nodejs.listen(string, Function)
66 |
67 | 监听来自 Node.js 环境的消息:
68 |
69 | ```js
70 | $nodejs.listen("eventId", () => {
71 |
72 | });
73 | ```
74 |
75 | 同样的,Node.js 环境可以通过 `$jsbox.notify(...)` 将消息传递给上述监听者。
76 |
77 | # $nodejs.version
78 |
79 | 获取当前 Node.js 的版本。
80 |
81 | # $nodejs.path
82 |
83 | 获取当前 Node.js 相关的路径。
--------------------------------------------------------------------------------
/docs/vm/node-jsbox.md:
--------------------------------------------------------------------------------
1 | # Node 调用 JSBox
2 |
3 | 正如我们之前提到的那样,目前 Node 运行时并没有提供像 JSBox 运行时那样丰富的 Native 接口,所以当你想实现一个和 iOS 原生有关的功能却发现没有相关的 Node 模块,你可以调用 JSBox。
4 |
5 | # $jsbox.run(object)
6 |
7 | 可以通过下面的方式来简单的运行一个 JSBox 脚本:
8 |
9 | ```js
10 | $jsbox.run(`
11 | $ui.render({
12 | views: [
13 | {
14 | type: "label",
15 | props: {
16 | text: "Hey"
17 | },
18 | layout: (make, view) => {
19 | make.center.equalTo(view.super);
20 | }
21 | }
22 | ]
23 | });`
24 | );
25 | ```
26 |
27 | 也就是说,传入一个字符串时,该字符串被当做 JSBox 脚本直接运行。
28 |
29 | 也可以对运行方式进行更详细的指定:
30 |
31 | ```js
32 | $jsbox.run({
33 | name: "MyApp",
34 | // script: "",
35 | query: {
36 | k1: "v1",
37 | k2: "v2"
38 | },
39 | listener: {
40 | id: "eventId",
41 | handler: result => {
42 | console.log("Message from JSBox: ", result);
43 | }
44 | }
45 | });
46 | ```
47 |
48 | 可以通过 `name` 指定 JSBox 脚本名,或者 `script` 指定直接运行的脚本内容。并且可以通过 `query` 传递参数给要运行的脚本,该 JSBox 脚本可以这样拿到参数:
49 |
50 | ```js
51 | const query = $context.query;
52 | ```
53 |
54 | 为了获取 JSBox 脚本的消息,可以通过 `listener` 来监听,该 JSBox 脚本可以通过 `id` 来将消息派发到 `handler` 函数:
55 |
56 | ```js
57 | $nodejs.notify("eventId", {
58 | k1: "v1",
59 | k2: "v2"
60 | });
61 | ```
62 |
63 | 这个时候 Node 程序中的 handler 会被调用,并打印出从 JSBox 获得的结果。
64 |
65 | # $jsbox.listen(string, Function)
66 |
67 | 监听来自 JSBox 环境的消息:
68 |
69 | ```js
70 | $jsbox.listen("eventId", () => {
71 |
72 | });
73 | ```
74 |
75 | 同样的,JSBox 环境可以通过 `$nodejs.notify(...)` 将消息传递给上述监听者。
76 |
77 | # $jsbox.version
78 |
79 | 获取当前 JSBox 的版本。
80 |
81 | # $jsbox.path
82 |
83 | 获取当前 JSBox 相关的路径。
--------------------------------------------------------------------------------
/docs/vm/objc.md:
--------------------------------------------------------------------------------
1 | # Node 调用 Objective-C
2 |
3 | 这一节实际上不是新内容,只是一个提醒。有些时候,即便是调用 JSBox 可能也不能实现对应的效果,因为 JSBox 也不可能提供 iOS 原生的全部接口。
4 |
5 | 但 JSBox 运行时提供了 Runtime 机制,用于调用 Objective-C,具体的文档可以在这里找到:https://docs.xteko.com/#/runtime/intro
6 |
7 | 这里给出一个简单的样例:
8 |
9 | ```js
10 | $jsbox.run(`
11 | const url = $objc("NSURL").$URLWithString("https://google.com");
12 | $objc("UIApplication").$sharedApplication().$openURL(url);`
13 | );
14 | ```
15 |
16 | 这会通过 Objective-C 的方式来打开一个网页。当然,我们不提倡在任何时候都使用这些技巧,但这些技巧在适合的时候能够成为一种解决方案。
--------------------------------------------------------------------------------