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> </section>
<% } %> <% } %>
<% if (ctx.canEditPostContent) { %>
<section class='post-content'>
<label>Content</label>
<div class='dropper-container'></div>
</section>
<% } %>
</div> </div>
<div class='messages'></div> <div class='messages'></div>

View File

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

View File

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

View File

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

View File

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

View File

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