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