javascript, etc to allow editing of directionality and edge titles. This commit results in effective, but really horrid UI-wise, editing of such things.
This commit is contained in:
parent
0ad2392af5
commit
25fa45356f
8 changed files with 278 additions and 76 deletions
|
@ -4,6 +4,7 @@ function selectEdgeOnClickHandler(adj, e) {
|
|||
|
||||
//editing overrides everything else
|
||||
if (e.altKey) {
|
||||
//in select-edit-delete-nodes-and-edges.js
|
||||
editEdge(adj, e);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -10,3 +10,9 @@ MetamapsModel.selectedEdges = new Array();
|
|||
MetamapsModel.lastCanvasClick = 0;
|
||||
MetamapsModel.DOUBLE_CLICK_TOLERANCE = 300;
|
||||
MetamapsModel.edgeHoveringOver = false;
|
||||
MetamapsModel.edgePermTimer1 = null;
|
||||
MetamapsModel.edgePermTimer2 = null;
|
||||
MetamapsModel.edgePermSliding = false;
|
||||
MetamapsModel.topicPermTimer1 = null;
|
||||
MetamapsModel.topicPermTimer2 = null;
|
||||
MetamapsModel.topicPermSliding = false;
|
||||
|
|
|
@ -175,8 +175,7 @@ var renderMidArrow = function(from, to, dim, swap, canvas){
|
|||
// move midpoint by half the "length" of the arrow so the arrow is centered on the midpoint
|
||||
var arrowPoint = new $jit.Complex((vect.x / 0.7) + midPoint.x, (vect.y / 0.7) + midPoint.y);
|
||||
// compute the tail intersection point with the edge line
|
||||
var intermediatePoint = new $jit.Complex(arrowPoint.x - vect.x,
|
||||
arrowPoint.y - vect.y);
|
||||
var intermediatePoint = new $jit.Complex(arrowPoint.x - vect.x, arrowPoint.y - vect.y);
|
||||
// vector perpendicular to vect
|
||||
var normal = new $jit.Complex(-vect.y / 2, vect.x / 2);
|
||||
var v1 = intermediatePoint.add(normal);
|
||||
|
@ -232,6 +231,28 @@ var nodeSettings = {
|
|||
}
|
||||
}
|
||||
|
||||
var renderEdgeArrows = function(edgeHelper, adj) {
|
||||
var canvas = Mconsole.canvas;
|
||||
var directionCat = adj.getData('category');
|
||||
var direction = adj.getData('direction');
|
||||
var pos = adj.nodeFrom.pos.getc(true);
|
||||
var posChild = adj.nodeTo.pos.getc(true);
|
||||
|
||||
//plot arrow edge
|
||||
if (directionCat == "none") {
|
||||
//this.edgeHelper.line.render({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, canvas);
|
||||
}
|
||||
else if (directionCat == "both") {
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, true, canvas);
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, false, canvas);
|
||||
}
|
||||
else if (directionCat == "from-to") {
|
||||
var direction = adj.data.$direction;
|
||||
var inv = (direction && direction.length > 1 && direction[0] != adj.nodeFrom.id);
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, inv, canvas);
|
||||
}
|
||||
}//renderEdgeArrow
|
||||
|
||||
// defining custom edges
|
||||
var edgeSettings = {
|
||||
'customEdge': {
|
||||
|
@ -242,19 +263,7 @@ var nodeSettings = {
|
|||
|
||||
var directionCat = adj.getData("category");
|
||||
//label placement on edges
|
||||
//plot arrow edge
|
||||
if (directionCat == "none") {
|
||||
this.edgeHelper.line.render({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, canvas);
|
||||
}
|
||||
else if (directionCat == "both") {
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, true, canvas);
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, false, canvas);
|
||||
}
|
||||
else if (directionCat == "from-to") {
|
||||
var direction = adj.data.$direction;
|
||||
var inv = (direction && direction.length>1 && direction[0] != adj.nodeFrom.id);
|
||||
renderMidArrow({ x: pos.x, y: pos.y }, { x: posChild.x, y: posChild.y }, 13, inv, canvas);
|
||||
}
|
||||
renderEdgeArrows(this.edgeHelper, adj);
|
||||
|
||||
//check for edge label in data
|
||||
var desc = adj.getData("desc");
|
||||
|
@ -322,6 +331,8 @@ function onMouseMoveHandler(node, eventInfo, e) {
|
|||
onMouseLeave(MetamapsModel.edgeHoveringOver)
|
||||
onMouseEnter(edge);
|
||||
}
|
||||
|
||||
//could be false
|
||||
MetamapsModel.edgeHoveringOver = edge;
|
||||
}
|
||||
|
||||
|
|
|
@ -329,20 +329,18 @@ function bindCallbacks(showCard, nameContainer, node) {
|
|||
$(showCard).find('.go-link').attr('href', link);
|
||||
});
|
||||
|
||||
var sliding2 = false;
|
||||
var lT1,lT2;
|
||||
$(showCard).find(".permActivator").bind('mouseover',
|
||||
function () {
|
||||
clearTimeout(lT2);
|
||||
clearTimeout(MetamapsModel.topicPermTimer2);
|
||||
that = this;
|
||||
lT1 = setTimeout(function() {
|
||||
if (! sliding2) {
|
||||
sliding2 = true;
|
||||
MetamapsModel.topicPermTimer1 = setTimeout(function() {
|
||||
if (! MetamapsModel.topicPermSliding) {
|
||||
MetamapsModel.topicPermSliding = true;
|
||||
$(that).animate({
|
||||
width: '203px',
|
||||
height: '37px'
|
||||
}, 300, function() {
|
||||
sliding2 = false;
|
||||
MetamapsModel.topicPermSliding = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
|
@ -350,16 +348,16 @@ function bindCallbacks(showCard, nameContainer, node) {
|
|||
|
||||
$(showCard).find(".permActivator").bind('mouseout',
|
||||
function () {
|
||||
clearTimeout(lT1);
|
||||
clearTimeout(MetamapsModel.topicPermTimer1);
|
||||
that = this;
|
||||
lT2 = setTimeout(function() {
|
||||
if (! sliding2) {
|
||||
sliding2 = true;
|
||||
MetamapsModel.topicPermTimer2 = setTimeout(function() {
|
||||
if (! MetamapsModel.topicPermSliding) {
|
||||
MetamapsModel.topicPermSliding = true;
|
||||
$(that).animate({
|
||||
height: '16px',
|
||||
width: '16px'
|
||||
}, 300, function() {
|
||||
sliding2 = false;
|
||||
MetamapsModel.topicPermSliding = false;
|
||||
});
|
||||
}
|
||||
},800);
|
||||
|
|
|
@ -1,56 +1,211 @@
|
|||
function editEdge(edge, e) {
|
||||
if (authorizeToEdit(edge)) {
|
||||
//reset so we don't interfere with other edges
|
||||
$('#edit_synapse').remove();
|
||||
//reset so we don't interfere with other edges
|
||||
$('#edit_synapse').remove();
|
||||
|
||||
deselectEdge(edge); //so the label is missing while editing
|
||||
var perm = document.createElement('div');
|
||||
perm.className = 'permission canEdit';
|
||||
var edit_div = document.createElement('div');
|
||||
edit_div.setAttribute('id', 'edit_synapse');
|
||||
perm.appendChild(edit_div);
|
||||
$('.main .wrapper').append(perm);
|
||||
$('#edit_synapse').attr('class', 'best_in_place best_in_place_desc');
|
||||
$('#edit_synapse').attr('data-object', 'synapse');
|
||||
$('#edit_synapse').attr('data-attribute', 'desc');
|
||||
$('#edit_synapse').attr('data-type', 'input');
|
||||
//TODO how to get blank data-nil
|
||||
$('#edit_synapse').attr('data-nil', ' ');
|
||||
$('#edit_synapse').attr('data-url', '/synapses/' + edge.getData("id"));
|
||||
$('#edit_synapse').html(edge.getData("desc"));
|
||||
//so label is missing while editing
|
||||
deselectEdge(edge);
|
||||
|
||||
$('#edit_synapse').css('position', 'absolute');
|
||||
$('#edit_synapse').css('left', e.clientX);
|
||||
$('#edit_synapse').css('top', e.clientY);
|
||||
//create the wrapper around the form elements, including permissions
|
||||
//classes to make best_in_place happy
|
||||
var edit_div = document.createElement('div');
|
||||
edit_div.setAttribute('id', 'edit_synapse');
|
||||
edit_div.className = 'permission canEdit';
|
||||
$('.main .wrapper').append(edit_div);
|
||||
|
||||
$('#edit_synapse').bind("ajax:success", function() {
|
||||
var desc = $(this).html();
|
||||
edge.setData("desc", desc);
|
||||
selectEdge(edge);
|
||||
Mconsole.plot();
|
||||
$('#edit_synapse').remove();
|
||||
});
|
||||
populateEditEdgeForm(edge);
|
||||
|
||||
$('#edit_synapse').focusout(function() {
|
||||
//in case they cancel
|
||||
$('#edit_synapse').hide();
|
||||
});
|
||||
|
||||
//css stuff above moves it, this activates it
|
||||
$('#edit_synapse').click();
|
||||
$('#edit_synapse form').submit(function() {
|
||||
//hide it once form submits.
|
||||
//If you don't do this, and data is unchanged, it'll show up on canvas
|
||||
$('#edit_synapse').hide();
|
||||
});
|
||||
$('#edit_synapse input').focus();
|
||||
$('#edit_synapse').show();
|
||||
//drop it in the right spot, activate it
|
||||
$('#edit_synapse').css('position', 'absolute');
|
||||
$('#edit_synapse').css('left', e.clientX);
|
||||
$('#edit_synapse').css('top', e.clientY);
|
||||
//$('#edit_synapse_name').click(); //required in case name is empty
|
||||
//$('#edit_synapse_name input').focus();
|
||||
$('#edit_synapse').show();
|
||||
}
|
||||
else if ((! authorizeToEdit(edge)) && userid) {
|
||||
alert("You don't have the permissions to edit this synapse.");
|
||||
}
|
||||
}
|
||||
|
||||
function populateEditEdgeForm(edge) {
|
||||
add_name_form(edge);
|
||||
add_perms_form(edge);
|
||||
add_direction_form(edge);
|
||||
}
|
||||
function add_name_form(edge) {
|
||||
//name editing form
|
||||
$('#edit_synapse').append('<div id="edit_synapse_name"></div>');
|
||||
$('#edit_synapse_name').attr('class', 'best_in_place best_in_place_desc');
|
||||
$('#edit_synapse_name').attr('data-object', 'synapse');
|
||||
$('#edit_synapse_name').attr('data-attribute', 'desc');
|
||||
$('#edit_synapse_name').attr('data-type', 'input');
|
||||
//TODO how to get blank data-nil
|
||||
$('#edit_synapse_name').attr('data-nil', ' ');
|
||||
$('#edit_synapse_name').attr('data-url', '/synapses/' + edge.getData("id"));
|
||||
$('#edit_synapse_name').html(edge.getData("desc"));
|
||||
|
||||
$('#edit_synapse_name').bind("ajax:success", function() {
|
||||
var desc = $(this).html();
|
||||
edge.setData("desc", desc);
|
||||
selectEdge(edge);
|
||||
Mconsole.plot();
|
||||
});
|
||||
}
|
||||
function add_perms_form(edge) {
|
||||
//permissions - if owner, also allow permission editing
|
||||
$('#edit_synapse').append('<div class="mapPerm"></div>');
|
||||
$('#edit_synapse .mapPerm').text(mk_permission(edge));
|
||||
if (userid == edge.getData('userid')) {
|
||||
$('#edit_synapse').append('<div class="permActivator" />');
|
||||
$('#edit_synapse .permActivator').append('<div class="editSettings" />');
|
||||
$('#edit_synapse .editSettings').append('<span>Permissions:</span>');
|
||||
$('#edit_synapse .editSettings').append('<span class="click-to-edit" />');
|
||||
$('#edit_synapse .click-to-edit').attr('title', 'Click to Edit');
|
||||
$('#edit_synapse .click-to-edit').append(best_in_place_perms(edge));
|
||||
$('#edit_synapse .editSettings').append('<div class="clearfloat" />');
|
||||
$('#edit_synapse .permActivator').bind('mouseover', function() {
|
||||
clearTimeout(MetamapsModel.edgePermTimer2);
|
||||
that = this;
|
||||
MetamapsModel.edgePermTimer1 = setTimeout(function() {
|
||||
if (! MetamapsModel.edgePermSliding) {
|
||||
MetamapsModel.edgePermSliding = true;
|
||||
$(that).animate({
|
||||
width: '203px',
|
||||
height: '37px'
|
||||
}, 300, function() {
|
||||
MetamapsModel.edgePermSliding = false;
|
||||
});
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
$('#edit_synapse .permActivator').bind('mouseout', function () {
|
||||
return;
|
||||
clearTimeout(MetamapsModel.edgePermTimer1);
|
||||
that = this;
|
||||
MetamapsModel.edgePermTimer2 = setTimeout(function() {
|
||||
if (! MetamapsModel.edgePermSliding) {
|
||||
MetamapsModel.edgePermSliding = true;
|
||||
$(that).animate({
|
||||
height: '16px',
|
||||
width: '16px'
|
||||
}, 300, function() {
|
||||
MetamapsModel.edgePermSliding = false;
|
||||
});
|
||||
}
|
||||
},800);
|
||||
}
|
||||
);
|
||||
}
|
||||
}//add_perms_form
|
||||
|
||||
function add_direction_form(edge) {
|
||||
//directionality checkboxes
|
||||
$('#edit_synapse').append('<input type="checkbox" id="edit_synapse_left">');
|
||||
$('#edit_synapse').append('<label class="left"><</label>');
|
||||
$('#edit_synapse').append('<input type="checkbox" id="edit_synapse_right">');
|
||||
$('#edit_synapse').append('<label class="right">></label>');
|
||||
|
||||
//determine which node is to the left and the right
|
||||
//if directly in a line, top is left
|
||||
if (edge.nodeFrom.pos.x < edge.nodeTo.pos.x ||
|
||||
edge.nodeFrom.pos.x == edge.nodeTo.pos.x &&
|
||||
edge.nodeFrom.pos.y < edge.nodeTo.pos.y) {
|
||||
var left = edge.nodeTo;
|
||||
var right = edge.nodeFrom;
|
||||
} else {
|
||||
var left = edge.nodeFrom;
|
||||
var right = edge.nodeTo;
|
||||
}
|
||||
|
||||
/*
|
||||
* One node is actually on the left onscreen. Call it left, & the other right.
|
||||
* If category is from-to, and that node is first, check the 'right' checkbox.
|
||||
* Else check the 'left' checkbox since the arrow is incoming.
|
||||
*/
|
||||
|
||||
var directionCat = edge.getData('category'); //both, none, from-to
|
||||
if (directionCat == 'from-to') {
|
||||
var from_to = edge.getData('direction');
|
||||
if (from_to[0] == left.id) {
|
||||
//check left checkbox
|
||||
$('#edit_synapse_left').prop('checked', true);
|
||||
} else {
|
||||
//check right checkbox
|
||||
$('#edit_synapse_right').prop('checked', true);
|
||||
}
|
||||
} else if (directionCat == 'both') {
|
||||
//check both checkboxes
|
||||
$('#edit_synapse_left').prop('checked', true);
|
||||
$('#edit_synapse_right').prop('checked', true);
|
||||
}
|
||||
$('edit_synapse_left, #edit_synapse_right').click(function() {
|
||||
var leftChecked = $('#edit_synapse_left').is(':checked');
|
||||
var rightChecked = $('#edit_synapse_right').is(':checked');
|
||||
|
||||
var dir = edge.getData('direction');
|
||||
var dirCat = 'none';
|
||||
if (leftChecked && rightChecked) {
|
||||
dirCat = 'both';
|
||||
} else if (!leftChecked && rightChecked) {
|
||||
dirCat = 'from-to';
|
||||
dir = [left.id, right.id];
|
||||
} else if (leftChecked && !rightChecked) {
|
||||
dirCat = 'from-to';
|
||||
dir = [right.id, left.id];
|
||||
}
|
||||
$.ajax({
|
||||
'type': 'PUT',
|
||||
'url': '/synapses/' + edge.getData('id'),
|
||||
'data': {
|
||||
synapse: {
|
||||
category:dirCat
|
||||
},
|
||||
node1_id: {
|
||||
node1: dir[0]
|
||||
},
|
||||
node2_id: {
|
||||
node2: dir[1]
|
||||
}
|
||||
},
|
||||
'success': function() {
|
||||
updateEdgeDisplay(edge, dir, dirCat);
|
||||
}
|
||||
});
|
||||
});
|
||||
}//add_direction_form
|
||||
|
||||
function updateEdgeDisplay(edge, dir, dirCat) {
|
||||
edge.setData('category', dirCat);
|
||||
edge.setData('direction', dir);
|
||||
|
||||
//render mid arrow
|
||||
renderEdgeArrows(null, edge);
|
||||
}
|
||||
|
||||
function best_in_place_perms(edge) {
|
||||
var output =
|
||||
'<span class="best_in_place best_in_place_permission" \
|
||||
id="best_in_place_topic_$_id_$_permission" \
|
||||
data-url="/synapses/$_id_$" \
|
||||
data-object="synapse" \
|
||||
data-collection=$_permission_choices_$ \
|
||||
data-attribute="permission" \
|
||||
data-type="select" \
|
||||
data-value="$_current_$">';
|
||||
|
||||
var permission_choices = "'[";
|
||||
permission_choices += '["commons","commons"],';
|
||||
permission_choices += '["public","public"],';
|
||||
permission_choices += '["private","private"]';
|
||||
permission_choices += "]'";
|
||||
|
||||
output = output.replace(/\$_permission_choices_\$/g, permission_choices);
|
||||
output = output.replace(/\$_id_\$/g, edge.getData('id'));
|
||||
output = output.replace(/\$_current_$\$/g, edge.getData('permission'));
|
||||
return output;
|
||||
}//best_in_place_perms
|
||||
|
||||
function deselectAllEdges() {
|
||||
for (var i = 0; i < MetamapsModel.selectedEdges.length; i += 1) {
|
||||
var edge = MetamapsModel.selectedEdges[i];
|
||||
|
|
|
@ -646,3 +646,13 @@ input[type="submit"] {
|
|||
.contact a {
|
||||
color: #36bbe8;
|
||||
}
|
||||
|
||||
#edit_synapse label,
|
||||
#edit_synapse_left,
|
||||
#edit_synapse_right {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#edit_synapse label.left {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
|
|
@ -103,6 +103,10 @@
|
|||
margin-top:2px;
|
||||
}
|
||||
|
||||
#edit_synapse .best_in_place_desc {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.best_in_place_desc textarea{
|
||||
width:150px;
|
||||
display:block;
|
||||
|
@ -157,7 +161,7 @@
|
|||
}
|
||||
|
||||
.editSettings span {
|
||||
float:left;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.permActivator {
|
||||
|
@ -181,3 +185,20 @@
|
|||
width:16px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
#edit_synapse .mapPerm,
|
||||
#edit_synapse .permActivator {
|
||||
position: static;
|
||||
display: inline-block;
|
||||
color: #000;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#edit_synapse {
|
||||
background-color: #aaa;
|
||||
border-radius: 0.5em;
|
||||
}
|
||||
|
||||
#edit_synapse_name {
|
||||
margin-left: 0.4em;
|
||||
}
|
||||
|
|
|
@ -106,14 +106,14 @@ class SynapsesController < ApplicationController
|
|||
|
||||
# GET synapses/:id/edit
|
||||
def edit
|
||||
@current = current_user
|
||||
@current = current_user
|
||||
@synapse = Synapse.find(params[:id]).authorize_to_edit(@current)
|
||||
|
||||
if @synapse
|
||||
@topics = Topic.visibleToUser(@current, nil)
|
||||
elsif not @synapse
|
||||
redirect_to root_url and return
|
||||
end
|
||||
if @synapse
|
||||
@topics = Topic.visibleToUser(@current, nil)
|
||||
elsif not @synapse
|
||||
redirect_to root_url and return
|
||||
end
|
||||
|
||||
respond_with(@synapse, @topics)
|
||||
end
|
||||
|
@ -132,7 +132,7 @@ class SynapsesController < ApplicationController
|
|||
if params[:node1_id] and params[:node1_id][:node1]
|
||||
@synapse.topic1 = Topic.find(params[:node1_id][:node1])
|
||||
end
|
||||
if params[:node1_id] and params[:node1_id][:node1]
|
||||
if params[:node2_id] and params[:node2_id][:node2]
|
||||
@synapse.topic2 = Topic.find(params[:node2_id][:node2])
|
||||
end
|
||||
@synapse.save
|
||||
|
|
Loading…
Reference in a new issue