client/posts: add post content editing

This commit is contained in:
rr- 2016-07-27 22:27:33 +02:00
parent 6635b507f2
commit 3d8eaab57a
6 changed files with 91 additions and 16 deletions

View file

@ -57,6 +57,14 @@
}) %>
</section>
<% } %>
<% if (ctx.canEditPostContent) { %>
<section class='post-content'>
<label>Content</label>
<div class='dropper-container'></div>
</section>
<% } %>
</div>
<div class='messages'></div>

View file

@ -115,6 +115,9 @@ class PostController {
if (e.detail.relations !== undefined) {
post.relations = e.detail.relations;
}
if (e.detail.content !== undefined) {
post.content = e.detail.content;
}
post.save()
.then(() => {
misc.disableExitConfirmation();

View file

@ -28,9 +28,14 @@ class FileDropperControl {
this._fileInputNode.addEventListener(
'change', e => this._evtFileChange(e));
this._originalHtml = this._dropperNode.innerHTML;
views.replaceContent(target, source);
}
reset() {
this._dropperNode.innerHTML = this._originalHtml;
}
_resolve(files) {
files = Array.from(files);
if (this._options.lock) {

View file

@ -11,15 +11,17 @@ class PostContentControl {
this._containerNode = containerNode;
this._template = views.getTemplate('post-content');
this._install();
this._currentFitFunction = {
'fit-both': this.fitBoth,
'fit-original': this.fitOriginal,
'fit-width': this.fitWidth,
'fit-height': this.fitHeight,
}[settings.get().fitMode] || this.fitBoth;
this._currentFitFunction();
this._install();
this._post.addEventListener(
'changeContent', e => this._evtPostContentChange(e));
}
fitWidth() {
@ -73,11 +75,15 @@ class PostContentControl {
return this._viewportSizeCalculator()[1];
}
_evtPostContentChange(e) {
this._post = e.detail.post;
this._post.mutateContentUrl();
this._reinstall();
}
_resize(width, height) {
const postContentNode =
this._containerNode.querySelector('.post-content');
postContentNode.style.width = width + 'px';
postContentNode.style.height = height + 'px';
this._postContentNode.style.width = width + 'px';
this._postContentNode.style.height = height + 'px';
}
_refreshSize() {
@ -85,18 +91,26 @@ class PostContentControl {
}
_install() {
const postContentNode = this._template({
post: this._post,
});
if (settings.get().transparencyGrid) {
postContentNode.classList.add('transparency-grid');
}
this._containerNode.appendChild(postContentNode);
this._reinstall();
optimizedResize.add(() => this._refreshSize());
views.monitorNodeRemoval(
this._containerNode, () => { this._uninstall(); });
}
_reinstall() {
const newNode = this._template({post: this._post});
if (settings.get().transparencyGrid) {
newNode.classList.add('transparency-grid');
}
if (this._postContentNode) {
this._containerNode.replaceChild(newNode, this._postContentNode);
} else {
this._containerNode.appendChild(newNode);
}
this._postContentNode = newNode;
this._refreshSize();
}
_uninstall() {
optimizedResize.remove(() => this._refreshSize());
}

View file

@ -5,6 +5,7 @@ const events = require('../events.js');
const misc = require('../util/misc.js');
const views = require('../util/views.js');
const TagInputControl = require('./tag_input_control.js');
const FileDropperControl = require('../controls/file_dropper_control.js');
const template = views.getTemplate('post-edit-sidebar');
@ -14,6 +15,7 @@ class PostEditSidebarControl extends events.EventTarget {
this._hostNode = hostNode;
this._post = post;
this._postContentControl = postContentControl;
this._newPostContent = null;
views.replaceContent(this._hostNode, template({
post: this._post,
@ -37,6 +39,24 @@ class PostEditSidebarControl extends events.EventTarget {
if (this._tagInputNode) {
this._tagControl = new TagInputControl(this._tagInputNode);
}
if (this._contentInputNode) {
this._contentFileDropper = new FileDropperControl(
this._contentInputNode,
{
lock: true,
resolve: files => {
this._newPostContent = files[0];
},
});
}
this._post.addEventListener(
'changeContent', e => this._evtPostContentChange(e));
}
_evtPostContentChange(e) {
this._contentFileDropper.reset();
}
_evtSubmit(e) {
@ -62,6 +82,10 @@ class PostEditSidebarControl extends events.EventTarget {
relations: this._relationsInputNode ?
misc.splitByWhitespace(this._relationsInputNode.value) :
undefined,
content: this._newPostContent ?
this._newPostContent :
undefined,
},
}));
}
@ -89,6 +113,10 @@ class PostEditSidebarControl extends events.EventTarget {
get _relationsInputNode() {
return this._formNode.querySelector('.relations input');
}
get _contentInputNode() {
return this._formNode.querySelector('.post-content .dropper-container');
}
};
module.exports = PostEditSidebarControl;

View file

@ -24,6 +24,7 @@ class Post extends events.EventTarget {
get canvasWidth() { return this._canvasWidth || 800; }
get canvasHeight() { return this._canvasHeight || 450; }
get fileSize() { return this._fileSize || 0; }
get content() { throw 'Invalid operation'; }
get flags() { return this._flags; }
get tags() { return this._tags; }
@ -40,6 +41,7 @@ class Post extends events.EventTarget {
set tags(value) { this._tags = value; }
set safety(value) { this._safety = value; }
set relations(value) { this._relations = value; }
set content(value) { this._content = value; }
static fromResponse(response) {
const ret = new Post();
@ -78,6 +80,7 @@ class Post extends events.EventTarget {
}
save() {
const files = [];
const detail = {};
// send only changed fields to avoid user privilege violation
@ -93,15 +96,22 @@ class Post extends events.EventTarget {
if (misc.arraysDiffer(this._relations, this._orig._relations)) {
detail.relations = this._relations;
}
if (this._content) {
files.content = this._content;
}
let promise = this._id ?
api.put('/post/' + this._id, detail) :
api.post('/posts', detail);
api.put('/post/' + this._id, detail, files) :
api.post('/posts', detail, files);
return promise.then(response => {
this._updateFromResponse(response);
this.dispatchEvent(
new CustomEvent('change', {detail: {post: this}}));
if (this._content) {
this.dispatchEvent(
new CustomEvent('changeContent', {detail: {post: this}}));
}
return Promise.resolve();
}, response => {
return Promise.reject(response.description);
@ -177,6 +187,13 @@ class Post extends events.EventTarget {
});
}
mutateContentUrl() {
this._contentUrl =
this._orig._contentUrl +
'?bypass-cache=' +
Math.round(Math.random()*1000);
}
_updateFromResponse(response) {
const map = {
_id: response.id,