@breakside/jskit 2021.52.0 → 2022.6.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 (79) 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/JSColor.js +9 -0
  7. package/Frameworks/Foundation.jsframework/JS/JSColorSpace.js +106 -20
  8. package/Frameworks/Foundation.jsframework/JS/JSMediaType.js +1 -1
  9. package/Frameworks/Foundation.jsframework/io.breakside.JSKit.Foundation-bundle.js +2 -2
  10. package/Frameworks/SecurityKit.jsframework/Info.json +2 -2
  11. package/Frameworks/SecurityKit.jsframework/io.breakside.JSKit.SecurityKit-bundle.js +2 -2
  12. package/Info.json +2 -2
  13. package/Node/io.breakside.jskit-bundle.js +2 -2
  14. package/Root/Frameworks/APIKit/APIRequest.js +99 -0
  15. package/Root/Frameworks/APIKit/Info.yaml +1 -1
  16. package/Root/Frameworks/APIKitTesting/Info.yaml +1 -1
  17. package/Root/Frameworks/AuthKit/Info.yaml +1 -1
  18. package/Root/Frameworks/CSSOM/Info.yaml +1 -1
  19. package/Root/Frameworks/ChartKit/Info.yaml +1 -1
  20. package/Root/Frameworks/ConferenceKit/Info.yaml +1 -1
  21. package/Root/Frameworks/DBKit/DBMongoStore.js +1 -0
  22. package/Root/Frameworks/DBKit/DBRedisStore.js +136 -117
  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/JSColor.js +9 -0
  29. package/Root/Frameworks/Foundation/JSColorSpace.js +106 -20
  30. package/Root/Frameworks/Foundation/JSMediaType.js +1 -1
  31. package/Root/Frameworks/ImageKit/IKColorProfile.js +1091 -0
  32. package/Root/Frameworks/ImageKit/IKColorSpace.js +49 -198
  33. package/Root/Frameworks/ImageKit/IKMatrix.js +124 -0
  34. package/Root/Frameworks/ImageKit/ImageKit.js +2 -0
  35. package/Root/Frameworks/ImageKit/Info.yaml +1 -1
  36. package/Root/Frameworks/MediaKit/Info.yaml +1 -1
  37. package/Root/Frameworks/MediaKitUI/Info.yaml +1 -1
  38. package/Root/Frameworks/NotificationKit/Info.yaml +1 -1
  39. package/Root/Frameworks/PDFKit/Info.yaml +1 -1
  40. package/Root/Frameworks/QRKit/Info.yaml +1 -1
  41. package/Root/Frameworks/SearchKit/Info.yaml +1 -1
  42. package/Root/Frameworks/SecurityKit/Info.yaml +1 -1
  43. package/Root/Frameworks/ServerKit/Info.yaml +1 -1
  44. package/Root/Frameworks/ServerKit/SKHTTPRequest.js +44 -0
  45. package/Root/Frameworks/ServerKit/SKJobQueue.js +1 -1
  46. package/Root/Frameworks/ServerKit/SKRedisJobQueue.js +7 -3
  47. package/Root/Frameworks/ServerKitTesting/Info.yaml +1 -1
  48. package/Root/Frameworks/TestKit/Info.yaml +1 -1
  49. package/Root/Frameworks/TestKit/TKMock.js +1 -1
  50. package/Root/Frameworks/UIKit/Info.yaml +1 -1
  51. package/Root/Frameworks/UIKit/UIBrowserViewController.js +2 -6
  52. package/Root/Frameworks/UIKit/UICollectionReusableView.js +91 -0
  53. package/Root/Frameworks/UIKit/UICollectionView.js +1254 -0
  54. package/Root/Frameworks/UIKit/UICollectionViewCell.js +121 -0
  55. package/Root/Frameworks/UIKit/UICollectionViewGridLayout.js +425 -0
  56. package/Root/Frameworks/UIKit/UICollectionViewLayout.js +82 -0
  57. package/Root/Frameworks/UIKit/UIColorWell.js +12 -1
  58. package/Root/Frameworks/UIKit/UIDisplayServer.js +5 -1
  59. package/Root/Frameworks/UIKit/UIKit.js +7 -0
  60. package/Root/Frameworks/UIKit/UILayer.js +3 -0
  61. package/Root/Frameworks/UIKit/UIListView.js +8 -9
  62. package/Root/Frameworks/UIKit/UIMenu.js +1 -1
  63. package/Root/Frameworks/UIKit/UIMenuView.js +5 -1
  64. package/Root/Frameworks/UIKit/UINavigationBar.js +9 -3
  65. package/Root/Frameworks/UIKit/UINavigationController.js +228 -112
  66. package/Root/Frameworks/UIKit/UINavigationItem.js +4 -0
  67. package/Root/Frameworks/UIKit/UIPopupButton.js +39 -3
  68. package/Root/Frameworks/UIKit/UIScrollView.js +2 -0
  69. package/Root/Frameworks/UIKit/UISplitViewController.js +215 -73
  70. package/Root/Frameworks/UIKit/UITabViewController.js +4 -10
  71. package/Root/Frameworks/UIKit/UITextField.js +3 -0
  72. package/Root/Frameworks/UIKit/UIView.js +3 -0
  73. package/Root/Frameworks/UIKit/UIViewController.js +141 -50
  74. package/Root/Frameworks/UIKit/UIWindow.js +4 -15
  75. package/Root/Frameworks/UIKitTesting/Info.yaml +1 -1
  76. package/Root/Frameworks/UIKitTesting/UIMockApplication.js +6 -0
  77. package/Root/Templates/http/${PROJECT_NAME}/Dockerfile +1 -1
  78. package/Root/Templates/node/${PROJECT_NAME}/Dockerfile +4 -2
  79. package/package.json +1 -1
@@ -41,7 +41,7 @@ JSClass("DBRedisStore", DBObjectStore, {
41
41
 
42
42
  open: function(completion){
43
43
  logger.info("Redis client connecting to %{public}:%d...", this.url.host, this.url.port || 6379);
44
- this.client = this.redis.createClient({url: this.url.encodedString});
44
+ this.client = this.redis.createClient({url: this.url.encodedString, legacyMode: true});
45
45
  var store = this;
46
46
  var errorHandler = function(error){
47
47
  logger.info("Failed to open Redis connection: %{error}", error);
@@ -67,8 +67,12 @@ JSClass("DBRedisStore", DBObjectStore, {
67
67
  store.close(fn);
68
68
  }
69
69
  };
70
- this.client.on("error", errorHandler);
71
- this.client.on("ready", readyHandler);
70
+ if (this.client.connect){
71
+ this.client.connect().then(readyHandler, errorHandler);
72
+ }else{
73
+ this.client.on("error", errorHandler);
74
+ this.client.on("ready", readyHandler);
75
+ }
72
76
  },
73
77
 
74
78
  closeCallback: null,
@@ -233,7 +237,7 @@ JSClass("DBRedisStore", DBObjectStore, {
233
237
 
234
238
  watchClientQueue: null,
235
239
 
236
- dequeueReusableWatchClient: function(){
240
+ dequeueReusableWatchClient: function(completion, target){
237
241
  if (this.watchClientQueue === null){
238
242
  this.watchClientQueue = [];
239
243
  }
@@ -245,7 +249,17 @@ JSClass("DBRedisStore", DBObjectStore, {
245
249
  return this.watchClientQueue.shift();
246
250
  }
247
251
  logger.info("opening watch client to %{public}:%d", this.url.host, this.url.port || 6379);
248
- return this.redis.createClient({url: this.url.encodedString});
252
+ var client = this.redis.createClient({url: this.url.encodedString, legacyMode: true});
253
+ if (client.connect){
254
+ client.connect().then(function(){
255
+ completion.call(target, client);
256
+ }, function(error){
257
+ logger.error("Error connecting to watch client: %{error}", error);
258
+ completion.call(target, null);
259
+ });
260
+ }else{
261
+ completion.call(target, client);
262
+ }
249
263
  },
250
264
 
251
265
  enqueueReusableWatchClient: function(client){
@@ -277,120 +291,125 @@ JSClass("DBRedisStore", DBObjectStore, {
277
291
  },
278
292
 
279
293
  exclusiveSave: function(id, change, completion){
280
- var watchClient = this.dequeueReusableWatchClient();
281
- var maxRetires = 30;
282
- var waitInterval = JSTimeInterval.milliseconds(20);
283
- var retires = 0;
284
- var store = this;
285
- var trySave = function(){
286
- try{
287
- watchClient.watch(id, function(error){
288
- if (error !== null){
289
- logger.error("Failure calling redis watch: %{error}", error);
290
- watchClient.quit();
291
- completion(false);
292
- return;
293
- }
294
- try{
295
- watchClient.get(id, function(error, json){
296
- if (error !== null){
297
- logger.error("Failure calling redis get: %{error}", error);
298
- watchClient.quit();
299
- completion(false);
300
- return;
301
- }
302
- var object = null;
303
- try{
304
- object = JSON.parse(json);
305
- }catch (e){
306
- logger.error("Failure parsing object json: %{error}", error);
307
- watchClient.quit();
308
- completion(false);
309
- return;
310
- }
311
- try{
312
- watchClient.ttl(id, function(error, ttl){
313
- if (error !== null){
314
- logger.error("Failure calling redis ttl: %{error}", error);
315
- watchClient.quit();
316
- completion(false);
317
- return;
318
- }
319
- try{
320
- change(object, function(changedObject){
321
- if (changedObject === null){
322
- watchClient.quit();
323
- completion(false);
324
- return;
325
- }
326
- var changedJSON = null;
327
- try{
328
- changedJSON = JSON.stringify(changedObject);
329
- }catch (e){
330
- logger.error("Failed to serialize object for redis: %{error}", e);
331
- watchClient.quit();
332
- completion(false);
333
- return;
334
- }
335
- var args = [id, changedJSON];
336
- if (ttl > 0){
337
- args.push("EX");
338
- args.push(ttl);
339
- }
340
- try{
341
- watchClient.multi().set(args).exec(function(error, results){
342
- if (error !== null){
343
- logger.error("Failure calling redis multi/set/exec: %{error}", error);
344
- watchClient.quit();
345
- completion(false);
346
- return;
347
- }
348
- if (results === null){
349
- // null results means the transaction failed, so it's our signal to retry
350
- ++retires;
351
- if (retires > maxRetires){
352
- store.enqueueReusableWatchClient(watchClient);
353
- completion(true);
354
- return;
355
- }
356
- JSTimer.scheduledTimerWithInterval(waitInterval, trySave);
357
- waitInterval = Math.min(1, waitInterval * 2);
358
- return;
359
- }
360
- store.enqueueReusableWatchClient(watchClient);
361
- completion(true);
362
- });
363
- }catch (e){
364
- logger.error("Error thrown calling redis multi/set/exec: %{error}", e);
365
- watchClient.quit();
366
- completion(false);
367
- }
368
- });
369
- }catch (e){
370
- logger.error("Error thrown calling change function: %{error}", e);
371
- watchClient.quit();
372
- completion(false);
373
- }
374
- });
375
- }catch (e){
376
- logger.error("Error thrown calling redis ttl: %{error}", error);
377
- watchClient.quit();
378
- completion(false);
379
- }
380
- });
381
- }catch (e){
382
- logger.error("Error thrown calling redis get: %{error}", error);
383
- watchClient.quit();
384
- completion(false);
385
- }
386
- });
387
- }catch (e){
388
- logger.error("Error thrown calling redis watch: %{error}", e);
389
- watchClient.quit();
294
+ this.dequeueReusableWatchClient(function(watchClient){
295
+ if (watchClient === null){
390
296
  completion(false);
297
+ return;
391
298
  }
392
- };
393
- trySave();
299
+ var maxRetires = 30;
300
+ var waitInterval = JSTimeInterval.milliseconds(20);
301
+ var retires = 0;
302
+ var store = this;
303
+ var trySave = function(){
304
+ try{
305
+ watchClient.watch(id, function(error){
306
+ if (error !== null){
307
+ logger.error("Failure calling redis watch: %{error}", error);
308
+ watchClient.quit();
309
+ completion(false);
310
+ return;
311
+ }
312
+ try{
313
+ watchClient.get(id, function(error, json){
314
+ if (error !== null){
315
+ logger.error("Failure calling redis get: %{error}", error);
316
+ watchClient.quit();
317
+ completion(false);
318
+ return;
319
+ }
320
+ var object = null;
321
+ try{
322
+ object = JSON.parse(json);
323
+ }catch (e){
324
+ logger.error("Failure parsing object json: %{error}", error);
325
+ watchClient.quit();
326
+ completion(false);
327
+ return;
328
+ }
329
+ try{
330
+ watchClient.ttl(id, function(error, ttl){
331
+ if (error !== null){
332
+ logger.error("Failure calling redis ttl: %{error}", error);
333
+ watchClient.quit();
334
+ completion(false);
335
+ return;
336
+ }
337
+ try{
338
+ change(object, function(changedObject){
339
+ if (changedObject === null){
340
+ watchClient.quit();
341
+ completion(false);
342
+ return;
343
+ }
344
+ var changedJSON = null;
345
+ try{
346
+ changedJSON = JSON.stringify(changedObject);
347
+ }catch (e){
348
+ logger.error("Failed to serialize object for redis: %{error}", e);
349
+ watchClient.quit();
350
+ completion(false);
351
+ return;
352
+ }
353
+ var args = [id, changedJSON];
354
+ if (ttl > 0){
355
+ args.push("EX");
356
+ args.push(ttl);
357
+ }
358
+ try{
359
+ watchClient.multi().set(args).exec(function(error, results){
360
+ if (error !== null){
361
+ logger.error("Failure calling redis multi/set/exec: %{error}", error);
362
+ watchClient.quit();
363
+ completion(false);
364
+ return;
365
+ }
366
+ if (results === null){
367
+ // null results means the transaction failed, so it's our signal to retry
368
+ ++retires;
369
+ if (retires > maxRetires){
370
+ store.enqueueReusableWatchClient(watchClient);
371
+ completion(true);
372
+ return;
373
+ }
374
+ JSTimer.scheduledTimerWithInterval(waitInterval, trySave);
375
+ waitInterval = Math.min(1, waitInterval * 2);
376
+ return;
377
+ }
378
+ store.enqueueReusableWatchClient(watchClient);
379
+ completion(true);
380
+ });
381
+ }catch (e){
382
+ logger.error("Error thrown calling redis multi/set/exec: %{error}", e);
383
+ watchClient.quit();
384
+ completion(false);
385
+ }
386
+ });
387
+ }catch (e){
388
+ logger.error("Error thrown calling change function: %{error}", e);
389
+ watchClient.quit();
390
+ completion(false);
391
+ }
392
+ });
393
+ }catch (e){
394
+ logger.error("Error thrown calling redis ttl: %{error}", error);
395
+ watchClient.quit();
396
+ completion(false);
397
+ }
398
+ });
399
+ }catch (e){
400
+ logger.error("Error thrown calling redis get: %{error}", error);
401
+ watchClient.quit();
402
+ completion(false);
403
+ }
404
+ });
405
+ }catch (e){
406
+ logger.error("Error thrown calling redis watch: %{error}", e);
407
+ watchClient.quit();
408
+ completion(false);
409
+ }
410
+ };
411
+ trySave();
412
+ }, this);
394
413
  },
395
414
 
396
415
  saveChange: function(change, completion){
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.DBKit
3
- JSBundleVersion: 2021.52.0
3
+ JSBundleVersion: 2022.6.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.DOM
3
- JSBundleVersion: 2021.52.0
3
+ JSBundleVersion: 2022.6.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.Dispatch
3
- JSBundleVersion: 2021.52.0
3
+ JSBundleVersion: 2022.6.0
4
4
  JSCopyright: Copyright © 2020 Breakside Inc.
5
5
  JSBundleEnvironments:
6
6
  html: Dispatch+HTML.js
@@ -1,6 +1,6 @@
1
1
  JSBundleType: framework
2
2
  JSBundleIdentifier: io.breakside.JSKit.FontKit
3
- JSBundleVersion: 2021.52.0
3
+ JSBundleVersion: 2022.6.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.Foundation
3
- JSBundleVersion: 2021.52.0
3
+ JSBundleVersion: 2022.6.0
4
4
  JSDevelopmentLanguage: en
5
5
  JSCopyright: Copyright © 2020 Breakside Inc.
6
6
  JSBundleEnvironments:
@@ -300,6 +300,15 @@ JSClass('JSColor', JSObject, {
300
300
  return JSColor.initWithSpaceAndComponents(JSColorSpace.gray, gray);
301
301
  },
302
302
 
303
+ colorInSpace: function(space){
304
+ if (space === this._space){
305
+ return this;
306
+ }
307
+ var components = space.componentsFromSpace(this._space, this._components);
308
+ components.push(this._components[this._components.length - 1]);
309
+ return JSColor.initWithSpaceAndComponents(space, components);
310
+ },
311
+
303
312
  rgbaHexStringRepresentation: function(){
304
313
  var color = this.rgbaColor();
305
314
  var r = Math.round(color.red * 255);
@@ -88,14 +88,14 @@ JSClass("JSXYZColorSpace", JSColorSpace, {
88
88
 
89
89
  name: "xyz",
90
90
 
91
- initWithWhitepoint: function(mediaWhitepoint, connectionWhitepoint){
92
- if (mediaWhitepoint === connectionWhitepoint){
91
+ initWithWhitepoint: function(mediaWhitepoint){
92
+ if (mediaWhitepoint === JSColorSpace.Whitepoint.profileConnection){
93
93
  return JSColorSpace.xyz;
94
94
  }
95
- if (mediaWhitepoint[0] === connectionWhitepoint[0] && mediaWhitepoint[1] === connectionWhitepoint[1] && mediaWhitepoint[2] === connectionWhitepoint[2]){
95
+ if (mediaWhitepoint[0] === JSColorSpace.Whitepoint.profileConnection[0] && mediaWhitepoint[1] === JSColorSpace.Whitepoint.profileConnection[1] && mediaWhitepoint[2] === JSColorSpace.Whitepoint.profileConnection[2]){
96
96
  return JSColorSpace.xyz;
97
97
  }
98
- return JSXYZScaledColorSpace.initWithWhitepoint(mediaWhitepoint, connectionWhitepoint);
98
+ return JSXYZScaledColorSpace.initWithWhitepoint(mediaWhitepoint);
99
99
  },
100
100
 
101
101
  initWithScale: function(scale){
@@ -125,11 +125,11 @@ JSClass("JSXYZScaledColorSpace", JSXYZColorSpace, {
125
125
  _scale: null,
126
126
  _inverseScale: null,
127
127
 
128
- initWithWhitepoint: function(mediaWhitepoint, connectionWhitepoint){
128
+ initWithWhitepoint: function(mediaWhitepoint){
129
129
  this.initWithScale([
130
- mediaWhitepoint[0] / connectionWhitepoint[0],
131
- mediaWhitepoint[1] / connectionWhitepoint[1],
132
- mediaWhitepoint[2] / connectionWhitepoint[2]
130
+ mediaWhitepoint[0] / JSColorSpace.Whitepoint.profileConnection[0],
131
+ mediaWhitepoint[1] / JSColorSpace.Whitepoint.profileConnection[1],
132
+ mediaWhitepoint[2] / JSColorSpace.Whitepoint.profileConnection[2]
133
133
  ]);
134
134
  },
135
135
 
@@ -164,10 +164,7 @@ JSClass("JSLabColorSpace", JSColorSpace, {
164
164
 
165
165
  name: "lab",
166
166
 
167
- mediaWhitepoint: null,
168
-
169
- initWithWhitepoint: function(mediaWhitepoint){
170
- this.mediaWhitepoint = mediaWhitepoint;
167
+ init: function(){
171
168
  },
172
169
 
173
170
  xyzFromComponents: function(components){
@@ -181,9 +178,9 @@ JSClass("JSLabColorSpace", JSColorSpace, {
181
178
  var fx = components[1] / 500.0 + fy;
182
179
  var fz = fy - components[2] / 200.0;
183
180
  return [
184
- this.mediaWhitepoint[0] * fi(fx),
185
- this.mediaWhitepoint[1] * fi(fy),
186
- this.mediaWhitepoint[2] * fi(fz)
181
+ JSColorSpace.Whitepoint.profileConnection[0] * fi(fx),
182
+ JSColorSpace.Whitepoint.profileConnection[1] * fi(fy),
183
+ JSColorSpace.Whitepoint.profileConnection[2] * fi(fz)
187
184
  ];
188
185
  },
189
186
 
@@ -194,9 +191,9 @@ JSClass("JSLabColorSpace", JSColorSpace, {
194
191
  }
195
192
  return (841.0 / 108.0) * x + 4.0 / 29.0;
196
193
  };
197
- var fx = f(xyz[0] / this.mediaWhitepoint[0]);
198
- var fy = f(xyz[1] / this.mediaWhitepoint[1]);
199
- var fz = f(xyz[2] / this.mediaWhitepoint[2]);
194
+ var fx = f(xyz[0] / JSColorSpace.Whitepoint.profileConnection[0]);
195
+ var fy = f(xyz[1] / JSColorSpace.Whitepoint.profileConnection[1]);
196
+ var fz = f(xyz[2] / JSColorSpace.Whitepoint.profileConnection[2]);
200
197
  return [
201
198
  116.0 * fy - 16.0,
202
199
  500.0 * (fx - fy),
@@ -239,10 +236,52 @@ JSClass("JSRGBColorSpace", JSColorSpace, {
239
236
 
240
237
  // MARK: - Lab conversions
241
238
 
239
+ xyzMatrix: [
240
+ [0.4360, 0.3851, 0.1431],
241
+ [0.2225, 0.7169, 0.0606],
242
+ [0.0139, 0.09710, 0.7139]
243
+ ],
244
+
245
+ xyzInverseMatrix: [
246
+ [3.13458, -1.61731, -0.491034],
247
+ [-0.978957, 1.91622, 0.0335704],
248
+ [0.0721194, -0.229142, 1.40575]
249
+ ],
250
+
251
+ g: 2.4,
252
+ a: 1.0 / 1.055,
253
+ b: 0.055 / 1.055,
254
+ c: 1.0 / 12.92,
255
+ d: 0.04045,
256
+
257
+ curve: function(x){
258
+ return parametricCurve3(x, this.g, this.a, this.b, this.c, this.d);
259
+ },
260
+
261
+ inverseCurve: function(y){
262
+ y = Math.max(0, Math.min(1, y));
263
+ return inverseParametricCurve3(y, this.g, this.a, this.b, this.c, this.d);
264
+ },
265
+
242
266
  xyzFromComponents: function(components){
267
+ var rgb = [
268
+ this.curve(components[0]),
269
+ this.curve(components[1]),
270
+ this.curve(components[2])
271
+ ];
272
+ return [
273
+ this.xyzMatrix[0][0] * rgb[0] + this.xyzMatrix[0][1] * rgb[1] + this.xyzMatrix[0][2] * rgb[2],
274
+ this.xyzMatrix[1][0] * rgb[0] + this.xyzMatrix[1][1] * rgb[1] + this.xyzMatrix[1][2] * rgb[2],
275
+ this.xyzMatrix[2][0] * rgb[0] + this.xyzMatrix[2][1] * rgb[1] + this.xyzMatrix[2][2] * rgb[2]
276
+ ];
243
277
  },
244
278
 
245
279
  componentsFromXYZ: function(xyz){
280
+ return [
281
+ this.inverseCurve(this.xyzInverseMatrix[0][0] * xyz[0] + this.xyzInverseMatrix[0][1] * xyz[1] + this.xyzInverseMatrix[0][2] * xyz[2]),
282
+ this.inverseCurve(this.xyzInverseMatrix[1][0] * xyz[0] + this.xyzInverseMatrix[1][1] * xyz[1] + this.xyzInverseMatrix[1][2] * xyz[2]),
283
+ this.inverseCurve(this.xyzInverseMatrix[2][0] * xyz[0] + this.xyzInverseMatrix[2][1] * xyz[1] + this.xyzInverseMatrix[2][2] * xyz[2])
284
+ ];
246
285
  },
247
286
 
248
287
  // MARK: - rgb <-> hsl
@@ -425,7 +464,38 @@ JSClass("JSGrayColorSpace", JSColorSpace, {
425
464
  return [
426
465
  components[0] + (1.0 - components[0]) * percentage
427
466
  ];
428
- }
467
+ },
468
+
469
+ g: 2.4,
470
+ a: 1.0 / 1.055,
471
+ b: 0.055 / 1.055,
472
+ c: 1.0 / 12.92,
473
+ d: 0.04045,
474
+
475
+ curve: function(x){
476
+ return parametricCurve3(x, this.g, this.a, this.b, this.c, this.d);
477
+ },
478
+
479
+ inverseCurve: function(y){
480
+ y = Math.max(0, Math.min(1, y));
481
+ return inverseParametricCurve3(y, this.g, this.a, this.b, this.c, this.d);
482
+ },
483
+
484
+ // MARK: - Lab conversions
485
+
486
+ xyzFromComponents: function(components){
487
+ var w = this.curve(components[0]);
488
+ return [
489
+ JSColorSpace.Whitepoint.profileConnection[0] * w,
490
+ JSColorSpace.Whitepoint.profileConnection[1] * w,
491
+ JSColorSpace.Whitepoint.profileConnection[2] * w
492
+ ];
493
+ },
494
+
495
+ componentsFromXYZ: function(xyz){
496
+ var y = Math.min(JSColorSpace.Whitepoint.profileConnection[1], Math.max(0, xyz[1])) / JSColorSpace.Whitepoint.profileConnection[1];
497
+ return [this.inverseCurve(y)];
498
+ },
429
499
 
430
500
  });
431
501
 
@@ -622,7 +692,7 @@ Object.defineProperties(JSColorSpace, {
622
692
  lab: {
623
693
  configurable: true,
624
694
  get: function(){
625
- var space = JSLabColorSpace.initWithWhitepoint(JSColorSpace.Whitepoint.D50);
695
+ var space = JSLabColorSpace.init();
626
696
  Object.defineProperty(this, "lab", {value: space});
627
697
  return space;
628
698
  }
@@ -635,4 +705,20 @@ JSColorSpace.Whitepoint = {
635
705
  D65: [0.9505, 1.0, 1.08883]
636
706
  };
637
707
 
708
+ JSColorSpace.Whitepoint.profileConnection = JSColorSpace.Whitepoint.D50;
709
+
710
+ var parametricCurve3 = function(x, g, a, b, c, d){
711
+ if (x >= d){
712
+ return Math.pow(a * x + b, g);
713
+ }
714
+ return c * x;
715
+ };
716
+
717
+ var inverseParametricCurve3 = function(y, g, a, b, c, d){
718
+ if (y < c * d){
719
+ return y / c;
720
+ }
721
+ return (Math.pow(y, 1.0 / g) - b) / a;
722
+ };
723
+
638
724
  })();
@@ -17,7 +17,7 @@
17
17
  'use strict';
18
18
 
19
19
  JSGlobalObject.JSMediaType = function(str, parameters){
20
- if (str === null || str === undefined){
20
+ if (str === null || str === undefined || str === ""){
21
21
  return null;
22
22
  }
23
23
  if (this === undefined){