Option name | Type | Description |
---|---|---|
ds1 | Object | the first data source. Instead of the first data source an array can be passed with arrays of Connection objects parameters in each array element. |
mode | String | the connection mode that defines the direction and the depth of connection. Possible values are '->', '<<-', '<<<->>>', etc. |
ds2 | Object | the second data source |
options | Object | not implemented yet |
This function creates one or many Connector objects that
create live reactive connection between objects implementing
dataSource interface:
Objects should emit messages when any part of their data changes,
methods on
and off
should be implemented to subscribe/unsubscribe
to change notification messages, methods set
and get
should be implemented to get/set data
on path objects, pointing to particular parts of the object, method path
should return path object for a given path string (see path utils for path string syntax).
Both Model and Data facet are such data sources, they can be linked by Connector object.
function minder(ds1, mode, ds2, options) {
if (Array.isArray(ds1)) {
var connDescriptions = ds1;
var connectors = connDescriptions.map(function(descr) {
return new Connector(descr[0], descr[1], descr[2], descr[3]);
});
connectors.forEach(_addConnector);
return connectors;
} else {
var cnct = new Connector(ds1, mode, ds2, options);
_addConnector(cnct);
return cnct;
}
}
messenger of minder where it emits events related to all connectors
var _messenger = new Messenger(minder, Messenger.defaultMethods);
var _connectors = []
, _receivedMessages = []
, _isPropagating = false;
_.extend(minder, {
getConnectors: minder_getConnectors,
getExpandedConnections: minder_getExpandedConnections,
isPropagating: minder_isPropagating,
whenPropagationCompleted: minder_whenPropagationCompleted,
destroyConnector: minder_destroyConnector,
destroy: minder_destroy
});
function _addConnector(cnct) {
cnct.___minder_id = _connectors.push(cnct) - 1;
cnct.on(/.*/, onConnectorMessage);
minder.postMessage('added', { connector: cnct });
minder.postMessage('turnedon', { connector: cnct });
}
function onConnectorMessage(msg, data) {
var data = data ? _.clone(data) : {};
_.extend(data, {
id: this.___minder_id,
connector: this
});
minder.postMessage(msg, data);
if (! _receivedMessages.length && ! _isPropagating) {
_.defer(_idleCheck);
_isPropagating = true;
}
_receivedMessages.push({ msg: msg, data: data });
}
function _idleCheck() {
if (_receivedMessages.length) {
_receivedMessages.length = 0;
_.defer(_idleCheck);
minder.postMessage('propagationticked');
} else {
_isPropagating = false;
minder.postMessage('propagationcompleted');
}
}
function minder_isPropagating() {
return _isPropagating;
}
function minder_whenPropagationCompleted(callback) {
if (_isPropagating)
minder.once('propagationcompleted', executeCallback);
else
_.defer(executeCallback);
function executeCallback() {
if (_isPropagating)
minder.once('propagationcompleted', executeCallback);
else
callback();
}
}
function minder_getConnectors(onOff) {
if (typeof onOff == 'undefined')
return _connectors;
return _connectors.filter(function(cnct) {
return cnct.isOn === onOff;
});
}
function minder_destroyConnector(cnct) {
cnct.destroy();
var index = _connectors.indexOf(cnct);
if (index >= 0)
delete _connectors[index];
else
logger.warn('minder: connector destroyed that is not registered in minder');
}
function minder_getExpandedConnections(onOff, searchStr) {
var connectors = minder.getConnectors(onOff);
var connections = connectors.map(function(cnct) {
var connection = {
leftSource: _getExpandedSource(cnct.ds1),
rightSource: _getExpandedSource(cnct.ds2),
mode: cnct.mode,
isOn: cnct.isOn
};
if (cnct.options)
connection.options = cnct.options;
return connection;
});
if (searchStr)
connections = connections.filter(function(cnctn) {
return _sourceMatchesString(cnctn.leftSource, searchStr)
|| _sourceMatchesString(cnctn.rightSource, searchStr);
});
return connections;
}
function _getExpandedSource(ds) {
var source = [];
if (typeof ds == 'function') {
if (ds._model && ds._accessPath) {
source.unshift(ds._accessPath);
ds = ds._model;
}
source.unshift(ds);
ds = ds._hostObject;
}
if (typeof ds == 'object') {
source.unshift(ds);
if (ds.owner)
source.unshift(ds.owner);
}
return source;
}
function _sourceMatchesString(source, matchStr) {
return source.some(function(srcNode) {
var className = srcNode.constructor && srcNode.constructor.name;
return _stringMatch(className, matchStr)
|| _stringMatch(srcNode.name, matchStr)
|| _stringMatch(srcNode, matchStr);
});
}
function _stringMatch(str, substr) {
return str && typeof str == 'string' && str.indexOf(substr) >= 0;
}
function minder_destroy() {
_connectors.forEach(function(cnct) {
destroyDS(cnct.ds1);
destroyDS(cnct.ds2);
cnct.destroy();
});
_messenger.destroy();
minder._destroyed = true;
function destroyDS(ds) {
if (ds && !ds._destroyed) ds.destroy();
}
}