Merge branch 'save-browse'

This commit is contained in:
John Firebaugh
2013-10-23 13:37:57 -07:00
10 changed files with 354 additions and 92 deletions

View File

@@ -261,7 +261,7 @@ ul li { list-style: none;}
border-radius: 0 0 3px 3px;
}
.toggle-list label > span {
.toggle-list label > span {
display: block;
overflow: hidden;
white-space: nowrap;
@@ -569,6 +569,18 @@ button[disabled] .icon.layers { background-position: -300px -40px;}
button[disabled] .icon.avatar { background-position: -320px -40px;}
button[disabled] .icon.nearby { background-position: -340px -40px;}
.icon.point.deleted { background-position: -302px -80px;}
.icon.line.deleted { background-position: -320px -80px;}
.icon.area.deleted { background-position: -340px -80px;}
.icon.point.created { background-position: -302px -100px;}
.icon.line.created { background-position: -320px -100px;}
.icon.area.created { background-position: -340px -100px;}
.icon.point.modified { background-position: -24px 0; }
.icon.modified { opacity: .5; }
/* Out link is special */
.icon.out-link { height: 14px; width: 14px; background-position: -500px 0;}
@@ -2418,6 +2430,8 @@ img.wiki-image {
float: none;
margin: auto;
display: block;
color: white;
font-size: 14px;
}
.mode-save .user-info img {
@@ -2438,12 +2452,15 @@ img.wiki-image {
color:#fff;
}
.mode-save .commit-info {
margin-bottom: 10px;
}
.mode-save .changeset-list {
overflow: auto;
border:1px solid #ccc;
border-radius: 4px;
background:#fff;
max-height: 160px;
}
.mode-save .warning-section .changeset-list button {
@@ -2454,6 +2471,15 @@ img.wiki-image {
position: relative;
border-top:1px solid #ccc;
padding:5px 10px;
cursor: pointer;
}
.mode-save .changeset-list li:hover {
background-color: #ececec;
}
.mode-save .changeset-list .alert {
opacity: 0.5;
}
.changeset-list li span.count {
@@ -2461,6 +2487,10 @@ img.wiki-image {
color:#555;
}
.mode-save .commit-section .changeset-list button {
border-left: 1px solid #CCC;
}
.changeset-list li span.count:before { content: '('; }
.changeset-list li span.count:after { content: ')'; }
@@ -2698,7 +2728,7 @@ img.wiki-image {
}
/* Move over tooltips that are near the edge of screen */
.add-point .tooltip {
left: 33.3333% !important;
left: 33.3333% !important;
}
.curtain-tooltip.intro-points-add .tooltip-arrow,

22
dist/img/sprite.svg vendored
View File

@@ -13,7 +13,7 @@
width="800"
height="560"
id="svg12393"
inkscape:version="0.48.4 r9939"
inkscape:version="0.48.2 r9819"
sodipodi:docname="sprite.svg">
<sodipodi:namedview
pagecolor="#ffffff"
@@ -27,10 +27,10 @@
inkscape:window-width="1920"
inkscape:window-height="1032"
id="namedview392"
showgrid="true"
inkscape:zoom="6.0142857"
inkscape:cx="517.7483"
inkscape:cy="535.87471"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="254.41613"
inkscape:cy="397.9087"
inkscape:window-x="2"
inkscape:window-y="0"
inkscape:window-maximized="0"
@@ -2162,5 +2162,17 @@
style="opacity:0.5;color:#000000;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path17944-2"
d="m 614,47.999997 -1,1 0,2 1,1 2,0 1,-1 0,-2 -1,-1 -2,0 z m 1,1 c 0.5523,0 1,0.4477 1,1 0,0.5523 -0.4477,1 -1,1 -0.5523,0 -1,-0.4477 -1,-1 0,-0.5523 0.4477,-1 1,-1 z" />
<path
d="m 357,83.999997 -1,1 0,1.59375 -6.40625,6.40625 -1.59375,0 -1,1 0,2 1,1 2,0 1,-1 0,-1.59375 6.40625,-6.40625 1.59375,0 1,-1 0,-2 -1,-1 z m -22,1 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 23,0 c 0.55228,0 1,0.44772 1,1 0,0.55229 -0.44772,1 -1,1 -0.25152,0 -0.48052,-0.0967 -0.65625,-0.25 -0.0344,-0.03002 -0.0638,-0.05934 -0.0937,-0.09375 -0.15335,-0.175731 -0.25,-0.404729 -0.25,-0.65625 0,-0.55228 0.44772,-1 1,-1 z m 10,0 -1,1 0,2 1,1 0,4 -1,1 0,2 1,1 2,0 1,-1 4,0 1,1 2,0 1,-1 0,-2 -1,-1 0,-4 1,-1 0,-2 -1,-1 -2,0 -1,1 -4,0 -1,-1 z m 1,1 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m -41.84375,2 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.10457,0 -2,-0.89543 -2,-2 0,-1.10457 0.89543,-2 2,-2 z m 35.84375,0 4,0 1,1 0,4 -1,1 -4,0 -1,-1 0,-4 z m -22,6 c 0.25152,0 0.48052,0.0967 0.65625,0.25 l 0.0937,0.09375 c 0.15335,0.175731 0.25,0.404734 0.25,0.65625 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 z m 20,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z"
id="path2997-7"
style="color:#000000;fill:#e06d5f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccsscsscssccscccccccccccccccccccccccccccssssssssssssssscccccccccsccsssssssssssssss" />
<path
sodipodi:nodetypes="cccccccccccccccccsscsscssccscccccccccccccccccccccccccccssssssssssssssscccccccccsccsssssssssssssss"
inkscape:connector-curvature="0"
style="color:#000000;fill:#8cd05f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path3444"
d="m 357,104 -1,1 0,1.59375 L 349.59375,113 348,113 l -1,1 0,2 1,1 2,0 1,-1 0,-1.59375 L 357.40625,108 359,108 l 1,-1 0,-2 -1,-1 z m -22,1 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 23,0 c 0.55228,0 1,0.44772 1,1 0,0.55229 -0.44772,1 -1,1 -0.25152,0 -0.48052,-0.0967 -0.65625,-0.25 -0.0344,-0.03 -0.0638,-0.0593 -0.0937,-0.0937 -0.15335,-0.17573 -0.25,-0.40473 -0.25,-0.65625 0,-0.55228 0.44772,-1 1,-1 z m 10,0 -1,1 0,2 1,1 0,4 -1,1 0,2 1,1 2,0 1,-1 4,0 1,1 2,0 1,-1 0,-2 -1,-1 0,-4 1,-1 0,-2 -1,-1 -2,0 -1,1 -4,0 -1,-1 z m 1,1 c 0.55228,0 1,0.44771 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55229 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.44771 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55229 0.44772,-1 1,-1 z m -41.84375,2 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.10457,0 -2,-0.89543 -2,-2 0,-1.10457 0.89543,-2 2,-2 z M 371,108 l 4,0 1,1 0,4 -1,1 -4,0 -1,-1 0,-4 z m -22,6 c 0.25152,0 0.48052,0.0967 0.65625,0.25 l 0.0937,0.0937 c 0.15335,0.17573 0.25,0.40473 0.25,0.65625 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 z m 20,0 c 0.55228,0 1,0.44771 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55229 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.44771 1,1 0,0.55228 -0.44772,1 -1,1 -0.55228,0 -1,-0.44772 -1,-1 0,-0.55229 0.44772,-1 1,-1 z" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -84,7 +84,6 @@ iD.Difference = function(base, head) {
};
difference.addParents = function(entities) {
for (var i in entities) {
addParents(head.parentWays(entities[i]), entities);
addParents(head.parentRelations(entities[i]), entities);
@@ -92,6 +91,55 @@ iD.Difference = function(base, head) {
return entities;
};
difference.summary = function() {
var relevant = {};
function addEntity(entity, graph, changeType) {
relevant[entity.id] = {
entity: entity,
graph: graph,
changeType: changeType
};
}
function addParents(entity) {
var parents = head.parentWays(entity);
for (var j = parents.length - 1; j >= 0; j--) {
var parent = parents[j];
if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
}
}
_.each(changes, function(change) {
if (change.head && change.head.geometry(head) !== 'vertex') {
addEntity(change.head, head, change.base ? 'modified' : 'created');
} else if (change.base && change.base.geometry(base) !== 'vertex') {
addEntity(change.base, base, 'deleted');
} else if (change.base && change.head) { // modified vertex
var moved = change.base.loc !== change.head.loc,
retagged = change.base.tags !== change.head.tags;
if (moved) {
addParents(change.head);
}
if (retagged || (moved && change.head.hasInterestingTags())) {
addEntity(change.head, head, 'modified');
}
} else if (change.head && change.head.hasInterestingTags()) { // created vertex
addEntity(change.head, head, 'created');
} else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
addEntity(change.base, base, 'deleted');
}
});
return d3.values(relevant);
};
difference.complete = function(extent) {
var result = {}, id, change;

View File

@@ -158,10 +158,6 @@ iD.History = function(context) {
return this.difference().length() > 0;
},
numChanges: function() {
return this.difference().length();
},
imageryUsed: function(sources) {
if (sources) {
imageryUsed = sources;

View File

@@ -1,18 +1,12 @@
iD.modes.Save = function(context) {
var ui = iD.ui.Commit(context)
.on('cancel', cancel)
.on('fix', fix)
.on('save', save);
function cancel() {
context.enter(iD.modes.Browse(context));
}
function fix(d) {
context.map().zoomTo(d.entity);
context.enter(iD.modes.Select(context, [d.entity.id]));
}
function save(e) {
var loading = iD.ui.Loading(context)
.message(t('save.uploading'))

View File

@@ -1,31 +1,20 @@
iD.ui.Commit = function(context) {
var event = d3.dispatch('cancel', 'save', 'fix'),
presets = context.presets();
function zipSame(d) {
var c = {}, n = -1;
for (var i = 0; i < d.length; i++) {
var desc = {
name: d[i].tags.name || presets.match(d[i], context.graph()).name(),
geometry: d[i].geometry(context.graph()),
count: 1,
tagText: iD.util.tagText(d[i])
};
var fingerprint = desc.name + desc.tagText;
if (c[fingerprint]) {
c[fingerprint].count++;
} else {
c[fingerprint] = desc;
}
}
return _.values(c);
}
var event = d3.dispatch('cancel', 'save');
function commit(selection) {
var changes = context.history().changes();
var changes = context.history().changes(),
summary = context.history().difference().summary();
function changesLength(d) { return changes[d].length; }
function zoomToEntity(change) {
var entity = change.entity;
if (change.changeType !== 'deleted' &&
context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
context.map().zoomTo(entity);
context.surface().selectAll(
iD.util.entityOrMemberSelector([entity.id], context.graph()))
.classed('hover', true);
}
}
var header = selection.append('div')
.attr('class', 'header fillL');
@@ -90,7 +79,7 @@ iD.ui.Commit = function(context) {
// Confirm Button
var saveButton = saveSection.append('button')
.attr('class', 'action col3 button')
.attr('class', 'action col4 button')
.on('click.save', function() {
event.save({
comment: commentField.node().value
@@ -101,11 +90,13 @@ iD.ui.Commit = function(context) {
.attr('class', 'label')
.text(t('commit.save'));
// Warnings
var warnings = body.selectAll('div.warning-section')
.data(iD.validate(changes, context.graph()))
.data([iD.validate(changes, context.graph())])
.enter()
.append('div')
.attr('class', 'modal-section warning-section fillL2');
.attr('class', 'modal-section warning-section fillL2')
.style('display', function(d) { return _.isEmpty(d) ? 'none' : null; });
warnings.append('h3')
.text(t('commit.warnings'));
@@ -115,52 +106,90 @@ iD.ui.Commit = function(context) {
.selectAll('li')
.data(function(d) { return d; })
.enter()
.append('li');
.append('li')
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', warningClick);
// only show the fix icon when an entity is given
warningLi.filter(function(d) { return d.entity; })
.append('button')
.attr('class', 'minor')
.on('click', event.fix)
.append('span')
.attr('class', 'icon warning');
warningLi.append('span')
.attr('class', 'alert icon icon-pre-text');
warningLi.append('strong').text(function(d) {
return d.message;
});
var section = body.selectAll('div.commit-section')
.data(['modified', 'deleted', 'created'].filter(changesLength))
var changeSection = body.selectAll('div.commit-section')
.data([0])
.enter()
.append('div')
.attr('class', 'commit-section modal-section fillL2');
section.append('h3')
.text(function(d) { return t('commit.' + d); })
.append('small')
.attr('class', 'count')
.text(changesLength);
changeSection.append('h3')
.text(summary.length + ' Changes');
var li = section.append('ul')
var li = changeSection.append('ul')
.attr('class', 'changeset-list')
.selectAll('li')
.data(function(d) { return zipSame(changes[d]); })
.data(summary)
.enter()
.append('li');
.append('li')
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', zoomToEntity);
li.append('strong')
.text(function(d) {
return d.geometry + ' ';
li.append('span')
.attr('class', function(d) {
return d.entity.geometry(d.graph) + ' ' + d.changeType + ' icon icon-pre-text';
});
li.append('span')
.text(function(d) { return d.name; })
.attr('title', function(d) { return d.tagText; });
.attr('class', 'change-type')
.text(function(d) {
return d.changeType + ' ';
});
li.filter(function(d) { return d.count > 1; })
.append('span')
.attr('class', 'count')
.text(function(d) { return d.count; });
li.append('strong')
.attr('class', 'entity-type')
.text(function(d) {
return context.presets().match(d.entity, d.graph).name();
});
li.append('span')
.attr('class', 'entity-name')
.text(function(d) {
var name = iD.util.displayName(d.entity) || '',
string = '';
if (name !== '') string += ':';
return string += ' ' + name;
});
li.style('opacity', 0)
.transition()
.style('opacity', 1);
li.style('opacity', 0)
.transition()
.style('opacity', 1);
function mouseover(d) {
if (d.entity) {
context.surface().selectAll(
iD.util.entityOrMemberSelector([d.entity.id], context.graph())
).classed('hover', true);
}
}
function mouseout() {
context.surface().selectAll('.hover')
.classed('hover', false);
}
function warningClick(d) {
if (d.entity) {
context.map().zoomTo(d.entity);
context.enter(iD.modes.Select(context, [d.entity.id]));
}
}
}
return d3.rebind(commit, event, 'on');

View File

@@ -42,13 +42,13 @@ iD.ui.Save = function(context) {
var numChanges = 0;
context.history().on('change.save', function() {
var _ = history.numChanges();
var _ = history.difference().summary().length;
if (_ === numChanges)
return;
numChanges = _;
tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
'save.help' : 'save.no_changes'), key))
'save.help' : 'save.no_changes'), key));
button
.classed('disabled', numChanges === 0)

View File

@@ -48,5 +48,5 @@ iD.validate = function(changes, graph) {
}
}
return warnings.length ? [warnings] : [];
return warnings;
};

View File

@@ -126,6 +126,175 @@ describe("iD.Difference", function () {
});
});
describe("#summary", function () {
var base = iD.Graph({
'a': iD.Node({id: 'a', tags: {crossing: 'zebra'}}),
'b': iD.Node({id: 'b'}),
'v': iD.Node({id: 'v'}),
'-': iD.Way({id: '-', nodes: ['a', 'b']})
});
it("reports a created way as created", function() {
var way = iD.Way({id: '+'}),
head = base.replace(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'created',
entity: way,
graph: head
}]);
});
it("reports a deleted way as deleted", function() {
var way = base.entity('-'),
head = base.remove(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'deleted',
entity: way,
graph: base
}]);
});
it("reports a modified way as modified", function() {
var way = base.entity('-').mergeTags({highway: 'primary'}),
head = base.replace(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: way,
graph: head
}]);
});
it("reports a way as modified when a member vertex is moved", function() {
var vertex = base.entity('b').move([0,3]),
head = base.replace(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: head.entity('-'),
graph: head
}]);
});
it("reports a way as modified when a member vertex is added", function() {
var vertex = iD.Node({id: 'c'}),
way = base.entity('-').addNode('c'),
head = base.replace(vertex).replace(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: way,
graph: head
}]);
});
it("reports a way as modified when a member vertex is removed", function() {
var way = base.entity('-').removeNode('b'),
head = base.replace(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: way,
graph: head
}]);
});
it("reports a created way containing a moved vertex as being created", function() {
var vertex = base.entity('b').move([0,3]),
way = iD.Way({id: '+', nodes: ['b']}),
head = base.replace(way).replace(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'created',
entity: way,
graph: head
}, {
changeType: 'modified',
entity: head.entity('-'),
graph: head
}]);
});
it("reports a created way with a created vertex as being created", function() {
var vertex = iD.Node({id: 'c'}),
way = iD.Way({id: '+', nodes: ['c']}),
head = base.replace(vertex).replace(way),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'created',
entity: way,
graph: head
}]);
});
it("reports a vertex as modified when it has tags and they are changed", function() {
var vertex = base.entity('a').mergeTags({highway: 'traffic_signals'}),
head = base.replace(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: vertex,
graph: head
}]);
});
it("reports a vertex as modified when it has tags and is moved", function() {
var vertex = base.entity('a').move([1, 2]),
head = base.replace(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: head.entity('-'),
graph: head
}, {
changeType: 'modified',
entity: vertex,
graph: head
}]);
});
it("reports a vertex as deleted when it had tags", function() {
var vertex = base.entity('v'),
head = base.remove(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'deleted',
entity: vertex,
graph: base
}]);
});
it("reports a vertex as created when it has tags", function() {
var vertex = iD.Node({id: 'c', tags: {crossing: 'zebra'}}),
way = base.entity('-').addNode('c'),
head = base.replace(way).replace(vertex),
diff = iD.Difference(base, head);
expect(diff.summary()).to.eql([{
changeType: 'modified',
entity: way,
graph: head
}, {
changeType: 'created',
entity: vertex,
graph: head
}]);
});
});
describe("#complete", function () {
it("includes created entities", function () {
var node = iD.Node({id: 'n'}),

View File

@@ -211,22 +211,6 @@ describe("iD.History", function () {
});
});
describe("#numChanges", function() {
it("is 0 when there are no changes", function() {
expect(history.numChanges()).to.eql(0);
});
it("is the sum of all types of changes", function() {
var node1 = iD.Node({id: "n1"}),
node2 = iD.Node();
history.merge({ n1: node1 });
history.perform(function (graph) { return graph.remove(node1); });
expect(history.numChanges()).to.eql(1);
history.perform(function (graph) { return graph.replace(node2); });
expect(history.numChanges()).to.eql(2);
});
});
describe("#reset", function () {
it("clears the version stack", function () {
history.perform(action, "annotation");