bm-core-ui 2.7.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 (99) hide show
  1. package/CHANGELOG.md +1624 -0
  2. package/LICENSE +21 -0
  3. package/README.md +145 -0
  4. package/build/@types/index.d.ts +14078 -0
  5. package/build/BMCodeEditor/BMCodeEditor.js +707 -0
  6. package/build/BMCollectionView/BMCollectionView.js +5861 -0
  7. package/build/BMCollectionView/BMCollectionViewCell.js +688 -0
  8. package/build/BMCollectionView/BMCollectionViewFlowLayout.js +4467 -0
  9. package/build/BMCollectionView/BMCollectionViewLayout.js +830 -0
  10. package/build/BMCollectionView/BMCollectionViewLayoutAttributes.js +673 -0
  11. package/build/BMCollectionView/BMCollectionViewMasonryLayout.js +491 -0
  12. package/build/BMCollectionView/BMCollectionViewStackLayout.js +634 -0
  13. package/build/BMCollectionView/BMCollectionViewTileLayout.js +1121 -0
  14. package/build/BMCoreUI.css +2833 -0
  15. package/build/BMView/BMAttributedLabelView.js +310 -0
  16. package/build/BMView/BMLayoutConstraint_v2.5.js +1813 -0
  17. package/build/BMView/BMLayoutGuide.js +192 -0
  18. package/build/BMView/BMLayoutSizeClass.js +466 -0
  19. package/build/BMView/BMMenu.js +574 -0
  20. package/build/BMView/BMScrollView.js +247 -0
  21. package/build/BMView/BMTextField.js +512 -0
  22. package/build/BMView/BMTextFieldDelegate.js +71 -0
  23. package/build/BMView/BMView_v2.5.js +3572 -0
  24. package/build/BMView/BMViewport.js +221 -0
  25. package/build/BMViewLayoutEditor/BMLayoutEditor.js +6117 -0
  26. package/build/BMViewLayoutEditor/BMLayoutEditorConstraintSettings.js +417 -0
  27. package/build/BMViewLayoutEditor/BMLayoutEditorDelegate.js +59 -0
  28. package/build/BMViewLayoutEditor/BMLayoutEditorSettingCells.js +1653 -0
  29. package/build/BMViewLayoutEditor/BMLayoutEditorSettings.js +1480 -0
  30. package/build/BMViewLayoutEditor/BMLayoutEditorSettingsComplexCells.js +431 -0
  31. package/build/BMViewLayoutEditor/BMLayoutEditorSettingsDelegate.js +46 -0
  32. package/build/BMViewLayoutEditor/BMLayoutEditorVariablesController.js +460 -0
  33. package/build/BMViewLayoutEditor/BMLayoutEditorViewGroupSettings.js +293 -0
  34. package/build/BMViewLayoutEditor/BMLayoutEditorViewSettings.js +382 -0
  35. package/build/BMViewLayoutEditor/BMLayoutVariableProvider.js +202 -0
  36. package/build/BMWindow/BMConfirmationPopup.js +477 -0
  37. package/build/BMWindow/BMKeyboardShortcut.js +151 -0
  38. package/build/BMWindow/BMPopover/BMPopover.js +492 -0
  39. package/build/BMWindow/BMToolWindow.js +71 -0
  40. package/build/BMWindow/BMWindow.js +2000 -0
  41. package/build/Core/BMAnimationContext.js +1181 -0
  42. package/build/Core/BMColor.js +991 -0
  43. package/build/Core/BMCoreUI.js +470 -0
  44. package/build/Core/BMFunctionCollection.js +110 -0
  45. package/build/Core/BMIndexPath.js +165 -0
  46. package/build/Core/BMInset.js +138 -0
  47. package/build/Core/BMKeyPath.js +100 -0
  48. package/build/Core/BMPoint.js +291 -0
  49. package/build/Core/BMRect.js +556 -0
  50. package/build/Core/BMSize.js +137 -0
  51. package/build/iScroll/LICENSE +22 -0
  52. package/build/iScroll/iscroll-probe.js +2154 -0
  53. package/build/images/AlignBottom.png +0 -0
  54. package/build/images/AlignCenterX.png +0 -0
  55. package/build/images/AlignCenterY.png +0 -0
  56. package/build/images/AlignLeading.png +0 -0
  57. package/build/images/AlignTop.png +0 -0
  58. package/build/images/AlignTrailing.png +0 -0
  59. package/build/images/AllConstraints.png +0 -0
  60. package/build/images/BottomConstraint.png +0 -0
  61. package/build/images/CenterXConstraint.png +0 -0
  62. package/build/images/CenterYConstraint.png +0 -0
  63. package/build/images/CoreUI2.png +0 -0
  64. package/build/images/CoreUI2@2x.png +0 -0
  65. package/build/images/Desktop.png +0 -0
  66. package/build/images/DesktopMini.png +0 -0
  67. package/build/images/EqualHeight.png +0 -0
  68. package/build/images/EqualHorizontalSpacing.png +0 -0
  69. package/build/images/EqualHorizontalSpacingInSuperview.png +0 -0
  70. package/build/images/EqualVerticalSpacing.png +0 -0
  71. package/build/images/EqualVerticalSpacingInSuperview.png +0 -0
  72. package/build/images/EqualWidth.png +0 -0
  73. package/build/images/HeightConstraint.png +0 -0
  74. package/build/images/InactiveConstraints.png +0 -0
  75. package/build/images/Layout.png +0 -0
  76. package/build/images/LayoutVariables.png +0 -0
  77. package/build/images/LeftConstraint.png +0 -0
  78. package/build/images/OwnConstraints.png +0 -0
  79. package/build/images/Phone.png +0 -0
  80. package/build/images/PhoneLandscape.png +0 -0
  81. package/build/images/PhoneLandscapeMini.png +0 -0
  82. package/build/images/PhoneMini.png +0 -0
  83. package/build/images/PhonePortrait.png +0 -0
  84. package/build/images/PhonePortraitMini.png +0 -0
  85. package/build/images/Properties.png +0 -0
  86. package/build/images/RightConstraint.png +0 -0
  87. package/build/images/SubviewConstraints.png +0 -0
  88. package/build/images/Tablet.png +0 -0
  89. package/build/images/TabletLandscape.png +0 -0
  90. package/build/images/TabletLandscapeMini.png +0 -0
  91. package/build/images/TabletMini.png +0 -0
  92. package/build/images/TabletPortrait.png +0 -0
  93. package/build/images/TabletPortraitMini.png +0 -0
  94. package/build/images/TopConstraint.png +0 -0
  95. package/build/images/WidthConstraint.png +0 -0
  96. package/build/index.js +40 -0
  97. package/lib/@types/BMCoreUI.min.d.ts +14078 -0
  98. package/lib/BMCoreUI.min.js +1 -0
  99. package/package.json +58 -0
@@ -0,0 +1,460 @@
1
+ // @ts-check
2
+
3
+ import {YES, NO} from '../Core/BMCoreUI'
4
+ import {BMSizeMake} from '../Core/BMSize'
5
+ import {BMRectMakeWithNodeFrame} from '../Core/BMRect'
6
+ import {BMIndexPathMakeWithRow} from '../Core/BMIndexPath'
7
+ import {__BMVelocityAnimate} from '../Core/BMAnimationContext'
8
+ import {BMMenuKind} from '../BMView/BMMenu'
9
+ import {BMCollectionViewCell} from '../BMCollectionView/BMCollectionViewCell'
10
+ import { _BMLayoutEditorSettingsView } from './BMLayoutEditorSettings'
11
+
12
+ // @type BMLayoutEditorVariableCell extends BMCollectionViewCell
13
+
14
+ /**
15
+ * A collection view cell that represents a layout variable, used by the layout editor.
16
+ */
17
+ export class BMLayoutEditorVariableCell extends BMCollectionViewCell {
18
+
19
+ initWithCollectionView(collectionView, args) {
20
+ super.initWithCollectionView(collectionView, args);
21
+
22
+ const node = args.node;
23
+
24
+ node.classList.add('BMLayoutEditorVariable');
25
+
26
+ const sizeClassBadge = document.createElement('div');
27
+ sizeClassBadge.className = 'BMLayoutEditorDetailsItemBadgeIcon';
28
+ this.sizeClassBadge = sizeClassBadge;
29
+ node.appendChild(sizeClassBadge);
30
+
31
+ const name = document.createElement('input');
32
+ name.type = 'text';
33
+ name.className = 'BMWindowInput BMLayoutEditorVariableName';
34
+ this.variableName = name;
35
+ node.appendChild(name);
36
+ this._initNameEditor();
37
+
38
+ const value = document.createElement('input');
39
+ value.type = 'number';
40
+ value.className = 'BMWindowInput BMLayoutEditorVariableValue';
41
+ this.variableValue = value;
42
+ node.appendChild(value);
43
+ this._initValueEditor();
44
+
45
+ const addVariationButton = document.createElement('div');
46
+ addVariationButton.className = 'BMWindowToolbarButton BMLayoutEditorToolbarButton BMLayoutEditorVariableButton BMLayoutEditorAddVariationButton';
47
+ addVariationButton.innerHTML = '<i class="material-icons">add_circle</i>';
48
+ node.appendChild(addVariationButton);
49
+ this.addVariationButton = addVariationButton;
50
+ this._initAddVariationButton();
51
+
52
+ const removeVariationButton = document.createElement('div');
53
+ removeVariationButton.className = 'BMWindowToolbarButton BMLayoutEditorToolbarButton BMLayoutEditorVariableButton BMLayoutEditorRemoveVariationButton';
54
+ removeVariationButton.innerHTML = '<i class="material-icons">remove_circle</i>';
55
+ node.appendChild(removeVariationButton);
56
+ this.removeVariationButton = removeVariationButton;
57
+ this._initRemoveVariationButton();
58
+
59
+ return this;
60
+ }
61
+
62
+ /**
63
+ * Initializes the action that occurs upon clicking on the add variation button.
64
+ */
65
+ _initAddVariationButton() {
66
+ this.addVariationButton.addEventListener('click', event => {
67
+ // TODO check if a variation already exists for this size class; ideally filter the menu
68
+ this.editor._showSizeClassMenuAtPoint(BMRectMakeWithNodeFrame(this.addVariationButton).center, {kind: BMMenuKind.Menu, action: sizeClass => {
69
+ // If this variation already exists, do nothing
70
+ const variables = this.collectionView.dataSet.variables;
71
+ const variable = variables.find(v => {
72
+ return v.name == this.indexPath.object.name && sizeClass.isEqualToSizeClass(v.sizeClass);
73
+ });
74
+
75
+ if (variable) return;
76
+
77
+ // Update the UI with the new value
78
+ this.collectionView.dataSet.beginUpdates();
79
+ this.collectionView.dataSet.variables.splice(this.indexPath.row + 1, 0, {name: this.indexPath.object.name, sizeClass, value: this.indexPath.object.value});
80
+ const newRow = this.indexPath.row + 1;
81
+ this.collectionView.dataSet.commitUpdatesWithCompletionHandler(() => {
82
+ // After the animation finishes, focus the new property's name
83
+ var newVariableIndexPath = this.collectionView.indexPathForObjectAtRow(newRow, {inSectionAtIndex: 0});
84
+ var newVariableCell = this.collectionView.cellAtIndexPath(newVariableIndexPath);
85
+
86
+ if (newVariableCell) {
87
+ newVariableCell.node.querySelector('.BMLayoutEditorVariableValue').focus();
88
+
89
+ this.collectionView.scrollToCellAtIndexPath(newVariableIndexPath, {animated: YES});
90
+ }
91
+ else {
92
+ // If the newly created property is not in view, its cell must be created before it can be focused
93
+ newVariableCell = propertiesCollection.retainCellForIndexPath(newVariableIndexPath);
94
+ newVariableCell.node.querySelector('.BMLayoutEditorVariableValue').focus();
95
+
96
+ // Because any input acquiring focus will cause its owning cell to be retained, the cell may be released from here
97
+ newVariableCell.release();
98
+
99
+ this.collectionView.scrollToCellAtIndexPath(newVariableIndexPath, {animated: YES});
100
+ }
101
+ });;
102
+
103
+ // Push this update to the backing variable provider
104
+ this.editor.layoutVariableProvider.setLayoutVariableValue(this.indexPath.object.value, {named: this.indexPath.object.name, inSizeClass: sizeClass});
105
+ }});
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Initializes the action that ocdurs upon clicking on the remove variation or remove variable button.
111
+ */
112
+ _initRemoveVariationButton() {
113
+ this.removeVariationButton.addEventListener('click', event => {
114
+ const variables = this.collectionView.dataSet.variables;
115
+ // This button behaves differently depending on whether it is pressed on a variation or a variable definition
116
+ // For variations, this should just remove the variation
117
+ if (this.indexPath.object.sizeClass) {
118
+ // Update the UI
119
+ this.collectionView.dataSet.beginUpdates();
120
+ variables.splice(this.indexPath.row, 1);
121
+ this.collectionView.dataSet.commitUpdates();
122
+
123
+ // And unregister the variation from the variable provider
124
+ this.editor.layoutVariableProvider.removeVariationForLayoutVariableNamed(this.indexPath.object.name, {inSizeClass: this.indexPath.object.sizeClass});
125
+ }
126
+ else {
127
+ // For variable definitions, this should unregister all size class variations and also remove the variable itself
128
+ // TODO: Verify that the variable is not used referened and provide a warning if it is
129
+ this.collectionView.dataSet.beginUpdates();
130
+ for (let i = 0; i < variables.length; i++) {
131
+ const variable = variables[i];
132
+ if (variable.name == this.indexPath.object.name) {
133
+ // Remove the variation or variable from the provider
134
+ if (variable.sizeClass) {
135
+ this.editor.layoutVariableProvider.removeVariationForLayoutVariableNamed(variable.name, {inSizeClass: variable.sizeClass});
136
+ }
137
+ else {
138
+ this.editor.layoutVariableProvider.unregisterLayoutVariableNamed(variable.name);
139
+ }
140
+
141
+ // Update the UI's backing data set
142
+ variables.splice(i, 1);
143
+ i--;
144
+ }
145
+ }
146
+
147
+ this.collectionView.dataSet.commitUpdates();
148
+ }
149
+ });
150
+ }
151
+
152
+ /**
153
+ * Initializes the name editor behaviours.
154
+ */
155
+ _initNameEditor() {
156
+ let initialName;
157
+
158
+ this.variableName.addEventListener('focus', async event => {
159
+ initialName = this._variable.name;
160
+ this.variableName.select();
161
+ this.retain();
162
+ const fn = event => event.preventDefault();
163
+ this.variableName.addEventListener('mouseup', fn);
164
+ await new Promise(resolve => setTimeout(resolve, 200));
165
+ this.variableName.removeEventListener('mouseup', fn);
166
+ });
167
+ this.variableName.addEventListener('blur', async event => {
168
+ let newName = this.variableName.value.trim();
169
+ if (newName != initialName) {
170
+ // Check that this new name is not used by any other variable
171
+ let hasNewName = NO;
172
+ for (const variable of this.collectionView.dataSet.variables) {
173
+ if (variable.name == newName) {
174
+ hasNewName = YES;
175
+ break;
176
+ }
177
+ }
178
+
179
+ if (!hasNewName) {
180
+ // Instruct the variable provider to rename the layout variable
181
+ this.editor.layoutVariableProvider.renameLayoutVariableNamed(initialName, {toName: newName});
182
+
183
+ // Also update the data set item backing the UI
184
+ for (const variable of this.collectionView.dataSet.variables) {
185
+ if (variable.name == initialName) {
186
+ variable.name = newName;
187
+ }
188
+ }
189
+ }
190
+ else {
191
+ // If there are naming collisions, restore the initial name
192
+ this.variableName.value = initialName;
193
+
194
+ await __BMVelocityAnimate(this.variableName, {translateX: '20px'}, {duration: 50, ease: 'easeOutQuad'});
195
+ await __BMVelocityAnimate(this.variableName, {translateX: '-20px'}, {duration: 100, ease: 'easeInOutQuad'});
196
+ __BMVelocityAnimate(this.variableName, {translateX: '0px'}, {duration: 50, ease: 'easeInQuad'})
197
+ }
198
+ }
199
+ this.release();
200
+ });
201
+ }
202
+
203
+ _initValueEditor() {
204
+ this.variableValue.addEventListener('focus', async event => {
205
+ this.variableValue.select();
206
+ this.retain();
207
+ const fn = event => event.preventDefault();
208
+ this.variableValue.addEventListener('mouseup', fn);
209
+ await new Promise(resolve => setTimeout(resolve, 200));
210
+ this.variableValue.removeEventListener('mouseup', fn);
211
+ });
212
+ this.variableValue.addEventListener('input', event => {
213
+ let newValue = parseFloat(this.variableValue.value.trim());
214
+ if (!isNaN(newValue)) {
215
+ // Update the local value of the variable
216
+ this._variable.value = newValue;
217
+ // Instruct the provider to update the value as well
218
+ if (this._variable.sizeClass) {
219
+ this.editor.layoutVariableProvider.setLayoutVariableValue(newValue, {named: this._variable.name, inSizeClass: this._variable.sizeClass});
220
+ }
221
+ else {
222
+ this.editor.layoutVariableProvider.registerLayoutVariableNamed(this._variable.name, {withValue: newValue});
223
+ }
224
+ }
225
+ })
226
+ this.variableValue.addEventListener('blur', async event => this.release());
227
+ }
228
+
229
+ /**
230
+ * The represented layout variable variation.
231
+ */
232
+ get variable() { // <BMLayoutVariableVariation>
233
+ return this._variable;
234
+ }
235
+ set variable(variable) {
236
+ this._variable = variable;
237
+
238
+ if (variable.sizeClass) {
239
+ this.addVariationButton.style.visibility = 'hidden';
240
+ this.sizeClassBadge.style.display = 'block';
241
+ this.variableName.style.display = 'none';
242
+
243
+ // TODO: Optimize this
244
+ const badge = this.editor.settingsBadgeForSizeClass(variable.sizeClass);
245
+ this.sizeClassBadge.className = badge.className;
246
+ this.sizeClassBadge.innerText = badge.innerText;
247
+
248
+ this.node.classList.remove('BMLayoutEditorVariableMain');
249
+ }
250
+ else {
251
+ this.addVariationButton.style.visibility = 'visible';
252
+ this.sizeClassBadge.style.display = 'none';
253
+ this.variableName.style.display = 'block';
254
+
255
+ this.node.classList.add('BMLayoutEditorVariableMain');
256
+ }
257
+
258
+ this.variableValue.value = variable.value;
259
+ this.variableName.value = variable.name;
260
+ }
261
+
262
+ }
263
+
264
+ // @endtype
265
+
266
+ // @type BMLayoutEditorEmptyVariablesCell extends BMCollectionViewCell
267
+
268
+ /**
269
+ * A collection view cell that displays a message to the user when no layout variables are displayed.
270
+ */
271
+ export class BMLayoutEditorEmptyVariablesCell extends BMCollectionViewCell {
272
+ initWithCollectionView(collectionView, args) {
273
+ super.initWithCollectionView(collectionView, args);
274
+
275
+ const layoutVariablesAvailable = collectionView.dataSet.provider.canUseLayoutVariables();
276
+
277
+ const title = document.createElement('div');
278
+ title.innerText = layoutVariablesAvailable ? 'No Layout Variables Defined' : 'Layout Variables Unavailable';
279
+ title.className = 'BMWindowLabel BMLayoutEditorMessageTitle';
280
+ this.node.appendChild(title);
281
+
282
+ const description = document.createElement('div');
283
+ description.innerText = layoutVariablesAvailable ? 'Use the "Add Variable" button below to add a layout variable.' : collectionView.dataSet.provider.unavailableLayoutVariablesUserLabel();
284
+ description.className = 'BMWindowLabel BMLayoutEditorMessageDescription';
285
+ this.node.appendChild(description);
286
+
287
+ this.node.classList.add('BMLayoutEditorEmptyVariableMessage');
288
+
289
+ return this;
290
+ }
291
+ }
292
+
293
+ // @endtype
294
+
295
+ // @type BMLayoutEditorVariablesDataSet implements BMCollectionViewDataSet, BMCollectionViewDelegate
296
+
297
+ /**
298
+ * A data set object that manages the display of layout variables and their variations in a layout editor.
299
+ */
300
+ export class BMLayoutEditorVariablesDataSet {
301
+
302
+ /**
303
+ * Initializes this data set with the given layout variable provider object.
304
+ * @param provider <BMLayoutVariableProvider> The layout variable provider to use.
305
+ * {
306
+ * @param collectionView <BMCollectionView> The collection view using this data set.
307
+ * @param editor <BMLayoutEditor> The layout editor using this data set.
308
+ * }
309
+ * @return <BMLayoutEditorVariablesDataSet> This data set object.
310
+ */
311
+ initWithLayoutVariableProvider(provider, {collectionView, editor}) {
312
+ this.provider = provider;
313
+ this.variables = [];
314
+
315
+ // Build the flat list of layout variables which can be used by collection view
316
+ const declaredVariables = provider.layoutVariables;
317
+ for (const variable in declaredVariables) {
318
+ this.variables.push({name: variable, value: declaredVariables[variable]});
319
+
320
+ const variations = provider.variationsForLayoutVariableNamed(variable);
321
+ for (const variation of variations) {
322
+ this.variables.push(variation);
323
+ }
324
+ }
325
+
326
+ this.collectionView = collectionView;
327
+ this.editor = editor;
328
+ return this;
329
+ }
330
+
331
+ numberOfSections() {
332
+ return Math.min(this.variables.length, 1);
333
+ }
334
+
335
+ numberOfObjectsInSectionAtIndex(index) {
336
+ return this.variables.length;
337
+ }
338
+
339
+ indexPathForObjectAtRow(row) {
340
+ return BMIndexPathMakeWithRow(row, {section: 0, forObject: this.variables[row]});
341
+ }
342
+
343
+ indexPathForObject(object) {
344
+ for (let i = 0; i < this.variables.length; i++) {
345
+ const variable = this.variables[i];
346
+
347
+ if (variable.name == object.name && variable.sizeClass == object.sizeClass) {
348
+ return BMIndexPathMakeWithRow(i, {section: 0, object: variable});
349
+ }
350
+ }
351
+ }
352
+
353
+ cellForItemAtIndexPath(indexPath) {
354
+ const cell = this.collectionView.dequeueCellForReuseIdentifier('Variable');
355
+ cell.editor = this.editor;
356
+ cell.variable = indexPath.object;
357
+ return cell;
358
+ }
359
+
360
+ cellForSupplementaryViewWithIdentifier(identifier, args) {
361
+ return this.collectionView.dequeueCellForSupplementaryViewWithIdentifier(identifier);
362
+ }
363
+
364
+ beginUpdates() {
365
+ this._oldData = this.variables.slice();
366
+ this._newData = this.variables;
367
+ }
368
+
369
+ useOldData(use) {
370
+ if (use) {
371
+ this.variables = this._oldData;
372
+ }
373
+ else {
374
+ this.variables = this._newData;
375
+ }
376
+ }
377
+
378
+ isUsingOldData() {
379
+ return this.variables === this._newData;
380
+ }
381
+
382
+ commitUpdates() {
383
+ return this.commitUpdatesWithCompletionHandler();
384
+ }
385
+
386
+ commitUpdatesWithCompletionHandler(handler) {
387
+ this.collectionView.updateEntireDataAnimated(YES, {completionHandler: handler});
388
+ this.variables = this._newData;
389
+ this._oldData = undefined;
390
+ }
391
+
392
+ addVariable() {
393
+ this.beginUpdates();
394
+
395
+ let name = 'new variable';
396
+ let i = 0;
397
+
398
+ // Find a unique name for this new layout variable
399
+ while (YES) {
400
+ let hasName = NO;
401
+
402
+ for (var j = 0; j < this.variables.length; j++) {
403
+ if (this.variables[j].name == name) {
404
+ hasName = YES;
405
+ break;
406
+ }
407
+ }
408
+
409
+ if (!hasName) {
410
+ break;
411
+ }
412
+ else {
413
+ i++;
414
+ name = 'new variable ' + i;
415
+ }
416
+ }
417
+
418
+ // Add it to the UI and to the provider
419
+ this.variables.push({name: name, value: 0});
420
+ this.provider.registerLayoutVariableNamed(name, {withValue: 0});
421
+
422
+ this.commitUpdatesWithCompletionHandler(() => {
423
+ // After the animation finishes, focus the new property's name
424
+ var newVariableIndexPath = this.indexPathForObjectAtRow(this.variables.length - 1, {inSectionAtIndex: 0});
425
+ var newVariableCell = this.collectionView.cellAtIndexPath(newVariableIndexPath);
426
+
427
+ if (newVariableCell) {
428
+ newVariableCell.node.querySelector('.BMLayoutEditorVariableName').focus();
429
+
430
+ this.collectionView.scrollToCellAtIndexPath(newVariableIndexPath, {animated: YES});
431
+ }
432
+ else {
433
+ // If the newly created property is not in view, its cell must be created before it can be focused
434
+ newVariableCell = this.collectionView.retainCellForIndexPath(newVariableIndexPath);
435
+ newVariableCell.node.querySelector('.BMLayoutEditorVariableName').focus();
436
+
437
+ // Because any input acquiring focus will cause its owning cell to be retained, the cell may be released from here
438
+ newVariableCell.release();
439
+
440
+ this.collectionView.scrollToCellAtIndexPath(newVariableIndexPath, {animated: YES});
441
+ }
442
+ });
443
+ }
444
+
445
+ collectionViewCanSelectCellAtIndexPath() {
446
+ return NO;
447
+ }
448
+
449
+ collectionViewSizeForCellAtIndexPath(collectionView, indexPath) {
450
+ if (!indexPath.object.sizeClass) {
451
+ return BMSizeMake(1, 48);
452
+ }
453
+ else {
454
+ return BMSizeMake(1, 32);
455
+ }
456
+ }
457
+
458
+ }
459
+
460
+ // @endtype