Description:
Make safe relation ids in environment view
Relation ids included spaces and other problematic chacracters in our
related DOM ids. This branch cleans those up, and also does a quick CSS
cleanup to make some text legible again.
Affected files:
A [revision details]
M app/templates/unit.handlebars
M app/views/topology/relation.js
M app/views/utils.js
M lib/views/stylesheet.less
M test/test_environment_view.js
M test/test_topology_relation.js
M test/test_utils.js
{{#unless relations}}
-This unit has no relations.
+<div class="yui3-u">This unit has no relations.</div>
{{else}}
<div id="relations" class="yui3-g">
<div class="yui3-u-1">
enter.insert('g', 'g.service') .attr('id', function(d) {
- return d.id;
+ return utils.generateSafeDOMId(d.id);
}) .attr('class', function(d) { // Mark the rel-group as a subordinate relation if need be.
@@ -461,7 +461,7 @@
// At this time, relations may have been redrawn, so here we have to
// retrieve the relation DOM element again.
var relationElement = view.get('container')
- .one('#' + relation.relation_id);
+ .one('#' + utils.generateSafeDOMId(relation.relation_id)); utils.addSVGClass(relationElement, 'to-remove pending-relation'); env.remove_relation(relation.endpoints[0], relation.endpoints[1], Y.bind(this._removeRelationCallback, this, view,
@@ -747,7 +747,7 @@
// Remove our pending relation from the DB, error or no. db.relations.remove( db.relations.getById(relation_id));
- vis.select('#' + relation_id).remove();
+ vis.select('#' + utils.generateSafeDOMId(relation_id)).remove();
if (ev.err) { db.notifications.add(
new models.Notification({
Reviewers: mp+158224_ code.launchpad. net,
Message:
Please take a look.
Description:
Make safe relation ids in environment view
Relation ids included spaces and other problematic chacracters in our
related DOM ids. This branch cleans those up, and also does a quick CSS
cleanup to make some text legible again.
https:/ /code.launchpad .net/~gary/ juju-gui/ bug1167295/ +merge/ 158224
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/8640043/
Affected files: unit.handlebars topology/ relation. js stylesheet. less environment_ view.js topology_ relation. js
A [revision details]
M app/templates/
M app/views/
M app/views/utils.js
M lib/views/
M test/test_
M test/test_
M test/test_utils.js
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>
Index: test/test_ environment_ view.js environment_ view.js' environment_ view.js 2013-04-04 14:45:42 +0000 environment_ view.js 2013-04-10 21:17:18 +0000 g).use( [
'juju- views', 'juju-tests-utils', 'juju-env',
'node- event-simulate' , 'juju-gui', 'slider', 'juju-tests. utils') ; 'juju.views' );
parseInt( this.getAttribu te(e), 10))
.should. equal(true) ; generateSafeDOM Id('relation- 0000000007' )); isNotNull( node); isDefined( node);
=== modified file 'test/test_
--- test/test_
+++ test/test_
@@ -84,7 +84,7 @@
Y = YUI(GlobalConfi
- 'landscape', 'dump'
+ 'landscape', 'dump', 'juju-view-utils'
], function(Y) {
testUtils = Y.namespace(
views = Y.namespace(
@@ -170,6 +170,13 @@
}, line);
+
+ // Verify that the node id has been munged as expected from the
+ // relation id. This is particularly important for Juju Core.
+ var node = container.one(
+ '#' + views.utils.
+ assert.
+ assert.
});
it('must be able to render subordinate and normal services',
@@ -750,7 +757,9 @@
db: db,
env: env}).render();
- var relation = container. one('#relation- 0000000001 .rel-label'), generateSafeDOM Id('relation- 0000000001' ) +
dialog_ btn,
+ var relation = container.one(
+ '#' + views.utils.
+ ' .rel-label'),
panel;
@@ -778,7 +787,9 @@
env: env}).render();
// Get a subordinate relation. one('#relation- 0000000007 .rel-label'), generateSafeDOM Id('relation- 0000000007' ) +
dialog_ btn,
- var relation = container.
+ var relation = container.one(
+ '#' + views.utils.
+ ' .rel-label'),
panel;
Index: test/test_ topology_ relation. js topology_ relation. js' topology_ relation. js 2013-01-23 21:56:36 +0000 topology_ relation. js 2013-04-10 21:17:18 +0000
=== modified file 'test/test_
--- test/test_
+++ test/test_
@@ -4,7 +4,8 @@
var Y, views, view, container, topo, db;
before( function( done) { g).use( ['juju- topology' , 'node', 'node-event- simulate' ], g).use( simulate' , 'juju-view-utils'],
function( Y) { 'juju.views' ); removeRelation. call(fauxView, relation, fauxView, undefined); equal(requested Selector, '#' + relationId); generateSafeDOM Id(relationId) );
- Y =
YUI(GlobalConfi
+ Y = YUI(GlobalConfi
+
['juju-topology', 'node', 'node-event-
views = Y.namespace(
done();
@@ -87,7 +88,8 @@
endpoints: [null, null]
};
view.
- assert.
+ assert.equal(
+ requestedSelector, '#' +
views.utils.
});
});
Index: app/templates/ unit.handlebars unit.handlebars ' unit.handlebars 2013-04-10 09:48:16 +0000 unit.handlebars 2013-04-10 20:37:33 +0000
=== modified file 'app/templates/
--- app/templates/
+++ app/templates/
@@ -55,7 +55,7 @@
</div>
{{#unless relations}}
-This unit has no relations.
+<div class="yui3-u">This unit has no relations.</div>
{{else}}
<div id="relations" class="yui3-g">
<div class="yui3-u-1">
Index: app/views/utils.js utils.js' 'juju.views' ), 'juju.views. utils') ;
=== modified file 'app/views/
--- app/views/utils.js 2013-04-10 09:40:06 +0000
+++ app/views/utils.js 2013-04-10 21:17:18 +0000
@@ -12,6 +12,41 @@
var views = Y.namespace(
utils = Y.namespace(
+ /*jshint bitwise: false*/ goo.gl/ PEOgF '').reduce( charCodeAt( 0); /bugs.launchpad .net/juju- gui/+bug/ 1167295 /\W/g, '_') + '-' + generateHash( value)) ; afeDOMId = generateSafeDOMId; mNow: null,
+ /**
+ Create a hash of a string. From stackoverflow: http://
+
+ @method generateHash
+ @param {String} value The string to hash.
+ @return {Integer} The hash of the string.
+ */
+ var generateHash = function(value) {
+ return value.split(
+ function(hash, character) {
+ hash = ((hash << 5) - hash) + character.
+ return hash & hash;
+ },
+ 0
+ );
+ };
+ /*jshint bitwise: true*/
+ utils.generateHash = generateHash;
+
+ /**
+ Create a stable, safe DOM id given an arbitrary string.
+ See details and discussion in
+ https:/
+
+ @method generateSafeDOMId
+ @param {String} value The string to hash.
+ @return {String} The calculated DOM id.
+ */
+ var generateSafeDOMId = function(value) {
+ return (
+ value.replace(
+ };
+ utils.generateS
+
var timestrings = {
prefixAgo: null,
prefixFro
Index: app/views/ topology/ relation. js topology/ relation. js' topology/ relation. js 2013-04-10 16:38:13 +0000 topology/ relation. js 2013-04-10 21:17:18 +0000
relation. target. id === service.id; afeDOMId( relation. id));
. getConnectorPai r(relation. target) ;
=== modified file 'app/views/
--- app/views/
+++ app/views/
@@ -164,7 +164,7 @@
return relation.source.id === service.id ||
}), function(relation) {
- var rel_group = d3.select('#' + relation.id);
+ var rel_group = d3.select('#' +
utils.generateS
var connectors = relation.source
var s = connectors[0];
@@ -199,7 +199,7 @@
- return d.id;
+ return utils.generateS
})
@@ -461,7 +461,7 @@
// At this time, relations may have been redrawn, so here we have to
// retrieve the relation DOM element again.
var relationElement = view.get(
- .one('#' + relation.
+ .one('#' + utils.generateS
@@ -747,7 +747,7 @@
// Remove our pending relation from the DB, error or no.
- vis.select('#' + relation_
+ vis.select('#' + utils.generateS
if (ev.err) {
new models.
Index: lib/views/ stylesheet. less stylesheet. less' stylesheet. less 2013-04-09 14:18:49 +0000 stylesheet. less 2013-04-10 20:37:33 +0000 d-clip: padding-box; yui3-widget- bd {
margin- bottom: 1em;
=== modified file 'lib/views/
--- lib/views/
+++ lib/views/
@@ -872,6 +872,7 @@
backgroun
outline: none;
font-weight: normal;
+ letter-spacing: normal;
.
}
Index: test/test_utils.js utils.js'
=== modified file 'test/test_
--- test/test_utils.js 2013-04-10 09:54:21 +0000
+++ test/test_utils.js 2013-04-10 21:17:18 +0000
@@ -12,6 +12,31 @@
});
});
+ it('can generate a hash', function() { strictEqual( views.utils. generateHash( ''), 0); isNumber( views.utils. generateHash( 'kumquat' )); isNumber( views.utils. generateHash( 'qumquat' )); generateHash( 'kumquat' ), generateHash( 'kumquat' )); generateHash( 'kumquat' ), generateHash( 'qumquat' )); 00000006! @#'; generateSafeDOM Id(relationId) , relation_ 00000006_ __-' + generateHash( relationId) );
+ // We aren't testing the algorithm here, just basic hash
characteristics.
+ // It's a number.
+ assert.
+ assert.
+ assert.
+ // It's stable.
+ assert.strictEqual(
+ views.utils.
+ views.utils.
+ // Different values hash differently.
+ assert.notEqual(
+ views.utils.
+ views.utils.
+ });
+
+ it('can generate safe relation ids', function() {
+ var relationId;
+ relationId = 'foo:Bar relation-
+ assert.strictEqual(
+ views.utils.
+ 'foo_Bar_
+ views.utils.
+ });
+
it('should create a confirmation panel',
function() {
var confirmed = false;