@@ -136,6 +136,7 @@ const ObservableMixin = {
136
136
137
137
// @typedef {Object } BindChain
138
138
// @property {Function } to See {@link ~ObservableMixin#_bindTo}.
139
+ // @property {Function } toMany See {@link ~ObservableMixin#_bindToMany}.
139
140
// @property {module:utils/observablemixin~Observable } _observable The observable which initializes the binding.
140
141
// @property {Array } _bindProperties Array of `_observable` properties to be bound.
141
142
// @property {Array } _to Array of `to()` observable–properties (`{ observable: toObservable, properties: ...toProperties }`).
@@ -144,6 +145,7 @@ const ObservableMixin = {
144
145
// initiated in this binding chain.
145
146
return {
146
147
to : bindTo ,
148
+ toMany : bindToMany ,
147
149
148
150
_observable : this ,
149
151
_bindProperties : bindProperties ,
@@ -414,6 +416,40 @@ function bindTo( ...args ) {
414
416
} ) ;
415
417
}
416
418
419
+ // Binds to an attribute in a set of iterable observables.
420
+ //
421
+ // @private
422
+ // @param {Iterable.<Observable> } observables
423
+ // @param {String } attribute
424
+ // @param {Function } callback
425
+ function bindToMany ( observables , attribute , callback ) {
426
+ if ( this . _bindings . size > 1 ) {
427
+ /**
428
+ * Binding one attribute to many observables only possible with one attribute.
429
+ *
430
+ * @error observable-bind-to-many-not-one-binding
431
+ */
432
+ throw new CKEditorError ( 'observable-bind-to-many-not-one-binding: Cannot bind multiple properties with toMany().' ) ;
433
+ }
434
+
435
+ this . to (
436
+ // Bind to #attribute of each observable...
437
+ ...getBindingTargets ( observables , attribute ) ,
438
+ // ...using given callback to parse attribute values.
439
+ callback
440
+ ) ;
441
+ }
442
+
443
+ // Returns an array of binding components for
444
+ // {@link Observable#bind } from a set of iterable observables.
445
+ //
446
+ // @param {Iterable.<Observable> } observables
447
+ // @param {String } attribute
448
+ // @returns {Array.<String> }
449
+ function getBindingTargets ( observables , attribute ) {
450
+ return Array . prototype . concat ( ...observables . map ( observable => [ observable , attribute ] ) ) ;
451
+ }
452
+
417
453
// Check if all entries of the array are of `String` type.
418
454
//
419
455
// @private
@@ -660,14 +696,21 @@ function attachBindToListeners( observable, toBindings ) {
660
696
*
661
697
* **Note**: To release the binding use {@link module:utils/observablemixin~Observable#unbind}.
662
698
*
699
+ * Using `bind().to()` chain:
700
+ *
663
701
* A.bind( 'a' ).to( B );
664
702
* A.bind( 'a' ).to( B, 'b' );
665
703
* A.bind( 'a', 'b' ).to( B, 'c', 'd' );
666
704
* A.bind( 'a' ).to( B, 'b', C, 'd', ( b, d ) => b + d );
667
705
*
706
+ * It is also possible to bind to the same property in a observables collection using `bind().toMany()` chain:
707
+ *
708
+ * A.bind( 'a' ).toMany( [ B, C, D ], 'x', ( a, b, c ) => a + b + c );
709
+ * A.bind( 'a' ).toMany( [ B, C, D ], 'x', ( ...x ) => x.every( x => x ) );
710
+ *
668
711
* @method #bind
669
712
* @param {...String } bindProperties Observable properties that will be bound to another observable(s).
670
- * @returns {Object } The bind chain with the `to()` method .
713
+ * @returns {Object } The bind chain with the `to()` and `toMany()` methods .
671
714
*/
672
715
673
716
/**
@@ -709,7 +752,7 @@ function attachBindToListeners( observable, toBindings ) {
709
752
*
710
753
*
711
754
* Note: we used a high priority listener here to execute this callback before the one which
712
- * calls the orignal method (which used the default priority).
755
+ * calls the original method (which used the default priority).
713
756
*
714
757
* It's also possible to change the return value:
715
758
*
0 commit comments