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,1813 @@
1
+ // @ts-check
2
+
3
+ import {YES, NO, BMExtend, BMCopyProperties, BMUUIDMake} from '../Core/BMCoreUI'
4
+ import {BMLayoutSizeClass} from './BMLayoutSizeClass'
5
+ import * as kiwi from 'kiwi.js'
6
+
7
+ // @type BMLayoutAttribute
8
+
9
+ /**
10
+ * Constants representing the layout attributes used by the CoreUI layout engine.
11
+ */
12
+ export var BMLayoutAttribute = Object.freeze({ // <enum>
13
+
14
+ /**
15
+ * The attribute corresponding to a view's leading edge.
16
+ * This is the same as the left edge in a left-to-right layout and
17
+ * the same as the right edge in a right-to-left layout.
18
+ */
19
+ Leading: 'Leading', // <enum>
20
+
21
+
22
+ /**
23
+ * The attribute corresponding to a view's trailing edge.
24
+ * This is the same as the right edge in a left-to-right layout and
25
+ * the same as the left edge in a right-to-left layout.
26
+ */
27
+ Trailing: 'Trailing', // <enum>
28
+
29
+
30
+ /**
31
+ * The attribute corresponding to a view's left edge.
32
+ */
33
+ Left: 'Left', // <enum>
34
+
35
+
36
+ /**
37
+ * The attribute corresponding to a view's right edge.
38
+ */
39
+ Right: 'Right', // <enum>
40
+
41
+
42
+ /**
43
+ * The attribute corresponding to a view's top edge.
44
+ */
45
+ Top: 'Top', // <enum>
46
+
47
+
48
+ /**
49
+ * The attribute corresponding to a view's bottom edge.
50
+ */
51
+ Bottom: 'Bottom', // <enum>
52
+
53
+
54
+ /**
55
+ * The attribute corresponding to a view's horizontal center.
56
+ */
57
+ CenterX: 'CenterX', // <enum>
58
+
59
+
60
+ /**
61
+ * The attribute corresponding to a view's vertical center.
62
+ */
63
+ CenterY: 'CenterY', // <enum>
64
+
65
+
66
+ /**
67
+ * The attribute corresponding to a view's width.
68
+ */
69
+ Width: 'Width', // <enum>
70
+
71
+
72
+ /**
73
+ * The attribute corresponding to a view's height.
74
+ */
75
+ Height: 'Height', // <enum>
76
+
77
+
78
+ /**
79
+ * The attribute corresponding to a view's aspect ratio.
80
+ */
81
+ AspectRatio: 'AspectRatio' // <enum>
82
+
83
+ });
84
+
85
+ // @endtype
86
+
87
+ // @type BMLayoutConstraintRelation
88
+
89
+ /**
90
+ * Constants that describe the equality or inequality relation between the two sides of a constraint.
91
+ */
92
+ export var BMLayoutConstraintRelation = Object.freeze({ // <enum>
93
+
94
+
95
+ /**
96
+ * Indicates that the two sides of the constraint's equation should be equal.
97
+ */
98
+ Equals: kiwi.Operator.Eq, // <enum>
99
+
100
+
101
+ /**
102
+ * Indicates that the source view's attribute's value should be less than the right-hand side expression's value.
103
+ */
104
+ LessThanOrEquals: kiwi.Operator.Le, // <enum>
105
+
106
+
107
+ /**
108
+ * Indicates that the source view's attribute's value should be greater than the right-hand side expression's value.
109
+ */
110
+ GreaterThanOrEquals: kiwi.Operator.Ge, // <enum>
111
+
112
+ });
113
+
114
+ // @endtype
115
+
116
+ // @type BMLayoutConstraintKind
117
+
118
+ /**
119
+ * Constants that describe what type of view attribute a layout constraint affects.
120
+ */
121
+ export var BMLayoutConstraintKind = Object.freeze({ // <enum>
122
+
123
+
124
+ /**
125
+ * Indicates that this constraint affects a horizontal attribute.
126
+ */
127
+ Horizontal: 'BMLayoutConstraintKindHorizontal', // <enum>
128
+
129
+
130
+ /**
131
+ * Indicates that this constraint affects a vertical attribute.
132
+ */
133
+ Vertical: 'BMLayoutConstraintKindVertical', // <enum>
134
+
135
+
136
+ /**
137
+ * Indicates that this constraint affects the aspect ratio.
138
+ */
139
+ AspectRatio: 'BMLayoutConstraintKindAspectRatio', // <enum>
140
+
141
+ });
142
+
143
+ // @endtype
144
+
145
+ const _BMLayoutConstraintClasses = {BMLayoutConstraint, BMEqualAttributeLayoutConstraint, BMEqualSpacingLayoutConstraint}
146
+
147
+ // @type BMLayoutConstraint
148
+
149
+ /**
150
+ * A layout constraint is a mathematical equality or inequality between two layout attributes on a view.
151
+ *
152
+ * They are used as rules by the CoreUI layout engine to lay out views.
153
+ *
154
+ * A constraint is a linear equation that takes the form of
155
+ * ```js
156
+ view1.attribute1 = multiplier * view2.attribute2 + constant
157
+ ```
158
+ * where the equals sign can be replaced with an inequality sign as needed.
159
+ * Note that despite looking like an assignment statement, the constraint expression is a mathematical equation and the layout
160
+ * system may choose to modify either side (or even both) of the equation to fulfill the constraint's requirements.
161
+ *
162
+ * There are four types of layout constraints: vertical position, horizontal position, width and height.
163
+ * Each of them controls a specific aspect of a view's layout. A view must have constraints which clearly define all four of those
164
+ * attributes for the layout system to be able to size it and position it correctly.
165
+ * Additionally, constraints having an attribute of a type on the left hand side of the equation can only have an attribute of the same type on the right hand side.
166
+ * In other words, for example, a view's vertical positioning can only depend on the vertical positioning of another view and not on its horizontal positioning or its size.
167
+ * For views that have intrinsic sizes, the sizing constraints are optional as the intrinsic sizes of the views will be used by default as size constraint inequalities.
168
+ * In addition, it is also possible to specify a constraint for a view's aspect ratio by linking its width to its own height.
169
+ * Similarly, it is also possible to specify a constraint that makes a view's aspect ratio depend upon the aspect ratio of another view.
170
+ * When creating an aspect ratio constraint, this may only be to another view's aspect ratio.
171
+ *
172
+ * Constraints may also have a priority value assigned to them. All constraints with a priority value lower than <code>BMLayoutConstraintPriorityRequired</code> are considered
173
+ * optional. The layout system will try to fulfill them, but it does not guarantee that it will do so and optional constraints may be ignored if it is needed to do so to fulfill
174
+ * the required constraints. When an optional constraint cannot be fulfilled, the layout system may nevertheless attempt to change the values of the attributes so that they are
175
+ * as close as possible to fulfill the optional constraint without breaking the required constraints.
176
+ */
177
+ export function BMLayoutConstraint() {} // <constructor>
178
+
179
+ /**
180
+ * The priority value indicating that the constraint is required to be fulfilled.
181
+ */
182
+ export var BMLayoutConstraintPriorityRequired = 1000; // <Number>
183
+
184
+ /**
185
+ * Constructs and returns an internal layout constraint initialized with the given values.
186
+ * The constraint will be marked inactive by default. Internal constraints are marked automatically as active
187
+ * by CoreUI when needed.
188
+ * @param view <BMView> The source view.
189
+ * {
190
+ * @param attribute <BMLayoutAttribute> The source view's attribute.
191
+ * @param relatedBy <BMLayoutConstraintRelation, nullable> Defaults to .Equals. The equation's equality or inequality sign.
192
+ * @param toView <BMView, nullable> The view to which the source view's attribute is related.
193
+ * If omitted, the constraint will cause the view's attribute to be
194
+ * solely related to the equation's constant component.
195
+ * @param secondAttribute <BMLayoutAttribute, nullable> The second view's attribute. May only be omitted if the second view is also omitted.
196
+ * @param multiplier <Number, nullable> Defaults to 1. The equation's multiplier.
197
+ * @param constant <Number, nullable> Defaults to 0. The equation's constant component.
198
+ * @param priority <Number, nullable> Defaults to </code>BMLayoutConstraintPriorityRequired</code>.
199
+ * The constraint's priority.
200
+ * }
201
+ */
202
+ BMLayoutConstraint.internalConstraintWithView = function (view, args) {
203
+ args._internal = YES;
204
+ let constraint = BMLayoutConstraint.constraintWithView(view, args);
205
+ return constraint;
206
+ }
207
+
208
+ /**
209
+ * Constructs and returns a layout constraint initialized with the given values.
210
+ * The constraint will be marked inactive by default. You must set the constraint's
211
+ * <code>isActive</code> property to <code>YES</code> to make this constraint take part in layout calculations.
212
+ * @param view <BMView> The source view.
213
+ * {
214
+ * @param attribute <BMLayoutAttribute> The source view's attribute.
215
+ * @param relatedBy <BMLayoutConstraintRelation, nullable> Defaults to .Equals. The equation's equality or inequality sign.
216
+ * @param toView <BMView, nullable> The view to which the source view's attribute is related.
217
+ * If omitted, the constraint will cause the view's attribute to be
218
+ * solely related to the equation's constant component.
219
+ * @param secondAttribute <BMLayoutAttribute, nullable> The second view's attribute. May only be omitted if the second view is also omitted.
220
+ * @param multiplier <Number, nullable> Defaults to 1. The equation's multiplier.
221
+ * @param constant <Number or String, nullable> Defaults to 0. The equation's constant component.
222
+ * @param priority <Number, nullable> Defaults to </code>BMLayoutConstraintPriorityRequired</code>.
223
+ * The constraint's priority.
224
+ * }
225
+ * @return <BMLayoutConstraint> A layout constraint.
226
+ */
227
+ BMLayoutConstraint.constraintWithView = function (view, args) {
228
+ var constraint = new BMLayoutConstraint();
229
+
230
+ constraint._identifier = BMUUIDMake();
231
+
232
+ constraint._sourceView = view;
233
+ constraint._sourceViewAttribute = args.attribute;
234
+
235
+ constraint._relation = args.relatedBy === undefined ? BMLayoutConstraintRelation.Equals : args.relatedBy;
236
+
237
+ constraint._targetView = args.toView;
238
+ constraint._targetViewAttribute = args.secondAttribute;
239
+
240
+ constraint._multiplier = isNaN(args.multiplier) ? 1 : args.multiplier;
241
+ constraint._constant = args.constant || 0;
242
+
243
+ if (args.priority) {
244
+ constraint._priority = args.priority;
245
+ }
246
+ else {
247
+ constraint._priority = BMLayoutConstraintPriorityRequired;
248
+ }
249
+
250
+ if (args.attribute === BMLayoutAttribute.AspectRatio) {
251
+ constraint._kind = BMLayoutConstraintKind.AspectRatio;
252
+ }
253
+ else if (args.attribute === BMLayoutAttribute.Top || args.attribute == BMLayoutAttribute.Bottom || args.attribute === BMLayoutAttribute.Height || args.attribute === BMLayoutAttribute.CenterY) {
254
+ constraint._kind = BMLayoutConstraintKind.Vertical;
255
+ }
256
+ else {
257
+ constraint._kind = BMLayoutConstraintKind.Horizontal;
258
+ }
259
+
260
+ constraint._variations = {};
261
+ constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
262
+ if (typeof constraint._constant == 'string') {
263
+ constraint._configuration.constantValue = view.rootView.valueForLayoutVariable(constraint._constant);
264
+ }
265
+ else {
266
+ constraint._configuration.constantValue = constraint._constant;
267
+ }
268
+
269
+
270
+ // When creating temporary internal constraints, they should not be added to the views
271
+ if (!args._internal) {
272
+ constraint._install();
273
+ }
274
+ else {
275
+ constraint._internal = YES;
276
+ }
277
+
278
+ return constraint;
279
+
280
+ };
281
+
282
+
283
+ /**
284
+ * Creates and returns a constraint with the values of the given serialized constraint.
285
+ * @param constraint <AnyObject> The serialized constraint.
286
+ * {
287
+ * @param viewIDs <BMView ^(String)> A block that is invoked for each view ID affected by the constraint.
288
+ * The block is given a String ID and is expected to return the corresponding
289
+ * view instance.
290
+ * }
291
+ * @return <BMLayoutConstraint, nullable> The constraint, or `undefined` if the constraint could not be deserialized.
292
+ */
293
+ BMLayoutConstraint.constraintWithSerializedConstraint = function (constraint, args) {
294
+ return Object.create(_BMLayoutConstraintClasses[constraint._class || 'BMLayoutConstraint'].prototype).initWithSerializedConstraint(constraint, args);
295
+ }
296
+
297
+ BMLayoutConstraint.prototype = {
298
+
299
+ /**
300
+ * A unique identifier assigned to this constraint. A random identifier is generated by CoreUI whenever a constraint
301
+ * is created, but the value of this property is not currently not used by CoreUI and can be freely modified after
302
+ * the constraint has been created.
303
+ *
304
+ * The identifier can be used to quickly obtain a reference to a specific constraint from its view hierarchy via the
305
+ * `constraintWithIdentifier(_)` method on views.
306
+ */
307
+ _identifier: undefined, // <String>
308
+ get identifier() { return this._identifier },
309
+ set identifier(identifier) {
310
+ this._identifier = identifier;
311
+ },
312
+
313
+ /**
314
+ * The Cassowary solver to which this layout constraint has been attached.
315
+ */
316
+ _solver: undefined, // <kiwi.Solver>
317
+
318
+ /**
319
+ * The Cassowary constraint represented by this layout constraint.
320
+ */
321
+ _constraint: undefined, // <kiwi.Constraint>
322
+
323
+ /**
324
+ * Initializes this constraint with the values of the given serialized constraint.
325
+ * @param constraint <AnyObject> The serialized constraint.
326
+ * {
327
+ * @param viewIDs <BMView ^(String)> A block that is invoked for each view ID affected by the constraint.
328
+ * The block is given a String ID and is expected to return the corresponding
329
+ * view instance.
330
+ * }
331
+ * @return <BMLayoutConstraint, nullable> This constraint, or `undefined` if the constraint could not be deserialized.
332
+ */
333
+ initWithSerializedConstraint(constraint, args) {
334
+ this._sourceViewAttribute = constraint._sourceViewAttribute;
335
+ this._relation = constraint._relation;
336
+ this._targetViewAttribute = constraint._targetViewAttribute;
337
+ this._multiplier = constraint._multiplier;
338
+ this._constant = constraint._constant;
339
+ this._kind = constraint._kind;
340
+ this._priority = constraint._priority;
341
+ this._sourceView = args.viewIDs(constraint._sourceView);
342
+ this._identifier = constraint._identifier || BMUUIDMake();
343
+
344
+ this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
345
+
346
+ if (!this._sourceView) return undefined;
347
+ if (constraint._targetView) {
348
+ this._targetView = args.viewIDs(constraint._targetView);
349
+ if (!this._targetView) return undefined;
350
+ }
351
+
352
+ // For variations, it is required to re-create the size class object references from their hash strings
353
+ this._variations = constraint._variations || {};
354
+ for (let key in this._variations) {
355
+ this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
356
+ }
357
+
358
+ // Create the configuration
359
+ this._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
360
+ this._updateConfiguration();
361
+
362
+ this._install();
363
+
364
+ return this;
365
+ },
366
+
367
+ /**
368
+ * Returns an array containing the attributes that this constraint affects
369
+ * for the given view. If this constraint does not affect that view, an empty
370
+ * array will be returned.
371
+ * @param view <BMView> The view.
372
+ * @return <[BMLayoutAttribute]> The list off affected attributes.
373
+ */
374
+ affectedAttributesForView(view) {
375
+ let attributes = [];
376
+
377
+ if (view == this._sourceView) return [this._sourceViewAttribute];
378
+ if (view == this._targetView) return [this._targetViewAttribute];
379
+
380
+ return attributes;
381
+ },
382
+
383
+ /**
384
+ * Returns <code>YES</code> if this constraint represents a constraint collection.
385
+ */
386
+ get isConstraintCollection() {
387
+ return NO;
388
+ },
389
+
390
+ /**
391
+ * Returns an array of primitive constraints that make up this constraint.
392
+ * For primitive constraints, this will return an array containing only this constraint.
393
+ */
394
+ get constituentConstraints() {
395
+ return [this];
396
+ },
397
+
398
+ /**
399
+ * Used by the CoreUI layout editor to determine if the constant for this constraint may be modified.
400
+ * For primitive constraints this is always `YES`.
401
+ */
402
+ get _hasEditableConstant() {
403
+ return YES;
404
+ },
405
+
406
+ /**
407
+ * The source view, on the left hand side of the equation.
408
+ */
409
+ _sourceView: undefined, // <BMView>
410
+
411
+ /**
412
+ * The source view's attribute involved in the equation.
413
+ */
414
+ _sourceViewAttribute: undefined, // <BMLayoutAttribute>
415
+
416
+ /**
417
+ * The target view, on the right hand side of the equation.
418
+ * If this property is not specified, this will be interpreted as a constant constraint.
419
+ */
420
+ _targetView: undefined, // <BMView, nullable>
421
+
422
+ /**
423
+ * The target view's attribute involved in the equation.
424
+ * This property must be specified if <code>targetView</code> is also specified.
425
+ */
426
+ _targetViewAttribute: undefined, // <BMLayoutAttribute, nullable>
427
+
428
+ /**
429
+ * The equation's multiplier component.
430
+ */
431
+ _multiplier: 1, // <Number>
432
+
433
+ /**
434
+ * An object that describes the active configuration for the properties that can vary
435
+ * based on size classes for this layout constraint.
436
+ */
437
+ _configuration: undefined, // <Object>
438
+
439
+ /**
440
+ * Invoked by CoreUI when the active size classes change for the view hierarchy
441
+ * to which this constraint belongs. This causes the constraint to update its configuration
442
+ * to match the new size classes, based on its variations.
443
+ * @param sizeClasses <[BMLayoutSizeClass]> The active size classes.
444
+ */
445
+ activeSizeClassesDidChange(sizeClasses) {
446
+ this._updateConfiguration();
447
+ },
448
+
449
+ /**
450
+ * Invoked by CoreUI when the value of any layout variable changes for the view hierarchy to which this contraint
451
+ * belongs. If this constraint uses a layout variable as its constant value, it will update the value of its constant accordingly.
452
+ */
453
+ layoutVariablesDidChange() {
454
+ if (typeof this._configuration.constant == 'string') {
455
+ this._updateConfiguration();
456
+ }
457
+ },
458
+
459
+ /**
460
+ * Invoked by CoreUI whenever size classes are invalidated or variations are introduced for this
461
+ * layout constraint to cause the configuration used by this layout constraint to be updated.
462
+ */
463
+ _updateConfiguration() {
464
+ return this._updateConfigurationSilently(NO);
465
+ },
466
+
467
+ /**
468
+ * Invoked by CoreUI whenever size classes are invalidated or variations are introduced for this
469
+ * layout constraint to cause the configuration used by this layout constraint to be updated.
470
+ * @param silently <Boolean> `YES` if this change should be silent, `NO` otherwise. If this change
471
+ * is silent, the internal configuration of this constraint will be updated, but this will
472
+ * not trigger any layout invalidations.
473
+ */
474
+ _updateConfigurationSilently(silently) {
475
+ let baseConfiguration = {constant: this._constant, priority: this._priority, isActive: this._isActive};
476
+ let viewport = (this._sourceView || this._views[0]).viewport;
477
+
478
+ // Check which variations should be active and in which order
479
+ for (let key in this._variations) {
480
+ this._variations[key]._matchPriority = viewport.matchPriorityForSizeClass(this._variations[key].sizeClass);
481
+ }
482
+
483
+ Object.keys(this._variations).map(key => this._variations[key]).sort((a, b) => b._matchPriority - a._matchPriority).forEach(variation => {
484
+ if (!variation._matchPriority) return;
485
+
486
+ if ('constant' in variation) baseConfiguration.constant = variation.constant;
487
+ if ('priority' in variation) baseConfiguration.priority = variation.priority;
488
+ if ('isActive' in variation) baseConfiguration.isActive = variation.isActive;
489
+ });
490
+
491
+ // Set to YES if the new configuration is different from the current configuration
492
+ let hasChanges = NO;
493
+
494
+ // Update the constant value accordingly
495
+ if (typeof baseConfiguration.constant == 'string') {
496
+ baseConfiguration.constantValue = this._sourceView.valueForLayoutVariable(baseConfiguration.constant);
497
+ }
498
+ else {
499
+ baseConfiguration.constantValue = baseConfiguration.constant;
500
+ }
501
+
502
+ // Update the configuration to the newly computed configuration
503
+ let oldConfiguration = this._configuration || baseConfiguration;
504
+ this._configuration = baseConfiguration;
505
+ if (this._reversesConstant) {
506
+ baseConfiguration.constantValue = -baseConfiguration.constantValue;
507
+ }
508
+
509
+ if (this.isConstraintCollection) {
510
+ for (let constraint of this.constituentConstraints) {
511
+ constraint._updateConfiguration();
512
+ }
513
+ return;
514
+ }
515
+
516
+ if (silently) return;
517
+
518
+ // Check how the configuration has changed and invalidate the layout accordingly
519
+ if (oldConfiguration.isActive != baseConfiguration.isActive) {
520
+ this._sourceView.needsLayout = YES;
521
+ this._sourceView.rootView._invalidatedConstraints = YES;
522
+ this._sourceView._checkConstraints();
523
+ if (this._targetView) {
524
+ this._targetView._checkConstraints();
525
+ }
526
+ hasChanges = YES;
527
+ }
528
+
529
+ if (oldConfiguration.priority != baseConfiguration.priority) {
530
+ this._sourceView.needsLayout = YES;
531
+ this._sourceView.rootView._invalidatedConstraints = YES;
532
+ hasChanges = YES;
533
+ }
534
+
535
+ if (oldConfiguration.constantValue != baseConfiguration.constantValue) {
536
+ if (!hasChanges) {
537
+ // Only modify the constant directly if there are no other changes; otherwise the next layout pass will handle this
538
+ hasChanges = YES;
539
+
540
+ // When changing the constant, update the attached solver, if there is one
541
+ if (this._solver) {
542
+ if (this._constraint) {
543
+ try {
544
+ if (this._solver.hasConstraint(this._constraint)) this._solver.removeConstraint(this._constraint);
545
+ }
546
+ catch (layoutError) {
547
+ this._cassowaryConstraint = undefined;
548
+ this._sourceView.rootView._invalidatedConstraints = YES;
549
+ this._sourceView.needsLayout = YES;
550
+ }
551
+ this._constraint = undefined;
552
+ }
553
+ // If this constant change causes the layout to be unsolvable, catch the error
554
+ // and trigger a full layout pass afterwards to invalidate this constraint
555
+ try {
556
+ this._solver.addConstraint(this._cassowaryConstraint);
557
+ }
558
+ catch (layoutError) {
559
+ this._cassowaryConstraint = undefined;
560
+ this._sourceView.rootView._invalidatedConstraints = YES;
561
+ this._sourceView.needsLayout = YES;
562
+ }
563
+ }
564
+
565
+ if (baseConfiguration.isActive) {
566
+ this._sourceView.needsLayout = YES;
567
+ }
568
+ }
569
+ }
570
+ },
571
+
572
+ /**
573
+ * @deprecated - Unused
574
+ * Returns an object containing the configuration for the current size class.
575
+ */
576
+ get _activeConfiguration() { // <Object>
577
+ let baseConfiguration = {constant: this._constant, priority: this._priority, isActive: this._isActive};
578
+
579
+ let sizeClass = this._sourceView.sizeClass;
580
+
581
+ // Find the list of size classes compatible with the view's size class
582
+ let compatibleVariations = [];
583
+ for (let key in this._variations) {
584
+ let variationSizeClass = this._variations[key].sizeClass;
585
+
586
+ if (variationSizeClass.matchesSizeClass(sizeClass)) {
587
+ compatibleVariations.push(this._variations[key]);
588
+ }
589
+ }
590
+
591
+ // Sort the size classes by priority, then copy over the variations in ascending priority order
592
+ compatibleVariations.sort((a, b) => b.sizeClass._priority - a.sizeClass._priority).forEach(variation => {
593
+ BMCopyProperties(baseConfiguration, variation);
594
+ });
595
+
596
+ // Return the composed configuration object
597
+ return baseConfiguration;
598
+ },
599
+
600
+ /**
601
+ * The equation's constant component.
602
+ */
603
+ _constant: 0, // <Number or String>
604
+ get constant() {
605
+ return this._constant;
606
+ },
607
+ set constant(constant) {
608
+ if (constant == this._constant) return;
609
+ this._constant = constant;
610
+ return this._updateConfiguration();
611
+
612
+ // When changing the constant, update the attached solver, if there is one
613
+ if (this._solver) {
614
+ if (this._constraint) {
615
+ this._solver.removeConstraint(this._constraint);
616
+ this._constraint = undefined;
617
+ }
618
+ this._solver.addConstraint(this._cassowaryConstraint);
619
+ }
620
+
621
+ if (this.isActive) {
622
+ this._sourceView.needsLayout = YES;
623
+ }
624
+ },
625
+
626
+ /**
627
+ * Sets this constraint's constant value for the given size class.
628
+ * @param constant <Number or String> The constant.
629
+ * {
630
+ * @param forSizeClass <BMLayoutSizeClass> The layout size class to which the constant should apply.
631
+ * }
632
+ */
633
+ setConstant(constant, args) {
634
+ if (!this._variations[args.forSizeClass._hashString]) {
635
+ this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
636
+ if (this.isConstraintCollection) {
637
+ this._views[0].rootView._invalidatedSizeClasses = YES;
638
+ }
639
+ else {
640
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
641
+ }
642
+ }
643
+
644
+ this._variations[args.forSizeClass._hashString].constant = constant;
645
+
646
+ // Update the configuration if this change affects the current size classes
647
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
648
+ this._updateConfiguration();
649
+ }
650
+ },
651
+
652
+ /**
653
+ * Removes this constraint's constant variation for the given size class.
654
+ * If this constraint doesn't have a constant variation for this size class, this method does nothing.
655
+ * @param sizeClass <BMLayoutSizeClass> The layout size class.
656
+ */
657
+ removeConstantVariationForSizeClass(sizeClass) {
658
+ if (this._variations[sizeClass._hashString]) {
659
+ // Delete the constant variation
660
+ delete this._variations[sizeClass._hashString].constant;
661
+
662
+ // Remove the variations object for this size class if there are no other variations left
663
+ if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
664
+ delete this._variations[sizeClass._hashString];
665
+ if (this.isConstraintCollection) {
666
+ this._views[0].rootView._invalidatedSizeClasses = YES;
667
+ }
668
+ else {
669
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
670
+ }
671
+ }
672
+
673
+ // Update the configuration if this change affects the current size classes
674
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
675
+ this._updateConfiguration();
676
+ }
677
+ }
678
+ },
679
+
680
+ /**
681
+ * Used to verify if this layout constraint has a constant variation for the given size class.
682
+ * @param sizeClass <BMLayoutSizeClass> The size class.
683
+ * @return <Boolean> `YES` if this constraint has a constant variation for the size class, `NO` otherwise.
684
+ */
685
+ hasConstantVariationForSizeClass(sizeClass) {
686
+ if (this._variations[sizeClass._hashString]) {
687
+ return 'constant' in this._variations[sizeClass._hashString];
688
+ }
689
+ return NO;
690
+ },
691
+
692
+ /**
693
+ * @deprecated - Unused
694
+ * Returns this constraint's constant for the currently active size class.
695
+ */
696
+ get activeConstant() { // <Number or String>
697
+ // TODO:
698
+ return this._configuration.constant;
699
+ let sizeClassHash = this._sourceView.sizeClass._hashString;
700
+
701
+ if ('constant' in this._variations[sizeClassHash]) {
702
+ return this._variations[sizeClassHash].constant;
703
+ }
704
+
705
+ return this._constant;
706
+ },
707
+
708
+ /**
709
+ * The constraint's priority.
710
+ */
711
+ _priority: BMLayoutConstraintPriorityRequired, // <Number>
712
+
713
+ get priority() {
714
+ return this._priority;
715
+ },
716
+ set priority(priority) {
717
+ if (this._priority != priority) {
718
+ this._priority = priority;
719
+ return this._updateConfiguration();
720
+
721
+ this._sourceView.needsLayout = YES;
722
+
723
+ if (this._targetView) this._targetView.needsLayout = YES;
724
+ this._sourceView.rootView._invalidatedConstraints = YES;
725
+ }
726
+ },
727
+
728
+ /**
729
+ * Sets this constraint's priority value for the given size class.
730
+ * @param priority <Number> The priority.
731
+ * {
732
+ * @param forSizeClass <BMLayoutSizeClass> The layout size class to which the priority should apply.
733
+ * }
734
+ */
735
+ setPriority(priority, args) {
736
+ if (!this._variations[args.forSizeClass._hashString]) {
737
+ this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
738
+ if (this.isConstraintCollection) {
739
+ this._views[0].rootView._invalidatedSizeClasses = YES;
740
+ }
741
+ else {
742
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
743
+ }
744
+ }
745
+
746
+ this._variations[args.forSizeClass._hashString].priority = priority;
747
+
748
+ // Update the configuration if this change affects the current size classes
749
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
750
+ this._updateConfiguration();
751
+ }
752
+ },
753
+
754
+ /**
755
+ * Removes this constraint's priority variation for the given size class.
756
+ * If this constraint doesn't have a priority variation for this size class, this method does nothing.
757
+ * @param sizeClass <BMLayoutSizeClass> The layout size class.
758
+ */
759
+ removePriorityVariationForSizeClass(sizeClass) {
760
+ if (this._variations[sizeClass._hashString]) {
761
+ // Delete the constant variation
762
+ delete this._variations[sizeClass._hashString].priority;
763
+
764
+ // Remove the variations object for this size class if there are no other variations left
765
+ if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
766
+ delete this._variations[sizeClass._hashString];
767
+ if (this.isConstraintCollection) {
768
+ this._views[0].rootView._invalidatedSizeClasses = YES;
769
+ }
770
+ else {
771
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
772
+ }
773
+ }
774
+
775
+ // Update the configuration if this change affects the current size classes
776
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
777
+ this._updateConfiguration();
778
+ }
779
+ }
780
+ },
781
+
782
+ /**
783
+ * Used to verify if this layout constraint has a priority variation for the given size class.
784
+ * @param sizeClass <BMLayoutSizeClass> The size class.
785
+ * @return <Boolean> `YES` if this constraint has a priority variation for the size class, `NO` otherwise.
786
+ */
787
+ hasPriorityVariationForSizeClass(sizeClass) {
788
+ if (this._variations[sizeClass._hashString]) {
789
+ return 'priority' in this._variations[sizeClass._hashString];
790
+ }
791
+ return NO;
792
+ },
793
+
794
+ /**
795
+ * @deprecated - Unused
796
+ * Returns this constraint's priority for the currently active size class.
797
+ */
798
+ get activePriority() { // <Number>
799
+ // TODO:
800
+ return this._configuration.priority;
801
+ let sizeClassHash = this._sourceView.sizeClass._hashString;
802
+
803
+ if ('priority' in this._variations[sizeClassHash]) {
804
+ return this._variations[sizeClassHash].priority;
805
+ }
806
+
807
+ return this._priority;
808
+ },
809
+
810
+ /**
811
+ * The equation sign.
812
+ */
813
+ _relation: BMLayoutConstraintRelation.Equals, // <BMLayoutConstraintRelation>
814
+
815
+ /**
816
+ * The kind of layout constraint.
817
+ */
818
+ _kind: undefined, // <BMLayoutConstraintKind>
819
+
820
+ /**
821
+ * Returns a string representing this constraint's category, for debugging purposes.
822
+ */
823
+ get categoryKind() { // <String>
824
+ if (this._kind == BMLayoutConstraintKind.Vertical) {
825
+ if (this._sourceViewAttribute == BMLayoutAttribute.Height) {
826
+ return 'Height';
827
+ }
828
+ else {
829
+ return 'Vertical Position';
830
+ }
831
+ }
832
+ else {
833
+ if (this._sourceViewAttribute == BMLayoutAttribute.Width) {
834
+ return 'Width';
835
+ }
836
+ else {
837
+ return 'Horizontal Position';
838
+ }
839
+ }
840
+ },
841
+
842
+ /**
843
+ * Defaults to NO. Should be set to YES to cause this constraint to become active and affect the layout.
844
+ *
845
+ * For newly created constraints, it is up to the developer to mark the constraint as active, however in most cases
846
+ * where constraints are created automatically, the view that manages the layout hierarchy will typically
847
+ * manage the active state of constraints it owns, based on the current set of size traits.
848
+ *
849
+ * This operation will throw an exception if the views to which the constraint is related are not part of the same view hierarchy.
850
+ */
851
+ _isActive: NO, // <Boolean>
852
+ get isActive() {
853
+ return this._isActive;
854
+ },
855
+ set isActive(active) {
856
+ if (active != this._isActive) {
857
+ this._isActive = active;
858
+ return this._updateConfiguration();
859
+ this._sourceView._checkConstraints();
860
+ this._sourceView.needsLayout = YES;
861
+ this._sourceView.rootView._invalidatedConstraints = YES;
862
+
863
+ if (this._targetView) {
864
+ if (this._targetView.rootView != this._sourceView.rootView) {
865
+ throw new Error('[BMCoreUI] Incorrectly attempting to activate a layout constraint that affects two views that do not share a common ancestor.');
866
+ }
867
+
868
+ this._targetView._checkConstraints();
869
+ this._targetView.needsLayout = YES;
870
+ }
871
+ }
872
+ },
873
+
874
+ /**
875
+ * Sets this constraint's active state for the given size class.
876
+ * @param isActive <Number> The active state.
877
+ * {
878
+ * @param forSizeClass <BMLayoutSizeClass> The layout size class to which the active state should apply.
879
+ * }
880
+ */
881
+ setIsActive(isActive, args) {
882
+ if (!this._variations[args.forSizeClass._hashString]) {
883
+ this._variations[args.forSizeClass._hashString] = {sizeClass: args.forSizeClass};
884
+ if (this.isConstraintCollection) {
885
+ this._views[0].rootView._invalidatedSizeClasses = YES;
886
+ }
887
+ else {
888
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
889
+ }
890
+ }
891
+
892
+ this._variations[args.forSizeClass._hashString].isActive = isActive;
893
+
894
+ // Update the configuration if this change affects the current size classes
895
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(args.forSizeClass)) {
896
+ this._updateConfiguration();
897
+ }
898
+ },
899
+
900
+ /**
901
+ * Removes this constraint's active variation for the given size class.
902
+ * If this constraint doesn't have a active variation for this size class, this method does nothing.
903
+ * @param sizeClass <BMLayoutSizeClass> The layout size class.
904
+ */
905
+ removeIsActiveVariationForSizeClass(sizeClass) {
906
+ if (this._variations[sizeClass._hashString]) {
907
+ // Delete the constant variation
908
+ delete this._variations[sizeClass._hashString].isActive;
909
+
910
+ // Remove the variations object for this size class if there are no other variations left
911
+ if (Object.keys(this._variations[sizeClass._hashString]).length == 1) {
912
+ delete this._variations[sizeClass._hashString];
913
+ if (this.isConstraintCollection) {
914
+ this._views[0].rootView._invalidatedSizeClasses = YES;
915
+ }
916
+ else {
917
+ this._sourceView.rootView._invalidatedSizeClasses = YES;
918
+ }
919
+ }
920
+
921
+ // Update the configuration if this change affects the current size classes
922
+ if ((this._sourceView || this._views[0]).viewport.matchesSizeClass(sizeClass)) {
923
+ this._updateConfiguration();
924
+ }
925
+ }
926
+ },
927
+
928
+ /**
929
+ * Used to verify if this layout constraint has an isActive variation for the given size class.
930
+ * @param sizeClass <BMLayoutSizeClass> The size class.
931
+ * @return <Boolean> `YES` if this constraint has an isActive variation for the size class, `NO` otherwise.
932
+ */
933
+ hasIsActiveVariationForSizeClass(sizeClass) {
934
+ if (this._variations[sizeClass._hashString]) {
935
+ return 'isActive' in this._variations[sizeClass._hashString];
936
+ }
937
+ return NO;
938
+ },
939
+
940
+ /**
941
+ * Returns `YES` if this constraint can affect the layout depending on the view hierarchy's current size class.
942
+ */
943
+ get affectsLayout() { // <Boolean>
944
+ return this._configuration.isActive;
945
+ let sizeClassHash = this._sourceView.sizeClass._hashString;
946
+
947
+ if ('isActive' in this._variations[sizeClassHash]) {
948
+ return this._variations[sizeClassHash].isActive;
949
+ }
950
+
951
+ return this._isActive;
952
+ },
953
+
954
+ /**
955
+ * Invoked internally to install this constraint onto the views it affects.
956
+ */
957
+ _install() {
958
+ this._sourceView._addConstraint(this);
959
+
960
+ if (this._targetView) {
961
+ this._targetView._addConstraint(this);
962
+ }
963
+
964
+ this._sourceView.rootView._invalidatedConstraints = YES;
965
+ },
966
+
967
+ /**
968
+ * Should be invoked when this constraint is no longer needed and should be removed from the views it affects.
969
+ * This constraint cannot be marked active after invoking this method.
970
+ */
971
+ remove() {
972
+ if (this._isActive) {
973
+ this._sourceView.needsLayout = YES;
974
+ }
975
+
976
+ this._isActive = NO;
977
+ this._sourceView._removeConstraint(this);
978
+ this._sourceView.rootView._invalidatedConstraints = YES;
979
+ if (this._targetView) {
980
+ this._targetView.needsLayout = YES;
981
+ this._targetView._removeConstraint(this);
982
+ this._sourceView.rootView._invalidatedConstraints = YES;
983
+ }
984
+
985
+ this._sourceView = undefined;
986
+ this._targetView = undefined;
987
+ },
988
+
989
+ /**
990
+ * Invoked internally by CoreUI to retrieve the Cassowary expression that will be
991
+ * generated by this layout constraint. This expression will be used as the basis of
992
+ * the Cassowary constraint that will finally be used in the layout calculations.
993
+ */
994
+ get _cassowaryExpression() { // <[kiwi.Expression]>
995
+ // Resolve the constant if it is a layout variable
996
+ let constant = this._configuration.constantValue || 0;
997
+ //if (typeof constant === 'string') constant = this._sourceView._layoutVariables[constant] || 0;
998
+
999
+ if (!this._targetView) {
1000
+ if (this._sourceViewAttribute == BMLayoutAttribute.AspectRatio) {
1001
+ // The aspect ratio is treated differently
1002
+ // It expressed as Ratio * Height - Width = 0
1003
+ return new kiwi.Expression(
1004
+ [constant, this._sourceView._variables[BMLayoutAttribute.Height]],
1005
+ [-1, this._sourceView._variables[BMLayoutAttribute.Width]]
1006
+ );
1007
+ }
1008
+ else {
1009
+ // All other attributes use expression provided by the view itself
1010
+ return constant ?
1011
+ this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute).plus(-constant) :
1012
+ this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute);
1013
+ }
1014
+ }
1015
+ else {
1016
+ if (this._sourceViewAttribute == BMLayoutAttribute.AspectRatio) {
1017
+ if (this._targetViewAttribute != BMLayoutAttribute.AspectRatio) {
1018
+ throw new Error('[BMCoreUI] Aspect ratio constraints must affect both views\' aspect ratio.');
1019
+ }
1020
+
1021
+ throw new Error('[BMCoreUI] Non-constant aspect ratio constraint are currently not supported.');
1022
+ }
1023
+
1024
+ // All two-view constraints are treated as the following epxression
1025
+ // View1.Attribute - Multiplier * View2.Attribute - Constant = 0
1026
+ var baseExpression = new kiwi.Expression(
1027
+ this._sourceView._cassowaryExpressionForLayoutAttribute(this._sourceViewAttribute)
1028
+ ).minus(
1029
+ this._targetView._cassowaryExpressionForLayoutAttribute(this._targetViewAttribute, {withMultiplier: this._multiplier})
1030
+ );
1031
+
1032
+ if (constant) {
1033
+ if (!this._sourceView.LTRLayout && this._kind == BMLayoutConstraintKind.Horizontal && this._sourceViewAttribute != BMLayoutAttribute.Width) {
1034
+ // Horizontal position RTL layouts need to have the constant's sign swapped
1035
+ baseExpression = baseExpression.plus(constant);
1036
+ }
1037
+ else {
1038
+ baseExpression = baseExpression.minus(constant);
1039
+ }
1040
+ }
1041
+
1042
+ return baseExpression;
1043
+ }
1044
+ },
1045
+
1046
+ /**
1047
+ * Invoked internally by CoreUI to retrieve the Cassowary constraint that will be
1048
+ * generated by this layout constraint.
1049
+ */
1050
+ get _cassowaryConstraint() {
1051
+ if (this._constraint) return this._constraint;
1052
+
1053
+ var expression = this._cassowaryExpression;
1054
+
1055
+ // CoreUI priorities go up to 1000 (Required)
1056
+ // which is mapped to the cassowary required strength value
1057
+ var priority = (this._configuration.priority == BMLayoutConstraintPriorityRequired ?
1058
+ kiwi.Strength.required :
1059
+ this._configuration.priority / 1000 * kiwi.Strength.required);
1060
+
1061
+ // Horizontal position RTL layouts need to have the inequality sign swapped
1062
+ let relation = this._relation;
1063
+ if (!this._sourceView.LTRLayout && this._kind == BMLayoutConstraintKind.Horizontal && this._sourceViewAttribute != BMLayoutAttribute.Width) {
1064
+ if (this._relation == BMLayoutConstraintRelation.GreaterThanOrEquals) {
1065
+ relation = BMLayoutConstraintRelation.LessThanOrEquals;
1066
+ }
1067
+ else if (this._relation == BMLayoutConstraintRelation.LessThanOrEquals) {
1068
+ relation = BMLayoutConstraintRelation.GreaterThanOrEquals;
1069
+ }
1070
+ }
1071
+
1072
+ // CoreUI expressions always use 0 on the right-hand side
1073
+ this._constraint = new kiwi.Constraint(expression, relation, undefined, priority);
1074
+ return this._constraint;
1075
+ },
1076
+
1077
+ /**
1078
+ * An object that specifies the variations supported by this layout constraint across
1079
+ * the size classes supported by its view hierarchy.
1080
+ */
1081
+ _variations: undefined, // <Dictionary<BMLayoutConstraintVariation>>
1082
+
1083
+ /**
1084
+ * Returns a variations object that can be serialized.
1085
+ */
1086
+ get _serializedVariations() {
1087
+ let variations = {};
1088
+
1089
+ if (this._variations) {
1090
+ Object.keys(this._variations).forEach(key => {
1091
+ variations[key] = {};
1092
+ Object.keys(this._variations[key]).forEach(key2 => {
1093
+ if (key2 == 'sizeClass') return;
1094
+ variations[key][key2] = this._variations[key][key2];
1095
+ })
1096
+ });
1097
+ }
1098
+
1099
+ return variations;
1100
+ },
1101
+
1102
+ /**
1103
+ * Returns a string representation of this constraint. This is
1104
+ * often used when generating layout-related debug messages.
1105
+ * The contents of the string depend on the currently active size classes.
1106
+ * @return <String> A string.
1107
+ */
1108
+ toString() {
1109
+ let operatorMap = {
1110
+ [BMLayoutConstraintRelation.Equals]: '=',
1111
+ [BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
1112
+ [BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
1113
+ }
1114
+
1115
+ if (this._targetView) {
1116
+
1117
+ let constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
1118
+
1119
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
1120
+ ${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
1121
+ ${constant}`;
1122
+ }
1123
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} ${this._configuration.constant} (${this._configuration.priority})`;
1124
+ },
1125
+
1126
+ /**
1127
+ * Returns a string representation of this constraint. This is
1128
+ * often used when generating layout-related debug messages.
1129
+ * The contents of the string depend on the currently active size classes.
1130
+ * @return <String> A string.
1131
+ */
1132
+ toCompactString() {
1133
+ let operatorMap = {
1134
+ [BMLayoutConstraintRelation.Equals]: '=',
1135
+ [BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
1136
+ [BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
1137
+ }
1138
+
1139
+ let sourceAttribute = this._sourceViewAttribute.charAt(0);
1140
+ if (this._sourceViewAttribute == BMLayoutAttribute.Left) sourceAttribute = 'Lf';
1141
+
1142
+ if (this._targetView) {
1143
+ let targetAttribute = this._targetViewAttribute.charAt(0);
1144
+ if (this._targetViewAttribute == BMLayoutAttribute.Left) targetAttribute = 'Lf';
1145
+
1146
+ let constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
1147
+
1148
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${sourceAttribute} ${operatorMap[this._relation]} \
1149
+ ${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${targetAttribute} \
1150
+ ${constant}`;
1151
+ }
1152
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${sourceAttribute} ${operatorMap[this._relation]} ${this._configuration.constant}`;
1153
+ },
1154
+
1155
+ /**
1156
+ * Returns a string representation of this constraint that is relative to the given view. This is
1157
+ * often used when generating layout-related debug messages.
1158
+ * The contents of the string depend on the currently active size classes.
1159
+ * @param view <BMView> The view for which to return the description.
1160
+ * @return <String> A string.
1161
+ */
1162
+ descriptionRelativeToView(view) {
1163
+ let operatorMap = {
1164
+ [BMLayoutConstraintRelation.Equals]: '=',
1165
+ [BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2265',
1166
+ [BMLayoutConstraintRelation.LessThanOrEquals]: '\u2264'
1167
+ }
1168
+
1169
+ if (this._sourceView !== view && this._targetView!== view) return this.toString();
1170
+
1171
+ if (this._targetView) {
1172
+ const constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
1173
+
1174
+ if (this._sourceView === view) {
1175
+ const constant = this._configuration.constant ? `${this._configuration.constant < 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
1176
+ return `${this._sourceViewAttribute} ${operatorMap[this._relation]} \
1177
+ ${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
1178
+ ${constant}`;
1179
+ }
1180
+ else {
1181
+ const constant = this._configuration.constant ? `${this._configuration.constant > 0 ? '-' : '+'} ${this._configuration.constant < 0 ? -this._configuration.constant : this._configuration.constant}` : '';
1182
+ const operatorMap = {
1183
+ [BMLayoutConstraintRelation.Equals]: '=',
1184
+ [BMLayoutConstraintRelation.GreaterThanOrEquals]: '\u2264',
1185
+ [BMLayoutConstraintRelation.LessThanOrEquals]: '\u2265'
1186
+ }
1187
+
1188
+ return `${this._targetViewAttribute} ${operatorMap[this._relation]} \
1189
+ ${(this._multiplier != 1 ? '(' : '')}${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} \
1190
+ ${constant}${(this._multiplier != 1 ? ') / ' + this._multiplier : '')}`
1191
+
1192
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
1193
+ ${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
1194
+ ${constant}`;
1195
+ }
1196
+
1197
+ return `${this._sourceView.debuggingName || this._sourceView.node.id}.${this._sourceViewAttribute} ${operatorMap[this._relation]} \
1198
+ ${(this._multiplier != 1 ? this._multiplier + '* ' : '')}${this._targetView.debuggingName || this._targetView.node.id}.${this._targetViewAttribute} \
1199
+ ${constant}`;
1200
+ }
1201
+
1202
+ return `${this._sourceViewAttribute} ${operatorMap[this._relation]} ${this._configuration.constant}`;
1203
+ },
1204
+
1205
+ /**
1206
+ * Returns an object representing this constraint that may be serialized to a string.
1207
+ * @param block <String ^(BMView)> A block that will be invoked for each view that this constraint affects.
1208
+ * The block is given the view instance and should return a string from which
1209
+ * a view reference may be obtained when this serialized representation is converted
1210
+ * back into a constraint.
1211
+ * @return <AnyObject> A serializable representation of this constraint.
1212
+ */
1213
+ serializedConstraintWithViewIDs(block) {
1214
+ return {
1215
+ _class: 'BMLayoutConstraint',
1216
+ _sourceViewAttribute: this._sourceViewAttribute,
1217
+ _relation: this._relation,
1218
+ _targetViewAttribute: this._targetViewAttribute,
1219
+ _constant: this._constant,
1220
+ _multiplier: this._multiplier,
1221
+ _priority: this._priority,
1222
+ _sourceView: block(this._sourceView),
1223
+ _targetView: this._targetView ? block(this._targetView) : undefined,
1224
+ _kind: this._kind,
1225
+ _identifier: this._identifier,
1226
+ _variations: this._serializedVariations,
1227
+ _isActive: this._isActive
1228
+ };
1229
+ }
1230
+
1231
+ };
1232
+
1233
+ // @endtype
1234
+
1235
+ // @type BMEqualAttributeLayoutConstraint extends BMLayoutConstraint
1236
+
1237
+ /**
1238
+ * An equal attribute layout constraint is a constraint collection that makes a given attribute
1239
+ * of a set of views have the same value.
1240
+ */
1241
+ export function BMEqualAttributeLayoutConstraint() {} // <constructor>
1242
+
1243
+ /**
1244
+ * Constructs and returns a constraint that makes all of the views given to it have the same value
1245
+ * for a given attribute.
1246
+ * @param attribute <BMLayoutAttribute> The attribute.
1247
+ * {
1248
+ * @param forViews <[BMView]> An array of views that this constraint affects. This array should contain at least
1249
+ * two views.
1250
+ * @param priority <Number, nullable> Defaults to <code>BMLayoutConstraintPriorityRequired</code>. The constraint's priority.
1251
+ * }
1252
+ * @return <BMEqualAttributeLayoutConstraint> A constraint.
1253
+ */
1254
+ BMEqualAttributeLayoutConstraint.constraintWithAttribute = function (attribute, args) {
1255
+ let constraint = new BMEqualAttributeLayoutConstraint();
1256
+
1257
+ constraint._identifier = BMUUIDMake();
1258
+
1259
+ constraint._views = args.forViews.slice();
1260
+ constraint._attribute = attribute;
1261
+ constraint._priority = args.priority || BMLayoutConstraintPriorityRequired;
1262
+
1263
+ if (attribute === BMLayoutAttribute.Top || attribute == BMLayoutAttribute.Bottom || attribute === BMLayoutAttribute.Height || attribute === BMLayoutAttribute.CenterY) {
1264
+ constraint._kind = BMLayoutConstraintKind.Vertical;
1265
+ }
1266
+ else {
1267
+ constraint._kind = BMLayoutConstraintKind.Horizontal;
1268
+ }
1269
+
1270
+ constraint._variations = {};
1271
+ constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
1272
+
1273
+ if (!args._internal) {
1274
+ constraint._install();
1275
+ }
1276
+ else {
1277
+ constraint._internal = YES;
1278
+ }
1279
+
1280
+ return constraint;
1281
+ }
1282
+
1283
+ BMEqualAttributeLayoutConstraint.prototype = BMExtend({}, BMLayoutConstraint.prototype, {
1284
+
1285
+ // @override - BMLayoutConstraint
1286
+ initWithSerializedConstraint(constraint, args) {
1287
+ this._views = constraint._views.map(viewID => args.viewIDs(viewID));
1288
+ for (var i = 0; i < this._views.length; i++) {
1289
+ if (!this._views[i]) return undefined;
1290
+ }
1291
+ this._attribute = constraint._attribute;
1292
+ this._kind = constraint._kind;
1293
+ this._priority = constraint._priority;
1294
+ this._identifier = constraint._identifier || BMUUIDMake();
1295
+ this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
1296
+
1297
+ // For variations, it is required to re-create the size class object references from their hash strings
1298
+ this._variations = constraint._variations || {};
1299
+ for (let key in this._variations) {
1300
+ this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
1301
+ }
1302
+
1303
+ // Create the configuration
1304
+ this._updateConfiguration();
1305
+
1306
+ this._install();
1307
+
1308
+ return this;
1309
+ },
1310
+
1311
+ /**
1312
+ * The views that this constraint affects.
1313
+ */
1314
+ _views: undefined, // <[BMView]>
1315
+
1316
+ /**
1317
+ * The attribute affected by this constraint.
1318
+ */
1319
+ _attribute: undefined, // <BMLayoutAttribute>
1320
+
1321
+ // @override - BMLayoutConstraint
1322
+ affectedAttributesForView(view) {
1323
+ let attributes = [];
1324
+
1325
+ if (this._views.indexOf(view) != -1) return [this._attribute];
1326
+
1327
+ return attributes;
1328
+ },
1329
+
1330
+
1331
+ // @override - BMLayoutConstraint
1332
+ get isConstraintCollection() {
1333
+ return YES;
1334
+ },
1335
+
1336
+
1337
+ _constituentConstraints: undefined, // <[BMLayoutConstraints]>
1338
+
1339
+ // @override - BMLayoutConstraint
1340
+ get constituentConstraints() {
1341
+ if (this._constituentConstraints) return this._constituentConstraints;
1342
+
1343
+ let constraints = [];
1344
+ let constituentConstraint;
1345
+
1346
+ for (let i = 1; i < this._views.length; i++) {
1347
+ constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[i - 1], {
1348
+ attribute: this._attribute,
1349
+ relatedBy: BMLayoutConstraintRelation.Equals,
1350
+ toView: this._views[i],
1351
+ secondAttribute: this._attribute,
1352
+ constant: 0,
1353
+ multiplier: 1,
1354
+ priority: this._priority
1355
+ }));
1356
+ constituentConstraint._variations = this._variations;
1357
+ constituentConstraint._isActive = this._isActive;
1358
+ constituentConstraint._updateConfigurationSilently(YES);
1359
+ }
1360
+
1361
+ this._constituentConstraints = constraints;
1362
+ return constraints;
1363
+ },
1364
+
1365
+ // @override - BMLayoutConstraint
1366
+ get constant() {
1367
+ return this._constant;
1368
+ },
1369
+ set constant(constant) {
1370
+ if (constant == this._constant) return;
1371
+ this._constant = constant;
1372
+ return this._updateConfiguration();
1373
+
1374
+ this.constituentConstraints.forEach(constraint => constraint.constant = constant);
1375
+ },
1376
+
1377
+
1378
+ // @override - BMLayoutConstraint
1379
+ get _hasEditableConstant() {
1380
+ return NO;
1381
+ },
1382
+
1383
+ // @override - BMLayoutConstraint
1384
+ get categoryKind() { // <String>
1385
+ if (this._kind == BMLayoutConstraintKind.Vertical) {
1386
+ if (this._attribute == BMLayoutAttribute.Height) {
1387
+ return 'Height';
1388
+ }
1389
+ else {
1390
+ return 'Vertical Position';
1391
+ }
1392
+ }
1393
+ else {
1394
+ if (this._attribute == BMLayoutAttribute.Width) {
1395
+ return 'Width';
1396
+ }
1397
+ else {
1398
+ return 'Horizontal Position';
1399
+ }
1400
+ }
1401
+ },
1402
+
1403
+
1404
+ // @override - BMLayoutConstraint
1405
+ _isActive: NO,
1406
+
1407
+ get isActive() {
1408
+ return this._isActive;
1409
+ },
1410
+ set isActive(active) {
1411
+ if (active != this._isActive) {
1412
+ this._isActive = active;
1413
+ return this._updateConfiguration();
1414
+ this._views[0].rootView._invalidatedConstraints = YES;
1415
+
1416
+ this._views.forEach(view => {
1417
+ view._checkConstraints();
1418
+ view.needsLayout = YES;
1419
+ });
1420
+ }
1421
+ },
1422
+
1423
+ // @override - BMLayoutConstraint
1424
+ _install() {
1425
+ this._views.forEach(view => view._addConstraint(this));
1426
+ this._views[0].rootView._invalidatedConstraints = YES;
1427
+ },
1428
+
1429
+
1430
+ // @override - BMLayoutConstraint
1431
+ remove() {
1432
+ if (this._isActive) {
1433
+ this._isActive = NO;
1434
+ }
1435
+
1436
+ this._views.forEach(view => {
1437
+ view._removeConstraint(this);
1438
+ view._checkConstraints();
1439
+ view.needsLayout = YES;
1440
+ });
1441
+ this._views[0].rootView._invalidatedConstraints = YES;
1442
+
1443
+ this._views = undefined;
1444
+ },
1445
+
1446
+
1447
+ // @override - BMLayoutConstraint
1448
+ toString() {
1449
+ return 'Equal ' + this._attribute;
1450
+ },
1451
+
1452
+
1453
+ // @override - BMLayoutConstraint
1454
+ toCompactString() {
1455
+ return 'Equal ' + this._attribute;
1456
+ },
1457
+
1458
+ // @override - BMLayoutConstraint
1459
+ serializedConstraintWithViewIDs(block) {
1460
+ return {
1461
+ _class: 'BMEqualAttributeLayoutConstraint',
1462
+ _attribute: this._attribute,
1463
+ _priority: this._priority,
1464
+ _views: this._views.map(view => block(view)),
1465
+ _kind: this._kind,
1466
+ _identifier: this._identifier,
1467
+ _variations: this._serializedVariations,
1468
+ _isActive: this._isActive
1469
+ };
1470
+ }
1471
+ });
1472
+
1473
+ // @endtype
1474
+
1475
+ // @type BMEqualSpacingLayoutConstraint extends BMLayoutConstraint
1476
+
1477
+
1478
+ /**
1479
+ * An equal attribute layout constraint is a constraint collection that makes a set of views
1480
+ * have the same spacing between them, and optionally between the first and last view and the superview.
1481
+ */
1482
+ export function BMEqualSpacingLayoutConstraint () {} // <constructor>
1483
+
1484
+
1485
+ /**
1486
+ * Constructs and returns a constraint that makes all of the views given to it have the same value
1487
+ * for a given attribute.
1488
+ * @param kind <BMLayoutConstraintKind> The kind of spacing. Should be .Horizontal or .Vertical
1489
+ * {
1490
+ * @param forViews <[BMView]> An array of views that this constraint affects. This array should contain at least
1491
+ * two views. If <code>withSuperview</code> is set to <code>YES</code>, this views in this
1492
+ * array must be siblings.
1493
+ * @param withSuperview <Boolean, nullable> Defaults to <code>NO</code>. If set to <code>YES</code>, the first and last views in
1494
+ * the array will have leading and trailing constraints bound to their superview. This method will raise an exception
1495
+ * if this parameter is set to `YES` and the views do not have the same superview.
1496
+ * @param constant <Number or String, nullable> Defaults to <code>0</code>. The spacing to apply between the views.
1497
+ * @param priority <Number, nullable> Defaults to <code>BMLayoutConstraintPriorityRequired</code>. The constraint's priority.
1498
+ * }
1499
+ * @return <BMEqualAttributeLayoutConstraint> A constraint.
1500
+ */
1501
+ BMEqualSpacingLayoutConstraint.constraintOfKind = function (kind, args) {
1502
+ let constraint = new BMEqualSpacingLayoutConstraint();
1503
+
1504
+ constraint._views = args.forViews.slice();
1505
+ constraint._kind = kind;
1506
+ constraint._priority = args.priority || BMLayoutConstraintPriorityRequired;
1507
+ constraint._constant = args.constant || 0;
1508
+
1509
+ constraint._identifier = BMUUIDMake();
1510
+
1511
+ if (args.withSuperview) {
1512
+ // Ensure that if the superview is specified the views are siblings
1513
+ constraint._withSuperview = args.withSuperview;
1514
+ let parent = args.forViews[0].superview;
1515
+ args.forViews.forEach(view => {
1516
+ if (view.superview != parent) throw new Error("The views must have the same superview.");
1517
+ });
1518
+
1519
+ constraint._superview = parent;
1520
+ }
1521
+
1522
+ if (kind == BMLayoutConstraintKind.Horizontal) {
1523
+ constraint._firstAttribute = BMLayoutAttribute.Leading;
1524
+ constraint._secondAttribute = BMLayoutAttribute.Trailing;
1525
+ }
1526
+ else {
1527
+ constraint._firstAttribute = BMLayoutAttribute.Top;
1528
+ constraint._secondAttribute = BMLayoutAttribute.Bottom;
1529
+ }
1530
+
1531
+ constraint._variations = {};
1532
+ constraint._configuration = {constant: constraint._constant, priority: constraint._priority, isActive: constraint._isActive};
1533
+ if (typeof constraint._constant == 'string') {
1534
+ constraint._configuration.constantValue = args.forViews[0].rootView.valueForLayoutVariable(constraint._constant);
1535
+ }
1536
+ else {
1537
+ constraint._configuration.constantValue = constraint._constant;
1538
+ }
1539
+
1540
+ if (!args._internal) {
1541
+ constraint._install();
1542
+ }
1543
+ else {
1544
+ constraint._internal = YES;
1545
+ }
1546
+
1547
+ return constraint;
1548
+ }
1549
+
1550
+
1551
+ BMEqualSpacingLayoutConstraint.prototype = BMExtend({}, BMLayoutConstraint.prototype, {
1552
+
1553
+ // @override - BMLayoutConstraint
1554
+ initWithSerializedConstraint(constraint, args) {
1555
+ this._views = constraint._views.map(viewID => args.viewIDs(viewID));
1556
+ for (var i = 0; i < this._views.length; i++) {
1557
+ if (!this._views[i]) return undefined;
1558
+ }
1559
+ if (constraint._superview) {
1560
+ this._superview = args.viewIDs(constraint._superview);
1561
+ if (!this._superview) return undefined;
1562
+ }
1563
+ this._firstAttribute = constraint._firstAttribute;
1564
+ this._secondAttribute = constraint._secondAttribute;
1565
+ this._constant = constraint._constant;
1566
+ this._kind = constraint._kind;
1567
+ this._priority = constraint._priority;
1568
+ this._identifier = constraint._identifier || BMUUIDMake();
1569
+ this._isActive = (constraint._isActive === undefined) ? YES : constraint._isActive;
1570
+
1571
+ // For variations, it is required to re-create the size class object references from their hash strings
1572
+ this._variations = constraint._variations || {};
1573
+ for (let key in this._variations) {
1574
+ this._variations[key].sizeClass = BMLayoutSizeClass._layoutSizeClassForHashString(key);
1575
+ }
1576
+
1577
+ // Create the configuration
1578
+ this._updateConfiguration();
1579
+
1580
+ this._install();
1581
+
1582
+ return this;
1583
+ },
1584
+
1585
+ /**
1586
+ * The views that this constraint affects.
1587
+ */
1588
+ _views: undefined, // <[BMView]>
1589
+
1590
+ /**
1591
+ * The superview affected by this constraint, if any.
1592
+ */
1593
+ _superview: undefined, // <BMView, nullable>
1594
+
1595
+ /**
1596
+ * The first attribute for this constraint. This is <code>.Leading</code> for horizontal spacing
1597
+ * and <code>.Top</code> for vertical spacing.
1598
+ */
1599
+ _firstAttribute: undefined, // <BMLayoutAttribute>
1600
+
1601
+ /**
1602
+ * The first attribute for this constraint. This is <code>.Leading</code> for horizontal spacing
1603
+ * and <code>.Top</code> for vertical spacing.
1604
+ */
1605
+ _secondAttribute: undefined, // <BMLayoutAttribute>
1606
+
1607
+ //
1608
+ // The type of spacing to apply.
1609
+ //
1610
+ _kind: undefined, // <BMLayoutConstraintKind>
1611
+
1612
+ // @override - BMLayoutConstraint
1613
+ affectedAttributesForView(view) {
1614
+ let attributes = [];
1615
+ let index = 0;
1616
+
1617
+ if (view == this._superview) return [this._firstAttribute, this._secondAttribute];
1618
+
1619
+ if ((index = this._views.indexOf(view)) != -1) {
1620
+ if (this._superview) {
1621
+ if (index == 0) return [this._secondAttribute];
1622
+ if (index == this._views.length - 1) return [this._firstAttribute];
1623
+ return [this._firstAttribute, this._secondAttribute];
1624
+ }
1625
+ else {
1626
+ return [this._firstAttribute, this._secondAttribute];
1627
+ }
1628
+ }
1629
+
1630
+ return attributes;
1631
+ },
1632
+
1633
+
1634
+ // @override - BMLayoutConstraint
1635
+ get isConstraintCollection() {
1636
+ return YES;
1637
+ },
1638
+
1639
+ _constituentConstraints: undefined, // <[BMLayoutConstraint]>
1640
+
1641
+ // @override - BMLayoutConstraint
1642
+ get constituentConstraints() {
1643
+ if (this._constituentConstraints) return this._constituentConstraints;
1644
+
1645
+ let constraints = [];
1646
+
1647
+ let constituentConstraint;
1648
+
1649
+ for (let i = 1; i < this._views.length; i++) {
1650
+ constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[i - 1], {
1651
+ attribute: this._secondAttribute,
1652
+ relatedBy: BMLayoutConstraintRelation.Equals,
1653
+ toView: this._views[i],
1654
+ secondAttribute: this._firstAttribute,
1655
+ constant: this._constant,
1656
+ multiplier: 1,
1657
+ priority: this._priority
1658
+ }));
1659
+
1660
+ constituentConstraint._reversesConstant = YES;
1661
+ constituentConstraint._variations = this._variations;
1662
+ constituentConstraint._isActive = this._isActive;
1663
+ constituentConstraint._updateConfigurationSilently(YES);
1664
+ }
1665
+
1666
+ if (this._superview) {
1667
+ constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[0], {
1668
+ attribute: this._firstAttribute,
1669
+ relatedBy: BMLayoutConstraintRelation.Equals,
1670
+ toView: this._superview,
1671
+ secondAttribute: this._firstAttribute,
1672
+ constant: this._constant,
1673
+ multiplier: 1,
1674
+ priority: this._priority
1675
+ }));
1676
+ constituentConstraint._variations = this._variations;
1677
+ constituentConstraint._isActive = this._isActive;
1678
+ constituentConstraint._updateConfigurationSilently(YES);
1679
+
1680
+ constraints.push(constituentConstraint = BMLayoutConstraint.internalConstraintWithView(this._views[this._views.length - 1], {
1681
+ attribute: this._secondAttribute,
1682
+ relatedBy: BMLayoutConstraintRelation.Equals,
1683
+ toView: this._superview,
1684
+ secondAttribute: this._secondAttribute,
1685
+ constant: this._constant,
1686
+ multiplier: 1,
1687
+ priority: this._priority
1688
+ }));
1689
+ constituentConstraint._reversesConstant = YES;
1690
+ constituentConstraint._variations = this._variations;
1691
+ constituentConstraint._isActive = this._isActive;
1692
+ constituentConstraint._updateConfigurationSilently(YES);
1693
+ }
1694
+
1695
+ this._constituentConstraints = constraints;
1696
+ return constraints;
1697
+ },
1698
+
1699
+ // @override - BMLayoutConstraint
1700
+ get constant() {
1701
+ return this._constant;
1702
+ },
1703
+ set constant(constant) {
1704
+ if (constant == this._constant) return;
1705
+ this._constant = constant;
1706
+ return this._updateConfiguration();
1707
+
1708
+ this.constituentConstraints.forEach(constraint => constraint.constant = constant);
1709
+ },
1710
+
1711
+
1712
+ // @override - BMLayoutConstraint
1713
+ get _hasEditableConstant() {
1714
+ return YES;
1715
+ },
1716
+
1717
+ // @override - BMLayoutConstraint
1718
+ get categoryKind() { // <String>
1719
+ if (this._kind == BMLayoutConstraintKind.Vertical) {
1720
+ return 'Vertical Position';
1721
+ }
1722
+ else {
1723
+ return 'Horizontal Position';
1724
+ }
1725
+ },
1726
+
1727
+
1728
+ // @override - BMLayoutConstraint
1729
+ _isActive: NO,
1730
+
1731
+ get isActive() {
1732
+ return this._isActive;
1733
+ },
1734
+ set isActive(active) {
1735
+ if (active != this._isActive) {
1736
+ this._isActive = active;
1737
+ return this._updateConfiguration();
1738
+ this._views[0].rootView._invalidatedConstraints = YES;
1739
+
1740
+ this._views.forEach(view => {
1741
+ view._checkConstraints();
1742
+ view.needsLayout = YES;
1743
+ });
1744
+
1745
+ if (this._superview) {
1746
+ this._superview._checkConstraints();
1747
+ this._superview.needsLayout = YES;
1748
+ }
1749
+ }
1750
+ },
1751
+
1752
+ // @override - BMLayoutConstraint
1753
+ _install() {
1754
+ this._views.forEach(view => view._addConstraint(this));
1755
+ this._views[0].rootView._invalidatedConstraints = YES;
1756
+
1757
+ if (this._superview) this._superview._addConstraint(this);
1758
+ },
1759
+
1760
+
1761
+ // @override - BMLayoutConstraint
1762
+ remove() {
1763
+ if (this._isActive) {
1764
+ this._isActive = NO;
1765
+ }
1766
+
1767
+ this._views.forEach(view => {
1768
+ view._removeConstraint(this);
1769
+ view._checkConstraints();
1770
+ view.needsLayout = YES;
1771
+ });
1772
+ this._views[0].rootView._invalidatedConstraints = YES;
1773
+
1774
+ if (this._superview) {
1775
+ this._superview._removeConstraint(this);
1776
+ this._superview._checkConstraints();
1777
+ this._superview.needsLayout = YES;
1778
+ }
1779
+
1780
+ this._views = undefined;
1781
+ },
1782
+
1783
+
1784
+ // @override - BMLayoutConstraint
1785
+ toString() {
1786
+ return 'Equal Spacing';
1787
+ },
1788
+
1789
+
1790
+ // @override - BMLayoutConstraint
1791
+ toCompactString() {
1792
+ return 'Equal Spacing';
1793
+ },
1794
+
1795
+ // @override - BMLayoutConstraint
1796
+ serializedConstraintWithViewIDs(block) {
1797
+ return {
1798
+ _class: 'BMEqualSpacingLayoutConstraint',
1799
+ _priority: this._priority,
1800
+ _views: this._views.map(view => block(view)),
1801
+ _superview: this._superview ? block(this._superview) : undefined,
1802
+ _constant: this._constant,
1803
+ _firstAttribute: this._firstAttribute,
1804
+ _secondAttribute: this._secondAttribute,
1805
+ _kind: this._kind,
1806
+ _identifier: this._identifier,
1807
+ _variations: this._serializedVariations,
1808
+ _isActive: this._isActive
1809
+ };
1810
+ }
1811
+ });
1812
+
1813
+ // @endtype