meteor-sharejs icon indicating copy to clipboard operation
meteor-sharejs copied to clipboard

Next steps for sharejs

Open DavidSichau opened this issue 8 years ago • 7 comments

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

  • [x] Rewrite the code in ecmascript 2015
  • [x] Use npm packages for code mirror and ace
  • [ ] Add React components for the editor

emascript 2015

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.

DavidSichau avatar Apr 26 '16 14:04 DavidSichau

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

Thanks bro <3

x5engine avatar May 01 '16 22:05 x5engine

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.

mizzao avatar May 01 '16 23:05 mizzao

@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!

vincentracine avatar May 09 '16 13:05 vincentracine

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?)

mizzao avatar May 09 '16 15:05 mizzao

@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.

DavidSichau avatar May 09 '16 16:05 DavidSichau

@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>
        )
    }
});

vincentracine avatar May 09 '16 19:05 vincentracine

@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.

DavidSichau avatar Jul 05 '16 19:07 DavidSichau