Created
March 21, 2012 01:21
-
-
Save unscriptable/2143389 to your computer and use it in GitHub Desktop.
event hub with strategies
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function () { | |
var undef; | |
/** | |
* This strategy will disable a data item during REST operations. | |
* This strategy only makes sense in a pessimistic network. | |
* We need to integrate promises into the EventHub in order for this | |
* strategy to work. Alternatively, we could have item states of | |
* 'adding', 'removing', 'updating', but that feels brutish. | |
*/ | |
return function createStrategy () { | |
var pendingItems, longEvents; | |
pendingItems = []; | |
longEvents = { | |
save: {}, | |
remove: {} | |
}; | |
return { | |
// TODO: shoud we prevent other events while busy or is setting the disabled state good enough? | |
allowEvent: undef, | |
processEvent: function (item, type, sourceNode, destNode, allNodes) { | |
if (type in longEvents) { | |
if (destNode == sourceNode) { | |
// TODO: determine when/how to enable after we determine if using promises or not | |
destNode.disable(true); | |
} | |
} | |
else { | |
return false; | |
} | |
} | |
}; | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function () { | |
var allowed, denied, prevented, undef; | |
function EventHub () { | |
this._nodes = []; | |
this._strategy = undef; | |
// this isn't very wirey | |
this._eventTypes = [ | |
'update', 'save', 'remove', 'select', 'edit', 'disable' | |
]; | |
} | |
// // unique flags | |
// allowed = {}; | |
// denied = {}; | |
// prevented = {}; | |
// | |
// EventHub.eventApproval = { | |
// allow: allowed, | |
// deny: denied, | |
// prevent: prevented | |
// }; | |
EventHub.prototype = { | |
/** | |
* Strategies determine if an event gets onto the network and then how | |
* it's processed by the other nodes in the network. (nodes are | |
* adapters). Strategies can be composed/combined. | |
* Should we compose them in this object or should we assume they've | |
* already been composed? (This impl assumed pre-composed.) | |
* @param strategy {Object} a strategy object has two methods: | |
* strategy.allowEvent {Function} function (data, type, sourceNode, allNodes) | |
* strategy.processEvent {Function} function (data, type, sourceNode, allNodes) | |
*/ | |
setStrategy: function (strategy) { | |
// type == 'update', 'add', 'remove', 'select', 'edit' | |
// strategies return an array of nodes that get event? or true/false? | |
// sync properties strategy | |
// cursor strategy | |
this._strategy = strategy; | |
}, | |
/** | |
* Applies the strategies to determine if the event is allowed on the | |
* network. Strategies should return false to deny the event. | |
* I think we need a way to indicate that an event should be not only | |
* denied, *but also prevented/reverted*. For instance, if a node sends | |
* a 'select:true' event when the FreezeSelectionWhileEditing strategy | |
* is applied, the node should be set back in the select:false state. | |
* @param sourceNode | |
* @param type | |
* @param data | |
*/ | |
allowEvent: function (sourceNode, type, data) { | |
var allNodes, strategy, receiverNodes; | |
allNodes = this._nodes; | |
strategy = this._strategy; | |
if (strategy && strategy.allowEvent) { | |
return strategy.allowEvent(data, type, sourceNode, allNodes); | |
} | |
else { | |
return allowed; | |
} | |
}, | |
/** | |
* Applies strategies to determine how to process an event for each | |
* node in the network. The default is to simply send the event to | |
* all nodes except the source node. Strategies could decide to | |
* send different events, skip nodes, etc. | |
* @param sourceNode | |
* @param type | |
* @param data | |
*/ | |
processEvent: function (sourceNode, type, data) { | |
var nodes, strategy, processFunc, i, node; | |
nodes = this._nodes; | |
strategy = this._strategy; | |
processFunc = strategy && strategy.processEvent; | |
i = nodes.length; | |
while ((node = nodes[i++])) { | |
if (!processFunc || undef === processFunc(data, type, sourceNode, node, nodes)) { | |
forwardEvent(data, type, sourceNode, node, nodes); | |
} | |
} | |
}, | |
addNode: function (node) { | |
var i, type; | |
// sniff for event hooks | |
for (i = 0; i < this._eventTypes.length; i++) { | |
type = this._eventTypes[i]; | |
if (typeof node[type] == 'function') { | |
node[type] = this._overrideNodeEvent(node, type, node[type]); | |
} | |
} | |
}, | |
_overrideNodeEvent: function (node, type, origEvent) { | |
var self = this; | |
return function (data) { | |
var allowed, result; | |
allowed = self.allowEvent(node, type, data); | |
if (allowed == prevented) { | |
throw new Error('not allowed'); | |
} | |
result = origEvent.call(node, data); | |
if (allowed == allowed) { | |
self.processEvent(node, type, data); | |
} | |
return result; | |
}; | |
} | |
}; | |
function forwardEvent (data, type, sourceNode, destNode) { | |
if (sourceNode != destNode) { | |
destNode[type](data); | |
} | |
} | |
return EventHub; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function () { | |
var allow, disallow, undef; | |
allow = true; | |
disallow = false; | |
return function createStrategy () { | |
var nodeBeingEdited; | |
return { | |
allowEvent: function (isEditing, type, sourceNode, allNodes) { | |
if (nodeBeingEdited) { | |
if (type == 'edit') { | |
if (isEditing) { | |
// don't allow another node to enter editing state | |
return disallow; | |
} | |
else if (nodeBeingEdited == sourceNode) { | |
// node is leaving editing state | |
nodeBeingEdited = undef; | |
return allow; | |
} | |
else { | |
// TODO: throw if we get an isEditing==false from a node that isn't being edited? | |
return disallow; | |
} | |
} | |
else { | |
// disallow select while editing | |
return type == 'select' ? disallow : allow; | |
} | |
} | |
else { | |
if (type == 'edit' && isEditing) { | |
nodeBeingEdited = sourceNode; | |
} | |
return allow; | |
} | |
}, | |
processEvent: undef | |
}; | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function () { | |
var undef; | |
/** | |
* This strategy only set nodes with the same identifier to | |
* select:true (isSelected == true). | |
*/ | |
return function createStrategy (options) { | |
var identifier; | |
identifier = options.symbolizer; | |
return { | |
allowEvent: undef, | |
processEvent: function (isSelected, type, sourceNode, destNode, allNodes) { | |
if ('select' in destNode && type == 'select' && isSelected) { | |
destNode['select'](identifier(sourceNode) != identifier(destNode) || isSelected); | |
return true; | |
} | |
} | |
}; | |
}; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define({ | |
myStore: { $ref: 'resource!my/endpoint' }, | |
myView: { | |
wire: 'my/databoudView', | |
get: 'viewNode', | |
// these should be in the view's spec, not here. In the view, they | |
// need to convert a dom event to a cola event (like they do here), | |
// but that means we also need a colaNode in the view's spec. | |
// colaNode: { bind: { adapts: 'viewNode', bindings: { /*...*/ } } } | |
on: { | |
'click:button.save': { | |
colaHub: 'save' // 'commit' ? | |
}, | |
'click:button.cancel': { | |
colaHub: 'cancel' // 'rollback'? | |
} | |
} | |
}, | |
colaHub: { | |
bind: { | |
nodes: [ | |
{ $ref: 'myStore' }, | |
{ $ref: 'myView' } | |
], | |
// we could probably compose these into common groups | |
// and alow dev to set a default set for their app? | |
strategies: [ | |
{ module: 'cola/strategy/FreezeSelectionWhileEditing' }, | |
{ module: 'cola/strategy/SelectSingleItemAtATime' } | |
], | |
// these are composed into a single comparator that is injected | |
// into the network | |
sortBy: { | |
name: 1, | |
updatedDate: -2 | |
} | |
// does it make sense to include a key here, too? | |
}, | |
// a place to put event handlers! | |
on: { | |
remove: { | |
controller: 'handleItemRemoved' | |
} | |
} | |
}, | |
controller: { | |
handleItemRemoved: function (item) { alert('item removed: ' + item.id); } | |
}, | |
plugins: [ | |
{ module: 'wire/dojo/store' }, | |
{ module: 'wire/dojo/on' }, | |
{ module: 'wire/cola' } | |
] | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(function () { | |
var allow, disallow, undef; | |
allow = true; | |
disallow = false; | |
/** | |
* This strategy defers all update events (property change events) until | |
* the node currently being edited leaves the editing state (edit:false). | |
* The converse of this strategy is RevertPropertyChangesAtRollback. | |
*/ | |
// TODO: propagate property changes when finished editing | |
return function createStrategy () { | |
var nodeBeingEdited; | |
return { | |
allowEvent: function (isOn, type, sourceNode, allNodes) { | |
if (nodeBeingEdited) { | |
if (type == 'edit') { | |
if (isOn) { | |
// don't allow another node to enter editing state | |
return disallow; | |
} | |
else if (nodeBeingEdited == sourceNode) { | |
// node is leaving editing state | |
nodeBeingEdited = undef; | |
return allow; | |
} | |
else { | |
// TODO: throw if we get an isOn==false from a node that isn't being edited? | |
return disallow; | |
} | |
} | |
else { | |
// disallow select while editing | |
return type == 'set' ? disallow : allow; | |
} | |
} | |
else { | |
if (type == 'edit' && isOn) { | |
nodeBeingEdited = sourceNode; | |
} | |
return allow; | |
} | |
}, | |
processEvent: undef | |
}; | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment