Commit 8d5b9609 authored by Remon Huijts's avatar Remon Huijts
Browse files

Reduce complexity by looping over rules not handlers

parent 82cf1269
......@@ -123007,21 +123007,109 @@ var interactions = {
return;
}
 
// Newer graphs have all their rules in the onclick attribute:
var clickRules = JSON.parse(cell.value.getAttribute('onclick'));
// Older graphs may have rules in the onhover attribute:
var hoverRules = JSON.parse(cell.value.getAttribute('onhover'));
// Get the node and all nodes of the children of cell:
var triggerNodes = interactions.cellNodes(graph, cell, true);
 
var actionString = cell.value.getAttribute('onclick');
var handlers = interactions.createEventHandlers(graph, actionString);
// Legacy graphs had actions in the onhover attribute as well:
actionString = cell.value.getAttribute('onhover');
handlers = handlers.concat(interactions.createEventHandlers(graph, actionString));
handlers.forEach(function(handler) {
clickRules.concat(hoverRules).forEach(function(rule) {
var handler = interactions.createHandler(graph, rule);
interactions.installHandler(handler, graph, triggerNodes);
});
});
},
 
/**
* Function: createHandler
*
* Covert the interaction rule object into an event handler.
*
* The action string should be formatted in json. It should be a list of
* dictionaries, each representing an action. Every dictionary should have
* at least an "action" field, with a string specifying which action to
* perform (currently one of "hide", "popup" or "highlight"), plus
* additional attributes depending on the specific action.
*
* The rule object, generally directly parsed from JSON, should contain the
* following properties:
* - "action": specifies the animation ("popup", "hide" or "highlight")
* - "targets": an array of objects, each with a "cell_id" (int) property
* - "colour": a valid CSS colour value (only needed for "highlight")
*
* Examples:
* - {"action": "popup", "targets": [{"cell_id": 2}, {"cell_id": 6}]}
* - {"action": "highlight", "targets": [{"cell_id": 3}], "colour": "red"}
*
* Returns a single handler function, ready to be applied to a graph; the
* function returns another function to apply to the graph to reset/stop the
* action (for example when the hover ends, etc.).
*
* Parameters:
*
* graph - graph object that the action should operate on
* rule - interaction rule object
*/
createHandler: function(graph, rule) {
// Create a dummy fallback handler:
var dummyHandler = function() {
debug('Dummy fallback handler has been called');
return function() {};
};
if (typeof rule.action == 'undefined') {
debug("field 'action' not specified");
return dummyHandler;
}
if (!Array.isArray(rule.targets) || !rule.targets.length) {
debug('Warning: No target specified for rule');
return dummyHandler;
}
var cells = interactions.getTargetCells(graph, rule.targets);
if (!Array.isArray(cells) || !cells.length) {
debug("No valid cells were specified by field 'targets'.");
return dummyHandler;
}
switch (rule.action) {
case 'hide':
// fall through
case 'popup':
// for 'popup', visibility is TRUE during the event, but
// FALSE before and after the event. For 'hide' it is the
// other way around.
var visibleDuringEvent = rule.action === 'popup';
// Reverse the visibility before the event:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
return function() {
// Apply the visibility when the event starts:
interactions.setCellVisibility(graph, cells, visibleDuringEvent);
return function() {
// Reverse the visibility again when the event ends:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
};
};
case 'highlight':
if (typeof rule.colour == 'undefined') {
rule.colour = '#0000FF';
}
return function() {
// Add the highlights when the event starts.
var h = interactions.highlightCells(graph, cells, rule.colour);
return function() {
// Remove the highlights when the event ends.
for (var i = 0; i < h.length; i++) {
h[i].hide();
}
};
};
default:
debug('action \"' + rule.action + '\" not found');
return dummyHandler;
}
},
/**
* Function: installHandler
*
......@@ -123062,95 +123150,6 @@ var interactions = {
});
},
 
/**
* Function: createEventHandlers
*
* Parse the action string (e.g., value of an onclick attribute) and create
* the corresponding event handlers.
*
* The action string should be formatted in json. It should be a list of
* dictionaries, each representing an action. Every dictionary should have
* at least an "action" field, with a string specifying which action to
* perform (currently one of "hide", "popup" or "highlight"), plus
* additional attributes depending on the specific action.
*
* Example:
* [{"action": "popup", "targets": [{"cell_id": 2}, {"cell_id": 6}]},
* {"action": "highlight", "targets": [{"cell_id": 3}], "colour": "red"}]
*
* Returns a list of actions: every action is a function to apply to a
* graph; that function returns another function to apply to the graph to
* reset/stop the action (for example when the hover ends, etc.).
*
* Parameters:
*
* graph - graph object that the action should operate on
* actionString - attribute value to parse
*/
createEventHandlers: function(graph, actionString) {
var handlers = [];
// Check if the actionString is false, zero, null, undefined or empty:
if (!actionString) {
return handlers;
}
JSON.parse(actionString).forEach(function(rule) {
if (typeof rule.action == 'undefined') {
debug("field 'action' not specified");
return;
}
if (!Array.isArray(rule.targets) || !rule.targets.length) {
debug('Warning: No target specified for rule');
return;
}
var cells = interactions.getTargetCells(graph, rule.targets);
if (!Array.isArray(cells) || !cells.length) {
debug("No valid cells were specified by field 'targets'.");
return;
}
switch (rule.action) {
case 'hide':
// fall through
case 'popup':
// for 'popup', visibility is TRUE during the event, but
// FALSE before and after the event. For 'hide' it is the
// other way around.
var visibleDuringEvent = rule.action === 'popup';
// Reverse the visibility before the event:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
handlers.push(function() {
// Apply the visibility when the event starts:
interactions.setCellVisibility(graph, cells, visibleDuringEvent);
return function() {
// Reverse the visibility again when the event ends:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
};
});
break;
case 'highlight':
if (typeof rule.colour == 'undefined') {
rule.colour = '#0000FF';
}
handlers.push(function() {
// Add the highlights when the event starts.
var h = interactions.highlightCells(graph, cells, rule.colour);
return function() {
// Remove the highlights when the event ends.
for (var i = 0; i < h.length; i++) {
h[i].hide();
}
};
});
break;
default:
debug('action \"' + rule.action + '\" not found');
}
});
return handlers;
},
/**
* Function: getTargetCells
*
......@@ -35,21 +35,109 @@ var interactions = {
return;
}
// Newer graphs have all their rules in the onclick attribute:
var clickRules = JSON.parse(cell.value.getAttribute('onclick'));
// Older graphs may have rules in the onhover attribute:
var hoverRules = JSON.parse(cell.value.getAttribute('onhover'));
// Get the node and all nodes of the children of cell:
var triggerNodes = interactions.cellNodes(graph, cell, true);
var actionString = cell.value.getAttribute('onclick');
var handlers = interactions.createEventHandlers(graph, actionString);
// Legacy graphs had actions in the onhover attribute as well:
actionString = cell.value.getAttribute('onhover');
handlers = handlers.concat(interactions.createEventHandlers(graph, actionString));
handlers.forEach(function(handler) {
clickRules.concat(hoverRules).forEach(function(rule) {
var handler = interactions.createHandler(graph, rule);
interactions.installHandler(handler, graph, triggerNodes);
});
});
},
/**
* Function: createHandler
*
* Covert the interaction rule object into an event handler.
*
* The action string should be formatted in json. It should be a list of
* dictionaries, each representing an action. Every dictionary should have
* at least an "action" field, with a string specifying which action to
* perform (currently one of "hide", "popup" or "highlight"), plus
* additional attributes depending on the specific action.
*
* The rule object, generally directly parsed from JSON, should contain the
* following properties:
* - "action": specifies the animation ("popup", "hide" or "highlight")
* - "targets": an array of objects, each with a "cell_id" (int) property
* - "colour": a valid CSS colour value (only needed for "highlight")
*
* Examples:
* - {"action": "popup", "targets": [{"cell_id": 2}, {"cell_id": 6}]}
* - {"action": "highlight", "targets": [{"cell_id": 3}], "colour": "red"}
*
* Returns a single handler function, ready to be applied to a graph; the
* function returns another function to apply to the graph to reset/stop the
* action (for example when the hover ends, etc.).
*
* Parameters:
*
* graph - graph object that the action should operate on
* rule - interaction rule object
*/
createHandler: function(graph, rule) {
// Create a dummy fallback handler:
var dummyHandler = function() {
debug('Dummy fallback handler has been called');
return function() {};
};
if (typeof rule.action == 'undefined') {
debug("field 'action' not specified");
return dummyHandler;
}
if (!Array.isArray(rule.targets) || !rule.targets.length) {
debug('Warning: No target specified for rule');
return dummyHandler;
}
var cells = interactions.getTargetCells(graph, rule.targets);
if (!Array.isArray(cells) || !cells.length) {
debug("No valid cells were specified by field 'targets'.");
return dummyHandler;
}
switch (rule.action) {
case 'hide':
// fall through
case 'popup':
// for 'popup', visibility is TRUE during the event, but
// FALSE before and after the event. For 'hide' it is the
// other way around.
var visibleDuringEvent = rule.action === 'popup';
// Reverse the visibility before the event:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
return function() {
// Apply the visibility when the event starts:
interactions.setCellVisibility(graph, cells, visibleDuringEvent);
return function() {
// Reverse the visibility again when the event ends:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
};
};
case 'highlight':
if (typeof rule.colour == 'undefined') {
rule.colour = '#0000FF';
}
return function() {
// Add the highlights when the event starts.
var h = interactions.highlightCells(graph, cells, rule.colour);
return function() {
// Remove the highlights when the event ends.
for (var i = 0; i < h.length; i++) {
h[i].hide();
}
};
};
default:
debug('action \"' + rule.action + '\" not found');
return dummyHandler;
}
},
/**
* Function: installHandler
*
......@@ -90,95 +178,6 @@ var interactions = {
});
},
/**
* Function: createEventHandlers
*
* Parse the action string (e.g., value of an onclick attribute) and create
* the corresponding event handlers.
*
* The action string should be formatted in json. It should be a list of
* dictionaries, each representing an action. Every dictionary should have
* at least an "action" field, with a string specifying which action to
* perform (currently one of "hide", "popup" or "highlight"), plus
* additional attributes depending on the specific action.
*
* Example:
* [{"action": "popup", "targets": [{"cell_id": 2}, {"cell_id": 6}]},
* {"action": "highlight", "targets": [{"cell_id": 3}], "colour": "red"}]
*
* Returns a list of actions: every action is a function to apply to a
* graph; that function returns another function to apply to the graph to
* reset/stop the action (for example when the hover ends, etc.).
*
* Parameters:
*
* graph - graph object that the action should operate on
* actionString - attribute value to parse
*/
createEventHandlers: function(graph, actionString) {
var handlers = [];
// Check if the actionString is false, zero, null, undefined or empty:
if (!actionString) {
return handlers;
}
JSON.parse(actionString).forEach(function(rule) {
if (typeof rule.action == 'undefined') {
debug("field 'action' not specified");
return;
}
if (!Array.isArray(rule.targets) || !rule.targets.length) {
debug('Warning: No target specified for rule');
return;
}
var cells = interactions.getTargetCells(graph, rule.targets);
if (!Array.isArray(cells) || !cells.length) {
debug("No valid cells were specified by field 'targets'.");
return;
}
switch (rule.action) {
case 'hide':
// fall through
case 'popup':
// for 'popup', visibility is TRUE during the event, but
// FALSE before and after the event. For 'hide' it is the
// other way around.
var visibleDuringEvent = rule.action === 'popup';
// Reverse the visibility before the event:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
handlers.push(function() {
// Apply the visibility when the event starts:
interactions.setCellVisibility(graph, cells, visibleDuringEvent);
return function() {
// Reverse the visibility again when the event ends:
interactions.setCellVisibility(graph, cells, !visibleDuringEvent);
};
});
break;
case 'highlight':
if (typeof rule.colour == 'undefined') {
rule.colour = '#0000FF';
}
handlers.push(function() {
// Add the highlights when the event starts.
var h = interactions.highlightCells(graph, cells, rule.colour);
return function() {
// Remove the highlights when the event ends.
for (var i = 0; i < h.length; i++) {
h[i].hide();
}
};
});
break;
default:
debug('action \"' + rule.action + '\" not found');
}
});
return handlers;
},
/**
* Function: getTargetCells
*
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment