<commit_before>iD.ui.preset = function(context) {
    var event = d3.dispatch('change'),
        state,
        fields,
        preset,
        tags,
        id;

    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = iD.ui.preset[field.type](field, context)
            .on('change', event.change);

        if (field.type === 'address' ||
            field.type === 'wikipedia' ||
            field.type === 'maxspeed') {
            field.input.entity(entity);
        }

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.any(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        if (!fields) {
            var entity = context.entity(id),
                geometry = context.geometry(id);

            fields = [UIField(context.presets().field('name'), entity)];

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fields.push(UIField(field, entity, true));
                }
            });

            context.presets().universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fields.push(UIField(field, entity));
                }
            });
        }

        var shown = fields.filter(function(field) { return field.shown(); }),
            notShown = fields.filter(function(field) { return !field.shown(); });

        var $form = selection.selectAll('.preset-form')
            .data([0]);

        $form.enter().append('div')
            .attr('class', 'preset-form inspector-inner fillL3');

        var $fields = $form.selectAll('.form-field')
            .data(shown, fieldKey);

        // Enter

        var $enter = $fields.enter()
            .insert('div', '.more-buttons')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var $label = $enter.append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        $label.append('button')
            .attr('class', 'modified-icon minor')
            .attr('tabindex', -1)
            .append('div')
            .attr('class', 'icon undo');

        // Update

        $fields.select('.modified-icon')
            .on('click', revert);

        $fields
            .classed('modified', function(field) {
                return field.modified();
            })
            .each(function(field) {
                var reference = iD.ui.TagReference({key: field.key});

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .call(reference.body)
                    .select('.form-label')
                    .call(reference.button);

                field.input.tags(tags);
            });

        $fields.exit()
            .remove();

        var $more = selection.selectAll('.more-buttons')
            .data([0]);

        $more.enter().append('div')
            .attr('class', 'more-buttons inspector-inner');

        var $buttons = $more.selectAll('.preset-add-field')
            .data(notShown, fieldKey);

        $buttons.enter()
            .append('button')
            .attr('class', 'preset-add-field')
            .call(bootstrap.tooltip()
                .placement('top')
                .title(function(d) { return d.label(); }))
            .append('span')
            .attr('class', function(d) { return 'icon ' + d.icon; });

        $buttons.on('click', show);

        $buttons.exit()
            .remove();

        function show(field) {
            field.show = true;
            presets(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            event.change(field.revert());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        preset = _;
        fields = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fields here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        id = _;
        fields = null;
        return presets;
    };

    return d3.rebind(presets, event, 'on');
};
<commit_msg>Ensure preset fields are consistently ordered (#1876)<commit_after>iD.ui.preset = function(context) {
    var event = d3.dispatch('change'),
        state,
        fields,
        preset,
        tags,
        id;

    function UIField(field, entity, show) {
        field = _.clone(field);

        field.input = iD.ui.preset[field.type](field, context)
            .on('change', event.change);

        if (field.type === 'address' ||
            field.type === 'wikipedia' ||
            field.type === 'maxspeed') {
            field.input.entity(entity);
        }

        field.keys = field.keys || [field.key];

        field.show = show;

        field.shown = function() {
            return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
        };

        field.modified = function() {
            var original = context.graph().base().entities[entity.id];
            return _.any(field.keys, function(key) {
                return original ? tags[key] !== original.tags[key] : tags[key];
            });
        };

        field.revert = function() {
            var original = context.graph().base().entities[entity.id],
                t = {};
            field.keys.forEach(function(key) {
                t[key] = original ? original.tags[key] : undefined;
            });
            return t;
        };

        return field;
    }

    function fieldKey(field) {
        return field.id;
    }

    function presets(selection) {
        if (!fields) {
            var entity = context.entity(id),
                geometry = context.geometry(id);

            fields = [UIField(context.presets().field('name'), entity)];

            preset.fields.forEach(function(field) {
                if (field.matchGeometry(geometry)) {
                    fields.push(UIField(field, entity, true));
                }
            });

            context.presets().universal().forEach(function(field) {
                if (preset.fields.indexOf(field) < 0) {
                    fields.push(UIField(field, entity));
                }
            });
        }

        var shown = fields.filter(function(field) { return field.shown(); }),
            notShown = fields.filter(function(field) { return !field.shown(); });

        var $form = selection.selectAll('.preset-form')
            .data([0]);

        $form.enter().append('div')
            .attr('class', 'preset-form inspector-inner fillL3');

        var $fields = $form.selectAll('.form-field')
            .data(shown, fieldKey);

        // Enter

        var $enter = $fields.enter()
            .insert('div', '.more-buttons')
            .attr('class', function(field) {
                return 'form-field form-field-' + field.id;
            });

        var $label = $enter.append('label')
            .attr('class', 'form-label')
            .attr('for', function(field) { return 'preset-input-' + field.id; })
            .text(function(field) { return field.label(); });

        $label.append('button')
            .attr('class', 'modified-icon minor')
            .attr('tabindex', -1)
            .append('div')
            .attr('class', 'icon undo');

        // Update

        $fields.select('.modified-icon')
            .on('click', revert);

        $fields
            .order()
            .classed('modified', function(field) {
                return field.modified();
            })
            .each(function(field) {
                var reference = iD.ui.TagReference({key: field.key});

                if (state === 'hover') {
                    reference.showing(false);
                }

                d3.select(this)
                    .call(field.input)
                    .call(reference.body)
                    .select('.form-label')
                    .call(reference.button);

                field.input.tags(tags);
            });

        $fields.exit()
            .remove();

        var $more = selection.selectAll('.more-buttons')
            .data([0]);

        $more.enter().append('div')
            .attr('class', 'more-buttons inspector-inner');

        var $buttons = $more.selectAll('.preset-add-field')
            .data(notShown, fieldKey);

        $buttons.enter()
            .append('button')
            .attr('class', 'preset-add-field')
            .call(bootstrap.tooltip()
                .placement('top')
                .title(function(d) { return d.label(); }))
            .append('span')
            .attr('class', function(d) { return 'icon ' + d.icon; });

        $buttons.on('click', show);

        $buttons.exit()
            .remove();

        function show(field) {
            field.show = true;
            presets(selection);
            field.input.focus();
        }

        function revert(field) {
            d3.event.stopPropagation();
            d3.event.preventDefault();
            event.change(field.revert());
        }
    }

    presets.preset = function(_) {
        if (!arguments.length) return preset;
        preset = _;
        fields = null;
        return presets;
    };

    presets.state = function(_) {
        if (!arguments.length) return state;
        state = _;
        return presets;
    };

    presets.tags = function(_) {
        if (!arguments.length) return tags;
        tags = _;
        // Don't reset fields here.
        return presets;
    };

    presets.entityID = function(_) {
        if (!arguments.length) return id;
        id = _;
        fields = null;
        return presets;
    };

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

{'fraction_non_alphanumeric': 0.15187146575711336, 'fraction_numerical': 0.002154205188044161, 'mean_word_length': 1.5225266017659045, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '872701', 'n_tokens_mistral': 3150, 'n_tokens_neox': 3002, 'n_words': 557}