@breakside/jskit 2023.20.0 → 2023.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/Frameworks/DOM.jsframework/Info.json +2 -2
  2. package/Frameworks/DOM.jsframework/io.breakside.JSKit.DOM-bundle.js +2 -2
  3. package/Frameworks/FontKit.jsframework/Info.json +2 -2
  4. package/Frameworks/FontKit.jsframework/io.breakside.JSKit.FontKit-bundle.js +2 -2
  5. package/Frameworks/Foundation.jsframework/Info.json +2 -2
  6. package/Frameworks/Foundation.jsframework/JS/JSURLResponse.js +1 -1
  7. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  8. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  9. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+HTML.js +31 -44
  10. package/Frameworks/SecurityKit.jsframework/JS/SECCipher+Node.js +16 -38
  11. package/Frameworks/SecurityKit.jsframework/JS/SECCipher.js +33 -3
  12. package/Frameworks/SecurityKit.jsframework/JS/SECHMAC.js +17 -0
  13. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  14. package/Info.json +2 -2
  15. package/Node/HTMLBuilder.js +76 -20
  16. package/Node/io.breakside.jskit-bundle.js +2 -2
  17. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  18. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  19. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  20. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  21. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  22. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  23. package/Root/Frameworks/DBKit/Info.yaml +1 -1
  24. package/Root/Frameworks/DOM/Info.yaml +1 -1
  25. package/Root/Frameworks/Dispatch/Info.yaml +1 -1
  26. package/Root/Frameworks/FontKit/Info.yaml +1 -1
  27. package/Root/Frameworks/Foundation/Info.yaml +1 -1
  28. package/Root/Frameworks/Foundation/JSURLResponse.js +1 -1
  29. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  30. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  31. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  32. package/Root/Frameworks/NotificationKit/Info.yaml +2 -1
  33. package/Root/Frameworks/NotificationKit/NKHTMLUserNotificationCenter.js +59 -18
  34. package/Root/Frameworks/NotificationKit/NKUserNotification.js +12 -1
  35. package/Root/Frameworks/NotificationKit/NKUserNotificationCenter.js +5 -0
  36. package/Root/Frameworks/NotificationKit/NKWebPushService.js +145 -38
  37. package/Root/Frameworks/NotificationKit/NotificationKit+Node.js +19 -0
  38. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  39. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  40. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  41. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  42. package/Root/Frameworks/SecurityKit/SECCipher+HTML.js +31 -44
  43. package/Root/Frameworks/SecurityKit/SECCipher+Node.js +16 -38
  44. package/Root/Frameworks/SecurityKit/SECCipher.js +33 -3
  45. package/Root/Frameworks/SecurityKit/SECHMAC.js +17 -0
  46. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  47. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  48. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  49. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  50. package/Root/Frameworks/UIKit/UIHTMLContentEditableTextInputManager.js +1 -1
  51. package/Root/Frameworks/UIKit/UIHTMLWindowServer.js +8 -1
  52. package/Root/Frameworks/UIKit/UIWindowServer.js +7 -13
  53. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  54. package/Root/Templates/html/${PROJECT_NAME}/www/${PROJECT_NAME}.webmanifest +9 -0
  55. package/Root/Templates/html/${PROJECT_NAME}/www/HTMLAppBootstrapper.js +7 -1
  56. package/Root/Templates/html/${PROJECT_NAME}/www/index.html +1 -0
  57. package/Root/Templates/html/${PROJECT_NAME}/www/service-worker.js +25 -1
  58. package/package.json +1 -1
@@ -195,14 +195,6 @@ SECCipherAESCounter.definePropertiesFromExtensions({
195
195
  counter: JSData.initWithLength(16),
196
196
  length: 64
197
197
  };
198
- this.decryptedMessageId =
199
- (nonce[6] << 48)
200
- | (nonce[5] << 40)
201
- | (nonce[4] << 32)
202
- | (nonce[3] << 24)
203
- | (nonce[2] << 16)
204
- | (nonce[1] << 8)
205
- | (nonce[0]);
206
198
  nonce.copyTo(algorithm.counter, 0);
207
199
  return algorithm;
208
200
  },
@@ -282,55 +274,41 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
282
274
 
283
275
  htmlAlgorithmName: HTMLCryptoAlgorithmNames.aesGCM,
284
276
 
285
- _getHTMLEncryptAlgorithm: function(){
286
- var nonce = JSData.initWithArray([
287
- 1,
288
- ((this.encryptedMessageId / 0x100000000) >> 16) & 0xFF,
289
- ((this.encryptedMessageId / 0x100000000) >> 8) & 0xFF,
290
- (this.encryptedMessageId / 0x100000000) & 0xFF,
291
- (this.encryptedMessageId >> 24) & 0xFF,
292
- (this.encryptedMessageId >> 16) & 0xFF,
293
- (this.encryptedMessageId >> 8) & 0xFF,
294
- this.encryptedMessageId & 0xF
295
- ]);
277
+ _getHTMLEncryptAlgorithm: function(nonce, _ivLength){
278
+ if (_ivLength === undefined){
279
+ _ivLength = nonce.length;
280
+ }
296
281
  var algorithm = {
297
282
  name: HTMLCryptoAlgorithmNames.aesGCM,
298
- iv: JSData.initWithLength(16),
283
+ iv: JSData.initWithLength(_ivLength),
299
284
  tagLength: 128
300
285
  };
301
286
  nonce.copyTo(algorithm.iv, 0);
302
287
  return algorithm;
303
288
  },
304
289
 
305
- _getHTMLDecryptAlgorithm: function(prefixedData){
306
- var nonce = prefixedData.subdataInRange(JSRange(0, 8));
290
+ _getHTMLDecryptAlgorithm: function(prefixedData, nonceLength, _ivLength){
291
+ if (nonceLength === undefined){
292
+ nonceLength = 8;
293
+ }
294
+ if (_ivLength === undefined){
295
+ _ivLength = nonceLength;
296
+ }
297
+ var nonce = prefixedData.subdataInRange(JSRange(0, nonceLength));
307
298
  var algorithm = {
308
299
  name: HTMLCryptoAlgorithmNames.aesGCM,
309
- iv: JSData.initWithLength(16),
300
+ iv: JSData.initWithLength(_ivLength),
310
301
  tagLength: 128
311
302
  };
312
- this.decryptedMessageId =
313
- (nonce[6] << 48)
314
- | (nonce[5] << 40)
315
- | (nonce[4] << 32)
316
- | (nonce[3] << 24)
317
- | (nonce[2] << 16)
318
- | (nonce[1] << 8)
319
- | (nonce[0]);
320
303
  nonce.copyTo(algorithm.iv, 0);
321
304
  return algorithm;
322
305
  },
323
306
 
324
- encrypt: function(data, key, completion, target){
307
+ encryptWithNonce: function(nonce, data, key, completion, target, _ivLength){
325
308
  if (!completion){
326
309
  completion = Promise.completion(Promise.resolveNonNull);
327
310
  }
328
- if (!this.ensureUniqueMessageID()){
329
- JSRunLoop.main.schedule(completion, target, null);
330
- return completion.promise;
331
- }
332
- var algorithm = this._getHTMLEncryptAlgorithm();
333
- var nonce = algorithm.iv.truncatedToLength(8);
311
+ var algorithm = this._getHTMLEncryptAlgorithm(nonce, _ivLength);
334
312
  crypto.subtle.encrypt(algorithm, key.htmlKey, data).then(function(encrypted){
335
313
  var noncePrefixed = JSData.initWithChunks([nonce, JSData.initWithBuffer(encrypted)]);
336
314
  completion.call(target, noncePrefixed);
@@ -340,12 +318,12 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
340
318
  return completion.promise;
341
319
  },
342
320
 
343
- decrypt: function(data, key, completion, target){
321
+ decryptWithNonceLength: function(nonceLength, data, key, completion, target, _ivLength){
344
322
  if (!completion){
345
323
  completion = Promise.completion(Promise.resolveNonNull);
346
324
  }
347
- var algorithm = this._getHTMLDecryptAlgorithm(data);
348
- var encrypted = data.subdataInRange(JSRange(8, data.length - 8));
325
+ var algorithm = this._getHTMLDecryptAlgorithm(data, nonceLength, _ivLength);
326
+ var encrypted = data.subdataInRange(JSRange(nonceLength, data.length - nonceLength));
349
327
  crypto.subtle.decrypt(algorithm, key.htmlKey, encrypted).then(function(decrypted){
350
328
  var decryptedData = JSData.initWithBuffer(decrypted);
351
329
  completion.call(target, decryptedData);
@@ -363,8 +341,17 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
363
341
  JSRunLoop.main.schedule(completion, target, null);
364
342
  return completion.promise;
365
343
  }
366
- var algorithm = this._getHTMLEncryptAlgorithm();
367
- var nonce = algorithm.iv.truncatedToLength(8);
344
+ var nonce = JSData.initWithArray([
345
+ 1,
346
+ ((this.encryptedMessageId / 0x100000000) >> 16) & 0xFF,
347
+ ((this.encryptedMessageId / 0x100000000) >> 8) & 0xFF,
348
+ (this.encryptedMessageId / 0x100000000) & 0xFF,
349
+ (this.encryptedMessageId >> 24) & 0xFF,
350
+ (this.encryptedMessageId >> 16) & 0xFF,
351
+ (this.encryptedMessageId >> 8) & 0xFF,
352
+ this.encryptedMessageId & 0xF
353
+ ]);
354
+ var algorithm = this._getHTMLEncryptAlgorithm(nonce, 16);
368
355
  crypto.subtle.wrapKey("raw", key.htmlKey, wrappingKey.htmlKey, algorithm).then(function(bytes){
369
356
  var noncePrefixed = JSData.initWithChunks([nonce, JSData.initWithBuffer(bytes)]);
370
357
  completion.call(target, noncePrefixed);
@@ -378,7 +365,7 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
378
365
  if (!completion){
379
366
  completion = Promise.completion(Promise.resolveNonNull);
380
367
  }
381
- var algorithm = this._getHTMLDecryptAlgorithm(wrappedKeyData);
368
+ var algorithm = this._getHTMLDecryptAlgorithm(wrappedKeyData, 8, 16);
382
369
  var unwrappedKeyHTMLAlgorithm = HTMLCryptoAlgorithmNames.fromAlgorithm(unwrappedKeyAlgorithm);
383
370
  wrappedKeyData = wrappedKeyData.subdataInRange(JSRange(8, wrappedKeyData.length - 8));
384
371
  crypto.subtle.unwrapKey("raw", wrappedKeyData, wrappingKey.htmlKey, algorithm, unwrappedKeyHTMLAlgorithm, true, ["encrypt", "decrypt"]).then(function(key){
@@ -182,14 +182,6 @@ SECCipherAESCounter.definePropertiesFromExtensions({
182
182
  return completion.promise;
183
183
  }
184
184
  var nonce = data.subdataInRange(JSRange(0, 8));
185
- this.decryptedMessageId =
186
- (nonce[6] << 48)
187
- | (nonce[5] << 40)
188
- | (nonce[4] << 32)
189
- | (nonce[3] << 24)
190
- | (nonce[2] << 16)
191
- | (nonce[1] << 8)
192
- | (nonce[0]);
193
185
  var iv = JSData.initWithLength(16);
194
186
  nonce.copyTo(iv, 0);
195
187
  var cipher = crypto.createDecipheriv(name, key.keyData, iv);
@@ -217,41 +209,31 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
217
209
  return null;
218
210
  },
219
211
 
220
- encrypt: function(data, key, completion, target){
212
+ encryptWithNonce: function(nonce, data, key, completion, target, _ivLength){
221
213
  if (!completion){
222
214
  completion = Promise.completion(Promise.resolveNonNull);
223
215
  }
224
- if (!this.ensureUniqueMessageID()){
225
- JSRunLoop.main.schedule(completion, target, null);
226
- return completion.promise;
227
- }
228
216
  var name = this._cipherNameForKey(key);
229
217
  if (name === null){
230
218
  JSRunLoop.main.schedule(completion, target, null);
231
219
  return completion.promise;
232
220
  }
233
- var nonce = JSData.initWithArray([
234
- 1,
235
- ((this.encryptedMessageId / 0x100000000) >> 16) & 0xFF,
236
- ((this.encryptedMessageId / 0x100000000) >> 8) & 0xFF,
237
- (this.encryptedMessageId / 0x100000000) & 0xFF,
238
- (this.encryptedMessageId >> 24) & 0xFF,
239
- (this.encryptedMessageId >> 16) & 0xFF,
240
- (this.encryptedMessageId >> 8) & 0xFF,
241
- this.encryptedMessageId & 0xF
242
- ]);
243
- var iv = JSData.initWithLength(16);
221
+ if (_ivLength === undefined){
222
+ _ivLength = nonce.length;
223
+ }
224
+ var iv = JSData.initWithLength(_ivLength);
244
225
  nonce.copyTo(iv, 0);
245
226
  var cipher = crypto.createCipheriv(name, key.keyData, iv);
246
227
  var chunks = [nonce, cipher.update(data), cipher.final()];
247
- var tag = JSData.initWithLength(16);
228
+ var tagLength = 16;
229
+ var tag = JSData.initWithLength(tagLength);
248
230
  cipher.getAuthTag().copyTo(tag, 0);
249
231
  chunks.push(tag);
250
232
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
251
233
  return completion.promise;
252
234
  },
253
235
 
254
- decrypt: function(data, key, completion, target){
236
+ decryptWithNonceLength: function(nonceLength, data, key, completion, target, _ivLength){
255
237
  if (!completion){
256
238
  completion = Promise.completion(Promise.resolveNonNull);
257
239
  }
@@ -261,21 +243,17 @@ SECCipherAESGaloisCounterMode.definePropertiesFromExtensions({
261
243
  JSRunLoop.main.schedule(completion, target, null);
262
244
  return completion.promise;
263
245
  }
264
- var nonce = data.subdataInRange(JSRange(0, 8));
265
- this.decryptedMessageId =
266
- (nonce[6] << 48)
267
- | (nonce[5] << 40)
268
- | (nonce[4] << 32)
269
- | (nonce[3] << 24)
270
- | (nonce[2] << 16)
271
- | (nonce[1] << 8)
272
- | (nonce[0]);
273
- var iv = JSData.initWithLength(16);
246
+ var nonce = data.subdataInRange(JSRange(0, nonceLength));
247
+ if (_ivLength === undefined){
248
+ _ivLength = nonceLength;
249
+ }
250
+ var iv = JSData.initWithLength(_ivLength);
274
251
  nonce.copyTo(iv, 0);
275
252
  var cipher = crypto.createDecipheriv(name, key.keyData, iv);
276
- var tag = data.subdataInRange(JSRange(data.length - 16, 16));
253
+ var tagLength = 16;
254
+ var tag = data.subdataInRange(JSRange(data.length - tagLength, tagLength));
277
255
  cipher.setAuthTag(tag);
278
- var chunks = [cipher.update(data.subdataInRange(JSRange(8, data.length - 8 - 16))), cipher.final()];
256
+ var chunks = [cipher.update(data.subdataInRange(JSRange(nonceLength, data.length - nonceLength - tagLength))), cipher.final()];
279
257
  JSRunLoop.main.schedule(completion, target, JSData.initWithChunks(chunks));
280
258
  }catch(e){
281
259
  JSRunLoop.main.schedule(completion, target, null);
@@ -190,7 +190,6 @@ JSClass("SECCipherAESCipherBlockChaining", SECCipher, {
190
190
  JSClass("SECCipherAESCounter", SECCipher, {
191
191
 
192
192
  encryptedMessageId: 0,
193
- decryptedMessageId: 0,
194
193
 
195
194
  ensureUniqueMessageID: function(){
196
195
  if (this.encryptedMessageId == 9007199254740991){
@@ -205,7 +204,6 @@ JSClass("SECCipherAESCounter", SECCipher, {
205
204
  JSClass("SECCipherAESGaloisCounterMode", SECCipher, {
206
205
 
207
206
  encryptedMessageId: 0,
208
- decryptedMessageId: 0,
209
207
 
210
208
  ensureUniqueMessageID: function(){
211
209
  if (this.encryptedMessageId == 9007199254740991){
@@ -213,7 +211,39 @@ JSClass("SECCipherAESGaloisCounterMode", SECCipher, {
213
211
  }
214
212
  ++this.encryptedMessageId;
215
213
  return true;
216
- }
214
+ },
215
+
216
+ encrypt: function(data, key, completion, target){
217
+ if (!completion){
218
+ completion = Promise.completion(Promise.resolveNonNull);
219
+ }
220
+ if (!this.ensureUniqueMessageID()){
221
+ JSRunLoop.main.schedule(completion, target, null);
222
+ return completion.promise;
223
+ }
224
+ var nonce = JSData.initWithArray([
225
+ 1,
226
+ ((this.encryptedMessageId / 0x100000000) >> 16) & 0xFF,
227
+ ((this.encryptedMessageId / 0x100000000) >> 8) & 0xFF,
228
+ (this.encryptedMessageId / 0x100000000) & 0xFF,
229
+ (this.encryptedMessageId >> 24) & 0xFF,
230
+ (this.encryptedMessageId >> 16) & 0xFF,
231
+ (this.encryptedMessageId >> 8) & 0xFF,
232
+ this.encryptedMessageId & 0xF
233
+ ]);
234
+ this.encryptWithNonce(nonce, data, key, completion, target, 16);
235
+ return completion.promise;
236
+ },
237
+
238
+ decrypt: function(data, key, completion, target){
239
+ return this.decryptWithNonceLength(8, data, key, completion, target, 16);
240
+ },
241
+
242
+ encryptWithNonce: function(nonce, data, key, completion, target){
243
+ },
244
+
245
+ decryptWithNonceLength: function(nonceLength, data, key, completion, target){
246
+ },
217
247
 
218
248
  });
219
249
 
@@ -64,4 +64,21 @@ SECHMAC.Algorithm = {
64
64
  sha256: "sha256",
65
65
  sha384: "sha384",
66
66
  sha512: "sha512"
67
+ };
68
+
69
+ SECHMAC.digest = function(algorithm, keyData, data, completion, target){
70
+ if (!completion){
71
+ completion = Promise.completion(Promise.resolveNonNull);
72
+ }
73
+ var hmac = SECHMAC.initWithAlgorithm(algorithm);
74
+ hmac.createKeyWithData(keyData, function(key){
75
+ if (key === null){
76
+ completion.call(target, null);
77
+ return;
78
+ }
79
+ hmac.key = key;
80
+ hmac.update(data);
81
+ hmac.sign(completion, target);
82
+ });
83
+ return completion.promise;
67
84
  };
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKit
3
- JSBundleVersion: 2023.20.0
3
+ JSBundleVersion: 2023.21.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.ServerKitTesting
3
- JSBundleVersion: 2023.20.0
3
+ JSBundleVersion: 2023.21.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.TestKit
3
- JSBundleVersion: 2023.20.0
3
+ JSBundleVersion: 2023.21.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKit
3
- JSBundleVersion: 2023.20.0
3
+ JSBundleVersion: 2023.21.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -57,8 +57,8 @@ JSClass('UIHTMLContentEditableTextInputManager', UITextInputManager, {
57
57
  this.textInputLayer = null;
58
58
  this.layoutManager = null;
59
59
  }else{
60
- this.textInputLayer = this.textInputClient.textInputLayer ? this.textInputClient.textInputLayer() : null;
61
60
  this.layoutManager = this.textInputClient.textInputLayoutManager ? this.textInputClient.textInputLayoutManager() : null;
61
+ this.textInputLayer = this.textInputClient.textInputLayer ? this.textInputClient.textInputLayer() : null;
62
62
  }
63
63
  },
64
64
 
@@ -401,6 +401,13 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
401
401
  preventDefault = false;
402
402
  }
403
403
  break;
404
+ case 81: // q
405
+ if (modifiers === UIPlatform.shared.commandModifier){
406
+ // We want to let the quit shortcut go through, so it can be
407
+ // handled by the system.
408
+ preventDefault = false;
409
+ }
410
+ break;
404
411
  case 88: // x
405
412
  if (modifiers === UIPlatform.shared.commandModifier){
406
413
  // We want to let the cut keyboard shortcut go through, so it can be
@@ -957,7 +964,7 @@ JSClass("UIHTMLWindowServer", UIWindowServer, {
957
964
  layoutWindow: function(window){
958
965
  UIHTMLWindowServer.$super.layoutWindow.call(this, window);
959
966
  if (window instanceof UIRootWindow){
960
- window.contentInsets = this.safeAreaInsets();
967
+ window.contentInsets = window.contentInsets.insetsWithInsets(this.safeAreaInsets());
961
968
  }
962
969
  },
963
970
 
@@ -165,9 +165,6 @@ JSClass("UIWindowServer", JSObject, {
165
165
  if (this._normalLevelRange.location === 0 && window.level === UIWindow.Level.normal){
166
166
  window.level = UIWindow.Level.back;
167
167
  }
168
- if (this._normalLevelRange.location === 0 && window.level == UIWindow.Level.back){
169
- this.updateRootWindowInsets(window);
170
- }
171
168
  this._beginWindowOrderChange();
172
169
  this._windowsById[window.objectID] = window;
173
170
  switch (window.level){
@@ -278,8 +275,13 @@ JSClass("UIWindowServer", JSObject, {
278
275
  },
279
276
 
280
277
  layoutWindow: function(window){
281
- if (window.level === UIWindow.Level.back){
278
+ if (window instanceof UIRootWindow){
282
279
  window.frame = window._screen.frame;
280
+ var insets = JSInsets.Zero;
281
+ if (this._menuBar !== null && this._menuBar.isOpaque){
282
+ insets.top = this._menuBar.frame.size.height;
283
+ }
284
+ window.contentInsets = insets;
283
285
  }else{
284
286
  // TODO: make sure nothing has moved off screen
285
287
  }
@@ -293,14 +295,6 @@ JSClass("UIWindowServer", JSObject, {
293
295
  this.screen.availableInsets = insets;
294
296
  },
295
297
 
296
- updateRootWindowInsets: function(rootWindow){
297
- var insets = JSInsets.Zero;
298
- if (this._menuBar !== null && this._menuBar.isOpaque){
299
- insets.top = this._menuBar.frame.size.height;
300
- rootWindow.contentInsets = insets;
301
- }
302
- },
303
-
304
298
  // -----------------------------------------------------------------------
305
299
  // MARK: - Text Input Coordination
306
300
 
@@ -346,7 +340,7 @@ JSClass("UIWindowServer", JSObject, {
346
340
  }
347
341
  this.updateScreenAvailableInsets();
348
342
  if (this.windowStack.length > 0 && this._normalLevelRange.location > 0){
349
- this.updateRootWindowInsets(this.windowStack[0]);
343
+ this.layoutWindow(this.windowStack[0]);
350
344
  }
351
345
  },
352
346
 
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.UIKitTesting
3
- JSBundleVersion: 2023.20.0
3
+ JSBundleVersion: 2023.21.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSLicenseNotice: |
@@ -0,0 +1,9 @@
1
+ {
2
+ "lang": "en",
3
+ "name": "${PROJECT_NAME}",
4
+ "short_name": "${PROJECT_NAME}",
5
+ "scope": "/",
6
+ "start_url": "/",
7
+ "display": "standalone",
8
+ "shortcuts": []
9
+ }
@@ -222,6 +222,8 @@ HTMLAppBootstrapper.prototype = {
222
222
  this.setStatus(HTMLAppBootstrapper.STATUS.appCrashed);
223
223
  },
224
224
 
225
+ scriptContainerElement: null,
226
+
225
227
  include: function(src, async, callback, errorCallback){
226
228
  try{
227
229
  this.loadingScripts[src] = {
@@ -244,7 +246,11 @@ HTMLAppBootstrapper.prototype = {
244
246
  errorCallback(new Error("Include of '" + src + "' failed"));
245
247
  });
246
248
  script.src = src;
247
- this.rootElement.ownerDocument.body.appendChild(script);
249
+ if (this.scriptContainerElement === null){
250
+ this.scriptContainerElement = this.rootElement.appendChild(this.rootElement.ownerDocument.createElement("div"));
251
+ this.scriptContainerElement.style.display = "none";
252
+ }
253
+ this.scriptContainerElement.appendChild(script);
248
254
  }catch (e){
249
255
  errorCallback(e);
250
256
  }
@@ -2,6 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset="utf-8">
5
+ <link rel="manifest" href="${PROJECT_NAME}.webmanifest">
5
6
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, viewport-fit=cover">
6
7
  <meta name="theme-color" media="(prefers-color-scheme: light)" content="white">
7
8
  <meta name="theme-color" media="(prefers-color-scheme: dark)" content="rgb(38,38,38)">
@@ -166,4 +166,28 @@ self.addEventListener('message', function(event){
166
166
  console.log('Client message to activate ' + cacheKey);
167
167
  self.skipWaiting();
168
168
  }
169
- });
169
+ });
170
+
171
+ // Push notification handling example:
172
+ //
173
+ // self.addEventListener('push', function(event){
174
+ // let message = event.data.json();
175
+ // console.log("received push message", message);
176
+ // if (message.type === "notification"){
177
+ // if (!self.Notification){
178
+ // console.warn("notifications not available");
179
+ // }
180
+ // if (self.Notification.permission !== "granted"){
181
+ // console.warn("notifications permission not granted");
182
+ // }
183
+ // var options = {
184
+ // };
185
+ // if (message.identifier){
186
+ // options.tag = message.identifier;
187
+ // }
188
+ // if (message.body !== null && message.body !== undefined){
189
+ // options.body = message.body;
190
+ // }
191
+ // self.registration.showNotification(message.title, options);
192
+ // }
193
+ // });
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "node": ">=10.10.0"
10
10
  },
11
11
  "name": "@breakside/jskit",
12
- "version": "2023.20.0",
12
+ "version": "2023.21.0",
13
13
  "license": "SEE LICENSE IN LICENSE.txt",
14
14
  "files": [
15
15
  "*"