【问题标题】:RealTime Collaborative Text-Editor in Nodejs & Socket.ioNodejs 和 Socket.io 中的实时协作文本编辑器
【发布时间】:2014-06-17 09:33:19
【问题描述】:

我正在开发一个具有类似于https://quip.com/ 的段落锁定属性的实时文本编辑器。在 socket.ionodejs 中。

这意味着当您在给定段落上写字时,其他合作者无法对其进行编辑。

当您按下回车键或将光标移动到新行时,该段落将变为 可编辑 以供其他协作者使用。

在这之后我很困惑。我正在考虑一个很好的方法来进一步前进。请提出建议。

下面是我的代码,它运行良好。到目前为止,我可以获取所有合作者的列表并将编辑器的内容广播给其他合作者。

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Connected Clients</title>
    <!--<meta charset="UTF-8"> -->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> 
    <!--<script type="text/javascript" src="jquery.js"></script>  -->
    <script src="/socket.io/socket.io.js"></script>
</head>

<body>
    <textarea id="editor" style="height:200px;width:300px">
        Thinknest Pragraph locking Test sample !
    </textarea>

    <script>
    function msgReceived(msg){
        //clientCounter.html(msg.clients);
        document.getElementById('people').innerHTML=msg.uid;
        //console.log(msg.id);  
    }

    var clientCounter;  

    $(document).ready(function () {
        clientCounter = $("#client_count");
        var socket = io.connect(
                         'http://localhost:5000', 
                         {'sync disconnect on unload':true}
                     ); 
        var uId=prompt("enter your userId",'');
        socket.emit('collabrator',uId);

        socket.on('message', function(msg){
            msgReceived(msg);
        });

        socket.on('online_collabs',function(data){  
            $('#online_ppl').html(data);
            clientCounter.html(data.length);
        });

        socket.on('remained_collabs',function(data){
            $('#online_ppl').html(data);
            clientCounter.html(data.length);
        });

        socket.on('note_collabs',function(data){
            $('#note_colabs').html(data);
        });

        socket.on('updated_para',function(data){
            //$('#editor').append(data);
            document.getElementById('editor').innerHTML=data;
        });

        $('#editor').on('keydown',function(){
            //var para=$('#editor').value;
            var para= $('#editor').val();
            //var para=document.querySelector('[contenteditable]');
            // var text=para.textContent;
            socket.emit('para',{paragraph:para});
        });
    });  
    </script>

    <p><span id="client_count">0</span> connected clients</p><br/>
    <ul id="people"></ul>
    <h3>Online Collaborators</h3>
    <span id="online_ppl"></span> <br>
    <h3>Note Collaborators</h3>
    <span id="note_colabs"></span>
</body>
</html>

server.js

var app = require('express')()
  , server = require('http').createServer(app)
  , io = require('socket.io').listen(server);

server.listen(5000);

app.get('/',function(req,res){
    res.sendfile("./index.html");
});

var activeClients = 0;
var Collaborators=['Colab1','Colab2','Colab3'];
var people=[];

io.sockets.on('connection', function(socket){
    clientConnect(socket);

    socket.on('disconnect', function(){
        clientDisconnect(socket);
    });

    socket.on('para',function(data){
        //io.sockets.emit('updated_para',data.paragraph);
        socket.broadcast.emit('updated_para',data.paragraph);
    });
});

function clientConnect(socket){
    //activeClients +=1;
    var userSocketId=socket.id;
    check_Collaborator(socket);

    io.sockets.emit('message', {uid:userSocketId});
}

var online_collabs=[];

function check_Collaborator(socket){
    socket.on('collabrator',function(data){
        if(Collaborators.indexOf(data)!=-1){
            socket.data=data;

            if(online_collabs.indexOf(data)==-1) {
                online_collabs.push(data);
            }

            io.sockets.emit('online_collabs',online_collabs);
            io.sockets.emit('note_collabs',Collaborators);
        } else {
            console.log("collabrator not found");
        }
    });
}

function clientDisconnect(socket){
    var index=online_collabs.indexOf(socket.data)

    if(index>-1)
        online_collabs.splice(index,1);

    //activeClients -=1;
    //io.sockets.emit('message', {clients:activeClients});
    io.sockets.emit('remained_collabs',online_collabs);
}

【问题讨论】:

  • 这个项目是开源的吗?我很想看看它,因为我正在寻找这样的东西。
  • 有一种叫做操作转换的东西,它不需要锁,但需要相当深入的理解,这里有一个wiki链接:en.wikipedia.org/wiki/Operational_transformation

标签: node.js socket.io real-time paragraph collaborative-editing


【解决方案1】:

我昨天已经看到了。你的问题到底是什么?您想知道如何使用 javascript 来“锁定”文本区域吗?我很困惑为什么您在问题中如此强调 node/socket.io。

另外,下次请格式化您的代码。你需要帮助,我明白了,然后让其他人更容易帮助你。

我不知道你必须做什么才能使其他人无法编辑段落。但是让我建议我在 socket.io 中应该做什么:

单独存储每个段落并记住谁锁定了它。对于锁定,我会使用 sessionID 以防用户不必注册。这看起来像这样:

var paragraphs = {
    data : [
        {
            text: "this is an unlocked paragraph",
            lock: ""
        },
        {
            text: "this is a locked paragraph",
            lock: "oWEALlLx5E-VejicAAAC"
        }
    ]
}

现在,用户可能会被允许在现有段落之前添加一个段落。因此,您应该保留一个额外的索引,例如:

var paragraphs = {
    index : [
        1,
        0
    ],
    data : [
        {
            text: "this the second paragraph",
            lock: "oWEALlLx5E-VejicAAAC"
        },
        {
            text: "this is the first paragraph",
            lock: ""
        }
    ]
}

现在通过套接字发送的数据量应该非常小 - 尽管有额外的客户端/服务器端逻辑。

【讨论】:

  • 是的,会格式化。写的很匆忙。无论如何,你有没有使用 Quip。我想在我的应用程序中做同样的事情。如果其他人在您所在的同一行上写,那会非常忙碌,所以锁定对我来说很重要。
【解决方案2】:

可以通过在当前编辑的段落中添加一个类来轻松实现段落锁定。将此段落与班级一起转移给其他用户。这样,如果用户试图改写,就可以通过类验证来阻止他。

生成一个类名看起来像 - className_userid (className_1)。

【讨论】:

    猜你喜欢
    • 2015-05-27
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 2012-02-23
    • 1970-01-01
    相关资源
    最近更新 更多