Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next steps for sharejs #71

Open
2 of 3 tasks
DavidSichau opened this issue Apr 26, 2016 · 7 comments
Open
2 of 3 tasks

Next steps for sharejs #71

DavidSichau opened this issue Apr 26, 2016 · 7 comments

Comments

@DavidSichau
Copy link
Collaborator

DavidSichau commented Apr 26, 2016

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

  • Rewrite the code in ecmascript 2015
  • 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.

@x5engine
Copy link

x5engine commented May 1, 2016

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

Thanks bro <3

@mizzao
Copy link
Owner

mizzao commented May 1, 2016

You may also want to check out a rather long discussion we had about supporting rich text editing over at josephg/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
Copy link

@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
Copy link
Owner

mizzao commented May 9, 2016

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
Copy link
Collaborator Author

@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
Copy link

vincentracine commented May 9, 2016

@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
Copy link
Collaborator Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants