client/posts: add post content editing
This commit is contained in:
parent
6635b507f2
commit
3d8eaab57a
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue