mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-16 13:59:27 +02:00
Switch to comboboxes
This commit is contained in:
+7
-9
@@ -140,21 +140,19 @@
|
||||
<body>
|
||||
<div id='foo'><input /></div>
|
||||
<div id='bar'><input /></div>
|
||||
<div id="iD"></div><script>
|
||||
<input />
|
||||
<div id="iD"><script>
|
||||
var options = d3.range(0, 50).map(function(i) {
|
||||
return {
|
||||
value: i * 10,
|
||||
title: i * 10
|
||||
value: '' + (i * 10),
|
||||
title: '' + (i * 10)
|
||||
};
|
||||
});
|
||||
|
||||
d3.select('#foo').call(d3.combobox()
|
||||
.data(function(selection, cb) {
|
||||
cb(options);
|
||||
}));
|
||||
.data(options));
|
||||
d3.select('#bar').call(d3.combobox()
|
||||
.data(function(selection, cb) {
|
||||
cb(options);
|
||||
}));
|
||||
.data(options));
|
||||
</script></body>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
+22
-24
@@ -563,6 +563,10 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.input-wrap-position {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tag-row input {
|
||||
width: 50%;
|
||||
border-left: 0;
|
||||
@@ -580,18 +584,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
border-left: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.input-wrap::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 9px;
|
||||
top: 14px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
border-top: 5px solid #ccc;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
||||
.tag-row button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
@@ -1435,11 +1427,9 @@ a.success-action {
|
||||
|
||||
.preset-input input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
div.combobox {
|
||||
.combobox {
|
||||
width:155px;
|
||||
z-index: 9999;
|
||||
display: none;
|
||||
@@ -1451,7 +1441,7 @@ div.combobox {
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.combobox a {
|
||||
.combobox a {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
cursor: pointer;
|
||||
@@ -1462,18 +1452,26 @@ div.combobox a {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
div.combobox a:hover,
|
||||
div.combobox a.selected {
|
||||
.combobox a:hover,
|
||||
.combobox a.selected {
|
||||
background: #e1e8ff;
|
||||
color: #154dff;
|
||||
}
|
||||
|
||||
div.combobox a:first-child {
|
||||
.combobox a:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
div.combobox-carat {
|
||||
cursor: pointer;
|
||||
padding:0 5px;
|
||||
vertical-align:middle;
|
||||
.combobox-carat::after {
|
||||
display:block;
|
||||
content: '';
|
||||
cursor:url(../img/cursor-pointer.png) 6 1, auto;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 5px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
border-top: 5px solid #ccc;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<script src='js/lib/ohauth.js'></script>
|
||||
<script src='js/lib/jxon.js'></script>
|
||||
<script src='js/lib/d3.typeahead.js'></script>
|
||||
<script src='js/lib/d3.combobox.js'></script>
|
||||
<script src='js/lib/d3.geo.tile.js'></script>
|
||||
<script src='js/lib/d3.size.js'></script>
|
||||
<script src='js/lib/d3.trigger.js'></script>
|
||||
|
||||
+17
-12
@@ -11,14 +11,14 @@ iD.ui.inspector = function() {
|
||||
var entity = selection.datum();
|
||||
|
||||
var iwrap = selection.append('div')
|
||||
.attr('class','inspector content');
|
||||
.attr('class','inspector content'),
|
||||
head = iwrap.append('div')
|
||||
.attr('class', 'head inspector-inner fillL'),
|
||||
h2 = head.append('h2');
|
||||
|
||||
var head = iwrap.append('div')
|
||||
.attr('class', 'head inspector-inner fillL');
|
||||
|
||||
var h2 = head.append('h2');
|
||||
h2.append('span')
|
||||
.attr('class', 'icon big icon-pre-text big-' + entity.geometry(graph));
|
||||
|
||||
var name = h2.append('input')
|
||||
.attr('placeholder', 'name')
|
||||
.property('value', function() {
|
||||
@@ -150,14 +150,18 @@ iD.ui.inspector = function() {
|
||||
var inputs = row.append('div')
|
||||
.attr('class', 'input-wrap');
|
||||
|
||||
inputs.append('input')
|
||||
inputs.append('span')
|
||||
.attr('class', 'key-wrap')
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('class', 'key')
|
||||
.attr('maxlength', 255)
|
||||
.property('value', function(d) { return d.key; })
|
||||
.on('change', function(d) { d.key = this.value; event.change(); });
|
||||
|
||||
inputs.append('input')
|
||||
inputs.append('span')
|
||||
.attr('class', 'input-wrap-position')
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('class', 'value')
|
||||
.attr('maxlength', 255)
|
||||
@@ -253,7 +257,7 @@ iD.ui.inspector = function() {
|
||||
geometry = entity.geometry(graph),
|
||||
row = d3.select(this),
|
||||
key = row.selectAll('.key'),
|
||||
value = row.selectAll('.value');
|
||||
value = row.selectAll('.input-wrap-position');
|
||||
|
||||
function sort(value, data) {
|
||||
var sameletter = [],
|
||||
@@ -278,14 +282,15 @@ iD.ui.inspector = function() {
|
||||
});
|
||||
}, 500)));
|
||||
|
||||
value.call(d3.typeahead()
|
||||
.data(_.debounce(function(_, callback) {
|
||||
var valueinput = value.select('input');
|
||||
value.call(d3.combobox()
|
||||
.fetcher(_.debounce(function(_, __, callback) {
|
||||
taginfo.values({
|
||||
key: key.property('value'),
|
||||
geometry: geometry,
|
||||
query: value.property('value')
|
||||
query: valueinput.property('value')
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(value.property('value'), data));
|
||||
if (!err) callback(sort(valueinput.property('value'), data));
|
||||
});
|
||||
}, 500)));
|
||||
}
|
||||
|
||||
+6
-8
@@ -76,14 +76,12 @@ iD.ui.preset = function() {
|
||||
});
|
||||
break;
|
||||
case 'select':
|
||||
i = this.append('select');
|
||||
var options = d.values.slice();
|
||||
options.unshift('');
|
||||
i.selectAll('option')
|
||||
.data(options)
|
||||
.enter()
|
||||
.append('option')
|
||||
.text(String);
|
||||
var w = this.append('span').attr('class', 'input-wrap-position');
|
||||
i = w.append('input');
|
||||
w.call(d3.combobox()
|
||||
.data([''].concat(d.values.slice()).map(function(o) {
|
||||
return { value: o, title: o };
|
||||
})));
|
||||
break;
|
||||
}
|
||||
if (i) {
|
||||
|
||||
+131
-68
@@ -1,16 +1,21 @@
|
||||
d3.combobox = function() {
|
||||
var event = d3.dispatch('accept'),
|
||||
autohighlight = false,
|
||||
autofilter = false,
|
||||
input,
|
||||
container,
|
||||
data;
|
||||
container, input, shown = false, data = [];
|
||||
|
||||
var fetcher = function(val, data, cb) {
|
||||
cb(data.filter(function(d) {
|
||||
return d.title
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.indexOf(val.toLowerCase()) !== -1;
|
||||
}));
|
||||
};
|
||||
|
||||
var typeahead = function(selection) {
|
||||
var hidden, idx = autohighlight ? 0 : -1;
|
||||
|
||||
var rect = selection.select('input').node().getBoundingClientRect();
|
||||
|
||||
var idx = -1,
|
||||
rect = selection.select('input')
|
||||
.node()
|
||||
.getBoundingClientRect();
|
||||
input = selection.select('input');
|
||||
|
||||
container = selection
|
||||
@@ -25,104 +30,174 @@ d3.combobox = function() {
|
||||
});
|
||||
|
||||
carat = selection
|
||||
.insert('div', ':first-child')
|
||||
.insert('a', ':first-child')
|
||||
.attr('class', 'combobox-carat')
|
||||
.text('+')
|
||||
.style({
|
||||
position: 'absolute',
|
||||
left: (rect.width - 20) + 'px',
|
||||
left: rect.width + 'px',
|
||||
top: '0px'
|
||||
})
|
||||
.on('click', function() {
|
||||
update();
|
||||
show();
|
||||
});
|
||||
.on('mousedown', stop)
|
||||
.on('click', click);
|
||||
|
||||
selection
|
||||
.on('keyup.typeahead', key);
|
||||
function stop() {
|
||||
// prevent the form element from blurring. it blurs
|
||||
// on mousedown
|
||||
d3.event.stopPropagation();
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
|
||||
hidden = false;
|
||||
function click() {
|
||||
d3.event.preventDefault();
|
||||
d3.event.stopPropagation();
|
||||
update();
|
||||
show();
|
||||
// focus the node so that a click outside of the
|
||||
// combo box will hide it
|
||||
input.node().focus();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
idx = autohighlight ? 0 : -1;
|
||||
hidden = true;
|
||||
function blur() {
|
||||
// hide the combobox whenever the input element
|
||||
// loses focus
|
||||
slowHide();
|
||||
}
|
||||
|
||||
function show() {
|
||||
container.style('display', 'block');
|
||||
shown = true;
|
||||
}
|
||||
|
||||
function hide() {
|
||||
idx = -1;
|
||||
container.style('display', 'none');
|
||||
shown = false;
|
||||
}
|
||||
|
||||
function slowHide() {
|
||||
if (autohighlight && container.select('a.selected').node()) {
|
||||
select(container.select('a.selected').datum());
|
||||
event.accept();
|
||||
}
|
||||
window.setTimeout(hide, 150);
|
||||
}
|
||||
|
||||
selection
|
||||
.on('focus.typeahead', show)
|
||||
.on('blur.typeahead', slowHide);
|
||||
|
||||
function key() {
|
||||
var len = container.selectAll('a').data().length;
|
||||
if (d3.event.keyCode === 40) {
|
||||
idx = Math.min(idx + 1, len - 1);
|
||||
return highlight();
|
||||
} else if (d3.event.keyCode === 38) {
|
||||
idx = Math.max(idx - 1, 0);
|
||||
return highlight();
|
||||
} else if (d3.event.keyCode === 13) {
|
||||
if (container.select('a.selected').node()) {
|
||||
select(container.select('a.selected').datum());
|
||||
}
|
||||
event.accept();
|
||||
hide();
|
||||
} else {
|
||||
update();
|
||||
function keydown() {
|
||||
if (!shown) return;
|
||||
switch (d3.event.keyCode) {
|
||||
// down arrow
|
||||
case 40:
|
||||
next();
|
||||
d3.event.preventDefault();
|
||||
break;
|
||||
// up arrow
|
||||
case 38:
|
||||
prev();
|
||||
d3.event.preventDefault();
|
||||
break;
|
||||
// escape, tab
|
||||
case 9:
|
||||
case 13:
|
||||
d3.event.preventDefault();
|
||||
break;
|
||||
}
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
|
||||
function keyup() {
|
||||
switch (d3.event.keyCode) {
|
||||
// escape
|
||||
case 27:
|
||||
hide();
|
||||
break;
|
||||
// escape, tab
|
||||
case 9:
|
||||
case 13:
|
||||
if (!shown) return;
|
||||
accept();
|
||||
break;
|
||||
default:
|
||||
update();
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
d3.event.stopPropagation();
|
||||
}
|
||||
|
||||
function accept() {
|
||||
if (container.select('a.selected').node()) {
|
||||
select(container.select('a.selected').datum());
|
||||
}
|
||||
hide();
|
||||
}
|
||||
|
||||
function next() {
|
||||
var len = container.selectAll('a').data().length;
|
||||
idx = Math.min(idx + 1, len - 1);
|
||||
highlight();
|
||||
}
|
||||
|
||||
function prev() {
|
||||
idx = Math.max(idx - 1, 0);
|
||||
highlight();
|
||||
}
|
||||
|
||||
function highlight() {
|
||||
container
|
||||
.selectAll('a')
|
||||
.classed('selected', function(d, i) { return i == idx; });
|
||||
var height = container.node().offsetHeight,
|
||||
top = container.select('a.selected').node().offsetTop,
|
||||
selectedHeight = container.select('a.selected').node().offsetHeight;
|
||||
if ((top + selectedHeight) < height) {
|
||||
container.node().scrollTop = 0;
|
||||
} else {
|
||||
container.node().scrollTop = top;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
function run(data) {
|
||||
container.style('display', function() {
|
||||
return data.length ? 'block' : 'none';
|
||||
});
|
||||
function render(data) {
|
||||
if (data.length) show();
|
||||
else hide();
|
||||
|
||||
var options = container
|
||||
.selectAll('a')
|
||||
.selectAll('a.combobox-option')
|
||||
.data(data, function(d) { return d.value; });
|
||||
|
||||
options.enter()
|
||||
.append('a')
|
||||
.text(function(d) { return d.value; })
|
||||
.attr('class', 'combobox-option')
|
||||
.attr('title', function(d) { return d.title; })
|
||||
.on('click', select);
|
||||
|
||||
options.exit().remove();
|
||||
|
||||
options
|
||||
.classed('selected', function(d, i) { return i == idx; });
|
||||
.classed('selected', function(d, i) { return i == idx; })
|
||||
.order();
|
||||
}
|
||||
|
||||
if (typeof data === 'function') data(selection, run);
|
||||
else run(data);
|
||||
fetcher.apply(selection, [
|
||||
selection.select('input').property('value'),
|
||||
data, render]);
|
||||
}
|
||||
|
||||
// select the choice given as d
|
||||
function select(d) {
|
||||
input
|
||||
.property('value', d.value)
|
||||
.trigger('change');
|
||||
container.style('display', 'none');
|
||||
event.accept(d);
|
||||
hide();
|
||||
}
|
||||
|
||||
input
|
||||
.on('blur.typeahead', blur)
|
||||
.on('keydown.typeahead', keydown)
|
||||
.on('keyup.typeahead', keyup);
|
||||
};
|
||||
|
||||
typeahead.fetcher = function(_) {
|
||||
if (!arguments.length) return fetcher;
|
||||
fetcher = _;
|
||||
return typeahead;
|
||||
};
|
||||
|
||||
typeahead.data = function(_) {
|
||||
@@ -131,17 +206,5 @@ d3.combobox = function() {
|
||||
return typeahead;
|
||||
};
|
||||
|
||||
typeahead.autofilter = function(_) {
|
||||
if (!arguments.length) return autofilter;
|
||||
autofilter = _;
|
||||
return typeahead;
|
||||
};
|
||||
|
||||
typeahead.autohighlight = function(_) {
|
||||
if (!arguments.length) return autohighlight;
|
||||
autohighlight = _;
|
||||
return typeahead;
|
||||
};
|
||||
|
||||
return d3.rebind(typeahead, event, 'on');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user