setInterval или Ext.direct.PollingProvider

Иногда в приложениях требуется обращение к серверу по определенному интервалу времени. Стандартными средствами JavaScript’a это делается примерно так:

setInterval(function() {
     RPC.util.Format(function() {
           ...
     });
}, 5000);

Но в ExtJS есть более корректный подход, использовать Ext.direct.PollingProvider. Если кратко, то Ext.direct.PollingProvider — это провайдер, который сам запрашивает данные с сервера с помощью direct-функции по таймеру.

PN.RPC.POLLING_API = {
           type: 'itpolling',
           pollFn: 'RPC.util.Format,
           id: 'datePoller',
           interval: 2000,
           listeners: {
               data: function (provider, e, eOpts) {
                    // e.response - здесь хранится результат выполнения
                    var poll = Ext.direct.Manager.getProvider('datePoller');
                    poll.disconnect(); // если хотим завершить запросы
               }
           }
       };
       setInterval()
       // register the polling API to the PollingProvider.
       Ext.Direct.addProvider(PN.RPC.POLLING_API);

Данный способ отлично подходит если, например, нужно запрашивать какую-либо direct — функцию. В руководстве ExtJS type указан как polling, но здесь используется наши itpolling В нем переопределены некоторые методы для работы с нашим itdirect

!!!Внимание. Помните о том что большое количество запросов к серверу могут «положит» пул IIS

Код провайдера

Ext.define('It.direct.PollingProvider', {
    extend: 'Ext.direct.PollingProvider',
    alias: 'direct.itpollingprovider',
    requires: [
        'Ext.Ajax',
        'Ext.util.TaskRunner',
        'Ext.direct.ExceptionEvent'
    ],
    type: 'itpolling',
 
    /*
     * переопределен
     */
    onData: function (opt, success, response) {
        var me = this,
            i, len, events;
        if (success) {
            //events = me.createEvents(response);
            //for (i = 0, len = events.length; i < len; ++i) {
                me.fireEvent('data', me, response);
            //}
        } else {
            events = new (Ext).direct.ExceptionEvent({
                data: null,
                code: Ext.direct.Manager.exceptions.TRANSPORT,
                message: 'Unable to connect to the server.',
                xhr: response
            });
            me.fireEvent('data', me, events);
        }
    },
 
    /*
     * переопределен
     */
    onPollFn: function (result, event, success, options) {
        this.onData(null, success, {
            response: result
        });
    }
}) 

Работа с датами в ExtJS. Меняем локализацию

По умолчинию ExtJS применяет en-локализацию. Чтобы поменять ее на ru выполните следующие действия:

— в app.json добавляем следующие параметры:

"requires": [
    "font-awesome",
    "ext-locale" // пакет с локализациями
],
 
"locale": "ru" // устанавливаем культуру

Полный перечень культур можно посмотреть в папке ext\classic\local\overrides

— после этого запускаем команду app build

— открываем файл ext\classic\local\overrides и добавлем следующие параметры в объект Ext.locale.ru.form.field.Date

 ***
format: "d.m.Y",
dateFormat: "d.m.Y", // формат даты который выводиться в поле
submitFormat: 'm/d/Y H:i:s' // требуется для правильного конвертирования даты на клиенте
  ***

— далее в настройках прокси, для store, требуется указать следующий параметр

Ext.define('PN.store.FS_Service_Groups_FS_ServicesCollection_ListView',
{
    extend: 'Ext.data.Store',
    model: 'PN.model.FS_Service_Groups_FS_ServicesCollection_ListView',
    //autoLoad: true,
 
    remoteFilter: true,
    remoteSort: true,
    remoteGroup: true,
 
    proxy: {
        type: 'itdirect',
        api: {
            read:       PN.Domain.FS_Services.Query,
            create:     PN.Domain.FS_Services.Add,
            update:     PN.Domain.FS_Services.Update,
            destroy:    PN.Domain.FS_Services.Delete
        },
        reader: {
                successProperty: 'success',
                rootProperty: 'records',
            } ,
        writer : {
        dateFormat: "d.m.Y H:i:s" // даты на сервер будут возвращаться именно в этом формате
        }
    }
});

Splash screen для ExtJS приложения

Чтобы вывести сообщение об ожидании, при старте приложения ExtJS, требуется выполнить следующие действия.

Находим index.html файл добавляем в него следующий код

Загрузка ExtJS…

Данное сообщение будет выводиться да начала готовности Ext.Application.

!!! Внимание. Требуется наследоваться от It.app.Application

В файле app.js указать следующий параметр:

Ext.application({
    name: 'ImportSubstitution',
    ***
    splashscreen: true,
    ***

Ну вот и все!
Как это реализовано?

В базовом классе произведены следующие изменения:

/*
 * Объект для хранения splashscreen переменной
 */
splashscreen: null,
constructor: function () {
       var startExtJSMessage = Ext.get('start-extjs');
       if (startExtJSMessage)
           startExtJSMessage.hide();
 
       if (this.splashscreen == true) {
           // start the mask on the body and get a reference to the mask
           this.splashscreen = Ext.getBody().mask('Загрузка приложения...', 'splashscreen');
       }
       this.callParent(arguments);
   },

/*
 * Инициализация splashscreen
 */
initSplashScreen: function () {
    if (typeof this.splashscreen == 'object') {
        this.splashscreen.destroy();
    }
},

onProfilesReady: function () {
    var me = this;
    me.loadRemotingApi(() => {
        me.initControllers();
        me.onBeforeLaunch();
        me.initSplashScreen();
        me.finishInitControllers();
    });
},

Динамическое дерево в ExtJS modern

В данной статье пойдет речь о том, как создать динамическое дерево (TreeList) в ExtJS Modern. Возможно данная реализация есть в «коробке», но я ее не нашел.

Стандарный компонент treelist отлично работает, если в хранилище находится например 100 записей, но если их будет тысяча или более? У меня получилось так, что мобильный телефон стал заметно тормозить. И после долгих поисков решения в интернете, решил доработать компонент.

Первое что я сделал — это создал наследник от treelist

Ext.define('MobileService.view.routeList.items.MobileTreeList', {
    extend: 'Ext.list.Tree',
    xtype: 'mobiletreelist',
 
    privates: {
// expand - стоит строить дочернии элементы или нет. По умолчанию null createItem: function (node, parent, expand) { var isRootItem = node.get('isRootItem'); // требуется для определения корневого элемента (те записи которые видит пользователь на первом уровне) if (!isRootItem && !expand) return null; return this.callParent(arguments); }, // переопределен. Основной метод для добавления дочерних элементов onNodeExpand: function (node) { var item = this.getItem(node); var childNodes = node.childNodes; for (i = 0, len = childNodes.length; i < len; ++i) { child = childNodes[i]; if (!this.itemMap[child.internalId]) { var _item = item.getOwner().createItem(child, item, true); if (_item) { this.itemMap[child.internalId] = _item; item.insertItem(_item, null); } } } this.callParent(arguments); } } });

Второе, создаем наследник от Ext.list.TreeItem

/*
 * для вывода дерево документов и строк я создал собственный класс для TreeItem
 */
Ext.define('MobileService.view.routeList.items.RouteListItem', {
    extend: 'Ext.list.TreeItem',
    xtype: 'routelistitem',
 
    privates: {
        updateNode: function (node) {
            if (node) {
                var me = this,
                    map = me.itemMap,
                    childNodes, owner, len, i, item, child;
                me.element.dom.setAttribute('data-recordId', node.internalId);
                if (!map) {
                    childNodes = node.childNodes;
                    owner = me.getOwner();
                    me.itemMap = map = {};
                    for (i = 0, len = childNodes.length; i < len; ++i) {
                        child = childNodes[i];
                        item = owner.createItem(child, me);
                        if (item) { // добавили проверку на возможность создания ветки
                            map[child.internalId] = item;
                            me.insertItem(item, null);
                        }
                    }
                }
                me.setExpanded(node.isExpanded());
                me.doNodeUpdate(node);
            }
        }
    }
});

Третье, создаем данные для хранилища

var root = {
    expanded: true,
    children: [
        {
            text: 'item1',
            isRootItem: true,
            children: [
                ....
            ]
        },
        {
            text: 'item1',
            isRootItem: true,
            children: [
                ....
            ]
        }
    ]
};
var store = Ext.create('Ext.data.TreeStore', {
            root: root
});

Наконец и сам компонент

                xtype: 'mobiletreelist',
                height: '100%',
                defaults: {
                    xtype: 'routelistitem'
                }

Вроде все, должно работать. Все дочернии элементы будут отрисовывать динамически

Ext JS 6.0.0.640

Сжатие JS-файлов

Для создание одного js-файлай из нескольких можно использовать утилиту от Google — Closure Compiler

  1. устанавливаем Java Runtime Environment version 7, если у Вас её нет
  2. Скачиваем файл compiler.jar
  3. Распаковываем в папку например e:\compressionjs
  4. Для примера создаем в этой папке js — файл (например simple.js)
  5. // A simple function.
    function hello(longName) {
      alert('Hello, ' + longName);
    }
    hello('New User');
    
  6. Выполняем команду java -jar compiler.jar —js sample.js —js_output_file hello-compiled.js

Примечание: Если нужно по всей папке собрать, то можно выполнить java -jar compiler.jar —js=»*.js» —js_output_file hello-compiled.js

Подробнее о командах можно узнать java -jar compiler.jar —help

Сборка мобильного приложения

Сборка мобильного приложения осуществляется под разные регионы. Список регионов нужно уточнить в исходном коде. Для этого перейти в папку resources/usersetting.Настройка приложения под регион.

  • открываем файл resources/config.json. Находим свойство theme и меняем на имя региона
  • далее переходим в файл resources/userseting/имя региона/config.json. В данном файле хранятся свойства которые были переопределены. Установить параметр debug=false
  • перейти в файл app.json. В свойстве requires установить пакет региона (если он есть, но если нет, то нужно убрать все пакеты, которые начинаются с ext_)
  • выполняем команду sencha app build native testing
  • после завершения команды на рабочем столе должна появиться *.apk

Автоматическая сборка.

В корне приложения должен находиться файл build.js. Он написан под nodejs. Команда для запуска выглядит следующим образом

node cmd build имя_региона

Если нужно собрать приложения для конечного заказчика, то требуется дополнительно указать параметр production

node cmd build имя_региона production

Внимание!!! При сборке приложения под Казань требуется поставить crosswalk. Для других регионов данный плагин должен быть удален

Сборка с crosswalk

crosswalk — это дополнительный плагин для работы мобильного приложения в android’e, где версия браузера «старая» (нет поддержки css3)

Переходим в каталог cordova

cd cordova

cordova plugin add cordova-plugin-crosswalk-webview

Далее возвращаемся обратно в каталог с приложением и запускаем
node cmd build [имя региона]

Примечание: Главное запомнить, что при сборке для региона, где crosswalk не требуется нужно удалить данный плагин
cd cordova

cordova plugin remove cordova-plugin-crosswalk-webview

Работа с командной строкой

Журнал изменений (check list)

node cmd checklist [команда]

Список команд:

add [описание] [тема]? [версия]? — добавление записи в check list

Пример: node cmd checklist «первая версия» * 1.69.2 или node cmd checklist «первая версия»

remove [версия] — удаление версии

get [версия]? — возвращается список версий или указанная запись

Пример: node cmd checklist get 1.69.2 или node cmd get

clear — очистка списка

Сохранение версии на сервере

node cmd checkversion — сохраняет текущию версию на сервере для дальнейшей обработки при ошибке

Сжатие данных

zip может одновременно и архивировать, и сжимать файлы; то есть вы можете сжать различные файлы, поместив их при этом в архив. Он известен еще с 1998 года и метод его работы был реализован на многих платформах, следовательно, это один из самых мобильных вариантов (особенно — если вам необходим доступ к вашему архиву из системы Windows).

zip -r archive folder

Создает архив archive.zip с содержимым каталога folder.

unzip archive.zip

Извлекает содержимое архива archive.zip в текущую директорию, создавая вложенные директории (используйте -j чтоб не создавать вложенных директорий).

Создание backup’а базы данных MySql

mysqlhotcopy -u=user -p=password [database] [/path/to/some/dir]

Если резервной копии базы данных было сделано с mysqlhotcopy, восстановление происходит, после остановки сервера, копирование содержимого файла резервной копии в каталог данных MySQL:

# cp -R /backup-db/miodatabase /var/lib/mysql