bm-core-ui 2.8.3 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -257,30 +257,38 @@ BMWindow.unregisterShowcaseElement = function (element) {
257
257
  BMWindow.enterShowcase = async function () {
258
258
  if (BMWindow._isShowcasing) return;
259
259
 
260
+ // Set a background color for the body to have a good contrast between the windows
261
+ // and the "empty space"
260
262
  document.body.style.backgroundColor = 'rgb(60, 60, 60)';
261
263
 
262
264
  BMWindow._isShowcasing = YES;
263
265
 
266
+ // Set up a handler to exit the showcase when clicking outside of any window
264
267
  document.body.addEventListener('click', BMWindow.exitShowcase);
265
268
 
269
+ // Only include non-minimized windows in the showcase
266
270
  let openWindows = BMWindow._windows.filter(value => !value._minimizedWindow);
267
271
 
268
- let viewportFrame = BMRectMake(0, 0, window.innerWidth, window.innerHeight);
269
-
272
+ // Add any window-like elements that have been registered to participate in the showcase
270
273
  for (let element of BMWindow._showcaseElements) {
271
274
  openWindows.unshift(element);
272
275
  }
273
276
 
274
277
  openWindows.forEach(window => {
278
+ // For each window, create a mask that consumes mouse events instead of the windows
279
+ // and disable pointer events for the windows
275
280
  window.node.classList.add('BMWindowShowcaseWindow');
276
281
 
277
282
  let selector = document.createElement('div');
278
283
  selector.classList.add('BMWindowShowcaseWindowSelector');
279
284
  selector.addEventListener('click', event => {
280
285
  if (window.becomeKeyWindow) {
286
+ // If the clicked element is a window, make it the key window
281
287
  window.becomeKeyWindow();
282
288
  }
283
289
  else {
290
+ // If a non-window element is clicked, bring it to the front by hiding
291
+ // all windows
284
292
  BMWindow.hideAll();
285
293
  }
286
294
  BMWindow.exitShowcase();
@@ -289,16 +297,30 @@ BMWindow.enterShowcase = async function () {
289
297
  window.node.appendChild(selector);
290
298
  });
291
299
 
300
+
301
+ let viewportFrame = BMRectMake(0, 0, window.innerWidth, window.innerHeight);
302
+ // Create a copy of each window's frame which will be used to determine where to place each window
303
+ // in the showcase
292
304
  let sourceRects = openWindows.map(window => window._fullScreen ? viewportFrame.copy() : window.frame.copy());
305
+
306
+ // Retain a copy of the original frames to determine what transforms to apply to each window
293
307
  let originalRects = sourceRects.map(rect => rect.copy());
308
+
309
+ // Set to NO when no windows overlap
294
310
  let overlap;
295
311
 
312
+ // Initialize the bounds with the viewport frame; this will expand to represent the entire area
313
+ // used by all windows as they get pushed apart
296
314
  let bounds = viewportFrame.copy();
297
315
 
316
+ // Because the algorithm works through multiple iterations where each intersecting windows
317
+ // are pushed apart slightly, set a maximum number of iterations to avoid situations
318
+ // where a fully non-intersecting layout cannot be obtained in an acceptable amount of time
298
319
  for (let i = 0; i < BM_WINDOW_SHOWCASE_MAX_ITERATIONS; i++) {
299
320
 
300
321
  for (let j = 0; j < sourceRects.length; j++) {
301
322
  for (let k = 0; k < sourceRects.length; k++) {
323
+ // Iterate through each pair of windows and push apart those windows that intersect
302
324
  if (j != k && sourceRects[j].intersectsRect(sourceRects[k])) {
303
325
  overlap = YES;
304
326
 
@@ -307,11 +329,15 @@ BMWindow.enterShowcase = async function () {
307
329
 
308
330
  let difference = rect2.center.pointBySubtractingPoint(rect1.center);
309
331
 
332
+ // If the windows have the same center point, choose a random direction
333
+ // in which to push them apart
310
334
  if (!difference.x && !difference.y) {
311
335
  difference.x = Math.random() * 2 - 1;
312
336
  difference.y = Math.random() * 2 - 1;
313
337
  }
314
338
 
339
+ // Adjust the direction in which the windows are pushed apart to maintain a similar
340
+ // aspect ratio between the bounds and the viewport
315
341
  if (bounds.height / bounds.width > viewportFrame.height / viewportFrame.width) {
316
342
  difference.x = difference.x * 2;
317
343
  }
@@ -319,13 +345,16 @@ BMWindow.enterShowcase = async function () {
319
345
  difference.y = difference.y * 2;
320
346
  }
321
347
 
348
+ // Normalize the distance
322
349
  let length = Math.sqrt(difference.x * difference.x + difference.y * difference.y);
323
350
  difference.x = difference.x * 20 / length;
324
351
  difference.y = difference.y * 20 / length;
325
352
 
353
+ // Push the two windows apart in opposite directions
326
354
  rect1.offsetWithX(-difference.x, {y: -difference.y});
327
355
  rect2.offsetWithX(difference.x, {y: difference.y});
328
356
 
357
+ // Extend the bounds to contain the windows in their new positions
329
358
  bounds = bounds.rectByUnionWithRect(rect1).rectByUnionWithRect(rect2);
330
359
 
331
360
  }
@@ -335,11 +364,14 @@ BMWindow.enterShowcase = async function () {
335
364
  if (!overlap) break;
336
365
  }
337
366
 
367
+ // Determine how much the windows need to be shrinked to fit on screen
338
368
  let scale = Math.min(1, viewportFrame.width / bounds.width, viewportFrame.height / bounds.height);
339
369
 
340
370
  for (let rect of sourceRects) {
371
+ // Adjust the rect's origin so that it is relative to the bounds instead of the viewport
341
372
  rect.offset(-bounds.left, -bounds.top);
342
373
 
374
+ // Apply the scale
343
375
  rect.origin.x = rect.origin.x * scale;
344
376
  rect.origin.y = rect.origin.y * scale;
345
377
 
@@ -351,11 +383,8 @@ BMWindow.enterShowcase = async function () {
351
383
  BMAnimateWithBlock(() => {
352
384
  BMAnimationContextEnableWebAnimations();
353
385
 
354
- /*let header = document.getElementById('twStudioHeader');
355
- let headerController = BMAnimationContextGetCurrent().controllerForObject(header, {node: header});
356
- headerController.registerBuiltInProperty('translateY', {withValue: -header.offsetHeight + 'px'});*/
357
-
358
386
  for (let i = 0; i < sourceRects.length; i++) {
387
+ // For each window, determine which transforms to apply and animate to them
359
388
  let transformRect = originalRects[i].rectWithTransformToRect(sourceRects[i]);
360
389
 
361
390
  let controller = BMAnimationContextGetCurrent().controllerForObject(openWindows[i].node, {node: openWindows[i].node});
@@ -391,19 +420,18 @@ BMWindow.exitShowcase = function (event) {
391
420
 
392
421
  BMWindow._isShowcasing = NO;
393
422
 
423
+ // Clear the event handlers set up for the showcase
394
424
  document.body.removeEventListener('click', BMWindow.exitShowcase);
395
425
  document.body.removeEventListener('wheel', BMWindow._wheelHandler, YES);
396
426
 
397
427
  let openWindows = BMWindow._windows.filter(value => !value._minimizedWindow);
398
- /*let twStudio = document.querySelector('#twStudioBody');
399
- let pageWindow = {node: twStudio};
400
- openWindows.unshift(pageWindow);*/
401
428
 
402
429
  for (let element of BMWindow._showcaseElements) {
403
430
  openWindows.unshift(element);
404
431
  }
405
432
 
406
433
  openWindows.forEach(window => {
434
+ // Clear the classes and masks created for each window
407
435
  window.node.classList.remove('BMWindowShowcaseWindow');
408
436
 
409
437
  let selector = window.node.querySelector('.BMWindowShowcaseWindowSelector');
@@ -413,11 +441,8 @@ BMWindow.exitShowcase = function (event) {
413
441
  BMAnimateWithBlock(() => {
414
442
  BMAnimationContextEnableWebAnimations();
415
443
 
416
- /*let header = document.getElementById('twStudioHeader');
417
- let headerController = BMAnimationContextGetCurrent().controllerForObject(header, {node: header});
418
- headerController.registerBuiltInProperty('translateY', {withValue: '0px'});*/
419
-
420
444
  for (let i = 0; i < openWindows.length; i++) {
445
+ // For each window, animate back to no transforms
421
446
  let controller = BMAnimationContextGetCurrent().controllerForObject(openWindows[i].node, {node: openWindows[i].node});
422
447
  controller.registerBuiltInPropertiesWithDictionary({
423
448
  translateX: '0px',
@@ -1427,6 +1452,7 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1427
1452
  self._blocker.style.backdropFilter = 'blur(' + ((1 - complete) * 15).toFixed(2) + 'px)';
1428
1453
  },*/
1429
1454
  complete: function () {
1455
+ self.windowDidClose();
1430
1456
  if (self.delegate && self.delegate.windowDidClose) {
1431
1457
  self.delegate.windowDidClose(self);
1432
1458
  }
@@ -1467,6 +1493,8 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1467
1493
 
1468
1494
  this._window.style.opacity = 0;
1469
1495
  this._window.style.display = 'none';
1496
+
1497
+ self.windowDidClose();
1470
1498
 
1471
1499
  if (self.delegate && self.delegate.windowDidClose) {
1472
1500
  self.delegate.windowDidClose(self);
@@ -1475,6 +1503,14 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1475
1503
  }
1476
1504
  },
1477
1505
 
1506
+ /**
1507
+ * Invoked after this window closes. Subclasses overriding this method must invoked
1508
+ * the superclass method at some point in their implementation.
1509
+ */
1510
+ windowDidClose() {
1511
+
1512
+ },
1513
+
1478
1514
  /**
1479
1515
  * Minimizes this window. This method will raise an error if this window is modal.
1480
1516
  * If this window is already minimized, this method will have no effect.
@@ -1793,14 +1829,14 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1793
1829
  if (BMWindow._keyWindow == this && !this._modal) {
1794
1830
  this.node.classList.remove('BMKeyWindow');
1795
1831
  this.node.classList.add('BMWindowInactive');
1796
- if (this.delegate && this.delegate.windowDidResignKeyWindow) {
1797
- this.delegate.windowDidResignKeyWindow(this);
1798
- }
1799
1832
  BMWindow._keyWindow = undefined;
1800
1833
 
1801
1834
  for (let toolWindow of this._toolWindows) {
1802
1835
  toolWindow.hide();
1803
1836
  }
1837
+ if (this.delegate && this.delegate.windowDidResignKeyWindow) {
1838
+ this.delegate.windowDidResignKeyWindow(this);
1839
+ }
1804
1840
  }
1805
1841
  },
1806
1842
 
@@ -1867,6 +1903,11 @@ BMWindow.prototype = BMExtend(Object.create(BMView.prototype), {
1867
1903
  * This instance should not be reused after invoking this method.
1868
1904
  */
1869
1905
  release() {
1906
+ if (this.__released) {
1907
+ // This needs to be handled because of the way Thingworx DOM nodes are removed and recreated in the composer
1908
+ return;
1909
+ }
1910
+
1870
1911
  if (BMWindow._keyWindow == this) BMWindow._keyWindow = undefined;
1871
1912
 
1872
1913
  if (this._boundViewportDidResize) {