Taginfo typeahead on keys as well as values

This commit is contained in:
John Firebaugh
2013-01-01 18:43:22 -08:00
parent 1956c2f55d
commit 3ffa8066c5
6 changed files with 125 additions and 34 deletions

View File

@@ -2,23 +2,29 @@ iD.taginfo = function() {
var taginfo = {},
endpoint = 'http://taginfo.openstreetmap.org/api/2/';
taginfo.values = function(key, callback) {
d3.json(endpoint + 'db/keys/values?' +
iD.util.qsString({
key: key,
taginfo.keys = function(parameters, callback) {
d3.json(endpoint + 'db/keys?' +
iD.util.qsString(_.extend({
rp: 20,
sortname: 'count_all',
sortorder: 'desc',
page: 1
}), callback);
}, parameters)), callback);
};
taginfo.docs = function(keyvalue, callback) {
taginfo.values = function(parameters, callback) {
d3.json(endpoint + 'db/keys/values?' +
iD.util.qsString(_.extend({
rp: 20,
sortname: 'count_all',
sortorder: 'desc',
page: 1
}, parameters)), callback);
};
taginfo.docs = function(parameters, callback) {
d3.json(endpoint + 'wiki/tags?' +
iD.util.qsString({
key: keyvalue.key,
value: keyvalue.value
}), callback);
iD.util.qsString(parameters), callback);
};
taginfo.endpoint = function(_) {

View File

@@ -52,12 +52,26 @@ iD.Inspector = function() {
}
}
function bindTypeahead(d, i) {
var selection = d3.select(this);
selection.call(d3.typeahead()
.data(function(selection, callback) {
taginfo.values(selection.datum().key, function(err, data) {
callback(data.data);
function bindTypeahead() {
var row = d3.select(this),
key = row.selectAll('.key'),
value = row.selectAll('.value');
key.call(d3.typeahead()
.data(function(_, callback) {
taginfo.keys({query: key.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.key};
}));
});
}));
value.call(d3.typeahead()
.data(function(_, callback) {
taginfo.values({key: key.property('value'), query: value.property('value')}, function(err, data) {
callback(data.data.map(function (d) {
return {value: d.value, title: d.description};
}));
});
}));
}
@@ -84,8 +98,9 @@ iD.Inspector = function() {
.property('type', 'text')
.attr('class', 'value')
.property('value', function(d) { return d.value; })
.on('keydown.push-more', pushMore)
.each(bindTypeahead);
.on('keydown.push-more', pushMore);
inputs.each(bindTypeahead);
var removeBtn = row.append('button')
.attr('tabindex', -1)

View File

@@ -1,8 +1,9 @@
d3.typeahead = function() {
var data, hidden;
var data;
var typeahead = function(selection) {
var container;
var container, hidden, idx = 0;
function setup() {
var rect = selection.node().getBoundingClientRect();
container = d3.select(document.body)
@@ -29,40 +30,35 @@ d3.typeahead = function() {
.on('focus.typeahead', setup)
.on('blur.typeahead', hide);
var idx = 0;
function update() {
if (hidden) setup();
if (d3.event.keyCode === 40) idx++;
if (d3.event.keyCode === 38) idx--;
if (d3.event.keyCode === 13) {
selection.property('value', container.select('a.selected').datum().value);
hide();
}
container
.selectAll('a')
.classed('selected', function(d, i) { return i == idx; });
// if (d3.event.keyCode === 13) // return
data(selection, function(data) {
var val = selection.property('value'),
matches = data.filter(function(d) {
return d.value.toLowerCase().indexOf(val) === 0;
}).map(function(d) {
return { value: d.value, description: d.description };
});
container.style('display', function() {
return matches.length ? 'block' : 'none';
return data.length ? 'block' : 'none';
});
var options = container
.selectAll('a')
.data(matches, function(d) { return d.value; });
.data(data, function(d) { return d.value; });
options.enter()
.append('a')
.text(function(d) { return d.value; })
.attr('title', function(d) { return d.description; })
.on('click', function(d) {
selection.property('value', d.value);
});
.attr('title', function(d) { return d.title; })
.on('click', function(d) { selection.property('value', d.value); });
options.exit().remove();
});
}

View File

@@ -131,6 +131,7 @@
<script src="spec/ui/geocoder.js"></script>
<script src="spec/connection.js"></script>
<script src="spec/oauth.js"></script>
<script src="spec/taginfo.js"></script>
<script src="spec/util.js"></script>
<script>

View File

@@ -58,6 +58,7 @@
<script src="spec/ui/inspector.js"></script>
<script src="spec/connection.js"></script>
<script src="spec/oauth.js"></script>
<script src="spec/taginfo.js"></script>
<script src="spec/util.js"></script>
<script>

72
test/spec/taginfo.js Normal file
View File

@@ -0,0 +1,72 @@
describe("iD.taginfo", function() {
var server;
beforeEach(function() {
server = sinon.fakeServer.create();
});
afterEach(function() {
server.restore();
});
function query(url) {
return iD.util.stringQs(url.substring(url.indexOf('?') + 1));
}
describe("#keys", function() {
it("calls the given callback with the results of the keys query", function() {
var taginfo = iD.taginfo(),
callback = sinon.spy();
taginfo.keys({query: "amen"}, callback);
server.respondWith("GET", new RegExp("http://taginfo.openstreetmap.org/api/2/db/keys"),
[200, { "Content-Type": "application/json" },
'{"data":[{"count_all":5190337,"key":"amenity"}]}']);
server.respond();
expect(query(server.requests[0].url)).to.eql(
{query: "amen", page: "1", rp: "20", sortname: "count_all", sortorder: "desc"});
expect(callback).to.have.been.calledWith(null,
{"data":[{"count_all":5190337,"key":"amenity"}]});
});
});
describe("#values", function() {
it("calls the given callback with the results of the values query", function() {
var taginfo = iD.taginfo(),
callback = sinon.spy();
taginfo.values({key: "amenity", query: "par"}, callback);
server.respondWith("GET", new RegExp("http://taginfo.openstreetmap.org/api/2/db/keys/values"),
[200, { "Content-Type": "application/json" },
'{"data":[{"value":"parking","description":"A place for parking cars"}]}']);
server.respond();
expect(query(server.requests[0].url)).to.eql(
{key: "amenity", query: "par", page: "1", rp: "20", sortname: 'count_all', sortorder: 'desc'});
expect(callback).to.have.been.calledWith(null,
{"data":[{"value":"parking","description":"A place for parking cars"}]});
});
});
describe("#docs", function() {
it("calls the given callback with the results of the docs query", function() {
var taginfo = iD.taginfo(),
callback = sinon.spy();
taginfo.docs({key: "amenity", value: "parking"}, callback);
server.respondWith("GET", new RegExp("http://taginfo.openstreetmap.org/api/2/wiki/tags"),
[200, { "Content-Type": "application/json" },
'[{"on_way":false,"lang":"en","on_area":true,"image":"File:Car park2.jpg"}]']);
server.respond();
expect(query(server.requests[0].url)).to.eql(
{key: "amenity", value: "parking"});
expect(callback).to.have.been.calledWith(null,
[{"on_way":false,"lang":"en","on_area":true,"image":"File:Car park2.jpg"}]);
});
});
});