Home Reference Source

application/components/common/rich-editor/media-resize.js

import React from 'react';
import LoadingIndicator from './../loading-indicator';
import {ResizableBox} from 'react-resizable';
import RaisedButton from 'material-ui/RaisedButton';
import BaseView from './../../base-view';

/**
 * MediaResize component handles the draggable
 * resizing of media blocks. This does not update media
 * block meta, but sends the data to a callback.
 */
class MediaResize extends BaseView {

    constructor(props) {
        super(props);
        this.displayName = 'MediaResize';

        this.handleResize = this.handleResize.bind(this);
        this.handleFinish = this.handleFinish.bind(this);

        this.state = {
            initialHeight: 0,
            initialWidth: 0,
            height: 0,
            width: 0
        };
    }

    /**
     * Set initial width and height if provided by properties
     */
    componentWillMount() {
        this.setState({
            'initialWidth': this.props.width ? this.props.width : 0,
            'initialHeight': this.props.height ? this.props.height : 0,
            'width': this.props.width ? this.props.width : 0,
            'height': this.props.height ? this.props.height : 0
        });
    }

    /**
     * Callback to set initial size if not set.
     *
     * @see render()
     */
    setSize() {
        const {height, width} = this.refs.container.getBoundingClientRect();        

        this.setState({
            initialHeight: height,
            initialWidth: width,
            height: height,
            width: width
        });
    }

    /**
     * Handle resize event. Updates the height and width.
     *
     * Also calls onResize prop if provided
     */
    handleResize(e, data) {
        const editorBox = this.refs.editorBox.getBoundingClientRect();
        const ratio = editorBox.width / data.size.width; 

        this.setState({
            height: data.size.height,
            width: data.size.width,
            editorWidth: editorBox.width,
            editorHeight: data.size.height * ratio
        });

        if (this.props.onResize) {
            this.props.onResize(data);
        }
    }
    
    handleFinish() {
        if (this.props.onFinish) {
            this.props.onFinish(this.state);
        }
    }

    render() {
        if (!this.props.content.size) {
            return <LoadingIndicator size="small" />
        }

        // If there is no initial width (i.e. it's null or 0) we inject the image into the component, get the size
        // THEN initialize the resizer. This is necessary because the resizer requires an initial height and width.
        if (!this.state.initialWidth) {
            return (
                <div ref='editorBox' style={{width:'95%'}}>
                    <LoadingIndicator size="small" />
                    <img ref='container' src={this.props.content.get('attachment').get('public_url')} style={{maxWidth: '100%'}} onLoad={this.setSize.bind(this)} />
                </div>
            );
        }

        const className = 'alignment-container ' + (this.props.align ? this.props.align : 'center');

        let maxResizeWidth = this.state.initialWidth + 5;
        let maxResizeHeight = this.state.initialHeight + 5;
        let minResizeWidth = 175;
        let minResizeHeight = this.state.initialHeight * (175/this.state.initialWidth);

        if (this.state.editorWidth) {
            maxResizeWidth = this.state.editorWidth;
        }
        if (this.state.editorHeight) {
            maxResizeHeight = this.state.editorHeight;
        }        

        return (
            <div ref='editorBox' style={{width:'95%', margin:'0 auto'}}>            
                <div className={className} style={{height: this.state.height, width: this.state.width}}>
                    <div className='alignment-inner' style={{height: this.state.height}}>
                        <div className='alignment-content' style={{height: this.state.height}}>
                            <div className='center-toolbar' style={{top: this.state.height/2}}>
                                <RaisedButton secondary={true} label='Done' onClick={this.handleFinish} />
                            </div>
                            <ResizableBox 
                                width={this.state.initialWidth} 
                                height={this.state.initialHeight} 
                                lockAspectRatio={true} 
                                onResize={this.handleResize}
                                minConstraints={[minResizeWidth, minResizeHeight]}
                                maxConstraints={[maxResizeWidth, maxResizeHeight]}
                                >
                                <img src={this.props.content.get('attachment').get('public_url')} style={{width: '100%'}} />
                            </ResizableBox>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

export default MediaResize;