вторник, 10 сентября 2013 г.

Кнопки браузера и история

Обычно в одностраничном приложении, написанном на ExtJs есть меню, как и в десктопном приложении или у веб-сайта. Щелчки по пунктам меню переключают активные компоненты приложения. Пользователь видит то один, то другой, то третий...

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

Чтобы решить проблему, используйте Ext.util.History.

У этого объекта есть свои особенности. Он нуждается в скрытом поле ввода и скрытом ифрейме. Кроме того его нужно инициализировать перед использованием.

В момент, когда в DOM-модели уже присутствует элемент BODY, нужно выполнить такой код:

Хорошо подходит для этой цели метод onLaunch контроллера меню или контроллера экрана (viewport).

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

Этот код должне находиться в контроллере меню в обработчике кликов по пунктам меню.

Пример из документации.

среда, 4 сентября 2013 г.

Как получить выбранные записи из выпадающего списка, предоставляющего возможность множественного выбора?

combobox.getPicker().getSelectionModel().getSelection()

getPicker возвращает объект типа Ext.view.BoundList, которому известно, какие записи выпадающего списка были выбраны.

Метод getPicker не описан в документации к версии 4.0.7, но он присутствует в коде библиотеки. В версии ExtJs 4.2.1 этот метод попал в документацию. Значит, можно считать, что его можно использовать и в ранней версии, не опасаясь того, что разработчики откажутся от него в следующей версии.

понедельник, 2 сентября 2013 г.

Связанные списки

Есть два списка xtype=combobox. Выбор элемента в любом списке приводит к фильтрации соседнего. Контроллер обрабатывает событие select. Обработчик этого события находит соседний список и его хранилище. Записи хранилища фильтруются. Проблема: несмотря на то, что фильтрация хранилища отрабатывает правильно, выпадающий список на экране отображает все записи.



Проблема решается установкой свойства lastQuery = '' внутри обработчика события beforequery. пример кода для фанатов MVC:



Теперь на экране всё, как надо:


Если не срабатывает событие, проверьте данные в хранилище.

среда, 28 августа 2013 г.

Хранилище для опций


В случае связанных моделей хорошей привычкой станет указание proxy. Если не указать proxy в модели OptionModel в примере ниже, то скрипт начнёт глючить будет вести себя неожиданным образом.


Ещё о полезных привычках...

среда, 21 августа 2013 г.

Voice Magic: Touch & Say

Writing Semantic JSON is very tedious. Generally every pronoun means that you must create a reference to a previous sentence. It's the core idea of this input format, so you can't just drop making references. Videos of Bret Victor inspired me to create a more practical approach.

You just touch the screen and say a word. A figure appears under your finger tip. It is bound to the recorded sound. Now you can reuse the figure dragging it from recent to new statements. I'm going to provide a picture to illustrate this.




When you touch a circle of a previous statement inside time line area, you hear your own recorded voice saying the respective word. When you touch a circle inside context area, you hear a short story about this object.

If someone feeds his speech into your device you can reference circles from the feed as well.

There are few real world objects that we describe in speech when we experience a circumstance. If one would take the labor to type letters near the figures one has used a lot, two multy-layered graphs of say me and another person could snap together producing talk.

You may ask: why not just talk to each other. Why do we need computers?

Imagine someone who lives a thousand years after this moment. How can you communicate with this person? Will you write a book? The imaginary person of the future won't find you book inside the mountain of books that will have accumulated since the present time.

Text lines are no more sufficient. We need graphs.

semanticweb.com

Схлопывание боковой панели

Оказалось, что версия ExtJs 4.0.7 позволяет создавать скрываемые боковые панели без помощи layout: 'border'. На что следует обратить внимание:

1. Нужно определить обработчики для событий expand и collapse боковой панели, которые заново отрисуют панель. Если этого не сделать, панель будет пропадать. При ресайзе окна браузера она будет появляться снова.

2. Установить ширину панели в пикселях, иначе проблемы, описанные в п.1, не исчезнут.

3. Запретить анимацию при схлопывании панели. Потому что она неудачная.

{
    xtype: 'panel',
    title: 'Фильтр',
    collapsible: true,
    collapseDirection: 'left',
    animCollapse: false,
    headerPosition: 'top',
    width: 400,
    listeners: {
        collapse: function(panel) {
            panel.doComponentLayout();
        },
        expand: function(panel) {
            panel.doComponentLayout();
        }
    }
}


четверг, 15 августа 2013 г.

Будущее программирования


Для слушателей в зале идёт 2013-ый год. На сцене - 1973-ий. Обратите внимание на проектор. Это настоящий проектор.

Сейчас (1973) Через 40 лет
создание программного кода непосредственное манипулирование данными
процедуры цели о ограничения
текст пространственное представление
последовательное выполнение параллельное выполнение





Bret Victor - The Future of Programming from Bret Victor on Vimeo.

Ещё...

вторник, 13 августа 2013 г.

WebRTC: подключение

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

Действующие лица:
  • браузер Маши
  • браузер Савелия
  • сторонний сервера
  • сигнальный сервер

Действие первое


Маша ждёт сообщение сообщение от Савелия. Она включает компьютер, открывает браузер. Заходит на страницу нашего сервиса.

Браузер Маши загружает при этом с сигнального сервера статические файлы: index.html, файлы со стилями, файл нашего приложения на ExtJs и картинки.

Сигнальный сервер нарочито быстро отдаёт файлы, чтобы показать, что эта задача для него не основная и что, на самом деле, он создан для другого.

Действие второе


Браузер Маши развернул перед ней на экране, созданное нами приложение. Чтобы принимать входящие сообщения, он успел сбегать на два сервера.

Сторонний сервер посмотрел на браузер Маши из интернета и рассказал, какой у того на самом деле IP. Заметив беспокойство на лице собеседника, он поспешил упокоить его, заверяя, что прочие браузеры всё равно смогут связаться с ним, несмотря на изоляцию, в которую он попал по вине разного рода маршрутизаторов и роутеров.

По совету стороннего сервера браузер Маши отослал своё описание на сигнальный сервер. Сигнальный сервер, не читая, положил это описание в архив. Он знал, что серверы намного важнее браузеров, и не вдавался в подробности их жизни. Запомнив только название канала связи, он сразу отключился.

Действие третье


Браузер Маши проверяет время от времени, не желает, кто-нибудь выйти с ним на связь. Сигнальный сервер монотонно отвечает, что нет, никого не было.

Действие четвёртое



На сцену выходит Савелий. Он отправляет письмо Маше. Вместо адреса - название канала связи.

Браузер Савелия уже загрузил наше приложение, написанное на ExtJs. Успел он побывать и у стороннего сервера. Сигнальному серверу он также направил своё описание и название канала связи.

Сигнальный сервер вёл себя необычно. Он понял, что браузеры Маши и Савелия могут общаться между собой и не докучать ему в течение этого времени своими запросами. Браузеру Савелия он вручил описание браузера Маши. Браузеру Маши, когда тот объявился в очередной раз, он вручил описание браузера Савелия.


Действие пятое (заключительное)


Радости браузеров нет предела. Наконец-то они избавились от общества этого высокомерного сигнального сервера. Имея описания друг друга, они всегда могут встретиться в сети и обсудить интересующие их темы.

Маша получила письмо Савелия.

От автора
Совпадение с реальными людьми случайны. Протоколы ICE, STUN и TURN оставлены за сценой умышленно. С ними ещё предстоит разобраться.

четверг, 8 августа 2013 г.

Рабочее пространство

Когда у вас в проекте не одно, а несколько одностраничных приложений на ExtJs (4.2), то в папку каждого приложения вы вынуждены повторно класть одни и те же файлы. Досадный пример - иконки. Более серьёзно заставляет задуматься над проблемой дублирование файлов SDK (библиотеки ExtJs). Они многочисленны, занимают много места на диске и тормозят IDE.

Выход есть - создавать приложения в рамках единой рабочей зоны. Трюк выполняется в два этапа:
  1. Создание рабочей зоны командой sencha generate workspace
  2. Создание приложения командой sencha generate app
Чтобы добавить второе, третье и прочие приложения, просто повторите пункт 2, изменив название приложения и имя папки внутри рабочего пространства.

Слово "трюк" было упомянуто выше, кстати, умышленно. Есть подводные камни. Чтобы обоити их и не оказаться на больничной койке на форуме поддержки, следует особое внимание  уделить тому, откуда вы будете вызывать команду sencha generate workspace. Её нужно вызывать из директории, в которой хранится SDK.

novikov@novikov-UX31A ~/NetBeansProjects/eurasclimat/www/httpdocs/sdk/ext-4.2.1.883 $ bash ~/bin/Sencha/Cmd/3.1.2.342/sencha generate workspace /home/novikov/NetBeansProjects/eurasclimat/www/httpdocs/workspace

Разберём команду по частям.

novikov@novikov-UX31A - имя пользователя и компьютера


 ~/NetBeansProjects/eurasclimat/www/httpdocs/sdk/ext-4.2.1.883 $ - директория, в которой хранится SDK


 bash ~/bin/Sencha/Cmd/3.1.2.342/sencha generate workspace - запуск команды через оболочку bash. Обратите внимание, что описан полный путь до исполняемого файла sencha. Это потому что я не стал настраивать переменную окружения PATH.

 /home/novikov/NetBeansProjects/eurasclimat/www/httpdocs/workspace - путь к создаваемому рабочему пространству.

После выполнения команды sencha generate workspace, в папке рабочего пространства, которую я совершенно произвольно назвал workspace, появится поддитектория - ext. Это то чего мы добивались. Чтобы на несколько одностраничных приложений была одна папка с библиотекой ExtJs.

Но это ещё не всё. Откроем папку рабочего пространства в терминале. Создавать новое приложение будем отсюда:

 novikov@novikov-UX31A ~/NetBeansProjects/eurasclimat/www/httpdocs/workspace/ext $ bash ~/bin/Sencha/Cmd/3.1.2.342/sencha generate app Project ../project

И наконец, для любителей кинематографа - видео:

суббота, 3 августа 2013 г.

Разговор браузеров - WebRTC

Хочу поделиться восторгом от новой технологии - WebRTC. Она развивается в рамках HTML5. Позволяет создать свой Skype на коленке. Заманчивой представляется, возможность прямой передачи данных из браузера в браузер. Одностраничные приложения приобретают новое качество.

Вот простенький пример. Подключается малюсенький скрипт adapter.js, который позволяет применять один и тот же код для Chrome и Firefox. После загрузки скрипта находим на странице элемент video и передаем в него поток с камеры:


Нужно разрешить доступ к устройствам. В данном случае - веб-камере.


 И ...


(Надо будет побриться)


воскресенье, 21 июля 2013 г.

Слушаем кнопки в Ext.form.field.HtmlEditor

В режиме изменения HTML-кода перестаёт генерироваться событие dirtychange. Из-за этого невозможно разблокировать кнопку сохранения формы. Проблема показана на видео:



Как справиться с таким затруднением, не прибегая к средствам чёрной магии? Как заставить коробочный компонент ExtJs генерировать новые события? Ниже представлен вариант решения.

Попутно замечу, что белая магия не использует костыли для достижения необходимого результата. Только волшебные палочки. Значит, мы остаёмся в рамках MVC и определяем обработчик в контроллере. Мы также не используем незадокументированные свойства объектов ExtJs (например, textareaEl).

Просто ждём, пока не отобразится HTML-редактор. Когда он отобразится, будет сгенерировано событие render. В обработчике этого события находим в DOM текстовое поле. На его событие keyup навешиваем проверку изменений. В документации написано, что при обнаружении изменений будет распространено событие dirtychange. Наша проблема будет решена.

Посмотрите на код представления и контроллера. Жирным выделен участок, который устранил проблему.


Представление (V)


Ext.define('Admin.view.HtmlEditor', {
   
    extend: 'Ext.form.Panel',
   
    alias: 'widget.app-html-editor',
   
    trackResetOnLoad: true, // позволяет следить за изменениями в полях формы через событие dirtychange
   
    layout: 'fit',
   
    items: [
        {
            xtype: 'htmleditor',
            itemId: 'html-editor-field',
            name: 'html'
        }
    ]


});



Контроллер (C)


Ext.define('Admin.controller.HtmlEditorController', {
   
    extend: 'Ext.app.Controller',

    init: function() {
       
        this.listen({
            component: {
                'app-html-editor': {
                    dirtychange: this.onDirtyChange
                },
                'app-html-editor [itemId="html-editor-field"]': {
                    render: this.listenToKeyEvents
                }

            }
        });
       
    },
   
    listenToKeyEvents: function(htmlEditorField) {
       
        htmlEditorField.getEl().down('textarea').on('keyup', function() {
           
            htmlEditorField.checkDirty();
           
        });
       
    },

   
    onDirtyChange: function(basicForm, isDirty) {

        var formPanel = basicForm.owner;
       
        var menuButton = formPanel.down('[itemId="menu-button"]');
        var saveButton = formPanel.down('[itemId="save-button"]');
        var cancelButton = formPanel.down('[itemId="cancel-button"]');
       
        if (isDirty) {
           
            menuButton.disable();
            saveButton.enable();
            cancelButton.enable();
           
        } else {
           
            menuButton.enable();
            saveButton.disable();
            cancelButton.disable();
           
        }
       
    }

 
});




Проверим, как это работает.




суббота, 22 июня 2013 г.

Рабочая лошадка, или веб-сервер на виртуальной машине


Очень удобно иметь на рабочей машине несколько виртуальных систем. Так больше порядка. Для каждого проекта свой набор серверов. О том, как поднять необходимое в VirtualBox, читайте ниже и приспосабливайте под свои нужды. (Все продукты бесплатны)

VirtualBox

скачать с сайта и открыть установочный файл в менеджере пакетов
Файл->Настройки->Сеть->Добавить виртуальную сеть хоста
    адрес 33.33.33.1
    маска 255.255.255.0
    DHCP выключить

Виртуальные машины (ВМ) создавать с нуля, а не копировать, чтобы избежать проблем с настройкой сети.

По умолчанию новая ВМ подключена через сетевой адаптер №1 типа NAT. Он позволяет скачивать файлы из Интернета, но не видит соседние ВМ.

sudo apt-get update
sudo apt-get upgrade
ifconfig
    должно присутствовать 2 сетевых интерфейса eth0 и lo
sudo nano /etc/network/interfaces
    auto eth1
    iface eth1 inet static
    address 33.33.33.101
    netmask 255.255.255.0
    network 33.33.33.0
    broadcast 33.33.33.255
    gateway 33.33.33.1

где 33.33.33.101 нужно изменить на IP-адрес создаваемой витуальной машины
sudo shutdown -h now

После выключения виртуальной машины, необходимо изменить её сетевые настройки.
Подключить сетевой адаптер №2 типа "Виртуальный адаптер хоста". Он позволит основной машине видеть виртуальную, и наоборот.
Однако после этого пропадёт связь с Интернетом у ВМ. На время обновления кода этот адаптер нужно отключать.
Проверить, что ifconfig показывает 3 сетевых интерфейса: lo, eth0, eth1.

Чтобы веб-сервер мог работать по сети с базой данных, "NAT" нужно поменять на "Сетевой мост".

FTP

sudo apt-get install vsftpd
sudo nano /etc/vsftpd.conf
    local_enable=YES
    chroot_local_user=YES
    local_root=/home
    anonymous_enable=NO
    write_enable=YES
    local_umask=022
sudo usermod -a -G my_user ftp
sudo service vsftpd restart

Вход через FTP-клиент под именем и паролем пользователя сервера Ubuntu.

Apache

sudo apt-get install apache2
mkdir /home/my_user/www
sudo nano /etc/apache2/sites-available/default
    В двух местах изменить путь /var/www на /home/my_user/www
sudo a2dissite default
sudo a2ensite default
sudo service apache2 restart

PHP


PostgreSQL

Установка версии 8.4
doc
help.ubuntu.com

sudo apt-get install postgresql-8.4
sudo apt-get install postgresql-contrib-8.4
sudo -u postgres psql < /usr/share/postgresql/8.4/contrib/adminpack.sql

Создаём пользователя:
sudo -u postgres psql postgres
    \password postgres
    \q

Открываем порт:
sudo nano /etc/postgresql/8.1/main/pg_hba.conf
    host    all    all    0.0.0.0/0    md5
sudo nano /etc/postgresql/8.4/main/postgresql.conf
    listen_addresses = '33.33.33.105,localhost'
Где 33.33.33.105, адрес машины, на которой устанавливается база данных.

Запускаем:
sudo /etc/init.d/postgresql restart
   

nginx

(бывает нужен иногда для проксирования виртуальных машин)

sudo -s 
nginx=stable # use nginx=development for latest development version 
add-apt-repository ppa:nginx/$nginx 
apt-get update apt-get install nginx


sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/my_site
sudo nano /etc/nginx/sites-available/my_site
     server {
        listen 80;
        server_name 192.168.0.41;
        location / {
                proxy_pass http://33.33.33.126/;
                proxy_redirect off;
        }
    }

sudo ln -s /etc/nginx/sites-available/my_site /etc/nginx/sites-enabled/my_syte
nginx -t
sudo service nginx restart


пятница, 21 июня 2013 г.

JSONS

Эта заметка не об ExtJs. Поговорим о возвышенном. Об искуственности интеллекта :).

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

Сообщения людей поступают в формате семантического JSON`а. Этот формат позволяет ссылаться на упомянутые ранее предметы.

JsFiddle


GitHub

воскресенье, 2 июня 2013 г.

Компиляция приложения, построенного на SDK ExtJs

Ознакомьтесь с предыдущими статьями:

Переходим в директорию проекта:

cd ~/NetBeansProjects/devconf2013/www/client/school/

Запускаем компиляцию и записываем сборку всех классов в файл  school.js.  Тут же минифицируем код и записываем то, что получилось в файл school-min.js.

sencha compile -classpath=sdk/src,app union -r -class school.Application and concat school.js and concat --compress school-min.js


В процессе выполнения команды подтянутся все классы, от которых зависит класс school.Application, определённый в файле:

~/www/doctornovikova/www/client/school/app/application.js

Если ОС не может найти команду sencha, нужно перезагрузить систему. Применятся настройки PATH из файла ~/.profile.

Документация по Sencha Cmd



суббота, 1 июня 2013 г.

Каркас нового приложения

Ознакомьтесь с предыдущей статьёй "Установка Sencha Cmd в Ubuntu".

Определим местонахождение папки с библиотекой ExtJs. Путь к ней будем использовать в командах Sencha Cmd (ключ -sdk).


У меня он выглядит так:

~/NetBeansProjects/devconf2013/www/client/library/ext-4.2.1.883

Однако одного этого пути недостаточно. Нужен ещё путь к папке, в которой будут лежать написанные нами классы.

Моё новое приложение называется school, поэтому создаю такую папку:

~/NetBeansProjects/devconf2013/www/client/school


Открываем терминал. Пляшем в иступлении.

Переходим в директорию, где расположен исполняемый файл утилиты Sencha Cmd. Помните, в статье про инсталляцию даной утилиты, я просил вас запомнить путь? В моём случае:

cd ~/bin/Sencha/Cmd/3.1.2.342

Предлагаем утилите Sencha Cmd создать стандартный набор папок и файлов для MVC-приложения. Я написал (в одну строку):

./sencha -sdk ~/NetBeansProjects/devconf2013/www/client/library/ext-4.2.1.883 generate app school ~/NetBeansProjects/devconf2013/www/client/school

Расшифровка:

sencha -sdk <путь к библиотеке ExtJs> generate app <имя создаваемого приложения> <путь к пустой директории>

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



Работа утилиты завершилась без сообщений об ошибках.


Теперь посмотрим на результат.


Всё готово! Создавайте классы представлений, контроллеров, хранилищ и моделей в предназначенных для этого разделах директории app:


О том, чтобы написаный вами код мог быстро загружаться и исполняться позаботится компилятор Sencha Cmd, о котором читайте в следующей статье Компиляция приложения, построенного на SDK ExtJs.

Установка Sencha Cmd в Ubuntu

КуримЧитаем документацию, доступную по ссылке:

документация по Sencha Cmd

Определяем, какая операционная система установлена на компьютере.


Скачиваем нужный файл со следующей страницы:

Sencha Cmd для Windows, Linux или Mac


Открываем терминал. Берём в руки бубен.

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

Изменяем ограничение прав на файл так, чтобы его мог запустить на исполнение любой пользователь:

sudo chmod 777 SenchaCmd-3.1.2.342-linux-x64.run

Запускаем скаченную нами программу установки из-под обычного пользователя:

./SenchaCmd-3.1.2.342-linux-x64.run

Если запустить эту программу от имени суперпользователя, то установка пройдёт без сообщений об ошибках, но пользоваться установленным приложением будет невозможно (см. здесь).


Соглашаемся с условиями лицензии.


Доходим до выбора места установки и запоминаем выбранную директорию.


Завершаем установку Sencha Cmd.


Об использовании утилиты читате в следующей статье "Каркас нового приложения".