iD.ui.preset.combo =
iD.ui.preset.typeCombo = function(field) {
    var event = d3.dispatch('change'),
        input;

    function combo(selection) {
        var combobox = d3.combobox();

        input = selection.selectAll('input')
            .data([0]);

        input.enter().append('input')
            .attr('type', 'text')
            .attr('id', 'preset-input-' + field.id);

        input
            .call(combobox)
            .on('change', change)
            .on('blur', change)
            .each(function() {
                if (field.options) {
                    options(field.options);
                } else {
                    iD.taginfo().values({
                        key: field.key
                    }, function(err, data) {
                        if (!err) options(_.pluck(data, 'value'));
                    });
                }
            });

        function options(opts) {
            combobox.data(opts.map(function(d) {
                var o = {};
                o.title = o.value = d.replace(/_+/g, ' ');
                return o;
            }));

            input.attr('placeholder', field.placeholder() ||
                (opts.length < 3 ? '' : opts.slice(0, 3).join(', ') + '...'));
        }
    }

    function change() {
        var value = input.value()
            .split(';')
            .map(function(s) { return s.trim(); })
            .join(';')
            .replace(/\s+/g, '_');

        if (field.type === 'typeCombo' && !value) value = 'yes';

        var t = {};
        t[field.key] = value || undefined;
        event.change(t);
    }

    combo.tags = function(tags) {
        var value = tags[field.key] || '';
        if (field.type === 'typeCombo' && value === 'yes') value = '';
        input.value(value);
    };

    combo.focus = function() {
        input.node().focus();
    };

    return d3.rebind(combo, event, 'on');
};

@@ -108,14 +108,518 @@
     
-input;
+optstrings = field.strings && field.strings.options,%0A        strings = %7B%7D,%0A        input;%0A%0A    if (optstrings) %7B%0A        _.each(optstrings, function(v, k) %7B%0A            strings%5Bk%5D = field.t('options.' + k, %7B 'default': v %7D);%0A        %7D);%0A    %7D else %7B%0A        iD.taginfo().values(%7Bkey: field.key%7D, function(err, data) %7B%0A            if (!err) %7B%0A                _.each(_.pluck(data, 'value'), function(k) %7B%0A                    strings%5Bk%5D = k.replace(/_+/g, ' ');%0A                %7D);%0A            %7D%0A        %7D);%0A    %7D
 %0A%0A  
@@ -760,24 +760,36 @@
 %5D);%0A%0A       
+ var enter =
  input.enter
@@ -790,16 +790,29 @@
 .enter()
+%0A            
 .append(
@@ -904,24 +904,89 @@
 field.id);%0A%0A
+        if (optstrings) %7B enter.attr('readonly', 'readonly'); %7D%0A%0A
         inpu
@@ -1132,383 +1132,40 @@
     
-if (field.options) %7B%0A                    options(field.options);%0A                %7D else %7B%0A                    iD.taginfo().values(%7B%0A                        key: field.key%0A                    %7D, function(err, data) %7B%0A                        if (!err) options(_.pluck(data, 'value'));%0A                    %7D);%0A                %7D%0A            %7D);%0A%0A        function options(opts) %7B%0A
+var keys = _.keys(strings);%0A    
     
@@ -1186,19 +1186,19 @@
 ox.data(
-opt
+key
 s.map(fu
@@ -1204,21 +1204,25 @@
 unction(
-d
+k
 ) %7B%0A
+    
         
@@ -1237,24 +1237,28 @@
 var o = %7B%7D;%0A
+    
             
@@ -1285,31 +1285,24 @@
 e = 
-d.replace(/_+/g, ' ');%0A
+strings%5Bk%5D;%0A    
     
@@ -1335,16 +1335,20 @@
         
+    
 %7D));%0A%0A  
@@ -1353,24 +1353,28 @@
             
+ 
+   
 input.attr('
@@ -1426,20 +1426,24 @@
         
-(opt
+    (key
 s.length
@@ -1454,19 +1454,19 @@
  ? '' : 
-opt
+key
 s.slice(
@@ -1497,25 +1497,31 @@
 ));%0A        
+   
-%7D
+ %7D);
 %0A    %7D%0A%0A    
@@ -1552,24 +1552,141 @@
     var 
-value = 
+optstring = _.find(_.keys(strings), function(k) %7B return strings%5Bk%5D === input.value(); %7D),%0A            value = optstring %7C%7C (
 input.va
@@ -1703,16 +1703,20 @@
         
+    
 .split('
@@ -1715,24 +1715,28 @@
 .split(';')%0A
+    
             
@@ -1786,16 +1786,20 @@
         
+ 
+   
 .join(';
@@ -1797,24 +1797,28 @@
  .join(';')%0A
+    
             
@@ -1838,16 +1838,17 @@
 /g, '_')
+)
 ;%0A%0A     
@@ -2049,21 +2049,19 @@
     var 
-value
+key
  = tags%5B
@@ -2070,16 +2070,57 @@
 eld.key%5D
+,%0A            value = strings%5Bkey%5D %7C%7C key
  %7C%7C '';%0A
@@ -2166,16 +2166,30 @@
 && value
+.toLowerCase()
  === 'ye

Support option strings for combo fields (#1259, #1709)