Что я собираюсь рассказать в этой серии статей?
В моих же планах на эту серию статей - раскрыть вам некоторые, на мой взгляд, не самые очевидные аспекты написания макросов для офисного пакета «Р7-Офис» версии десктоп. Думаю, многое из мною здесь написанного вряд ли будет вами легко найдено в открытом доступе. Кое – что конечно имеется в «секретных Телеграмм чатах» (в которых я и сам много чего подчерпнул и даже считался там типа эксперта), но некоторые данные, не найдёте наверное даже там. Я надеюсь, изложенные в этих статьях мысли, будут стоить потраченных вами усилий на их чтение. Ну а если вам не интересны мои рассуждения на тему текущего положения дела с макросами и плагинами в редакторе «Р7» - смело пропускайте эту вводную статью и ждите следующих.
Пока мой план на статьи таков:
Введение в общие проблемы написания макросов в «Р7»(эта статья)
Мое собственное решение для построения сложных форм в макросах
Прочее (по результатам этих статей, будет зависить от вашего мнения)
Эта часть будет короткой, и не особо полезной именно в плане конкретных решений. Но я подумал и решил, что нужно на что то опереться, чтобы кинуться в этот омут, поэтому начну с неё.
Для чего я это пишу?
Ранее я уже обращался к проблемам автоматизации в отечественном офисном пакете «МойОфис», и опубликовал здесь ряд статей по отладке (и кстати, планирую ещё вернуться к нему, но позже). А теперь у меня накопился опыт по другому решению от отечественных разработчиков: офисному пакету «Р7», который до недавнего времени являлся просто форком опенсоурс редактора «OnlyOffice», только в «упаковке» для внутреннего рынка. Но с августа 2024 это увы, далеко не так, и их пути всё дальше расходятся. Но относительно общая база, всё ещё позволяет использовать исходники последнего, для понимания работы АПИ в «Р7».
За время работы, я столкнулся со многими проблемами, которые приходилось решать, и по каждой из них можно писать отдельные статьи. Но я решил для начала сосредоточится на той, которая многим покажется неочевидной и даже - неважной, а ведь по сути, она мало где освещена.
Чтобы понять, зачем вообще писать статьи на такие темы, я в этой вводной, хотел бы сперва просто сделать небольшой обзор по проблемам программирования макросов в «Р7», ибо пока не погрузишься в сам процесс, о многом просто наивно думаешь хорошо. Конечно, информация об разных аспектах автоматизации в «Р7»(и «OnlyOffice») уже давно описана. Есть официальные источники по АПИ. Есть разного рода курсы по написанию макросов и плагинов (к написанию некоторых из них я причастен непосредственно). Это все легко найти в интернете. Но но когда касаешься задачи в достаточно узком, и казалось бы - простом вопросе, как взаимодействие с пользователем в рамках макросов, то всё становится не столь уж и простым! Почему я так утверждаю, я и хотел бы изложить в этой статье, чтобы читатель мог понять, для чего ему читать следующие статьи этой серии.
Итак, моё краткое видение, что собой представляет сам «Р7» и его АПИ, с которым придется бороться.
Об мне
Я, Шумаков Виталий, программист с почти 30 летним стажем. По воле судьбы, занимаюсь последние годы различными задачами автоматизации тех или иных процессов. Кроме того, многие годы был на стороне внедрения программных продуктов, и хорошо знаю обе стороны этого процесса. Долгое время я занимался в основном VBA в CorelDraw, где стал относительно известным разработчиком, благодаря своим макросам по разработке чертежей для станков c ЧПУ. Но, потом случилось сами знаете что, и моя множественная клиентская база, была отрезана вместе с нашей банковской системой от возможностей финансовой поддержки моей работы. А внутри страны, увы, все не столь радужно ибо рынок этот достаточно специфичный. Так я и вернулся к вопросам автоматизации в сфере бизнес процессов. Так как в силу тех же обстоятельств, стало активно развиваться внедрение отечественного ПО, то решил обратить внимание именно в эту сторону. Достаточно активно поковырял «Мой офис», и написал несколько статей сюда, на Хабр, за что и получил «инвайт» прямо от администрации. Благодаря этим статьям, меня нашел один из здешних постоянных авторов, и пригласил меня поучаствовать в своем стартапе, как ведущего разработчика, но уже в другом офисном пакете отечественной разработки - в Р7. Мы сотрудничали некоторый период времени (два года), за которые я успел достаточно глубоко изучить разные аспекты работы с этим редактором (в основном табличной его части), в том числе и весьма глубоко скрытые от глаз обычного пользователя. Благо, что его исходный аналог OnlyOffice — до сих пор является open source и позволяет понять многие моменты в работе. По пути я из��чил „с нуля“ совсем не характерные для моих прежних интересов frontend разработку и язык JavaScript (но экспертом здесь я так и не стал, так что мои решения могут для опытных в этих вопросах программистов показаться дилетантскими, что так и есть!). Заодно узнал много нового для себя из мира BI, так как никогда не тяготел к этому направлению. Так же успел опробовать много разных способов решения задач связи между офисным редактором и внешним миром. Поучаствовал в проектах по переводу макросов из MS Office в Р7 для очень крупного заказчика и ощутил всю "боль" таких работ! Создал свой редактор для макросов в Р7 и разработал модульную систему для упрощения работы в его макросах. А так же, ещё много чего, о чем я рассказывать не буду из‑за контрактных обязательств. В силу определённых обстоятельств, я теперь снова „в свободном плаванье“, и бывшему работодателю желаю всяческих успехов, ибо продукты мы сделали классные! Надеюсь, у него всё получится далее и без моей помощи!
Но мой накопленный опыт и знания — они со мной, и продолжают „мучать“ мой пытливый мозг. Я продолжаю уже чисто самостоятельно свои поиски и предлагаю вам, ознакомится с некоторыми моими личными наработками!
Кратко про «Р7»
Офисный пакет «Р7», видимо исходя из реализации идей «мультиплатформенности», являет собой скомбинированное в одно целое, клиент-серверное web приложение. "Бэкэнд" часть написана на высокоуровневых языках C# и С++, с использование фреймфорка Qt (для десктоп и мобильных реш��ний) и отвечает за внутренние механизмы по работе с документом и рендеринг содержимого пользователю. А "фронтэнд" предоставляет собой пользовательский графический интерфейс и АПИ для автоматизации. Причем, запускается этот «комбайн» сразу как одно целое приложение, и вся «кухня» по взаимодействию этих двух частей скрыта от глаз пользователя.
Поскольку в работу бэкэнда мы вмешиваться не можем, то нам оставляют лишь возможность работать только на уровне фронэнда. Вот про это я и буду дальше говорить.
Что же такое « frontend» слой в «Р7»?
Наверное, для упрощения себе жизни (но не нам!), разработчики «OnlyOffice/Р7», решили построить графический интерфейс с пользователем, а заодно и АПИ любой автоматизации, на базе хорошо обкатанного и надежного web движка браузера Chromium. Думаю, особо представлять его нет смысла, ибо на его ядре крутится, наверное, где-то 80-90% всех веб-браузеров. Chromium, если верить статье на Википедии, сам по себе давно opensource (с 2008 года), и открыт под BCD лицензией. На его базе построено помимо браузеров, ещё и огромное число так называемых WebApp - приложений, которые чаще всего используют ядро для построения графического интерфейса, простого в разработке за счет использования языка разметки HTML в связке с каскадными таблицами стилей CSS и скриптовым языком JavaScript. По этому же принципу построена и видимая пользователям часть редактора «Р7». Но конечно же, всё не так просто! Разработчиками была проделана очень большая работа, для интеграции АПИ базового ядра редактора с кодом Chromium-а.
Написанное АПИ для вызовов из javascript весьма обширное и покрывает многие аспекты работы редакторов (пишу именно так, во множественном числе, потому что в бэкэнд ядре их несколько, как минимум три – текстовый, табличный и презентаций). Но открытая и документированная для пользователя часть, представляет собой значительно урезанную версию всего АПИ, которая оставляет «за скобками» очень многие потребности в работе! На момент написания статьи, к примеру, в табличном редакторе нет, официального АПИ доступа к сводным таблицам, к фильтрам ячеек,к некоторым аспектам форматирования и много ещё к чему. А те функции АПИ что открыты - зачастую имеют либо довольно много багов, либо скрытых «особенностей», которые мало того что никак не документированы, но и по сути чаще всего не признаются как баги. И в итоге, это всё, для программиста отдельная головная боль!
Ну и что же делать, если официального АПИ оказалось мало для решения задач, а решать их надо?
К счастью, для пытливого ума нет преград! Если перевести редактор с помощью ключа загрузки «-ascdesktop-support-debug-info» (он кстати сам по себе наследие использования Chromium) в режим с запуска с возможностью отладки, то контекстным меню, например на контролах или формах редактора, можно выводить привычный для многих пользователей браузеров DevTools:

А в нём уже(ура! ), можно получать, переведя редактор или плагин в останов, доступ к внутренним глобальным объектам самого редактора:

И это значит - есть возможность увидеть остальное javascript АПИ текущего редактора (хотя бОльшая часть из него обсфуркцированая и мало что даст), которое не описывается официально, и через которое можно получать доступ к управлению большинством официально скрытых объектов в модели данных документов!
Впрочем, тут есть огромное НО! Для 99% пользователей, это скорее пагубный путь, ибо любое малейшее неверное использование этого АПИ приводит в лучшем случае к краху документа! В худшем - к «падению» всего редактора, даже без возможности сохранить документ! Тем не менее, о малой части из этого скрытого АПИ, которая более-менее уже исследована и может использоваться сравнительно безопасно, я вам поведаю, так как для многих стоявших передо мной (думаю и не только передо мной) задач, просто не существует пока иного пути, кроме как использовать такие вот «костыли» в виде скрытых функций АПИ.
Сразу обозначу: у меня нет возможности и задачи расписывать все особенности и всё скрытое АПИ, которым можно пользоваться для целей автоматизации. Я и сам его не знаю в должной мере, ибо никогда не ставил себе такую цель - глубоко узнать все скрытые возможности. Да и тема у меня сейчас так же очень узкая. Скрытое же АПИ весьма обширное и в разы превосходит официальное.
Особенности объектной модели документов в «Р7»
Так как я не знаю уровень подготовки читающих этот текст, я так же опишу свой взгляд (в малом объеме из того, что мог бы расписать) на некоторые особенности открытой части АПИ в «Р7», из-за которых приходится городить весь этот «огород» в дальнейшем.
У вас нет возможности записать свои ручные действия и далее воспроизвести их, чтобы автоматизировать таким способом какие-то свои рутинные ручные действия. Даже в «МойОфис» такая функция есть, а вот в «Р7» – извините! Только хардкор! Только ручное набивание кода с полным предварительным пониманием, что вы хотите добиться, а как это можно сделать.
Забудьте о самом верхнем уровне абстракции модели классов в «MS Office» – Application! В модели «Р7» просто нет некой главенствующей части, которая бы собой символизировала сам редактор, и предоставляла бы сервисные функции предназначенные для координации работы пользователя в целом. Вы НЕ СМОЖЕТЕ, к примеру, получить список открытых в редакторах документов. И доступа к другим открытым документам получить не сможете! В API «Р7» вы можете получить доступ ТОЛЬКО к текущему документу в котором вы вызываете макрос или плагин!
Так же вам не удастся, к примеру, штатно в фоновом режим подгружать документы в редактор, для считывания из них каких-либо данных. С недавних пор можно использовать внешние ��сылки на такие документы. Тогда связанные по ссылке данные будут считываться при открытии основного документа или при его принудительном обновлении. Но через АПИ этот процесс просто недоступен! Да и сам линки все равно остаются пока ненадёжным и часто глючат. Поэтому, для гарантированной надежности получения данных, в итоге приходится городить загрузку документов в память плагина или макроса сторонними js библиотеками (если такие есть для нужного формата документов). Или же использовать внешние средства в виде запущенных во вне редактора вэб прокси серверов, и получать доступ к файлам с их помощью (на чем сейчас строится уже целая своя, небольшая индустрия, но сейчас не про неё).
Объектная модель документов, лишь внешне напоминает ту, что имеется в «MS Office». В целом применяются похожие структуры данных и их иерархии. Названия объектов, атрибутов и методов почти одинаковые везде, для схожих по своей сути частей документа. Но особенности языка плюс видимо какие - то свои мысли разработчиков, иногда дают другое наименование функций и некоторых объектов. И если копать глубже, то приходишь к выводу: эти аналогии зачастую - довольно поверхностные и поэтому чаще всего не выйдет напрямую транслировать синтаксические названия при переводе макроса из «МС Офиса» на VBA в макросы «Р7» на javascript. Кстати, именно поэтому, обычно не получается у Искусственного Интеллекта писать даже сравнительно простые макросы сразу работающими, так как ИИ быстро начинает галлюцинировать несуществующими в АПИ «Р7(OnlyOffice)» объектами, функциями и атрибутами, придумывая их на ходу, по аналогии с известными ему АПИ объектной модели из микрософтовского офиса, референсным для подобных задач.
Как следствие из предыдущего пункта, и из-за разности базовых особенностей языков, которые используются для автоматизации, не всегда аналогичны и аргументы и их последовательность при вызовах методов классов. Поэтому, у вас всегда должна быть под рукой шпаргалка по фукнциям АПИ, или же настроено автодополнение, чтобы не ошибиться, что и в какой последовательности вы передаёте при вызовах функций. Поскольку javascript типо-независимый язык, то очень легко передать внутрь не ту последовательность данных, и потом очень долго вылавливать ошибки, которая появляются из-за этого, но о которых чаще всего, консоль отладчика пользователя просто не оповещает!
Однопоточная модель работы javascript.При больших объемах расчётных данных, которые нужно прогнать через макрос или плагин, это просто огромная «боль» из-за медлительности всех действий. Ещё и вся «красота» для сложных алгоритмов требующих последовательно-параллельных ветвлений в рабочих алгоритмах. Кое-что для выполнения подобных алгоритмов конечно можно реализовывать через Promise, но это все равно приводит к сильному ухудшению понимания js кода. Не говоря уже про то, что вся внутренняя работа с данными в общем то идет в асинхронном режиме, что может приводить к неопределённости конечных результатов, так как не всегда понятно, какие действия пользователя внутри документа окончатся первыми, и что выводится в итоге как результат для вызов через callCommand() в плагинах. А в макросах что либо серьезное писать по обработке данных даже не стоит и пробовать! В общем, не предназначен javascript изначально для таких задач, и поэтому и написание сложных алгоритмов обработки данных, это задача не для слабаков.
Странные методологические просчеты разработчиков. Некоторые, в общем очевидные за долгие годы работы миллионов пользователей методы, просто не предусмотрены изначально. Вот, например, не отключается расчет формул и перерисовка экрана при изменении данных в таблицах. Если в листах есть формулы в больших количествах, то любые действия в документах по изменению данных приводят к запуску циклов расчетов по всей книге сразу! И это никак не отменить, даже пользователем через меню самого редактора! Не предусмотрено, и всё!
Песочница в макросах. Макросы по сути – это вызов функции eval(), в которую передается записанный как строка код макроса. Процедура опасная и при любых неверных действиях – приводящая к серьезным проблемам. Поэтому написать нормально работающий макрос, который чуть сложнее, чем раскрашивание ячеек по цветам – это целое искусство, требующее терпения и хороших навыков по отладке в javascript. Я бы вообще рекомендовал: сперва написать код для макроса и отладить его в куда более безопасных плагинах, и лишь потом сразу «оптом» переносить его в документы как макрос (сам часто так и делаю). Сам круг задач для макросов из-за использования для их выполнения eval(), сильно ограничен простыми задачами. Большой код для макросов лучше не писать!
Есть также проблемы с использованием в макросах внешних библиотек задач отсутствующих в функционале редакторов. Это сложно, но можно конечно, и я знаю, как минимум два способа как это сделать. Но они коммерческая тайна.
Все действия кода внутри eval() только в ‘strict mode’ (строгий режим), а значит - любая ошибка с объявлениями переменных приводит к остановкам выполнения, которые начинающим трудно понять и устранить. Отладить код макроса можно, по сути, только расставив ‘debugger’ в коде макроса и только потом при остановке в DevTools искать причины ошибок. Но если вы уже крутой программист на js, то все эти проблемы можно обойти или хотя бы - приглушить, и писать довольно серьезные макросы, «с подкидным и девушками пониженной социальной ответственности», как говорится. Часть решений я уже придумал за вас, и покажу вам возможные пути.
Думаю, дальше продолжать смысла нет, ибо проблем увы хватает и на их описание с разбором, можно потратить не одну статью (но я буду о них писать в других своих источниках, так что, как модно сейчас у блоггеров : «лайк и подписка» на них!). Моя же цель сейчас не ввести вас в депрессию, а напротив показать что и в «Р7» можно решать многие сложные задачи, только надо знать – как?!
В следующих статьях я опишу пка лишь одну из проблем, которую трудно решить штатными методами, и о которой я не писал в списке проблем: способы взаимодействия с пользователем из макросов.Сперва, я напишу про методы, которыми можно это сделать. И делать нам это придется сразу в нештатным АПИ.
В третьей статье я опишу свое бесплатное и платное решения, в которых будут решены многие проблемы с нудным действиями, возникающие при программировании вручную через АПИ. Сами же мои решение, надеюсь, к тому времени станут доступны через официальный магазин плагинов «Р7».
Спасибо тем кто дочитал до конца, и жду вас в следующей статье этого цикла!