Added post note editing to frontend
This commit is contained in:
parent
e983e72013
commit
50608074c6
7 changed files with 184 additions and 28 deletions
10
TODO
10
TODO
|
@ -11,15 +11,7 @@ first major release.
|
|||
- tags: add tag edit snapshots (backed-only)
|
||||
|
||||
- post notes
|
||||
- "add note" in sidebar creates new note in the middle of image
|
||||
- hovering notes shows note text
|
||||
- dragging and resizing notes is always possible
|
||||
- clicking note reveals modal popup with textarea to input text
|
||||
- under textarea there are buttons for saving and/or deleting the note.
|
||||
- post notes should have separate table and shouldn't be stored as json
|
||||
column.
|
||||
- post notes should be visible in post edit history.
|
||||
(move post snapshot factory methods to PostService)
|
||||
- post notes history
|
||||
|
||||
refactors:
|
||||
- add enum validation in IValidatables (needs refactors of enums and
|
||||
|
|
|
@ -174,6 +174,10 @@
|
|||
.post-content {
|
||||
position: relative;
|
||||
}
|
||||
.post-notes-target,
|
||||
.post-notes {
|
||||
pointer-events: none;
|
||||
}
|
||||
.post-notes {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
@ -181,17 +185,35 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.post-note-edit {
|
||||
pointer-events: auto;
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
padding: 1em;
|
||||
left: 10%;
|
||||
top: 10%;
|
||||
}
|
||||
.post-note-edit textarea {
|
||||
width: 20em;
|
||||
height: 5em;
|
||||
}
|
||||
.post-note-edit .actions {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
.post-note-edit .actions button:not(:last-child) {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
.post-note {
|
||||
pointer-events: auto;
|
||||
position: absolute;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
.post-note .dragger {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: move;
|
||||
}
|
||||
.post-note .text-wrapper {
|
||||
position: absolute;
|
||||
display: none;
|
||||
|
@ -199,6 +221,9 @@
|
|||
left: -1px;
|
||||
padding-top: 0.5em;
|
||||
cursor: pointer;
|
||||
width: -webkit-max-content;
|
||||
width: -moz-max-content;
|
||||
width: max-content;
|
||||
}
|
||||
.post-note .text {
|
||||
padding: 0.5em;
|
||||
|
@ -209,6 +234,19 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.post-note .text p:first-of-type {
|
||||
margin-top: 0;
|
||||
}
|
||||
.post-note .text p:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.post-note .dragger {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: move;
|
||||
}
|
||||
.post-note .resizer {
|
||||
position: absolute;
|
||||
cursor: nwse-resize;
|
||||
|
|
|
@ -40,9 +40,14 @@ App.Presenters.PostContentPresenter = function(
|
|||
function() {});
|
||||
}
|
||||
|
||||
function addNewPostNote() {
|
||||
postNotesPresenter.addNewPostNote();
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
render: render,
|
||||
addNewPostNote: addNewPostNote,
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -4,18 +4,25 @@ App.Presenters = App.Presenters || {};
|
|||
App.Presenters.PostNotesPresenter = function(
|
||||
jQuery,
|
||||
util,
|
||||
promise) {
|
||||
promise,
|
||||
api,
|
||||
auth) {
|
||||
|
||||
var post;
|
||||
var notes;
|
||||
var templates = {};
|
||||
var $target;
|
||||
var $form;
|
||||
var privileges = {};
|
||||
|
||||
function init(params, loaded) {
|
||||
$target = params.$target;
|
||||
post = params.post;
|
||||
notes = params.notes || [];
|
||||
|
||||
privileges.canDeletePostNotes = auth.hasPrivilege(auth.privileges.deletePostNotes);
|
||||
privileges.canEditPostNotes = auth.hasPrivilege(auth.privileges.editPostNotes);
|
||||
|
||||
promise.wait(util.promiseTemplate('post-notes'))
|
||||
.then(function(postNotesTemplate) {
|
||||
templates.postNotes = postNotesTemplate;
|
||||
|
@ -27,26 +34,100 @@ App.Presenters.PostNotesPresenter = function(
|
|||
});
|
||||
}
|
||||
|
||||
function addNewNote() {
|
||||
notes.push({left: 50, top: 50, width: 50, height: 50, text: '…'});
|
||||
function addNewPostNote() {
|
||||
notes.push({left: 50, top: 50, width: 50, height: 50, text: '…'});
|
||||
}
|
||||
|
||||
function addNewNoteAndRender() {
|
||||
addNewNote();
|
||||
function addNewPostNoteAndRender() {
|
||||
addNewPostNote();
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
$target.html(templates.postNotes({post: post, notes: notes}));
|
||||
$target.html(templates.postNotes({
|
||||
privileges: privileges,
|
||||
post: post,
|
||||
notes: notes,
|
||||
formatMarkdown: util.formatMarkdown}));
|
||||
|
||||
$form = $target.find('.post-note-edit');
|
||||
var $postNotes = $target.find('.post-note');
|
||||
|
||||
$postNotes.each(function(i) {
|
||||
var postNote = notes[i];
|
||||
var $postNote = jQuery(this);
|
||||
$postNote.data('postNote', notes[i]);
|
||||
$postNote.find('.text-wrapper').mouseup(postNoteClicked);
|
||||
$postNote.data('postNote', postNote);
|
||||
$postNote.find('.text-wrapper').click(postNoteClicked);
|
||||
postNote.$element = $postNote;
|
||||
makeDraggable($postNote);
|
||||
makeResizable($postNote);
|
||||
});
|
||||
|
||||
$form.find('button').click(formSubmitted);
|
||||
}
|
||||
|
||||
function formSubmitted(e) {
|
||||
e.preventDefault();
|
||||
var $button = jQuery(e.target);
|
||||
var sender = $button.val();
|
||||
|
||||
var postNote = $form.data('postNote');
|
||||
postNote.left = postNote.$element.offset().left - $target.offset().left;
|
||||
postNote.top = postNote.$element.offset().top - $target.offset().top;
|
||||
postNote.width = postNote.$element.width();
|
||||
postNote.height = postNote.$element.height();
|
||||
postNote.text = $form.find('textarea').val();
|
||||
|
||||
if (sender === 'cancel') {
|
||||
hideForm();
|
||||
} else if (sender === 'remove') {
|
||||
removePostNote(postNote);
|
||||
} else if (sender === 'save') {
|
||||
savePostNote(postNote);
|
||||
}
|
||||
}
|
||||
|
||||
function removePostNote(postNote) {
|
||||
if (postNote.id) {
|
||||
if (window.confirm('Are you sure you want to delete this note?')) {
|
||||
promise.wait(api.delete('/notes/' + postNote.id))
|
||||
.then(function() {
|
||||
hideForm();
|
||||
postNote.$element.remove();
|
||||
}).fail(function(response) {
|
||||
window.alert(response.json && response.json.error || response);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
postNote.$element.remove();
|
||||
hideForm();
|
||||
}
|
||||
}
|
||||
|
||||
function savePostNote(postNote) {
|
||||
if (window.confirm('Are you sure you want to save this note?')) {
|
||||
var formData = {
|
||||
left: postNote.left,
|
||||
top: postNote.top,
|
||||
width: postNote.width,
|
||||
height: postNote.height,
|
||||
text: postNote.text,
|
||||
};
|
||||
|
||||
var p = postNote.id ?
|
||||
api.put('/notes/' + postNote.id, formData) :
|
||||
api.post('/notes/' + post.id, formData);
|
||||
|
||||
promise.wait(p)
|
||||
.then(function(response) {
|
||||
hideForm();
|
||||
postNote.id = response.json.id;
|
||||
postNote.$element.data('postNote', postNote);
|
||||
render();
|
||||
}).fail(function(response) {
|
||||
window.alert(response.json && response.json.error || response);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function postNoteClicked(e) {
|
||||
|
@ -55,8 +136,19 @@ App.Presenters.PostNotesPresenter = function(
|
|||
if ($postNote.hasClass('resizing') || $postNote.hasClass('dragging')) {
|
||||
return;
|
||||
}
|
||||
showFormForPostNote($postNote);
|
||||
}
|
||||
|
||||
function showFormForPostNote($postNote) {
|
||||
var postNote = $postNote.data('postNote');
|
||||
$form.data('postNote', postNote);
|
||||
$form.find('textarea').val(postNote.text);
|
||||
$form.show();
|
||||
}
|
||||
|
||||
function hideForm() {
|
||||
$form.hide();
|
||||
}
|
||||
|
||||
function makeDraggable($element) {
|
||||
var $dragger = jQuery('<div class="dragger"></div>');
|
||||
|
@ -103,7 +195,6 @@ App.Presenters.PostNotesPresenter = function(
|
|||
e.stopPropagation();
|
||||
$element.addClass('resizing');
|
||||
|
||||
var $parent = $element.parent();
|
||||
var deltaX = $element.width() - e.clientX;
|
||||
var deltaY = $element.height() - e.clientY;
|
||||
|
||||
|
@ -129,7 +220,7 @@ App.Presenters.PostNotesPresenter = function(
|
|||
return {
|
||||
init: init,
|
||||
render: render,
|
||||
addNewNote: addNewNoteAndRender,
|
||||
addNewPostNote: addNewPostNoteAndRender,
|
||||
};
|
||||
|
||||
};
|
||||
|
@ -137,5 +228,7 @@ App.Presenters.PostNotesPresenter = function(
|
|||
App.DI.register('postNotesPresenter', [
|
||||
'jQuery',
|
||||
'util',
|
||||
'promise'],
|
||||
'promise',
|
||||
'api',
|
||||
'auth'],
|
||||
App.Presenters.PostNotesPresenter);
|
||||
|
|
|
@ -36,6 +36,7 @@ App.Presenters.PostPresenter = function(
|
|||
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
|
||||
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
|
||||
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
||||
privileges.canAddPostNotes = auth.hasPrivilege(auth.privileges.addPostNotes);
|
||||
|
||||
promise.wait(
|
||||
util.promiseTemplate('post'),
|
||||
|
@ -182,6 +183,12 @@ App.Presenters.PostPresenter = function(
|
|||
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
|
||||
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
|
||||
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
|
||||
$el.find('#sidebar .add-note').click(addNoteButtonClicked);
|
||||
}
|
||||
|
||||
function addNoteButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
postContentPresenter.addNewPostNote();
|
||||
}
|
||||
|
||||
function deleteButtonClicked(e) {
|
||||
|
|
|
@ -8,10 +8,23 @@
|
|||
|
||||
<div class="text-wrapper">
|
||||
<div class="text">
|
||||
<%= note.text %>
|
||||
<%= formatMarkdown(note.text) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<% }) %>
|
||||
</div>
|
||||
|
||||
<form class="post-note-edit">
|
||||
<textarea></textarea>
|
||||
<div class="actions"><!--
|
||||
--><% if (privileges.canEditPostNotes) { %><!--
|
||||
--><button type="submit" name="sender" value="save">Save</button><!--
|
||||
--><% } %><!--
|
||||
--><button type="submit" name="sender" value="cancel">Cancel</button><!--
|
||||
--><% if (privileges.canDeletePostNotes) { %><!--
|
||||
--><button type="submit" name="sender" value="remove">Remove</button><!--
|
||||
--><% } %><!--
|
||||
--></div>
|
||||
</form>
|
||||
|
|
|
@ -207,6 +207,14 @@
|
|||
</li>
|
||||
<% } %>
|
||||
|
||||
<% if (privileges.canAddPostNotes) { %>
|
||||
<li>
|
||||
<a class="add-note" href="#">
|
||||
Add new note
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
|
||||
<% if (privileges.canDeletePosts) { %>
|
||||
<li>
|
||||
<a class="delete" href="#">
|
||||
|
|
Loading…
Reference in a new issue