From 9e4e79430011472126cb873c0189224d19c1f325 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 21 May 2013 16:39:30 -0700 Subject: [PATCH] Rewrite PresetGrid --- js/id/presets/preset.js | 10 ++ js/id/ui/inspector.js | 7 +- js/id/ui/preset_grid.js | 275 ++++++++++++++++++++-------------------- 3 files changed, 149 insertions(+), 143 deletions(-) diff --git a/js/id/presets/preset.js b/js/id/presets/preset.js index ce825600b..9b0ec527b 100644 --- a/js/id/presets/preset.js +++ b/js/id/presets/preset.js @@ -45,6 +45,16 @@ iD.presets.Preset = function(id, preset, fields) { return preset.t('terms', {'default': ''}).split(','); }; + preset.reference = function() { + var reference = {key: Object.keys(preset.tags)[0]}; + + if (preset.tags[reference.key] !== '*') { + reference.value = preset.tags[reference.key]; + } + + return reference; + }; + preset.removeTags = function(tags, geometry) { tags = _.omit(tags, _.keys(preset.tags)); diff --git a/js/id/ui/inspector.js b/js/id/ui/inspector.js index cffcb5877..4224ace63 100644 --- a/js/id/ui/inspector.js +++ b/js/id/ui/inspector.js @@ -64,8 +64,11 @@ iD.ui.Inspector = function(context, entity) { .transition() .style('right', right); - presetGrid.autofocus(true); - presetLayer.call(presetGrid, preset); + presetGrid + .current(preset) + .autofocus(true); + + presetLayer.call(presetGrid); }); var tagless = _.without(Object.keys(entity.tags), 'area').length === 0; diff --git a/js/id/ui/preset_grid.js b/js/id/ui/preset_grid.js index a16698c46..f28ced38f 100644 --- a/js/id/ui/preset_grid.js +++ b/js/id/ui/preset_grid.js @@ -1,14 +1,14 @@ iD.ui.PresetGrid = function(context, entity) { var event = d3.dispatch('choose', 'close'), - presets, + presets, current, autofocus = false; - function presetgrid(selection, preset) { + function presetGrid(selection) { + var geometry = entity.geometry(context.graph()); + presets = context.presets().matchGeometry(geometry); selection.html(''); - presets = context.presets().matchGeometry(entity.geometry(context.graph())); - var messagewrap = selection.append('div') .attr('class', 'header fillL cf'); @@ -16,7 +16,7 @@ iD.ui.PresetGrid = function(context, entity) { .attr('class', 'inspector-inner') .text(t('inspector.choose')); - if (preset) { + if (current) { messagewrap.append('button') .attr('class', 'preset-choose') .on('click', event.choose) @@ -30,15 +30,6 @@ iD.ui.PresetGrid = function(context, entity) { .attr('class', 'icon close'); } - var geometry = entity.geometry(context.graph()); - - var gridwrap = selection.append('div') - .attr('class', 'fillL2 inspector-body inspector-body-' + geometry); - - var grid = gridwrap.append('div') - .attr('class', 'preset-grid fillL cf') - .call(drawGrid, context.presets().defaults(geometry, 36)); - function keydown() { // hack to let delete shortcut work when search is autofocused if (search.property('value').length === 0 && @@ -62,7 +53,7 @@ iD.ui.PresetGrid = function(context, entity) { // enter var value = search.property('value'); if (d3.event.keyCode === 13 && value.length) { - choose(grid.selectAll('.grid-entry:first-child').datum()); + grid.selectAll('.grid-entry:first-child').datum().choose(); } else { grid.classed('filtered', value.length); if (value.length) { @@ -95,137 +86,139 @@ iD.ui.PresetGrid = function(context, entity) { search.node().focus(); } - function choose(d) { - // Category - if (d.members) { - var subgrid = insertBox(grid, d, 'subgrid'); + var gridwrap = selection.append('div') + .attr('class', 'fillL2 inspector-body inspector-body-' + geometry); - if (subgrid) { - subgrid.append('div') - .attr('class', 'arrow'); - - subgrid.append('div') - .attr('class', 'preset-grid fillL3 cf fl') - .call(drawGrid, d.members); - - subgrid.style('max-height', '0px') - .style('padding-bottom', '0px') - .transition() - .duration(300) - .style('padding-bottom', '20px') - .style('max-height', (d.members.collection.length * 80) + 200 + 'px'); - } - - // Preset - } else { - context.presets().choose(d); - event.choose(d); - } - } - - // Inserts a div inline after the entry for the provided entity - // Used for preset descriptions, and for expanding categories - function insertBox(grid, entity, klass) { - - var entries = grid.selectAll('button.grid-entry'), - shown = grid.selectAll('.box-insert'), - shownIndex = Infinity, - index; - - if (shown.node()) { - shown.transition() - .duration(200) - .style('opacity','0') - .style('max-height', '0px') - .style('padding-top', '0px') - .style('padding-bottom', '0px') - .remove(); - - if (shown.datum() === entity && shown.classed(klass)) return; - shownIndex = Array.prototype.indexOf.call(shown.node().parentNode.childNodes, shown.node()); - } - - entries.each(function(d, i) { - if (d === entity) index = i; - }); - - if (index >= shownIndex) index++; - - var elem = document.createElement('div'); - grid.node().insertBefore(elem, grid.node().childNodes[index + 1]); - - var newbox = d3.select(elem) - .attr('class', 'col12 box-insert ' + klass) - .datum(entity); - - return newbox; - } - - function drawGrid(grid, presets) { - - function helpClick(d) { - d3.event.stopPropagation(); - - var presetinspect = insertBox(grid, d, 'preset-inspect'); - - if (!presetinspect) return; - - var tag = {key: Object.keys(d.tags)[0]}; - - if (d.tags[tag.key] !== '*') { - tag.value = d.tags[tag.key]; - } - - var tagReference = iD.ui.TagReference(entity, tag); - presetinspect.style('max-height', '200px') - .call(tagReference); - tagReference.show(); - } - - grid.selectAll('.preset-inspect, .subgrid').remove(); - - var entries = grid - .selectAll('.grid-entry-wrap') - .data(presets.collection, function(d) { return d.id; }); - - entries.exit() - .remove(); - - var entered = entries.enter() - .append('div') - .attr('class','grid-button-wrap col12 grid-entry-wrap') - .classed('category', function(d) { return !!d.members; }) - .classed('current', function(d) { return d === preset; }); - - var buttonInner = entered.append('button') - .attr('class', 'grid-entry') - .on('click', choose); - - buttonInner - .style('opacity', 0) - .transition() - .style('opacity', 1); - - buttonInner - .call(iD.ui.PresetIcon(context.geometry(entity.id))); - - var label = buttonInner.append('div') - .attr('class','label') - .text(function(d) { return d.name(); }); - - entered.filter(function(d) { return !d.members; }) - .call(iD.ui.TagReferenceButton() - .on('click', helpClick)); - - entries.order(); - } + var grid = gridwrap.append('div') + .attr('class', 'preset-grid fillL cf') + .call(drawGrid, context.presets().defaults(geometry, 36)); } - presetgrid.autofocus = function(_) { + function drawGrid(grid, presets) { + var collection = presets.collection.map(function(preset) { + return preset.members ? CategoryItem(preset) : PresetItem(preset) + }); + + var items = grid.selectAll('.preset-item') + .data(collection, function(d) { return d.preset.id; }); + + items.enter().append('div') + .attr('class', 'preset-item') + .classed('current', function(item) { return item.preset === current; }) + .each(function(item) { + d3.select(this).call(item); + }) + .style('opacity', 0) + .transition() + .style('opacity', 1); + + items.order(); + + items.exit() + .remove(); + } + + function CategoryItem(preset) { + var box, subgrid, shown = false; + + function item(selection) { + var wrap = selection.append('div') + .attr('class', 'grid-button-wrap category col12'); + + wrap.append('button') + .datum(preset) + .attr('class', 'grid-entry') + .call(iD.ui.PresetIcon(context.geometry(entity.id))) + .on('click', item.choose) + .append('div') + .attr('class', 'label') + .text(preset.name()); + + box = selection.append('div') + .attr('class', 'subgrid col12') + .style('max-height', '0'); + + box.append('div') + .attr('class', 'arrow'); + + subgrid = box.append('div') + .attr('class', 'preset-grid fillL3 cf fl'); + } + + item.choose = function() { + if (shown) { + shown = false; + box.transition() + .duration(200) + .style('opacity', '0') + .style('max-height', '0') + .style('padding-bottom', '0'); + } else { + shown = true; + subgrid.call(drawGrid, preset.members); + box.transition() + .duration(200) + .style('opacity', '1') + .style('max-height', 200 + preset.members.collection.length * 80 + 'px') + .style('padding-bottom', '20px'); + } + }; + + item.preset = preset; + + return item; + } + + function PresetItem(preset) { + function item(selection) { + var wrap = selection.append('div') + .attr('class', 'grid-button-wrap col12'); + + wrap.append('button') + .datum(preset) + .attr('class', 'grid-entry') + .call(iD.ui.PresetIcon(context.geometry(entity.id))) + .on('click', item.choose) + .append('div') + .attr('class', 'label') + .text(preset.name()); + + wrap.call(iD.ui.TagReferenceButton() + .on('click', item.help)); + + selection.append('div') + .attr('class', 'preset-inspect col12') + .style('max-height', '200px') + .call(item.reference); + } + + item.choose = function() { + context.presets().choose(preset); + event.choose(preset); + }; + + item.help = function() { + d3.event.stopPropagation(); + item.reference.toggle(); + }; + + item.preset = preset; + item.reference = iD.ui.TagReference(null, preset.reference()); + + return item; + } + + presetGrid.autofocus = function(_) { if (!arguments.length) return autofocus; autofocus = _; - return presetgrid; + return presetGrid; }; - return d3.rebind(presetgrid, event, 'on'); + presetGrid.current = function(_) { + if (!arguments.length) return current; + current = _; + return presetGrid; + }; + + return d3.rebind(presetGrid, event, 'on'); };