Tagging work in progress

This commit is contained in:
Richard Fairhurst
2012-10-12 00:32:13 +01:00
parent 3744ca602d
commit 50f7a5dcfc
44 changed files with 334 additions and 20 deletions
+14 -4
View File
@@ -1,38 +1,48 @@
// iD/Controller.js
define(['dojo/_base/declare','dojo/on','iD/actions/UndoStack'], function(declare,on){
define(['dojo/_base/declare','dojo/on','dojo/Evented',
'iD/actions/UndoStack','iD/tags/PresetList'], function(declare,on,Evented){
// ----------------------------------------------------------------------
// Controller base class
declare("iD.Controller", null, {
declare("iD.Controller", [Evented], {
state: null, // current ControllerState
map: null, // current Map
stepper: null, // current StepPane
undoStack: null, // main undoStack
presets: null, // tag presets
editorCache: null, // cache of tag editor objects, means we don't have to repeatedly load them
constructor:function(_map) {
// summary: The Controller marshalls ControllerStates and passes events to them.
this.map=_map;
this.undoStack=new iD.actions.UndoStack();
this.presets={};
this.editorCache={};
},
setStepper:function(_stepper) {
// summary: Set reference for the singleton-like class for the step-by-step instruction panel.
this.stepper=_stepper;
},
setTagPresets:function(type,url) {
// summary: Load and store a JSON tag preset file.
this.presets[type]=new iD.tags.PresetList(type,url);
},
setState:function(newState) {
// summary: Enter a new ControllerState, firing exitState on the old one, and enterState on the new one.
if (newState==this.state) { return; }
if (this.state) {
this.state.exitState(newState);
on.emit(window, "exitState", { bubbles: true, cancelable: true, state: this.state.stateNameAsArray() });
this.emit("exitState", { bubbles: true, cancelable: true, state: this.state.stateNameAsArray() });
}
newState.setController(this);
this.state=newState;
newState.enterState();
on.emit(window, "enterState", { bubbles: true, cancelable: true, state: this.state.stateNameAsArray() });
this.emit("enterState", { bubbles: true, cancelable: true, state: this.state.stateNameAsArray() });
},
entityMouseEvent:function(event,entityUI) {
+8 -1
View File
@@ -11,7 +11,7 @@ define(['dojo/_base/declare','dojo/_base/array','dojo/_base/lang',
declare("iD.Entity", null, {
connection: null,
id: NaN,
id: NaN,
loaded: false,
tags: null,
entityType: '',
@@ -106,6 +106,13 @@ declare("iD.Entity", null, {
}
return n.length==0 ? 'unknown' : n.join('; '); // String
},
matchesTags:function(hash) {
for (var k in hash) {
if (!this.tags[k] || this.tags[k]!=hash[k]) return false;
}
return true;
},
// ---------------
// Parent-handling
+17 -4
View File
@@ -1,7 +1,8 @@
// iD/controller/edit/EditBaseState.js
define(['dojo/_base/declare','dijit/TooltipDialog','dijit/popup',
'iD/controller/ControllerState'], function(declare){
define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/array','dojo/on',
'dijit/registry','dijit/TooltipDialog','dijit/Dialog','dijit/popup',
'iD/controller/ControllerState','iD/tags/TagEditor'], function(declare,lang,array,on,registry){
// ----------------------------------------------------------------------
// EditBaseState class - provides shared UI functions to edit mode states
@@ -21,18 +22,30 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], {
// entity: iD.Entity The entity to be edited.
var h=entity.friendlyName(); h = (h=='') ? h : h+"<br/>";
this.editortooltip = new dijit.TooltipDialog({
content: h+"<button data-dojo-type='dijit.form.Button' type='submit'>Edit tags</button> "
+"<button data-dojo-type='dijit.form.Button' type='submit'>Edit shape</button> ",
content: h+"<button data-dojo-type='dijit.form.Button' id='editTags' parseOnLoad='false' type='submit'>Edit tags</button> "
+"<button data-dojo-type='dijit.form.Button' id='editShape' parseOnLoad='false' type='submit'>Edit shape</button> ",
autoFocus: false
});
on(registry.byId('editTags'), 'click', lang.hitch(this,this.editTags,entity));
dijit.popup.open({ popup: this.editortooltip, x: x, y: y });
},
closeEditorTooltip:function() {
// summary: Close the tooltip.
array.forEach(['editTags','editShape'], function(b){
if (!registry.byId(b)) return;
registry.byId(b).type=''; // fix Safari issue
registry.byId(b).destroy(); // remove from registry so we can reinitialise next time
});
if (this.editortooltip) { dijit.popup.close(this.editortooltip); }
},
editTags:function(entity) {
// summary: Open a tag editor for the selected entity.
var tagEditor = new iD.tags.TagEditor(entity,this.controller);
this.closeEditorTooltip();
},
});
// ----------------------------------------------------------------------
+1 -1
View File
@@ -143,7 +143,7 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], {
};
},
shapeStrokeStyler:function() {
if (isNaN(this.casing_color)) { return { width:0 }; }
if (isNaN(this.casing_color)) { return { width:0 }; }
return {
color: this.dojoColor(this.casing_color, this.casing_opacity ? this.casing_opacity : 1),
width: this.casing_width ? this.casing_width : 1
+50
View File
@@ -0,0 +1,50 @@
// iD/tags/PresetList.js
// List of presets for a given type (e.g. nodes, ways)
define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/xhr'], function(declare,lang,xhr){
declare("iD.tags.PresetList", null, {
entityType: null,
presets: null,
constructor:function(_type,_url) {
// summary: List of presets for a given type (e.g. nodes, ways)
this.entityType=_type;
dojo.xhrGet({
url: _url,
handleAs: "json",
load: lang.hitch(this, this.loaded),
error: function(err) { console.log("Couldn't load presets"); }
});
},
loaded:function(_obj) {
this.presets=_obj;
console.log("Loaded presets for "+this.entityType);
},
assembleEditorsForEntity:function(_entity) {
if (_entity.entityType!=this.entityType) return false;
var editorList=[];
for (var group in this.presets) {
for (var preset in this.presets[group]) {
var props=this.presets[group][preset];
if (_entity.matchesTags(props.tags)) {
for (var i in props.editors) {
var editor=props.editors[i];
if (editorList.indexOf(editor)==-1) { editorList.push(editor); }
}
}
}
}
return editorList;
}
});
// ----------------------------------------------------------------------
// End of module
});
+100
View File
@@ -0,0 +1,100 @@
// 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'],
function(declare,lang,xhr,domConstruct){
declare("iD.tags.TagEditor", null, {
entity: null,
controller: null,
dialog: null,
editorContainers: null, // hash of DOM nodes to put editors in
constructor:function(_entity,_controller) {
// summary: Construct a tag editor dialog box.
console.log("TagEditor constructor");
this.entity=_entity;
this.controller=_controller;
this.editorContainers={};
// Create the dialog, and the form to put the editors in
this.dialog = new dijit.Dialog({ title: "My Dialog", content: "Test 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.dialog.set('content',form);
this.dialog.show();
// Add each editor
var presetList=this.controller.presets[_entity.entityType];
var editors=presetList.assembleEditorsForEntity(_entity);
for (var i in editors) {
var editor=editors[i];
this.appendEditor(editor,form.domNode);
}
},
appendEditor:function(_editor,_destination) {
// summary: Request an editor (cached if available, XHR if not), and call renderEditor when it's available.
if (this.controller.editorCache[_editor]) {
this.renderEditor(_editor,_destination);
} else {
dojo.xhrGet({
url: "presets/editors/"+_editor+".json",
handleAs: "json",
load: lang.hitch(this, this.loadedEditor, _editor, _destination),
error: function(err) { console.log("Couldn't load editor"); }
});
}
},
loadedEditor:function(_editor,_destination,_obj) {
// summary: Editor has loaded via XHR, so store it in the cache and render it.
this.controller.editorCache[_editor]=_obj;
this.renderEditor(_editor,_destination);
},
renderEditor:function(_editor,_destination) {
// summary: Render an editor as a form.
var editor=this.controller.editorCache[_editor];
// Add the subhead
var element=domConstruct.create('h3');
element.appendChild(dojo.doc.createTextNode(_editor));
_destination.appendChild(element);
// Add each form element
for (var label in editor) {
var item=editor[label];
var value=this.getTagValue(item.key);
element=domConstruct.create('div');
switch (item.type) {
case 'text':
var textbox = new dijit.form.TextBox({ name: item.key, value: value, type: 'text' }, domConstruct.create('input'));
element.appendChild(dojo.doc.createTextNode(label));
element.appendChild(textbox.domNode);
break;
case 'dropdown':
case 'relation':
case 'hidden':
}
_destination.appendChild(element);
}
// var submitbtn = new dijit.form.Button({ name: 'submit', type: 'submit', value: 'Submit', label: "Submit" }, dojo.doc.createElement('button'));
// 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] : '';
},
});
// ----------------------------------------------------------------------
// End of module
});