From 663f880f5756f6453de079b45a7f2954e8b48828 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Wed, 17 Oct 2012 14:34:34 -0400 Subject: [PATCH] Create simple Taginfo wrapper, suggest tags with datalists, rework tag editor window stashing concept of presets for now. --- css/app.css | 17 ++++++++ index.html | 1 + js/iD/Node.js | 50 +++++++++++----------- js/iD/Taginfo.js | 28 ++++++++++++ js/iD/Way.js | 16 +++---- js/iD/tags/PresetList.js | 1 - js/iD/tags/TagEditor.js | 92 ++++++++++++++++++++++++++++------------ 7 files changed, 144 insertions(+), 61 deletions(-) create mode 100644 js/iD/Taginfo.js diff --git a/css/app.css b/css/app.css index fe8e1538b..4c6e46406 100644 --- a/css/app.css +++ b/css/app.css @@ -1,7 +1,14 @@ /* Additional CSS rules will go here */ +* { + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + .currentMode { font-weight: bold; } +/* Zoom controls */ #zoombuttons { position:absolute; right:20px; @@ -31,3 +38,13 @@ border-left:0; border-radius: 0 4px 4px 0; } + +/* Tag window */ +#tagform input.key { + margin-right:10px; +} +#tagform input.key, +#tagform input.value { + font: normal 13px/20px 'Helvetica'; + width:135px; +} diff --git a/index.html b/index.html index 3220e6585..e838daa92 100755 --- a/index.html +++ b/index.html @@ -21,6 +21,7 @@ + diff --git a/js/iD/Node.js b/js/iD/Node.js index ca1c21b78..7c285639c 100644 --- a/js/iD/Node.js +++ b/js/iD/Node.js @@ -16,45 +16,45 @@ iD.Node = function(conn, id, lat, lon, tags, loaded) { }; iD.Node.prototype = { - project: function() { - // summary: Update the projected latitude value (this.latp) from the latitude (this.lat). - this.latp = 180/Math.PI * + project: function() { + // summary: Update the projected latitude value (this.latp) from the latitude (this.lat). + this.latp = 180/Math.PI * Math.log(Math.tan(Math.PI/4+this.lat*(Math.PI/180)/2)); - }, - latp2lat: function(a) { - // summary: Get a latitude from a projected latitude. - // returns: Latitude. - return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); - }, + }, + latp2lat: function(a) { + // summary: Get a latitude from a projected latitude. + // returns: Latitude. + return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); + }, - within: function(left, right, top, bottom) { + within: function(left, right, top, bottom) { return (this.lon >= left) && (this.lon <= right) && (this.lat >= bottom) && (this.lat <= top); }, - refresh: function() { - var ways = this.parentWays(); - _.each(ways, _.bind(function(way) { this.connection.refreshEntity(way); }, this)); - this.connection.refreshEntity(this); - }, + refresh: function() { + var ways = this.parentWays(); + _.each(ways, _.bind(function(way) { this.connection.refreshEntity(way); }, this)); + this.connection.refreshEntity(this); + }, - doSetLonLatp: function(lon,latproj,performAction) { - // summary: Change the position of a node, using an undo stack. - performAction(new iD.actions.MoveNodeAction(this, + doSetLonLatp: function(lon,latproj,performAction) { + // summary: Change the position of a node, using an undo stack. + performAction(new iD.actions.MoveNodeAction(this, this.latp2lat(latproj), lon, lang.hitch(this,this._setLatLonImmediate))); - }, + }, - _setLatLonImmediate: function(lat,lon) { - this.lat = lat; - this.lon = lon; - this.project(); - var ways = this.parentWays(); + _setLatLonImmediate: function(lat,lon) { + this.lat = lat; + this.lon = lon; + this.project(); + var ways = this.parentWays(); _.each(ways, _.bind(function(way) { way.expandBbox(this); }, this)); - } + } }; diff --git a/js/iD/Taginfo.js b/js/iD/Taginfo.js new file mode 100644 index 000000000..eb65a6234 --- /dev/null +++ b/js/iD/Taginfo.js @@ -0,0 +1,28 @@ +if (typeof iD === 'undefined') iD = {}; + +// Taginfo service singleton +iD.Taginfo = (function() { + + var taginfo = {}, + endpoint = 'http://taginfo.openstreetmap.org/api/2/'; + + // Given a key, return common values + // TODO: get type, count correctly based on it + taginfo.values = function(key, callback) { + $.ajax({ + url: endpoint + 'db/keys/values', + data: { + key: key, + sortname: 'count_all', + sortorder: 'desc', + page: 1 + }, + dataType: 'jsonp', + success: function(resp) { + if (resp.data) callback(resp.data); + } + }); + }; + + return taginfo; +})(); diff --git a/js/iD/Way.js b/js/iD/Way.js index 2f9d7cdcb..268e6de0e 100644 --- a/js/iD/Way.js +++ b/js/iD/Way.js @@ -91,16 +91,16 @@ iD.Way.prototype = { // isSnap: Boolean Should the node position be snapped to be exactly on the segment? // returns: The index at which the node was inserted. var closestProportion = 1, - newIndex = 0, - snapped; + newIndex = 0, + snapped; for (var i = 0; i < this.nodes.length - 1; i++) { - var node1 = this.nodes[i]; - var node2 = this.nodes[i + 1]; - var directDist = this._pythagoras(node1, node2); - var viaNewDist = this._pythagoras(node1, newNode) + - this._pythagoras(node2, newNode); - var proportion = Math.abs(viaNewDist/directDist - 1); + var node1 = this.nodes[i], + node2 = this.nodes[i + 1], + directDist = this._pythagoras(node1, node2), + viaNewDist = this._pythagoras(node1, newNode) + + this._pythagoras(node2, newNode), + proportion = Math.abs(viaNewDist/directDist - 1); if (proportion < closestProportion) { newIndex = i+1; closestProportion = proportion; diff --git a/js/iD/tags/PresetList.js b/js/iD/tags/PresetList.js index 78946d475..463b89d24 100644 --- a/js/iD/tags/PresetList.js +++ b/js/iD/tags/PresetList.js @@ -12,7 +12,6 @@ declare("iD.tags.PresetList", null, { // summary: List of presets for a given type (e.g. nodes, ways) this.entityType = type; - console.log(url); $.ajax({ url: url, success: _.bind(this.loaded, this), diff --git a/js/iD/tags/TagEditor.js b/js/iD/tags/TagEditor.js index dad3d24a7..20610d6ac 100644 --- a/js/iD/tags/TagEditor.js +++ b/js/iD/tags/TagEditor.js @@ -1,7 +1,7 @@ // iD/tags/TagEditor.js define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/xhr','dojo/dom-construct', - 'dijit/Dialog','dijit/form/Form','dijit/form/Button','dijit/form/TextBox'], + 'dijit/Dialog','dijit/form/Form','dijit/form/Button','dijit/form/TextBox'], function(declare,lang,xhr,domConstruct){ declare("iD.tags.TagEditor", null, { @@ -23,21 +23,18 @@ declare("iD.tags.TagEditor", null, { content: "", style: "width: 300px" }); - var form = new dijit.form.Form({ - encType: 'multipart/form-data', - action: '', - method: '', - onSubmit: function(event) { console.log('submit'); } - }, dojo.doc.createElement('div')); + this.$content = $('
'); + this.render(); - this.dialog.set('content', form); + this.dialog.set('content', this.$content[0]); this.dialog.show(); - // What editors are relevant? - var presetList = this.controller.presets[entity.entityType]; - var applicablePresets = presetList.assembleEditorsForEntity(entity); + /* + // What editors are relevant? + var presetList = this.controller.presets[entity.entityType], + applicablePresets = presetList.assembleEditorsForEntity(entity), + i; - var i; // Add preset types for (i in applicablePresets.presets) { this.appendPreset(i, applicablePresets.presets[i], form.domNode); @@ -47,14 +44,60 @@ declare("iD.tags.TagEditor", null, { for (i in applicablePresets.editors) { this.appendEditor(applicablePresets.editors[i], form.domNode); } + */ }, // ------------ // Presets + render: function() { + this.$content.empty(); + // TODO: optimize + if (!$('#datalists').size()) { + $(document.body).append('
'); + } + _.each(this.entity.tags, _.bind(function(value, key) { + var row = $('
'), + keyid = 'key-' + key; + + $('') + .val(key) + .attr({ + 'class': 'key' + }).appendTo(row); + + $('') + .val(value) + .attr({ + 'list': keyid, + 'class': 'value' + }).appendTo(row); + + // Share datalists between same-keys + if (!$('datalist#' + keyid).size()) { + iD.Taginfo.values(key, function(values) { + + var $dl = $('') + .attr('id', keyid); + + _.each(values, function(v) { + $dl.append($('') + .attr('value', v.value)); + }); + + $('#datalists').append($dl); + }); + } + + this.$content.append(row); + }, this)); + }, + appendPreset:function(name, preset, destination) { - var element=domConstruct.create('h2'); - element.appendChild(domConstruct.create('img', { src: 'presets/' + preset.icon })); + var element = domConstruct.create('h2'); + element.appendChild(domConstruct.create('img', { + src: 'presets/' + preset.icon + })); element.appendChild(dojo.doc.createTextNode(name)); destination.appendChild(element); }, @@ -67,11 +110,10 @@ declare("iD.tags.TagEditor", null, { if (this.controller.editorCache[editor]) { this.renderEditor(editor, destination); } else { - dojo.xhrGet({ - url: "presets/editors/"+_editor+".json", - handleAs: "json", + $.ajax({ + url: "presets/editors/" + editor + ".json", // TODO: eliminate lang.hitch here - load: lang.hitch(this, this.loadedEditor, editor, destination), + success: lang.hitch(this, this.loadedEditor, editor, destination), error: function(err) { console.log("Couldn't load editor"); } }); } @@ -83,16 +125,17 @@ declare("iD.tags.TagEditor", null, { this.renderEditor(editor, destination); }, - renderEditor: function(_editor, destination) { + renderEditor: function(editor_name, destination) { // summary: Render an editor as a form. - var editor=this.controller.editorCache[_editor]; + editor = this.controller.editorCache[editor_name]; // Add the subhead - var element=domConstruct.create('h3'); - element.appendChild(dojo.doc.createTextNode(_editor)); + var element = domConstruct.create('h3'); + element.appendChild(dojo.doc.createTextNode(editor)); destination.appendChild(element); // Add each form element + // this.$content for (var label in editor) { var item = editor[label]; var value = this.getTagValue(item.key); @@ -117,11 +160,6 @@ declare("iD.tags.TagEditor", null, { // var resetbtn = new dijit.form.Button({ type: 'reset', label: 'Reset' }, dojo.doc.createElement('button')); // _destination.appendChild(submitbtn.domNode); // _destination.appendChild(resetbtn.domNode); - }, - - getTagValue:function(k) { - // summary: Get the value of a tag for the current entity, or empty string if unset. - return this.entity.tags[k] ? this.entity.tags[k] : ''; } });