Files
iD/modules/ui/note_editor.js
2018-07-24 16:22:21 -04:00

392 lines
12 KiB
JavaScript

import { dispatch as d3_dispatch } from 'd3-dispatch';
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { t } from '../util/locale';
import { services } from '../services';
import { modeBrowse } from '../modes';
import { svgIcon } from '../svg';
// import { uiField } from './field';
// import { uiFormFields } from './form_fields';
import {
uiNoteComments,
uiNoteHeader,
uiNoteReport,
uiViewOnOSM,
} from './index';
import {
utilNoAuto,
utilRebind
} from '../util';
export function uiNoteEditor(context) {
var dispatch = d3_dispatch('change');
var noteComments = uiNoteComments();
var noteHeader = uiNoteHeader();
// var formFields = uiFormFields(context);
var _note;
// var _fieldsArr;
function noteEditor(selection) {
var header = selection.selectAll('.header')
.data([0]);
var headerEnter = header.enter()
.append('div')
.attr('class', 'header fillL');
headerEnter
.append('button')
.attr('class', 'fr note-editor-close')
.on('click', function() {
context.enter(modeBrowse(context));
})
.call(svgIcon('#iD-icon-close'));
headerEnter
.append('h3')
.text(t('note.title'));
var body = selection.selectAll('.body')
.data([0]);
body = body.enter()
.append('div')
.attr('class', 'body')
.merge(body);
var editor = body.selectAll('.note-editor')
.data([0]);
editor.enter()
.append('div')
.attr('class', 'modal-section note-editor')
.merge(editor)
.call(noteHeader.note(_note))
.call(noteComments.note(_note))
.call(noteSaveSection);
var footer = selection.selectAll('.footer')
.data([0]);
footer.enter()
.append('div')
.attr('class', 'footer')
.merge(footer)
.call(uiViewOnOSM(context).what(_note))
.call(uiNoteReport(context).note(_note));
// rerender the note editor on any auth change
var osm = services.osm;
if (osm) {
osm.on('change.note-save', function() {
selection.call(noteEditor);
});
}
}
function noteSaveSection(selection) {
var isSelected = (_note && _note.id === context.selectedNoteID());
var noteSave = selection.selectAll('.note-save')
.data((isSelected ? [_note] : []), function(d) { return d.status + d.id; });
// exit
noteSave.exit()
.remove();
// enter
var noteSaveEnter = noteSave.enter()
.append('div')
.attr('class', 'note-save save-section cf');
// // if new note, show categories to pick from
// if (_note.isNew()) {
// var presets = context.presets();
// // NOTE: this key isn't a age and therefore there is no documentation (yet)
// _fieldsArr = [
// uiField(context, presets.field('category'), null, { show: true, revert: false }),
// ];
// _fieldsArr.forEach(function(field) {
// field
// .on('change', changeCategory);
// });
// noteSaveEnter
// .append('div')
// .attr('class', 'note-category')
// .call(formFields.fieldsArr(_fieldsArr));
// }
// function changeCategory() {
// // NOTE: perhaps there is a better way to get value
// var val = d3_select('input[name=\'category\']:checked').property('__data__') || undefined;
// // store the unsaved category with the note itself
// _note = _note.update({ newCategory: val });
// var osm = services.osm;
// if (osm) {
// osm.replaceNote(_note); // update note cache
// }
// noteSave
// .call(noteSaveButtons);
// }
noteSaveEnter
.append('h4')
.attr('class', '.note-save-header')
.text(function() {
return _note.isNew() ? t('note.newDescription') : t('note.newComment');
});
noteSaveEnter
.append('textarea')
.attr('id', 'new-comment-input')
.attr('placeholder', t('note.inputPlaceholder'))
.attr('maxlength', 1000)
.property('value', function(d) { return d.newComment; })
.call(utilNoAuto)
.on('input', changeInput)
.on('blur', changeInput);
// update
noteSave = noteSaveEnter
.merge(noteSave)
.call(userDetails)
.call(noteSaveButtons);
function changeInput() {
var input = d3_select(this);
var val = input.property('value').trim() || undefined;
// store the unsaved comment with the note itself
_note = _note.update({ newComment: val });
var osm = services.osm;
if (osm) {
osm.replaceNote(_note); // update note cache
}
noteSave
.call(noteSaveButtons);
}
}
function userDetails(selection) {
var detailSection = selection.selectAll('.detail-section')
.data([0]);
detailSection = detailSection.enter()
.append('div')
.attr('class', 'detail-section')
.merge(detailSection);
var osm = services.osm;
if (!osm) return;
// Add warning if user is not logged in
var hasAuth = osm.authenticated();
var authWarning = detailSection.selectAll('.auth-warning')
.data(hasAuth ? [] : [0]);
authWarning.exit()
.transition()
.duration(200)
.style('opacity', 0)
.remove();
var authEnter = authWarning.enter()
.insert('div', '.tag-reference-body')
.attr('class', 'field-warning auth-warning')
.style('opacity', 0);
authEnter
.call(svgIcon('#iD-icon-alert', 'inline'));
authEnter
.append('span')
.text(t('note.login'));
authEnter
.append('a')
.attr('target', '_blank')
.call(svgIcon('#iD-icon-out-link', 'inline'))
.append('span')
.text(t('login'))
.on('click.note-login', function() {
d3_event.preventDefault();
osm.authenticate();
});
authEnter
.transition()
.duration(200)
.style('opacity', 1);
var prose = detailSection.selectAll('.note-save-prose')
.data(hasAuth ? [0] : []);
prose.exit()
.remove();
prose = prose.enter()
.append('p')
.attr('class', 'note-save-prose')
.text(t('note.upload_explanation'))
.merge(prose);
osm.userDetails(function(err, user) {
if (err) return;
var userLink = d3_select(document.createElement('div'));
if (user.image_url) {
userLink
.append('img')
.attr('src', user.image_url)
.attr('class', 'icon pre-text user-icon');
}
userLink
.append('a')
.attr('class', 'user-info')
.text(user.display_name)
.attr('href', osm.userURL(user.display_name))
.attr('tabindex', -1)
.attr('target', '_blank');
prose
.html(t('note.upload_explanation_with_user', { user: userLink.html() }));
});
}
function noteSaveButtons(selection) {
var osm = services.osm;
var hasAuth = osm && osm.authenticated();
var isSelected = (_note && _note.id === context.selectedNoteID());
var buttonSection = selection.selectAll('.buttons')
.data((isSelected ? [_note] : []), function(d) { return d.status + d.id; });
// exit
buttonSection.exit()
.remove();
// enter
var buttonEnter = buttonSection.enter()
.append('div')
.attr('class', 'buttons');
if (_note.isNew()) {
buttonEnter
.append('button')
.attr('class', 'button cancel-button secondary-action')
.text(t('confirm.cancel'));
buttonEnter
.append('button')
.attr('class', 'button save-button action')
.text(t('note.save'));
} else {
buttonEnter
.append('button')
.attr('class', 'button status-button action');
buttonEnter
.append('button')
.attr('class', 'button comment-button action')
.text(t('note.comment'));
}
// update
buttonSection = buttonSection
.merge(buttonEnter);
buttonSection.select('.cancel-button') // select and propagate data
.on('click.cancel', function(d) {
this.blur(); // avoid keeping focus on the button - #4641
var osm = services.osm;
if (osm) {
osm.removeNote(d);
}
context.enter(modeBrowse(context));
});
buttonSection.select('.save-button') // select and propagate data
.attr('disabled', function(d) {
return (hasAuth && d.status === 'open' && d.newComment) ? null : true;
})
.on('click.save', function(d) {
this.blur(); // avoid keeping focus on the button - #4641
var osm = services.osm;
if (osm) {
osm.postNoteCreate(d, function(err, note) {
dispatch.call('change', note);
});
}
});
buttonSection.select('.status-button') // select and propagate data
.attr('disabled', (hasAuth ? null : true))
.text(function(d) {
var action = (d.status === 'open' ? 'close' : 'open');
var andComment = (d.newComment ? '_comment' : '');
return t('note.' + action + andComment);
})
.on('click.status', function(d) {
this.blur(); // avoid keeping focus on the button - #4641
var osm = services.osm;
if (osm) {
var setStatus = (d.status === 'open' ? 'closed' : 'open');
osm.postNoteUpdate(d, setStatus, function(err, note) {
dispatch.call('change', note);
});
}
});
buttonSection.select('.comment-button') // select and propagate data
.attr('disabled', function(d) {
return (hasAuth && d.status === 'open' && d.newComment) ? null : true;
})
.on('click.comment', function(d) {
this.blur(); // avoid keeping focus on the button - #4641
var osm = services.osm;
if (osm) {
osm.postNoteUpdate(d, d.status, function(err, note) {
dispatch.call('change', note);
});
}
});
}
noteEditor.note = function(_) {
if (!arguments.length) return _note;
_note = _;
return noteEditor;
};
return utilRebind(noteEditor, dispatch, 'on');
}