Merge lp:~benji/juju-gui/add-rel-improvements-3 into lp:juju-gui/experimental

Proposed by Benji York
Status: Merged
Merged at revision: 233
Proposed branch: lp:~benji/juju-gui/add-rel-improvements-3
Merge into: lp:juju-gui/experimental
Diff against target: 553 lines (+216/-93)
5 files modified
README (+1/-1)
app/views/environment.js (+151/-91)
docs/style-guide.rst (+38/-0)
test/test_environment_view.js (+26/-0)
undocumented (+0/-1)
To merge this branch: bzr merge lp:~benji/juju-gui/add-rel-improvements-3
Reviewer Review Type Date Requested Status
Gary Poster (community) Approve
Review via email: mp+133104@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Gary Poster (gary) wrote :
Download full text (7.1 KiB)

Hey Benji. Thank you for this. It is a nice improvement that worked
well when I tried it. Tests passed and merge with trunk was also fine
for me.

I have a bunch of fairly trivial comments & requests. If you agree,
please just make the changes and treat this as an automatic approval.

Gary

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js
File app/views/environment.js (right):

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode1
app/views/environment.js:1: 'use strict';
Please add the module yuidoc comment.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode10
app/views/environment.js:10: var EnvironmentView =
Y.Base.create('EnvironmentView', Y.View,
Please add the class yuidoc comment.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode23
app/views/environment.js:23: /** The user clicked on the "Build
Relation" menu item. */
We had a good conversation in a hangout about my mild concerns about the
fact that this is required because of yuidoc-linter even though yuidoc
ignored it; and about the fact that you are using a /** TEXT */ syntax
when I thought we were standardizing on a multiline syntax:
/**
  * TEXT
  */

I still have those concerns, and would feel slightly happier if you
changed to always use the multiline spelling (particularly given the use
of "/* */" rather than "//") but I am OK with letting you document and
advocate for your positions, in your role as
Bringer-of-YUIDoc-to-the-Masses.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode28
app/views/environment.js:28: this.addRelationDragStart.call(this, box,
context);
Could you check to see if "this.addRelationDragStart(box, context);"
will work? I think it will.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode82
app/views/environment.js:82: }
not entirely idle thought, but one that is not really directly pertinent
to your branch: I wonder how a service is supposed to make a
relationship to itself, which IIUC is possible.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode128
app/views/environment.js:128: */
As mentioned yesterday, please add @method, @param and @return tags with
the appropriate bits and bobs.

Oh, wait: this is an event handler, so yuidoc will not document it.

:-( I find this a bit hard to catch.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode133
app/views/environment.js:133: self.rectMousemove.call(node.getDOMNode(),
d, self);
So, where other uses of "call" in this file seem pointless, this one
actually seems to have a point...and it seems like a really odd pattern
to me. As we discussed yesterday, you are following an existing
pattern, so I'm not asking for any changes from you, but could you find
out from Matt or Ben why this pattern exists, and arrange for the
information to be shared with the rest of us, either from them or you?

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode171
app/views/environment.js:171: */
Add @method, @param, @return, please. ^D^D^D Nevermind, event handler.

Unnecessary ext...

Read more...

Revision history for this message
Gary Poster (gary) :
review: Approve
Revision history for this message
Thiago Veronezi (tveronezi) wrote :

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js
File app/views/environment.js (right):

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode28
app/views/environment.js:28: this.addRelationDragStart.call(this, box,
context);
why do you need to use the 'call' method and pass 'this'?
You could simply call 'this.addRelationDragStart(box, context)', no?

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode133
app/views/environment.js:133: self.rectMousemove.call(node.getDOMNode(),
d, self);
why to you set the scope to getDOMNode and pass self ('this') as
parameter? You could pass the domNode as parameter instead...

self.rectMousemove(node.getDOMNode(), d);

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode176
app/views/environment.js:176: self.rectMousemove.call(node.getDOMNode(),
d, self);
It seems we have mousemove more than once in this file. You could
extract it to a common function in this closure.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode209
app/views/environment.js:209: self.backgroundClicked.call(self);
You dont need to use 'call'. You can do...

self.backgroundClicked();

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode446
app/views/environment.js:446: rectMousemove: function(d, self) {
According the the rest of the code, the scope here is domNode. If you
dont change the scope you can do (not tested... :) )...

// *************************
self.rectMousemove(node.getDOMNode());

rectMousemove: function(domNode) {
   var mouse = d3.mouse(domNode);
   d3.event.x = mouse[0];
   d3.event.y = mouse[1];
   this.addRelationDrag(this.get('addRelationStart_service'), domNode);
},
// *************************

btw, you dont use the 'd' parameter.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode1231
app/views/environment.js:1231: possible_relations = Y.Array.map(
The indentation in this block is really strange. Maybe you could just
declare the variable and then assign the value to it in another line.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode1529
app/views/environment.js:1529: view.startRelation.call(view, service);
It seems you like to use the 'call' function. :)

https://codereview.appspot.com/6821088/diff/1/undocumented
File undocumented (left):

https://codereview.appspot.com/6821088/diff/1/undocumented#oldcode116
undocumented:116: app/views/environment.js click
On 2012/11/07 15:10:41, gary.poster wrote:
> The People of the Future thank you.

Hahahaha!

https://codereview.appspot.com/6821088/

223. By Benji York

add YUIDoc info to the style guide

224. By Benji York

refactorings prompted by review

Revision history for this message
Gary Poster (gary) wrote :
Download full text (7.7 KiB)

On 2012/11/08 17:25:06, benji wrote:
> I have addressed everything other than one comment by Gary about the
tests in
> which I couldn’t figure out what he wanted.

Thank you!

I'd be happy to re-review if you wanted, but it is not up in Rietveld so
I won't unless you ask. I'll reply to a few comments here in-line
below, though.

...

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode23
> app/views/environment.js:23: /** The user clicked on the "Build
Relation" menu
> item. */
> On 2012/11/07 15:10:41, gary.poster wrote:
> > We had a good conversation in a hangout about my mild concerns about
the fact
> > that this is required because of yuidoc-linter even though yuidoc
ignored it;
> > and about the fact that you are using a /** TEXT */ syntax when I
thought we
> > were standardizing on a multiline syntax:
> > /**
> > * TEXT
> > */
> >
> > I still have those concerns, and would feel slightly happier if you
changed to
> > always use the multiline spelling (particularly given the use of "/*
*/"
> rather
> > than "//") but I am OK with letting you document and advocate for
your
> > positions, in your role as Bringer-of-YUIDoc-to-the-Masses.

> The multi-line format seems to overemphasize the importance of the
comment, so I
> have left these. However, I have updated the style guide to include a
(first
> draft) policy that explains the situations in which you would use one
or the
> other.

Cool, sounds good. Thank you.

...

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode128
> app/views/environment.js:128: */
> On 2012/11/07 15:10:41, gary.poster wrote:
> > As mentioned yesterday, please add @method, @param and @return tags
with the
> > appropriate bits and bobs.
> >
> > Oh, wait: this is an event handler, so yuidoc will not document it.
> >
> > :-( I find this a bit hard to catch.

> Yep, the plethora of event handlers makes this code hard to grok. I
am not sure
> what we should do instead. As an improvement I refactored the code so
there is
> a single view method that gets called when any of the mousemove events
are
> triggered. That method now has full docs.

Huh, cool. Sounds good, thank you.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode133
> app/views/environment.js:133:
self.rectMousemove.call(node.getDOMNode(), d,
> self);
> On 2012/11/07 15:21:04, thiago wrote:
> > why to you set the scope to getDOMNode and pass self ('this') as
parameter?
> You
> > could pass the domNode as parameter instead...

> This was preexisting code (that got moved around). It is indeed
insane. I
> refactored this extensively and it now doesn't do this.

:-) Cool!

Ben told be that ".call" has the advantage of naturally supporting
chaining. However, in my own experiments I could not get this to work
so I may have misunderstood.

https://codereview.appspot.com/6821088/diff/1/app/views/environment.js#newcode171
> app/views/environment.js:171: */
> On 2012/11/07 15:10:41, gary.poster wrote:
> > Add @method, @param, @return, please. ^D^D^D Nevermind, event
han...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2012-11-05 19:35:15 +0000
3+++ README 2012-11-08 17:28:23 +0000
4@@ -105,7 +105,7 @@
5
6 $ make yuidoc
7
8-The documentation for yuidoc markup is at
9+The documentation for YUIDoc markup is at
10 http://yui.github.com/yuidoc/syntax/ .
11
12 Running lint
13
14=== modified file 'app/views/environment.js'
15--- app/views/environment.js 2012-11-07 12:32:38 +0000
16+++ app/views/environment.js 2012-11-08 17:28:23 +0000
17@@ -1,4 +1,9 @@
18 'use strict';
19+/**
20+ * Provides the main app class.
21+ *
22+ * @module views
23+ */
24
25 YUI.add('juju-view-environment', function(Y) {
26
27@@ -7,6 +12,12 @@
28 Templates = views.Templates,
29 models = Y.namespace('juju.models');
30
31+ /**
32+ * Display an environment.
33+ *
34+ * @class environment
35+ * @namespace views
36+ */
37 var EnvironmentView = Y.Base.create('EnvironmentView', Y.View,
38 [views.JujuBaseView], {
39 events: {
40@@ -20,17 +31,19 @@
41 },
42 // Menu/Controls
43 '.add-relation': {
44+ /** The user clicked on the "Build Relation" menu item. */
45 click: function() {
46 var box = this.get('active_service'),
47 service = this.serviceForBox(box),
48 context = this.get('active_context');
49+ this.addRelationDragStart(box, context);
50 this.service_click_actions
51 .toggleControlPanel(box, this, context);
52- this.service_click_actions
53- .addRelationStart(box, this, context);
54+ this.service_click_actions.addRelationStart(box, this, context);
55 }
56 },
57 '.view-service': {
58+ /** The user clicked on the "View" menu item. */
59 click: function() {
60 // Get the service element
61 var box = this.get('active_service'),
62@@ -42,6 +55,7 @@
63 }
64 },
65 '.destroy-service': {
66+ /** The user clicked on the "Destroy" menu item. */
67 click: function() {
68 // Get the service element
69 var box = this.get('active_service'),
70@@ -72,6 +86,12 @@
71 if (!d.containsPoint(mouse_coords, self.zoom)) {
72 return;
73 }
74+
75+ // Do not fire if we're on the same service.
76+ if (d === self.get('addRelationStart_service')) {
77+ return;
78+ }
79+
80 self.set('potential_drop_point_service', d);
81 self.set('potential_drop_point_rect', rect);
82 self.addSVGClass(rect, 'hover');
83@@ -112,7 +132,8 @@
84 self.dragline.attr('class',
85 'relation pending-relation dragline dragging');
86 }
87- }
88+ },
89+ mousemove: 'mousemove'
90 },
91 '.sub-rel-block': {
92 mouseenter: function(d, self) {
93@@ -143,16 +164,30 @@
94
95 // Relation Related
96 '.rel-label': {
97- click: 'relationClick'
98+ /** The user clicked on the relation label. */
99+ click: 'relationClick',
100+ mousemove: 'mousemove'
101 },
102
103- // Canvas related
104 '#canvas rect:first-child': {
105+ /**
106+ * If the user clicks on the background we cancel any active add
107+ * relation.
108+ */
109 click: function(d, self) {
110 var container = self.get('container');
111 container.all('.environment-menu.active').removeClass('active');
112 self.service_click_actions.toggleControlPanel(null, self);
113 self.cancelRelationBuild();
114+ },
115+ mousemove: 'mousemove'
116+ },
117+ '.dragline': {
118+ /** The user clicked while the dragline was active. */
119+ click: function(d, self) {
120+ // It was technically the dragline that was clicked, but the
121+ // intent was to click on the background, so...
122+ self.backgroundClicked();
123 }
124 }
125 },
126@@ -168,28 +203,12 @@
127 return;
128 }
129
130- // set a flag on the view that we're building a relation
131- self.buildingRelation = true;
132-
133 // Sometimes mouseover is fired after the mousedown, so ensure
134 // we have the correct event in d3.event for d3.mouse().
135 d3.event = e;
136
137- // Flash an indicator around the center of the service block.
138- var center = d.getCenter();
139- self.vis.append('circle')
140- .attr('cx', center[0])
141- .attr('cy', center[1])
142- .attr('r', 100)
143- .attr('class', 'mouse-down-indicator')
144- .transition()
145- .duration(750)
146- .ease('bounce')
147- .attr('r', 0)
148- .remove();
149-
150 // Start the process of adding a relation
151- self.addRelationDragStart.call(self, d, this);
152+ self.addRelationDragStart(d, this);
153 }, [d, evt], false);
154 },
155 'mouseup.addrel': function(d, self) {
156@@ -400,6 +419,27 @@
157 self.removeRelationConfirm(d, this, self);
158 },
159
160+ /**
161+ * If the mouse moves and we are adding a relation, then the dragline
162+ * needs to be updated.
163+ *
164+ * @method mousemove
165+ * @param {object} d Unused.
166+ * @param {object} self The environment view itself.
167+ * @return {undefined} Side effects only.
168+ */
169+ mousemove: function(d, self) {
170+ if (self.clickAddRelation) {
171+ var container = self.get('container'),
172+ node = container.one('#canvas rect:first-child').getDOMNode(),
173+ mouse = d3.mouse(node);
174+ d3.event.x = mouse[0];
175+ d3.event.y = mouse[1];
176+ self.addRelationDrag
177+ .call(self, self.get('addRelationStart_service'), node);
178+ }
179+ },
180+
181 /*
182 * Sync view models with current db.models.
183 */
184@@ -461,7 +501,7 @@
185 })
186 .on('drag', function(d, i) {
187 if (self.buildingRelation) {
188- self.addRelationDrag.call(self, d, this);
189+ self.addRelationDrag(d, this);
190 } else {
191 if (self.longClickTimer) {
192 self.longClickTimer.cancel();
193@@ -483,7 +523,7 @@
194 })
195 .on('dragend', function(d, i) {
196 if (self.buildingRelation) {
197- self.addRelationDragEnd.call(self, d, this);
198+ self.addRelationDragEnd();
199 }
200 });
201
202@@ -1020,23 +1060,26 @@
203 },
204
205 addRelationDragStart: function(d, context) {
206- // Create a pending drag-line behind services.
207- var dragline = this.vis.insert('line', '.service')
208+ // Create a pending drag-line.
209+ var dragline = this.vis.append('line')
210 .attr('class', 'relation pending-relation dragline dragging'),
211 self = this;
212
213- // Start the line in the middle of the service.
214- var point = d.getCenter();
215- dragline.attr('x1', point[0])
216- .attr('y1', point[1])
217- .attr('x2', point[0])
218- .attr('y2', point[1]);
219+ // Start the line between the cursor and the nearest connector
220+ // point on the service.
221+ var mouse = d3.mouse(Y.one('svg').getDOMNode());
222+ self.cursorBox = views.BoundingBox();
223+ self.cursorBox.pos = {x: mouse[0], y: mouse[1], w: 0, h: 0};
224+ var point = self.cursorBox.getConnectorPair(d);
225+ dragline.attr('x1', point[0][0])
226+ .attr('y1', point[0][1])
227+ .attr('x2', point[1][0])
228+ .attr('y2', point[1][1]);
229 self.dragline = dragline;
230- self.cursorBox = views.BoundingBox();
231
232 // Start the add-relation process.
233 self.service_click_actions
234- .addRelationStart(d, self, context);
235+ .addRelationStart(d, self, context);
236 },
237
238 addRelationDrag: function(d, context) {
239@@ -1057,7 +1100,7 @@
240 }
241 },
242
243- addRelationDragEnd: function(d, context) {
244+ addRelationDragEnd: function() {
245 // Get the line, the endpoint service, and the target <rect>.
246 var self = this;
247 var rect = self.get('potential_drop_point_rect');
248@@ -1133,11 +1176,80 @@
249 this.dragline.remove();
250 this.dragline = null;
251 }
252+ this.clickAddRelation = null;
253 this.set('currentServiceClickAction', 'toggleControlPanel');
254+ this.buildingRelation = false;
255 this.show(this.vis.selectAll('.service'))
256 .classed('selectable-service', false);
257 },
258
259+ /**
260+ * The user clicked on the environment view background.
261+ *
262+ * If we are in the middle of adding a relation, cancel the relation
263+ * adding.
264+ *
265+ * @method backgroundClicked
266+ * @return {undefined} Side effects only.
267+ */
268+ backgroundClicked: function() {
269+ if (this.clickAddRelation) {
270+ this.cancelRelationBuild();
271+ }
272+ },
273+
274+ /**
275+ * An "add relation" action has been initiated by the user.
276+ *
277+ * @method startRelation
278+ * @param {object} service The service that is the source of the
279+ * relation.
280+ * @return {undefined} Side effects only.
281+ */
282+ startRelation: function(service) {
283+ // Set flags on the view that indicate we are building a relation.
284+ this.buildingRelation = true;
285+ this.clickAddRelation = true;
286+
287+ this.show(this.vis.selectAll('.service'));
288+
289+ var db = this.get('db'),
290+ getServiceEndpoints = this.get('getServiceEndpoints'),
291+ endpoints = models.getEndpoints(
292+ service, getServiceEndpoints(), db),
293+ // Transform endpoints into a list of relatable services (to the
294+ // service).
295+ possible_relations = Y.Array.map(
296+ Y.Array.flatten(Y.Object.values(endpoints)),
297+ function(ep) {return ep.service;}),
298+ invalidRelationTargets = {};
299+
300+ // Iterate services and invert the possibles list.
301+ db.services.each(function(s) {
302+ if (Y.Array.indexOf(possible_relations,
303+ s.get('id')) === -1) {
304+ invalidRelationTargets[s.get('id')] = true;
305+ }
306+ });
307+
308+ // Fade elements to which we can't relate.
309+ // Rather than two loops this marks
310+ // all services as selectable and then
311+ // removes the invalid ones.
312+ this.fade(this.vis.selectAll('.service')
313+ .classed('selectable-service', true)
314+ .filter(function(d) {
315+ return (d.id in invalidRelationTargets &&
316+ d.id !== service.id);
317+ }))
318+ .classed('selectable-service', false);
319+
320+ // Store possible endpoints.
321+ this.set('addRelationStart_possibleEndpoints', endpoints);
322+ // Set click action.
323+ this.set('currentServiceClickAction', 'ambiguousAddRelationCheck');
324+ },
325+
326
327 /*
328 * Zoom in event handler.
329@@ -1403,51 +1515,10 @@
330 * flow.
331 */
332 addRelationStart: function(m, view, context) {
333- view.show(view.vis.selectAll('.service'));
334-
335- var db = view.get('db'),
336- getServiceEndpoints = view.get('getServiceEndpoints'),
337- service = view.serviceForBox(m),
338- endpoints = models.getEndpoints(
339- service, getServiceEndpoints(), db),
340-
341- /* Transform endpoints into a list of
342- * relatable services (to the service in m)
343- */
344- possible_relations = Y.Array.map(
345- Y.Array.flatten(Y.Object.values(
346- endpoints)),
347- function(ep) {return ep.service;}),
348- invalidRelationTargets = {};
349-
350- // Iterate services and invert the possibles list.
351- db.services.each(function(s) {
352- if (Y.Array.indexOf(possible_relations,
353- s.get('id')) === -1) {
354- invalidRelationTargets[s.get('id')] = true;
355- }
356- });
357-
358- // Fade elements to which we can't relate.
359- // Rather than two loops this marks
360- // all services as selecable and then
361- // removes the invalid ones
362- view.fade(view.vis.selectAll('.service')
363- .classed('selectable-service', true)
364- .filter(function(d) {
365- return (d.id in invalidRelationTargets &&
366- d.id !== m.id);
367- }))
368- .classed('selectable-service', false);
369-
370-
371-
372+ var service = view.serviceForBox(m);
373+ view.startRelation(service);
374 // Store start service in attrs.
375 view.set('addRelationStart_service', m);
376- // Store possible endpoints.
377- view.set('addRelationStart_possibleEndpoints', endpoints);
378- // Set click action.
379- view.set('currentServiceClickAction', 'ambiguousAddRelationCheck');
380 },
381
382 /*
383@@ -1479,19 +1550,8 @@
384 return a[0].name + a[1].name < b[0].name + b[1].name;
385 });
386
387- // Create a pending line if it doesn't exist, as in the case of
388- // clicking to add relation.
389- if (!view.dragline) {
390- var dragline = view.vis.insert('line', '.service')
391- .attr('class', 'relation pending-relation dragline'),
392- points = m.getConnectorPair(
393- view.get('addRelationStart_service'));
394- dragline.attr('x1', points[0][0])
395- .attr('y1', points[0][1])
396- .attr('x2', points[1][0])
397- .attr('y2', points[1][1]);
398- view.dragline = dragline;
399- }
400+ // Stop rubberbanding on mousemove.
401+ view.clickAddRelation = null;
402
403 // Display menu with available endpoints.
404 var menu = container.one('#ambiguous-relation-menu');
405
406=== modified file 'docs/style-guide.rst'
407--- docs/style-guide.rst 2012-10-04 17:07:28 +0000
408+++ docs/style-guide.rst 2012-11-08 17:28:23 +0000
409@@ -5,6 +5,7 @@
410 This guide is an attempt to describe a code style that both works well with the
411 JavaScript beautifier and helps developers avoid pitfalls.
412
413+
414 Indentation
415 ===========
416
417@@ -13,18 +14,21 @@
418 beautifier ("make beautify"). The lowest (least leading whitespace) acceptable
419 indention will be applied.
420
421+
422 For loops
423 =========
424
425 Unless you are counting something, for loops (and for-in loops) are a trap.
426 Use Y.Object.each instead.
427
428+
429 Whitespace
430 ==========
431
432 No trailing whitespace on lines or at the end of the file (i.e., the file
433 should end with a non-blank line).
434
435+
436 Object literal formatting
437 =========================
438
439@@ -61,6 +65,7 @@
440 type: 'int'}},
441 errors = utils.validate(values, schema);
442
443+
444 Chaining method calls
445 =====================
446
447@@ -118,6 +123,7 @@
448 .bing()
449 .zing());
450
451+
452 Creating HTML
453 =============
454
455@@ -148,3 +154,35 @@
456
457 It is important that the indentation of the calls communicates the structure of
458 the resulting DOM tree. Compare and contrast the above examples.
459+
460+
461+Comments
462+========
463+
464+We use YUIDoc to document the applications internals. YUIDoc comments
465+start with "/**" and end with "*/". The Makefile includes a simple
466+linter that enforces YUIDoc comments for each function in the
467+application.
468+
469+This simple linting sometimes means that functions that we might not
470+otherwise document require documentation. If a one-line comment is
471+sufficient in those situations, a comment of this form may be used:
472+
473+ /** Handle errors */
474+ error_callback: function(err) {
475+ ...
476+ }
477+
478+Most functions (or methods) will call for normal, multi-line YUIDoc
479+comments like this:
480+
481+ /**
482+ * Frob the thingy.
483+ *
484+ * @method frob
485+ * @param {object} type How the thingy should be frobbed.
486+ * @return {undefined} Side-effects only, eturns nothing.
487+ */
488+
489+Full documentation for the various YUIDoc directives is at
490+http://yui.github.com/yuidoc/syntax/ .
491
492=== modified file 'test/test_environment_view.js'
493--- test/test_environment_view.js 2012-11-01 13:21:53 +0000
494+++ test/test_environment_view.js 2012-11-08 17:28:23 +0000
495@@ -340,6 +340,9 @@
496 container.all('.selectable-service')
497 .size()
498 .should.equal(2);
499+ container.all('.dragline')
500+ .size()
501+ .should.equal(1);
502 service.next().simulate('click');
503 container.all('.selectable-service').size()
504 .should.equal(0);
505@@ -370,6 +373,28 @@
506 view.get('rmrelation_dialog').hide();
507 });
508
509+ it('should stop creating a relation if the background is clicked',
510+ function() {
511+ var db = new models.Database(),
512+ endpoint_map = {'service-1': {requires: [], provides: []}},
513+ view = new views.environment(
514+ { container: container,
515+ db: db,
516+ env: env,
517+ getServiceEndpoints: function() {return endpoint_map;}}),
518+ service = new models.Service({ id: 'service-1'});
519+
520+ db.services.add([service]);
521+ view.render();
522+
523+ // If the user has clicked on the "Add Relation" menu item...
524+ view.startRelation(service);
525+ assert.isTrue(view.buildingRelation);
526+ // ...clicking on the background causes the relation drag to stop.
527+ view.backgroundClicked();
528+ assert.isFalse(view.buildingRelation);
529+ });
530+
531 // TODO: This will be fully testable once we have specification on the
532 // list view itself. Skipped until then.
533 it.skip('must be able to switch between graph and list views',
534@@ -390,6 +415,7 @@
535 }
536 );
537 });
538+
539 describe('view model support infrastructure', function() {
540 var Y, views, models;
541
542
543=== modified file 'undocumented'
544--- undocumented 2012-11-06 02:04:22 +0000
545+++ undocumented 2012-11-08 17:28:23 +0000
546@@ -110,7 +110,6 @@
547 app/views/environment.js attachSceneEvents
548 app/views/environment.js buildScene
549 app/views/environment.js cancelRelationBuild
550-app/views/environment.js click
551 app/views/environment.js destroyService
552 app/views/environment.js destroyServiceConfirm
553 app/views/environment.js detachSceneEvents

Subscribers

People subscribed via source and target branches