client/posts: add copying notes to clipboard
Saves some frustration when losing changes due to editing conflict
This commit is contained in:
parent
674d6c35d7
commit
87735110aa
|
@ -66,6 +66,12 @@
|
||||||
<a href class='add'>Add a note</a>
|
<a href class='add'>Add a note</a>
|
||||||
<%= ctx.makeTextarea({disabled: true, text: 'Content (supports Markdown)', rows: '8'}) %>
|
<%= ctx.makeTextarea({disabled: true, text: 'Content (supports Markdown)', rows: '8'}) %>
|
||||||
<a href class='delete inactive'>Delete selected note</a>
|
<a href class='delete inactive'>Delete selected note</a>
|
||||||
|
<% if (ctx.hasClipboard) { %>
|
||||||
|
<br/>
|
||||||
|
<a href class='copy'>Export notes to clipboard</a>
|
||||||
|
<br/>
|
||||||
|
<a href class='paste'>Import notes from clipboard</a>
|
||||||
|
<% } %>
|
||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ const config = require('../config.js');
|
||||||
const events = require('../events.js');
|
const events = require('../events.js');
|
||||||
const misc = require('../util/misc.js');
|
const misc = require('../util/misc.js');
|
||||||
const views = require('../util/views.js');
|
const views = require('../util/views.js');
|
||||||
|
const Note = require('../models/note.js');
|
||||||
|
const Point = require('../models/point.js');
|
||||||
const TagInputControl = require('./tag_input_control.js');
|
const TagInputControl = require('./tag_input_control.js');
|
||||||
const ExpanderControl = require('../controls/expander_control.js');
|
const ExpanderControl = require('../controls/expander_control.js');
|
||||||
const FileDropperControl = require('../controls/file_dropper_control.js');
|
const FileDropperControl = require('../controls/file_dropper_control.js');
|
||||||
|
@ -25,6 +27,7 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
views.replaceContent(this._hostNode, template({
|
views.replaceContent(this._hostNode, template({
|
||||||
post: this._post,
|
post: this._post,
|
||||||
enableSafety: config.enableSafety,
|
enableSafety: config.enableSafety,
|
||||||
|
hasClipboard: document.queryCommandSupported('copy'),
|
||||||
canEditPostSafety: api.hasPrivilege('posts:edit:safety'),
|
canEditPostSafety: api.hasPrivilege('posts:edit:safety'),
|
||||||
canEditPostSource: api.hasPrivilege('posts:edit:source'),
|
canEditPostSource: api.hasPrivilege('posts:edit:source'),
|
||||||
canEditPostTags: api.hasPrivilege('posts:edit:tags'),
|
canEditPostTags: api.hasPrivilege('posts:edit:tags'),
|
||||||
|
@ -107,6 +110,16 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
'click', e => this._evtAddNoteClick(e));
|
'click', e => this._evtAddNoteClick(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._copyNotesLinkNode) {
|
||||||
|
this._copyNotesLinkNode.addEventListener(
|
||||||
|
'click', e => this._evtCopyNotesClick(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._pasteNotesLinkNode) {
|
||||||
|
this._pasteNotesLinkNode.addEventListener(
|
||||||
|
'click', e => this._evtPasteNotesClick(e));
|
||||||
|
}
|
||||||
|
|
||||||
if (this._deleteNoteLinkNode) {
|
if (this._deleteNoteLinkNode) {
|
||||||
this._deleteNoteLinkNode.addEventListener(
|
this._deleteNoteLinkNode.addEventListener(
|
||||||
'click', e => this._evtDeleteNoteClick(e));
|
'click', e => this._evtDeleteNoteClick(e));
|
||||||
|
@ -252,6 +265,50 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
this._postNotesOverlayControl.switchToDrawing();
|
this._postNotesOverlayControl.switchToDrawing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_evtCopyNotesClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
let textarea = document.createElement('textarea');
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.opacity = '0';
|
||||||
|
textarea.value = JSON.stringify([...this._post.notes].map(note => ({
|
||||||
|
polygon: [...note.polygon].map(
|
||||||
|
point => [point.x, point.y]),
|
||||||
|
text: note.text,
|
||||||
|
})));
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.select();
|
||||||
|
|
||||||
|
let success = false;
|
||||||
|
try {
|
||||||
|
success = document.execCommand('copy');
|
||||||
|
} catch (err) {
|
||||||
|
}
|
||||||
|
textarea.blur();
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
alert(success
|
||||||
|
? 'Notes copied to clipboard.'
|
||||||
|
: 'Failed to copy the text to clipboard. Sorry.');
|
||||||
|
}
|
||||||
|
|
||||||
|
_evtPasteNotesClick(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const text = window.prompt(
|
||||||
|
'Please enter the exported notes snapshot:');
|
||||||
|
if (!text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const notesObj = JSON.parse(text);
|
||||||
|
this._post.notes.clear();
|
||||||
|
for (let noteObj of notesObj) {
|
||||||
|
let note = new Note();
|
||||||
|
for (let pointObj of noteObj.polygon) {
|
||||||
|
note.polygon.add(new Point(pointObj[0], pointObj[1]));
|
||||||
|
}
|
||||||
|
note.text = noteObj.text;
|
||||||
|
this._post.notes.add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_evtDeleteNoteClick(e) {
|
_evtDeleteNoteClick(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.target.classList.contains('inactive')) {
|
if (e.target.classList.contains('inactive')) {
|
||||||
|
@ -350,6 +407,14 @@ class PostEditSidebarControl extends events.EventTarget {
|
||||||
return this._formNode.querySelector('.notes .add');
|
return this._formNode.querySelector('.notes .add');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get _copyNotesLinkNode() {
|
||||||
|
return this._formNode.querySelector('.notes .copy');
|
||||||
|
}
|
||||||
|
|
||||||
|
get _pasteNotesLinkNode() {
|
||||||
|
return this._formNode.querySelector('.notes .paste');
|
||||||
|
}
|
||||||
|
|
||||||
get _deleteNoteLinkNode() {
|
get _deleteNoteLinkNode() {
|
||||||
return this._formNode.querySelector('.notes .delete');
|
return this._formNode.querySelector('.notes .delete');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue