ONLYOFFICE. Голая правда об исходном коде облачного офиса


    В начале июля Teamlab переименовался в ONLYOFFICE и полностью открыл исходный код своего приложения, включая онлайн редакторы документов, совместное редактирование, диаграмму Ганта и функционал выставления счетов.
    За две недели мы получили массу вопросов на эту тему, поэтому на правах сотрудника компании возьмусь разъяснить, что к чему. Если у вас нет времени читать пост, просто скачайте инсталляцию ONLYOFFICE с Sourceforge. Разверните на своем сервере. Готово! У вас есть свой облачный офис. Вы великолепны.

    Почему Teamlab стал ONLYOFFICE

    Идея ребрендинга существовала довольно давно. В своем блоге мы написали целый пост о том, почему мы выбрали ONLY в качестве новой приставки к своему офису, однако, были и вполне конкретные причины. Во-первых, название Teamlab перестало отражать идею продукта, ведь «team» ассоциируется с небольшой командой, в то время как среди наших клиентов все чаще появляются компании по 300 и 400 человек. Во-вторых, помимо нас, к сожалению, это слово облюбовали дизайнеры интерактивных вешалок из Японии.

    Почему мы открыли исходный код (Honesty is the best policy потому что)

    Основная причина — это, безусловно, доверие. Не только со стороны клиентов, но и со стороны наших партнеров. В сегодняшней ситуации мы получаем довольно много вопросов о безопасности хранения корпоративных данных, особенно от зарубежных клиентов. Публикуя код ONLYOFFICE на Sourceforge и GitHub, мы делаем еще один шаг им навстречу.

    Выбор лицензии

    Публикуя исходные коды своего продукта, мы преследовали несколько целей:
    • Привлечь внимание opensource сообщества.
    • Закрепить авторство продукта.
    • Усилить доверие зарубежных клиентов и партнеров.

    Взвесив все за и против, мы выбрали AGPL v3. В двух словах она означает следующее: вы можете использовать ONLYOFFICE в своей компании бесплатно и без ограничений, но если хотите встроить наш код в собственное приложение, вам придется открыть исходные коды своего продукта под той же лицензией. Подробнее здесь.

    Что говорят наши программисты

    Переходим к самой интересной части нашего поста. Open Source версия ONLYOFFICE готовилась к выпуску довольно долго — один только текстовый редактор содержит более 500 000 строк кода! Конечно же, нам есть, о чем рассказать:

    Особое внимание к Internet Explorer
    Основа алгоритма растеризации взята из freetype, так как это качественный, проверенный временем открытый шрифтовый движок. Сами алгоритмы немного изменили, чтобы скорость выполнения была выше именно в браузере, поскольку мы пишем на javascript.

    А вот, например, кэш букв нам пришлось писать в двух вариантах: для Internet Explorer и для всех остальных. Из-за специфики браузера в IE первая реализация была медленной.
    Олег, ведущий программист

    Что вы знаете о ширине столбцов в Excel?
    Существует два основных сценария использования Excel:
    • финансовые расчёты,
    • создание бланков (счетов) для дальнейшего заполнения и распечатки.

    Большое количество бланков были созданы еще до появления нашего редактора таблиц, поэтому нашей задачей было не только научиться правильно их открывать, но и корректно рассчитывать ширины столбцов и высоты строк. В противном случае при печати бланк мог бы не убраться на лист.
    Например, стандартная ширина столбца в Microsoft Excel — 8.43 символа (characters). Она рассчитывается из ширины по умолчанию в 8 символов, которая переводится в пиксели в зависимости от стиля Normal. Затем, как оказалось, полученное число округляется до ближайшего кратного 8-ми.
    Еще одна особенность — это высота строки. В Excel нельзя задать межстрочный интервал, как, например, в Word, поэтому расчет высоты строки в Excel отличается от расчета высоты строки в Word. Вот, например, сравнение в шрифте Cambria Math 11:

    В итоге мы реализовали расчёт так, чтобы ни один символ не оказался обрезанным.
    Александр, ведущий программист

    Как мы связали дерево зависимостей и топологическую сортировку
    Большая часть электронных таблиц так или иначе содержит в себе формулы. Для решения задач разбора и подсчета формул было реализованы парсер и калькулятор. Также в работе с формулами особого внимания заслуживает построение зависимостей между ячейками. Для этой цели был использован алгоритм топологической сортировки, позволяющий строить порядок обхода дерева зависимостей.
    Дмитрий, программист

    Пятнадцать тысяч тестов и 80 машин
    Чтобы протестировать инсталляцию ONLYOFFICE, мы развернули её у себя и запустили уже привычный процесс. В сумме набежало порядка 15000 тестов, которые запускаются на 80 машинах. Кстати, хостим мы их теперь на Digital Ocean и в ближайшее время расскажем о том, как перенесли туда всю тестовую структуру.
    Стас, руководитель отдела тестирования

    Hopes&Fears
    Боимся ли мы того, что наш код кто-то позаимствует в корыстных целях? Нет. Использование кода ONLYOFFICE четко прописано в лицензии, и здесь мы защищены международным правом.
    Не думаем ли мы, что кто-то «подсмотрит» и сделает аналогичный продукт? Конечно, думаем. Но на это у ребят уйдет не менее 3 лет, так что мы не вот уж сильно переживаем. Впрочем, мы давно уже привыкли находиться и выживать в высококонкурентной среде.
    Александра, руководитель отдела продвижения

    Что вам стоит свой редактор на канве построить?
    Любой текстовый редактор начинается с разбивки текста на строки и отрисовки. Первый рабочий вариант состоял из 150 строк кода и был реализован следующим образом:

    // Класс ParaText
    function ParaText(value)
    {
        this.Value = value;
        this.Type  = para_Text;
     
        this.Width  = 0;
        this.Height = 0;
    }
    
    ParaText.prototype.Draw = function(X, Y, Context);
    ParaText.prototype.Measure = function(Context);
     

    Еще 140 строк кода
    // Класс ParaSpace
    function ParaSpace()
    {
        this.Type = para_Space;
     
        this.Width  = 0;
        this.Height = 0;
    }
     
    ParaSpace.prototype.Draw = function(X,Y, Context);
    ParaSpace.prototype.Measure = function(Context);
     
     
    // Класс ParaNewLineRendered
    function ParaNewLineRendered()
    {
        this.Type = para_NewLineRendered;
        this.Width  = 0;
        this.Height = 0;
    }
     
    ParaNewLineRendered.prototype.Draw = function();
    ParaNewLineRendered.prototype.Measure = function();
     
    // Класс Paragraph
    function CParagraph()
    {
        //...................
     
        // Начальный сдвиг
        this.X = 0;
        this.Y = 0;
     
        // Ширина строки 
        this.XLimit = 0;
     
        // Содержимое параграфа, состоящее из объектов типа ParaText, ParaSpace и ParaNewLineRendered
        this.Content = new Array();
     
        // Высота строки. Пусть у нас она будет одинаковая для всех строк
        this.dLineHeight = 0;
        //...................	
    }
     
    CParagraph.prototype.Recalculate = function()
    {        
        // Подготовка к новому пересчету. Здесь мы удаляем старые элементы ParaNewLineRendered
        //..............................
     
        // Смещаемся в начало параграфа
        var X = this.X, Y = this.Y;
     
        // Рассчитываем параграф   
        var CurLine = 0;
     
        var bNewLine         = false;
        var bFirstItemOnLine = true;
        var bWord            = false;
        var nWordStartPos    = 0;
        var dWordLen         = 0;
     
        for ( var nPos = 0; nPos < this.Content.length; nPos++ )
        {
            var Item = this.Content[nPos];
     
            switch( Item.Type )
            {
                case para_Text:
                {
                    var dLetterLen = Item.Measure( Context ).Width;
     
                    if ( !bWord )
                    {
                        // Если слово только началось, и до него на строке ничего не было, тогда не надо проверять убирается ли оно на строке.					
                        if ( !bFirstItemOnLine )
                        {
                            if ( X + dLetterLen > this.XLimit )
                            {
                                // Уже первая буква в слове не убралась в строке - ставим перенос строки
                                this.Content.splice( nPos, 0, new ParaNewLineRendered() );
                                bNewLine = true;
                            }
                        }
     
                        if ( !bNewLine )
                        {
                            nWordStartPos = nPos;
                            dWordLen      = dLetterLen;
                            bWord         = true;
                        }
                    }
                    else
                    {
                        if ( X + dWordLen + dLetterLen > this.XLimit )
                        {
                            if ( bFirstItemOnLine )
                            {
                                // Слово оказалось единственным элементом строки и все равно
                                // не умещается целиком. Ставим перенос строки на текущей позиции.
                                X += dWordLen;
                                this.Content.splice( nPos, 0, new ParaNewLineRendered() );
     
                                bNewLine = true;
                            }
                            else
                            {
                                // Смещаемся к началу слова и перед ним ставим перенос строки
                                this.Content.splice( nWordStartPos, 0, new ParaNewLineRendered() );
                                nPos = nWordStartPos;
     
                                bNewLine = true;
                            }
                        }
     
                        if ( !bNewLine )
                        {
                            dWordLen += dLetterLen;
                        }
                    }
                    break;
                }
                case para_Space:
                {
                    bFirstItemOnLine = false;
                    
                    var dSpaceLen = Item.Measure( Canvas ).Width;
                    if ( bWord )
                    {
                        // Не надо проверять, убирается ли слово - мы это проверяем при добавлении букв
                        X += dWordLen;
     
                        bWord    = false;
                        dWordLen = 0;
                    }
     
                    if ( X + dSpaceLen > this.XLimit )
                    {
                        bNewLine = true;
                    }
                    else
                        X += dSpaceLen;
                    
                    break;
                }
            }
     
            // Переходим на новую строку
            if ( bNewLine )
            {
                bNewLine         = false;
                bFirstItemOnLine = true;
                bWord            = false;
                dWordLen         = 0;
     
                // По горизонтали смещаемся в начало параграфа, а по вертикали смещаемся вниз на высоту строки
                X = this.X;
                Y += this.dLineHeight;
     
                CurLine++;
            }
        }
    }
     
    CParagraph.prototype.Draw = function(Context)
    {
        var Y = this.Y;
        var X = this.X;
     
        var nCount = this.Content.length;
        for ( var nPos = 0; nPos < nCount; nPos++ )
        {
            var Item = this.Content[nPos];
            
            Item.Draw( X, Y, Context );
     
            X += Item.Width;
            
            if ( para_NewLineRendered == Item.Type )
            {
                Y += this.dLineHeight;
                X = this.X;
            }
        }
    }
    


    Илья, ведущий программист

    Через две недели после начала разработки был готов первый тестовый пример:


    Скачать и протестировать пример можно здесь.
    Нет ничего приятнее, чем сравнивать его с тем, чего мы достигли за несколько лет. И с тем, на каком этапе находятся сейчас редакторы конкурентов.


    Протестировать все редакторы можно без регистрации на сайте personal.teamlab.com. Им, кстати, вообще можно активно пользоваться — он бесплатный.

    Наша цель? Пользователи ONLYOFFICE по всему миру

    Планов у нас действительно много. Уже сейчас мы активно работаем над мобильными и десктопными приложениями, помимо этого к осени выйдет версия офисных редакторов 3.0, а еще мы подумываем над тем, чтобы коммитить разработку на GitHub в режиме реального времени.

    Кажется, все. Перемещаем обсуждение в комментарии)
    Метки:
    Поделиться публикацией
    Комментарии 35
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        Вам придется открыть код подключения :)
        • +4
          А еще лучше к pydio ;)
        • 0
          Неплохо, выглядит серьезно. Правда мою тестовую вордовую доку с табличками открыло совсем не так как её открывает даже wordpad. Могу дать ссылку если интересно
          • 0
            Да, конечно. Будем признательны
            • +5
              Спасибо. Действительно в текущей версии документ открывается не совсем корректно. Однако в упомянутой версии 3.0 файл открывается точь-в-точь как в MS Word. Поскольку версия не опубликована, пока только скриншот.

              image
              • 0
                Не сразу понял, что иконка между андерлайном и надстрочным текстом означает «перечёрнутый текст». Первая ассоциация — иероглиф :)

                Возможно, стоит зачёркнутое S (т.е. S) использовать вместо Т?
                • 0
                  передал дизайнерам)
                  • НЛО прилетело и опубликовало эту надпись здесь
              • НЛО прилетело и опубликовало эту надпись здесь
                • +3
                  Обалдеть, это просто космически круто.
                  Я конечно первым делом стал думать — как frontend части интегрировать с Rails или какими-то еще фреймворками.

                  • НЛО прилетело и опубликовало эту надпись здесь
                    • 0
                      в будущем все должно быть очень хорошо ;)
                      • 0
                        С этого места можно поподробней?
                        • НЛО прилетело и опубликовало эту надпись здесь
                    • +3
                      Являюсь разработчиком приложения по конвертации docx->pdf. Знаю, на сколько docx «хорош». Импортировал в ваш редактор несколько файлов, результаты не плохие. Хочу пожелать вам удачи в этом не легком деле. Молодцы!
                      • +5
                        Очень огорчило, что для развертывания сервера необходима windows-платформа…
                        • +1
                          Выше был дан ответ. Работаем над другими платформами, нужно время.
                          • НЛО прилетело и опубликовало эту надпись здесь
                        • +3
                          Шикарное приложение. Продолжайте в том же духе!
                          • 0
                            Подскажите как в демке загрузить свой файл для редактирования.
                            • 0
                              нужно войти через аккаунт google или facebook
                            • +1
                              Пользуюсь как сервисом, но открытость кода была одним из важных факторов выбора именно teamlab (начал еще до переименования).
                              Установочные файлы хранятся локально, архивы скачиваются еженедельно и если по какой-то причине пропадет доступ к сервису — данные всё равно останутся и с ними можно продолжать работать как обычно.

                              Тестовая миграция из облака в локальную версию прошла успешно.
                              • +1
                                Пользуемся серверной версией TeamLab c 2011 года (IT-компания, 20 человек). За время работы объем данных составил > 50 Гб. Грузим в него все, начиная от печатных версий договоров с заказчиками и заканчивая фотографиями с коропоративов. Очень довольны. Недавно поставили последнюю версию. Порадовала диаграмма Ганта и новое оформление. Однако, нам так и не удалось настроить отправку подтверждения регистрации пользователей на электронную почту.
                                • НЛО прилетело и опубликовало эту надпись здесь
                                  • +1
                                    Здравствуйте! Опишите нам пожалуйста детальный сценарий на support@onlyoffice.com — мы вышлем вам инструкцию для решения проблемы.
                                • 0
                                  а есть у вас в планах какой-нибудь скриптовый язык для автоматизации? А-ля Google Apps Script — штука в умелых руках весьма мощная и полезная.
                                  • 0
                                    Нет, пока не планируем
                                  • 0
                                    Мои поздравления, не смотря на то, что меня как пользователя расстраивает ваше сосредоточение на онлайн-редакторе документов, а не на ином функционале (нормальном Ганте, к примеру).
                                    • +1
                                      Плюсану. Очень хочется видеть подвижки в CRM, а то счета сделали круто, но явно не доделали до конца))) Прям каждый день захожу в надежде увидеть новые настройки… Может там, с 1С синхронизация..))))
                                    • 0
                                      После предыдущей статьи о вас тут просто взял и попробовал написать текст по работе в вашем редакторе. Не вышло, по середине процесса переключился на гуглдокс. Были проблемы с навигацей по тексту (активное использование клавиатуры с shift, ctrl, alt), еще какие-то мелочи, которые в совокупности блокировали мою работу. Писал об этом где-то, кажется у вас в обратной связи или типа того чем-то… Не знаю, пофиксили или нет, надо будет попробовать еще раз в новой версии.
                                      • 0
                                        Пока активно использую ГуглоДокс.
                                        Очередной раз посмотрел на ваш продукт — видны значительные подвижки. И скорость работы выросла, что радует.

                                        Однако первое на что наткнулся и чего не хватает (в Ворд) — это вставка изображения из буфера обмена, как в ГуглоДокс (по Ctrl-V).
                                        • 0
                                          в 3ей версии редактора это работает, правда пока она находится в тестировании :)
                                        • 0
                                          Еще такая мелочь — когда открыто несколько вкладок с документами (при активном использовании вкладок) то в заголовке остается только значок, и не понятно какая к вкладка к какому документу относится:



                                          Я бы делал разделение по типам документов, например так:

                                          • 0
                                            передал пожелания нашим дизайнерам

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.