Архитектура 2.0 в Simple UI

03.02.23

Разработка - Мобильная разработка

11-й релиз платформы – своего рода перезагрузка проекта, внедрение новой архитектуры, новых принципов, которые должны стать базой для дальнейшего развития платформы. Цель – сделать мощнее и гибче, но одновременно проще и понятнее, сократить объем необходимой документации, сделать концепцию более целостной и логичной. Дополнение к статье https://infostart.ru/public/1153616/

Единый формат обработчиков и асинхронность

 

Все события в платформе теперь возникают в 3х ключевых точках:

  •     События экрана
  •     События ActiveCV
  •     События системы в целом. Теперь тут собраны все виды событий, а также их список расширен.

Также события могут запускаться из кода или, например, по окончанию каких то фоновых механизмов.

На любое событие платформы вне зависимости, где это событие происходит (экраны, ActiveCV, общие события платформы) можно подписать любое количество различных любых обработчиков (массив). Этот массив предполагает чередование любого количества обработчиков любых типов и режимов исполнения (синхронные и асинхронные). Этот массив можно определить в конфигурации с помощью конструктора, запустить командой, запустить по псевдониму. Он может состоять из одного действия, а может из множества.

Например, так это выглядит в конструкторе 
 

 

Строковое написание обработчика аналогично определению в конфигураторе, оно используется для запуска из кода, но и в целом проще для понимания.

Пример массива из одного простого синхронного обработчика в строковом виде:

[{"action": "run", "type": "python", "method": "post_online"}]

В общем случае синтаксис состоит из следующих элементов:

[{"action":"run[async]","type":"python|online|http|sql|…","method":handlerName|parameters","postExecute":{<handler description>}}]

где:

action – либо run либо runasync – синхроннй или асинхронный запуск

type – тип интерпретатора (где обработчик будет выполняться). На текущий момент это Python, онлайн (на стороне бекенда), нативная обработка (sql,http,set). В будущем добавятся другие исполнители

method – в случае интерпретаторов – это имя функции, также для нативных обработчиков это может быть сразу команда с параметрами

postExecute – это поле имеет смысл для асинхронных обработчиков, туда можно вставить массив обработчиков которые будут выполнены по завершению (а в нем может быть еще один массив и т.д. – рекурсия)

В старой архитектуре на любое событие экрана могло быть выполнено 2 действия в строгой очередности и строго синхронно– Python потом Онлайн. Либо одно из них либо оба. 

Это можно изобразить так в новой архитектуре:

[{"action": "run", "type": "python", "method": "open_handler"},{"action": "run", "type": "online", "method": "open_handler"},{"action": "run", "type": "python", "method": "input_handler"},{"action": "run", "type": "online", "method": "input_handler"}]

Или так бы это выглядело в конструкторе:


 

Так, чтобы что-то заполнить в Python, потом отправить в онлайн, потом прочитать результаты опять в Python – это было невозможно. Теперь возможно, более того, онлайн в силу возможных задержек желательно запускать async с постобработкой

Пример обработчика с асинхронным вызовом, по завершению которого вызывается синхронный вызов и асинхронный сразу после.

Этот пример есть в демо- конфигурации.
 

 

Тут для примера в демо-базе асинхронной процедуре стоит задержка на 2с. Если вы нажмете Вперед, то сразу появится тост, хотя в массиве обработчик идет а 2й строке. Это нормально – асинхронный обработчик запустился первым, но ушел «думать», следом запускается следующий обработчик. В этом и смысл асихрона на экранах и в ActiveCV – не морозить систему, пока обработчики «думают»

 

Общие обработчики системы

 

 

Система порождает и отлавливает множество событий, которые имеют теперь единую точку входа и единый формат обработчиков.

В новой архитектуре добавилось несколько новых событий и на базе этого механизма будут появляться новые другие события. 
Вот перечень этих событий:

onLaunch  - при запуске перед формированием главного меню. Так как вызывается до формирования меню, то в этом обработчике например можно перерисовать меню или заполнить плитки. По сути заменяет таймер с периодом -1, который также можно использовать для этой цели.

onIntentBarcode – получение штрихкода через подписку на Intent на уровне платформы в целом(до экрана). Например может использоваться для работы со сканером без экранов либо для пред проверки штрихкодов. В переменные помещается: listener=”barcode”, barcode=<штрихкод>

onBluetoothBarcode – получение штрихкода от подключенного Bluetooth-сканера на уровне платформы в целом. В переменные помещается: listener=”barcode”, barcode=<штрихкод>

onBackgroundCommand – получение события onBackgroundCommand в сервисе событий, отправленного из какого то обработчика (командой-переменной BackgroundCommand ) . В listener помещается аргумент команды BackgroundCommand

onRecognitionListenerResult – события по результату распознавания речи после использования команды voice в сервисе. В переменные помещается: listener=”voice_success”, voice_result=<распознанная фраза>

onIntent – получения сообщения от другого Андроид-приложения (подписка на Intent). Из сообщения извлекаются поле “body” и помещается в переменную. Через него можно передавать данные от другого приложения.

onWebServiceSyncCommand – получения команды через встроенный веб-сервер приложения. На адрес веб-сервиса <адрес устройства>:8095 можно послать запрос GET или POST (если нужно передать данные то POST) вида http://<адрес устройства>:8095?mode=SyncCommand&listener=<произвольное название обработчика>. В эжтот момент срабатывает данное событие. Обработчик может что то поместить в переменные и все переменные отправляются назад в виде JSON объекта. Но, можно также не отправлять все переменные а переопределить ответ(напрмиер сделать не JSON а строковый) с помощью команды WSResponse

onSQLDataChange и onError возникают при выполнении любой записи в SQL если запрос идёт через SQL-провайдера (onError в случае ошибки). Таким образом можно например перехватывать записываемые данные централизованно и помещать их в очередь на отправку.

onOpenFile – событие, в котором можно получить файл, открытый приложением. С приложением можно поделиться текстовым файлом любым способом (через Поделиться… и через Открыть с помощью…) даже если приложение не открыто. При этом срабатывает обработчик и в переменные content и extra_text помещается содержимое файла и ссылка на файл.
 

Новый формат обработчиков в конструкторе

 

 

С новой архитектурой отпала нужда в множестве полей и закладок и можно переключить конструктор в режим Архитектура 2.0 (через меню), также новые конфигурации сразу создаются в этом режиме. Признак arch2 прописывается в самой конфигурации, он влияет только на вид конфигуратора. Собственно, одна из целей новой архитектуры была – сократить количество полей, сложность документации и дать единый принцип ко всей системе.

 

Подписка сразу на listener


 

 

 

Теперь необязательно писать в обработчике условие типа Если Переменные.listener=…, достаточно просто указать в конфигурации в поле listener имя нужного события, например переменную кнопки. Проведя множество кодревью, я понял, что конструкции с условиями на listener занимают много лишнего кода, теперь можно обойтись без этого. Мелочь, но делает код более читаемым.

 

При запуске/по расписанию

 

Может работать как раньше(вызывать процедуры python), но теперь имеется возможность подписать на эти события массив обработчиков, а значит, можно, например, запускать по таймеру и обычный онлайн обработчики, не только питон (и также обработчики других типов). Делается это через псевдоним. На закладке общие обработчики можно добавить обработчики без события, но с псевдонимом

При запуске, можно запускать как раньше (с периодом -1), но в большинстве случаев также подойдет общее событие onLaunch, которое, кстати, запускается до формирования меню, но после загрузки конфигурации, а значит, меню, например, можно перерисовать в этот момент. 

 

Новые управляющие команды

 

RunEvent – запускает массив обработчиков вручную

BreakHandlers – останавливает выполнение массива после какого то обработчика. Это полезно, например, для проверки ввода (аналог Отказ в 1С)

RefreshScreen – перерисовка текущего экрана без вызова события и обработчиков. Это важная команда для асинхрона – после завершения расчетов, если нужно, например, что-то обновить на экране, достаточно вызвать эту команду и все элементы экрана, которые заполнены из @переменная, будут обновлены. Если ее не вызывать, то по завершению асинхронно на экране ничего не обновится.

noRefresh – отказ от перерисовки экрана и вызова обработчиков
 

Новые принципы работы с SQL

 

Решались следующие цели:

  •  Единая точка доступа к СУБД и работа с несколькими базами
  •  Ввиду особенностей реализации SQLite под именно Android разработчики  SQLite рекомендуют реализовывать паттерн singleton для работы  с SQL, чтобы исключить параллельную многопользовательскую работу. Если не пользоваться этим принципом, то организация, например, записи из обработчика по расписанию через Python рано или поздно пересечется с обработчиком экрана, который тоже что-то записывает, и произойдет падение СУБД с потерей всех данных.
  •  Обращение к SQL не только из Python, но и, например, из онлайн обработчика и других обработчиков. Дело в том, что python требует контекста приложения, но приложение часто может быть не запущено, при этом может быть запущен сервис, который что-то скачивает или отправляет - требуется работа с SQL. Также в будущем планируются механизмы, которые тоже работают автономно без участия приложения. 
  •  Ну и, собственно, Python учить не обязательно, если речь идет о какой то простой логике с SQL. Все можно сделать из backend. Это использование SQL  в чистом виде без необходимости разбираться в еще одном языке.  
  • Кроме того, теперь все виды обработчиков, что называется, равны. Далее будут появляться новые интерпертаторы языков и новые виды обработчиков, и у них у всех будет доступ к SQL в едином стандартном виде
  • Также единая точка доступа (провайдер) порождает и общие события SQL (при записи, ошибка), которые опять же удобнее обрабатывать не на отдельных экранах, а в одном обработчике. Например, перехватывать  onSQLDataChange и писать в очередь на отправку

Можно работать с SQL через команды-переменные либо(если из python-обработчиков), использовать вызовы специального класса в явном виде. 

Вот справочник команд-переменных:

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

SQLExec, параметр: {“query”:”SQL statement”,”params”:”parameters with delimiter”} Например {"query":"create table IF NOT EXISTS goods (id integer primary key autoincrement,art text, barcode text, nom text)","params":""}. Выполняет запрос на изменение БД (все кроме SELECT), параметры в запросе указываются в неименованном виде, а в params, перечисляются через запятую. Например:

SQLExecMany, параметр:{“query”:”SQL statement”,”params”:”array of parameters”}  – выполняет запрос в  BULK-режиме с массивом из множества записей. Параметры запроса передаются в виде массива записей в неименованном виде (через ?)

Пример:
 

values=[]
    for i in range(1,3):
        record =[]
        record.append("AA"+str(i))
        record.append("22"+str(i))
        record.append("Товар через переменную "+str(i))
        values.append(record)
   
   
    hashMap.put("SQLExecMany",json.dumps({"query":"insert into goods(art,barcode,nom) values(?,?,?)","params":json.dumps(values,ensure_ascii=False)}))

SQLParameter – имеет смысл для SQLExecMany для передачи массива записей в качестве параметра из других обработчиков

SQLQuery , параметр {“query”:”SQL statement”,”params”:”parameters with delimiter”} – запрос типа SELECT, который пишет выборку в виде JSON-массива в стек переменных

Те же функции можно вызывать из импортируемого класса напрямую. Этот вариант хорош тем, что результат получаешь сразу, а не на конец шага, и его лучше использовать в python-обработчиках.

from ru.travelfood.simple_ui import SimpleSQLProvider as sqlClass
sql = sqlClass()
    success=sql.SQLExec("insert into goods(art,barcode,nom) values(?,?,?)","111222,22000332323,Некий товар")
    res = sql.SQLQuery("select * from goods where id=1","")
    if success:    
        hashMap.put("toast",res)

 

Работа с SQL напрямую через конфигурацию (обработчик SQL)

 

Можно работать с SQL не через команды-переменные и не через Python, а напрямую. Это один из «нативных» обработчиков. Я сделал его как еще одну попытку упростить разработку там, где это возможно – убрать лишний код и повысить читаемость. До «питона» у меня была попытка конструктора SQL, HTTP и установки переменных, неудачно и неудобно. Но вот сейчас я переосмыслил это полностью и предлагаю оценить еще одну попытку. Надеюсь, это будет удобно и не нужно будет лишний раз залезать в Python для чего-то простого. Как и два предыдущих варианта – этот также работает через единый провайдер со всеми вытекающими свойствами – регистрацией событий и т.д.

Данный вид обработчика удобно использовать для простых ситуаций – вытащить переменные из SQL по отбору, записать простой insert или update и т.д.

Что, например, можно делать этим инструментом:

  1.     Передавать любые поля в запрос из стека переменных через @, также как они передаются на форму. Например, этот запрос запишет в таблицу name и barcode. Это касается и переменных запроса и условий.
  2.     Select распознается как выборка и пишет результат в переменные в виде JSON-массива (такой же как если вызвать это через команду переменные или класс)
  3.     Но если в select написать limit 1 то обработчик запишет переменные 1й строки сразу в стек переменных. Удобно например при открытии сделать выборку, сразу получить переменные и привязать их на форму – без парсинга и т.е. 

 
Как видите, я постарался сделать так, чтобы работать было так же просто, как в консоли запросов.
 

Новые принципы работы с HTTP

 

Онлайн-обработчики сами по себе, но помимо выполнения онлайн-обработчиков также можно потребоваться доступ к другим REST API. Это можно делать например из Python (requests) но также предлагается еще один метод и вот его преимущества:

  • Скрыть настройки подключения, сделать удобное обращение через псевдоним соединения. Т.е. один раз где-то записываются настройки подключения к какому-то эндпоинту – URL, авторизация, заголовки, а потом в запросах можно просто упоминать этот псевдоним, за котрым это все стоит. Это способ скрыть логины и пароли корпоративной системы от компрометации
  • Совместимость с шифрованием в корпоративной  версии. Вышеперечисленные настройки в корпоративной версии хранятся в криптозащищенном хранилище
  • Также как с SQL одна из задач данного подхода – работа с запросами без python (который требует контекста, а такие вещи, как запросы, часто как раз работают без запущенного приложения, в фоне или в воркерах). 

Настройки подключения закрепляются за псевдонимом 1 раз на устройстве через команду HTTPAddAlias. Например:

hashMap.put("HTTPAddAlias",json.dumps({"alias":"odata","url":hashMap.get("url"),"headers":{"Content-Type":"application/json; charset=utf-8","Accept":"*/*"},"basic":{"user":hashMap.get("user"),"password":hashMap.get("password")}},ensure_ascii=False))


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

Например, можно написать вот такой запрос:
 

 

Тут используется строковый синтаксис:

На первом месте идет метод – GET,POST,PUT и т.д.

На втором адрес, причем начало URL (как и все остальное берется из псевдонима. Сам псевдоним записывается через #

На третьем месте может быть body. Например, JSON c переменными, причем переменные, так же как и везде – через @

Например, так можно поместить переменные из стека в тело запроса:

 

 

Работа с переменными напрямую через конструктор (обработчик SET)

 

И также можно устанавливать переменные или команды-переменные напрямую без необходимости организации отдельного обработчика. Т.е. можно выполнять простые команды, пользуясь переменными. Причины те же, что и в предыдущих нативных обработчиках. Кроме того, как выяснилось на практике, организовать вывод тоста или бипа, не залезая в python - удобно.

Правила простые:

  1.  если есть параметр, то он устанавливается через =, если нет, то пишется просто переменная без параметра. Пробелы на концах отсекаются
  2.  можно использовать сразу несколько через запятую
  3.  Также как и везде, можно обращаться к переменным через @

Например, тут устанавливаются сразу 3 переменных – toast,vibrate, speak
 

 

Прочие нововведения

 

SetSettingsJSON – команда для установки настроек в том же формате, в котором их можно загружать через файл или QR

app_shutdown – команда выключения приложения

StartCaptureCamera – запуск камеры, аналогично размещению стандартной кнопки. Только тут можно повесить на свою кнопку или какое то событие

StartMediaGallery – запуск выбора файла из галереи вручную. Также можно повесить например на свою кнопку
 

Подписывайтесь на мой телеграмм канал, чтобы быть в курсе новостей и также я туда выкладываю всякие полезные штуки: https://t.me/devsimpleui

SimpleUI Android Simple

См. также

Мобильная разработка Мессенджеры и боты Платформа 1С v8.3 1С:Конвертация данных Платные (руб)

Теперь создать telegram-бота - элементарно. Достаточно просто нарисовать блок-схему телеграм-бота, и он сразу заработает. Это возможно при использовании Графического конструктора телеграм-ботов. Это единственный конструктор ботов для telegram, чье качество и функционал подтверждены фирмой 1С, есть сертификат 1С:Совместимо. Расширение в интерактивном режиме, с помощью блок-схем, позволяет с минимальными трудозатратами создать телеграм-ботов в любой конфигурации, работающей на платформе «1С:Предприятие 8.3».

13200 руб.

27.12.2021    38186    108    161    

201

Мобильная разработка Сканер штрих-кода Терминал сбора данных Управляемые формы Мобильная платформа 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Управленческий учет Платные (руб)

Сбор заказов, инвентаризация, проверка ценников, просмотр полной информации об остатках и ценах со смартфона Онлайн - все это содержит в себе решение 1С "Штрихкод-информер" (штрих-код чекер). Отправка данных со смартфона выполняется либо напрямую в открытую форму документа, отсканировав QR-код, либо в общую корзину учетной системы, не подходя к компьютеру. Кассир или оператор сможет просмотреть список присланных данных и загрузить в любую форму, поддерживающую работу с ТСД. Для работы с мобильным приложением требуется опубликовать HTTP-сервис из поставляемого расширения.

3000 руб.

03.12.2018    59283    192    103    

172

Сканер штрих-кода Терминал сбора данных Мобильная разработка Монитор заказов Оптовая торговля Розничная торговля Ценообразование, анализ цен Программист Пользователь Платформа 1С v8.3 Мобильная платформа 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Оптовая торговля, дистрибуция, логистика Управленческий учет Платные (руб)

Простой мобильный ТСД (терминал сбора данных) сканер для 1С для смартфонов на iOS и Android, не требующий сложных настроек и установки дополнительных программ. Обмен между Вашей 1С и мобильным приложением осуществляется через облачный сервис и расширение конфигурации. Работает с конфигурациями УТ 11, ERP, КА2, Розница 2, Розница 3, УНФ 1.6, УНФ 3.0. Полнофункциональный демо-доступ для своей конфигурации можно запросить в настройках мобильного приложения - все необходимое придет на почту автоматически.

2000 руб.

22.04.2019    97206    586    189    

321

Логистика, склад и ТМЦ Сканер штрих-кода Терминал сбора данных Мобильная разработка Платформа 1С v8.3 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)

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

3450 руб.

28.04.2023    9464    15    0    

9

Мобильная разработка Платформа 1С v8.3 Конфигурации 1cv8 Финансовые услуги, инвестиции Управленческий учет Платные (руб)

Мобильное приложение и конфигурация 1С для автоматической торговли на бирже через API Тинькофф банка. Достаточно задать настройки, нажать «Пуск», и робот сам торгует ежедневно.

7000 руб.

25.05.2022    4641    1    0    

6

Мобильная разработка WEB-интеграция Программист Мобильная платформа Абонемент ($m)

Экспериментальный релиз и простенький скрипт к нему закрывает потребности в любых видах синхронизации между устройствами Simple и между Simple и бек-системами (например 1С). По сути – это очень простой python-скрипт, который можно запустить на доступной машине, сервере или VPS и он будет связывать клиентские устройства между собой и с 1С или другими бек-системами. В самой платформе появилось для этого множество доработок для поддержки стабильного постоянного соединения, докачки больших файлов и работе в фоне. Дополнение к основной статье https://infostart.ru/1c/tools/1153616/

1 стартмани

23.08.2024    1212    6    informa1555    1    

13

Мобильная разработка Мобильная платформа Абонемент ($m)

В этом релизе собрано много нового из области интерфейса, связи, хранения и важные новые способы управления. Дополнение к основной статье https://infostart.ru/1c/tools/1153616/

1 стартмани

25.06.2024    2595    28    informa1555    0    

33
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. quazare 3800 03.02.23 09:50 Сейчас в теме
Ребята, я хочу у вас спросить - кто занимался разработкой web-приложения на платформе (именно через браузер) - отпишитесь здесь или мне в личку.

А вообще какие сейчас используются инструменты по разработке web для браузеров
2. maksa2005 550 03.02.23 12:15 Сейчас в теме
14. van_za 269 03.02.23 14:48 Сейчас в теме
"А вообще какие сейчас используются инструменты по разработке web для браузеров"
-js, TypeScript, node js, figma, swagernpm, webpack, react, axios, redux и т.д.
15. siamagic 03.02.23 14:57 Сейчас в теме
(1) сейчас тебе накидают гумно фремворков коорые тормозят, смотрит в сторону wpa с наитивным кодом - быстро и эффективно.
16. quazare 3800 03.02.23 15:01 Сейчас в теме
(15) так я и хотел посмотреть WPA - ни одного примера не могу найти
18. lmnlmn 69 03.02.23 15:46 Сейчас в теме
(15) WPA это PWA или еще что-то новенькое появилось?
siamagic; +1 Ответить
19. siamagic 03.02.23 21:53 Сейчас в теме
(18) кому надо понял, ну дурачек для опечатки нашелся, с граммер нации американцев поясни разницу пожайлуста
20. siamagic 03.02.23 21:55 Сейчас в теме
(18)Всегда путал... спасибо тебе PWA - Пиздец Веб ...)))))))))) и оно действительно так.
3. quazare 3800 03.02.23 12:25 Сейчас в теме
(2) у меня ошибка защищенного соединения по ссылке
5. quazare 3800 03.02.23 12:28 Сейчас в теме
Все равно не могу открыть - это андройдом надо?
7. maksa2005 550 03.02.23 12:51 Сейчас в теме
(5)любой сайт открывает это.
Личный кабинет Тепломир
Личный кабинет Менеджера
МастерОк86
6. quazare 3800 03.02.23 12:36 Сейчас в теме
(4) скинь в личку как называются - погляжу
8. quazare 3800 03.02.23 13:00 Сейчас в теме
(7) посмотреть не удалось.

ну это ты сделал на андройде - платформой, я так понял. именно веб приложение, чтобы можно было открыть бараузером - на чем сейчас делают то...
9. maksa2005 550 03.02.23 13:03 Сейчас в теме
(8)а зачем? смысл? кучу денег отдать за красивый интерфейс в вебе? людям скорость нужна в работе, не красота реализации. Да 1с в webe и так обладает UI
13. John_d 5891 03.02.23 14:28 Сейчас в теме
(8) я делал ТСД на JavaScript. В статье были видео, но ютуб грохнул мой канал со всеми видео)
https://infostart.ru/1c/articles/1507241/
10. quazare 3800 03.02.23 13:07 Сейчас в теме
(9) зачем и смысл - не правильные вопросы. Вот хотелось бы посмотреть на приложения созданные именно для веб и через платформу? Есть такие? Дайте ссылку. На андройде не нужно
11. maksa2005 550 03.02.23 13:10 Сейчас в теме
(10) У меня таких нет. спроси Цифрового кота. Он много таких сделал)
12. quazare 3800 03.02.23 13:20 Сейчас в теме
(11) ждем примеры от цифрового кота
17. siamagic 03.02.23 15:04 Сейчас в теме
Выглядит максимально паршиво, как правило веб хорош для РМК, или удаленных юзерей.
Где стоит красиво вывести необходимые реквизиты и ТЧ.
При необходимости - если начинаетс яредактирование подтягиваются из кеша или с субд возможные значения выбора.
Делается через ОДата - летает вполне себе быстро, но намного проще через шттп-сервис - тоже будет универсально.

Зачем делать то что описано в статье не обозначено.
21. legioner55 05.04.23 10:58 Сейчас в теме
Добрый день! Начал разбираться с simple_editor и не могу найти в документации как производится перепривязка файлов обработчиков? Заранее спасибо.
Оставьте свое сообщение