@@ -136,6 +136,7 @@ const ObservableMixin = {
136136
137137 // @typedef {Object } BindChain
138138 // @property {Function } to See {@link ~ObservableMixin#_bindTo}.
139+ // @property {Function } toMany See {@link ~ObservableMixin#_bindToMany}.
139140 // @property {module:utils/observablemixin~Observable } _observable The observable which initializes the binding.
140141 // @property {Array } _bindProperties Array of `_observable` properties to be bound.
141142 // @property {Array } _to Array of `to()` observable–properties (`{ observable: toObservable, properties: ...toProperties }`).
@@ -144,6 +145,7 @@ const ObservableMixin = {
144145 // initiated in this binding chain.
145146 return {
146147 to : bindTo ,
148+ toMany : bindToMany ,
147149
148150 _observable : this ,
149151 _bindProperties : bindProperties ,
@@ -414,6 +416,40 @@ function bindTo( ...args ) {
414416 } ) ;
415417}
416418
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+
417453// Check if all entries of the array are of `String` type.
418454//
419455// @private
@@ -660,14 +696,21 @@ function attachBindToListeners( observable, toBindings ) {
660696 *
661697 * **Note**: To release the binding use {@link module:utils/observablemixin~Observable#unbind}.
662698 *
699+ * Using `bind().to()` chain:
700+ *
663701 * A.bind( 'a' ).to( B );
664702 * A.bind( 'a' ).to( B, 'b' );
665703 * A.bind( 'a', 'b' ).to( B, 'c', 'd' );
666704 * A.bind( 'a' ).to( B, 'b', C, 'd', ( b, d ) => b + d );
667705 *
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+ *
668711 * @method #bind
669712 * @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 .
671714 */
672715
673716/**
@@ -709,7 +752,7 @@ function attachBindToListeners( observable, toBindings ) {
709752 *
710753 *
711754 * 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).
713756 *
714757 * It's also possible to change the return value:
715758 *
0 commit comments