Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1205)

Side by Side Diff: app/views/environment.js

Issue 6821088: Improve dragline behavior.
Patch Set: Created 5 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 'use strict'; 1 'use strict';
gary.poster 2012/11/07 15:10:41 Please add the module yuidoc comment.
benji 2012/11/08 17:25:06 Done.
2 2
3 YUI.add('juju-view-environment', function(Y) { 3 YUI.add('juju-view-environment', function(Y) {
4 4
5 var views = Y.namespace('juju.views'), 5 var views = Y.namespace('juju.views'),
6 utils = Y.namespace('juju.views.utils'), 6 utils = Y.namespace('juju.views.utils'),
7 Templates = views.Templates, 7 Templates = views.Templates,
8 models = Y.namespace('juju.models'); 8 models = Y.namespace('juju.models');
9 9
10 var EnvironmentView = Y.Base.create('EnvironmentView', Y.View, 10 var EnvironmentView = Y.Base.create('EnvironmentView', Y.View,
gary.poster 2012/11/07 15:10:41 Please add the class yuidoc comment.
benji 2012/11/08 17:25:06 Done.
11 [views.JujuBaseView], { 11 [views.JujuBaseView], {
12 events: { 12 events: {
13 '#zoom-out-btn': {click: 'zoom_out'}, 13 '#zoom-out-btn': {click: 'zoom_out'},
14 '#zoom-in-btn': {click: 'zoom_in'}, 14 '#zoom-in-btn': {click: 'zoom_in'},
15 '.graph-list-picker .picker-button': { 15 '.graph-list-picker .picker-button': {
16 click: 'showGraphListPicker' 16 click: 'showGraphListPicker'
17 }, 17 },
18 '.graph-list-picker .picker-expanded': { 18 '.graph-list-picker .picker-expanded': {
19 click: 'hideGraphListPicker' 19 click: 'hideGraphListPicker'
20 }, 20 },
21 // Menu/Controls 21 // Menu/Controls
22 '.add-relation': { 22 '.add-relation': {
23 /** The user clicked on the "Build Relation" menu item. */
gary.poster 2012/11/07 15:10:41 We had a good conversation in a hangout about my m
benji 2012/11/08 17:25:06 The multi-line format seems to overemphasize the i
23 click: function() { 24 click: function() {
24 var box = this.get('active_service'), 25 var box = this.get('active_service'),
25 service = this.serviceForBox(box), 26 service = this.serviceForBox(box),
26 context = this.get('active_context'); 27 context = this.get('active_context');
28 this.addRelationDragStart.call(this, box, context);
gary.poster 2012/11/07 15:10:41 Could you check to see if "this.addRelationDragSta
thiago 2012/11/07 15:21:04 why do you need to use the 'call' method and pass
benji 2012/11/08 17:25:06 It does indeed work.
benji 2012/11/08 17:25:06 Right. That's fixed.
27 this.service_click_actions 29 this.service_click_actions
28 .toggleControlPanel(box, this, context); 30 .toggleControlPanel(box, this, context);
29 this.service_click_actions 31 this.service_click_actions.addRelationStart(box, this, context);
30 .addRelationStart(box, this, context);
31 } 32 }
32 }, 33 },
33 '.view-service': { 34 '.view-service': {
35 /** The user clicked on the "View" menu item. */
34 click: function() { 36 click: function() {
35 // Get the service element 37 // Get the service element
36 var box = this.get('active_service'), 38 var box = this.get('active_service'),
37 service = this.serviceForBox(box); 39 service = this.serviceForBox(box);
38 this.service_click_actions 40 this.service_click_actions
39 .toggleControlPanel(box, this); 41 .toggleControlPanel(box, this);
40 this.service_click_actions 42 this.service_click_actions
41 .show_service(service, this); 43 .show_service(service, this);
42 } 44 }
43 }, 45 },
44 '.destroy-service': { 46 '.destroy-service': {
47 /** The user clicked on the "Destroy" menu item. */
45 click: function() { 48 click: function() {
46 // Get the service element 49 // Get the service element
47 var box = this.get('active_service'), 50 var box = this.get('active_service'),
48 service = this.serviceForBox(box); 51 service = this.serviceForBox(box);
49 this.service_click_actions 52 this.service_click_actions
50 .toggleControlPanel(box, this); 53 .toggleControlPanel(box, this);
51 this.service_click_actions 54 this.service_click_actions
52 .destroyServiceConfirm(service, this); 55 .destroyServiceConfirm(service, this);
53 } 56 }
54 } 57 }
(...skipping 10 matching lines...) Expand all
65 if (!self.hasSVGClass(rect, 'selectable-service')) { 68 if (!self.hasSVGClass(rect, 'selectable-service')) {
66 return; 69 return;
67 } 70 }
68 71
69 // Do not fire unless we're within the service box. 72 // Do not fire unless we're within the service box.
70 var container = self.get('container'), 73 var container = self.get('container'),
71 mouse_coords = d3.mouse(container.one('svg').getDOMNode()); 74 mouse_coords = d3.mouse(container.one('svg').getDOMNode());
72 if (!d.containsPoint(mouse_coords, self.zoom)) { 75 if (!d.containsPoint(mouse_coords, self.zoom)) {
73 return; 76 return;
74 } 77 }
78
79 // Do not fire if we're on the same service.
80 if (d === self.get('addRelationStart_service')) {
81 return;
82 }
gary.poster 2012/11/07 15:10:41 not entirely idle thought, but one that is not rea
benji 2012/11/08 17:25:06 That is a good question. I tried a bit but I coul
83
75 self.set('potential_drop_point_service', d); 84 self.set('potential_drop_point_service', d);
76 self.set('potential_drop_point_rect', rect); 85 self.set('potential_drop_point_rect', rect);
77 self.addSVGClass(rect, 'hover'); 86 self.addSVGClass(rect, 'hover');
78 87
79 // If we have an active dragline, stop redrawing it on mousemove 88 // If we have an active dragline, stop redrawing it on mousemove
80 // and draw the line between the two nearest connector points of 89 // and draw the line between the two nearest connector points of
81 // the two services. 90 // the two services.
82 if (self.dragline) { 91 if (self.dragline) {
83 var connectors = d.getConnectorPair( 92 var connectors = d.getConnectorPair(
84 self.get('addRelationStart_service')), 93 self.get('addRelationStart_service')),
(...skipping 20 matching lines...) Expand all
105 } 114 }
106 var rect = Y.one(this).one('.service-border'); 115 var rect = Y.one(this).one('.service-border');
107 self.set('potential_drop_point_service', null); 116 self.set('potential_drop_point_service', null);
108 self.set('potential_drop_point_rect', null); 117 self.set('potential_drop_point_rect', null);
109 self.removeSVGClass(rect, 'hover'); 118 self.removeSVGClass(rect, 'hover');
110 119
111 if (self.dragline) { 120 if (self.dragline) {
112 self.dragline.attr('class', 121 self.dragline.attr('class',
113 'relation pending-relation dragline dragging'); 122 'relation pending-relation dragline dragging');
114 } 123 }
124 },
125 /**
126 * If the mouse moves over a service and we are adding a relation,
127 * then the dragline needs to be updated.
128 */
gary.poster 2012/11/07 15:10:41 As mentioned yesterday, please add @method, @param
benji 2012/11/08 17:25:06 Yep, the plethora of event handlers makes this cod
129 mousemove: function(d, self) {
130 if (self.clickAddRelation) {
131 var container = self.get('container'),
132 node = container.one('#canvas rect:first-child');
133 self.rectMousemove.call(node.getDOMNode(), d, self);
gary.poster 2012/11/07 15:10:41 So, where other uses of "call" in this file seem p
thiago 2012/11/07 15:21:04 why to you set the scope to getDOMNode and pass se
benji 2012/11/08 17:25:06 This was preexisting code (that got moved around).
134 }
115 } 135 }
116 }, 136 },
117 '.sub-rel-block': { 137 '.sub-rel-block': {
118 mouseenter: function(d, self) { 138 mouseenter: function(d, self) {
119 // Add an 'active' class to all of the subordinate relations 139 // Add an 'active' class to all of the subordinate relations
120 // belonging to this service. 140 // belonging to this service.
121 self.subordinateRelationsForService(d) 141 self.subordinateRelationsForService(d)
122 .forEach(function(p) { 142 .forEach(function(p) {
123 self.addSVGClass('#' + p.id, 'active'); 143 self.addSVGClass('#' + p.id, 'active');
124 }); 144 });
(...skipping 11 matching lines...) Expand all
136 }, 156 },
137 mouseout: function(d, self) { 157 mouseout: function(d, self) {
138 d3.select(this) 158 d3.select(this)
139 .select('.unit-count') 159 .select('.unit-count')
140 .attr('class', 'unit-count hide-count'); 160 .attr('class', 'unit-count hide-count');
141 } 161 }
142 }, 162 },
143 163
144 // Relation Related 164 // Relation Related
145 '.rel-label': { 165 '.rel-label': {
146 click: 'relationClick' 166 /** The user clicked on the relation label. */
167 click: 'relationClick',
168 /**
169 * If the mouse moves over a relation label and we are adding a
170 * relation, then the dragline needs to be updated.
171 */
gary.poster 2012/11/07 15:10:41 Add @method, @param, @return, please. ^D^D^D Never
benji 2012/11/08 17:25:06 I don't understand event bubbling. However I did
172 mousemove: function(d, self) {
173 if (self.clickAddRelation) {
174 var container = self.get('container'),
175 node = container.one('#canvas rect:first-child');
176 self.rectMousemove.call(node.getDOMNode(), d, self);
thiago 2012/11/07 15:21:04 It seems we have mousemove more than once in this
benji 2012/11/08 17:25:06 Good catch. I have refactored the code so there i
benji 2012/11/08 17:25:06 Yep, fixed as per earlier comment.
177 }
178 }
147 }, 179 },
148 180
149 // Canvas related
150 '#canvas rect:first-child': { 181 '#canvas rect:first-child': {
182 /**
183 * If the user clicks on the background we cancel any active add
184 * relation.
gary.poster 2012/11/07 15:10:41 Add @method, @param, @return please. ^D^D^D Neverm
benji 2012/11/08 17:25:06 Refactored away, see above.
185 */
151 click: function(d, self) { 186 click: function(d, self) {
152 var container = self.get('container'); 187 var container = self.get('container');
153 container.all('.environment-menu.active').removeClass('active'); 188 container.all('.environment-menu.active').removeClass('active');
154 self.service_click_actions.toggleControlPanel(null, self); 189 self.service_click_actions.toggleControlPanel(null, self);
155 self.cancelRelationBuild(); 190 self.cancelRelationBuild();
191 },
192 /**
193 * If the mouse moves over the background and we are adding a
194 * relation, then the dragline needs to be updated.
195 */
196 mousemove: function(d, self) {
197 if (self.clickAddRelation) {
198 var container = self.get('container'),
199 node = container.one('#canvas rect:first-child');
200 self.rectMousemove.call(node.getDOMNode(), d, self);
201 }
202 }
203 },
204 '.dragline': {
205 /** The user clicked while the dragline was active. */
206 click: function(d, self) {
207 // It was technically the dragline that was clicked, but the
208 // intent was to click on the background, so...
209 self.backgroundClicked.call(self);
gary.poster 2012/11/07 15:10:41 Please try "self.backgroundClicked();"
thiago 2012/11/07 15:21:04 You dont need to use 'call'. You can do... self.b
benji 2012/11/08 17:25:06 Fixed.
156 } 210 }
157 } 211 }
158 }, 212 },
159 213
160 d3Events: { 214 d3Events: {
161 '.service': { 215 '.service': {
162 'mousedown.addrel': function(d, self) { 216 'mousedown.addrel': function(d, self) {
163 var evt = d3.event; 217 var evt = d3.event;
164 self.longClickTimer = Y.later(750, this, function(d, e) { 218 self.longClickTimer = Y.later(750, this, function(d, e) {
165 // Provide some leeway for accidental dragging. 219 // Provide some leeway for accidental dragging.
166 if ((Math.abs(d.x - d.oldX) + Math.abs(d.y - d.oldY)) / 220 if ((Math.abs(d.x - d.oldX) + Math.abs(d.y - d.oldY)) /
167 2 > 5) { 221 2 > 5) {
168 return; 222 return;
169 } 223 }
170 224
171 // set a flag on the view that we're building a relation
172 self.buildingRelation = true;
173
174 // Sometimes mouseover is fired after the mousedown, so ensure 225 // Sometimes mouseover is fired after the mousedown, so ensure
175 // we have the correct event in d3.event for d3.mouse(). 226 // we have the correct event in d3.event for d3.mouse().
176 d3.event = e; 227 d3.event = e;
177 228
178 // Flash an indicator around the center of the service block.
179 var center = d.getCenter();
180 self.vis.append('circle')
181 .attr('cx', center[0])
182 .attr('cy', center[1])
183 .attr('r', 100)
184 .attr('class', 'mouse-down-indicator')
185 .transition()
186 .duration(750)
187 .ease('bounce')
188 .attr('r', 0)
189 .remove();
190
191 // Start the process of adding a relation 229 // Start the process of adding a relation
192 self.addRelationDragStart.call(self, d, this); 230 self.addRelationDragStart.call(self, d, this);
193 }, [d, evt], false); 231 }, [d, evt], false);
194 }, 232 },
195 'mouseup.addrel': function(d, self) { 233 'mouseup.addrel': function(d, self) {
196 // Cancel the long-click timer if it exists. 234 // Cancel the long-click timer if it exists.
197 if (self.longClickTimer) { 235 if (self.longClickTimer) {
198 self.longClickTimer.cancel(); 236 self.longClickTimer.cancel();
199 } 237 }
200 } 238 }
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 serviceDblClick: function(d, self) { 431 serviceDblClick: function(d, self) {
394 // Just show the service on double-click. 432 // Just show the service on double-click.
395 var service = self.serviceForBox(d); 433 var service = self.serviceForBox(d);
396 (self.service_click_actions.show_service)(service, self); 434 (self.service_click_actions.show_service)(service, self);
397 }, 435 },
398 436
399 relationClick: function(d, self) { 437 relationClick: function(d, self) {
400 self.removeRelationConfirm(d, this, self); 438 self.removeRelationConfirm(d, this, self);
401 }, 439 },
402 440
441 /**
442 * Update the dragline to follow the mouse.
443 *
444 * @method rectMousemove
445 */
446 rectMousemove: function(d, self) {
thiago 2012/11/07 15:21:04 According the the rest of the code, the scope here
benji 2012/11/08 17:25:06 Yep, this got refactored considerably, somewhat al
447 var mouse = d3.mouse(this);
gary.poster 2012/11/07 15:10:41 Commenting that "this" is not what it appears to b
benji 2012/11/08 17:25:06 The refactoring removed the local "this" craziness
448 d3.event.x = mouse[0];
449 d3.event.y = mouse[1];
450 self.addRelationDrag
451 .call(self, self.get('addRelationStart_service'), this);
gary.poster 2012/11/07 15:10:41 This ought to work as "self.addRelationDrag(self.
benji 2012/11/08 17:25:06 Yep. I wonder why there was so much of this patte
452 },
453
403 /* 454 /*
404 * Sync view models with current db.models. 455 * Sync view models with current db.models.
405 */ 456 */
406 updateData: function() { 457 updateData: function() {
407 //model data 458 //model data
408 var vis = this.vis, 459 var vis = this.vis,
409 db = this.get('db'), 460 db = this.get('db'),
410 relations = db.relations.toArray(), 461 relations = db.relations.toArray(),
411 services = db.services.map(views.toBoundingBox); 462 services = db.services.map(views.toBoundingBox);
412 463
(...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after
1013 container = this.get('container'); 1064 container = this.get('container');
1014 if (curr_action === 'show_service') { 1065 if (curr_action === 'show_service') {
1015 this.set('currentServiceClickAction', 'addRelationStart'); 1066 this.set('currentServiceClickAction', 'addRelationStart');
1016 } else if (curr_action === 'addRelationStart' || 1067 } else if (curr_action === 'addRelationStart' ||
1017 curr_action === 'ambiguousAddRelationCheck') { 1068 curr_action === 'ambiguousAddRelationCheck') {
1018 this.set('currentServiceClickAction', 'toggleControlPanel'); 1069 this.set('currentServiceClickAction', 'toggleControlPanel');
1019 } // Otherwise do nothing. 1070 } // Otherwise do nothing.
1020 }, 1071 },
1021 1072
1022 addRelationDragStart: function(d, context) { 1073 addRelationDragStart: function(d, context) {
1023 // Create a pending drag-line behind services. 1074 // Create a pending drag-line behind services.
gary.poster 2012/11/07 15:10:41 Is it really "behind" now? I think it is "in fron
benji 2012/11/08 17:25:06 Done.
1024 var dragline = this.vis.insert('line', '.service') 1075 var dragline = this.vis.append('line')
1025 .attr('class', 'relation pending-relation dragline dragging'), 1076 .attr('class', 'relation pending-relation dragline dragging'),
1026 self = this; 1077 self = this;
1027 1078
1028 // Start the line in the middle of the service. 1079 // Start the line between the cursor and the nearest connector
1029 var point = d.getCenter(); 1080 // point on the service.
1030 dragline.attr('x1', point[0]) 1081 var mouse = d3.mouse(Y.one('svg').getDOMNode());
1031 .attr('y1', point[1]) 1082 self.cursorBox = views.BoundingBox();
1032 .attr('x2', point[0]) 1083 self.cursorBox.pos = {x: mouse[0], y: mouse[1], w: 0, h: 0};
1033 .attr('y2', point[1]); 1084 var point = self.cursorBox.getConnectorPair(d);
1085 dragline.attr('x1', point[0][0])
1086 .attr('y1', point[0][1])
1087 .attr('x2', point[1][0])
1088 .attr('y2', point[1][1]);
1034 self.dragline = dragline; 1089 self.dragline = dragline;
1035 self.cursorBox = views.BoundingBox();
1036 1090
1037 // Start the add-relation process. 1091 // Start the add-relation process.
1038 self.service_click_actions 1092 self.service_click_actions
1039 .addRelationStart(d, self, context); 1093 .addRelationStart(d, self, context);
1040 }, 1094 },
1041 1095
1042 addRelationDrag: function(d, context) { 1096 addRelationDrag: function(d, context) {
1043 // Rubberband our potential relation line if we're not currently 1097 // Rubberband our potential relation line if we're not currently
1044 // hovering over a potential drop-point. 1098 // hovering over a potential drop-point.
1045 if (!this.get('potential_drop_point_service')) { 1099 if (!this.get('potential_drop_point_service')) {
1046 // Create a BoundingBox for our cursor. 1100 // Create a BoundingBox for our cursor.
1047 this.cursorBox.pos = {x: d3.event.x, y: d3.event.y, w: 0, h: 0}; 1101 this.cursorBox.pos = {x: d3.event.x, y: d3.event.y, w: 0, h: 0};
1048 1102
1049 // Draw the relation line from the connector point nearest the 1103 // Draw the relation line from the connector point nearest the
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1126 }, 1180 },
1127 this))); 1181 this)));
1128 }, 1182 },
1129 1183
1130 cancelRelationBuild: function() { 1184 cancelRelationBuild: function() {
1131 if (this.dragline) { 1185 if (this.dragline) {
1132 // Get rid of our drag line 1186 // Get rid of our drag line
1133 this.dragline.remove(); 1187 this.dragline.remove();
1134 this.dragline = null; 1188 this.dragline = null;
1135 } 1189 }
1190 this.clickAddRelation = null;
1136 this.set('currentServiceClickAction', 'toggleControlPanel'); 1191 this.set('currentServiceClickAction', 'toggleControlPanel');
1192 this.buildingRelation = false;
1137 this.show(this.vis.selectAll('.service')) 1193 this.show(this.vis.selectAll('.service'))
1138 .classed('selectable-service', false); 1194 .classed('selectable-service', false);
1139 }, 1195 },
1140 1196
1197 /**
1198 * The user clicked on the environment view background.
1199 *
1200 * If we are in the middle of adding a relation, cancel the relation
1201 * adding.
1202 *
1203 * @method backgroundClicked
gary.poster 2012/11/07 15:10:41 Might as well add a "@return {undefined}" in there
benji 2012/11/08 17:25:06 Done.
1204 */
1205 backgroundClicked: function() {
1206 if (this.clickAddRelation) {
1207 this.cancelRelationBuild();
1208 }
1209 },
1210
1211 /**
1212 * An "add relation" action has been initiated by the user.
1213 *
1214 * @method startRelation
gary.poster 2012/11/07 15:10:41 @param and @return
benji 2012/11/08 17:25:06 Done.
1215 */
1216 startRelation: function(service) {
1217 // Set flags on the view that indicate we are building a relation.
1218 this.buildingRelation = true;
1219 this.clickAddRelation = true;
1220
1221 this.show(this.vis.selectAll('.service'));
1222
1223 var db = this.get('db'),
1224 getServiceEndpoints = this.get('getServiceEndpoints'),
1225 endpoints = models.getEndpoints(
1226 service, getServiceEndpoints(), db),
gary.poster 2012/11/07 15:10:41 I'm guessing that's the best indentation that our
benji 2012/11/08 17:25:06 Fixed. This was bad when it was moved from anothe
1227
1228 /* Transform endpoints into a list of
1229 * relatable services (to the service)
1230 */
gary.poster 2012/11/07 15:10:41 This has broken indentation. Can we simply use "/
benji 2012/11/08 17:25:06 This comment was in this code when I moved it from
1231 possible_relations = Y.Array.map(
thiago 2012/11/07 15:21:04 The indentation in this block is really strange. M
benji 2012/11/08 17:25:06 Agreed. I didn't notice how weird it was when I m
1232 Y.Array.flatten(Y.Object.values(
gary.poster 2012/11/07 15:10:41 can we indent this 2 or 4 spaces?
benji 2012/11/08 17:25:06 This was inherited from elsewhere, but the fix was
1233 endpoints)),
1234 function(ep) {return ep.service;}),
1235 invalidRelationTargets = {};
1236
1237 // Iterate services and invert the possibles list.
1238 db.services.each(function(s) {
1239 if (Y.Array.indexOf(possible_relations,
1240 s.get('id')) === -1) {
1241 invalidRelationTargets[s.get('id')] = true;
1242 }
1243 });
1244
1245 // Fade elements to which we can't relate.
1246 // Rather than two loops this marks
1247 // all services as selectable and then
1248 // removes the invalid ones.
1249 this.fade(this.vis.selectAll('.service')
1250 .classed('selectable-service', true)
1251 .filter(function(d) {
1252 return (d.id in invalidRelationTargets &&
1253 d.id !== service.id);
1254 }))
1255 .classed('selectable-service', false);
1256
1257 // Store possible endpoints.
1258 this.set('addRelationStart_possibleEndpoints', endpoints);
1259 // Set click action.
1260 this.set('currentServiceClickAction', 'ambiguousAddRelationCheck');
1261 },
1262
1141 1263
1142 /* 1264 /*
1143 * Zoom in event handler. 1265 * Zoom in event handler.
1144 */ 1266 */
1145 zoom_out: function(evt) { 1267 zoom_out: function(evt) {
1146 var slider = this.slider, 1268 var slider = this.slider,
1147 val = slider.get('value'); 1269 val = slider.get('value');
1148 slider.set('value', val - 25); 1270 slider.set('value', val - 25);
1149 }, 1271 },
1150 1272
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
1396 } 1518 }
1397 btn.set('disabled', false); 1519 btn.set('disabled', false);
1398 }, 1520 },
1399 1521
1400 1522
1401 /* 1523 /*
1402 * Fired when clicking the first service in the add relation 1524 * Fired when clicking the first service in the add relation
1403 * flow. 1525 * flow.
1404 */ 1526 */
1405 addRelationStart: function(m, view, context) { 1527 addRelationStart: function(m, view, context) {
1406 view.show(view.vis.selectAll('.service')); 1528 var service = view.serviceForBox(m);
1407 1529 view.startRelation.call(view, service);
gary.poster 2012/11/07 15:10:41 Try view.startRelation(service) please
thiago 2012/11/07 15:21:04 It seems you like to use the 'call' function. :)
benji 2012/11/08 17:25:06 The code I inherited likes the call method. I hav
1408 var db = view.get('db'),
1409 getServiceEndpoints = view.get('getServiceEndpoints'),
1410 service = view.serviceForBox(m),
1411 endpoints = models.getEndpoints(
1412 service, getServiceEndpoints(), db),
1413
1414 /* Transform endpoints into a list of
1415 * relatable services (to the service in m)
1416 */
1417 possible_relations = Y.Array.map(
1418 Y.Array.flatten(Y.Object.values(
1419 endpoints)),
1420 function(ep) {return ep.service;}),
1421 invalidRelationTargets = {};
1422
1423 // Iterate services and invert the possibles list.
1424 db.services.each(function(s) {
1425 if (Y.Array.indexOf(possible_relations,
1426 s.get('id')) === -1) {
1427 invalidRelationTargets[s.get('id')] = true;
1428 }
1429 });
1430
1431 // Fade elements to which we can't relate.
1432 // Rather than two loops this marks
1433 // all services as selecable and then
1434 // removes the invalid ones
1435 view.fade(view.vis.selectAll('.service')
1436 .classed('selectable-service', true)
1437 .filter(function(d) {
1438 return (d.id in invalidRelationTargets &&
1439 d.id !== m.id);
1440 }))
1441 .classed('selectable-service', false);
1442
1443
1444
1445 // Store start service in attrs. 1530 // Store start service in attrs.
1446 view.set('addRelationStart_service', m); 1531 view.set('addRelationStart_service', m);
1447 // Store possible endpoints.
1448 view.set('addRelationStart_possibleEndpoints', endpoints);
1449 // Set click action.
1450 view.set('currentServiceClickAction', 'ambiguousAddRelationCheck');
1451 }, 1532 },
1452 1533
1453 /* 1534 /*
1454 * Test if the pending relation is ambiguous. Display a menu if so, 1535 * Test if the pending relation is ambiguous. Display a menu if so,
1455 * create the relation if not. 1536 * create the relation if not.
1456 */ 1537 */
1457 ambiguousAddRelationCheck: function(m, view, context) { 1538 ambiguousAddRelationCheck: function(m, view, context) {
1458 var endpoints = view 1539 var endpoints = view
1459 .get('addRelationStart_possibleEndpoints')[m.id], 1540 .get('addRelationStart_possibleEndpoints')[m.id],
1460 container = view.get('container'); 1541 container = view.get('container');
(...skipping 11 matching lines...) Expand all
1472 view.service_click_actions 1553 view.service_click_actions
1473 .addRelationEnd(endpoints_item, view, context); 1554 .addRelationEnd(endpoints_item, view, context);
1474 return; 1555 return;
1475 } 1556 }
1476 1557
1477 // Sort the endpoints alphabetically by relation name. 1558 // Sort the endpoints alphabetically by relation name.
1478 endpoints = endpoints.sort(function(a, b) { 1559 endpoints = endpoints.sort(function(a, b) {
1479 return a[0].name + a[1].name < b[0].name + b[1].name; 1560 return a[0].name + a[1].name < b[0].name + b[1].name;
1480 }); 1561 });
1481 1562
1482 // Create a pending line if it doesn't exist, as in the case of 1563 // Stop rubberbanding on mousemove.
1483 // clicking to add relation. 1564 view.clickAddRelation = null;
1484 if (!view.dragline) {
1485 var dragline = view.vis.insert('line', '.service')
1486 .attr('class', 'relation pending-relation dragline'),
1487 points = m.getConnectorPair(
1488 view.get('addRelationStart_service'));
1489 dragline.attr('x1', points[0][0])
1490 .attr('y1', points[0][1])
1491 .attr('x2', points[1][0])
1492 .attr('y2', points[1][1]);
1493 view.dragline = dragline;
1494 }
1495 1565
1496 // Display menu with available endpoints. 1566 // Display menu with available endpoints.
1497 var menu = container.one('#ambiguous-relation-menu'); 1567 var menu = container.one('#ambiguous-relation-menu');
1498 if (menu.one('.menu')) { 1568 if (menu.one('.menu')) {
1499 menu.one('.menu').remove(true); 1569 menu.one('.menu').remove(true);
1500 } 1570 }
1501 1571
1502 menu.append(Templates 1572 menu.append(Templates
1503 .ambiguousRelationList({endpoints: endpoints})); 1573 .ambiguousRelationList({endpoints: endpoints}));
1504 1574
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
1636 'juju-models', 1706 'juju-models',
1637 'd3', 1707 'd3',
1638 'base-build', 1708 'base-build',
1639 'handlebars-base', 1709 'handlebars-base',
1640 'node', 1710 'node',
1641 'svg-layouts', 1711 'svg-layouts',
1642 'event-resize', 1712 'event-resize',
1643 'slider', 1713 'slider',
1644 'view'] 1714 'view']
1645 }); 1715 });
OLDNEW
« no previous file with comments | « [revision details] ('k') | test/test_environment_view.js » ('j') | test/test_environment_view.js » ('J')

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 204d58d