mizzao / meteor-sharejs

Meteor smart package for transparently adding ShareJS editors to an app
MIT License
225 stars 53 forks source link

Next steps for sharejs #71

Open DavidSichau opened 8 years ago

DavidSichau commented 8 years ago

I think to prepare sharejs for the future we need to focus on these points.

The main reason is, that I never really liked coffeescript. It will also help users with no coffeescript experience to faster dig into the code.

NPM Packages

The current importing of ace and code mirror works, but with the introduction of npm packages in meteor 1.3 this seems to be a better suitable approach.

React Components.

As React gained some serious focus in the meteor community this should be supported.

x5engine commented 8 years ago

React is so much easier and faster than blaze just DO IT :)

Thanks bro <3

mizzao commented 8 years ago

You may also want to check out a rather long discussion we had about supporting rich text editing over at share/ShareJS#1.

Regarding "just do it" with react: I think this is easier said than done, although I agree that having both Blaze and React components would be potentially useful.

vincentracine commented 8 years ago

@mizzao I'm currently working on a project which required me to use React instead of Blaze and things work perfectly. If you need my help, please let me know!

mizzao commented 8 years ago

Hi @vincentracine - @DavidSichau is doing most of the work on this package now, so I'm sure he'll be interested. Do you have some example code available somewhere or posted in a gist (other than what you pasted in that other issue?)

DavidSichau commented 8 years ago

@vincentracine It would be nice if you could share some code with me.

I am currently working on the transition to npm packages. As soon as I finish this I will focus on react.

vincentracine commented 8 years ago

@DavidSichau @mizzao Here you go guys. The code works but for some reason right now setting the mode or theme throws an error and so I raised a new issue but this should work.

// AceEditor.js
export default AceEditor = React.createClass({

    getInitialState(){
        return {
            doc: null,
            editor: null
        }
    },

    componentDidMount(){
        // Get Ace Editor from DOM
        this.setState({
            editor: ace.edit("editor")
        });

        // Set Ace Editor behaviour
        //this.setTheme('ace/theme/chrome');
        //this.state.editor.getSession().setMode("ace/mode/python");
        this.state.editor.setFontSize(14);
        this.state.editor.setShowPrintMargin(false);
        this.state.editor.getSession().setUseWrapMode(true);
        this.state.editor.$blockScrolling = Infinity;
        this.state.editor.resize();

        this.onChange();
    },

    shouldComponentUpdate(nextProps, nextState) {
        return nextProps.docid !== this.props.docid;
    },

    componentDidUpdate(){
        this.onChange();
    },

    componentWillUnmount(){

        // Disconnect from ShareJS
        this.disconnect();

        // Clean up Ace memory to avoid memory leaks
        this.state.editor.destroy();

    },

    // ------- ShareJS

    onChange(){

        // Doesn't have a document opened but wants to connect
        if(!this.isConnected() && this.props.docid){
            this.connect(this.props.docid);
        }

        // Has a document opened but wants to open a new document
        if(this.isConnected() && this.props.docid){
            this.disconnect();
            this.connect(this.props.docid);
        }

        // Has a document opened but wants to close it
        if(this.isConnected() && !this.props.docid){
            this.disconnect();
        }

    },
    connect(documentId){
        let self = this;

        if(this.isConnected()){
            throw new Error('Already connected to ShareJS');
        }

        // Open the document
        sharejs.open(documentId, 'text', function(error, doc){
            if(error) {
                console.error("Connection error:", error);
            }else{
                // Update state
                self.setState({ doc: doc });

                // Check we are connected
                if(self.isConnected()){
                    // Attach ace editor to document
                    doc.attach_ace(self.state.editor);
                    console.log('Opened document [',documentId,']');
                }else{
                    console.error("Document was opened but closed right away");
                }
            }
        });
    },
    disconnect(){
        if(this.isConnected()){
            let name = this.state.doc.name;
            this.state.doc.close();
            if(this.state.doc.state === 'closed'){
                console.log('Closed document [',name,']');
            }else{
                console.error('Failed to close document [',name,']');
            }
            this.state.doc.detach_ace();
        }
    },
    isConnected(){
        return this.state.doc != null && this.state.doc.state === 'open';
    },

    // ------- End of ShareJS

    // ------- Editor State

    setTheme(theme){
        this.state.editor.setTheme(theme);
    },
    getAceInstance(){
        return this.state.editor;
    },
    getText(){
        return this.state.editor ? this.state.editor.getValue() : null;
    },

    // ------- End of Editor State

    render() {
        return (
            <div id='editor' ref="editor" data-doc={this.props.docid} className="shareJSAce"></div>
        )
    }
});

And you can use it like this:

EditorPage = React.createClass({

    mixins: [ReactMeteorData],

    getMeteorData() {
        return {
            currentUser: Meteor.user(),
            document: Documents.findOne({_id: this.props.docId})
        }
    },

    ready(){
        return this.data.document;
    },

    render(){
        return (
            <Row class="container-fluid">
                <div className="col-xs-12">
                                        <h3 className="file-name">{this.ready() ? this.data.document.title : 'Loading...'}</h3>
                    {this.ready() ? (
                        <AceEditor ref="editor" docid={this.props.docId}/>
                    ) : null}
                </div>
            </Row>
        )
    }
});
DavidSichau commented 8 years ago

@vincentracine Sorry for the long delay. I will take a look at this. I think the best would be to distribute it as an individual package. Something like sharejs-ace-react.

I will first merge my other pull request and than have a look at your code.