Случайно накосячили в документе, который вам только что пошарили? Драг-н-дропнули куда-то кусок чужого текста и не знаете, как жить дальше? Угодили курсором в ячейку вашего коллеги и уничтожили его данные? Ctrl+Z не раз спасало наши жизни и репутации добропорядочных коллег, не портящих чужие (и свои) документы.
В последнем выпуске мы добавили возможность сделать Undo в быстром совместном редактировании. Почему его не было раньше, как там всё устроено, и почему случается так, что вы жмете undo до упора, а документ всё равно не остается пустым, вы узнаете из этой статьи.
Undo в быстром режиме совместного редактирования появилось у нас вместе со сносками в версии 4.3. Больше о релизе вы можете узнать из нашей прошлой статьи (из этой статьи вы узнаете только об undo).
Быстрый, строгий, злой
Короткая справка о том, чем вообще отличаются режимы коэдитинга:
- Быстрый. Вы видите, что печатает ваш соавтор. («Что за чепуху ты печатаешь, Николай?!»)
- Строгий. Вы спокойно работаете над своим куском текста, а правки соавтора видите только после сохранения. («Что за чепуху ты напечатал, Геннадий?!»)
Быстрый режим совместного редактирования включен в редакторах ONLYOFFICE по умолчанию. Раньше в нём не было undo.
Почему раньше в быстром режиме не было undo
Мы думали, что это опасно для документа. Допустим, Николай вставляет автофигуру, а Геннадий перетаскивает в нее часть текста из документа. Затем Николай отменяет действие, в результате чего удаляется автофигура. А с ней и часть текста, которую уже никак не вернуть. Геннадий и Николай грустно идут пить чай, обсуждая, как восстановить утраченный текст.
Тем не менее, мы пришли к выводу, что даже в быстром режиме возможность отменить последнее действие нужна. Это просто удобно. Например, в ситуации, описанной в начале этого текста, когда вы, выделяя текст для более внимательного чтения, случайно перетащили его мышкой, а в это время документ редактировал кто-то еще. Или даже не редактировал, а просто забыл закрыть его. Или это вы сами забыли закрыть этот же документ в соседней вкладке. В общем, нужна возможно автоматически откатить последнее действие.
К undo, конечно же, нужно относиться осторожно (но на самом деле, вы рискуете уже просто когда шарите на кого-то документ с возможностью редактирования). Но мы расскажем вам, как всё устроено, чтобы минимизировать риски.
Google и мы
Нас постоянно спрашивают (на самом деле, спрашивают): Вы сделали это как у Google Docs? Нет.
Да, у них есть совместное редактирование и возможность сделать undo, и у нас эти вещи тоже есть. Но это не значит, что у нас внутри всё одинаково.
Как у Google. Документ находится на сервере, туда же отправляются все правки, там же собирается финальная версия документа. Например: Николай выделил какое-то слово жирненьким, а Геннадий курсивом. Оба два отправляют свои изменения на сервер, который уже разруливает этот конфуз: в частности, сообщает Николаю добавить курсив, а Геннадию сделать свой курсив жирным. В такой схеме ситуация, в которой один и тот же документ выглядит на разных клиентах по-разному, возможна (на очень короткий промежуток времени, конечно же).
Как у ONLYOFFICE. Если у Google ядро документа редактируется на сервере, то у нас всё это происходит на каждом клиенте. Сервер используется как база данных, в которой хранятся изменения. Как в такой схеме должны лечь изменения в ситуации, когда Николай выделил какое-то слово жирненьким, а Геннадий курсивом? Изменения лягут последовательно, при чем последовательность будет одна и та же на каждом клиенте. Ситуация, в которых у Николая и Геннадия документы выглядят по-разному в какой-то момент времени, невозможна.
Как это вообще связано с undo, спросите вы (на самом деле, мы понятия не имеем, спросите вы или нет, но представим как будто вы спросили). Из следующего пункта нашей истории вы поймете как.
Что происходит, когда вы нажимаете Ctrl+Z
Как мы уже сказали, в ONLYOFFICE все самые важные вещи происходят непосредственно на клиенте. Там же хранится список действий — не только своих, но и чужих. Свои собственные действия помечаются, чтобы потом была возможность их откатить.
И вот тут-то мы переходим к тому, как на самом деле происходит undo. Когда человек редактирует документ в одиночестве всё, в принципе, понятно. В блоке изменений хранятся действия одного человека и в случае необходимости мы просто берем последнее действие и производим антидействие. Блок действий при этом сокращается на единицу.
В совместном редактировании схема сложнее просто потому, что в списке изменений хранятся действия нескольких человек.
Рассмотрим простой пример. В документе содержится такой текст:
абв
Николай добавил в конце букву д и получил текст:
абвд
Увидев результат, Николай передумал и захотел отменить ввод буквы д. В это же время придирчивый Геннадий удалил букву б и в документе остался такой текст:
авд
Николай нажимает undo. Удаление и добавление текста происходит по позициям. Своим первым действием Николай добавил букву в позицию 3. В обычном редактировании undo сработало бы просто как удаление буквы из третьей позиции. Но ведь Геннадий уже постарался и удалил букву б из позиции 2 и буква д переместилась на её место. Таким образом в третьей позиции теперь просто пусто и удалять оттуда ну совсем нечего.
Это означает, что простая схема не прокатывает и перед тем, как отменить действия Николая, нужно их перегнать в самый конец блока, так как будто бы они были последними (после всех чужих действий).
Если перенести действие Николая по добавлению буквы д в самый конец блока, то есть после того, как Геннадий злодейски удалил букву б из второй позиции, то получится, что Николай добавил букву Д в позицию 2. Делаем обратное действие — удаление из позиции 2. Undo проходит.
Таким образом основной принцип таков: мы берем пачку действий клиента, который хочет сделать undo, коммутируем их (перестанавливаем через чужие действия по определенным правилам) и формируем новый блок обратных действий, как в обычном undo.
У клиента Николая, сделавшего undo, применяется антидействие, а всем остальным рассылается просто пачка его действий, то есть для них нет никакой разницы сделал он undo или просто удалил букву руками.
Ещё с undo, конечно, разные интересные проблемы, например
Неоткатываемые действия
Еще один простой пример:
1. Николай добавляет текст 12.
2. Геннадий удаляет 2.
3. Николай делает undo 2 раза.
4. Геннадий делает undo.
Итак, оба пользователя откатили все свои действия и у обоих не осталось ни одного undo в рукаве. Однако изначально пустой документ после отмены всех совершенных в нём действий пустым не остался. В нём гордо красуется цифра 2. Откатить её с помощью undo невозможно.
Исчезающие элементы
Рассмотрим ещё раз случай произошедший с Геннадием и Никлаем в начале статьи:
1. Николай добавляет автофигуру.
2. Геннадий набирает текст в автофигуре.
3. Нестабильный Николай делает undo автофигуры.
4. Вместе с автофигурой пропадает и текст, набранный Геннадием внутри неё. Окончательно.
Любая проблема с undo в быстром совместном редактировании объясняется тем, что последовательность реальных действий в документе и последовательность, в которой нажимается undo, не совпадают.
Это не недостатки нашей реализации undo. Оно работает правильно. Оно будет идеальным, если вы с коллегами будете одновременно работать над разными объектами. И вот вам наше напутственное слово: будьте, как это сейчас модно говорить, mindful, работая с документами. Переключайтесь между режимами совместного редактирования и используйте undo с умом.
Автор: xkorolx